1 / 41

Gordon Stewart (Princeton), Mahanth Gowda (UIUC),

ZIRIA w ireless PHY programming for hardware dummies. Gordon Stewart (Princeton), Mahanth Gowda (UIUC), Geoff Mainland (Drexel ), Cristina Luengo (UPC), Anton Ekblad (Chalmers) Bozidar Radunovic (MSR ), Dimitrios Vytiniotis (MSR ). Programming software radios. Typical scenario:

Download Presentation

Gordon Stewart (Princeton), Mahanth Gowda (UIUC),

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. ZIRIA wireless PHY programming for hardware dummies Gordon Stewart (Princeton), Mahanth Gowda (UIUC), Geoff Mainland (Drexel), Cristina Luengo (UPC), Anton Ekblad (Chalmers) Bozidar Radunovic (MSR), Dimitrios Vytiniotis (MSR)

  2. Programming software radios Typical scenario: RF + A/D sends samples through PCI-express to CPU. All PHY/MAC processing done on CPU • Lots of recent innovation in PHY/MAC design • Communities: MobiCom, SIGCOMM • Software Defined Radio (SDR) platforms useful for experimentation and research • GNURadio (C/C++, Python) predominant platform • relatively easy to program, lots of libraries • slow; first real-time GNURadioWiFi RX in appeared only last year • SORA (MSR Asia): C++ library + custom hardware • lots of manual optimizations, • hard to modify SORA pipelines, shared state • A breakthrough: extremely fast code and libraries!

  3. The problem • Essentially the traditional complaints against FPGAs … • Error prone designs, latency-sensitivity issues • Code semantics tied to underlying hardware or execution model • Hard to maintain the code, big barrier to entry • … become valid against software platforms too, undermining the very advantages of software! • Airblue [ANCS’10] offered a solution: a hardware synthesis platform that offers latency-insensitivity and high-level programmability • ZIRIA: similar goals for software implementations

  4. SDR manual optimizations (SORA) struct _init_lut { void operator()(uchar (&lut)[256][128]) { int i,j,k; uchar x, s, o; for ( i=0; i<256; i++) { for ( j=0; j<128; j++) { x = (uchar)i; s = (uchar)j; o = 0; for ( k=0; k<8; k++) { uchar o1 = (x ^ (s) ^ (s >> 3)) & 0x01; s = (s >> 1) | (o1 << 6); o = (o >> 1) | (o1 << 7); x = x >> 1; } lut [i][j] = o; } } } } Hand-written bit-fiddling code to create lookup tables for specific computations that must run very fast … and more e.g. manual provision of dataflow pipeline widths

  5. Another problem: dataflow abstractions Predominant abstraction used (e.g. SORA, StreamIt, GnuRadio) is that of a “vertex” in a dataflow graph • Reasonable as abstraction of the execution model (ensures low-latency) • Unsatisfactory as programming and compilation model Why unsatisfactory? It does not expose: When is vertex “state” (re-) initialized? Under which external “control” messages can the vertex change behavior? How can vertex transmit “control” information to other vertices? Events (messages) come in Events (messages) come out

  6. Example: dataflow abstractions in SORA DEFINE_LOCAL_CONTEXT(TBB11aRxRateSel, CF_11RxPLCPSwitch, CF_11aRxVector ); template<TDEMUX5_ARGS> class TBB11aRxRateSel : public TDemux<TDEMUX5_PARAMS> { CTX_VAR_RO (CF_11RxPLCPSwitch::PLCPState, plcp_state ); CTX_VAR_RO (ulong, data_rate_kbps ); // data rate in kbps public: ….. public: REFERENCE_LOCAL_CONTEXT(TBB11aRxRateSel); STD_DEMUX5_CONSTRUCTOR(TBB11aRxRateSel) BIND_CONTEXT(CF_11RxPLCPSwitch::plcp_state, plcp_state) BIND_CONTEXT(CF_11aRxVector::data_rate_kbps, data_rate_kbps) {} void Reset() { Next0()->Reset(); // No need to reset all path, just reset the path we used in this frame switch (data_rate_kbps) { case 6000: case 9000: Next1()->Reset(); break; case 12000: case 18000: Next2()->Reset(); break; case 24000: case 36000: Next3()->Reset(); break; case 48000: case 54000: Next4()->Reset(); break; } } Shared statewith other components Verbose, hinders fast prototyping Implementation of component relies on dataflow graph!

  7. What is “state” and “control”: WiFi RX Channel characteristics: a control value Payload modulation parameters: A control value Transmission detected: a control value Packetstart Channel info DetectSTS ChannelEstimation InvertChannel InvertChannel Packetinfo Decode Header Decode Packet Detect if we have transmission: Processing while updating internal state Estimates the effects of the communication channel

  8. A great opportunity to use functional programming ideas in a high-performance scenario • Better dataflow abstractions for capturing state initialization and control values • We identify an important gap: a lot of related work focuses more on efficient DSP (e.g. SORA, Spiral, Feldspar, StreamIt) and much less on control, but e.g. LTE spec is 400 pages with a handful (and mostly standardized) DSP algorithms • Better automatic optimizations

  9. ZIRIA • A non-embeddedDSL for bit stream and packet processing • Programming abstractions well-suited for wireless PHY implementations in software (e.g. 802.11a/g) • Optimizing compiler that generates real-time code • Developed @ MSR Cambridge, open source under Apache 2.0 www.github.com/dimitriv/Ziria http://research.microsoft.com/projects/Ziria • Repo includes WiFi RX & TX PHY implementation for SORA hardware

  10. ZIRIA: A 2-level language • Lower-level • Imperative C-like language for manipulating bits, bytes, arrays, etc. • Statically known array sizes • Aimed at EE crowd (used to Cand Matlab) • Higher-level: • Monadic language for specifying and composing stream processors • Enforces clean separation between control and data flow • Intuitive semantics (in a process calculus) • Runtime implements low-level execution model • inspired by stream fusion in Haskell • provides efficient sequential and pipeline-parallel executions

  11. ZIRIA programming abstractions inStream(a) inStream(a) t c outControl(v) A stream computer c,of type: ST (C v) a b A stream transformer t, of type: ST T a b outStream(b) outStream(b) * Types similar to (but a lot simpler than) Haskell Pipes

  12. Control-aware streaming abstractions inStream(a) inStream(a) t c outControl(v) take :: ST (C a) a b emit :: v -> ST (C ()) a v map :: (a -> b) -> ST T a b repeat :: ST (C ()) a b -> ST T a b outStream(b) outStream(b)

  13. Data- and control-path composition Drain-from-downstream semantics (>>>) :: ST T a b -> ST T b c -> ST T a c (>>>) :: ST (C v) a b -> ST T b c -> ST (C v) a c (>>>) :: ST T a b -> ST (C v) b c -> ST (C v) a c Composition along “control path” (like a monad*) Reinventing a Swedish classic: The “Fudgets” GUI monad [Carlsson & Hallgren, 1996] Composition along “data path” (like an arrow) (>>=) :: ST (C v) a b -> (v -> ST x a b) -> ST x a b return :: v -> ST (C v) a b • Like Yampa’s switch, but using different channels for control and data • Monad similar to Elliott’s Task monad [PADL’99]

  14. Composing pipelines, in diagrams Monadic ‘seq’ notation  seq { x <- m1; m2 } === m1 >>= (\x -> m2) • T • C c1 t2 seq { v <- (c1 >>> t1) ; t2 >>> t3 } t1 t3

  15. High-level WiFi RX skeleton Channel info Packetstart DetectSTS ChannelEstimation InvertChannel InvertChannel let comp wifi_rx = seq { pstart <- detectSTS() ; cinfo <- estimateChannel(pstart) ; pinfo <- invertChannel(cinfo) >>> decodeHeader() ; invertChannel(cinfo) >>> decodePacket(pinfo) } Packetinfo Decode Header Decode Packet

  16. Plugging in low-level imperative code let comp scrambler() = varscrmbl_st: arr[7] bit := {'1,'1,'1,'1,'1,'1,'1}; vartmp,y: bit; repeat{ (x:bit) <- take; do { tmp := (scrmbl_st[3] ^ scrmbl_st[0]); scrmbl_st[0:5] := scrmbl_st[1:6]; scrmbl_st[6] := tmp;         y := x ^ tmp       }; emit (y) } Low-level imperative code Lifted with “do”

  17. CPU execution model Every c :: ST (C v) a bcompiles to 3 functions: tick:: () → St (Result v b + NeedInput) process :: a → St (Result v b) init:: () → St () data Result v b ::= Skip | Yield b | Done v Compilation task: compose* tick(), process(), init() compositionally from smaller blocks * Actual implementation uses labeled blocks and gotos

  18. Main loop write b to output tick() Result v b Skip Yield(b) Done(v) NeedInput read a from input process(a) write v to ctrl output

  19. CPU scheduling: no queues • Ticking (c1 >>> c2) starts from c2, processing (c1 >>> c2) starts from c1 • Reason: design decision to avoid introducing queues as result of compilation • Actually queues could be introduced explicitly by programmers, • … or as a result of vectorization (see later) but we guarantee that upon control transitions no un-processed data remains in the queues (which is on of the main reasons SORA pipelines are hard to modify!) • Ticking/processing seq { x <- c1; c2 } starts from c1; when Done, we init() c2 and start ticking/processing on c2

  20. Optimizing ZIRIA code • Exploit monad laws, partial evaluation • Fuse parts of dataflow graphs • Reuse memory, avoid redundant memcopying • Compile expressions to lookup tables (LUTs) • Pipeline vectorization transformation • Pipeline parallelization The rest of the talk

  21. Pipeline vectorization Problem statement: given (c :: ST x a b), automatically rewrite it to c_vect :: ST x (arr[N] a) (arr[M] b) for suitable N,M. Benefits of vectorization • Fatter pipelines => lower dataflow graph interpretive overhead • Array inputs vs individual elements => more data locality • Especially for bit-arrays, enhances effects of LUTs

  22. Computer vectorization feasible sets Assume we have cardinality info: # of values the component takes and emits before returning (Here: ain = 80, aout = 2) Feasible vectorization set: { (din,dout) | din `divides` ain, dout `divides` aout } seq { x <- takes 80 ; var y : arr[64] int ; do { y := f(x) } ; emit y[0] ; emit y[1] } e.g. din = 8, dout =2 seq { var x : arr[80] int ; for i in 0..10 { (xa : arr[8] int) <- take; x[i*8,8] := xa; } ; var y : arr[64] int ; do { y := f(x) } ; emit y[0,2] } ST (C ()) intint ST (C ()) (arr[8] int) (arr[2] int)

  23. Impl. keeps feasible sets and not just singletons seq { x <- c1 ; c2 } c1_v1 :: ST (C v) (arr[80] int) (arr[2] int) c1_v2 :: ST (C v) (arr[16] int) (arr[2] int) …. Well-typed choice: c1_v1 and c2_v2 Hence: we must keep sets c2_v1 ::ST (C v) (arr[24] int) (arr[2] int) c2_v2 :: ST (C v) (arr[16] int) (arr[2] int) ….

  24. Transformer vectorizations Without loss of generality, every ZIRIA transformer can be treated as: repeat c where c is a computer How to vectorize(repeat c)?

  25. Transformer vectorizations in isolation • Let c have cardinality info (ain, aout) • Can vectorize to divisors of ain (aout) [as before] • Can also vectorizeto multiples of ain (aout) How to vectorize (repeat c)? Why? It’s a TRANSFORMER, it’s supposed to always have data to process repeat { (vect_xa : arr[8] int) <- take; times i 2 { times j 4 { do { vect_ya[j] := f(vect_xa[i*4 + j]) } } emit vect_ya; } } repeat { x <- take ; emit f(x) } ST T intint ST T (arr[8] int) (arr[4] int)

  26. Transformers-before-computers • ANSWER: No! (repeat c) may consume data destined for c2 after the switch • SOLUTION: consider (K*ain, N*K*aout), NOT arbitrary multiples˚ LET ME QUESTION THIS ASSUMPTION (˚) caveat: assumes that (repeat c) >>> c1 terminates when c1 and c have returned. No “unemitted” data from c seq { x <- (repeat c) >>> c1 ; c2 } ``It’s a TRANSFORMER, it’s supposed to always have data to process’’ Assume c1 vectorizes to input (arr[4] int) ain = 1, aout =1 QUIZ: Is vect. ST T (arr[8] int) (arr[4] int) correct?

  27. Transformers-after-computers • ANSWER: No! (repeat c) may not have a full 8-element array to emit when c1 terminates! • SOLUTION: consider (N*K*ain, K*aout), NOT arbitrary multiples [symmetrically to before] The danger of consuming more data or emitting less data when a shared variable changes is what makes SORA pipelines with manually provisioned queues harder to modify seq { x <- c1 >>> (repeat c) ; c2 } Assume c1 vectorizes to output (arr[4] int) ain = 1, aout =1 QUIZ: Is vect. (ST T (arr[4] int) (arr[8] int) correct?

  28. How to choose final vectorization? • In the end we may have very different vectorization candidates • Which one to choose? Intuition: prefer fat pipelines • Failed idea: maximize sum of pipeline arrays • Alas it does not give uniformly fat pipelines: 256+4+256 > 128+64+128 4 256 256 4 c1_vect c2_vect 128 64 128 64 c1_vect’ c2_vect’

  29. How to choose final vectorization? • Solution: a classical idea from distributed optimization • Maximize sum of a convex function (e.g. log) of sizes of pipeline arrays • log 256+log 4+log 256 = 8+2+8 = 18 < 20 = 7+6+7 = log 128+log 64+log 128 • Sum of log(.) gives uniformly fat pipelines and can be computed locally 4 256 256 4 c1_vect c2_vect 64 128 128 64 c1_vect’ c2_vect’

  30. Final piece of the puzzle: pruning • As we build feasible sets from the bottom up we must not discard vectorizations • But there may be multiple vectorizations with the same type, e.g: • Which one to choose?[They have same type (ST x (arr[8] bit) (arr[8] bit)] • We must prune by choosing one per type to avoid search space explosion • Answer: keep the one with maximum utility from previous slide 4 8 8 4 c1_vect c2_vect 2 8 8 2 c1_vect’ c2_vect’

  31. Vectorization and LUT synergy let comp scrambler() = varscrmbl_st: arr[7] bit := {'1,'1,'1,'1,'1,'1,'1}; vartmp,y: bit; repeat{ (x:bit) <- take; do{ tmp := (scrmbl_st[3] ^ scrmbl_st[0]); scrmbl_st[0:5] := scrmbl_st[1:6]; scrmbl_st[6] := tmp;         y := x ^ tmp       }; emit (y) } let comp v_scrambler() = varscrmbl_st: arr[7] bit := {'1,'1,'1,'1,'1,'1,'1}; vartmp,y: bit; varvect_ya_26: arr[8] bit; let auto_map_71(vect_xa_25: arr[8] bit) = LUTfor vect_j_28 in 0, 8 {           vect_ya_26[vect_j_28] := tmp:= scrmbl_st[3]^scrmbl_st[0]; scrmbl_st[0:+6] := scrmbl_st[1:+6]; scrmbl_st[6] := tmp; y := vect_xa_25[0*8+vect_j_28]^tmp; return y }; return vect_ya_26 inmap auto_map_71 Vectorization Automaticlookup-table-compilation Input-vars = scrmbl_st, vect_xa_25 = 15 bits Output-vars = vect_ya_26, scrmbl_st = 2 bytes IDEA: precompile to LUT of 2^15 * 2 = 64K RESULT: ~ 1Gbps scrambler

  32. Performance numbers (RX)

  33. Performance numbers (TX) More work to be done here, SORA much faster!

  34. Effects of optimizations (RX) Most benefits come from vectorization of the RX complex16 pipelines

  35. Effects of optimizations (TX) Vectorization alone is slow (bit array addressing) but enables LUTs!

  36. Latency (TX) • Methodology • Sample consecutive read/write operations • Normalize 1/data-rate • Result: largely satisfying latency requirements

  37. Latency (RX) WiFi 802.11a/g requires SIFS ~ 16/10us, and 0.1 << 10 1/40Mhz = 0.024

  38. Latency (conclusions) • Mostly latency requirements are satisfied • On top of this, hardware buffers amortize latency • Big/unstable latency would mean packet dropping in the RX: but we see ~ 95% packet successful reception in our experiments with SORA hardware

  39. What’s next • Compilation to FPGAs and/or custom DSPs • A general story for parallelism with many low-power cores • A high-level semantics in a process calculus • Porting to other hardware platforms (e.g. USRP) • Improve array representations, take ideas from Feldspar [Chalmers], Nikola [Drexel] • Work on a Haskell embedding to take advantage of generative programming in the style of Feldspar and SPIRAL [CMU,ETH]

  40. Conclusions Although ZIRIA is not a pure functional PL: • Has design inspired by monads and arrows • Stateful components communicate only through explicit control and data channels => A lesson from taming state in pure functional languages • Strong types that capture both data and control channel improve reusability and modularity • … and they allow for optimizations that would otherwise be entirely manual (e.g. vectorization) Putting functional programming (ideas) to work!

  41. Thanks! http://research.microsoft.com/en-us/projects/ziria/ www.github.com/dimitriv/Ziria

More Related