Wednesday, October 28, 2009

C Bitfields and HW Registers

When I need a quick low-level programming "fix", I browse the archives at PageTable.com. Last week I read the post on Readable and Maintainable Bitfields in C which argued the merits of using bitfields over bitmasks+macros. Although I agree with the post's points I think it omitted one important detail - the danger of using bitfields with hardware registers.

Hardware registers can be mapped into a processor's memory space and accessed with standard memory read/write instructions. Therefore the temptation is to define a bitfield type representing a register's structure and set a pointer to its base memory address. For example, assuming register bar is four bytes wide, has five bit-fields, and is located at memory address 0xBAADF00D one might be tempted to do the following:

typedef struct {
    unsigned int f1:8;
    unsigned int f2:4;
    unsigned int f3:8;
    unsigned int f4:4;
    unsigned int f5:8;
  } registerBar_t;


// Set pointer to register's memory address
registerBar_t *pBar = 0xBAADF00D;

// Use pointer to access register
pBar->f1 = 0xFE;

One problem with this approach is that many registers are designed to be accessed only at their full size - all accesses must be aligned to the register's base address and read/write the whole thing. Unfortunately, the setting of f1 in the above example may produce a partial register write that can lead to unexpected and unintended results.

Another challenge when dealing with registers is that, unlike main memory, register accesses can have side effects. Even register reads can cause the hardware to initiate action or clear information. Consider the following example:

...
tmpf1 = pBar->f1;
tmpf2 = pBar->f2;
...

If reads of register bar are destructive causing its contents to be cleared then the read of f1 may clear the contents of f2 before it is read by the subsequent pointer dereference. The resulting loss of information could cause the driver, hardware, or both to behave unexpectedly.

Alternatively, if reads of register bar cause the hardware to initiate action then spurious activity may occur if the f1 and f2 accesses are done separately.

Because of these granularity and side effect issues, I was advised early in my career to avoid using bitfields with hardware registers. This is, I think, an important point that is captured in the PageTable.com post's comments but not in the post itself which is an unfortunate omission.

After reading the PageTable.com post, I realized that I always took this advice on faith and never looked at the instructions generated by bitfield accesses. So I decided to do a quick experiment, below is a short program that accesses a bitfield with fields of varying size and alignment.

#include <stdio.h>

typedef union {
  struct {
    unsigned int f1:8; // Bits 07:00
    unsigned int f2:4; // Bits 11:08
    unsigned int f3:8; // Bits 19:12
    unsigned int f4:4; // Bits 23:20
    unsigned int f5:8; // Bits 31:24
  };
  unsigned int raw;
} bitfield_t;


int main()
{
  bitfield_t bitfield;
  unsigned int tmp;

  bitfield.raw = 0x0;

  // Set bit field f1
  bitfield.f1 = 0xEF;
  tmp = bitfield.f1;
  printf(" After f1: F1(0x%02x) RAW(0x%08x)\n", 
         tmp,
         bitfield.raw);

  // Set bit field f2
  bitfield.f2 = 0xE;
  tmp = bitfield.f2;
  printf(" After f2: F2(0x%02x) RAW(0x%08x)\n", 
         tmp,
         bitfield.raw);

  // Set bit field f3
  bitfield.f3 = 0xDB;
  tmp = bitfield.f3;
  printf(" After f3: F3(0x%02x) RAW(0x%08x)\n", 
         tmp,
         bitfield.raw);

  // Set bit field f4
  bitfield.f4 = 0xA;
  tmp = bitfield.f4;
  printf(" After f4: F4(0x%02x) RAW(0x%08x)\n", 
         tmp,
         bitfield.raw);

  // Set bit field f5
  bitfield.f5 = 0xDE;
  tmp = bitfield.f5;
  printf(" After f5: F5(0x%02x) RAW(0x%08x)\n", 
         tmp,
         bitfield.raw);

  // Set with raw
  bitfield.raw = 0xDECAFBAD;
  tmp = bitfield.raw;
  printf("After raw: RAW(0x%08x)\n", 
         tmp);

  return 0;
}

Compiling and running this program on an Ubuntu system results in the expected output.

jcardent@ubuntu:~/tmp$ gcc -g -o foo foo.c 
jcardent@ubuntu:~/tmp$ ./foo 
 After f1: F1(0xef) RAW(0x000000ef)
 After f2: F2(0x0e) RAW(0x00000eef)
 After f3: F3(0xdb) RAW(0x000dbeef)
 After f4: F4(0x0a) RAW(0x00adbeef)
 After f5: F5(0xde) RAW(0xdeadbeef)
