Home | History | Annotate | Download | only in www
      1 <html><head><title>The design of toybox</title></head>
      2 <!--#include file="header.html" -->
      3 
      4 <b><h2>Design goals</h2></b>
      5 
      6 <p>Toybox should be simple, small, fast, and full featured.  Often, these
      7 things need to be balanced off against each other.  In general, keeping the
      8 code simple the most important (and hardest) goal, and small is slightly more
      9 important than fast. Features are the reason we write code in the first
     10 place but this has all been implemented before so if we can't do a better
     11 job why bother?  It should be possible to get 80% of the way to each goal
     12 before they really start to fight.</p>
     13 
     14 <p>Here they are in reverse order of importance:</p>
     15 
     16 <b><h3>Features</h3></b>
     17 
     18 <p>The <a href=roadmap.html>roadmap</a> has the list of features we're
     19 trying to implement, and the reasons for them. After the 1.0 release
     20 some of that material may get moved here.</p>
     21 
     22 <p>Some things are simply outside the scope of the project: even though
     23 posix defines commands for compiling and linking, we're not going to include
     24 a compiler or linker (and support for a potentially infinite number of hardware
     25 targets). And until somebody comes up with a ~30k ssh implementation, we're
     26 going to point you at dropbear or polarssl.</p>
     27 
     28 <p>Environmental dependencies are a type of complexity, so needing other
     29 packages to build or run is a big downside.  For example, we don't use curses
     30 when we can simply output ansi escape sequences and trust all terminal
     31 programs written in the past 30 years to be able to support them. (A common
     32 use case is to download a statically linked toybox binary to an arbitrary
     33 Linux system, and use it in an otherwise unknown environment; being
     34 self-contained helps support this.)</p>
     35 
     36 <b><h3>Speed</h3></b>
     37 
     38 <p>It's easy to say lots about optimizing for speed (which is why this section
     39 is so long), but at the same time it's the optimization we care the least about.
     40 The essence of speed is being as efficient as possible, which means doing as
     41 little work as possible.  A design that's small and simple gets you 90% of the
     42 way there, and most of the rest is either fine-tuning or more trouble than
     43 it's worth (and often actually counterproductive).  Still, here's some
     44 advice:</p>
     45 
     46 <p>First, understand the darn problem you're trying to solve.  You'd think
     47 I wouldn't have to say this, but I do.  Trying to find a faster sorting
     48 algorithm is no substitute for figuring out a way to skip the sorting step
     49 entirely.  The fastest way to do anything is not to have to do it at all,
     50 and _all_ optimization boils down to avoiding unnecessary work.</p>
     51 
     52 <p>Speed is easy to measure; there are dozens of profiling tools for Linux
     53 (although personally I find the "time" command a good starting place).
     54 Don't waste too much time trying to optimize something you can't measure,
     55 and there's no much point speeding up things you don't spend much time doing
     56 anyway.</p>
     57 
     58 <p>Understand the difference between throughput and latency.  Faster
     59 processors improve throughput, but don't always do much for latency.
     60 After 30 years of Moore's Law, most of the remaining problems are latency,
     61 not throughput.  (There are of course a few exceptions, like data compression
     62 code, encryption, rsync...)  Worry about throughput inside long-running
     63 loops, and worry about latency everywhere else.  (And don't worry too much
     64 about avoiding system calls or function calls or anything else in the name
     65 of speed unless you are in the middle of a tight loop that's you've already
     66 proven isn't running fast enough.)</p>
     67 
     68 <p>"Locality of reference" is generally nice, in all sorts of contexts.
     69 It's obvious that waiting for disk access is 1000x slower than doing stuff in
     70 RAM (and making the disk seek is 10x slower than sequential reads/writes),
     71 but it's just as true that a loop which stays in L1 cache is many times faster
     72 than a loop that has to wait for a DRAM fetch on each iteration.  Don't worry
     73 about whether "&" is faster than "%" until your executable loop stays in L1
     74 cache and the data access is fetching cache lines intelligently.  (To
     75 understand DRAM, L1, and L2 cache, read Hannibal's marvelous ram guide at Ars
     76 Technica:
     77 <a href=http://arstechnica.com/paedia/r/ram_guide/ram_guide.part1-2.html>part one</a>,
     78 <a href=http://arstechnica.com/paedia/r/ram_guide/ram_guide.part2-1.html>part two</a>,
     79 <a href=http://arstechnica.com/paedia/r/ram_guide/ram_guide.part3-1.html>part three</a>,
     80 plus this
     81 <a href=http://arstechnica.com/articles/paedia/cpu/caching.ars/1>article on
     82 cacheing</a>, and this one on
     83 <a href=http://arstechnica.com/articles/paedia/cpu/bandwidth-latency.ars>bandwidth
     84 and latency</a>.
     85 And there's <a href=http://arstechnica.com/paedia/index.html>more where that came from</a>.)
     86 Running out of L1 cache can execute one instruction per clock cycle, going
     87 to L2 cache costs a dozen or so clock cycles, and waiting for a worst case dram
     88 fetch (round trip latency with a bank switch) can cost thousands of
     89 clock cycles.  (Historically, this disparity has gotten worse with time,
     90 just like the speed hit for swapping to disk.  These days, a _big_ L1 cache
     91 is 128k and a big L2 cache is a couple of megabytes.  A cheap low-power
     92 embedded processor may have 8k of L1 cache and no L2.)</p>
     93 
     94 <p>Learn how virtual memory and memory managment units work.  Don't touch
     95 memory you don't have to.  Even just reading memory evicts stuff from L1 and L2
     96 cache, which may have to be read back in later.  Writing memory can force the
     97 operating system to break copy-on-write, which allocates more memory.  (The
     98 memory returned by malloc() is only a virtual allocation, filled with lots of
     99 copy-on-write mappings of the zero page.  Actual physical pages get allocated
    100 when the copy-on-write gets broken by writing to the virtual page.  This
    101 is why checking the return value of malloc() isn't very useful anymore, it
    102 only detects running out of virtual memory, not physical memory.  Unless
    103 you're using a NOMMU system, where all bets are off.)</p>
    104 
    105 <p>Don't think that just because you don't have a swap file the system can't
    106 start swap thrashing: any file backed page (ala mmap) can be evicted, and
    107 there's a reason all running programs require an executable file (they're
    108 mmaped, and can be flushed back to disk when memory is short).  And long
    109 before that, disk cache gets reclaimed and has to be read back in.  When the
    110 operating system really can't free up any more pages it triggers the out of
    111 memory killer to free up pages by killing processes (the alternative is the
    112 entire OS freezing solid).  Modern operating systems seldom run out of
    113 memory gracefully.</p>
    114 
    115 <p>Also, it's better to be simple than clever.  Many people think that mmap()
    116 is faster than read() because it avoids a copy, but twiddling with the memory
    117 management is itself slow, and can cause unnecessary CPU cache flushes.  And
    118 if a read faults in dozens of pages sequentially, but your mmap iterates
    119 backwards through a file (causing lots of seeks, each of which your program
    120 blocks waiting for), the read can be many times faster.  On the other hand, the
    121 mmap can sometimes use less memory, since the memory provided by mmap
    122 comes from the page cache (allocated anyway), and it can be faster if you're
    123 doing a lot of different updates to the same area.  The moral?  Measure, then
    124 try to speed things up, and measure again to confirm it actually _did_ speed
    125 things up rather than made them worse.  (And understanding what's really going
    126 on underneath is a big help to making it happen faster.)</p>
    127 
    128 <p>In general, being simple is better than being clever.  Optimization
    129 strategies change with time.  For example, decades ago precalculating a table
    130 of results (for things like isdigit() or cosine(int degrees)) was clearly
    131 faster because processors were so slow.  Then processors got faster and grew
    132 math coprocessors, and calculating the value each time became faster than
    133 the table lookup (because the calculation fit in L1 cache but the lookup
    134 had to go out to DRAM).  Then cache sizes got bigger (the Pentium M has
    135 2 megabytes of L2 cache) and the table fit in cache, so the table became
    136 fast again...  Predicting how changes in hardware will affect your algorithm
    137 is difficult, and using ten year old optimization advice and produce
    138 laughably bad results.  But being simple and efficient is always going to
    139 give at least a reasonable result.</p>
    140 
    141 <p>The famous quote from Ken Thompson, "When in doubt, use brute force",
    142 applies to toybox.  Do the simple thing first, do as little of it as possible,
    143 and make sure it's right.  You can always speed it up later.</p>
    144 
    145 <b><h3>Size</h3></b>
    146 <p>Again, simple gives you most of this.  An algorithm that does less work
    147 is generally smaller.  Understand the problem, treat size as a cost, and
    148 get a good bang for the byte.</p>
    149 
    150 <p>Understand the difference between binary size, heap size, and stack size.
    151 Your binary is the executable file on disk, your heap is where malloc() memory
    152 lives, and your stack is where local variables (and function call return
    153 addresses) live.  Optimizing for binary size is generally good: executing
    154 fewer instructions makes your program run faster (and fits more of it in
    155 cache).  On embedded systems, binary size is especially precious because
    156 flash is expensive (and its successor, MRAM, even more so).  Small stack size
    157 is important for nommu systems because they have to preallocate their stack
    158 and can't make it bigger via page fault.  And everybody likes a small heap.</p>
    159 
    160 <p>Measure the right things.  Especially with modern optimizers, expecting
    161 something to be smaller is no guarantee it will be after the compiler's done
    162 with it.  Binary size isn't the most accurate indicator of the impact of a
    163 given change, because lots of things get combined and rounded during
    164 compilation and linking.  Matt Mackall's bloat-o-meter is a python script
    165 which compares two versions of a program, and shows size changes in each
    166 symbol (using the "nm" command behind the scenes).  To use this, run
    167 "make baseline" to build a baseline version to compare against, and
    168 then "make bloatometer" to compare that baseline version against the current
    169 code.</p>
    170 
    171 <p>Avoid special cases.  Whenever you see similar chunks of code in more than
    172 one place, it might be possible to combine them and have the users call shared
    173 code. (This is the most commonly cited trick, which doesn't make it easy. If
    174 seeing two lines of code do the same thing makes you slightly uncomfortable,
    175 you've got the right mindset.)</p>
    176 
    177 <p>Some specific advice: Using a char in place of an int when doing math
    178 produces significantly larger code on some platforms (notably arm),
    179 because each time the compiler has to emit code to convert it to int, do the
    180 math, and convert it back.  Bitfields have this problem on most platforms.
    181 Because of this, using char to index a for() loop is probably not a net win,
    182 although using char (or a bitfield) to store a value in a structure that's
    183 repeated hundreds of times can be a good tradeoff of binary size for heap
    184 space.</p>
    185 
    186 <b><h3>Simple</h3></b>
    187 
    188 <p>Complexity is a cost, just like code size or runtime speed. Treat it as
    189 a cost, and spend your complexity budget wisely. (Sometimes this means you
    190 can't afford a feature because it complicates the code too much to be
    191 worth it.)</p>
    192 
    193 <p>Simplicity has lots of benefits.  Simple code is easy to maintain, easy to
    194 port to new processors, easy to audit for security holes, and easy to
    195 understand.</p>
    196 
    197 <p>Simplicity itself can have subtle non-obvious aspects requiring a tradeoff
    198 between one kind of simplicity and another: simple for the computer to
    199 execute and simple for a human reader to understand aren't always the
    200 same thing. A compact and clever algorithm that does very little work may
    201 not be as easy to explain or understand as a larger more explicit version
    202 requiring more code, memory, and CPU time. When balancing these, err on the
    203 side of doing less work, but add comments describing how you
    204 could be more explicit.</p>
    205 
    206 <p>In general, comments are not a substitute for good code (or well chosen
    207 variable or function names). Commenting "x += y;" with "/* add y to x */"
    208 can actually detract from the program's readability. If you need to describe
    209 what the code is doing (rather than _why_ it's doing it), that means the
    210 code itself isn't very clear.</p>
    211 
    212 <p>Prioritizing simplicity tends to serve our other goals: simplifying code
    213 generally reduces its size (both in terms of binary size and runtime memory
    214 usage), and avoiding unnecessary work makes code run faster. Smaller code
    215 also tends to run faster on modern hardware due to CPU cacheing: fitting your
    216 code into L1 cache is great, and staying in L2 cache is still pretty good.</p>
    217 
    218 <p><a href=http://www.joelonsoftware.com/articles/fog0000000069.html>Joel
    219 Spolsky argues against throwing code out and starting over</a>, and he has
    220 good points: an existing debugged codebase contains a huge amount of baked
    221 in knowledge about strange real-world use cases that the designers didn't
    222 know about until users hit the bugs, and most of this knowledge is never
    223 explicitly stated anywhere except in the source code.</p>
    224 
    225 <p>That said, the Mythical Man-Month's "build one to throw away" advice points
    226 out that until you've solved the problem you don't properly understand it, and
    227 about the time you finish your first version is when you've finally figured
    228 out what you _should_ have done.  (The corrolary is that if you build one
    229 expecting to throw it away, you'll actually wind up throwing away two.  You
    230 don't understand the problem until you _have_ solved it.)</p>
    231 
    232 <p>Joel is talking about what closed source software can afford to do: Code
    233 that works and has been paid for is a corporate asset not lightly abandoned.
    234 Open source software can afford to re-implement code that works, over and
    235 over from scratch, for incremental gains.  Before toybox, the unix command line
    236 has already been reimplemented from scratch several times in a row (the
    237 original AT&amp;T Unix command line in assembly and then in C, the BSD
    238 versions, the GNU tools, BusyBox...) but maybe toybox can do a better job. :)</p>
    239 
    240 <p>P.S.  How could I resist linking to an article about
    241 <a href=http://blog.outer-court.com/archive/2005-08-24-n14.html>why
    242 programmers should strive to be lazy and dumb</a>?</p>
    243 
    244 <b><h2>Portability issues</h2></b>
    245 
    246 <b><h3>Platforms</h3></b>
    247 <p>Toybox should run on Android (all commands with musl-libc, as large a subset
    248 as practical with bionic), and every other hardware platform Linux runs on.
    249 Other posix/susv4 environments (perhaps MacOS X or newlib+libgloss) are vaguely
    250 interesting but only if they're easy to support; I'm not going to spend much
    251 effort on them.</p>
    252 
    253 <p>I don't do windows.</p>
    254 
    255 <b><h3>32/64 bit</h3></b>
    256 <p>Toybox should work on both 32 bit and 64 bit systems.  By the end of 2008
    257 64 bit hardware will be the new desktop standard, but 32 bit hardware will
    258 continue to be important in embedded devices for years to come.</p>
    259 
    260 <p>Toybox relies on the fact that on any Unix-like platform, pointer and long
    261 are always the same size (on both 32 and 64 bit).  Pointer and int are _not_
    262 the same size on 64 bit systems, but pointer and long are.</p>
    263 
    264 <p>This is guaranteed by the LP64 memory model, a Unix standard (which Linux
    265 and MacOS X both implement, and which modern 64 bit processors such as
    266 x86-64 were <a href=http://www.pagetable.com/?p=6>designed for</a>).  See
    267 <a href=http://www.unix.org/whitepapers/64bit.html>the LP64 standard</a> and
    268 <a href=http://www.unix.org/version2/whatsnew/lp64_wp.html>the LP64
    269 rationale</a> for details.</p>
    270 
    271 <p>Note that Windows doesn't work like this, and I don't care.
    272 <a href=http://blogs.msdn.com/oldnewthing/archive/2005/01/31/363790.aspx>The
    273 insane legacy reasons why this is broken on Windows are explained here.</a></p>
    274 
    275 <b><h3>Signedness of char</h3></b>
    276 <p>On platforms like x86, variables of type char default to unsigned.  On
    277 platforms like arm, char defaults to signed.  This difference can lead to
    278 subtle portability bugs, and to avoid them we specify which one we want by
    279 feeding the compiler -funsigned-char.</p>
    280 
    281 <p>The reason to pick "unsigned" is that way we're 8-bit clean by default.</p>
    282 
    283 <p><h3>Error messages and internationalization:</h3></p>
    284 <p>Error messages are extremely terse not just to save bytes, but because we
    285 don't use any sort of _("string") translation infrastructure.</p>
    286 
    287 <p>Thus "bad -A '%c'" is
    288 preferable to "Unrecognized address base '%c'", because a non-english speaker
    289 can see that -A was the problem, and with a ~20 word english vocabulary is
    290 more likely to know (or guess) "bad" than the longer message.</p>
    291 
    292 <p>The help text might someday have translated versions, and strerror()
    293 messages produced by perror_exit() and friends can be expected to be
    294 localized by libc. Our error functions also prepend the command name,
    295 which non-english speakers can presumably recognize already.</p>
    296 
    297 <p>An enventual goal is <a href=http://yarchive.net/comp/linux/utf8.html>UTF-8</a> support, although it isn't a priority for the
    298 first pass of each command. (All commands should at least be 8-bit clean.)</p>
    299 
    300 <p>Locale support isn't currently a goal; that's a presentation layer issue,
    301 X11 or Dalvik's problem.</p>
    302 
    303 <a name="codestyle" />
    304 <h2>Coding style</h2>
    305 
    306 <p>The real coding style holy wars are over things that don't matter
    307 (whitespace, indentation, curly bracket placement...) and thus have no
    308 obviously correct answer. As in academia, "the fighting is so vicious because
    309 the stakes are so small". That said, being consistent makes the code readable,
    310 so here's how to make toybox code look like other toybox code.</p>
    311 
    312 <p>Toybox source uses two spaces per indentation level, and wraps at 80
    313 columns. (Indentation of continuation lines is awkward no matter what
    314 you do, sometimes two spaces looks better, sometimes indenting to the
    315 contents of a parentheses looks better.)</p>
    316 
    317 <p>There's a space after C flow control statements that look like functions, so
    318 "if (blah)" instead of "if(blah)". (Note that sizeof is actually an
    319 operator, so we don't give it a space for the same reason ++ doesn't get
    320 one. Yeah, it doesn't need the parentheses either, but it gets them.
    321 These rules are mostly to make the code look consistent, and thus easier
    322 to read.) We also put a space around assignment operators (on both sides),
    323 so "int x = 0;".</p>
    324 
    325 <p>Blank lines (vertical whitespace) go between thoughts. "We were doing that,
    326 now we're doing this. (Not a hard and fast rule about _where_ it goes,
    327 but there should be some.)"</p>
    328 
    329 <p>Variable declarations go at the start of blocks, with a blank line between
    330 them and other code. Yes, c99 allows you to put them anywhere, but they're
    331 harder to find if you do that. If there's a large enough distance between
    332 the declaration and the code using it to make you uncomfortable, maybe the
    333 function's too big, or is there an if statement or something you can
    334 use as an excuse to start a new closer block?</p>
    335 
    336 <p>If statments with a single line body go on the same line if the result
    337 fits in 80 columns, on a second line if it doesn't. We usually only use
    338 curly brackets if we need to, either because the body is multiple lines or
    339 because we need to distinguish which if an else binds to. Curly brackets go
    340 on the same line as the test/loop statement. The exception to both cases is
    341 if the test part of an if statement is long enough to split into multiple
    342 lines, then we put the curly bracket on its own line afterwards (so it doesn't
    343 get lost in the multple line variably indented mess), and we put it there
    344 even if it's only grouping one line (because the indentation level is not
    345 providing clear information in that case).</p>
    346 
    347 <p>I.E.</p>
    348 
    349 <blockquote>
    350 <pre>
    351 if (thingy) thingy;
    352 else thingy;
    353 
    354 if (thingy) {
    355   thingy;
    356   thingy;
    357 } else thingy;
    358 
    359 if (blah blah blah...
    360     && blah blah blah)
    361 {
    362   thingy;
    363 }
    364 </pre></blockquote>
    365 
    366 <p>Gotos are allowed for error handling, and for breaking out of
    367 nested loops. In general, a goto should only jump forward (not back), and
    368 should either jump to the end of an outer loop, or to error handling code
    369 at the end of the function. Goto labels are never indented: they override the
    370 block structure of the file. Putting them at the left edge makes them easy
    371 to spot as overrides to the normal flow of control, which they are.</p>
    372 
    373 <p>When there's a shorter way to say something, we tend to do that for
    374 consistency. For example, we tend to say "*blah" instead of "blah[0]" unless
    375 we're referring to more than one element of blah. Similarly, NULL is
    376 really just 0 (and C will automatically typecast 0 to anything, except in
    377 varargs), "if (function() != NULL)" is the same as "if (function())",
    378 "x = (blah == NULL);" is "x = !blah;", and so on.</p>
    379 
    380 <p>The goal is to be
    381 concise, not cryptic: if you're worried about the code being hard to
    382 understand, splitting it to multiple steps on multiple lines is
    383 better than a NOP operation like "!= NULL". A common sign of trying to
    384 hard is nesting ? : three levels deep, sometimes if/else and a temporary
    385 variable is just plain easier to read. If you think you need a comment,
    386 you may be right.</p>
    387 
    388 <p>Comments are nice, but don't overdo it. Comments should explain _why_,
    389 not how. If the code doesn't make the how part obvious, that's a problem with
    390 the code. Sometimes choosing a better variable name is more revealing than a
    391 comment. Comments on their own line are better than comments on the end of
    392 lines, and they usually have a blank line before them. Most of toybox's
    393 comments are c99 style // single line comments, even when there's more than
    394 one of them. The /* multiline */ style is used at the start for the metadata,
    395 but not so much in the code itself. They don't nest cleanly, are easy to leave
    396 accidentally unterminated, need extra nonfunctional * to look right, and if
    397 you need _that_ much explanation maybe what you really need is a URL citation
    398 linking to a standards document? Long comments can fall out of sync with what
    399 the code is doing. Comments do not get regression tested. There's no such
    400 thing as self-documenting code (if nothing else, code with _no_ comments
    401 is a bit unfriendly to new readers), but "chocolate sauce isn't the answer
    402 to bad cooking" either. Don't use comments as a crutch to explain unclear
    403 code if the code can be fixed.</p>
    404 
    405 <!--#include file="footer.html" -->
    406