<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>The Electric Cloud Blog</title>
	<atom:link href="http://blog.electric-cloud.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.electric-cloud.com</link>
	<description>This is your source for software build-test-deploy best practices and technical tips and tricks for Electric Cloud solutions</description>
	<lastBuildDate>Mon, 08 Mar 2010 17:51:16 +0000</lastBuildDate>
	<generator>http://wordpress.com/</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<cloud domain='blog.electric-cloud.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://www.gravatar.com/blavatar/69f9c69836db8c4404b635236f654808?s=96&#038;d=http://s2.wp.com/i/buttonw-com.png</url>
		<title>The Electric Cloud Blog</title>
		<link>http://blog.electric-cloud.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://blog.electric-cloud.com/osd.xml" title="The Electric Cloud Blog" />
	<atom:link rel='hub' href='http://blog.electric-cloud.com/?pushpress=hub'/>
		<item>
		<title>How scalable is SCons?</title>
		<link>http://blog.electric-cloud.com/2010/03/08/how-scalable-is-scons/</link>
		<comments>http://blog.electric-cloud.com/2010/03/08/how-scalable-is-scons/#comments</comments>
		<pubDate>Mon, 08 Mar 2010 17:46:39 +0000</pubDate>
		<dc:creator>Eric Melski</dc:creator>
				<category><![CDATA[ElectricAccelerator]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[scons]]></category>

		<guid isPermaLink="false">http://blog.electric-cloud.com/?p=625</guid>
		<description><![CDATA[The marquee feature in ElectricAccelerator 5.0 is Electrify, a new front-end to the Accelerator cluster that allows us to distribute work from a wide variety of processes in addition to the make-based processes that we have always managed.  One example is SCons, an alternative build system implemented in Python that has a small (compared [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.electric-cloud.com&blog=5211544&post=625&subd=ecloud&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>The marquee feature in ElectricAccelerator 5.0 is <i>Electrify</i>, a new front-end to the Accelerator cluster that allows us to distribute work from a wide variety of processes in addition to the make-based processes that we have always managed.  One example is <a href="http://www.scons.org/">SCons</a>, an alternative build system implemented in Python that has a small (compared to make) but apparently growing (slowly) market share.  It&#8217;s sometimes touted as <a href="http://freshmeat.net/articles/stop-the-autoconf-insanity-why-we-need-a-new-build-system">an ideal replacement for make</a>, with a <a href="http://scons.org">long list of reasons why it is considered superior</a>.  But not everybody likes it.  Some have reported <a href="http://gamesfromwithin.com/bad-news-for-scons-fans">significant performance problems</a>.  Even the SCons maintainers agree, SCons <a href="http://scons.org/wiki/SconsVsOtherBuildTools">&#8220;Can get slow on big projects&#8221;</a>.</p>
<p>
Of course that caught my eye, since making big projects build fast is what I do.  What exactly does it mean that SCons &#8220;can get slow&#8221; on &#8220;big&#8221; projects?  How slow is slow?  How big is big?  So to satisfy my own curiosity, and so that I might better advise customers seeking to use SCons with Electrify, I set out to answer those questions.  All I needed was some free hardware and some time.  <i>Lots and lots and lots of time.</i>
</p>
<p>
<span id="more-625"></span></p>
<h3>The Setup</h3>
</p>
<p>
My test environment was as follows:
</p>
<ul>
<li>RedHat Desktop 3 (kernel version 2.4.21-58.ELsmp)</li>
<li>Dual 2.4 GHz Intel Xeon with hyperthreading enabled</li>
<li>2 GB RAM</li>
<li>SCons v1.2.0.r3842</li>
<li>Python 2.6.2</li>
</ul>
<p>
The test build consists of (a lot of) compiles and links.  Starting from the bottom, we have <i>N</i> C files each with a unique associated header file.  The C files and headers were spread across <i>N/500</i> directories in order to eliminate filesystem scalability concerns.  Both the C files and the header files are trivial:  the header only includes stdio.h; the C file includes the associated header and a second, shared header, then defines a trivial function.  Objects are collected into groups of 20 and stored into a standard archive.  Every 20th object is linked into an executable along with the archive.  The build is generated using a script written by one of our talented QA engineers for testing Accelerator.
</p>
<p><h3>Overall build time</h3>
</p>
<p>
The primary concern was naturally end-to-end build time for a from-scratch build.  I used the standard Linux <i>time</i> utility to capture this data, and averaged the results from two runs (except for the build with 40,000 C files, because that just took too long):
</p>
<p>
<a href="http://ecloud.files.wordpress.com/2010/03/graph.png"><img src="http://ecloud.files.wordpress.com/2010/03/graph.png?w=300&#038;h=180" alt="Overall build time" title="graph" width="300" height="180" class="aligncenter size-medium wp-image-626" /></a>
</p>
<p>
That doesn&#8217;t look too good!  In fact, that curve looks suspiciously like the function <i>f(x) = x<sup>2</sup></i>.  Let&#8217;s plot that on our graph:
</p>
<p>
<a href="http://ecloud.files.wordpress.com/2010/03/graph_with_xsquared.png"><img src="http://ecloud.files.wordpress.com/2010/03/graph_with_xsquared.png?w=300&#038;h=180" alt="Overall build time compared to x-squared growth" title="graph_with_xsquared" width="300" height="180" class="aligncenter size-medium wp-image-627" /></a>
</p>
<p>
That looks like a pretty close fit &mdash; so it seems that the build duration increases in proportion to the square of the number of input files.  That&#8217;s bad news &mdash; as you can see, that very quickly adds up to outrageously long build times.
</p>
<p><h3>Ruling out other causes</h3>
</p>
<p>
It&#8217;s possible that this performance degradation is due to some factor other than SCons.  To rule out that possibility, I created a shell script that runs the exact set of commands, in the same order, that the SCons-based build had, and timed the execution of that script.  The work done by that script is the <i>actual work</i> of the build:  the bare minimum that must be done to compile and link all of the source files.  By definition, everything else is overhead.  Let&#8217;s add that data to the graph:
</p>
<p>
<a href="http://ecloud.files.wordpress.com/2010/03/graph_with_shell.png"><img src="http://ecloud.files.wordpress.com/2010/03/graph_with_shell.png?w=300&#038;h=180" alt="Overall build time compared to actual work" title="graph_with_shell" width="300" height="180" class="aligncenter size-medium wp-image-628" /></a>
</p>
<p>
As expected, the time needed for the actual work grows linearly in proportion to the number of C files in the build.  That means that the performance degradation is not due to some other component of the system &mdash; if it were, we would have seen a similar problem with the simple shell script.  Instead, the problem is clearly in SCons itself.
</p>
<p><h3>Comparing overhead to actual work</h3>
<p>Now that we know the amount of time for the actual work, we can compute the amount of time spent on overhead introduced by SCons &mdash; that&#8217;s just the difference between the &#8220;overall build time&#8221; and the &#8220;actual work&#8221; lines in our graph.  For example, with 40,000 C files, the SCons build time is about 4 1/2 hours; the actual work time is about 25 minutes.  SCons is adding more than <b>four hours  of overhead</b> to the build!
</p>
<p>
Let&#8217;s put that into terms that are a little easier to grok:  rather than looking at the absolute numbers, we&#8217;ll look at the overhead as a percentage of the total build time.
</p>
<p>
<a href="http://ecloud.files.wordpress.com/2010/03/overhead.png"><img src="http://ecloud.files.wordpress.com/2010/03/overhead.png?w=300&#038;h=180" alt="Overhead from SCons as a percentage of overall build time" title="overhead" width="300" height="180" class="aligncenter size-medium wp-image-629" /></a>
</p>
<p>
Even with only a few hundred files, SCons overhead represents 50% of the total build time; with 10,000 C files, SCons overhead represents 75% of the total build time; and with 40,000 C files, SCons overhead accounts for a whopping 90% of the total time!
</p>
<p><h3>Memory usage</h3>
</p>
<p>
The final metric that I tracked was SCons memory utilization, using the built-in <i>&#8211;debug=memory</i> flag.  This metric is of particular interest to me, since I&#8217;ve spent a lot of time streamlining Accelerator&#8217;s memory usage so that it can accommodate truly enormous builds (millions of compiles).  After the disastrous build time results, I was relieved to see that memory usage seems to grow linearly with the number of source files in the build (NB:  here I&#8217;m counting <i>total</i> source files, including both C files and headers, not only C files):
</p>
<p>
<a href="http://ecloud.files.wordpress.com/2010/03/memory.png"><img src="http://ecloud.files.wordpress.com/2010/03/memory.png?w=300&#038;h=180" alt="SCons memory usage" title="memory" width="300" height="180" class="aligncenter size-medium wp-image-630" /></a>
</p>
<p>
Unfortunately, although the growth is linear, the rate of growth is quite high: each additional source file adds more than 19,000 bytes (!) to the memory footprint.  At that rate, SCons will exhaust the available memory address space for a 32-bit process at only about 110,000 total source files.
</p>
<p><h3>Conclusions</h3>
</p>
<p>
These results paint a pretty grim picture for SCons:  based on the overall build times, I can&#8217;t imagine anybody seriously using SCons for builds with more than a couple thousand files.  And even if you were willing to put up with the long builds, the memory usage data indicates that SCons has a hard limit of around 110,000 total source files.
</p>
<p>
Are there any SCons experts out there able to explain why SCons seems to perform so badly here?</p>
<br />Filed under: <a href='http://blog.electric-cloud.com/category/electricaccelerator/'>ElectricAccelerator</a>, <a href='http://blog.electric-cloud.com/category/software-development/'>Software Development</a> Tagged: <a href='http://blog.electric-cloud.com/tag/electricaccelerator/'>ElectricAccelerator</a>, <a href='http://blog.electric-cloud.com/tag/performance/'>performance</a>, <a href='http://blog.electric-cloud.com/tag/scons/'>scons</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/ecloud.wordpress.com/625/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/ecloud.wordpress.com/625/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/ecloud.wordpress.com/625/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/ecloud.wordpress.com/625/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/ecloud.wordpress.com/625/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/ecloud.wordpress.com/625/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/ecloud.wordpress.com/625/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/ecloud.wordpress.com/625/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/ecloud.wordpress.com/625/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/ecloud.wordpress.com/625/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.electric-cloud.com&blog=5211544&post=625&subd=ecloud&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://blog.electric-cloud.com/2010/03/08/how-scalable-is-scons/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/6344c5478a4b5f0e8c546c736b2a7e0d?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=PG" medium="image">
			<media:title type="html">ericm</media:title>
		</media:content>

		<media:content url="http://ecloud.files.wordpress.com/2010/03/graph.png?w=300" medium="image">
			<media:title type="html">graph</media:title>
		</media:content>

		<media:content url="http://ecloud.files.wordpress.com/2010/03/graph_with_xsquared.png?w=300" medium="image">
			<media:title type="html">graph_with_xsquared</media:title>
		</media:content>

		<media:content url="http://ecloud.files.wordpress.com/2010/03/graph_with_shell.png?w=300" medium="image">
			<media:title type="html">graph_with_shell</media:title>
		</media:content>

		<media:content url="http://ecloud.files.wordpress.com/2010/03/overhead.png?w=300" medium="image">
			<media:title type="html">overhead</media:title>
		</media:content>

		<media:content url="http://ecloud.files.wordpress.com/2010/03/memory.png?w=300" medium="image">
			<media:title type="html">memory</media:title>
		</media:content>
	</item>
		<item>
		<title>Automating around scarcity by using virtual resources</title>
		<link>http://blog.electric-cloud.com/2010/01/28/automating-around-scarcity-by-using-virtual-resources/</link>
		<comments>http://blog.electric-cloud.com/2010/01/28/automating-around-scarcity-by-using-virtual-resources/#comments</comments>
		<pubDate>Thu, 28 Jan 2010 23:19:47 +0000</pubDate>
		<dc:creator>Erin Curtis</dc:creator>
				<category><![CDATA[Build-Test-Deploy Best Practices]]></category>
		<category><![CDATA[ElectricCommander]]></category>
		<category><![CDATA[Virtualization]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[resource management]]></category>

		<guid isPermaLink="false">http://blog.electric-cloud.com/?p=621</guid>
		<description><![CDATA[[posted on behalf of Usman Muzaffar, who is on a long flight with no WiFi]
Here&#8217;s a sobering truth that shows up often in software automation: people are way better at sharing stuff than computers are. For example: say you have a scarce resource, like a box with special hardware or a service with serial access. [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.electric-cloud.com&blog=5211544&post=621&subd=ecloud&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>[posted on behalf of Usman Muzaffar, who is on a long flight with no WiFi]</p>
<p>Here&#8217;s a sobering truth that shows up often in software automation: people are way better at sharing stuff than computers are. For example: say you have a scarce resource, like a box with special hardware or a service with serial access. You&#8217;re tasked with automating a software build/test/release workflow, and part of it needs to talk to this One Big And Fancy Thing. Do you try to teach your build script good playground behavior, so it automatically knows when to wait politely (and when, as deadlines approach, it should bully its way to the top of the slide), or do you declare this problem out-of-scope, and just provide the hook to let the team manage access manually?</p>
<p>The default on that checkbox is: *don&#8217;t automate*, for two reasons. First: letting people handle it means no extra work. More importantly, because we&#8217;ve been doing it our whole life, we&#8217;re actually pretty good at adapting to environments where we have to share things, whether that&#8217;s roads or restrooms or rack space. A small number of people on the same team with similar goals will usual self-organize around a few ground rules with a minimum of fuss. One clear and crisply delivered directive at a weekly team meeting (&#8220;OK guys the new 32-way sol box is for the full server test suite, so give that priority and check with each other before you use it for other stuff&#8221;) is often all it takes.</p>
<p>Second, technically getting the semantics of shared simultaneous access right is a notorious pain in the neck. As in any software automation system, there&#8217;s no credit for a partial answer: it&#8217;s a net loss if your script still needs a babysitter for the corner cases. So that means your solution needs to take selection and queuing and load into account, and have mechanisms for priority and pre-emption and be smart about busted network connections. More fundamentally, at its core it usually boils down to something awfully close to multithreaded programming, with the usual challenges in that space around semaphores, locks, deadlocks, races. Great stuff in a CS course or maybe your server&#8217;s ConnectionPool class &#8212; rathole alert in your build and test system!</p>
<p>So, largely with good reason, the automation train comes to a screeching halt right here. It&#8217;s just not worth the effort to build a system that&#8217;s going to manage the synchronization for parallel access to scarce resources. In other words: when shared resources wind up in the software production system, people show up next to them, and that sucks all the fun (and potential efficiency gains) out of automation. What to do?</p>
<p>One thing worth investigating are tools that can handle this for you.  Solving this was a key goal for our ElectricCommander product. Commander lets you describe your job as a series of command line steps, and each step can be specified to run on a resource. A resource is simply a system that we&#8217;ll remotely execute commands on, and it comes with a sack full of infrastructure goodies you&#8217;d expect like pooling, exclusive reservation, broadcast, security, access control, load balancing, and fault tolerance. As a user of the system, you specify what you want to run, and where you want to run it, press the &#8216;Go&#8217; button and Commander does the rest, queuing steps when resources are oversubscribed and efficiently scheduling around your other constraints. Nice!</p>
<p>Then one day a customer asked us how they could automatically control access to a piece of hardware that simulated network traffic critical to the product&#8217;s system test. This wasn&#8217;t a gadget we could install software on; indeed, we couldn&#8217;t directly connect to it at all, so Commander can’t treat it as a resource. But it soon became evident that we could solve this just as elegantly with a simple tweak to the approach. Fundamentally, we needed the ability to specify that a step 1) needed access, 2) must block when it wasn&#8217;t available, and 3) once acquired, hang on to it until it was done. If something could just take care of this synchronization and queuing, the test could connect to the traffic simulator directly and simply execute as if invoked manually.</p>
<p>In other words: the problem called for a *subset* of Commander resources;  ignore half the stuff in the goodie sack (remote login, execution, fault tolerance, etc.) and you&#8217;re left with a general purpose resource access and acquisition facility. We set up dummy resources (good old 127.0.0.1, always up and ready for this sort of game!), injected them into the workflow and configured the job to hang on to them as long as it was talking to the traffic simulator. It worked beautifully: each test run was guaranteed to get just the access it needed, and for the first time, the customer had safe, parallel end-to-end automation for the full test cycle.</p>
<p>More importantly, this design pattern, since dubbed Virtual Resources, opened a whole new realm of possibilities. Once you start looking for them, there are *lots* of shared things in a software system that aren&#8217;t compute hosts, and they&#8217;re all threatening or overcomplicating automation in some way or another.  We&#8217;ve used Virtual Resources to manage access database tables, SCM labels, virtual machines, filesystem repositories, flaky external systems that don&#8217;t like more than one client talking to them, and our customers keep showing us new ways. It&#8217;s a great example of how the core of a clean design &#8212; a resource is something a job can request and relinquish &#8212; was readily adapted to a wider set of problems around Software Production Automation.</p>
<br />Filed under: <a href='http://blog.electric-cloud.com/category/build-test-deploy-best-practices/'>Build-Test-Deploy Best Practices</a>, <a href='http://blog.electric-cloud.com/category/electriccommander/'>ElectricCommander</a>, <a href='http://blog.electric-cloud.com/category/virtualization/'>Virtualization</a> Tagged: <a href='http://blog.electric-cloud.com/tag/automation/'>automation</a>, <a href='http://blog.electric-cloud.com/tag/resource-management/'>resource management</a>, <a href='http://blog.electric-cloud.com/tag/virtualization/'>Virtualization</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/ecloud.wordpress.com/621/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/ecloud.wordpress.com/621/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/ecloud.wordpress.com/621/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/ecloud.wordpress.com/621/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/ecloud.wordpress.com/621/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/ecloud.wordpress.com/621/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/ecloud.wordpress.com/621/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/ecloud.wordpress.com/621/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/ecloud.wordpress.com/621/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/ecloud.wordpress.com/621/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.electric-cloud.com&blog=5211544&post=621&subd=ecloud&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://blog.electric-cloud.com/2010/01/28/automating-around-scarcity-by-using-virtual-resources/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/a900e4b0e626e3038848af796256a60c?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=PG" medium="image">
			<media:title type="html">ec</media:title>
		</media:content>
	</item>
		<item>
		<title>How to quickly navigate an unfamiliar makefile</title>
		<link>http://blog.electric-cloud.com/2009/11/10/how-to-quickly-navigate-an-unfamiliar-makefile/</link>
		<comments>http://blog.electric-cloud.com/2009/11/10/how-to-quickly-navigate-an-unfamiliar-makefile/#comments</comments>
		<pubDate>Tue, 10 Nov 2009 18:21:37 +0000</pubDate>
		<dc:creator>Eric Melski</dc:creator>
				<category><![CDATA[ElectricAccelerator]]></category>
		<category><![CDATA[SparkBuild]]></category>
		<category><![CDATA[annotation]]></category>
		<category><![CDATA[makefile]]></category>

		<guid isPermaLink="false">http://blog.electric-cloud.com/?p=610</guid>
		<description><![CDATA[The other day, I was working with an unfamiliar build and I needed to get familiar with it in a hurry.  In this case, I was dealing with a makefile generated by the Perl utility h2xs, but the trick I&#8217;ll show you here works any time you need to find your way around a [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.electric-cloud.com&blog=5211544&post=610&subd=ecloud&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>The other day, I was working with an unfamiliar build and I needed to get familiar with it in a hurry.  In this case, I was dealing with a makefile generated by the Perl utility <i>h2xs</i>, but the trick I&#8217;ll show you here works any time you need to find your way around a new build system, whether it&#8217;s something you just downloaded or an internal project you just transferred to.</p>
<p>
What I wanted to do was add a few object files to the link command.  Here&#8217;s the build log, with the link command highlighted:
</p>
<p><pre style="font:80% courier, verdana, monospace;border:1px solid #ccc;width:90%;background:#fff7f0;color:#000;overflow:auto;margin:1em auto 2em;padding:1em;">gcc -c  -I. -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -O2 -g   -DVERSION=\"0.01\" -DXS_VERSION=\"0.01\" -fPIC "-I/usr/lib/perl/5.10/CORE"   mylib.c
rm -f blib/arch/auto/mylib/mylib.so
<font color="red"><b>gcc  -shared -O2 -g -L/usr/local/lib mylib.o   -o blib/arch/auto/mylib/mylib.so   \
                \
</b></font>
chmod 755 blib/arch/auto/mylib/mylib.so
</pre>
</p>
<p>
Should be easy, right?  I just needed to find that command in the makefile and make my changes.  Wrong.  Read on to see how <i>annotation</i> helped solve this problem.
</p>
<p>
<span id="more-610"></span><br />
The thing is, the command I&#8217;m looking for doesn&#8217;t appear anywhere in the makefile.  All of the rules look like this:
</p>
<p><pre style="font:80% courier, verdana, monospace;border:1px solid #ccc;width:90%;background:#fff7f0;color:#000;overflow:auto;margin:1em auto 2em;padding:1em;">$(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.c</pre>
</p>
<p>
There&#8217;s not a single useful literal string in sight, so <i>grep</i> is right out.  And it&#8217;s not like you could just start reading the makefile top-to-bottom to figure out which variables contribute to the command line that produces the output that you see in the log.  The makefile is nearly a thousand lines long with literally hundreds of variable definitions:
</p>
<p><pre style="font:80% courier, verdana, monospace;border:1px solid #ccc;width:90%;height:30ex;background:#fff7f0;color:#000;overflow:auto;margin:1em auto 2em;padding:1em;"># This Makefile is for the mylib extension to perl.
#
# It was generated automatically by MakeMaker version
# 6.42 (Revision: 41145) from the contents of
# Makefile.PL. Don't edit this file, edit Makefile.PL instead.
#
#       ANY CHANGES MADE HERE WILL BE LOST!
#
#   MakeMaker ARGV: ()
#
#   MakeMaker Parameters:

#     ABSTRACT_FROM =&gt; q[lib/mylib.pm]
#     AUTHOR =&gt; q[Eric Melski ]
#     DEFINE =&gt; q[]
#     INC =&gt; q[-I.]
#     LIBS =&gt; [q[]]
#     NAME =&gt; q[mylib]
#     PREREQ_PM =&gt; {  }
#     VERSION_FROM =&gt; q[lib/mylib.pm]

# --- MakeMaker post_initialize section:

# --- MakeMaker const_config section:

# These definitions are from config.sh (via /usr/lib/perl/5.10/Config.pm)

# They may have been overridden via Makefile.PL or on the command line
AR = ar
CC = gcc
CCCDLFLAGS = -fPIC
CCDLFLAGS = -Wl,-E
DLEXT = so
DLSRC = dl_dlopen.xs
EXE_EXT =
FULL_AR = /usr/bin/ar
LD = gcc
LDDLFLAGS = -shared -O2 -g -L/usr/local/lib
LDFLAGS =  -L/usr/local/lib
LIBC = /lib/libc-2.9.so
LIB_EXT = .a
OBJ_EXT = .o
OSNAME = linux
OSVERS = 2.6.24-23-server
RANLIB = :
SITELIBEXP = /usr/local/share/perl/5.10.0
SITEARCHEXP = /usr/local/lib/perl/5.10.0
SO = so
VENDORARCHEXP = /usr/lib/perl5
VENDORLIBEXP = /usr/share/perl5

# --- MakeMaker constants section:
AR_STATIC_ARGS = cr
DIRFILESEP = /
DFSEP = $(DIRFILESEP)
NAME = mylib
NAME_SYM = mylib
VERSION = 0.01
VERSION_MACRO = VERSION
VERSION_SYM = 0_01
DEFINE_VERSION = -D$(VERSION_MACRO)=\"$(VERSION)\"
XS_VERSION = 0.01
XS_VERSION_MACRO = XS_VERSION
XS_DEFINE_VERSION = -D$(XS_VERSION_MACRO)=\"$(XS_VERSION)\"
INST_ARCHLIB = blib/arch
INST_SCRIPT = blib/script
INST_BIN = blib/bin
INST_LIB = blib/lib
INST_MAN1DIR = blib/man1
INST_MAN3DIR = blib/man3
MAN1EXT = 1p
MAN3EXT = 3pm
INSTALLDIRS = site
DESTDIR =
PREFIX = /usr
PERLPREFIX = $(PREFIX)
SITEPREFIX = $(PREFIX)/local
VENDORPREFIX = $(PREFIX)
INSTALLPRIVLIB = $(PERLPREFIX)/share/perl/5.10
DESTINSTALLPRIVLIB = $(DESTDIR)$(INSTALLPRIVLIB)
INSTALLSITELIB = $(SITEPREFIX)/share/perl/5.10.0
DESTINSTALLSITELIB = $(DESTDIR)$(INSTALLSITELIB)
INSTALLVENDORLIB = $(VENDORPREFIX)/share/perl5
DESTINSTALLVENDORLIB = $(DESTDIR)$(INSTALLVENDORLIB)
INSTALLARCHLIB = $(PERLPREFIX)/lib/perl/5.10
DESTINSTALLARCHLIB = $(DESTDIR)$(INSTALLARCHLIB)
INSTALLSITEARCH = $(SITEPREFIX)/lib/perl/5.10.0
DESTINSTALLSITEARCH = $(DESTDIR)$(INSTALLSITEARCH)
INSTALLVENDORARCH = $(VENDORPREFIX)/lib/perl5
DESTINSTALLVENDORARCH = $(DESTDIR)$(INSTALLVENDORARCH)
INSTALLBIN = $(PERLPREFIX)/bin
DESTINSTALLBIN = $(DESTDIR)$(INSTALLBIN)
INSTALLSITEBIN = $(SITEPREFIX)/bin
DESTINSTALLSITEBIN = $(DESTDIR)$(INSTALLSITEBIN)
INSTALLVENDORBIN = $(VENDORPREFIX)/bin
DESTINSTALLVENDORBIN = $(DESTDIR)$(INSTALLVENDORBIN)
INSTALLSCRIPT = $(PERLPREFIX)/bin
DESTINSTALLSCRIPT = $(DESTDIR)$(INSTALLSCRIPT)
INSTALLSITESCRIPT = $(SITEPREFIX)/bin
DESTINSTALLSITESCRIPT = $(DESTDIR)$(INSTALLSITESCRIPT)
INSTALLVENDORSCRIPT = $(VENDORPREFIX)/bin
DESTINSTALLVENDORSCRIPT = $(DESTDIR)$(INSTALLVENDORSCRIPT)
INSTALLMAN1DIR = $(PERLPREFIX)/share/man/man1
DESTINSTALLMAN1DIR = $(DESTDIR)$(INSTALLMAN1DIR)
INSTALLSITEMAN1DIR = $(SITEPREFIX)/man/man1
DESTINSTALLSITEMAN1DIR = $(DESTDIR)$(INSTALLSITEMAN1DIR)
INSTALLVENDORMAN1DIR = $(VENDORPREFIX)/share/man/man1
DESTINSTALLVENDORMAN1DIR = $(DESTDIR)$(INSTALLVENDORMAN1DIR)
INSTALLMAN3DIR = $(PERLPREFIX)/share/man/man3
DESTINSTALLMAN3DIR = $(DESTDIR)$(INSTALLMAN3DIR)
INSTALLSITEMAN3DIR = $(SITEPREFIX)/man/man3
DESTINSTALLSITEMAN3DIR = $(DESTDIR)$(INSTALLSITEMAN3DIR)
INSTALLVENDORMAN3DIR = $(VENDORPREFIX)/share/man/man3
DESTINSTALLVENDORMAN3DIR = $(DESTDIR)$(INSTALLVENDORMAN3DIR)
PERL_LIB = /usr/share/perl/5.10
PERL_ARCHLIB = /usr/lib/perl/5.10
LIBPERL_A = libperl.a
FIRST_MAKEFILE = Makefile
MAKEFILE_OLD = Makefile.old
MAKE_APERL_FILE = Makefile.aperl
PERLMAINCC = $(CC)
PERL_INC = /usr/lib/perl/5.10/CORE
PERL = /usr/bin/perl
FULLPERL = /usr/bin/perl
ABSPERL = $(PERL)
PERLRUN = $(PERL)
FULLPERLRUN = $(FULLPERL)
ABSPERLRUN = $(ABSPERL)
PERLRUNINST = $(PERLRUN) "-I$(INST_ARCHLIB)" "-I$(INST_LIB)"
FULLPERLRUNINST = $(FULLPERLRUN) "-I$(INST_ARCHLIB)" "-I$(INST_LIB)"
ABSPERLRUNINST = $(ABSPERLRUN) "-I$(INST_ARCHLIB)" "-I$(INST_LIB)"
PERL_CORE = 0
PERM_RW = 644
PERM_RWX = 755

MAKEMAKER   = /usr/share/perl/5.10/ExtUtils/MakeMaker.pm
MM_VERSION  = 6.42
MM_REVISION = 41145

# FULLEXT = Pathname for extension directory (eg Foo/Bar/Oracle).
# BASEEXT = Basename part of FULLEXT. May be just equal FULLEXT. (eg Oracle)
# PARENT_NAME = NAME without BASEEXT and no trailing :: (eg Foo::Bar)
# DLBASE  = Basename part of dynamic library. May be just equal BASEEXT.
MAKE = make
FULLEXT = mylib
BASEEXT = mylib
PARENT_NAME =
DLBASE = $(BASEEXT)
VERSION_FROM = lib/mylib.pm
INC = -I.
DEFINE =
OBJECT = $(BASEEXT)$(OBJ_EXT)
LDFROM = $(OBJECT)
LINKTYPE = dynamic
BOOTDEP = 

# Handy lists of source code files:
XS_FILES = mylib.xs
C_FILES  = mylib.c
O_FILES  = mylib.o
H_FILES  = ppport.h
MAN1PODS =
MAN3PODS = lib/mylib.pm

# Where is the Config information that we are using/depend on
CONFIGDEP = $(PERL_ARCHLIB)$(DFSEP)Config.pm $(PERL_INC)$(DFSEP)config.h

# Where to build things
INST_LIBDIR      = $(INST_LIB)
INST_ARCHLIBDIR  = $(INST_ARCHLIB)

INST_AUTODIR     = $(INST_LIB)/auto/$(FULLEXT)
INST_ARCHAUTODIR = $(INST_ARCHLIB)/auto/$(FULLEXT)

INST_STATIC      = $(INST_ARCHAUTODIR)/$(BASEEXT)$(LIB_EXT)
INST_DYNAMIC     = $(INST_ARCHAUTODIR)/$(DLBASE).$(DLEXT)
INST_BOOT        = $(INST_ARCHAUTODIR)/$(BASEEXT).bs

# Extra linker info
EXPORT_LIST        =
PERL_ARCHIVE       =
PERL_ARCHIVE_AFTER = 

TO_INST_PM = lib/mylib.pm

PM_TO_BLIB = lib/mylib.pm \
	blib/lib/mylib.pm

# --- MakeMaker platform_constants section:
MM_Unix_VERSION = 6.42
PERL_MALLOC_DEF = -DPERL_EXTMALLOC_DEF -Dmalloc=Perl_malloc -Dfree=Perl_mfree -Drealloc=Perl_realloc -Dcalloc=Perl_calloc

# --- MakeMaker tool_autosplit section:
# Usage: $(AUTOSPLITFILE) FileToSplit AutoDirToSplitInto
AUTOSPLITFILE = $(ABSPERLRUN)  -e 'use AutoSplit;  autosplit($$ARGV[0], $$ARGV[1], 0, 1, 1)' --

# --- MakeMaker tool_xsubpp section:

XSUBPPDIR = /usr/share/perl/5.10/ExtUtils
XSUBPP = $(XSUBPPDIR)$(DFSEP)xsubpp
XSUBPPRUN = $(PERLRUN) $(XSUBPP)
XSPROTOARG =
XSUBPPDEPS = /usr/share/perl/5.10/ExtUtils/typemap typemap $(XSUBPP)
XSUBPPARGS = -typemap /usr/share/perl/5.10/ExtUtils/typemap -typemap typemap
XSUBPP_EXTRA_ARGS = 

# --- MakeMaker tools_other section:
SHELL = /bin/sh
CHMOD = chmod
CP = cp
MV = mv
NOOP = $(SHELL) -c true
NOECHO = @
RM_F = rm -f
RM_RF = rm -rf
TEST_F = test -f
TOUCH = touch
UMASK_NULL = umask 0
DEV_NULL = &gt; /dev/null 2&gt;&amp;1
MKPATH = $(ABSPERLRUN) "-MExtUtils::Command" -e mkpath
EQUALIZE_TIMESTAMP = $(ABSPERLRUN) "-MExtUtils::Command" -e eqtime
ECHO = echo
ECHO_N = echo -n
UNINST = 0
VERBINST = 0
MOD_INSTALL = $(ABSPERLRUN) -MExtUtils::Install -e 'install({@ARGV}, '\''$(VERBINST)'\'', 0, '\''$(UNINST)'\'');' --
DOC_INSTALL = $(ABSPERLRUN) "-MExtUtils::Command::MM" -e perllocal_install
UNINSTALL = $(ABSPERLRUN) "-MExtUtils::Command::MM" -e uninstall
WARN_IF_OLD_PACKLIST = $(ABSPERLRUN) "-MExtUtils::Command::MM" -e warn_if_old_packlist
MACROSTART =
MACROEND =
USEMAKEFILE = -f
FIXIN = $(PERLRUN) "-MExtUtils::MY" -e "MY-&gt;fixin(shift)"

# --- MakeMaker makemakerdflt section:
makemakerdflt : all
	$(NOECHO) $(NOOP)

# --- MakeMaker dist section:
TAR = tar
TARFLAGS = cvf
ZIP = zip
ZIPFLAGS = -r
COMPRESS = gzip --best
SUFFIX = .gz
SHAR = shar
PREOP = $(NOECHO) $(NOOP)
POSTOP = $(NOECHO) $(NOOP)
TO_UNIX = $(NOECHO) $(NOOP)
CI = ci -u
RCS_LABEL = rcs -Nv$(VERSION_SYM): -q
DIST_CP = best
DIST_DEFAULT = tardist
DISTNAME = mylib
DISTVNAME = mylib-0.01

# --- MakeMaker macro section:

# --- MakeMaker depend section:

# --- MakeMaker cflags section:

CCFLAGS = -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
OPTIMIZE = -O2 -g
PERLTYPE =
MPOLLUTE = 

# --- MakeMaker const_loadlibs section:

# mylib might depend on some other libraries:
# See ExtUtils::Liblist for details
#

# --- MakeMaker const_cccmd section:
CCCMD = $(CC) -c $(PASTHRU_INC) $(INC) \
	$(CCFLAGS) $(OPTIMIZE) \
	$(PERLTYPE) $(MPOLLUTE) $(DEFINE_VERSION) \
	$(XS_DEFINE_VERSION)

# --- MakeMaker post_constants section:

# --- MakeMaker pasthru section:

PASTHRU = LIBPERL_A="$(LIBPERL_A)"\
	LINKTYPE="$(LINKTYPE)"\
	OPTIMIZE="$(OPTIMIZE)"\
	PREFIX="$(PREFIX)"\
	PASTHRU_DEFINE="$(PASTHRU_DEFINE)"\
	PASTHRU_INC="$(PASTHRU_INC)"

# --- MakeMaker special_targets section:
.SUFFIXES : .xs .c .C .cpp .i .s .cxx .cc $(OBJ_EXT)

.PHONY: all config static dynamic test linkext manifest blibdirs clean realclean disttest distdir

# --- MakeMaker c_o section:

.c.i:
	cc -E -c $(PASTHRU_INC) $(INC) \
	$(CCFLAGS) $(OPTIMIZE) \
	$(PERLTYPE) $(MPOLLUTE) $(DEFINE_VERSION) \
	$(XS_DEFINE_VERSION) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.c &gt; $*.i

.c.s:
	$(CCCMD) -S $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.c

.c$(OBJ_EXT):
	$(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.c

.cpp$(OBJ_EXT):
	$(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.cpp

.cxx$(OBJ_EXT):
	$(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.cxx

.cc$(OBJ_EXT):
	$(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.cc

.C$(OBJ_EXT):
	$(CCCMD) $*.C

# --- MakeMaker xs_c section:

.xs.c:
	$(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(XSUBPP_EXTRA_ARGS) $*.xs &gt; $*.xsc &amp;&amp; $(MV) $*.xsc $*.c

# --- MakeMaker xs_o section:

.xs$(OBJ_EXT):
	$(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $*.xs &gt; $*.xsc &amp;&amp; $(MV) $*.xsc $*.c
	$(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.c

# --- MakeMaker top_targets section:
all :: pure_all manifypods
	$(NOECHO) $(NOOP)

pure_all :: config pm_to_blib subdirs linkext
	$(NOECHO) $(NOOP)

subdirs :: $(MYEXTLIB)
	$(NOECHO) $(NOOP)

config :: $(FIRST_MAKEFILE) blibdirs
	$(NOECHO) $(NOOP)

$(O_FILES): $(H_FILES)

help :
	perldoc ExtUtils::MakeMaker

# --- MakeMaker blibdirs section:
blibdirs : $(INST_LIBDIR)$(DFSEP).exists $(INST_ARCHLIB)$(DFSEP).exists $(INST_AUTODIR)$(DFSEP).exists $(INST_ARCHAUTODIR)$(DFSEP).exists $(INST_BIN)$(DFSEP).exists $(INST_SCRIPT)$(DFSEP).exists $(INST_MAN1DIR)$(DFSEP).exists $(INST_MAN3DIR)$(DFSEP).exists
	$(NOECHO) $(NOOP)

# Backwards compat with 6.18 through 6.25
blibdirs.ts : blibdirs
	$(NOECHO) $(NOOP)

$(INST_LIBDIR)$(DFSEP).exists :: Makefile.PL
	$(NOECHO) $(MKPATH) $(INST_LIBDIR)
	$(NOECHO) $(CHMOD) 755 $(INST_LIBDIR)
	$(NOECHO) $(TOUCH) $(INST_LIBDIR)$(DFSEP).exists

$(INST_ARCHLIB)$(DFSEP).exists :: Makefile.PL
	$(NOECHO) $(MKPATH) $(INST_ARCHLIB)
	$(NOECHO) $(CHMOD) 755 $(INST_ARCHLIB)
	$(NOECHO) $(TOUCH) $(INST_ARCHLIB)$(DFSEP).exists

$(INST_AUTODIR)$(DFSEP).exists :: Makefile.PL
	$(NOECHO) $(MKPATH) $(INST_AUTODIR)
	$(NOECHO) $(CHMOD) 755 $(INST_AUTODIR)
	$(NOECHO) $(TOUCH) $(INST_AUTODIR)$(DFSEP).exists

$(INST_ARCHAUTODIR)$(DFSEP).exists :: Makefile.PL
	$(NOECHO) $(MKPATH) $(INST_ARCHAUTODIR)
	$(NOECHO) $(CHMOD) 755 $(INST_ARCHAUTODIR)
	$(NOECHO) $(TOUCH) $(INST_ARCHAUTODIR)$(DFSEP).exists

$(INST_BIN)$(DFSEP).exists :: Makefile.PL
	$(NOECHO) $(MKPATH) $(INST_BIN)
	$(NOECHO) $(CHMOD) 755 $(INST_BIN)
	$(NOECHO) $(TOUCH) $(INST_BIN)$(DFSEP).exists

$(INST_SCRIPT)$(DFSEP).exists :: Makefile.PL
	$(NOECHO) $(MKPATH) $(INST_SCRIPT)
	$(NOECHO) $(CHMOD) 755 $(INST_SCRIPT)
	$(NOECHO) $(TOUCH) $(INST_SCRIPT)$(DFSEP).exists

$(INST_MAN1DIR)$(DFSEP).exists :: Makefile.PL
	$(NOECHO) $(MKPATH) $(INST_MAN1DIR)
	$(NOECHO) $(CHMOD) 755 $(INST_MAN1DIR)
	$(NOECHO) $(TOUCH) $(INST_MAN1DIR)$(DFSEP).exists

$(INST_MAN3DIR)$(DFSEP).exists :: Makefile.PL
	$(NOECHO) $(MKPATH) $(INST_MAN3DIR)
	$(NOECHO) $(CHMOD) 755 $(INST_MAN3DIR)
	$(NOECHO) $(TOUCH) $(INST_MAN3DIR)$(DFSEP).exists

# --- MakeMaker linkext section:

linkext :: $(LINKTYPE)
	$(NOECHO) $(NOOP)

# --- MakeMaker dlsyms section:

# --- MakeMaker dynamic section:

dynamic :: $(FIRST_MAKEFILE) $(INST_DYNAMIC) $(INST_BOOT)
	$(NOECHO) $(NOOP)

# --- MakeMaker dynamic_bs section:
BOOTSTRAP = $(BASEEXT).bs

# As Mkbootstrap might not write a file (if none is required)
# we use touch to prevent make continually trying to remake it.
# The DynaLoader only reads a non-empty file.
$(BOOTSTRAP) : $(FIRST_MAKEFILE) $(BOOTDEP) $(INST_ARCHAUTODIR)$(DFSEP).exists
	$(NOECHO) $(ECHO) "Running Mkbootstrap for $(NAME) ($(BSLOADLIBS))"
	$(NOECHO) $(PERLRUN) \
		"-MExtUtils::Mkbootstrap" \
		-e "Mkbootstrap('$(BASEEXT)','$(BSLOADLIBS)');"
	$(NOECHO) $(TOUCH) $@
	$(CHMOD) $(PERM_RW) $@

$(INST_BOOT) : $(BOOTSTRAP) $(INST_ARCHAUTODIR)$(DFSEP).exists
	$(NOECHO) $(RM_RF) $@
	- $(CP) $(BOOTSTRAP) $@
	$(CHMOD) $(PERM_RW) $@

# --- MakeMaker dynamic_lib section:

# This section creates the dynamically loadable $(INST_DYNAMIC)
# from $(OBJECT) and possibly $(MYEXTLIB).
ARMAYBE = :
OTHERLDFLAGS =
INST_DYNAMIC_DEP =
INST_DYNAMIC_FIX = 

$(INST_DYNAMIC): $(OBJECT) $(MYEXTLIB) $(BOOTSTRAP) $(INST_ARCHAUTODIR)$(DFSEP).exists $(EXPORT_LIST) $(PERL_ARCHIVE) $(PERL_ARCHIVE_AFTER) $(INST_DYNAMIC_DEP)
	$(RM_F) $@
	$(LD)  $(LDDLFLAGS) $(LDFROM) $(OTHERLDFLAGS) -o $@ $(MYEXTLIB)	\
	  $(PERL_ARCHIVE) $(LDLOADLIBS) $(PERL_ARCHIVE_AFTER) $(EXPORT_LIST)	\
	  $(INST_DYNAMIC_FIX)
	$(CHMOD) $(PERM_RWX) $@

# --- MakeMaker static section:

## $(INST_PM) has been moved to the all: target.
## It remains here for awhile to allow for old usage: "make static"
static :: $(FIRST_MAKEFILE) $(INST_STATIC)
	$(NOECHO) $(NOOP)

# --- MakeMaker static_lib section:

$(INST_STATIC) : $(OBJECT) $(MYEXTLIB) $(INST_ARCHAUTODIR)$(DFSEP).exists
	$(RM_RF) $@
	$(FULL_AR) $(AR_STATIC_ARGS) $@ $(OBJECT) &amp;&amp; $(RANLIB) $@
	$(CHMOD) $(PERM_RWX) $@
	$(NOECHO) $(ECHO) "$(EXTRALIBS)" &gt; $(INST_ARCHAUTODIR)/extralibs.ld

# --- MakeMaker manifypods section:

POD2MAN_EXE = $(PERLRUN) "-MExtUtils::Command::MM" -e pod2man "--"
POD2MAN = $(POD2MAN_EXE)

manifypods : pure_all  \
	lib/mylib.pm
	$(NOECHO) $(POD2MAN) --section=$(MAN3EXT) --perm_rw=$(PERM_RW) \
	  lib/mylib.pm $(INST_MAN3DIR)/mylib.$(MAN3EXT) 

# --- MakeMaker processPL section:

# --- MakeMaker installbin section:

# --- MakeMaker subdirs section:

# none

# --- MakeMaker clean_subdirs section:
clean_subdirs :
	$(NOECHO) $(NOOP)

# --- MakeMaker clean section:

# Delete temporary files but do not touch installed files. We don't delete
# the Makefile here so a later make realclean still has a makefile to use.

clean :: clean_subdirs
	- $(RM_F) \
	  *$(LIB_EXT) core \
	  core.[0-9] $(INST_ARCHAUTODIR)/extralibs.all \
	  core.[0-9][0-9] $(BASEEXT).bso \
	  pm_to_blib.ts core.[0-9][0-9][0-9][0-9] \
	  $(BASEEXT).x $(BOOTSTRAP) \
	  perl$(EXE_EXT) tmon.out \
	  *$(OBJ_EXT) pm_to_blib \
	  $(INST_ARCHAUTODIR)/extralibs.ld blibdirs.ts \
	  core.[0-9][0-9][0-9][0-9][0-9] mylib.c \
	  *perl.core core.*perl.*.? \
	  $(MAKE_APERL_FILE) $(BASEEXT).def \
	  perl core.[0-9][0-9][0-9] \
	  mon.out lib$(BASEEXT).def \
	  perlmain.c perl.exe \
	  so_locations $(BASEEXT).exp
	- $(RM_RF) \
	  blib
	- $(MV) $(FIRST_MAKEFILE) $(MAKEFILE_OLD) $(DEV_NULL)

# --- MakeMaker realclean_subdirs section:
realclean_subdirs :
	$(NOECHO) $(NOOP)

# --- MakeMaker realclean section:
# Delete temporary files (via clean) and also delete dist files
realclean purge ::  clean realclean_subdirs
	- $(RM_F) \
	  $(OBJECT) $(MAKEFILE_OLD) \
	  $(FIRST_MAKEFILE)
	- $(RM_RF) \
	  $(DISTVNAME) 

# --- MakeMaker metafile section:
metafile : create_distdir
	$(NOECHO) $(ECHO) Generating META.yml
	$(NOECHO) $(ECHO) '--- #YAML:1.0' &gt; META_new.yml
	$(NOECHO) $(ECHO) 'name:                mylib' &gt;&gt; META_new.yml
	$(NOECHO) $(ECHO) 'version:             0.01' &gt;&gt; META_new.yml
	$(NOECHO) $(ECHO) 'abstract:            Perl extension for blah blah blah' &gt;&gt; META_new.yml
	$(NOECHO) $(ECHO) 'license:             ~' &gt;&gt; META_new.yml
	$(NOECHO) $(ECHO) 'author:              ' &gt;&gt; META_new.yml
	$(NOECHO) $(ECHO) '    - Eric Melski ' &gt;&gt; META_new.yml
	$(NOECHO) $(ECHO) 'generated_by:        ExtUtils::MakeMaker version 6.42' &gt;&gt; META_new.yml
	$(NOECHO) $(ECHO) 'distribution_type:   module' &gt;&gt; META_new.yml
	$(NOECHO) $(ECHO) 'requires:     ' &gt;&gt; META_new.yml
	$(NOECHO) $(ECHO) 'meta-spec:' &gt;&gt; META_new.yml
	$(NOECHO) $(ECHO) '    url:     http://module-build.sourceforge.net/META-spec-v1.3.html' &gt;&gt; META_new.yml
	$(NOECHO) $(ECHO) '    version: 1.3' &gt;&gt; META_new.yml
	-$(NOECHO) $(MV) META_new.yml $(DISTVNAME)/META.yml

# --- MakeMaker signature section:
signature :
	cpansign -s

# --- MakeMaker dist_basics section:
distclean :: realclean distcheck
	$(NOECHO) $(NOOP)

distcheck :
	$(PERLRUN) "-MExtUtils::Manifest=fullcheck" -e fullcheck

skipcheck :
	$(PERLRUN) "-MExtUtils::Manifest=skipcheck" -e skipcheck

manifest :
	$(PERLRUN) "-MExtUtils::Manifest=mkmanifest" -e mkmanifest

veryclean : realclean
	$(RM_F) *~ */*~ *.orig */*.orig *.bak */*.bak *.old */*.old 

# --- MakeMaker dist_core section:

dist : $(DIST_DEFAULT) $(FIRST_MAKEFILE)
	$(NOECHO) $(ABSPERLRUN) -l -e 'print '\''Warning: Makefile possibly out of date with $(VERSION_FROM)'\''' \
	  -e '    if -e '\''$(VERSION_FROM)'\'' and -M '\''$(VERSION_FROM)'\''  $(DISTVNAME).tar$(SUFFIX)_uu

$(DISTVNAME).tar$(SUFFIX) : distdir
	$(PREOP)
	$(TO_UNIX)
	$(TAR) $(TARFLAGS) $(DISTVNAME).tar $(DISTVNAME)
	$(RM_RF) $(DISTVNAME)
	$(COMPRESS) $(DISTVNAME).tar
	$(POSTOP)

zipdist : $(DISTVNAME).zip
	$(NOECHO) $(NOOP)

$(DISTVNAME).zip : distdir
	$(PREOP)
	$(ZIP) $(ZIPFLAGS) $(DISTVNAME).zip $(DISTVNAME)
	$(RM_RF) $(DISTVNAME)
	$(POSTOP)

shdist : distdir
	$(PREOP)
	$(SHAR) $(DISTVNAME) &gt; $(DISTVNAME).shar
	$(RM_RF) $(DISTVNAME)
	$(POSTOP)

# --- MakeMaker distdir section:
create_distdir :
	$(RM_RF) $(DISTVNAME)
	$(PERLRUN) "-MExtUtils::Manifest=manicopy,maniread" \
		-e "manicopy(maniread(),'$(DISTVNAME)', '$(DIST_CP)');"

distdir : create_distdir distmeta
	$(NOECHO) $(NOOP)

# --- MakeMaker dist_test section:
disttest : distdir
	cd $(DISTVNAME) &amp;&amp; $(ABSPERLRUN) Makefile.PL
	cd $(DISTVNAME) &amp;&amp; $(MAKE) $(PASTHRU)
	cd $(DISTVNAME) &amp;&amp; $(MAKE) test $(PASTHRU)

# --- MakeMaker dist_ci section:

ci :
	$(PERLRUN) "-MExtUtils::Manifest=maniread" \
	  -e "@all = keys %{ maniread() };" \
	  -e "print(qq{Executing $(CI) @all\n}); system(qq{$(CI) @all});" \
	  -e "print(qq{Executing $(RCS_LABEL) ...\n}); system(qq{$(RCS_LABEL) @all});"

# --- MakeMaker distmeta section:
distmeta : create_distdir metafile
	$(NOECHO) cd $(DISTVNAME) &amp;&amp; $(ABSPERLRUN) -MExtUtils::Manifest=maniadd -e 'eval { maniadd({q{META.yml} =&gt; q{Module meta-data (added by MakeMaker)}}) } ' \
	  -e '    or print "Could not add META.yml to MANIFEST: $${'\''@'\''}\n"' --

# --- MakeMaker distsignature section:
distsignature : create_distdir
	$(NOECHO) cd $(DISTVNAME) &amp;&amp; $(ABSPERLRUN) -MExtUtils::Manifest=maniadd -e 'eval { maniadd({q{SIGNATURE} =&gt; q{Public-key signature (added by MakeMaker)}}) } ' \
	  -e '    or print "Could not add SIGNATURE to MANIFEST: $${'\''@'\''}\n"' --
	$(NOECHO) cd $(DISTVNAME) &amp;&amp; $(TOUCH) SIGNATURE
	cd $(DISTVNAME) &amp;&amp; cpansign -s

# --- MakeMaker install section:

install :: pure_install doc_install
	$(NOECHO) $(NOOP)

install_perl :: pure_perl_install doc_perl_install
	$(NOECHO) $(NOOP)

install_site :: pure_site_install doc_site_install
	$(NOECHO) $(NOOP)

install_vendor :: pure_vendor_install doc_vendor_install
	$(NOECHO) $(NOOP)

pure_install :: pure_$(INSTALLDIRS)_install
	$(NOECHO) $(NOOP)

doc_install :: doc_$(INSTALLDIRS)_install
	$(NOECHO) $(NOOP)

pure__install : pure_site_install
	$(NOECHO) $(ECHO) INSTALLDIRS not defined, defaulting to INSTALLDIRS=site

doc__install : doc_site_install
	$(NOECHO) $(ECHO) INSTALLDIRS not defined, defaulting to INSTALLDIRS=site

pure_perl_install :: all
	$(NOECHO) umask 022; $(MOD_INSTALL) \
		$(INST_LIB) $(DESTINSTALLPRIVLIB) \
		$(INST_ARCHLIB) $(DESTINSTALLARCHLIB) \
		$(INST_BIN) $(DESTINSTALLBIN) \
		$(INST_SCRIPT) $(DESTINSTALLSCRIPT) \
		$(INST_MAN1DIR) $(DESTINSTALLMAN1DIR) \
		$(INST_MAN3DIR) $(DESTINSTALLMAN3DIR)
	$(NOECHO) $(WARN_IF_OLD_PACKLIST) \
		$(SITEARCHEXP)/auto/$(FULLEXT)

pure_site_install :: all
	$(NOECHO) umask 02; $(MOD_INSTALL) \
		read $(SITEARCHEXP)/auto/$(FULLEXT)/.packlist \
		write $(DESTINSTALLSITEARCH)/auto/$(FULLEXT)/.packlist \
		$(INST_LIB) $(DESTINSTALLSITELIB) \
		$(INST_ARCHLIB) $(DESTINSTALLSITEARCH) \
		$(INST_BIN) $(DESTINSTALLSITEBIN) \
		$(INST_SCRIPT) $(DESTINSTALLSITESCRIPT) \
		$(INST_MAN1DIR) $(DESTINSTALLSITEMAN1DIR) \
		$(INST_MAN3DIR) $(DESTINSTALLSITEMAN3DIR)
	$(NOECHO) $(WARN_IF_OLD_PACKLIST) \
		$(PERL_ARCHLIB)/auto/$(FULLEXT)

pure_vendor_install :: all
	$(NOECHO) umask 022; $(MOD_INSTALL) \
		$(INST_LIB) $(DESTINSTALLVENDORLIB) \
		$(INST_ARCHLIB) $(DESTINSTALLVENDORARCH) \
		$(INST_BIN) $(DESTINSTALLVENDORBIN) \
		$(INST_SCRIPT) $(DESTINSTALLVENDORSCRIPT) \
		$(INST_MAN1DIR) $(DESTINSTALLVENDORMAN1DIR) \
		$(INST_MAN3DIR) $(DESTINSTALLVENDORMAN3DIR)

doc_perl_install :: all

doc_site_install :: all
	$(NOECHO) $(ECHO) Appending installation info to $(DESTINSTALLSITEARCH)/perllocal.pod
	-$(NOECHO) umask 02; $(MKPATH) $(DESTINSTALLSITEARCH)
	-$(NOECHO) umask 02; $(DOC_INSTALL) \
		"Module" "$(NAME)" \
		"installed into" "$(INSTALLSITELIB)" \
		LINKTYPE "$(LINKTYPE)" \
		VERSION "$(VERSION)" \
		EXE_FILES "$(EXE_FILES)" \
		&gt;&gt; $(DESTINSTALLSITEARCH)/perllocal.pod

doc_vendor_install :: all

uninstall :: uninstall_from_$(INSTALLDIRS)dirs
	$(NOECHO) $(NOOP)

uninstall_from_perldirs ::

uninstall_from_sitedirs ::
	$(NOECHO) $(UNINSTALL) $(SITEARCHEXP)/auto/$(FULLEXT)/.packlist

uninstall_from_vendordirs ::

# --- MakeMaker force section:
# Phony target to force checking subdirectories.
FORCE :
	$(NOECHO) $(NOOP)

# --- MakeMaker perldepend section:

PERL_HDRS = \
	$(PERL_INC)/EXTERN.h		\
	$(PERL_INC)/INTERN.h		\
	$(PERL_INC)/XSUB.h		\
	$(PERL_INC)/av.h		\
	$(PERL_INC)/cc_runtime.h	\
	$(PERL_INC)/config.h		\
	$(PERL_INC)/cop.h		\
	$(PERL_INC)/cv.h		\
	$(PERL_INC)/dosish.h		\
	$(PERL_INC)/embed.h		\
	$(PERL_INC)/embedvar.h		\
	$(PERL_INC)/fakethr.h		\
	$(PERL_INC)/form.h		\
	$(PERL_INC)/gv.h		\
	$(PERL_INC)/handy.h		\
	$(PERL_INC)/hv.h		\
	$(PERL_INC)/intrpvar.h		\
	$(PERL_INC)/iperlsys.h		\
	$(PERL_INC)/keywords.h		\
	$(PERL_INC)/mg.h		\
	$(PERL_INC)/nostdio.h		\
	$(PERL_INC)/op.h		\
	$(PERL_INC)/opcode.h		\
	$(PERL_INC)/patchlevel.h	\
	$(PERL_INC)/perl.h		\
	$(PERL_INC)/perlio.h		\
	$(PERL_INC)/perlsdio.h		\
	$(PERL_INC)/perlsfio.h		\
	$(PERL_INC)/perlvars.h		\
	$(PERL_INC)/perly.h		\
	$(PERL_INC)/pp.h		\
	$(PERL_INC)/pp_proto.h		\
	$(PERL_INC)/proto.h		\
	$(PERL_INC)/regcomp.h		\
	$(PERL_INC)/regexp.h		\
	$(PERL_INC)/regnodes.h		\
	$(PERL_INC)/scope.h		\
	$(PERL_INC)/sv.h		\
	$(PERL_INC)/thread.h		\
	$(PERL_INC)/unixish.h		\
	$(PERL_INC)/util.h

$(OBJECT) : $(PERL_HDRS)

mylib.c : $(XSUBPPDEPS)

# --- MakeMaker makefile section:

$(OBJECT) : $(FIRST_MAKEFILE)

# We take a very conservative approach here, but it's worth it.
# We move Makefile to Makefile.old here to avoid gnu make looping.
$(FIRST_MAKEFILE) : Makefile.PL $(CONFIGDEP)
	$(NOECHO) $(ECHO) "Makefile out-of-date with respect to $?"
	$(NOECHO) $(ECHO) "Cleaning current config before rebuilding Makefile..."
	-$(NOECHO) $(RM_F) $(MAKEFILE_OLD)
	-$(NOECHO) $(MV)   $(FIRST_MAKEFILE) $(MAKEFILE_OLD)
	- $(MAKE) $(USEMAKEFILE) $(MAKEFILE_OLD) clean $(DEV_NULL)
	$(PERLRUN) Makefile.PL
	$(NOECHO) $(ECHO) "==&gt; Your Makefile has been rebuilt.  Please rerun the $(MAKE) command.  &lt;==&quot;
	false

# --- MakeMaker staticmake section:

# --- MakeMaker makeaperl section ---
MAP_TARGET    = perl
FULLPERL      = /usr/bin/perl

$(MAP_TARGET) :: static $(MAKE_APERL_FILE)
	$(MAKE) $(USEMAKEFILE) $(MAKE_APERL_FILE) $@

$(MAKE_APERL_FILE) : $(FIRST_MAKEFILE) pm_to_blib
	$(NOECHO) $(ECHO) Writing \&quot;$(MAKE_APERL_FILE)\&quot; for this $(MAP_TARGET)
	$(NOECHO) $(PERLRUNINST) \
		Makefile.PL DIR= \
		MAKEFILE=$(MAKE_APERL_FILE) LINKTYPE=static \
		MAKEAPERL=1 NORECURS=1 CCCDLFLAGS=

# --- MakeMaker test section:

TEST_VERBOSE=0
TEST_TYPE=test_$(LINKTYPE)
TEST_FILE = test.pl
TEST_FILES = t/*.t
TESTDB_SW = -d

testdb :: testdb_$(LINKTYPE)

test :: $(TEST_TYPE) subdirs-test

subdirs-test ::
	$(NOECHO) $(NOOP)

test_dynamic :: pure_all
	PERL_DL_NONLAZY=1 $(FULLPERLRUN) &quot;-MExtUtils::Command::MM&quot; &quot;-e&quot; &quot;test_harness($(TEST_VERBOSE), &#39;$(INST_LIB)&#39;, &#39;$(INST_ARCHLIB)&#39;)&quot; $(TEST_FILES)

testdb_dynamic :: pure_all
	PERL_DL_NONLAZY=1 $(FULLPERLRUN) $(TESTDB_SW) &quot;-I$(INST_LIB)&quot; &quot;-I$(INST_ARCHLIB)&quot; $(TEST_FILE)

test_ : test_dynamic

test_static :: pure_all $(MAP_TARGET)
	PERL_DL_NONLAZY=1 ./$(MAP_TARGET) &quot;-MExtUtils::Command::MM&quot; &quot;-e&quot; &quot;test_harness($(TEST_VERBOSE), &#39;$(INST_LIB)&#39;, &#39;$(INST_ARCHLIB)&#39;)&quot; $(TEST_FILES)

testdb_static :: pure_all $(MAP_TARGET)
	PERL_DL_NONLAZY=1 ./$(MAP_TARGET) $(TESTDB_SW) &quot;-I$(INST_LIB)&quot; &quot;-I$(INST_ARCHLIB)&quot; $(TEST_FILE)

# --- MakeMaker ppd section:
# Creates a PPD (Perl Package Description) for a binary distribution.
ppd :
	$(NOECHO) $(ECHO) &#39;&lt;SOFTPKG NAME=&quot;$(DISTNAME)&quot; VERSION=&quot;0,01,0,0&quot;&gt;&#39; &gt; $(DISTNAME).ppd
	$(NOECHO) $(ECHO) &#39;    &lt;TITLE&gt;$(DISTNAME)&lt;/TITLE&gt;&#39; &gt;&gt; $(DISTNAME).ppd
	$(NOECHO) $(ECHO) &#39;    &lt;ABSTRACT&gt;Perl extension for blah blah blah&lt;/ABSTRACT&gt;&#39; &gt;&gt; $(DISTNAME).ppd
	$(NOECHO) $(ECHO) &#39;    &lt;AUTHOR&gt;Eric Melski &lt;ericm@&gt;&lt;/AUTHOR&gt;&#39; &gt;&gt; $(DISTNAME).ppd
	$(NOECHO) $(ECHO) &#39;    &lt;IMPLEMENTATION&gt;&#39; &gt;&gt; $(DISTNAME).ppd
	$(NOECHO) $(ECHO) &#39;        &lt;OS NAME=&quot;$(OSNAME)&quot; /&gt;&#39; &gt;&gt; $(DISTNAME).ppd
	$(NOECHO) $(ECHO) &#39;        &lt;ARCHITECTURE NAME=&quot;i486-linux-gnu-thread-multi-5.1&quot; /&gt;&#39; &gt;&gt; $(DISTNAME).ppd
	$(NOECHO) $(ECHO) &#39;        &lt;CODEBASE HREF=&quot;&quot; /&gt;&#39; &gt;&gt; $(DISTNAME).ppd
	$(NOECHO) $(ECHO) &#39;    &lt;/IMPLEMENTATION&gt;&#39; &gt;&gt; $(DISTNAME).ppd
	$(NOECHO) $(ECHO) &#39;&lt;/SOFTPKG&gt;&#39; &gt;&gt; $(DISTNAME).ppd

# --- MakeMaker pm_to_blib section:

pm_to_blib : $(TO_INST_PM)
	$(NOECHO) $(ABSPERLRUN) -MExtUtils::Install -e &#39;pm_to_blib({@ARGV}, &#39;\&#39;&#39;$(INST_LIB)/auto&#39;\&#39;&#39;, &#39;\&#39;&#39;$(PM_FILTER)&#39;\&#39;&#39;)&#39; -- \
	  lib/mylib.pm blib/lib/mylib.pm
	$(NOECHO) $(TOUCH) pm_to_blib

# --- MakeMaker selfdocument section:

# --- MakeMaker postamble section:

# End.
</pre>
</p>
<p>
It seems hopeless.  This makefile suffers from a classic problem:  unless you&#8217;re the guy who wrote it in the first place, it&#8217;s an impenetrable fog.  You&#8217;re in for a world of hurt when you try to understand it, or worse, try to modify it.  Lucky for me &mdash; and for you if you ever find yourself in this situation &mdash; there&#8217;s a powerful new tool in your toolbox:  emake&#8217;s annotated build logs, or simply <i>annotation</i>.
</p>
<p>
If you have ElectricAccelerator or <a href="http://www.sparkbuild.com/">SparkBuild</a>, a free gmake- and NMAKE-compatible make replacement, you just need to enable annotation on your next build:</p>
<pre style="font:80% courier, verdana, monospace;border:1px solid #ccc;width:90%;background:#fff7f0;color:#000;overflow:auto;margin:1em auto 2em;padding:1em;">emake --emake-annodetail=basic &gt; build.xml 2&gt;&amp;1</pre>
</p>
<p>
Now you can search <tt>build.xml</tt> for the log output or the command-line that you&#8217;re interested in.  You can use ElectricInsight or SparkBuild Insight, of course, but for a simple query like this I just use <i>less</i>.  Searching for the log output of the command I&#8217;m looking for (<i>gcc -shared</i>) leads me to this:
</p>
<p><pre style="font:80% courier, verdana, monospace;border:1px solid #ccc;width:90%;background:#fff7f0;color:#000;overflow:auto;margin:1em auto 2em;padding:1em;">...
&lt;job id="J09be71b8" thread="b7b34940" type="rule" name="blib/arch/auto/mylib/mylib.so" file="Makefile" line="469" neededby="J09be7138"&gt;
&lt;output&gt;&lt;![CDATA[]]&gt;&lt;/output&gt;
&lt;command line="470"&gt;
&lt;argv&gt;&lt;![CDATA[rm -f blib/arch/auto/mylib/mylib.so]]&gt;&lt;/argv&gt;
&lt;output&gt;&lt;![CDATA[rm -f blib/arch/auto/mylib/mylib.so
]]&gt;&lt;/output&gt;
&lt;output src="prog"&gt;&lt;![CDATA[]]&gt;&lt;/output&gt;
&lt;/command&gt;
&lt;command line="471-473"&gt;
&lt;argv&gt;&lt;![CDATA[<font color="red"><b>gcc  -shared </b></font>-O2 -g -L/usr/local/lib mylib.o  -o blib/arch/auto/mylib/mylib.so      \
                \
          ]]&gt;&lt;/argv&gt;
&lt;output&gt;&lt;![CDATA[<font color="red"><b>gcc  -shared </b></font>-O2 -g -L/usr/local/lib mylib.o  -o blib/arch/auto/mylib/mylib.so    \
                \

]]&gt;&lt;/output&gt;
&lt;output src="prog"&gt;&lt;![CDATA[]]&gt;&lt;/output&gt;
&lt;/command&gt;
...</pre>
</p>
<p>
Now, I just scan back a few lines to find the start of the <i>&lt;job&gt;</i> tag containing that text.  The <i>file</i> attribute tells me which makefile contains the rule definition, and the <i>line</i> attribute tells me which line it starts on:
</p>
<p><pre style="font:80% courier, verdana, monospace;border:1px solid #ccc;width:90%;background:#fff7f0;color:#000;overflow:auto;margin:1em auto 2em;padding:1em;">...
&lt;job id="J09be71b8" thread="b7b34940" type="rule" name="blib/arch/auto/mylib/mylib.so" <font color="red"><b>file="Makefile" line="469"</b></font> neededby="J09be7138"&gt;
...</pre>
</p>
<p>
<b>Bingo!</b>  The rule I want starts on line 469 of the file <i>Makefile</i>.  Using that as an anchor it&#8217;s now trivial to see how to modify the makefile to produce the result I&#8217;m after.
</p>
<p><h3>The best tool for the job</h3>
</p>
<p>
Trying to figure out how a build system is put together can feel like being dropped in the middle of a dense jungle.  Annotated build logs are like a map leading you back to daylight.  There&#8217;s nothing else like them.</p>
<br />Posted in ElectricAccelerator, SparkBuild Tagged: annotation, ElectricAccelerator, makefile, SparkBuild <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/ecloud.wordpress.com/610/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/ecloud.wordpress.com/610/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/ecloud.wordpress.com/610/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/ecloud.wordpress.com/610/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/ecloud.wordpress.com/610/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/ecloud.wordpress.com/610/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/ecloud.wordpress.com/610/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/ecloud.wordpress.com/610/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/ecloud.wordpress.com/610/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/ecloud.wordpress.com/610/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.electric-cloud.com&blog=5211544&post=610&subd=ecloud&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://blog.electric-cloud.com/2009/11/10/how-to-quickly-navigate-an-unfamiliar-makefile/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/6344c5478a4b5f0e8c546c736b2a7e0d?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=PG" medium="image">
			<media:title type="html">ericm</media:title>
		</media:content>
	</item>
		<item>
		<title>The Cloud Two-Step:  How do you know what Dev/Test processes to run in the Cloud?</title>
		<link>http://blog.electric-cloud.com/2009/11/09/the-cloud-two-step-how-do-you-know-what-devtest-processes-to-run-in-the-cloud/</link>
		<comments>http://blog.electric-cloud.com/2009/11/09/the-cloud-two-step-how-do-you-know-what-devtest-processes-to-run-in-the-cloud/#comments</comments>
		<pubDate>Mon, 09 Nov 2009 19:50:27 +0000</pubDate>
		<dc:creator>Mike Maciag</dc:creator>
				<category><![CDATA[Build-Test-Deploy Best Practices]]></category>
		<category><![CDATA[Cloud Computing]]></category>
		<category><![CDATA[ElectricCommander]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Virtualization]]></category>
		<category><![CDATA[virtual]]></category>
		<category><![CDATA[amazon ec2]]></category>
		<category><![CDATA[Software Testing]]></category>

		<guid isPermaLink="false">http://blog.electric-cloud.com/?p=605</guid>
		<description><![CDATA[I just came across a piece that Bernard Golden wrote in his CIO blog entitled Dev/Test in the Cloud: Rules for Getting it Right.   He makes a lot of good points including what we see the most successful enterprise development shops doing with the cloud; “Treat the cloud as an extension, not a separation.” 
Unfortunately, he [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.electric-cloud.com&blog=5211544&post=605&subd=ecloud&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>I just came across a piece that Bernard Golden wrote in his CIO blog entitled <a href="http://www.cio.com/article/506305/Dev_Test_in_the_Cloud_Rules_for_Getting_it_Right">Dev/Test in the Cloud: Rules for Getting it Right</a>.   He makes a lot of good points including what we see the most successful enterprise development shops doing with the cloud; “Treat the cloud as an extension, not a separation.” </p>
<p>Unfortunately, he does not point out what dev/test tools should be put up in the cloud but simply states “dev/test tasks,” as if it is obvious which ones to migrate.  Let’s see if we can leverage his work to figure which dev/test tasks are cloud-ready in two steps:<br />
<span id="more-605"></span><br />
 <strong><span style="text-decoration:underline;">Step 1:   Figure out what is NOT GOOD for the cloud.</span></strong>  List your existing dev/test processes and cross things off that aren’t:</p>
<ul>
<li>Mostly independent, or have clean dependencies on stuff that’s in your network but externally accessible</li>
<li>OK to upload (no security concerns or bandwidth constraints)</li>
<li>Run on plain vanilla x86 systems (today the cloud is the world of Windows and Linux)</li>
<li>Made with tools that you can run externally (watch for node-locked licenses, etc.)</li>
</ul>
<p><strong><span style="text-decoration:underline;">Step 2:  Of what is left, figure out what will get the most benefit from the cloud</span></strong>.  In other words those that are slow, resource intensive, or bursty in compute demand.</p>
<p>Do you have anything left?  Good!  Most enterprises have critical development steps but not entire development workflows that can be wholesale lifted to the cloud.  Great examples are; compiling sources, testing on several different operating systems, and scalability and load testing.  This is why Mr. Golden was smart to point out that you should “Treat the cloud as an extension, not a separation.”</p>
<p>The remaining question is how can you effectively manage the process if it likely requires a combination of cloud, physical and virtual compute resources and the integration and orchestration of dozens of tools in your tool chain?  Certainly this is enough to make a traditional development process held together by home-grown scripts and a hard working release team break under the pressure.</p>
<p>Lab manager applications do a great job of determining “where” something should be run but does not handle “what” should be run or manage the process of “how” the steps are completed.  For this, check out ElectricCommander.   We are helping some of the largest development enterprises in the world migrate the right dev/test steps to the cloud.</p>
<br />Posted in Build-Test-Deploy Best Practices, Cloud Computing, ElectricCommander, Software Development, virtual, Virtualization Tagged: amazon ec2, Cloud Computing, Software Testing <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/ecloud.wordpress.com/605/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/ecloud.wordpress.com/605/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/ecloud.wordpress.com/605/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/ecloud.wordpress.com/605/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/ecloud.wordpress.com/605/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/ecloud.wordpress.com/605/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/ecloud.wordpress.com/605/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/ecloud.wordpress.com/605/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/ecloud.wordpress.com/605/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/ecloud.wordpress.com/605/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.electric-cloud.com&blog=5211544&post=605&subd=ecloud&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://blog.electric-cloud.com/2009/11/09/the-cloud-two-step-how-do-you-know-what-devtest-processes-to-run-in-the-cloud/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/3f8af1a057fc8f4e5c7e94dd8156a0ac?s=96&#38;d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=PG" medium="image">
			<media:title type="html">mmaciag</media:title>
		</media:content>
	</item>
		<item>
		<title>Seven lessons from seven years at Electric Cloud</title>
		<link>http://blog.electric-cloud.com/2009/11/02/seven-lessons-from-seven-years-at-electric-cloud/</link>
		<comments>http://blog.electric-cloud.com/2009/11/02/seven-lessons-from-seven-years-at-electric-cloud/#comments</comments>
		<pubDate>Mon, 02 Nov 2009 18:18:47 +0000</pubDate>
		<dc:creator>Eric Melski</dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Electric Cloud]]></category>

		<guid isPermaLink="false">http://blog.electric-cloud.com/?p=590</guid>
		<description><![CDATA[We wrapped up the 2009 Electric Cloud Customer Summit a couple weeks ago.  Like last year, I left refreshed and reinvigorated after hearing so many customers&#8217; stories.  Comments like, &#8220;Developer builds are now measured in seconds [with Accelerator].  Nobody does local builds anymore,&#8221; and, &#8220;ElectricAccelerator will give you better performance than you [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.electric-cloud.com&blog=5211544&post=590&subd=ecloud&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>We wrapped up the 2009 Electric Cloud Customer Summit a couple weeks ago.  Like last year, I left refreshed and reinvigorated after hearing so many customers&#8217; stories.  Comments like, &#8220;Developer builds are now measured in seconds [with Accelerator].  Nobody does local builds anymore,&#8221; and, &#8220;ElectricAccelerator will give you better performance than you deserve,&#8221; really make me feel like all the hard work is worthwhile.  But one of my favorite takeaways from the summit was this picture:</p>
<p><table align="center">
<caption align="bottom"><font size="-2">From left: Eric Melski, Usman Muzaffar, Sven Delmas, Scott Stanton</font></caption>
<tr>
<td><a href="http://ecloud.files.wordpress.com/2009/10/team_new.jpg"><img src="http://ecloud.files.wordpress.com/2009/10/team_new.jpg?w=300&#038;h=201" alt="team_new" title="team_new" width="300" height="201" class="aligncenter size-medium wp-image-593" /></a></td>
</tr>
</table>
<p>
That&#8217;s the original engineering team at Electric Cloud, still together after more than seven years.  It&#8217;s unusual to catch us all together in one spot like this though, since we have much different roles at the company now:  I&#8217;m an Architect; Usman is VP of Product Management; Sven is Director of Engineering; and Scott is the Chief Architect.
</p>
<p>
When I saw this picture I wondered if I could find a similar shot from sometime in Electric Cloud&#8217;s history.  Lucky for me we&#8217;ve always had a few shutter bugs at the company, so I had a few to choose from.<br />
<span id="more-590"></span><br />
The best was this shot from October 2002, almost 7 years to-the-day before the new picture, and just 6 months after Electric Cloud was formally incorporated:
</p>
<p><table align="center">
<caption align="bottom"><font size="-2">Back row, from left: Eric Melski, Sven Delmas, Scott Stanton, John Graham-Cumming, Steve Stukenborg; front row: John Ousterhout, Gloria Hui, Usman Muzaffar</font></caption>
<tr>
<td><a href="http://ecloud.files.wordpress.com/2009/10/team_old.jpg"><img src="http://ecloud.files.wordpress.com/2009/10/team_old.jpg?w=300&#038;h=224" alt="team_old" title="team_old" width="300" height="224" class="aligncenter size-medium wp-image-594" /></a></td>
</tr>
</table>
<p>
So we&#8217;re looking a little older and a little grayer, but overall, none the worse for the wear, I think.  Filling out the old picture is John Ousterhout, founder; John Graham-Cumming, co-founder; Steve Stukenborg, Director of Marketing; and Gloria Hui, office manager/human resources.
</p>
<p><h3>Lessons learned</h3>
</p>
<p>
Anytime you see pictures like this side-by-side, you naturally think about how much you&#8217;ve changed over the years and what you have to show for it.  I&#8217;ve certainly learned a lot during my time at Electric Cloud.  Here are some of the most valuable lessons:
</p>
<ol>
<li><b>Don&#8217;t let &#8220;the best&#8221; be the enemy of &#8220;the good&#8221;</b>.  When you get a bunch of smart people together to work on a problem, the tendency is to strive for the &#8220;perfect&#8221; solution.  Why not?  &#8220;We can do it,&#8221; you think.  And you&#8217;re probably right &mdash; given enough time, you probably can.  The problem is that you don&#8217;t have enough time.  Customers need solutions <i>yesterday</i>, not a year from now.  If you can deliver something that solves 80% of the problem, that&#8217;s probably good enough to at least get your foot in the door, and for many users that may be good enough, period.</li>
<li><b>You&#8217;ll never &#8220;get away with&#8221; not implementing something</b>.  At least, not for very long.  That doesn&#8217;t mean you have to do everything right away.  It just means don&#8217;t be surprised when you end up having to go back and fill in all those corners you cut.</li>
<li><b>For mission critical apps, crashing is unacceptable in any context</b>.  Some people seem to think that crashing is an acceptable response for some kinds of errors, particularly out-of-memory errors.  Try telling that to the customer that has a build that was running for several hours and then just died.  Not cool.  If at all possible, the application should keep running, even if it has to do so with siginficantly degraded performance.  If you can change the conversation from, &#8220;My build crashed!!  FIX IT FIX IT FIX IT&#8221; to &#8220;My build is not as fast as I would like,&#8221; that&#8217;s already a win.</li>
<li><b>The adage about premature optimization is NOT an excuse to write sloppy code</b>.  Yes, yes, <a href="http://en.wikipedia.org/wiki/Program_optimization#When_to_optimize">&#8220;Premature optimization is the root of all evil.&#8221;</a>  Agreed.  But that does not absolve the developer from using his brain during development.  You should be cognizent of the performance decisions you&#8217;re making, even if you choose not to optimize something right away.  And if it&#8217;s just as easy to implement something using a more efficient algorithm, you should do so.  This is particularly important for an application like Accelerator, where performance is the entire <a href="http://en.wikipedia.org/wiki/Raison_d'être">raison d&#8217;&#234;tre</a>.</li>
<li><b>&#8220;Clever&#8221; code isn&#8217;t</b>.  We&#8217;ve all done this at some point.  You write a little bit of code, and you realize that if you&#8217;re very clever, you can use a single field to represent two values, or you can rewrite a loop using a single line of STL algorithm-fu with <a href="http://www.cplusplus.com/reference/std/functional/bind2nd/"><tt>bind2nd</tt></a> this and <a href="http://www.cplusplus.com/reference/std/functional/mem_fun/"><tt>mem_fun</tt></a> that.  The problem is, nobody will remember how that &#8220;clever&#8221; bit of code is supposed to work in six months or a year &mdash; not even you will, in all likelihood.  You&#8217;re much better off writing <b>clear</b> code, and leaving the &#8220;clever&#8221; stuff for the cowboys who participate in things like the <a href="http://www.ioccc.org/">IOCCC</a>.</li>
<li><b>Don&#8217;t be afraid of change</b>.  In a small company like Electric Cloud, change is inevitable.  Those of us that are still here from that original team all have different roles and responsibilities than we did when we first set out on this journey.  The focus of the company as a whole has grown and shifted.  All of these were scary to some degree.  The important thing is that you don&#8217;t let yourself be paralyzed by that fear, but rather that you embrace the changes for the opportunities they present.  What fun would it be if everything just stayed the same forever?</li>
<li><b>If you fold in the side mirrors, a 1999 Volkswagon Jetta will fit &mdash; <i>barely</i> &mdash; through a standard US commercial double-door frame</b>.  But, it&#8217;s really hard to get oil stains out of carpet:<br />
</p>
<table align="center">
<caption align="bottom"><font size="-2">The start of an elaborate practical joke&#8230;</font></caption>
<tr>
<td><a href="http://ecloud.files.wordpress.com/2009/10/jetta_cropped.jpg"><img src="http://ecloud.files.wordpress.com/2009/10/jetta_cropped.jpg?w=265&#038;h=300" alt="jetta_cropped" title="jetta_cropped" width="265" height="300" class="aligncenter size-medium wp-image-592" /></a></td>
</tr>
</table>
</li>
</ol>
<p><h3>Looking forward</h3>
</p>
<p>
This is just a sample of the things I&#8217;ve learned here at Electric Cloud.  Here&#8217;s looking forward to another seven years and many more lessons &mdash; as they say, the day you stop learning is the day you die.</p>
<br />Posted in Software Development Tagged: Electric Cloud <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/ecloud.wordpress.com/590/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/ecloud.wordpress.com/590/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/ecloud.wordpress.com/590/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/ecloud.wordpress.com/590/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/ecloud.wordpress.com/590/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/ecloud.wordpress.com/590/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/ecloud.wordpress.com/590/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/ecloud.wordpress.com/590/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/ecloud.wordpress.com/590/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/ecloud.wordpress.com/590/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.electric-cloud.com&blog=5211544&post=590&subd=ecloud&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://blog.electric-cloud.com/2009/11/02/seven-lessons-from-seven-years-at-electric-cloud/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/6344c5478a4b5f0e8c546c736b2a7e0d?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=PG" medium="image">
			<media:title type="html">ericm</media:title>
		</media:content>

		<media:content url="http://ecloud.files.wordpress.com/2009/10/team_new.jpg?w=300" medium="image">
			<media:title type="html">team_new</media:title>
		</media:content>

		<media:content url="http://ecloud.files.wordpress.com/2009/10/team_old.jpg?w=300" medium="image">
			<media:title type="html">team_old</media:title>
		</media:content>

		<media:content url="http://ecloud.files.wordpress.com/2009/10/jetta_cropped.jpg?w=265" medium="image">
			<media:title type="html">jetta_cropped</media:title>
		</media:content>
	</item>
		<item>
		<title>What is SparkBuild?</title>
		<link>http://blog.electric-cloud.com/2009/10/27/what-is-sparkbuild/</link>
		<comments>http://blog.electric-cloud.com/2009/10/27/what-is-sparkbuild/#comments</comments>
		<pubDate>Tue, 27 Oct 2009 17:34:50 +0000</pubDate>
		<dc:creator>Eric Melski</dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[SparkBuild]]></category>
		<category><![CDATA[subbuild]]></category>

		<guid isPermaLink="false">http://blog.electric-cloud.com/?p=569</guid>
		<description><![CDATA[At the 2009 Electric Cloud Customer Summit we introduced SparkBuild, a free gmake- and NMAKE-compatible build tool.  SparkBuild is now in public beta, and several people have asked us for some more explanation:  what is SparkBuild and why should I care?  I thought I&#8217;d take a crack at answering those questions, hopefully [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.electric-cloud.com&blog=5211544&post=569&subd=ecloud&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>At the 2009 Electric Cloud Customer Summit we introduced <a href="http://www.sparkbuild.com/">SparkBuild</a>, a free gmake- and NMAKE-compatible build tool.  SparkBuild is now in public beta, and several people have asked us for some more explanation:  <i>what is SparkBuild and why should I care?</i>  I thought I&#8217;d take a crack at answering those questions, hopefully without sounding too &#8220;marketingy&#8221;.  Here goes.</p>
<p>
SparkBuild is actually a package containing two components:  SparkBuild emake and SparkBuild Insight.  As the names imply, these components are derived from the corresponding pieces of ElectricAccelerator and ElectricInsight.  That means that they offer some of the same benefits that our commercial product does, but for free, of course.  Why did we do this?  I&#8217;ll be completely honest with you:  we&#8217;re hoping that people will use SparkBuild, share SparkBuild and talk about SparkBuild, ultimately raising awareness of Electric Cloud and our commerical products.  Beyond that though, I&#8217;m personally excited about SparkBuild because I want to see these technologies that I&#8217;ve worked on for so long get used by as many people as possible.
</p>
<p>
I think you&#8217;ll be interested in SparkBuild because it offers some of the same benefits that our commercial tools do (annotation and build analysis), and even some that aren&#8217;t yet part of Accelerator (subbuilds).  Read on to learn more about what these features provide and how you can use them.<br />
<span id="more-569"></span>
</p>
<p><h3>Annotation</h3>
</p>
<p>
SparkBuild emake can emit XML-annotated build logs, or <i>annotation</i>.  The additional information includes data like:
</p>
<ul>
<li>The environment and working directory used to run each command.</li>
<li>The exact, expanded command-line of each command &mdash; even those that were run in &#8220;silent&#8221; mode with the <i>@</i> prefix.</li>
<li>The runtime of each command.</li>
<li>The relationship between submakes in the build.</li>
<li>The build dependency graph.</li>
</ul>
<p>
This is the kind of information you&#8217;ve been trying to get out of your build tool for years (raise your hand if you&#8217;ve ever sprinkled <i>date</i> commands in your makefiles for performance measurement!).  Now sophisticated analysis of your build is possible, and many useful reports are trivial one-liners using standard XML processing tools like <a href="http://freshmeat.net/projects/xmlclitools/">the XML command-line tools</a>.  For example:
</p>
<ul>
<li><b>Pinpoint failed commands</b>: <i>xmlgrep -g -f build.anno 0 &#8220;job:type!=remake.failed&#8221;</i></li>
<li><b>Find the prereqs of any target</b>: <i>xmlgrep -g -f build.anno 0 &#8220;job.waitingJobs:idList~=Jb4220fbc&#8221;</i></li>
<li><b>Find targets that have a given prereq</b>: <i>xmlgrep -g -f full.xml 0 &#8220;job:id=Jb4220fbc&#8221; | xmlfmt job.waitingJobs:idList</i></li>
</ul>
<p><h3>SparkBuild Insight</h3>
</p>
<p>
Not everybody has the time to code up fancy analysis of the data in annotation, so SparkBuild includes SparkBuild Insight, a derivative of ElectricInsight, our commercial build visualization and analysis tool.  Although it doesn&#8217;t have all the reports that ElectricInsight does, don&#8217;t make the mistake of thinking it&#8217;s underpowered.  You can:
</p>
<ul>
<li>&#8230; see the amount of time spent on different types of work, like compiles, links, etc.:<br />
<a href="http://ecloud.files.wordpress.com/2009/10/timebytype2.png"><img src="http://ecloud.files.wordpress.com/2009/10/timebytype2.png?w=300&#038;h=206" alt="timebytype" title="timebytype" width="300" height="206"/></a></li>
<li>&#8230; see the specific targets associated with each type of work:<br />
<a href="http://ecloud.files.wordpress.com/2009/10/legend1.png"><img src="http://ecloud.files.wordpress.com/2009/10/legend1.png?w=300&#038;h=139" alt="legend" title="legend" width="300" height="139"/></a></li>
<li>&#8230; drill into targets to see the commands executed and the output from those commands:<br />
<a href="http://ecloud.files.wordpress.com/2009/10/details1.png"><img src="http://ecloud.files.wordpress.com/2009/10/details1.png?w=300&#038;h=182" alt="details" title="details" width="300" height="182"/></a></li>
<li>&#8230; search for targets using numerous criteria, like runtime, commands, name, and type of work:<br />
<a href="http://ecloud.files.wordpress.com/2009/10/search1.png"><img src="http://ecloud.files.wordpress.com/2009/10/search1.png?w=300&#038;h=211" alt="search" title="search" width="300" height="211"/></a></li>
</ul>
<p><h3>Subbuilds</h3>
</p>
<p>
Subbuilds are build avoidance done right:  literally skipping entire swaths of the build tree by building only the parts of the tree that are relevant to the work you&#8217;re doing <i>now</i>.  This is one of those features I wish we had implemented years ago when we first thought of it, because it really is that useful to me on a daily basis.  My edit-build-test cycle is faster, and I never have to deal with incremental builds that break because I pulled in another developer&#8217;s changes to one of my prerequisite libraries when I resynced to the source repository.  You can <a href="http://blog.electric-cloud.com/2009/10/21/subbuilds-build-avoidance-done-right/">read more about subbuilds here</a>.
</p>
<p><h3>Availability</h3>
</p>
<p>
SparkBuild is in public beta and is available for download at <a href="http://www.sparkbuild.com/">www.sparkbuild.com</a>.  You&#8217;ll also find documentation and videos explaining how to use SparkBuild, and user forums where you can get help from Electric Cloud employees and what we hope will be a thriving community of users.  Try it out and let us know what you think!</p>
<br />Posted in Software Development, SparkBuild Tagged: SparkBuild, subbuild <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/ecloud.wordpress.com/569/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/ecloud.wordpress.com/569/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/ecloud.wordpress.com/569/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/ecloud.wordpress.com/569/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/ecloud.wordpress.com/569/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/ecloud.wordpress.com/569/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/ecloud.wordpress.com/569/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/ecloud.wordpress.com/569/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/ecloud.wordpress.com/569/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/ecloud.wordpress.com/569/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.electric-cloud.com&blog=5211544&post=569&subd=ecloud&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://blog.electric-cloud.com/2009/10/27/what-is-sparkbuild/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/6344c5478a4b5f0e8c546c736b2a7e0d?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=PG" medium="image">
			<media:title type="html">ericm</media:title>
		</media:content>

		<media:content url="http://ecloud.files.wordpress.com/2009/10/timebytype2.png?w=300" medium="image">
			<media:title type="html">timebytype</media:title>
		</media:content>

		<media:content url="http://ecloud.files.wordpress.com/2009/10/legend1.png?w=300" medium="image">
			<media:title type="html">legend</media:title>
		</media:content>

		<media:content url="http://ecloud.files.wordpress.com/2009/10/details1.png?w=300" medium="image">
			<media:title type="html">details</media:title>
		</media:content>

		<media:content url="http://ecloud.files.wordpress.com/2009/10/search1.png?w=300" medium="image">
			<media:title type="html">search</media:title>
		</media:content>
	</item>
		<item>
		<title>Subbuilds: build avoidance done right</title>
		<link>http://blog.electric-cloud.com/2009/10/21/subbuilds-build-avoidance-done-right/</link>
		<comments>http://blog.electric-cloud.com/2009/10/21/subbuilds-build-avoidance-done-right/#comments</comments>
		<pubDate>Wed, 21 Oct 2009 23:12:37 +0000</pubDate>
		<dc:creator>Eric Melski</dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[SparkBuild]]></category>
		<category><![CDATA[Agile]]></category>
		<category><![CDATA[annotation]]></category>
		<category><![CDATA[ElectricAccelerator]]></category>
		<category><![CDATA[incremental build]]></category>
		<category><![CDATA[makefile]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[subbuild]]></category>

		<guid isPermaLink="false">http://blog.electric-cloud.com/?p=552</guid>
		<description><![CDATA[I&#8217;ve heard it said that the best programmer is a lazy programmer.  I&#8217;ve always taken that to mean that the best programmers avoid unnecessary work, by working smarter and not harder; and that they focus on building only those features that are really required now, not allowing speculative work to distract them.

I wouldn&#8217;t presume [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.electric-cloud.com&blog=5211544&post=552&subd=ecloud&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve heard it said that the best programmer is a lazy programmer.  I&#8217;ve always taken that to mean that the best programmers avoid unnecessary work, by working smarter and not harder; and that they focus on building only those features that are really required <i>now</i>, not allowing speculative work to distract them.</p>
<p>
I wouldn&#8217;t presume to call myself a great programmer, but I definitely hate doing unnecessary work.  That&#8217;s why the concept of <i>build avoidance</i> is so intriguing.  If you&#8217;ve spent any time on the build speed problem, you&#8217;ve probably come across this term.  Unfortunately it&#8217;s been conflated with the single technique implemented by tools like <a href="http://ccache.samba.org/">ccache</a> and <a href="http://en.wikipedia.org/wiki/ClearCase#Features">ClearCase winkins</a>.  I say &#8220;unfortunate&#8221; for two reasons:  first, those tools don&#8217;t really work all that well, at least not for individual developers; and second, the technique they employ is not really build avoidance at all, but rather <i>object reuse</i>.  But by co-opting the term <i>build avoidance</i> and associating it with such lackluster results, many people have become dismissive of build avoidance.
</p>
<p>
<i>Subbuilds</i> are a more literal, and more effective, approach to build avoidance:  reduce build time by building only the stuff required for your active component.  Don&#8217;t waste time building the stuff that&#8217;s not related to what you&#8217;re working on <i>now</i>.  It seems so obvious I&#8217;m almost embarrassed to be explaining it.  But the payoff is anything but embarrassing.  On my project, after making changes to one of the prerequisites libraries for the application I&#8217;m working on, a regular incremental takes 10 minutes; a subbuild incremental takes just 77 seconds:
</p>
<table>
<tr>
<td align="right">Standard&nbsp;incremental:</td>
<td>
<div style="background:#85aef7;width:305px;">609s</div>
</td>
</tr>
<tr>
<td align="right">Subbuild&nbsp;incremental:</td>
<td>
<div style="background:#a3ffa3;width:39px;">77s</div>
</td>
</tr>
</table>
<p>Not bad!  Read on for more about how subbuilds work and how you can get <a href="http://www.sparkbuild.com/"><b>SparkBuild</b></a>, a free gmake- and NMAKE-compatible build tool, so you can try subbuilds yourself.<br />
<span id="more-552"></span></p>
<p><h3>What is a subbuild?</h3>
</p>
<p>
A subbuild is just the smallest part of a full build tree that must be built in order to completely build a single component of the build, including all its prerequisites.  For example, my project consists of several applications and the libraries they depend on.  Each of these components resides in a separate directory, and we use recursive make invocations to build everything.  (<i>Nota bene</i>:  if you have a non-recursive make then you probably already enjoy many of the benefits of subbuilds, but you should definitely still <a href="http://blog.electric-cloud.com/2009/10/27/what-is-sparkbuild/">check out the other features of SparkBuild</a>!)
</p>
<p>
The dependency graph for my project looks like this:
</p>
<p>
<img src="http://ecloud.files.wordpress.com/2009/10/depgraph.png"/>
</p>
<p>
You can see that to build the <i>agent</i> component, for example, we only need to build the <i>util</i>, <i>xml</i>, and <i>http</i> libraries, and the <i>agent</i> application code, of course:
</p>
<p>
<img src="http://ecloud.files.wordpress.com/2009/10/subbuild.png"/>
</p>
<p>
This subset defines the agent subbuild.
</p>
<p><h3>Subbuilds and developers</h3>
</p>
<p>
What makes subbuilds really interesting for developers is the realization that usually you&#8217;re working on just one component at a time.  For example, on any given day I might be working on the agent component, or the cm, but rarely both.  Most of the edits I make will be on code in the <i>agent</i> directory, with occassional edits to the agent&#8217;s prerequisites.  As I&#8217;m running through the edit-compile-test cycle, I have some choices about how to run the build.  The most natural thing for me is to simply run <i>make</i> in the <i>agent</i> directory.  After all, most of the changes I make are in that directory, so that will do the right thing most of the time.  Of course, if I have made changes to any of the prerequisites, or if I resync with the source depot and pick up somebody else&#8217;s changes in one of those prerequisites, I&#8217;ll probably get a busted build.
</p>
<p>
The next most obvious approach is a rebuild from the root of my source tree.  This ensures that I always update all the pieces I need for the agent, but at the cost of also building components that are irrelevant to my current focus:  if I&#8217;m just trying to rebuild to run the agent&#8217;s unit tests, there&#8217;s no need for me to rebuild the <i>cm</i> application, or the <i>ldap</i> library.
</p>
<p>
The best choice is the agent subbuild, the minimum set of things that must be built to be sure that the agent component is fully up-to-date.  But although it&#8217;s possible on a small project like this to execute the subbuild manually, it&#8217;s a nuisance, and on a bigger project it may not be practical or even possible.  You need a build tool that can <i>automatically</i> determine which parts of the build make up the subbuild for any component, and then <i>automatically</i> execute that subbuild.  That tool is SparkBuild emake.
</p>
<p><h3>Subbuilds with SparkBuild</h3>
</p>
<p>
Subbuilds with SparkBuild start with a full build, during which emake captures information about which targets are produced by each submake.  In subsequent builds, emake references that database anytime it can&#8217;t find a rule to build a particular target.  If a match is found, emake runs the corresponding submake before proceeding.  For example, the rule for the actual agent target looks like this:
</p>
<p><pre>$(OUT)/agent/agent: $(OUT)/agent/*.o $(OUT)/xml/xml.a $(OUT)/http/http.a
	g++ -o $@ $^
</pre>
</p>
<p>
In a normal build, gmake would see the dependency on <i>$(OUT)/xml/xml.a</i> and use that file if it existed already, regardless of whether it was actually up-to-date; or report &#8220;no rule to make&#8221; if the file did not exist.  With SparkBuild, emake checks the subbuild database for an entry matching <i>$(OUT)/xml/xml.a</i> and sees that it must run <i>make</i> in the <i>xml</i> directory before proceeding.  Like magic, each of the agent&#8217;s prerequisites is updated without requiring me to take any action other than swapping <i>emake &#8211;emake-subbuild-db=my.db</i> for <i>gmake</i> in my build command-line.
</p>
<p>
Still not convinced that it&#8217;s worth a look?  Here&#8217;s some more concrete results comparing a few different build scenarios from my project.  These comparisons assume that I&#8217;m actively working on the <i>agent</i> component, and that I ran either a standard incremental, from the root of the source tree, or a subbuild using SparkBuild emake:
</p>
<table>
<caption align="bottom"><font size="-1">Normal builds versus subbuilds (serial build time, shorter is better)</font></caption>
<tr>
<td>No&nbsp;changes,&nbsp;standard:</td>
<td>
<div style="background:#85aef7;width:10px;">19s</div>
</td>
</tr>
<tr>
<td>No&nbsp;changes,&nbsp;subbuild:</td>
<td>
<div style="background:#a3ffa3;width:0;">0.5s</div>
</td>
</tr>
<tr>
<td colspan="2">
<hr /></td>
</tr>
<tr>
<td>Changes&nbsp;in&nbsp;<i>agent</i>,&nbsp;standard:</td>
<td>
<div style="background:#85aef7;width:41px;">81s</div>
</td>
</tr>
<tr>
<td>Changes&nbsp;in&nbsp;<i>agent</i>,&nbsp;subbuild:</td>
<td>
<div style="background:#a3ffa3;width:16px;">31s</div>
</td>
</tr>
<tr>
<td colspan="2">
<hr /></td>
</tr>
<tr>
<td>Changes&nbsp;in&nbsp;<i>util</i>,&nbsp;standard:</td>
<td>
<div style="background:#85aef7;width:305px;">609s</div>
</td>
</tr>
<tr>
<td>Changes&nbsp;in&nbsp;<i>util</i>,&nbsp;subbuild:</td>
<td>
<div style="background:#a3ffa3;width:39px;">77s</div>
</td>
</tr>
<tr>
<td colspan="2">
<hr /></td>
</tr>
<tr>
<td>Full&nbsp;build:</td>
<td>
<div style="background:#85aef7;width:364px;">729s</div>
</td>
</tr>
<tr>
<td>Subbuild&nbsp;build:</td>
<td>
<div style="background:#a3ffa3;width:59px;">118s</div>
</td>
</tr>
</table>
<p><h3>Conclusion and Availability</h3>
</p>
<p>
Tools like ccache and ClearCase winkins have co-opted the term <i>build avoidance</i>, but in fact they do <i>object reuse</i>, not build avoidance, and they are not very useful for developer builds.  Subbuilds are a simple but highly effective approach to build avoidance that save significant time during developer builds by literally skipping parts of the build tree that are unrelated to your current focus.
</p>
<p>
If you want to try out subbuilds yourself, you can download SparkBuild from <a href="http://www.sparkbuild.com/">www.sparkbuild.com</a>.  It&#8217;s completely free (<a href="http://en.wikipedia.org/wiki/Gratis_versus_Libre#.22Free_as_in_beer.22_vs_.22Free_as_in_speech.22">as in beer</a>), so you&#8217;ve got nothing to lose&#8230; except those long coffee breaks, of course!</p>
<br />Posted in Software Development, SparkBuild Tagged: Agile, annotation, ElectricAccelerator, incremental build, makefile, performance, SparkBuild, subbuild <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/ecloud.wordpress.com/552/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/ecloud.wordpress.com/552/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/ecloud.wordpress.com/552/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/ecloud.wordpress.com/552/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/ecloud.wordpress.com/552/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/ecloud.wordpress.com/552/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/ecloud.wordpress.com/552/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/ecloud.wordpress.com/552/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/ecloud.wordpress.com/552/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/ecloud.wordpress.com/552/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.electric-cloud.com&blog=5211544&post=552&subd=ecloud&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://blog.electric-cloud.com/2009/10/21/subbuilds-build-avoidance-done-right/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/6344c5478a4b5f0e8c546c736b2a7e0d?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=PG" medium="image">
			<media:title type="html">ericm</media:title>
		</media:content>
	</item>
		<item>
		<title>Private clouds: more than just buzzword bingo</title>
		<link>http://blog.electric-cloud.com/2009/10/05/private-clouds-more-than-just-buzzword-bingo/</link>
		<comments>http://blog.electric-cloud.com/2009/10/05/private-clouds-more-than-just-buzzword-bingo/#comments</comments>
		<pubDate>Mon, 05 Oct 2009 17:22:16 +0000</pubDate>
		<dc:creator>Eric Melski</dc:creator>
				<category><![CDATA[Cloud Computing]]></category>
		<category><![CDATA[Virtualization]]></category>
		<category><![CDATA[cloud]]></category>
		<category><![CDATA[testing]]></category>
		<category><![CDATA[Virtual Infrastructure]]></category>
		<category><![CDATA[vmware]]></category>

		<guid isPermaLink="false">http://blog.electric-cloud.com/?p=547</guid>
		<description><![CDATA[A friend pointed me to a blog in which Ronald Schmelzer, an analyst at ZapThink, asserts that the term &#8220;private cloud&#8221; is nothing more than empty marketing hype.  Ironically, he proposes that we instead use the term &#8220;service-oriented cloud computing.&#8221;  Maybe I&#8217;m being obtuse, but &#8220;service-oriented&#8221; anything is about the most buzzladen term [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.electric-cloud.com&blog=5211544&post=547&subd=ecloud&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>A friend pointed me to a blog in which <a href="http://briefingsdirectblog.blogspot.com/2009/10/private-clouds-valuable-concept-or.html">Ronald Schmelzer, an analyst at ZapThink, asserts that the term &#8220;private cloud&#8221; is nothing more than empty marketing hype</a>.  Ironically, he proposes that we instead use the term &#8220;service-oriented cloud computing.&#8221;  Maybe I&#8217;m being obtuse, but &#8220;service-oriented&#8221; anything is about the most buzzladen term I&#8217;ve heard in the last five years.  Seriously, have you read the <a href="http://en.wikipedia.org/wiki/Service_Oriented_Architecture">SOA article on Wikipedia</a>?  It&#8217;s over 5,000 words long, chock-a-block full of the &#8220;principles of service-orientation&#8221; like &#8220;autonomy&#8221; and &#8220;composability&#8221;.  What a joke!</p>
<p>
Let me see how many words I need to define private clouds.  It&#8217;s <i>a centralized infrastructure supplied by a single organization&#8217;s IT department that provides virtualized compute resources on demand to users within that organization</i>.  Let&#8217;s see, that&#8217;s&#8230; 21 words.  Not bad, but I bet if you&#8217;re like me, you&#8217;re probably looking at that and thinking that it still doesn&#8217;t make much sense, so let me give you a concrete example.<br />
<span id="more-547"></span>
</p>
<p>
I develop cluster-based software.  Testing requires at least three computers, sometimes more.  Oh, and we develop simultaneously for seven x86-based platforms, counting all the variants of Windows and Linux that we support.  In the <i>bad old days</i>, we had a server room crammed full of rack-mounted computers, each hosting one or two operating systems.  This approach had lots of problems:
</p>
<ul>
<li><b>There was never enough to go around</b>:  even with over a hundred systems (for just 8 employees!), we were constantly fighting each other for resources, especially for the precious few multi-core systems we had.</li>
<li><b>It was inefficient</b>: one dev might reserve a set of machines for stability or performance testing and leave them tied up for days on end.  Often they were not literally using the hardware 24/7, but there was no safe way for anybody else to exploit the idle cycles.</li>
<li><b>It was limited and inflexible</b>: even with dual-boot systems we didn&#8217;t have enough to really represent the full range of operating systems we wanted to support, and honestly, although dual-boot works great on your desktop, it is a major pain when applied to a cluster of computers in a locked server room at the other end of the building.</li>
<li><b>It was wild and hairy</b>: even if you got the number and type of systems you needed, you couldn&#8217;t be sure the last guy to use them had left them in a usable state.</li>
</ul>
<p>
Sure, we could have &#8220;solved&#8221; this problem by throwing money at it:  a bigger server room, more computers, a new A/C system to keep all those computers cool (yes, that was really a stumbling block for us for a long time), and of course, time to install and configure the extra systems.  What a mess!
</p>
<p>
Today, we&#8217;ve replaced that pile of computers with a <i>private cloud</i>:  a VMWare LabManager instance managed by our IT department.  When I want to run a test, I use LabManager to provision a cluster containing as many computers as I want, running whatever OS I choose.  With a few clicks of the mouse, I have a cluster of virtual machines at my disposal, booted and initialized to a known good state.  I can grow the cluster as needed, or create a second cluster to run tests of a different feature or on a different OS.  Other devs and QA can simultaneously deploy their own clusters without worrying about stepping on my toes.  When I&#8217;m done, I click another button and my virtual test cluster vanishes without a trace, leaving no wasted resources or idle computers behind.
</p>
<p>
But of course, these benefits &mdash; scalability, flexibility, reusability, reproducibility, etc &mdash; are the hallmark of cloud computing in general.  What&#8217;s special about <i>private</i> clouds then?  For me it comes down to one thing:  <b>bandwidth</b>.  As you know, <a href="http://blog.electric-cloud.com/2009/09/14/getting-data-to-the-cloud/">getting your data into and out of a public cloud is a major problem</a>, with no clear solution.  But getting my data into and out of a private cloud on my high-speed corporate LAN is trivial.  It&#8217;s that simple.  For our needs, the public cloud just doesn&#8217;t quite cut it, because we have too much data (in the form of VM images and test data) to be schlepping back and forth across the Internet.  Moving the cloud inside the corporate network solves that problem.  As an added bonus, we don&#8217;t have to worry about whether or intellectual property is secure on some external corporation&#8217;s servers.  Our stuff never leaves our network.
</p>
<p>
I think where Ronald and his pundit pals go wrong is in thinking about cloud computing as being only for providing services and applications from your company to your customers.  As a developer, I can tell you that cloud computing also addresses a real need by supporting development and testing activities within a company, and private clouds make that technology practical for users with high bandwidth requirements.</p>
<br />Posted in Cloud Computing, Virtualization Tagged: cloud, testing, Virtual Infrastructure, Virtualization, vmware <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/ecloud.wordpress.com/547/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/ecloud.wordpress.com/547/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/ecloud.wordpress.com/547/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/ecloud.wordpress.com/547/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/ecloud.wordpress.com/547/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/ecloud.wordpress.com/547/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/ecloud.wordpress.com/547/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/ecloud.wordpress.com/547/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/ecloud.wordpress.com/547/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/ecloud.wordpress.com/547/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.electric-cloud.com&blog=5211544&post=547&subd=ecloud&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://blog.electric-cloud.com/2009/10/05/private-clouds-more-than-just-buzzword-bingo/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/6344c5478a4b5f0e8c546c736b2a7e0d?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=PG" medium="image">
			<media:title type="html">ericm</media:title>
		</media:content>
	</item>
		<item>
		<title>Using Markov Chains to Generate Test Input</title>
		<link>http://blog.electric-cloud.com/2009/09/15/using-markov-chains-to-generate-test-input/</link>
		<comments>http://blog.electric-cloud.com/2009/09/15/using-markov-chains-to-generate-test-input/#comments</comments>
		<pubDate>Tue, 15 Sep 2009 14:46:00 +0000</pubDate>
		<dc:creator>Eric Melski</dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[ElectricAccelerator]]></category>
		<category><![CDATA[gmake]]></category>
		<category><![CDATA[gnu make]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://blog.electric-cloud.com/?p=542</guid>
		<description><![CDATA[One challenge that we&#8217;ve faced at Electric Cloud is how to verify that our makefile parser correctly emulates GNU Make.  We started by generating test cases based on a close reading of the gmake manual.  Then we turned to real-world examples:  makefiles from dozens of open source projects and from our customers. [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.electric-cloud.com&blog=5211544&post=542&subd=ecloud&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>One challenge that we&#8217;ve faced at Electric Cloud is how to verify that our makefile parser correctly emulates GNU Make.  We started by generating test cases based on a close reading of the gmake manual.  Then we turned to real-world examples:  makefiles from dozens of open source projects and from our customers.  After several years of this we&#8217;ve accumulated nearly two thousand individual tests of our gmake emulation, and yet we still sometimes find incompatibilities.  We&#8217;re always looking for new ways to test our parser.</p>
<p>
One idea is to generate random text and use that as a &#8220;makefile&#8221;.  Unfortunately, truly random text is almost useless in this regard, because it doesn&#8217;t look anything like a real makefile.  Instead, we can use <a href="http://en.wikipedia.org/wiki/Markov_chain"><i>Markov chains</i></a> to generate random text that is very much like a real makefile.  When we first introduced this technique, we uncovered 13 previously unknown incompatibilities &mdash; at the time that represented 10% of the total defects reported against the parser!  Read on to learn more about Markov chains and how we applied them in practice.<br />
<span id="more-542"></span>
</p>
<p><h3>Markov chains</h3>
</p>
<p>
A Markov chain is simply a sequence of random values in which the next value is in some way dependent on the current value, rather than being completely random.  Consider the case of generating random text one letter at a time, from the set of uppercase English letters (A-Z).  If the sequence is completely random, then for each character generated, any letter is equally probable.  Regardless of what characters you&#8217;ve generated up to this point, you are just as likely to get a <i>D</i> as an <i>X</i> next.  Think of it as if you have a bag of tiles, one for each letter.  With truly random text, you pick one tile and write down the letter on that tile.  Then you return the tile to the bag and pick again.  Lather, rinse, repeat until you&#8217;ve generated as much text as you like.
</p>
<p>
But suppose we said that the probability of the next character is dependent on the last character we generated.  For example, in English text if you run across the letter <i>Q</i> you can be pretty sure that the next character is going to be <i>U</i>.  It&#8217;s almost certainly not going to be <i>X</i>, or <i>Z</i>, etc.  We can build a table that tells us the probabilty that any given letter will be followed by any other letter.  For the letter <i>Q</i>, the table might look like this:
</p>
<table>
<tr>
<td>Letter</td>
<td>Probability of appearing after <i>Q</i></td>
</tr>
<tr>
<td>A</td>
<td>1%</td>
</tr>
<tr>
<td>E</td>
<td>1%</td>
</tr>
<tr>
<td>I</td>
<td>1%</td>
</tr>
<tr>
<td>O</td>
<td>1%</td>
</tr>
<tr>
<td>U</td>
<td>96%</td>
</tr>
<tr>
<td>All others</td>
<td>0%</td>
</tr>
</table>
<p>
We can do a much better job of generating text that looks like English if we use these tables to guide us.  Imagine that instead of one bag of tiles with one tile for each letter, we have one bag for each letter, and we fill each bag with tiles according to the probabilities in our table.  For example, the bag for the letter <i>Q</i> would contain 96 <i>U</i> tiles, and one tile each for <i>A</i>, <i>E</i>, <i>I</i>, and <i>O</i>.  Each time we want to generate a new letter, we look at the last letter we generated, find the bag of tiles corresponding to that letter, and pick out one tile.  After writing down the letter, we return the tile to the bag and repeat the process.  The sequence of letters that we generate in this manner is a simple Markov chain.
</p>
<p>
How do you build the probability tables?  One way is to generate them from some sample input.  If we have a sufficiently large example of text in the target language, we can scan it and count the number of times each letter occurs, and the number of times it is followed by each letter.  Note that it is critical to have a large and varied input.  If the sample is too small, the resulting probability tables won&#8217;t accurately represent the target language.  The generator will only be able to generate the input text itself.
</p>
<p><h3>Markov chains of order <i>m</i></h3>
</p>
<p>
Of course, we don&#8217;t have to limit ourselves to considering just the single previous letter.  For example, if the previous two characters are <i>ST</i>, then the next character is probably a vowel, or maybe an <i>R</i>.  It&#8217;s probably not going to be <i>D</i>, or <i>Q</i>, etc.  Just as before, we can make a table that tells us the probability that any given pair of letters will be followed by any other letter.  And we can keep going, adding more and more of the preceding letters to our formula.  The number of previous characters we use is called the <i>order</i> of the chain, so if we use the previous 4 characters, we would say we have a <i>Markov chain of order 4</i>.
</p>
<p>
The greater the order of the chain, the &#8220;smarter&#8221; our generator becomes, because it is considering more context when choosing letters.  As you can see, the generated text looks more and more like the target language as you increase the order (although after a some point, you get little additional benefit from further increases):
</p>
<table>
<tr>
<td>Order</td>
<td>Result</td>
</tr>
<tr>
<td>0 (purely random)</td>
<td>ehnee.Alr noer ealcra edctn eIi</td>
</tr>
<tr>
<td>1</td>
<td>Pige foule.ce d futht wrion e mara</td>
</tr>
<tr>
<td>2</td>
<td>Prookiname arg-tm aread on achivedging</td>
</tr>
<tr>
<td>3</td>
<td>Yes, and no usinession be</td>
</tr>
<tr>
<td>4</td>
<td>Project that last it make you first, moderneath.</td>
</tr>
</table>
<p><h3>Using Markov chains in testing</h3>
</p>
<p>
In order to use this technique effectively in testing, you need a couple of things besides the generator itself:
</p>
<ol>
<li><b>A large sample input to seed the generator</b>.  As noted, the bigger your sample input text, the higher the quality of the probability tables, and therefore the more varied your generated text will be.  Since we are trying to generate makefiles, we used several megabytes of makefiles from a variety of open-source projects as the sample text.</li>
<li><b>An automated evaluation mechanism</b>.  You have to be able to determine quickly and automatically if a given generated file is processed correctly or not.  Of course, <i>correct</i> can mean many different things here.  It might be as simple as &#8220;does not cause a program crash&#8221;.  In our case, it means &#8220;emake parses this makefile the same way that gmake does&#8221;, so we use gmake as a <a href="http://en.wikipedia.org/wiki/Reference_implementation"><i>reference implementation</i></a>.  Note that it doesn&#8217;t matter if the generated text truly is a completely valid makefile.  In fact most of the time it will not be.  What matters is those cases is that emake and gmake both report the <i>same</i> error.</li>
</ol>
<p>
We wrote a simple shell script to drive the testing process.  First, it uses the generator to produce several random makefiles.  Then it runs each makefile through both gmake and emake, and compares the results.  Any differences are reported for further investigation.
</p>
<p><h3>Conclusion</h3>
</p>
<p>
Verifying the implementation of an emulator for a complex system is hard, especially when the original system has no formal specification.  Using randomly generated input is a useful way to extend the breadth of your testing, and Markov chains make it possible to generate even more useful random input.  Our original implementation of this technique uncovered several previously unknown defects, and it continues to pay dividends both by uncovering new defects and by providing a confidence measure for our emulation.
</p>
<p>
If you want to play with Markov chains yourself, you can download the <a href="http://community.electric-cloud.com/display/eckb/Markov+chain+generator">source for the generator used in this article</a>.  NB: the program has only been compiled and used on Linux; on other platforms your mileage may vary.  For more information about Markov chains, I recommend <a href="http://www.cs.bell-labs.com/cm/cs/pearls/sec153.html">Section 15.3 of the excellent book <i>Programming Pearls</i> by Jon Bentley</a>.</p>
<hr />
<p>
If you enjoyed this article about testing techniques, you may enjoy this related article:
</p>
<ul>
<li><a href="http://blog.electric-cloud.com/2009/05/05/delta-the-coolest-tool-youve-never-heard-of/">Delta: the coolest tool you&#8217;ve never heard of</a></li>
</ul>
<br />Posted in Software Development Tagged: ElectricAccelerator, gmake, gnu make, testing <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/ecloud.wordpress.com/542/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/ecloud.wordpress.com/542/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/ecloud.wordpress.com/542/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/ecloud.wordpress.com/542/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/ecloud.wordpress.com/542/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/ecloud.wordpress.com/542/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/ecloud.wordpress.com/542/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/ecloud.wordpress.com/542/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/ecloud.wordpress.com/542/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/ecloud.wordpress.com/542/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.electric-cloud.com&blog=5211544&post=542&subd=ecloud&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://blog.electric-cloud.com/2009/09/15/using-markov-chains-to-generate-test-input/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/6344c5478a4b5f0e8c546c736b2a7e0d?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=PG" medium="image">
			<media:title type="html">ericm</media:title>
		</media:content>
	</item>
		<item>
		<title>Getting data to the cloud</title>
		<link>http://blog.electric-cloud.com/2009/09/14/getting-data-to-the-cloud/</link>
		<comments>http://blog.electric-cloud.com/2009/09/14/getting-data-to-the-cloud/#comments</comments>
		<pubDate>Mon, 14 Sep 2009 16:15:01 +0000</pubDate>
		<dc:creator>Eric Melski</dc:creator>
				<category><![CDATA[Cloud Computing]]></category>
		<category><![CDATA[amazon]]></category>
		<category><![CDATA[cloud]]></category>

		<guid isPermaLink="false">http://blog.electric-cloud.com/?p=539</guid>
		<description><![CDATA[One of the problems facing cloud computing is the difficulty in getting data from your local servers to the cloud.  My home Internet connection offers me maybe 768 Kbps upstream, on a good day, if I&#8217;m standing in the right place and nobody else in my neighborhood is home.  Even at the office, [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.electric-cloud.com&blog=5211544&post=539&subd=ecloud&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>One of the problems facing cloud computing is the difficulty in getting data from your local servers to the cloud.  My home Internet connection offers me maybe 768 Kbps upstream, on a good day, if I&#8217;m standing in the right place and nobody else in my neighborhood is home.  Even at the office, we have a fractional T1 connection, so we get something like 1.5 Mbps upstream.  One (just one!) of the VM images I use for testing is 3.3 GB.  Pushing that up to the cloud would take about five hours under ideal conditions!</p>
<p>
I don&#8217;t know what the solution to this problem is, yet, but it&#8217;s definitely something a lot of people are working on.  I thought I&#8217;d point out a couple of interesting ideas in this area.  First is the <a href="http://asperasoft.com/en/technology/fasp_overview_1/fasp_technology_overview_1"><i>Fast and Secure Protocol</i></a>, a TCP replacement developed by Aspera and now <a href="http://www.technologyreview.com/computing/23451/">integrated with Amazon Web Services</a>.  The basic idea is to improve transmission rates by eliminating some of the inefficiencies in TCP.  In theory this will allow you to more reliably achieve those &#8220;ideal condition&#8221; transfer rates, and if <a href="http://asperasoft.com/en/technology/fasp_transfer_times_14/fasp_transfer_times_14">their benchmarks</a> are to be believed, they&#8217;ve done just that.  However, all this does is help me ensure that transferring my VM image really does take &#8220;only&#8221; 5 hours &mdash; so I guess that&#8217;s good, but this doesn&#8217;t seem like a revolution.
</p>
<p>
From my perspective, a more interesting idea is <a href="http://pdos.csail.mit.edu/lbfs/"><i>LBFS</i></a>, the low-bandwidth filesystem.  This is a network filesystem, like NFS, but expressly designed for use over &#8220;skinny&#8221; network connections.  It was developed several years ago at MIT, but I hadn&#8217;t heard of it until today, so I imagine many of you probably haven&#8217;t either.  The most interesting idea in LBFS is that you can reduce the amount of data you transfer by exploiting commonalities between different files or different versions of the same file.  Basically, you compute a hash for every block of every file that is transferred, and then you only send blocks that haven&#8217;t already been sent.  On the client side, it takes the list of hashes and uses them to reassemble the file.  This can give you a dramatic reduction in bandwidth requirements.  For example, consider PDB files, the debugging information generated by the Visual C++ compiler:  every time you compile another object referencing the same PDB, new symbols are added to it and some indexes are updated, but most of the data remains unchanged.
</p>
<p>
Like I said, I don&#8217;t know what the solution to this problem is, but there are already some exciting ideas out there, and I&#8217;m sure we&#8217;ll see even more as cloud computing continues to evolve.</p>
<br />Posted in Cloud Computing Tagged: amazon, cloud <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/ecloud.wordpress.com/539/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/ecloud.wordpress.com/539/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/ecloud.wordpress.com/539/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/ecloud.wordpress.com/539/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/ecloud.wordpress.com/539/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/ecloud.wordpress.com/539/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/ecloud.wordpress.com/539/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/ecloud.wordpress.com/539/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/ecloud.wordpress.com/539/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/ecloud.wordpress.com/539/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.electric-cloud.com&blog=5211544&post=539&subd=ecloud&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://blog.electric-cloud.com/2009/09/14/getting-data-to-the-cloud/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/6344c5478a4b5f0e8c546c736b2a7e0d?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=PG" medium="image">
			<media:title type="html">ericm</media:title>
		</media:content>
	</item>
	</channel>
</rss>