After raw: RAW(0xdecafbad)

Running the command

jcardent@ubuntu:~/tmp$ objdump -d -S foo 

reveals the instructions generated to access the bit-fields. Looking at the f1 write and read sequence shows:

  // Set bit field f1
  bitfield.f1 = 0xEF;
 80483dc:       c6 45 f8 ef        movb   $0xef,-0x8(%ebp)
  tmp = bitfield.f1;
 80483e0:       0f b6 45 f8        movzbl -0x8(%ebp),%eax
 80483e4:       0f b6 c0           movzbl %al,%eax
 80483e7:       89 45 f4           mov    %eax,-0xc(%ebp)

The first thing to note from this disassembly fragment is that bitfield is located on the stack eight bytes below %ebp. Likewise, tmp is located at offset 0xC.

From this example it's clear that the write to f1 uses a single byte move instruction. If bitfield had been mapped to a hardware register, this would have resulted in an aligned but too short write access that could have produced unintended behavior.

The read of f1 is less clear until the movzbl instruction is understood to be a move from a single byte to a word, four bytes in this case. So here again, if bitfield had been mapped to a register the single-byte access may have resulted in unintended behavior like dataloss (top three bytes cleared) or spurious action (if subsequent reads are done to other fields for the same operation).

Looking at the f2 write and read sequence shows:

 // Set bit field f2
  bitfield.f2 = 0xE;
 8048404:       0f b6 45 f9        movzbl -0x7(%ebp),%eax
 8048408:       83 e0 f0           and    $0xfffffff0,%eax
 804840b:       83 c8 0e           or     $0xe,%eax
 804840e:       88 45 f9           mov    %al,-0x7(%ebp)
  tmp = bitfield.f2;
 8048411:       0f b6 45 f9        movzbl -0x7(%ebp),%eax
 8048415:       83 e0 0f           and    $0xf,%eax
 8048418:       0f b6 c0           movzbl %al,%eax
 804841b:       89 45 f4           mov    %eax,-0xc(%ebp)

In this case, setting the four bit-wide field f2 results in a byte-wide read-modify-write sequence aligned with the second byte of bitfield, evidenced by the offset of 0x7 instead of 0x8. Similarly, reading f2 results in a byte-wide read aligned with the second byte of bitfield. Both accesses are too short and misaligned.

Since f3 spans bytes 2 and 3 of bitfield, its access sequence results in aligned, four byte-wide mov instructions.

  bitfield.f3 = 0xDB;
 8048438:       8b 45 f8           mov    -0x8(%ebp),%eax
 804843b:       25 ff 0f f0 ff     and    $0xfff00fff,%eax
 8048440:       0d 00 b0 0d 00     or     $0xdb000,%eax
 8048445:       89 45 f8           mov    %eax,-0x8(%ebp)
  tmp = bitfield.f3;
 8048448:       8b 45 f8           mov    -0x8(%ebp),%eax
 804844b:       c1 e8 0c           shr    $0xc,%eax
 804844e:       80 e4 ff           and    $0xff,%ah
 8048451:       0f b6 c0           movzbl %al,%eax
 8048454:       89 45 f4           mov    %eax,-0xc(%ebp)

Although the accesses themselves are well-formed, unintended behaviors can still result if f3 is only one of multiple fields that must be set for a single operation.

Since the structure of bitfield is symmetrical, the accesses to fields f4 and f5 produce instructions similar to those for f2 and f1 respectively albeit with different offsets.

Finally, the accesses to raw produce aligned, full-width instructions as expected.

  // Set with raw
  bitfield.raw = 0xDECAFBAD;
 80484cd:       c7 45 f8 ad fb ca de movl   $0xdecafbad,-0x8(%ebp)
  tmp = bitfield.raw;
 80484d4:       8b 45 f8           mov    -0x8(%ebp),%eax
 80484d7:       89 45 f4           mov    %eax,-0xc(%ebp)

This last example illustrates a tempting workaround for "safely" using bitfields to manage register accesses. Consider:

registerBar_t *pBar = 0xBAADF00D;
registerBar_t tmpBar;

// Set field f1 to 0xff
tmpBar.raw = pBar->raw;
tmpBar.f1  = 0xff;
pBar->raw  = tmpBar.raw;

While this approach works, it suffers the risk of an uninformed future maintainer "optimizing out" the temporary variable and just using the bitfield method directly. In this regard, it may be more maintainable to use bitmasks and macros for register accesses.

