{"id":77,"date":"2012-08-17T19:42:47","date_gmt":"2012-08-17T19:42:47","guid":{"rendered":"http:\/\/blog.mozilla.org\/nfroyd\/?p=77"},"modified":"2012-08-17T19:42:47","modified_gmt":"2012-08-17T19:42:47","slug":"moving-away-from-x-macros","status":"publish","type":"post","link":"https:\/\/blog.mozilla.org\/nfroyd\/2012\/08\/17\/moving-away-from-x-macros\/","title":{"rendered":"moving away from x-macros"},"content":{"rendered":"<p>In any large (and even many small) codebases, there comes a point where some knowledge about an entity X is needed at various points throughout the codebase, but the knowledge required at each point is ever-so-slightly different.\u00a0 You could provide comments at each point, stating the list of other locations that need to be updated appropriately when changes occur at that point, but that gets tedious quickly; it&#8217;s also error-prone, since it&#8217;s easy to forget the updating.\u00a0 One technique for handling this in Mozilla&#8217;s C++ codebase is known as X-macros: a header file filled with calls to some macro X:<\/p>\n<pre>X(name1, data1, ...)\r\nX(name2, data2, ...)\r\nX(name3, data3, ...)\r\n...<\/pre>\n<p>This header is then included at various points.\u00a0 At each point, X is defined to extract whatever data is necessary:<\/p>\n<pre>enum ID {\r\n#define X(name, data, size) name\r\n#include \"Xmacro_header.h\"\r\n#undef X\r\n};\r\n...\r\nstatic const uint32_t sizes[] = {\r\n#define X(name, data, size) size,\r\n#include \"Xmacro_header.h\"\r\n#undef X\r\n};\r\n...\r\nmethod(enum ID, ...)\r\n{\r\n  uint32_t size = sizes[ID];\r\n \u00a0...\r\n}<\/pre>\n<p>A prime example of this is the header <a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/source\/content\/events\/public\/nsEventNameList.h\">content\/events\/public\/nsEventNameList.h<\/a>, which gets included at various points for generating method declarations, method definitions, and name tables; we use a similar header <a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/source\/toolkit\/components\/telemetry\/TelemetryHistograms.h\">toolkit\/components\/telemetry\/TelemetryHistograms.h<\/a> for defining Telemetry histograms and the associated IDs those histograms are identified with.<\/p>\n<p>But we are moving away from this technique in Telemetry: we&#8217;re soon going <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=781531\">to define our histograms using JSON<\/a> and generate the necessary information from that JSON with Python scripts, rather than relying on the C preprocessor.<\/p>\n<p>The main motivation for doing this is validation: we don&#8217;t have anything on the server-side of Telemetry which defines schemas for Telemetry data.\u00a0 The client knows what are the bucket ranges for individual histograms, for instance, but the server doesn&#8217;t.\u00a0 So the server has to accept all kinds of bogus data, whereas it could reject that data if some sort of schema for the data was provided.\u00a0 And generating that information is (relatively) more easily done from a JSON definition than from a C preprocessor definition.<\/p>\n<p>Some forms of client-side validation are eased by this process as well.\u00a0 For example, there&#8217;s a quirk in how &#8220;linear&#8221; histograms are defined that <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=763359\">makes it easy to lose data<\/a> when trying to capture data than runs from 1 to N.\u00a0 There are <a href=\"http:\/\/mxr.mozilla.org\/mozilla-central\/source\/toolkit\/components\/telemetry\/TelemetryHistograms.h#23\">ways around this<\/a>, but they don&#8217;t always get used properly.\u00a0 With the histograms defined in JSON, we can make this sort of &#8220;enumerated&#8221; histogram a first class citizen and error on misdefinitions of &#8220;linear&#8221; histograms for capturing enumerated data.<\/p>\n<p>Other future enhancements are also easier to do when you&#8217;re not limited by the C preprocessor, like <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=748444\">eliminating relocations<\/a> (and generally making the histogram information take up less space in the binary), <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=778123\">automating field trials<\/a>, providing labels for individual buckets, and so forth.\u00a0 There are some downsides, notably that defining related histograms can&#8217;t be done with a little <tt>#define<\/tt> trickery, but the benefits more than make up for it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In any large (and even many small) codebases, there comes a point where some knowledge about an entity X is needed at various points throughout the codebase, but the knowledge required at each point is ever-so-slightly different.\u00a0 You could provide comments at each point, stating the list of other locations that need to be updated [&hellip;]<\/p>\n","protected":false},"author":320,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/posts\/77"}],"collection":[{"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/users\/320"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/comments?post=77"}],"version-history":[{"count":0,"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/posts\/77\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/media?parent=77"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/categories?post=77"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mozilla.org\/nfroyd\/wp-json\/wp\/v2\/tags?post=77"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}