Of course, problems can arise regardless of the method used if "uninformed" developers are allowed to change the code. The only prevention here is to make sure there is suitable training and disciplined code reviews.

Thursday, October 22, 2009

Book Review: Coders At Work

Coders At Work: Reflections on the Craft of Programming by Peter Seibel

I really enjoyed this book. Peter Seibel did an outstanding job in selecting a group of interviewees that are both legendary and represent a wide range of programming domains. In addition, Peter's questions were similar enough to allow comparisons between responses but maintained a conversational flow that prevented the interviews from feeling formulaic. Ehud Lamm's quote from the font cover perhaps says it best, "reading this book may be the next best thing to chatting with these illustrious programmers in person".

I read the interviews out of order based on my interests. All were good but my favorite ones were (in no particular order):

One striking observation was how many of the interviewees fit into Malcolm Gladwell's definition of an Outlier. Nearly all of them had opportunities to get a significant amount of programming experience at a young age and serendipitously found jobs that provided the right environment for them to succeed.

I also found interesting the "organic" approach most of the interviewees took to programming. None seemed to rely on formalized best practices but instead used their intuition to tailor their approach based on the task at hand. To me this suggests that you just can't codify great programming which matches my experiences with the great programmers that I have known.

Finally, it's notable how many of the people interviewed either starting out hacking Lisp or were heavily influenced by it. Of course this may be due to selection bias given that the author, Peter Seibel, is a a Lisp hacker himself and wrote the outstanding book Practical Common Lisp. As a Lisp fan, I don't mind the potential bias; it's a feature, not a bug!

Wednesday, October 14, 2009

Favorite Innovation Resources

My company's annual innovation conference is today and I'll be participating in a panel of innovators. As a result, innovation is on my mind so I thought I would post my favorite innovation resources. Unfortunately, this is only a quick list of links as I don't have time to discuss in detail what I like about each resource. Perhaps this will be a theme for a future series of posts.

Innovation

  • The Innovator's Solution: sequel to The Innovator's Dilemma, I prefer this book as it discusses many secondary factors related to disruption and how to avoid it. Key points to me were transitions between tightly-integrated and modular architectures and avoiding products that are incremental innovations for incumbents.
  • Drucker's Innovation and Entrepreneurship: simply a great book that should be required reading for every innovator, entrepreneur, and executive manager. Based on my years of experience as an innovator within a large company I found Drucker's insights and advice to be relevant, pragmatic, and actionable. Given its publication date, it appears to me that this book served as the foundation for the "popular" innovation books of the 90's and beyond. Reading Drucker's book helped to provide more context for those later works. This book is well worth the time to read it.
  • The Doblin Group's Ten Types of Innovation: a great cheat-sheet summarizing the various forms of innovation. I have this hanging on my office wall at work.
  • Skate to Where the Money Will Be: perhaps one of the most important papers for any innovator to read, especially those involved in long term strategic planning for an established company.
  • Creating New Market Space: a great HBS article on systematic ways of identifying new market opportunities.
  • What is a Strategy: to some degree innovating is deeply tied to defining a strategy. As a result, it's important to understand what a strategy is and Porter is a leading thinker in this area.
  • The Myths of Innovation: a thought provoking book that dispels some of the myths surrounding innovation.
  • Serious Play: a decent book that makes the important point that sometimes a model or prototype is needed to serve as the catalyst and focal point for exploratory innovation. I've spent most of my engineering career building prototypes so I found this book to be a thoughtful resource.
  • The Power of Product Platforms: written by one of my MBA professors, this book introduces the concept of using modular architectures to build derivative products to serve different market segments. A powerful concept in my experience.
  • Eureka! It Really Takes Years of Hard Work: a nice New York Times article discussing the fact that innovation is often the result of a lot of hard work and not an instantaneous eureka moment.

Execution

  • Crossing the Chasm: Geoffrey Moore's classic book about making the transition from the early to mainstream markets. A lot of great advice for innovators.
  • Dealing with Darwin: another Moore classic, this one discusses how to structure an organization to maintain a pipeline of innovations and sustain corporate growth. A good read for anyone involved in maintaining an established business.
  • That Art of the Start: a great and inspiring book on starting a new venture. I particularly appreciated the no nonsense advice and strong focus on fundamentals. My bias towards the latter has always made me feel like a "pseudo-MBA" so Guy's advice increased my confidence in my own opinions in this area.

Creative Problem Solving

  • ThinkerToys: a great resource for creative thinking techniques.
  • Back of the Napkin: sometimes a whiteboard or pen+paper are the most powerful tools for communicating ideas and innovations. This book provides great tips on visual thinking and communication.
  • The Mind Map Book: I have found mind-mapping to be a very effective and powerful technique for creative thinking. Written by the one of the original proponents of mind-mapping, this is a good resource for learning how to create and use mind-maps.
  • How to think Like Einstein: despite the cheeky title this book contains useful tips on creative thinking.
  • How to Think Like Leonardo Da Vinci: same as the above, cheeky title but good advice.

As I mentioned, this is just a short list of the resources that I've found most useful. In future posts I may discuss these and other resources in more detail.

Friday, October 9, 2009

Book Review: Fortune's Formula

Fortune's Formula: The Untold Story of the Scientific Betting System that Beat the Casinos and Wall Street by William Poundstone

[Read in August of 2009 but was delayed in writing the review.]

I absolutely loved this book, in fact I more or less devoured it as it involved three topics that I find very interesting:

How can a book involving these three topics be anything but good!

OK, enough gushing, the book is essentially about the following three people:

  • Claude Shannon: Bell Labs super-genius most famous for creating the field of Information Theory but who also invented the use of boolean binary logic in digital computers, and made material contributions to the fields of Mendelian genetics, cryptography, and computational logistics.
  • John L. Kelley: Bell Labs scientist famous amongst geeks for programming an IBM 704 to sing the song Daisy Bell which inspired HAL-9000's song at the end of the movie 2001: A Space Odyssey. Kelly is also famous for using Shannon's Information Theory to create the Kelly Criterion method for optimal betting or investing given inside information.
  • Edward O. Thorpe: M.I.T. professor famous for writing the book Beat the Dealer which proved card counting could be used to win at Black Jack. Thorpe is also famous for pioneering the use of computers in hedge fund investing (a.k.a quantitative finance). Thorpe's fund, Princeton Newport Partners, achieved an impressive annualized return of 15.1% over its 19 year duration.

The story more or less goes thusly:

  • Shannon invents Information Theory
  • With Shannon's help Kelley uses Information Theory to create the Kelly Criterion for determining an optimal betting strategy given inside information.
  • After meeting at M.I.T., Shannon and Thorpe research ways of using wearable computers to win at roulette. Thorpe goes on to use the Kelly Criteria to first make optimal bets while card counting and later make profitable investments for his hedge fund.

The book focuses on how the interaction between these three men gave rise to much wealth. Along the way Poundstone discusses related topics such as Efficient Market Theory, the Random Walk Hypothesis, and statistical arbitrage. Poundstone includes just enough mathematics to make the story interesting to technical readers without alienating other audiences.

It must be noted that the book offers a much richer story including the influences of organized crime at various stages of history.

All in all, a great book that I highly recommend to anyone interested in these topics.

Book Review: Labyrinths of Reason

[Read in August of 2009 but was delayed in writing the review.]

Labyrinths of Reason: paradox, puzzles, and the frailty of knowledge by William Poundstone.

Ouch, my head hurts. How do we really know we're not just brains-in-vats living in a simulated reality?

This is more or less the central theme of the book which guides the reader through various thought experiments designed to probe the depths of meaning, understanding, and knowing. Along the way Poundstone discusses various topics such as:

I could go on but doing so would still do the book an injustice. It's a great book that covers a lot of interesting topics. Well worth reading if you are interested in these kinds of things but be prepared to get a few headaches from excessive thinking. I'm planning to re-read it perhaps a year from now to try to better absorb the material.

Book Review: Prisoner's Dilemma

[Read in August of 2009 but was delayed in writing the review.]

Prisoner's Dilemma: John Von Neumann, Game Theory, and the Puzzle of the Bomb by William Poundstone.

A book ostensibly about Game Theory, I felt that it was more of a montage of:

The Game Theory content was fascinating and informative covering various kinds of games, strategies, and complications stemming from repeated games. Good stuff.

I found the Von Neumann biography captivating as it provided a deeper insight into his personal nature than I had read before. Clearly he was an incredibly intelligent man but he also clearly had a number of personal challenges. While this material makes Von Neumann appear more "human", it's not particularly pleasant to read about. Also, I thought the account of his death from cancer was too detailed and grim.

Personally, I have no interest in the history of the RAND corporation or the cold war so I found these parts of the book difficult to get through. But others may find this material more interesting.

All in all, not a bad book if you're interested in these topics but I wouldn't recommend this for "feel good" reading.