<?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>Exercise for the Reader</title>
	<atom:link href="http://exerciseforthereader.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://exerciseforthereader.wordpress.com</link>
	<description>Seth Porter&#039;s collection of problems and neat tricks</description>
	<lastBuildDate>Mon, 05 Jul 2010 17:35:57 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='exerciseforthereader.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>Exercise for the Reader</title>
		<link>http://exerciseforthereader.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://exerciseforthereader.wordpress.com/osd.xml" title="Exercise for the Reader" />
	<atom:link rel='hub' href='http://exerciseforthereader.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Server Monitoring, Revisited</title>
		<link>http://exerciseforthereader.wordpress.com/2010/07/05/server-monitoring-revisited/</link>
		<comments>http://exerciseforthereader.wordpress.com/2010/07/05/server-monitoring-revisited/#comments</comments>
		<pubDate>Mon, 05 Jul 2010 17:35:57 +0000</pubDate>
		<dc:creator>Seth Porter</dc:creator>
				<category><![CDATA[Computing Infrastructure]]></category>

		<guid isPermaLink="false">http://exerciseforthereader.wordpress.com/?p=131</guid>
		<description><![CDATA[In which we belatedly celebrate a year&#8217;s worth of baseline data; entertain an aside into intrusion detection via passive measurements; resolve some of the Mystery of the 12V Deviations; and conclude with daydreams of better sensors and monitoring beyond the box itself. A Year of Data A few months ago, I hit the milestone of [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=exerciseforthereader.wordpress.com&amp;blog=5637329&amp;post=131&amp;subd=exerciseforthereader&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><em>In which we belatedly celebrate a year&#8217;s worth of baseline data; entertain an aside into intrusion detection via passive measurements; resolve some of the Mystery of the 12V Deviations; and conclude with daydreams of better sensors and monitoring beyond the box itself.</em></p>
<h2>A Year of Data</h2>
<p>A few months ago, I hit the milestone of a full year&#8217;s worth of data collected by my <a href="http://exerciseforthereader.wordpress.com/2009/06/20/server-monitoring-with-pretty-pictures/">server monitoring tools</a>. I started a writeup at the time, which I&#8217;m finally revisiting in hopes of actually posting it. (I&#8217;ve also learned that I seem to be capturing exactly a year of historical data, which is unfortunate; I&#8217;d perhaps naively assumed that the powers-of-two backoff in storage frequency would give me an infinite time window, albeit eventually degrading to a single sample for the oldest time slice.)</p>
<p>First, a quick overview; here is a year&#8217;s worth of smoothed temperature data (the average-per-interval is plotted, whereas my usual &#8220;is something wrong&#8221; daily charts are plotting the maximum in a given interval).</p>
<div id="attachment_134" class="wp-caption aligncenter" style="width: 807px"><a href="http://exerciseforthereader.files.wordpress.com/2010/07/smoothed_1_year_temps.png"><img class="size-full wp-image-134" title="Smoothed 1 Year Temperatures" src="http://exerciseforthereader.files.wordpress.com/2010/07/smoothed_1_year_temps.png?w=797&#038;h=458" alt="" width="797" height="458" /></a><p class="wp-caption-text">Smoothed 1 Year Temperatures</p></div>
<p>The temperature curve is about what you&#8217;d predict for a computer that lives in a poorly-insulated room in Pittsburgh. I lost my outside temperature correlation data (RRDWeather gave up on me a while ago &#8211; maybe weather.com changed their policies, or just their web service API, and I never really did anything beyond sending an e-mail to the developer). However, I&#8217;m quite confident that they&#8217;re well aligned; anyone who lived here this year can pick out, say, that late warm spell we had at the end of November. The one thing that concerns me a little is the decreasing separation between the board and the drive temps; that makes me wonder if I&#8217;ve obstructed airflows a little (leading to more indirect heating of the drives). Still and all, there are no major deviations here, and a year later I&#8217;m basically in the same temp bracket that I was last July, which is somewhat soothing (and the whole point of establishing this baseline data).</p>
<p>One of the ongoing puzzles from this server-monitoring data has been the voltage data. It has a variety of odd characteristics, including daily and seasonal cycles, as well as a fair amount of apparent noise. I had thought they&#8217;d quieted down a lot when I installed a uninterruptible power supply (with supply-voltage smoothing). I still think that&#8217;s true for most of the lines, particularly the 3.3V and 1.5V rails, which are actually providing power to the chips. However, there&#8217;s still a significant variation on the 5V and 12V rails. Looking at this data for the past month, you can clearly see a daily cycle on the 12V rail through Weeks 24 and 25:</p>
<div id="attachment_136" class="wp-caption aligncenter" style="width: 607px"><a href="http://exerciseforthereader.files.wordpress.com/2010/07/voltages_past_month.png"><img class="size-full wp-image-136" title="Voltages June-July 2010" src="http://exerciseforthereader.files.wordpress.com/2010/07/voltages_past_month.png?w=597&#038;h=306" alt="" width="597" height="306" /></a><p class="wp-caption-text">Voltages June-July 2010</p></div>
<p>In the chart here, you can also see a &#8220;reboot discontinuity&#8221; at the  beginning of week 23; from memory, I think this was a kernel update.</p>
<h2>An Aside Into Passive Monitoring</h2>
<p>The occasional almost-vertical drops in voltage (noticeable in this chart at the reboot and the end of week 26) are strongly correlated with system usage (for instance, the CPU utilization chart); a co-worker has suggested that this would be an interesting approach to intrusion detection. I might get more into this in a later post, but history suggests otherwise, so please tolerate a brief excursion to look at another set of charts, in this case the history of the DNS daemon running on the server. First, the last 28 hours of data:</p>
<div id="attachment_137" class="wp-caption aligncenter" style="width: 591px"><a href="http://exerciseforthereader.files.wordpress.com/2010/07/dns_last_day.png"><img class="size-full wp-image-137" title="DNS Data - Last 28 Hours" src="http://exerciseforthereader.files.wordpress.com/2010/07/dns_last_day.png?w=581&#038;h=194" alt="" width="581" height="194" /></a><p class="wp-caption-text">DNS Data - Last 28 Hours</p></div>
<p>I haven&#8217;t spent as much time exploring the reporting mechanism for this chart, so things don&#8217;t add up as nicely as some of the others, but the intent here is that the thin blue line records the number of requests, which is then partitioned into success or failure cases. I&#8217;m not sure if the open gap (between the explained results and the number of queries) is due to failures other than NXDomain (non-existent domain), or if this is simply an artifact of differing time scales and reporting methods. I&#8217;m also not sure about the sampling time frame &#8211; this is obviously &#8220;queries per time period&#8221;, but without knowing the granularity, the absolute scale (area under the curve / total queries per hour) is meaningless. However, the basic view of local network activity is pretty compelling, as long as interpreted strictly in relative terms.</p>
<p>For a moment of background: Calliope, the server, performs both DHCP and DNS duties. Except for a couple of local hosts, DNS is simply forward and cached from Verizon&#8217;s DNS provider. The interesting bit here is that my local server provides DNS with zero &#8220;time to live&#8221;, so clients will immediately ask again if they need to resolve the same host repeatedly. This means that the record of DNS activity on the server is a reasonably accurate record of internet usage across all hosts in my network, even the uninstrumented ones like the PlayStation etc.</p>
<p>In this chart, you can see a midnight spike, probably primarily cron jobs and the like. More interestingly, you can see my flurry of surfing in late afternoon, trying to figure out whether the T was a viable way to see the city fireworks, followed by several dark hours when we were off watching things go boom. Then this morning you can see machines coming on for the first time (checking for updates, etc), a period of quiet coffee drinking (lately I&#8217;m reading &#8220;The Worst Journey in the World&#8221;, rather than surfing, over coffee), and then a steady rumble of activity as I fired up my main box and started working on this post.</p>
<p>The weekly and monthly charts have similar stories to tell, but not much additional interest; overall activity tends to peak on the weekends, and during the week there&#8217;s a definite shift to activity later in the day (when I get home from work), but this is all predictable (though useful from an intrusion-detection point of view). Before returning to the earlier question of voltage excursions, I&#8217;ll just post one more DNS chart, this time showing the past year&#8217;s activity:</p>
<div id="attachment_139" class="wp-caption aligncenter" style="width: 591px"><a href="http://exerciseforthereader.files.wordpress.com/2010/07/dns_last_year.png"><img class="size-full wp-image-139" title="DNS Data - Past Year" src="http://exerciseforthereader.files.wordpress.com/2010/07/dns_last_year.png?w=581&#038;h=194" alt="" width="581" height="194" /></a><p class="wp-caption-text">DNS Data - Past Year</p></div>
<p>For the most part, the patterns have disappeared into noise, though there&#8217;s still a definite periodicity; I wonder if my cycle of amusements (computer vs books vs television, and so forth) is really that predictable? There&#8217;s also a spike around Christmas, from shopping and travel planning, and an interesting nadir in March, which I think I can explain: this was a period of high intensity at work, and just before I started working on a consulting side-project (which explains the above-average usage for the following months). In any event, I find this data kind of interesting, though the real fun would be in correlating it against a diary or other activity measures to see if it&#8217;s really a valid proxy for how much time I spend on the computer.</p>
<h2>Back to the Voltage Fluctuation</h2>
<p>Anyway, returning to the voltage dilemma, we saw a month&#8217;s worth of data previously; here is the data for the full year:</p>
<div id="attachment_142" class="wp-caption aligncenter" style="width: 607px"><a href="http://exerciseforthereader.files.wordpress.com/2010/07/voltages_past_year.png"><img class="size-full wp-image-142" title="Motherboard Voltages: Past Year" src="http://exerciseforthereader.files.wordpress.com/2010/07/voltages_past_year.png?w=597&#038;h=306" alt="" width="597" height="306" /></a><p class="wp-caption-text">Motherboard Voltages: Past Year</p></div>
<p>It&#8217;s not the easiest chart to read, I admit. In all cases the plots are deviations from &#8220;nominal voltages&#8221;. Most of the traces are really rock solid, varying only a few millivolts if that. However, there&#8217;s clearly something going on with the 5V and 12V lines: they vary together, and they have a clear seasonal component. That pattern from October and November is particularly interesting, if you remember that both those months had sharp cold spikes followed by surprisingly mild weather.</p>
<p>I&#8217;ve probably given away the game by now, but I&#8217;ll walk through it anyway. Since statistics are pretty tricky on these datasets (the data points are actually averages over varying intervals, and I suspect that does evil things to the normal distribution assumption), I decided to satisfy my curiousity with a visual correlation instead. To do this, I plotted a key temperature curve (reported motherboard temperature) on the same graph as the 5V and 12V deviation plots, then inverted the scale on the temperature (so valleys are the highest temperatures) and iteratively adjusted constant and scale until they lay in the same general region. (I probably could have also just inverted temp and thrown it onto a secondary axis, but this was easier.) As a result, the vertical units for the voltage lines are millivolts of deviation from their spec voltages, and for the temperature they&#8217;re completely synthetic units. Note that the chart is kind of mis-titled: for the reasons noted above  (&#8220;I&#8217;m not good at stats&#8221;), this is not a direct plot of correlation, but  simply a superposition of the two datasets (suitably massaged). We  already know that the 12V line and the 5V line are pretty well aligned,  so look for how well the green line tracks the pattern established by  the voltages:</p>
<div id="attachment_143" class="wp-caption aligncenter" style="width: 807px"><a href="http://exerciseforthereader.files.wordpress.com/2010/07/temperature_voltage_one_year.png"><img class="size-full wp-image-143" title="Temperature / Voltage Analysis - Past Year" src="http://exerciseforthereader.files.wordpress.com/2010/07/temperature_voltage_one_year.png?w=797&#038;h=402" alt="" width="797" height="402" /></a><p class="wp-caption-text">Temperature / Voltage Analysis - Past Year</p></div>
<p>Looking at this chart, as has been clearly foreshadowed, we have a strong &#8220;correlation&#8221; over the course of the year. My explanation for the basic pattern here is the system fans. There are both 5V and 12V fans in the system. Since the server is relatively underutilized (only accessible by me and my wife, and typically for light duty), the usage of these fans is the dominant change in power usage over time.</p>
<p>There is clearly some overshoot in both directions, in warmest days of summer and the coldest days of winter. I invoke two explanations for this. In summer, these are NOT independent measures &#8211; the fans are working to cool the motherboard. I would infer that temperatures were actually higher in August than July, but the fans kicked in to keep the motherboard temperature roughly constant across those two months.</p>
<p>This rationale doesn&#8217;t seem to work to explain the winter overshoots, since the fans only work to push the temperatures in one direction. There are two scenarios here. One is that we over-compensate with heating when it&#8217;s coldest outside; this generates a noisy graph on a yearly scale (since the temperatures are varying widely over the course of the day, and the fan load correspondingly). A second explanation would be that the fans are essentially idle through the winter, and as a result they cease to be the dominant driving force on particularly the 12V line. This allows the daily noise of varying utilization to show through, instead of being drowned in the all-day-long load of the fans.</p>
<p>Unfortunately, I lack the data to disambiguate these last two scenarios. Most of the fans are controlled by an off-board fan controller (sitting in a drive bay, but not providing instrumentation data back to the host computer). The BIOS-controlled fans should report their speed, but I&#8217;ve never been able to get good data out of them; I suspect that at heart the problem is that this motherboard came from a pre-packaged HP &#8220;media computer&#8221;, and they may have saved a few pennies by cutting out some of the monitoring tool support. At some point I&#8217;ll upgrade my dev box, and transplant its rather more enthusiast motherboard to the server. That&#8217;ll be a setup chore to be sure, but perhaps I&#8217;ll be able to get some direct information. In the meantime, having such a long baseline allows me to be pretty confident in my indirect conclusions. (Note that this is the whole point of this post: if I point-sampled this data at any time throughout the year, I really wouldn&#8217;t be able to draw any conclusions at all. However, a year&#8217;s worth of data tells a pretty compelling story, even without formal stats to back it up.)</p>
<h2>Sampling Outside the Box: 1-Wire and Friends</h2>
<p>I have some longer-range thoughts or daydreams, time and money permitting (primarily time). I spent quite a while looking for a fan controller which &#8221;would&#8221; report its sensor readings to the host. Apparently they exist, but the only examples I was able to find that really fit my needs were<a href="http://www.matrixorbital.ca/products/mx_series/" target="_blank"> these beasts</a> from <a href="http://www.matrixorbital.ca/" target="_blank">Matrix Orbital</a>. While extremely in their own way, I really don&#8217;t need an OLED screen displaying weather etc on my server box, when the whole point is that I don&#8217;t see or hear the server anyway. However, some of the tech specs on this monster mentioned that it can gather and report data from any &#8220;1-wire&#8221; sensor source. That set me off on a whole other trail.</p>
<p>It turns out that &#8220;1-wire&#8221; is a Texas Instruments physical and logical protocol for simple, low-power sensor networks. It looks to be primarily designed for industrial applications, but there is a hobbyist community as well (particularly for <a href="http://www.zen35309.zen.co.uk/wx/tech.html" target="_blank">weather stations</a>, it seems, although I found a fascinating story of a buried moisture sensor driving an automated sprinkler system &#8211; now <em>that&#8217;s</em> gardening! [Update: Okay, I think the hobby-built CO2 sensor beats the automated sprinklers; no link because I noticed belatedly that it's deep in an "Advanced Marijuana Cultivation" forum - I'm still bemused by how Google ends up cross-cutting conversations!]). There are USB &#8220;host adapters&#8221; available, as well as a pretty wide range of sensor units (and raw adapters which simply sample a voltage and report it) &#8211; the net result seems to be that you can monitor pretty much anything you want, if you obey the topology and run length constraints and don&#8217;t mind writing some software to interrogate and record.</p>
<p>So my new dream is to expand my coverage significantly. This project started as a way to monitor the health of my server (and particularly to spot dead fans) without being able to see or hear it. However, there&#8217;s no reason I can&#8217;t use the same infrastructure to monitor our living space as a whole. I&#8217;d love to track ambient temperatures in various parts of the house, to see where the insulation is failing (and prove out my intuition that it really is &#8221;cold&#8221; in the dead space under my computer desk). Weather metrics are less near and dear to my heart, but it could be amusing to have a windspeed sensor or track rainfall. Moisture sensors in the basement could give a approximation of <a href="http://www.homeheartbeat.com/HomeHeartBeat/index.htm" target="_blank">Home Heartbeat</a>, without the vendor lock-in and high prices. I haven&#8217;t found a good AC sensor yet, but it seems like it would be possible to do some approximation of the &#8220;Smart Grid&#8221; idea (realtime electricity-usage tracking) without having to wait on Duke Light to figure it out. Even further down the road (and after building some trust in the system), it could be combined with an X-10 network for real closed-loop environmental control &#8211; far better than simply putting everything on a timer, or &#8220;home automation&#8221; which requires a user at a web browser to actually do anything. Before I dive into anything that big (and potentially annoying if done wrong), I&#8217;ll probably start with simpler closed-loop systems. For example, there&#8217;s no reason why my nightly cron tasks can&#8217;t wait for system idle, instead of running at midnight &#8211; that&#8217;s when I get some of my best work done! Some small-scale experiments with this sort of feedback loop would teach me a lot about how to control yoyoing and all the other pitfalls of feedback-based machine control, without annoying my wife.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/exerciseforthereader.wordpress.com/131/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/exerciseforthereader.wordpress.com/131/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/exerciseforthereader.wordpress.com/131/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/exerciseforthereader.wordpress.com/131/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/exerciseforthereader.wordpress.com/131/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/exerciseforthereader.wordpress.com/131/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/exerciseforthereader.wordpress.com/131/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/exerciseforthereader.wordpress.com/131/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/exerciseforthereader.wordpress.com/131/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/exerciseforthereader.wordpress.com/131/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/exerciseforthereader.wordpress.com/131/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/exerciseforthereader.wordpress.com/131/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/exerciseforthereader.wordpress.com/131/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/exerciseforthereader.wordpress.com/131/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=exerciseforthereader.wordpress.com&amp;blog=5637329&amp;post=131&amp;subd=exerciseforthereader&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://exerciseforthereader.wordpress.com/2010/07/05/server-monitoring-revisited/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">Seth</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2010/07/smoothed_1_year_temps.png" medium="image">
			<media:title type="html">Smoothed 1 Year Temperatures</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2010/07/voltages_past_month.png" medium="image">
			<media:title type="html">Voltages June-July 2010</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2010/07/dns_last_day.png" medium="image">
			<media:title type="html">DNS Data - Last 28 Hours</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2010/07/dns_last_year.png" medium="image">
			<media:title type="html">DNS Data - Past Year</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2010/07/voltages_past_year.png" medium="image">
			<media:title type="html">Motherboard Voltages: Past Year</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2010/07/temperature_voltage_one_year.png" medium="image">
			<media:title type="html">Temperature / Voltage Analysis - Past Year</media:title>
		</media:content>
	</item>
		<item>
		<title>B-Splines: Better Math</title>
		<link>http://exerciseforthereader.wordpress.com/2009/12/05/b-splines-better-math/</link>
		<comments>http://exerciseforthereader.wordpress.com/2009/12/05/b-splines-better-math/#comments</comments>
		<pubDate>Sun, 06 Dec 2009 02:13:57 +0000</pubDate>
		<dc:creator>Seth Porter</dc:creator>
				<category><![CDATA[3D Graphics]]></category>
		<category><![CDATA[Numerical methods]]></category>

		<guid isPermaLink="false">http://exerciseforthereader.wordpress.com/?p=115</guid>
		<description><![CDATA[In the previous three parts of this series, we&#8217;d sorted out why B-splines are interesting curves, attempted to sort out B-splines terminology, and decided that it would be really nice to be able to evaluation them with uniform functions. I&#8217;d tried some quick and dirty approaches to force it to be, and had gotten little [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=exerciseforthereader.wordpress.com&amp;blog=5637329&amp;post=115&amp;subd=exerciseforthereader&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>In the previous three parts of this series, we&#8217;d sorted out why <a title="B-splines are interesting curves" href="http://exerciseforthereader.wordpress.com/2009/11/01/the-b-spline-series-motivation/" target="_blank">B-splines are interesting curves</a>, <a title="attempted to sort out B-splines terminology" href="http://exerciseforthereader.wordpress.com/2009/11/01/b-spline-definitions/" target="_blank">attempted to sort out B-splines terminology</a>, and decided that <a title="it would be really nice to be able to evaluation them with uniform functions" href="http://exerciseforthereader.wordpress.com/2009/11/01/an-aside-about-uniformit/" target="_blank">it would be really nice to be able to evaluation them with uniform functions</a>. I&#8217;d tried some quick and dirty approaches to force it to be, and had gotten little in response. It was time to actually do some algebra and figure out what was going on.</p>
<h2 id="ANoteAboutTools">A Note About Tools</h2>
<p>That means there are going to be a lot of LaTex-created images in this section. Sorry, but it&#8217;s a lot less painful than trying to write out math in raw HTML. (Okay, writing this inspired me to search for LaTex to MathML translators, and of course the W3 itself maintains quite a <a title="LaTex to MathML translators" href="http://www.w3.org/Math/Software/mathml_software_cat_converters.html" target="_blank">nice list</a>. Oh well, I promise I&#8217;ll look into that for next time.) In the meantime, I&#8217;m using the wiki built into <a href="http://trac.edgewall.org/">Trac</a> to write this post, with the <a href="http://trac-hacks.org/wiki/TracMathPlugin">TracMath</a> plugin to take inline LaTeX blocks and render them as PNGs. This means that I just type</p>
<pre>#!latex
$$N_{i,k}(v)={{\left(
  T_{k+i} - v\right)\,N_{i+1,k-1}(v)}\over{T_{k+i}-T_{i+1}}} +
  {{\left(v-T_{i}\right)\,N_{i,k-1}(v)}\over{T_{k+i-1}-T_{i} }}$$
</pre>
<p>and I get</p>
<div class="mceTemp mceIEcenter">
<dl class="wp-caption aligncenter">
<dt class="wp-caption-dt"><a href="http://exerciseforthereader.files.wordpress.com/2009/12/n_i_k_v.png"><img class="size-full wp-image-117" title="Sample LaTex equation" src="http://exerciseforthereader.files.wordpress.com/2009/12/n_i_k_v.png?w=398&#038;h=40" alt="Sample LaTex equation" width="398" height="40" /></a></dt>
</dl>
</div>
<p>Well, okay, <em>I</em> don&#8217;t write that, because I can&#8217;t remember LaTeX math syntax to save my life. (I got pretty good at it in college, but it&#8217;s been a while.) Anyway, it&#8217;s hard to parse by eye, and I&#8217;m very prone to swap a <em>u</em> for a <em>v</em>, which can be unfortunate when you&#8217;ve just carefully <a title="drawn a distinction between them" href="http://exerciseforthereader.wordpress.com/2009/11/01/b-spline-definitions/" target="_blank">drawn a distinction between them</a>.</p>
<p>Instead, I&#8217;m using <a href="http://maxima.sourceforge.net/">Maxima</a>, a free Computer Algebra System. It&#8217;s stranger to pick up than Mathematica, but the price is right (and it&#8217;s quite powerful once you get used to its ways). It seems to be really flaky on recent Ubuntu releases, which is unfortunate, but I&#8217;m primarily using 5.17.0 for Windows and it works like a champ. It has a very nice <tt>tex</tt> function, which will spit out the TeX formatting for any given expression.</p>
<p>So in practice, I work the math in Maxima, have it convert to TeX, then paste that into the post. (Sometimes I tweak it slightly, for example to pull out a leading &#8220;1/2&#8243; rather than leaving the whole expression over 2 as Maxima seems to prefer. But for the most part, the expressions in the text are directly out of Maxima.) I have some ideas of writing a Trac plugin to close the loop and directly evaluate and typeset Maxima expressions in the text, but I haven&#8217;t got it all worked out yet: the equations in a piece generally build on each other, so you need enough lifecycle awareness to start and maintain a separate Maxima state for each page in flight. Also you probably need some non-displayed helper definitions and intermediate values, so you need a separate bit of syntax to indicate what should be rendered into the page. I think the fact of the existence of the <a href="http://trac.edgewall.org/browser/trunk/trac/wiki/macros.py">PageOutlineMacro</a> means it&#8217;s possible, but the fact that the PageOutlineMacro actually re-parses the whole page means it&#8217;s not necessarily easy. (I&#8217;d also still have to solve creating and maintaining enough state that the various individual blocks could fetch their expression / formatted results from the initial gather-and-run macro.) Anyway, for the moment I&#8217;ll do it the hard way.</p>
<h2 id="BacktotheMath">Back to the Math</h2>
<p>I&#8217;m going to run through a concrete k=3 (quadratic) example with 6 control points (so n=5), and claim that this demonstrates a general solution for k=3. I&#8217;m pretty sure it does, but it&#8217;s a lot easier to keep track of the indexes with a concrete number. Or so I claim.</p>
<p>So, the knot vector <strong>T</strong> should be the sequence <em>[0, 0, 0, 1, 2, 3, 4, 4, 4]</em>. Recall that indices are zero-based, and that N<sub>i,1</sub> is defined as</p>
<p><a href="http://exerciseforthereader.files.wordpress.com/2009/12/n_i_1_v.png"><img class="aligncenter size-full wp-image-118" title="N_(i,1)(v)" src="http://exerciseforthereader.files.wordpress.com/2009/12/n_i_1_v.png?w=297&#038;h=18" alt="N_(i,1)(v) = (if t_i" width="297" height="18" /></a></p>
<p>Given this, the N<sub>i,1</sub> terms will start being interesting at <em>i=2</em>, where N<sub>2,1</sub>= 1 for 0 &lt;= u &lt; 1. From then on, each N<sub>i,1</sub> is non-zero on N<sub>i,1</sub>= 1 for i-2 &lt;= u &lt; i-2+1, up through the last value we need at N<sub>5,1</sub>. Using Maxima to evaluate the raw B-spline equation</p>
<p><a href="http://exerciseforthereader.files.wordpress.com/2009/12/b_3_v.png"><img class="aligncenter size-full wp-image-119" title="B_3_v" src="http://exerciseforthereader.files.wordpress.com/2009/12/b_3_v.png?w=162&#038;h=45" alt="" width="162" height="45" /></a></p>
<p>for our knot vector <strong>T</strong> (again, this is the <em>k=3</em> case), we get a whomping huge expression in terms of the control points <strong>P</strong>, the N<sub>i,1</sub> &#8220;switches&#8221;, and of course <em>v</em>. I won&#8217;t reproduce the whole thing here (fully expanded, there are 33 terms, and even my new wider columns can&#8217;t handle that), but here&#8217;s the coefficient of the second control  point <strong>P<sub>1</sub></strong> for flavor:</p>
<p><a href="http://exerciseforthereader.files.wordpress.com/2009/12/b_3_v_expanded.png"><img class="aligncenter size-full wp-image-120" title="One term of B_3(v)" src="http://exerciseforthereader.files.wordpress.com/2009/12/b_3_v_expanded.png?w=549&#038;h=42" alt="" width="549" height="42" /></a></p>
<h3 id="ExplicitEquationsforEachSegment">Explicit Equations for Each Segment</h3>
<p>The good thing is that we don&#8217;t ever really need the whole equation at once. Only one of the <em>N<sub>i,1</sub></em> terms will be 1 at any given time &#8212; this is what produces the curve segments. By setting N<sub>2,1</sub> through N<sub>5,1</sub> to 1 in turn (and the other N<sub>i,1</sub> terms to 0) we can produce the four curve segments. In turn, these are</p>
<p><a href="http://exerciseforthereader.files.wordpress.com/2009/12/explicit_bspline_segments.png"><img class="aligncenter size-full wp-image-121" title="Explicit B-spline segments" src="http://exerciseforthereader.files.wordpress.com/2009/12/explicit_bspline_segments.png?w=444&#038;h=177" alt="Explicit B-spline segments" width="444" height="177" /></a></p>
<h3 id="MaximaScript">Maxima Script</h3>
<p>For anyone who&#8217;s following along at home, here&#8217;s the Maxima to get our results so far:</p>
<pre>N(N1, T, i, k, v) := if k = 1 then N1[i] else
(if T[i+k-1] = T[i] then 0 else (v- T[i])* N(N1, T, i, k-1, v) / (T[i+k-1] - T[i]))
 +
(if T[i+k] = T[i+1] then 0 else (T[i+k] - v) * N(N1, T, i+1, k-1, v) / (T[i+k] - T[i+1]));

BSpline(P, N1, T, n, k, v) := sum(P[i] * N(N1, T, i, k, v), i, 0, n);
T5Vals : [0, 0, 0, 1, 2, 3, 4, 4, 4];
T5[i] := T5Vals[i+1];

BSpline5_3(v) = BSpline(P, N1, T5, 5, 3, v);

makeN1Helper(curveSeg, n, k) := makelist(if j - k + 3 = curveSeg then 1 else 0, j, 0, n-1);
BSpline5_3_Seg(seg, P, u) := BSpline(P, makeN1Helper(seg, 5, 3), T5, 5, 3, u);
for seg : 1 step 1 thru 4 do disp(
  segment[seg] = facsum(ratsimp(
    BSpline5_3_Seg(seg, P, v)), P[seg-1], P[seg], P[seg+1]));
</pre>
<p>Note that Maxima lists are one-based, hence the helper function <em>T5</em> to preserve the zero-based indexing in the original definitions. Since <em>N<sub>i,0</sub></em> is never referenced, I can get away with a list starting at index 1 (though I admit this is made more confusing by the choice of a zero-based loop variable. Oops.) Also note that <em>BSpline5_3</em> wasn&#8217;t actually defined as a function there &#8212; that was just an equality, to make Maxima print it out nicely. Other than that, this is pretty much what it looks like. Oh, and notice that the recursive <em>N</em> definition has to avoid a couple of divide by zero cases to implement the &#8220;where 0/0 is defined to be 0&#8243; escape hatch.</p>
<h3 id="Reparamaterization">Reparamaterization</h3>
<p>Okay, those equations work but they look pretty ugly (and they&#8217;re different in each segment, but we&#8217;ll work on that in a minute). It took me a while to sort this out, but I sort of tipped my hand back in the &#8220;Definitions&#8221; post where I introduce <em>w</em> and <em>j</em>, so I&#8217;ll just repeat the equation from there: <em>v = u (n-k+2) = j+w-1</em>. Remember that <em>j</em> is the segment number ranging from 1 to <em>n-k+2</em>, which is exactly the subscript of <em>segment</em> in the explicit equations above. So we substitute <em>w-1</em> in the first equation, <em>1+w-1</em> in the second and so forth. Using the Maxima definitions above, this is just evaluating the <em>BSpline5_3_Seg</em> function above at <em>seg+w-1</em> rather than <em>v</em>:</p>
<pre class="wiki">for seg : 1 step 1 thru 4 do disp(
  segment[seg] = facsum(ratsimp(
    BSpline5_3_Seg(seg, P, seg+w-1)), P[seg-1], P[seg], P[seg+1]));
</pre>
<p>(the <em>facsum</em> bit just rearranges the terms) yielding</p>
<p><a href="http://exerciseforthereader.files.wordpress.com/2009/12/reparameterized_bspline_segments.png"><img class="aligncenter size-full wp-image-122" title="Reparameterized B-spline segments" src="http://exerciseforthereader.files.wordpress.com/2009/12/reparameterized_bspline_segments.png?w=415&#038;h=177" alt="Reparameterized B-spline segments" width="415" height="177" /></a></p>
<p>Now we&#8217;re getting somewhere. The middle two equations are identical except for shifted subscripts on <strong>P</strong>. The first two and last two are different, but we can work that out in a minute. First let&#8217;s generalize the uniform version and check our claim that</p>
<p><a href="http://exerciseforthereader.files.wordpress.com/2009/12/b_uniform_k3.png"><img class="aligncenter size-full wp-image-123" title="Uniform B-spline for k=3" src="http://exerciseforthereader.files.wordpress.com/2009/12/b_uniform_k3.png?w=473&#038;h=40" alt="Uniform B-spline for k=3" width="473" height="40" /></a></p>
<p>works for those middle terms. This will also give us a peek at the what&#8217;s going on with the end segments.</p>
<pre class="wiki">B3[uniform](P, j, w) := (-P[j]*(2*w^2-2*w-1)+P[j+1]*w^2+P[j-1]*(w-1)^2)/2;
for seg : 1 step 1 thru 4 do disp(
  difference[seg] = ratsimp(
    BSpline5_3_Seg(seg, P, seg+w-1) - B3[uniform](P, seg, w))
);
</pre>
<p>yielding</p>
<p><a href="http://exerciseforthereader.files.wordpress.com/2009/12/uniform_differences.png"><img class="aligncenter size-full wp-image-124" title="B-spline segment differences from uniform" src="http://exerciseforthereader.files.wordpress.com/2009/12/uniform_differences.png?w=416&#038;h=131" alt="B-spline segment differences from uniform" width="416" height="131" /></a></p>
<p>What we&#8217;re computing here is the difference between the &#8220;real&#8221; equation for each of the four segments and what we get from using the uniform equation for all of the segments (ignoring the segment number).</p>
<p>Doesn&#8217;t look immediately promising, but there are two good things:</p>
<ul>
<li>the two middle segments are as predicted by the uniform function above</li>
<li>the two end segments&#8217; differences only involve two control points</li>
</ul>
<p>We know that <em>P<sub>1</sub></em> and <em>P<sub>4</sub></em> are used in the middle two segments as well as the end segments, so we can&#8217;t do anything to them. However, the two end points (<em>P<sub>0</sub></em> and <em>P<sub>5</sub></em>) are only used in the end segments. So what it we feed some different value (not the current <em>P<sub>0</sub></em>, but some combination of <em>P<sub>0</sub></em> and <em>P<sub>1</sub></em>) into the uniform equation? Can we make the result be the same as evaluating the &#8220;real&#8221; B-spline function on the original control points?</p>
<p>In the uniform version of segment 1, we replace <em>P<sub>0</sub></em> with a new variable <em>x</em>, then set it equal to the real first segment of the <em>k=3</em> B-spline:</p>
<p><a href="http://exerciseforthereader.files.wordpress.com/2009/12/seg_1_with_free_p0.png"><img class="aligncenter size-full wp-image-125" title="Segment 1 with p0 as free variable" src="http://exerciseforthereader.files.wordpress.com/2009/12/seg_1_with_free_p0.png?w=686&#038;h=37" alt="Segment 1 with p0 as free variable" width="686" height="37" /></a></p>
<p>We then solve for <em>x</em> hoping we can eliminate all the <em>w</em> terms:</p>
<pre class="wiki">rightAnswer : ratsimp(BSpline5_3_Seg(1, P, 1+w-1));
uniformWithFreeP0 : ratsubst(x, P[0], B3[uniform](P, 1, w));
solve(uniformWithFreeP0 = rightAnswer, x);
</pre>
<p>and we get (<strong>drumroll, please</strong>)</p>
<p><a href="http://exerciseforthereader.files.wordpress.com/2009/12/2p_0-p_1.png"><img class="aligncenter size-full wp-image-126" title="x=2*p_0-p_1" src="http://exerciseforthereader.files.wordpress.com/2009/12/2p_0-p_1.png?w=98&#038;h=14" alt="x=2*p_0-p_1" width="98" height="14" /></a></p>
<p>(Okay, that didn&#8217;t really need a LaTeX block, but it really did take me quite a while to figure out, and I was inexplicably happy when I found it (literally: one very really reason for this whole series is to explain to my wife why I was grinning so much that week). If I&#8217;d happened to have run into that formula up front I would have spared myself a great deal of frustrating math trying to figure out how to make sense of what I was seeing. Of course, I also wouldn&#8217;t have learned a lot about splines, so maybe it was better this way.)</p>
<p>Repeating the process for the last control point (in this case <em>P<sub>5</sub></em>), we get <em>x = 2 P<sub>5</sub>-P<sub>4</sub></em>:</p>
<pre class="wiki">rightAnswer2 : ratsimp(BSpline5_3_Seg(4, P, 4+w-1));
uniform2WithFreeP0 : ratsubst(x, P[5], B3[uniform](P, 4, w));
solve(uniform2WithFreeP0 = rightAnswer2, x);
</pre>
<p>This is a reassuring result &#8212; the equations are all symmetric, so it should be possible to reverse the control points and produce the same curve. Therefore, it&#8217;s nice to see that this formulation for the end-points is also symmetric.</p>
<p>So the practical upshot of this is that we now have a way to evaluate all the segments of a B-spline, even the &#8220;weird&#8221; end segments, with the same uniform equation. To do this, we have to massage the control points a little. Given the input sequence</p>
<blockquote><p><em>( P<sub>0</sub> , P<sub>1</sub> , &#8230; , P<sub>n-1</sub> , P<sub>n</sub> )</em></p></blockquote>
<p>we need to make a copy, so we can feed the uniform function the sequence</p>
<blockquote><p><em>( 2 P<sub>0</sub> &#8211; P<sub>1</sub> , P<sub>1</sub> , &#8230; , P<sub>n-1</sub> , 2 P<sub>n</sub> &#8211; P<sub>n-1</sub> )</em></p></blockquote>
<p>instead. That doesn&#8217;t seem like much of a price to pay for freedom (or at least for being able to evaluate all segments of all k=3 B-splines curves with the same straight-line evaluation code).</p>
<p>The same general approach works for k=4 curves (cubic B-splines). Because the cubic blending functions involve more points in each segment, we have to replace both <em>P0</em> and <em>P1</em> with free variables, and solve for them simultaneously (using the known equations for the first <em>two</em> segments, instead of just the first segment), but it&#8217;s the same logic and it works quite nicely. I haven&#8217;t tried to generalize a formula for any value of <em>k</em>, mostly because quadratic and cubic B-splines are far more common than other types.</p>
<p>This took much longer to post than I&#8217;d planned, but I hope it was worth the wait for someone. I can absolutely guarantee that this isn&#8217;t an original result, but I haven&#8217;t actually seen it in Wikipedia or MathWorld or the usual suspects, so I feel entitled to be slightly smug.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/exerciseforthereader.wordpress.com/115/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/exerciseforthereader.wordpress.com/115/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/exerciseforthereader.wordpress.com/115/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/exerciseforthereader.wordpress.com/115/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/exerciseforthereader.wordpress.com/115/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/exerciseforthereader.wordpress.com/115/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/exerciseforthereader.wordpress.com/115/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/exerciseforthereader.wordpress.com/115/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/exerciseforthereader.wordpress.com/115/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/exerciseforthereader.wordpress.com/115/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/exerciseforthereader.wordpress.com/115/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/exerciseforthereader.wordpress.com/115/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/exerciseforthereader.wordpress.com/115/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/exerciseforthereader.wordpress.com/115/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=exerciseforthereader.wordpress.com&amp;blog=5637329&amp;post=115&amp;subd=exerciseforthereader&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://exerciseforthereader.wordpress.com/2009/12/05/b-splines-better-math/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">Seth</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/12/n_i_k_v.png" medium="image">
			<media:title type="html">Sample LaTex equation</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/12/n_i_1_v.png" medium="image">
			<media:title type="html">N_(i,1)(v)</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/12/b_3_v.png" medium="image">
			<media:title type="html">B_3_v</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/12/b_3_v_expanded.png" medium="image">
			<media:title type="html">One term of B_3(v)</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/12/explicit_bspline_segments.png" medium="image">
			<media:title type="html">Explicit B-spline segments</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/12/reparameterized_bspline_segments.png" medium="image">
			<media:title type="html">Reparameterized B-spline segments</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/12/b_uniform_k3.png" medium="image">
			<media:title type="html">Uniform B-spline for k=3</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/12/uniform_differences.png" medium="image">
			<media:title type="html">B-spline segment differences from uniform</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/12/seg_1_with_free_p0.png" medium="image">
			<media:title type="html">Segment 1 with p0 as free variable</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/12/2p_0-p_1.png" medium="image">
			<media:title type="html">x=2*p_0-p_1</media:title>
		</media:content>
	</item>
		<item>
		<title>The Stylesheet Blues</title>
		<link>http://exerciseforthereader.wordpress.com/2009/11/02/the-stylesheet-blues/</link>
		<comments>http://exerciseforthereader.wordpress.com/2009/11/02/the-stylesheet-blues/#comments</comments>
		<pubDate>Mon, 02 Nov 2009 14:01:33 +0000</pubDate>
		<dc:creator>Seth Porter</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://exerciseforthereader.wordpress.com/?p=108</guid>
		<description><![CDATA[Previous visitors might notice a new look. The fixed width column just wasn&#8217;t working for me, and the math looked really hideous when is was scaled into 400 pixels. So I&#8217;m trying out a new &#8220;theme&#8221;, as a quick-and-dirty way to avoid having to actually, you know, design a visual look for this site. Which [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=exerciseforthereader.wordpress.com&amp;blog=5637329&amp;post=108&amp;subd=exerciseforthereader&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Previous visitors might notice a new look. The fixed width column just wasn&#8217;t working for me, and the math looked really hideous when is was scaled into 400 pixels.</p>
<p>So I&#8217;m trying out a new &#8220;theme&#8221;, as a quick-and-dirty way to avoid having to actually, you know, design a visual look for this site. Which would be nice, but unfortunately said theme apparently doesn&#8217;t handle definition lists (&lt;dl&gt;, &lt;dd&gt; and &lt;dt&gt;), which are my recent favorite way to avoid dealing with tables. (I stole this affection from a blog post I read sometime, but since it no longer appears in the top page of Google results for &#8220;definition list&#8221;, I&#8217;m deeming it an orphan work and mine for the appropriation.)</p>
<p>Anyway, it looks like there is some CSS work in my future, probably mining <a href="http://www.maxdesign.com.au/presentation/definition/" target="_blank">this site</a> pretty heavily. (I continue to be delighted to live in a world where you can search on any given HTML tag and be pretty much guaranteed to find a nicely organized page of CSS techniques, rants against rampant misuse (generally a good source for ideas you hadn&#8217;t yet thought of), and generally a rich literature for those of us in the &#8220;I care about CSS for exactly as long as it takes to get my font sizes consistent&#8221; camp).)</p>
<p>Given my frequency of updates, you can therefore look forward to many months of inappropriately-sized definitions and other offenses against visual design.</p>
<p>(I actually do have another article in the B-spline Series, wherein I get to look all clever (had I not previously tipped my hand about my various confusions) by presenting a rather nice uniform version of k=3 and k=4 B-splines based on preconditioning the control points. There will be more LaTeX math! More empirically-derived constants which I pass off as proven! It&#8217;ll be great.)</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/exerciseforthereader.wordpress.com/108/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/exerciseforthereader.wordpress.com/108/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/exerciseforthereader.wordpress.com/108/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/exerciseforthereader.wordpress.com/108/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/exerciseforthereader.wordpress.com/108/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/exerciseforthereader.wordpress.com/108/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/exerciseforthereader.wordpress.com/108/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/exerciseforthereader.wordpress.com/108/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/exerciseforthereader.wordpress.com/108/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/exerciseforthereader.wordpress.com/108/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/exerciseforthereader.wordpress.com/108/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/exerciseforthereader.wordpress.com/108/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/exerciseforthereader.wordpress.com/108/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/exerciseforthereader.wordpress.com/108/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=exerciseforthereader.wordpress.com&amp;blog=5637329&amp;post=108&amp;subd=exerciseforthereader&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://exerciseforthereader.wordpress.com/2009/11/02/the-stylesheet-blues/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">Seth</media:title>
		</media:content>
	</item>
		<item>
		<title>An Aside About Uniformity</title>
		<link>http://exerciseforthereader.wordpress.com/2009/11/01/an-aside-about-uniformit/</link>
		<comments>http://exerciseforthereader.wordpress.com/2009/11/01/an-aside-about-uniformit/#comments</comments>
		<pubDate>Sun, 01 Nov 2009 21:51:04 +0000</pubDate>
		<dc:creator>Seth Porter</dc:creator>
				<category><![CDATA[3D Graphics]]></category>

		<guid isPermaLink="false">http://exerciseforthereader.wordpress.com/?p=105</guid>
		<description><![CDATA[Before getting into a correct treatment of the problem, and deriving a correct way to handle these differing end segments (as part of the B-spline series of posts), I should explain what I mean by &#8220;uniform&#8221; and why I&#8217;m so hung up on it. (That is, other than the fact that the Buniform function is [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=exerciseforthereader.wordpress.com&amp;blog=5637329&amp;post=105&amp;subd=exerciseforthereader&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Before getting into a correct treatment of the problem, and deriving a correct way to handle these differing end segments (as part of the B-spline series of posts), I should explain what I mean by &#8220;uniform&#8221; and why I&#8217;m so hung up on it. (That is, other than the fact that the B<sub>uniform</sub> function is an easily-understood mixing of three control points, while the recursive definition of the basis functions makes my head hurt.) In particular, why not just accept a solution along the lines of:</p>
<pre class="wiki">function evaluateBSplineWithConditional(u) =
v = u * (n-k+2)
segment = floor(v)
w = fractional_part(v)
if(segment &lt;= 1) then
  do weird thing(segment, w)
else
  do uniform thing(segment, w)</pre>
<p>(I may have got the indexing slightly wrong, but I think this works (and is a good illustration of why I was being so pedantic about u, v, and w above &#8212; it&#8217;s not complex math, but it&#8217;s easy to mess up the parameterization).) Also note that I&#8217;m only looking at the weirdness at the beginning of the curve; properly the conditional would need to check whether the segment was at <em>either</em> end of the curve. This is a simplified version to support the discussion, not an actual implementation.</p>
<p>Endpoints are often exceptional cases; why not just define the evaluation with that exceptional case and move on? All the more so since my attempted trick of &#8220;pre-conditioning the data&#8221; (replacing the original sequence of control points with a sequence with repeats at the beginning and end) didn&#8217;t work? (An important background assumption to the rest of this discussion is that this function is going to be run many many times, since we need a lot of points on that curve to make it look like a smooth curve when we draw it on-screen, or when we send the points to a CNC router to cut metal, or whatever we&#8217;re doing with it. If we only needed to do it once, this would probably be the right solution.)</p>
<h3 id="TheProblemwithBranching">The Problem with Branching</h3>
<p>The answer basically has to do with computer architecture and the way it has evolved over the past couple of decades. Once upon a time, when I was programming on my father&#8217;s hand-me-down Heathkit Z-80, this would have been a perfect solution &#8212; each time we needed to evaluate a B-spline, we&#8217;d simply decide if we were in the normal or weird section of the curve, and calculate accordingly. The problem is that as we poured billions of dollars into CPU fabrication techniques, we got more and more transistors, and needed some way to take advantage of them in order to make things run faster. One major solution is &#8220;pipelining&#8221;, which essentially can be described as doing many things at once. Rather than waiting for each step to complete before we start on the next step, the CPU will get a lot of things started at once, and pull them all together when needed. (Perhaps I&#8217;ve been watching too much Iron Chef, but this seems like partitioning work out to a sous chef.) In the extreme case of the P4 architecture, the pipeline was up to 20 stages long. A much more technical discussion can be found at <a class="ext-link" href="http://arstechnica.com/old/content/2001/05/p4andg4e.ars"><span class="icon">http://arstechnica.com/old/content/2001/05/p4andg4e.ars</span></a> but the basic takeaway is that for a modern CPU to run fast, it needs to be able to do many things at once.</p>
<p><span id="more-105"></span></p>
<p>A conditional (the &#8220;if / then&#8221; in the pseudo-code above) wreaks holy hell on this scheme. Before the CPU can get started on &#8220;do uniform thing&#8221; or &#8220;do weird thing&#8221;, it has to know which one it needs to do. This is one cause of a &#8220;pipeline stall&#8221;, since instead of doing 20 things at once, we have to wait for the conditional to be evaluated (through all 20 stages) before doing anything. This is absolutely brutal on performance.</p>
<p>Modern CPUs actually try to work around this problem as well, using &#8220;speculative execution&#8221; and &#8220;branch prediction&#8221; &#8212; basically, they keep track of what happened last time we ran this code, and assume that the same thing will happen this time. If they guess right, when the conditional is finally evaluated they can just act as if they knew it all along. If they guess wrong, they have to throw away all the speculative work and start over on the correct path. This works, but it&#8217;s hugely complex, and it makes performance less predictable and more dynamic (because performance becomes directly tied to the accuracy of the branch prediction). In our case, things would run fast through the first curve segment, when the &#8220;weird&#8221; path is consistently followed. This would be followed by a period of degraded performance when it kept guessing &#8220;weird&#8221; but the real answer was &#8220;uniform&#8221;. At some point, the branch prediction unit would be retrained to guess &#8220;uniform&#8221; instead, and performance would recover until we hit another &#8220;weird&#8221; segment. In short, speculative execution and branch prediction are nice things to have, but no substitute for &#8220;straight-line&#8221;, branch-free code.</p>
<p>This whole preference for a single codepath is even more dramatically true when we talk about &#8220;SIMD&#8221; (Single Instruction, Multiple Data) parallelism. This approach to performance showed up on CPUs in the MMX and SSE instruction sets, and is one of the ways to really increase performance on modern silicon. Essentially, rather than evaluating points on the spline one at a time, we could stack up a list of points to be evaluated side-by-side, then grind through them four (or however many) at a time. See <a class="ext-link" href="http://arstechnica.com/old/content/2000/03/simd.ars"><span class="icon">http://arstechnica.com/old/content/2000/03/simd.ars</span></a> for a more responsible description. The challenge here is that &#8220;Single Instruction&#8221; bit &#8212; you have to be doing the <em>same</em> thing to your four data points, not looking at each one individually and deciding whether to give it the &#8220;uniform&#8221; or &#8220;weird&#8221; treatment. This is true of the SIMD instructions in modern Intel and AMD CPUs, and even more so of &#8220;shader programs&#8221; running on graphics cards&#8217; GPUs. In fact, early shader programs didn&#8217;t even <em>have</em> conditional instructions; everything <em>had</em> to be straight-line code. More recent cards allow you to branch on the GPU, but at a potentially fearsome cost to performance (see <a class="ext-link" href="http://forums.nvidia.com/index.php?showtopic=107865"><span class="icon">http://forums.nvidia.com/index.php?showtopic=107865</span></a> for instance).</p>
<h3 id="SeparateBatches">Separate Batches</h3>
<p>So we&#8217;re all agreed that branching is Bad. What can we do?</p>
<p>One approach is the &#8220;hoist the conditional&#8221; out of the inner loop. This somewhat compromises the nice clean interface of the evaluateBSplineWithConditional function, but often be a performance win. To describe this approach, we need to introduce another level of the program, namely the function which was calling the evaluateBSplineWithConditional function. Assume that we&#8217;re trying to fill an array with evenly-spaced points on the B-spline, in order to render them or drive a CNC router or whatever. Using the original definition we&#8217;d have something like</p>
<pre class="wiki">function naiveFillArrayWithSpline(array, numPoints)
  dU = 1 / (numPoints - 1)
  for(i = 0; i &lt; numPoints; i++)
    u = dU * i
    array[i] = evaluateBSplineWithConditional(u)</pre>
<p>The naiveFillArrayWithSpline function would really work on any parametric curve function that expects a <em>u</em> ranging from 0 to 1. Instead, we can give it some knowledge about the end-conditions of B-splines, to produce a version without any conditionals in the main loops:</p>
<pre class="wiki">function batchedFillArrayWithSpline(array, numPoints)
  numSegments = n-k+2
  pointsPerSegment = numPoints / numSegments
  dW = 1 / pointsPerSegment
  for(i = 0; i &lt; pointsPerSegment; i++)
    w = dW * i
    array[i] = do weird thing (1, w)
  for(j = 1; j &lt; numSegments - 1; j++)
    for(i = 0; i &lt; numPoints; i++)
      w = dW * j
      array[j*pointsPerSegment + i] = do uniform thing(j, w)</pre>
<p>(Again I&#8217;m ignoring the weirdness at the end of the curve, which would require another &#8220;do weird thing&#8221; loop. I&#8217;m also playing fast and loose with the array indexing, assuming that numPoints divides evenly into numSegments, and so forth &#8212; this is another strawman, in other words.)</p>
<p>This is a much uglier function than naiveFillArrayWithSpline. It also has a lot of specific knowledge about B-splines embedded in it; you couldn&#8217;t reuse this for, say, making an array filled with <em>sin(u)</em>. However, it has the huge virtue that there are no conditionals embedded in the inner loops. In fact, there are no conditionals at all &#8212; by changing the problem from &#8220;evaluate a B-spline at a given value of u&#8221; to &#8220;fill an array with evenly-spaced values of a B-spline&#8221; we&#8217;ve been able to significantly improve the performance characteristics.</p>
<p>This version still has flaws, however. One is a software engineering issue: we might need both this version <em>and</em> the evaluateBSplineWithConditional function, if we need to be able to fill arrays efficiently but also need to be able to evaluate arbitrary points (perhaps searching for an intersection). Maintaining two functions with different structure, but supposed to produce the same result, is a good recipe for maintenance pain. (In a prior job, we had exactly this situation &#8212; and in fact the single-value version did disagree with the bulk version, which was an on-going source of confusion.)</p>
<p>There&#8217;s an argument to be made that software engineering pain is the price of doing business, and perhaps a different language or some code generation approach would let us keep a single version of the source code while still producing these two versions for actual production use. There are two technical flaws (or two aspects of the same flaw), though, that mean this version is sub-optimal even ignoring maintenance considerations.</p>
<p>From the point of view of running this code on a CPU, the issue is code size. Instead of a single, small codepath we now have a rather larger function to evaluate. The on-disk size of a program is pretty much irrelevant in the modern world, but the actual in-use code size still matters because of caching. The CPU has a limited (and often surprisingly small) instruction cache on-die; it&#8217;s vastly faster to execute code from that cache than it is to load code from main memory. While it&#8217;s unlikely that the method above would actually be larger than the instruction cache, it&#8217;s definitely larger than a uniform version, which means it would occupy more of the instruction cache. If, say, the actual rendering loop has to be pushed out of the cache in order to load our spline evaluation method, then we&#8217;re paying a definite performance cost for code size (although one that&#8217;s very difficult to rigorously detect and characterize).</p>
<p>In the case where this code would run on the GPU, the cost is somewhat easier to see. Rendering commands are transferred from the CPU to the graphics card in &#8220;batches&#8221;, where everything in a batch is using the same shader programs, the same constants, and so forth (only the vertex data changes between data points). The GPU-based analogue of the method above would be to render the spline in three batches: one for the first &#8220;weird&#8221; segment, one for the uniform segments, and one for the final &#8220;weird&#8221; segment. The number of batches is very often a limiting factor in naive rendering approaches; magnifying the batch count by a factor of 3 is a quick way to become batch-limited. In these circumstances it can even be possible for the performance wins of GPU-native evaluation to be completely lost in the face of the communications overhead.</p>
<h3 id="ArithmeticConditionals">Arithmetic &#8220;Conditionals&#8221;</h3>
<p>If the cost of the computations is low enough, and the penalty for branching is high enough, there can be another answer. Instead of having the program explicitly branch, or separating the different conditions into different loops / different batches, we can simply do both branches. The obvious problem is that we&#8217;ll have two output values, but we need to produce exactly one (the right one). To solve this problem, we introduce a &#8220;condition variable&#8221; which is 1 in one conditional branch and 0 in the other. This is typically a &#8220;natural&#8221; operation because in C (and C-like languages) boolean variables are internally stored as an integer which is 1 for true and 0 for false. In this idiom, the core of the function becomes something like</p>
<pre class="wiki">function doBoth(segment, w)
isWeird = (segment &lt;= 1)
isNormal = 1 - isWeird

weirdResult = do weird thing(segment, w)
normalResult = do uniform thing(segment, w)

answer = weirdResult * isWeird + normalResult * isNormal</pre>
<p>This seems incredibly counter-intuitive as a speed-up, but it can actually be a win if the &#8220;weird&#8221; and &#8220;uniform&#8221; paths are both rather cheap to evaluate, and the cost of separate batches is high enough. A nice advantage of this approach is that we&#8217;re back to having a single method which can be used as the core of an array-filling loop and also used to evaluate &#8220;one-off&#8221; points.</p>
<p>In practical terms, I would guess that on the CPU, this approach is likely to be slower than the batchedFill method above, while on the graphics card it would be closer. (This reflects the fact that CPU instruction cache pressure is probably less critical than the communications overhead of sending batches to the GPU, combined with just how fast the GPU is at evaluating math &#8212; in the GPU case, the bar for &#8220;rather cheap to evaluate&#8221; is lower, and the cost of separate batches is higher). I haven&#8217;t done any benchmarking at all to test whether the B-spline functions actually fit these assumptions on the hardware I have available.</p>
<h3 id="TradeoffsandRealHardware">Tradeoffs and Real Hardware</h3>
<p>The last paragraph hints at why all of these approaches are kind of unfortunate. It&#8217;s very possible (in fact, likely) for the &#8220;right&#8221; answer to vary with different graphics cards, different CPUs, and different connections between CPU and GPU. For instance, within a given generation of graphics cards, the cost of evaluating functions tends to drop (as the cards get faster), but the cost of submitting a batch is typically fixed (by the interface between CPU and graphics card, which experiences much slower evolution). However, for on-board graphics (where the GPU is on the motherboard or even integrated into the CPU itself) the cost of batch submission may be almost zero, while these kinds of GPUs are typically computationally weak (so the cost of evaluating the functions would be higher).</p>
<p>One very common solution to this sort of dilemma is to optimize for performance on <em>your</em> hardware, and figure it&#8217;s reasonably representative of your customers. If there&#8217;s any validity to that assumption, this may be a reasonable approach, but it&#8217;s fraught with peril; if nothing else, the optimal solution will change over time (with new generations of hardware), so your program is unlikely to age well. It can also be embarrassing, if customers upgrade their hardware and notice that your program doesn&#8217;t take any advantage of their expensive new graphics card.</p>
<p>To really do this kind of thing right, across heterogenous hardware and with an eye toward future-proofing your program, you would need to &#8220;do it all&#8221;, with dynamic strategy selection. For each performance-critical routine, provide all three variants listed above, then benchmark <em>on the customer hardware</em> to figure out which is fastest in this particular computer. This approach actually can work, and is really used by some very performance-sensitive applications. (For instance, the ATLAS project <a class="ext-link" href="http://math-atlas.sourceforge.net/"><span class="icon">http://math-atlas.sourceforge.net/</span></a> does this for certain key linear algebra computations. Likewise, the &#8220;md&#8221; RAID system on Linux boxes will test several versions of the XOR routine at runtime to determine which is fastest. In both of these cases, a very small but very performance-critical part of the code is being optimized.) This approach is <em>very</em> expensive in programmer and testing time, and easy to get wrong if you don&#8217;t have a wide range of hardware available to validate your performance assumptions.</p>
<p>Sometimes you can instead leverage the work of other projects. For example, many problems can be coerced into problems of linear algebra, and you can then take advantage of the optimally-tuned ATLAS functions to solve them. There is typically overhead in expressing a problem this way, but it can be a win in time-to-market and coding complexity. Unfortunately, this isn&#8217;t a mechanical solution, and it isn&#8217;t applicable in all cases. In the case of B-splines, it would be possible to express the &#8220;do weird thing&#8221; and &#8220;do uniform thing&#8221; sections in terms of matrix multiplication, but it would not be easy to capture the general &#8220;do this or do that&#8221; problem as I&#8217;ve set it up here.</p>
<p>So the long and the short of it (after this very long digression) is that conditionals are a pain no matter how you slice it. Vastly better is to be able to precondition the data &#8212; that is, feed a fixed formula something clever to make it do what you want, rather than using two different formulas. (You can tell that I got it to work, or think I did, from my phrasing. If B-splines were inextricably <em>different</em> in their end segments, I&#8217;d be writing a very nice summation about how conditionals are hard but sometimes unavoidable, and the next section would be about how the real clever is solution is to have several B-splines to draw, and draw all the middles of <em>all</em> the curves in one batch, and all the end-segments in another batch. Which is actually pretty clever, now that I think of it. But it&#8217;s definitely not the way this post is going.)</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/exerciseforthereader.wordpress.com/105/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/exerciseforthereader.wordpress.com/105/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/exerciseforthereader.wordpress.com/105/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/exerciseforthereader.wordpress.com/105/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/exerciseforthereader.wordpress.com/105/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/exerciseforthereader.wordpress.com/105/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/exerciseforthereader.wordpress.com/105/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/exerciseforthereader.wordpress.com/105/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/exerciseforthereader.wordpress.com/105/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/exerciseforthereader.wordpress.com/105/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/exerciseforthereader.wordpress.com/105/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/exerciseforthereader.wordpress.com/105/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/exerciseforthereader.wordpress.com/105/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/exerciseforthereader.wordpress.com/105/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=exerciseforthereader.wordpress.com&amp;blog=5637329&amp;post=105&amp;subd=exerciseforthereader&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://exerciseforthereader.wordpress.com/2009/11/01/an-aside-about-uniformit/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">Seth</media:title>
		</media:content>
	</item>
		<item>
		<title>The B-spline Series: Definitions (Abridged)</title>
		<link>http://exerciseforthereader.wordpress.com/2009/11/01/b-spline-definitions/</link>
		<comments>http://exerciseforthereader.wordpress.com/2009/11/01/b-spline-definitions/#comments</comments>
		<pubDate>Sun, 01 Nov 2009 21:24:51 +0000</pubDate>
		<dc:creator>Seth Porter</dc:creator>
				<category><![CDATA[3D Graphics]]></category>

		<guid isPermaLink="false">http://exerciseforthereader.wordpress.com/?p=90</guid>
		<description><![CDATA[This is the second part of a so-far three part series. See part one for some context. For a typical background you can look at MathWorld or Wikipedia. These are pretty representative of the descriptions you&#8217;ll find on the internet in casual searching: technically correct, with nicely formatted equations, but not a whole lot of [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=exerciseforthereader.wordpress.com&amp;blog=5637329&amp;post=90&amp;subd=exerciseforthereader&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><em>This is the second part of a so-far three part series. See <a title="The B-spline Series: Motivation" href="http://exerciseforthereader.wordpress.com/2009/11/01/the-b-spline-series-motivation/" target="_blank">part one</a> for some context.</em></p>
<p>For a typical background you can look at <a onclick="return mugicPopWin(this,event);" oncontextmenu="mugicRightClick(this);" href="http://mathworld.wolfram.com/B-Spline.html" target="_blank"><span class="icon">MathWorld</span></a> or <a href="http://en.wikipedia.org/wiki/B-spline" target="_blank"><span class="icon">Wikipedia</span></a>. These are pretty representative of the descriptions you&#8217;ll find on the internet in casual searching: technically correct, with nicely formatted equations, but not a whole lot of actual help if you&#8217;re trying to understand the things. In particular, the recursive definition of the basis functions are very clever but incredibly unintuitive as far as what they mean. (I also notice that the links share my own indecisiveness about how to title-case &#8220;B-spline&#8221;.)</p>
<p>A much more useful writeup can be found in the &#8220;B-spline Curves&#8221; section in <a href="http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/" target="_blank"><span class="icon">these excellent class notes</span></a>. This is a nice treatment with lots of pretty pictures, although I think the author makes things somewhat more complex by staying with the raw 0 to 1 parameterization throughout (so the elements of the knot vector end up as fractions rather than integers). Nothing wrong with it, just a different treatment (and I suspect one motivated by uniform representation <em>across many kinds of curves</em>, rather than my focus on uniform representation <em>for all segments of the B-spline</em> to ease high-volume computation).</p>
<p>(I should say at this point that I&#8217;m torn about how to present things. It&#8217;s very tempting to start with what I know now, tell a nice clean story, and maybe then offer an amusing anecdote about how even I didn&#8217;t quite get it at first&#8230; but that&#8217;s exactly what the textbook I was working from did (well, except for the amusing anecdote), and it didn&#8217;t serve me very well. So instead I&#8217;ll let the game tell the story, and just lay it out as it happened to me.)</p>
<p><span id="more-90"></span></p>
<p>First I have to explain why I was motivated to take a shortcut, which is a mixture of raw intellectual laziness and premature optimization. Starting with the intellectual laziness, here&#8217;s the basic definition of a B-spline. First, some definitions and terminology (Note that wherever I say something condescending like &#8220;the casual reader could be confused&#8221;, I really mean &#8220;<strong>I</strong> was confused for about a day&#8221;):</p>
<dl>
<dt><em>u</em></dt>
<dd>The parametric input variable. In general usage, u definitionally ranges between 0 and 1 &#8212; this defines the extent of any parametric curve (one where <em>x=f(u)</em> and <em>y=g(u)</em>). However, spline literature, or at least the text I&#8217;m working from, is pretty casual about redefining <em>u</em> to work over various different ranges as convenient. To avoid confusion, I&#8217;ll use <em>u</em> in the traditional 0..1 sense, and <em>v</em> and <em>w</em> to track these other ranges. </dd>
<dt><strong>P</strong><sub>0..n</sub></dt>
<dd>The list of control points. This is probably the most important input to the B-spline curve. Note that indexing is zero-based, and there are <em>n+1</em> control points. Note that <strong>P</strong> is a list of <em>vectors</em>, and their dimensionality wholly determines the dimensionality of the output. In other words, if <strong>P</strong> is a list of <em>(x,y)</em> points, then the position of a B-spline defined on <strong>P</strong> at a given <em>u</em> will also be an <em>(x,y)</em> point. Likewise if <strong>P</strong> is defined in 3-space, that is <em>(x,y,z)</em> then the resulting curve is also defined in 3-space. </dd>
<dt><em>n</em></dt>
<dd>One less than the number of control points. </dd>
<dt><em>k</em></dt>
<dd>An input to the B-spline curve, this determines the degree of the polynomials used for each curve segment, as well as various other things. Most of this post considers the case of k=3. </dd>
<dt>degree</dt>
<dd>Generally: the highest exponent appearing in a polynomial: the degree of <em>u<sup>2</sup>+3 u + 1</em> is 2. Specifically, for the B-spline segments, <em>degree = k-1</em> (so my working example with k=3 produces a quadratic on <em>u</em>). </dd>
<dt><em>v</em></dt>
<dd>A variable in the range <em>[ 0 , n-k+2 ]</em>. This range is mapped to the 0 to 1 range of <em>u</em> in the obvious way: <em>v = u (n-k+2)</em> </dd>
<dt><span style="text-decoration:line-through;"><em>T<sub>0..n-k+2</sub></em></span><em><sub> </sub></em><em>T<sub>0..n+k+1</sub></em></dt>
<dd><em>[Edit 11/03/09 - there are n+k+2 total knots (numbered 0 through n+k+1), even though the highest number appearing in the knot vector is n-k+2.] </em>The <strong>knot vector</strong>. Note that the knot vector&#8217;s indexing is zero based. In the case we&#8217;re considering (uniform end-interpolating B-splines) it consists of a list of integers between 0 and n-k+2. The first <em>k</em> entries are 0, then the numbers 1 through <em>n-k+1</em>, then <em>k</em> copies of <em>n-k+2</em>. For example, the knot vector for a 6 control point (<em>n=5</em>), second degree (<em>k=3</em>) B-spline would be <em>T = { 0, 0, 0, 1, 2, 3, 4, 4, 4 }</em>. Note that these are not quite indices into the control point array (for one thing, they wouldn&#8217;t reference all <em>n+1</em> control points). These values actually are in the same parameter space as <em>v</em>, above, and basically they serve to knock out terms in the basis functions (when the same value appears repeatedly in the knot vector). </dd>
<dt><em>N<sub>i,k</sub>(v)</em></dt>
<dd>A B-spline basis function, parameterized on <em>i</em> and <em>k</em>. Defined in two parts, as<img class="aligncenter size-full wp-image-92" title="N_i_1" src="http://exerciseforthereader.files.wordpress.com/2009/11/n_i_1.png?w=297&#038;h=18" alt="N_i,1(v) := (if t_i &lt;= v &lt;= t_{i+1} then 1 else 0)" width="297" height="18" /></dd>
</dl>
<p style="padding-left:30px;">and</p>
<p><img class="aligncenter size-full wp-image-93" title="N_i,k(v)" src="http://exerciseforthereader.files.wordpress.com/2009/11/n_i_k.png?w=398&#038;h=40" alt="N_i,k(v) := (u- T[i])* N(i, k-1, u) / (T[i+k-1] - T[i]) + (T[i+k] - u) * N(i+1, k-1, u) / (T[i+k] - T[i+1])" width="398" height="40" /></p>
<p style="padding-left:30px;">where 0/0 is defined to be 0. This was the intimidating expression that inspired me to take any shortcut presented. In retrospect, I should have noticed that the denominator would be 1 in both terms unless you&#8217;re near an end of the curve, in which case one and then both terms will go to 0 (thanks to the slightly odd definition of dividing by zero). The rest of the time, the <em>N<sub>i,1</sub></em> terms will act as switches, picking a set of terms from each basis function which will be non-zero in the current section of the curve. Also, note that in much of the literature, this function is written as a function of <em>u</em>, but we&#8217;ve already made the jump to the <em>v</em> range as described above, so I replaced the u&#8217;s with v&#8217;s.</p>
<dl>
<dt><em>B<sub>k</sub>(v)</em></dt>
<dd>The actual B-spline curve, given a list of control points <em>p</em> and a degree-controlling <em>k</em>. This function is sometimes referred to as <em>p(u)</em>, but this is easily confused with the list of control points. Defined as<img class="aligncenter size-full wp-image-94" title="B-spline curve definition" src="http://exerciseforthereader.files.wordpress.com/2009/11/b_k.png?w=163&#038;h=45" alt="BSpline(n, k, u) := sum(P[i] * N(i, k, u), i, 0, n);" width="163" height="45" /></dd>
</dl>
<hr />The key thing you&#8217;ll notice in this section is that B-splines come out of the mathematical world, not the computer world. The core clever trick is using the lowest-order basis functions as &#8220;switches&#8221; to select which terms are non-zero. (To their credit, though, at least the lists all use zero-based indices, which will save some tearing-out-of-hair later. (Well, it would if Maxima, the symbolic math program I&#8217;m using, didn&#8217;t insist on one-based indices&#8230;)) This allows a very pretty representation of the function as a whole (see <em>B(v)</em> above), at the expense of hiding all the conditionals way down deep inside these (recursively defined) basis functions. This makes for pretty math, but a hideously slow and ugly direct implementation. As far as I can tell, the intent was to get the top-level <em>B(v)</em> function to look a lot like the definition of Bezier and Hermite curves. Mission accomplished, but with a twist &#8212; the definitions of <em>those</em> functions are quite friendly to naive implementation, while this one is pure pain. See <a class="ext-link" href="http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/B-spline/bspline-curve-coef.html"><span class="icon">http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/B-spline/bspline-curve-coef.html</span></a> for a discussion of this and a different evaluation approach than I will examine here.</p>
<p>&nbsp;</p>
<p>I looked at all that, winced hard, and skipped ahead to where they&#8217;d solved the uniform version, giving the nice-ish equation for a single segment of</p>
<p><img class="aligncenter size-full wp-image-95" title="B-spline uniform version for k=3" src="http://exerciseforthereader.files.wordpress.com/2009/11/b_uniform_k3.png?w=511&#038;h=29" alt="$$B_{uniform,k=3,i}(u)=\frac{1}{2}\,\left( -{p}_{i}\,\left( 2\,{u}^{2}-2\,u-1\right) +{p}_{i+1}\,{u}^{2}+{p}_{i-1}\,{\left( u-1\right) }^{2}\right)$$" width="511" height="29" /></p>
<p>or in matrix form,</p>
<p><img class="aligncenter size-full wp-image-96" title="B-spline uniform formulation for k=3, matrix form" src="http://exerciseforthereader.files.wordpress.com/2009/11/b_uniform_k3_matrix.png?w=469&#038;h=57" alt="$$B_{uniform,k=3,i}(u)=\frac{1}{2}\,\left( \begin{pmatrix}{u}^{2} &amp; u &amp; 1\end{pmatrix}.\begin{pmatrix}1 &amp; -2 &amp; 1\cr -2 &amp; 2 &amp; 0\cr 1 &amp; 1 &amp; 0\end{pmatrix}.\begin{pmatrix}{P}_{i-1}\cr {P}_{i}\cr {P}_{i+1}\end{pmatrix}\right)$$" width="469" height="57" /></p>
<p>This was what I wanted anyway, an invariant equation where I could just feed it different parameter values and it would produce an x and y. To prevent completely following the path of my own confusion, I&#8217;ll point out here that this function is actually defined in terms of</p>
<dl>
<dt><em>w</em></dt>
<dd>Yet another parameterization. In this case, w ranges from 0 to 1 <em>within each curve segment</em>. This is a reinterpretation of the <em>v</em> parameter as the sum of an integer part (the segment number) and a fractional part (<em>w</em>). </dd>
<dt><em>j</em></dt>
<dd>The curve segment number, not to be confused with the <em>i</em> which goes from 0 to n in the definition of B above. To tie these various interpretations of parameter together, <em>v=u (n-k+2)=j+w-1</em>. <em>j</em> ranges from 1 to <em>n-k+2</em>. <strong>Note</strong> that <em>j</em> is one-based, NOT zero-based (hence the -1 offset when mapped from the 0 to n-k+2 range). This is because at the end of the curve, j=n-k+2 and w=1 &#8212; effectively, <em>w</em> is adding one to the range of <em>j</em> (so we need a -1 correction to get the ends to line up right). At the beginning of the curve, w=0, so j must be 1 or we&#8217;d again go out of range. A more intuitive interpretation of this is that <em>j</em> is the count of intervals, so this is a pretty standard fencepost correction (<a class="ext-link" href="http://en.wikipedia.org/wiki/Off-by-one_error"><span class="icon">http://en.wikipedia.org/wiki/Off-by-one_error</span></a>). </dd>
</dl>
<p>In terms of these renamed variables, the uniform equation would be</p>
<p><img class="aligncenter size-full wp-image-97" title="B-spline uniform version with renamed variables" src="http://exerciseforthereader.files.wordpress.com/2009/11/b_uniform_k3_rename.png?w=531&#038;h=28" alt="$$B_{uniform,k=3,j}(w)=\frac{1}{2}\,\left( -{p}_{j}\,\left( 2\,{w}^{2}-2\,w-1\right) +{p}_{j+1}\,{w}^{2}+{p}_{j-1}\,{\left( w-1\right) }^{2}\right)$$" width="531" height="28" /></p>
<p>So hurray, there was an easy and uniform equation after all; I could either pass in a different window of three control points for each segment, or I could pass in the segment number in addition to the segment-relative parameter (<em>w</em>) and look up the right control points.</p>
<p>The first problem I encountered was that the curve created this way doesn&#8217;t actually interpolate the end points. That is to say, when v=0 the curve isn&#8217;t at p<sub>0</sub>. Here&#8217;s where I really took a shortcut. Instead of backing off and trying to figure out what was going on, I noticed two things:</p>
<ul>
<li>The knot vector sort of looks like index indirection lookup table. I think this is an especially Computer Science-ish assumption &#8212; adding a layer of indirection is a pretty standard way to make non-uniform processes look uniform (see below for a more detailed discussion of what I mean by &#8220;uniform&#8221;), and a table of integers looks a lot like a list of indices. Particularly because the knot vector repeats its first and last values.</li>
<li>If you feed the B<sub>uniform</sub> function the points [p<sub>0</sub> , p<sub>0</sub> , p<sub>1</sub>] (pretending that the control point list had multiple copies of the end-points), and evaluate it at v=0, it does actually evaluate to p<sub>0</sub>.</li>
</ul>
<p>I was actually working with k=4 for these initial experiments; I only dropped back to k=3 in an attempt to simplify things to figure out what was going on. The effect I saw is magnified at higher values of k &#8212; in the cubic k=4 case, each B<sub>uniform</sub> is mixing together 4 control points instead of 3. To get it to interpolate the end-point required <em>two</em> additional segments to get from the last &#8220;normal&#8221; segment (on [ p<sub>0</sub> , p<sub>1</sub> , p<sub>2</sub> , p<sub>3</sub> ]) to actually end up at p<sub>0</sub>. The last normal segment, evaluated at u=0, gives us <em>1/6 (P<sub>2</sub>+4 P<sub>1</sub> + P<sub>0</sub>)</em>. When we evaluate on [ p<sub>0</sub> , p<sub>0</sub> , p<sub>1</sub> , p<sub>2</sub> ] as the first &#8220;weird&#8221; term, at u=0 we get <em>1/6 (P<sub>1</sub>+5 P<sub>0</sub>)</em>. It&#8217;s not until we&#8217;re looking at [ p<sub>0</sub> , p<sub>0</sub> , p<sub>0</sub> , p<sub>1</sub> ] that we actually get p<sub>0</sub> at u=0.</p>
<p>In short, I got a little seduced by algebraic numerology &#8212; of <em>course</em> if you have a function which mixes 4 points, and you replace enough of those four points with copies of the same point, you&#8217;ll end up with a function which returns that point no matter what you give it. (This is the final reductive case, where all four points are actually copies of p<sub>0</sub> .)</p>
<p>The actual problem here is that we&#8217;ve wandered pretty far from the original definition of a B-spline. In particular, we have too many curve segments &#8212; v is ranging from something like <em>-1</em> to <em>n-k</em> rather than <em>1</em> to <em>n-k+2</em>. (The key difference from the &#8220;real&#8221; B-spline is that the proper B-spline doesn&#8217;t actually have a &#8220;normal&#8221; segment on [ p<sub>0</sub> , p<sub>1</sub> , p<sub>2</sub> , p<sub>3</sub> ] &#8212; instead, it&#8217;s already started going into special cases.)</p>
<p>The practical upshot of this is that we&#8217;re spending far too much of the parameter space near the end-points of the curve, leaving only a small portion for the whole interior of the curve. This could be disastrous for rendering, where it&#8217;s very nice to sample at evenly-spaced intervals of <em>u</em> and assume that this will lead to generally evenly-spaced vertices in 3-space: with this scheme we&#8217;d end up with a great many sampling points at the beginning and end of the curve, and a paucity in the interior.</p>
<p>Even this difficulty could be overcome, by introducing yet another reparameterization to redistribute the incoming u values more evenly over the length of the curve. However, there was no getting around the problem that the actual 3-space shape of the curve was different than my reference implementation (a 3D modeling tool). I&#8217;m always willing to entertain the possibility that the reference is wrong and I&#8217;m right (perhaps too willing), but at least I needed to understand what was going on here.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/exerciseforthereader.wordpress.com/90/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/exerciseforthereader.wordpress.com/90/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/exerciseforthereader.wordpress.com/90/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/exerciseforthereader.wordpress.com/90/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/exerciseforthereader.wordpress.com/90/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/exerciseforthereader.wordpress.com/90/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/exerciseforthereader.wordpress.com/90/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/exerciseforthereader.wordpress.com/90/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/exerciseforthereader.wordpress.com/90/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/exerciseforthereader.wordpress.com/90/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/exerciseforthereader.wordpress.com/90/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/exerciseforthereader.wordpress.com/90/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/exerciseforthereader.wordpress.com/90/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/exerciseforthereader.wordpress.com/90/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=exerciseforthereader.wordpress.com&amp;blog=5637329&amp;post=90&amp;subd=exerciseforthereader&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://exerciseforthereader.wordpress.com/2009/11/01/b-spline-definitions/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">Seth</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/11/n_i_1.png" medium="image">
			<media:title type="html">N_i_1</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/11/n_i_k.png" medium="image">
			<media:title type="html">N_i,k(v)</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/11/b_k.png" medium="image">
			<media:title type="html">B-spline curve definition</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/11/b_uniform_k3.png" medium="image">
			<media:title type="html">B-spline uniform version for k=3</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/11/b_uniform_k3_matrix.png" medium="image">
			<media:title type="html">B-spline uniform formulation for k=3, matrix form</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/11/b_uniform_k3_rename.png" medium="image">
			<media:title type="html">B-spline uniform version with renamed variables</media:title>
		</media:content>
	</item>
		<item>
		<title>The B-spline Series: Motivation</title>
		<link>http://exerciseforthereader.wordpress.com/2009/11/01/the-b-spline-series-motivation/</link>
		<comments>http://exerciseforthereader.wordpress.com/2009/11/01/the-b-spline-series-motivation/#comments</comments>
		<pubDate>Sun, 01 Nov 2009 20:51:11 +0000</pubDate>
		<dc:creator>Seth Porter</dc:creator>
				<category><![CDATA[3D Graphics]]></category>

		<guid isPermaLink="false">http://exerciseforthereader.wordpress.com/?p=81</guid>
		<description><![CDATA[The B-Spline family of curves are a nice way to make smooth curves from a series of control points. The idea is that the control points give you &#8220;handles&#8221; to pull the curve around; it won&#8217;t actually pass through any of them (except for the first and last ones), but it will be attracted to [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=exerciseforthereader.wordpress.com&amp;blog=5637329&amp;post=81&amp;subd=exerciseforthereader&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>The B-Spline family of curves are a nice way to make smooth curves from a series of <em>control points</em>. The idea is that the control points give you &#8220;handles&#8221; to pull the curve around; it won&#8217;t actually pass through any of them (except for the first and last ones), but it will be attracted to them while retaining some nice smoothness properties.</p>
<p>That much I knew coming in. For various reasons, I wanted to write a program to evaluate B-splines, with a particular eye to rendering them in 3D. This seemed like it was going to be a very easy task; instead, I learned a lot along the way.</p>
<p><span id="more-81"></span></p>
<h2 id="AMotivationforB-Splines">A Motivation for B-Splines</h2>
<p>Ignoring the math for a moment, let&#8217;s talk about the basic idea of B-splines. There are quite a few ways to fit a smooth (roughly meaning &#8220;at least twice differentiable, and with at least the first derivative being continuous across the function) curves to a set of control points. (And in fact there are a lot more if the curve doesn&#8217;t even have to pass through the control points!)</p>
<p>The simplest approach is to observe that you can always fit a quadratic (degree = 2) polynomial to any three points, or a cubic (degree = 3) to any four points, and so forth. I don&#8217;t think anyone uses this approach in serious modelling or drawing software, but it&#8217;s kind of the benchmark against which other approaches can be compared. One key benefit, which I&#8217;ll discuss below, is that this approach gives you a single function across the entire length of the curve, making them naturally uniform. There are a few problems, however:</p>
<ul>
<li>They get uglier as you have more and more control points, since the degree of the polynomial rises along with the control point count</li>
<li>More fatally, they wiggle. This is most easily seen in a picture:</li>
</ul>
<p>&nbsp;</p>
<div id="attachment_82" class="wp-caption aligncenter" style="width: 460px"><img class="size-full wp-image-82" title="Polynomial Wiggle" src="http://exerciseforthereader.files.wordpress.com/2009/11/polynomial_wiggle.png?w=450&#038;h=196" alt="pts : [[0, 0], [1, 3], [2, 0], [3, 0], [4, 0], [5, 0], [6, 0]]; load(interpol); plot2d([[discrete,pts], lagrange(pts)], [x, 0, 6.1], [style, [points, 1], [lines]], [legend, false]);" width="450" height="196" /><p class="wp-caption-text">Polynomial interpolation demonstrating &quot;wiggle&quot;</p></div>Notice how the curve repeatedly dips below the <em>y=0</em> line, even though the control points are strictly non-negative. (It also overshoots at the top, going up into <em>y=4</em> territory before hitting the <em>(1, 2)</em> point on the <em>downstroke</em>.) These would be annoying enough, but the worst part is that it never becomes a straight line, even when fed 5 linear control points. This makes simple polynomial interpolation pretty much useless for industrial design: imagine if your mouse had ripples all through its surface, simply because of a stylishly sharp curve at the nose. Even worse, the direction of the wiggles can actually flip in response to relatively small changes in the control points!</p>
<p>&nbsp;</p>
<p>A much better family of functions (for geometric modeling purposes) are the Bézier curves. These very useful curves are used in many drawing programs. These curves don&#8217;t actually go through the control points, except for the first and last ones, but instead use the control points as &#8220;handles&#8221; (you can think of them as pulling the curve toward them with springs, rather than having the curve attached to them). Bézier curves exhibit the &#8220;convex hull property&#8221;, meaning (casually) that if you draw lines connecting the control points, the curve will be contained within those lines. In other words, they don&#8217;t have the overshoot problems of simple polynomial interpolation. The fact that they don&#8217;t go through the control points is disconcerting at first, but isn&#8217;t fundamentally a problem for many design and modeling tasks.</p>
<p>Here&#8217;s a Bézier curve through the same control points:</p>
<p>&nbsp;</p>
<p><div id="attachment_83" class="wp-caption aligncenter" style="width: 460px"><img class="size-full wp-image-83" title="Bézier Curve Example" src="http://exerciseforthereader.files.wordpress.com/2009/11/bezier_curve.png?w=450&#038;h=223" alt="Bezier(i, n, u) := binomial(n, i) * u^i * (1-u)^(n-i); BCurve(P, n, u) := sum(P[i+1]*Bezier(i, n, u), i, 0, n); plot2d([[discrete,pts], [parametric, BCurve(pts, 6, u)[1], BCurve(pts, 6, u)[2], [u, 0.001, 1], [nticks, 80]]], [x, 0, 6.1], [style, [points, 1], [lines]], [legend, false]);" width="450" height="223" /><p class="wp-caption-text">A Bézier curve through the same control points</p></div>Notice that this curve is much more restrained; it doesn&#8217;t come close to the (1, 3) control point, but it doesn&#8217;t overshoot or wiggle. This is a curve you could use to design a mouse. There is still one key problem, however: if you move one of the control points, the entire shape of the curve will be affected. To see why this is a problem, imagine that you&#8217;ve got the mouse almost perfect. The shape fits perfectly in your hand, is big enough to hold the electronics &#8212; everything&#8217;s done except that one VP decides that the stylish sharp curve at the end is perhaps a bit <em>too</em> sharp. You adjust the control points slightly and the VP is happy. But now, the entire rest of the shape has changed &#8212; maybe you don&#8217;t have enough clearance for the electronics, maybe the hand-rest isn&#8217;t quite as comfortable. Of course you can go and change those control points, too, but each time you touch something, everything changes. This is known in the trade as <em>global propagation of local changes</em>. As a result, Bézier curves are perhaps best suited for freehand work.</p>
<p>&nbsp;</p>
<p>By now you can probably guess what the nice properties of B-splines are. They act a lot like Bézier curves, having the convex hull property and interpolating only the first and last control points, with the key difference that a change to a control point will only change a limited portion of the curve. To accomplish this trick, B-splines are made up of a number of separate curve segments, rather than a single high-degree polynomial. These segments are cleverly constructed so that when they meet, both segments are curving the same way (their first derivatives are the same). In fact, B-splines have an extra parameter, <em>k</em>, which controls both the polynomial degree of these segments and how continuous they are when they meet (how many derivatives are equal at the intersection point). In common usage, k is 3 or 4, leading to either quadratic or cubic curve segments. (Lower values of k aren&#8217;t &#8220;curves&#8221; in the common sense; k=2 produces straight lines connecting the control points, and k=1 is the disjoint set of control points, not connected at all. Higher k values lead to a &#8220;stiffer&#8221; spline, as the requirement of equal second and third and fourth derivatives forces the curve closer and closer to a straight line.)</p>
<p>As an example, here&#8217;s a <em>k=3</em> B-spline (each segment is a quadratic curve) through the same control points as the curves above. As before, the control points are shown as blue circles. Additionally, the segments are each drawn in different colors, and the boundaries between segments are marked by red squares:</p>
<p>&nbsp;</p>
<p><div id="attachment_84" class="wp-caption aligncenter" style="width: 460px"><img class="size-full wp-image-84" title="B-spline Example" src="http://exerciseforthereader.files.wordpress.com/2009/11/bspline_example.png?w=450&#038;h=232" alt="pts2 : [[0, 0], [1, 3], [2, 0], [3, 0], [4, 0], [5, 0], [6, 0], [7, 0]]; mySegments7 : makelist(at(basis_indep_spline3(P, seg, u), [P[0]=2*P[0]-P[1], P[7]=2*P[7]-P[6]]), seg, 1, 6); accumX : mySegments7; for idx : 0 step 1 thru 7 do accumX : subst(pts2[idx+1][1], P[idx], accumX); accumY : mySegments7; for idx : 0 step 1 thru 7 do accumY : subst(pts2[idx+1][2], P[idx], accumY); makePlotList(u0, u1) := makelist([parametric, accumX[i], accumY[i], [u, u0, u1]], i, 1, 6); plot2d(append([[discrete, pts2]], makePlotList(0, 1),   [[discrete, makelist([at(accumX[i], u=1), at(accumY[i], u=1)], i, 1, 6)]]),      [x, -1, 6.1], [y, -0.2, 3.2],     [style, [points, 1],      [lines], [lines], [lines], [lines], [lines], [lines],     [points, 1,2,6]],     [legend, false]);" width="450" height="232" /><p class="wp-caption-text">A k=3 B-spline curve through the same control points</p></div>To make things a little clearer (perhaps), here&#8217;s the same curve with each segment drawn from <em>u=-0.1</em> to <em>u=1.1</em>. This &#8220;overdraw&#8221; demonstrates how each segment really is a parabola, carefully chosen so that the slopes are momentarily equal at the point where the segments meet:</p>
<p>&nbsp;</p>
<p><div id="attachment_85" class="wp-caption aligncenter" style="width: 460px"><img class="size-full wp-image-85" title="B-spline Example with Segment Overdraw" src="http://exerciseforthereader.files.wordpress.com/2009/11/bspline_overdraw_example.png?w=450&#038;h=260" alt="B-spline Example with Segment Overdraw" width="450" height="260" /><p class="wp-caption-text">B-spline Curve with segments rendered from u=-0.1 to u=1.1</p></div>
<p>Notice that we have the nice non-wiggling behavior of the Bézier curve, combined with a much narrower range of influence for each control point. The control points only influence nearby segments, meaning that this curve &#8220;flattens out&#8221; much more quickly than the Bézier version.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/exerciseforthereader.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/exerciseforthereader.wordpress.com/81/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/exerciseforthereader.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/exerciseforthereader.wordpress.com/81/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/exerciseforthereader.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/exerciseforthereader.wordpress.com/81/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/exerciseforthereader.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/exerciseforthereader.wordpress.com/81/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/exerciseforthereader.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/exerciseforthereader.wordpress.com/81/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/exerciseforthereader.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/exerciseforthereader.wordpress.com/81/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/exerciseforthereader.wordpress.com/81/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/exerciseforthereader.wordpress.com/81/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=exerciseforthereader.wordpress.com&amp;blog=5637329&amp;post=81&amp;subd=exerciseforthereader&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://exerciseforthereader.wordpress.com/2009/11/01/the-b-spline-series-motivation/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">Seth</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/11/polynomial_wiggle.png" medium="image">
			<media:title type="html">Polynomial Wiggle</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/11/bezier_curve.png" medium="image">
			<media:title type="html">Bézier Curve Example</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/11/bspline_example.png" medium="image">
			<media:title type="html">B-spline Example</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/11/bspline_overdraw_example.png" medium="image">
			<media:title type="html">B-spline Example with Segment Overdraw</media:title>
		</media:content>
	</item>
		<item>
		<title>The Ugly Truth Behind Pretty Pictures</title>
		<link>http://exerciseforthereader.wordpress.com/2009/06/27/the-ugly-truth/</link>
		<comments>http://exerciseforthereader.wordpress.com/2009/06/27/the-ugly-truth/#comments</comments>
		<pubDate>Sat, 27 Jun 2009 05:06:14 +0000</pubDate>
		<dc:creator>Seth Porter</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://exerciseforthereader.wordpress.com/?p=73</guid>
		<description><![CDATA[Or maybe not that ugly, but it makes a better headline. Last post I promised the backstory behind the pretty pictures. As a fair warning, there are no pictures this time around, just lots of discussion of Linux monitoring tools and their integration. As a second caveat, I&#8217;m not always positive whether a given tool [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=exerciseforthereader.wordpress.com&amp;blog=5637329&amp;post=73&amp;subd=exerciseforthereader&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Or maybe not <em>that</em> ugly, but it makes a better headline.</p>
<p>Last post I promised the backstory behind the <a title="Server Monitoring with Pretty Pictures" href="http://exerciseforthereader.wordpress.com/2009/06/20/server-monitoring-with-pretty-pictures/" target="_blank">pretty pictures</a>. As a fair warning, there are no pictures this time around, just lots of discussion of Linux monitoring tools and their integration.<span id="more-73"></span></p>
<p>As a second caveat, I&#8217;m not always positive whether a given tool is vital for the monitoring per se, or whether it was just something I used to set the stage and figure out what I <em>could</em> monitor. That being said, I&#8217;ll do my best to reconstruct the history, with the help of Aptitude logs and <a title="Fast System VerSioning" href="http://fsvs.tigris.org/" target="_blank">FSVS</a> diffs.</p>
<p>A very brief plug for a package I like: fsvs is basically Subversion-for-config-files in my usage, though I understand it  can be used as a bare metal deployment system. Well worth looking into. (And I just discovered that apparently it stands for &#8220;Fast System VerSioning&#8221;. Huh. I always assumed the &#8220;FS&#8221; was for &#8220;File System&#8221;, but I admit I never thought much about the &#8220;VS&#8221;&#8230; shame they had to force the acronym with intercaps.)</p>
<p>There are three distinct layers to the software stack, if you follow the data from original collection all the way to final presentation. I&#8217;ll start with the data providers.</p>
<h2>Sources for Health Data</h2>
<p>For some of these I&#8217;ll link to the project&#8217;s home page, but in all cases these were installed from the Debian package repositories. I&#8217;m using the most recent versions for Debian Lenny, aka stable. If it&#8217;s relevant,  you can check which version exactly I&#8217;m using via <a href="http://www.debian.org/distrib/packages#search_packages" target="_blank">the Debian search page</a>.</p>
<dl>
<dt><a title="CPUFreqUtils" href="http://www.kernel.org/pub/linux/utils/kernel/cpufreq/cpufrequtils.html" target="_blank">cpufrequtils</a></dt>
<dd>I used these to set up CPU frequency scaling policy; can&#8217;t remember if this is also used directly in data gathering. The key point here is using kernel freq management instead of a userspace daemon. I don&#8217;t think it necessarily matters from a monitoring point of view, but it&#8217;s much tidier and should be more efficient.</dd>
<dt>hddtemp</dt>
<dd>Monitors hard drive temperatures as reported by <a href="http://en.wikipedia.org/wiki/S.M.A.R.T." target="_blank">SMART</a>-capable  drives (otherwise known as &#8220;just about any SATA or IDE hard drive, these days). I can&#8217;t find a good homepage for this tool (it&#8217;s <strong>not</strong> the one at hddtemp.com, which appears to be Windows-based and a bit full of itself).  As I recall, the main purpose (for this use) is to provide a network daemon (localhost only, thank you) which the data gathering can query on demand. I explicitly <em>disable</em> the periodic monitoring option, which would be redundant (and rolls my logs).</dd>
<dt>smartmontools</dt>
<dd>I use this package to enable SMART on all drives and monitor for catastrophic changes — in that case, it sends an e-mail directly to my phone. I also use it to schedule automatic self-tests of the drives (scattered across typical idle time). I don&#8217;t remember if this tool is required to make the pictures, but it&#8217;s a key part of the peace of mind story.</dd>
<dt>lm-sensors</dt>
<dd>(A confession is in order here. I accidentally lied to a co-worker about this one; I don&#8217;t actually use sensord at all. I did at one point, but it was just logging to syslog, which kept the drives awake at all times but wasn&#8217;t easy to skim for trends. Instead, I use a common monitoring  package for all values I&#8217;m tracking, as described below. Sorry if I threw you off-track, Eric!)</dd>
<dd>This very useful package reads motherboard sensors for things like CPU and VRM temperatures, voltages, and fan speeds. There&#8217;s a command line tool for detecting and configuring your sensors (some config file editing is required, but it&#8217;s a pretty straightforward process). The sensord companion package can monitor for thresholds and log sensor values, but as noted above I prefer to use a common tool for that.</dd>
<dt><a href="http://www.wains.be/projects/rrdweather/" target="_blank">RRDWeather</a></dt>
<dd>This is a neat little tool for fetching weather data from weather.com&#8217;s web service and storing it in an RRD database. This tool is a little unlike the others, in that it&#8217;s directly storing samples, rather than providing a service which can be queried on demand.</dd>
</dl>
<p>The rest of the monitored values are either built into the kernel, or provided directly by the system being monitored (such as Apache&#8217;s server stats).</p>
<h2>Data Storage</h2>
<p>The key part here, and the one that got me started on all of this in the first place, is <a href="http://oss.oetiker.ch/rrdtool/" target="_blank">RRDTool</a>. The RRD stands for &#8220;Round Robin Database&#8221;. It has no built-in data collection apparatus, nor any GUI or web-based support for graph creation and rendering (though I believe there&#8217;s a small example CGI script). Rather, it simply provides a command-line mechanism for creating databases, a command-line or programmatic interface for adding data samples, and a command-line tool to generate charts given a chart specification.</p>
<p>The neat thing about RRD is that the databases can cover long periods of time, with fine near-term temporal resolution, while only consuming a fixed amount of disk. In rough terms, the trick is to progressively degrade the resolution: store the last day or so at 5 second intervals, say, but the past week only at 1 minute intervals, and so on until far enough back you might only save only value per day. This is a very clever trick, and solves one pernicious problem of long-baseline logging: when the data gathering itself becomes the problem you&#8217;re trying to detect.</p>
<p>There are some interesting consequences of this scheme. The most important to the user is that you have to define, at database creation time, exactly how you want to combine values (to come up with a single value to represent a minute, starting with samples every five seconds). From an alternative point of view, you need to figure out what charts you want to draw, and be sure to save that data. Fortunately, you can specify multiple aggregations functions, but you pay for it in increased disk usage for a given time period. For example, you might decide that you only care about the maximum recorded temperature in a period; in that case the database will only store maximums once it starts coalescing. For something like voltages, where any deviation up or down is bad, you might go further and record average, min and max. (I imagine this could also make a nice &#8220;envelope&#8221; chart, showing all three at once.) The only real problem is that you can&#8217;t decide retroactively that you wish you were recording some other aggregate function, since it&#8217;s already thrown that information away.</p>
<p>A second consequence of this scheme is more subtle, and didn&#8217;t immediately occur to me. Simple graphs of these values will behave as expected. However, when you start getting cute and graphing calculated values (such as my stacked CPU utilization chart), you can see anomalies where the line breaks out of the bounds of the actual physical measurement. For example, the stacked line for idle plus system plus user time hit a whopping 300%, despite the theoretical limit of 200% (one hundred per &#8220;virtual core&#8221;). The problem is that I&#8217;m gathering maximums over a period of time, then stacking them together. If, at one point during the five minute period, idle was at 100% (er, I mean 200%), and at another time the kernel was using 200%, then each max would be 200% and the stacked line would be twice as high as it logically could be. Makes perfect sense when you think about it, but it took me longer to catch on to than I&#8217;d care to admit. I suspect that this effect would only show up for certain aggregation functions and certain combinations of them (maybe average would always sum to unity?), but I wouldn&#8217;t care to bet on it without doing more math than I&#8217;m prepared to do for this post.</p>
<p>Oh, one other thing: I posted exclusively PNGs in the &#8220;pretty pictures&#8221; post, to increase the odds that everyone would be able to see them correctly. The tool, however, is perfectly happy rendering to SVG, PDF, or EPS as well. This is good news if you want to annotate or print the resulting charts. I haven&#8217;t played with the other formats much, so I can&#8217;t speak to details like how the SVGs look under significant resizing.</p>
<h2>Data Collection</h2>
<p>As noted above, RRDTool provides data storage and rendering, but defers to others to actually provide the data. There&#8217;s a remarkably rich ecosystem here — of course you can code your own with the scripting language of your choice, but there are also tools for gathering data from a wide variety of sources. You can find a partial list at <a href="http://oss.oetiker.ch/rrdtool/rrdworld/index.en.html" target="_blank">the &#8220;RRDWorld&#8221; page</a>.</p>
<p>Most of the full systems (as opposed to task-specific utilities) are focused on large-scale monitoring; the kind of task where one computer is dedicated almost exclusively to data gathering and presentation, watching an enterprise LAN. Very nice, and presumably useful if you&#8217;re into that sort of thing, but muchly overkill for my needs. Also, these suites seem to mostly assume SNMP as a common monitoring language, so I&#8217;d need to bridge all those disparate data sources to that format.</p>
<p>A second obvious option would be writing a script to gather exactly the data I want. This would be a cool project, would let me talk to any data source with a reasonable textual interface, and would give me the satisfaction of doing it all myself (er, except for the data storage and rendering). The trouble is I&#8217;m just not up to it. I mean, I could write the script perfectly well, but I&#8217;d be cutting corners — I probably wouldn&#8217;t properly daemonize it, making startup and shutdown tricky, and the time I&#8217;d save by working in Perl would be returned with interest in the time I&#8217;d spend trying to get CPU utilization down. After all, this isn&#8217;t a run-once data-munging script; this would be polling multiple times a minute, potentially spawning quite a few processes each time to gather reports. What I really need is a dedicated program, ideally written in an efficient language (trading programmer time for CPU cycles), and even more ideally able to talk to most of these data sources in their native APIs (to avoid repeatedly launching the command line interfaces).</p>
<p>Fortunately for me, this program has already been written: <a href="http://collectd.org/" target="_blank">collectd</a>. At least at the time I made the choice, this was a dedicated, narrow-focus app, written in C, and emphasizing low impact for high frequency monitoring. (Since then they seem to have added an embedded Perl interpreter and gone to a more modular architecture, but so far the core values seem to have remained intact.) In the newer version in Lenny, all data gathering (and even the RRD backend) is plugin based. However, there are native plugins for all the sources listed above (as well as quite a few kernel and application-native sources), so I&#8217;m not running a boatload of Perl fragments every few seconds.</p>
<p>Configuration is slightly tricky: collectd.conf is an Apache-style semi-XML format, which took some getting used to. A few of the counters still don&#8217;t seem to do exactly what I want; in particular I haven&#8217;t found a setup for disk traffic monitoring that deals gracefully with my RAID5 and LVM partitioning scheme. However, on the whole I&#8217;ve been very happy with the tool, and I&#8217;m quite willing to believe that my remaining problems are user error.</p>
<p>Oh, one word of warning: collectd&#8217;s preferred RRD setup changed significantly in the upgrade from Debian Etch to Lenny. Unfortunately I missed this at the time, and when I finally caught on to it there wasn&#8217;t an easy way to merge my newly collected data and the historical baseline. I still have the old files archived, but this pointed up a particular risk in upgrading data collection tools when you&#8217;re trying to maintain a baseline. I&#8217;d probably be a lot more upset if I&#8217;d been looking at the loss of a year or so of data, so I&#8217;m grateful I learned the lesson at the cost of January through March. They were boring months anyway, at least from a server health point of view.</p>
<h2>Graph Definition and Rendering</h2>
<p>As may have been obvious from the discussion of calculated values, RRDTool has a pretty robust scheme for defining composite values. It&#8217;s a sort of funky RPN syntax, but that&#8217;s a nice reminder of old HP calculators. This actually happens inside a chart definition, where you can load data from one or more files, then combine the values as desired, before finally drawing various styles of stacked or filled lines. In my limited experience, the RPN syntax is manageable, but the overall file format is a bit of a handful (and begs for a templating engine for related charts). Since I needed a tool anyway to bridge graph requests into Apache (and ideally to manage little things like caching and updating them), I decided to try some  web-based front ends.</p>
<p>I started out using Torrus (linked from the RRDWorld page cited above). The version in Debian Etch was SNMP-centric, and offered its own data gathering services, but I could disable all that and just point it at a directory tree of RRD files (which is what collectd produces). There was some Perl wrangling to produce the charts I wanted (since collectd tends to store one datapoint per file, and I wanted both CPUs on the same chart, for example), but the end result was quite workable. I got a hierarchical view of all available data sources, with auto-generated charts for each, as well as the couple of hand-tuned ones. Configuration was a little heavyweight (modifying Perl files as well as XML config files), but the end result was quite usable.</p>
<p>As you may guess from the past tense, we have since parted ways. When I upgraded to Debian Lenny, the new collectd hierachy wasn&#8217;t as close to what Torrus expected. Torrus had also changed; the &#8220;plain old directory tree&#8221; option was now barely supported, in favor of a streamlined workflow for directly querying your SNML sources. Wonderful if that&#8217;s what you&#8217;re doing, but in my case it&#8217;s not. So, faced with the option of proliferating scripts to try to glue these tools together, I looked for another solution.</p>
<p>That&#8217;s when I started using <a href="http://web.taranis.org/drraw/" target="_blank">drraw</a>. It follows the lead of RRDTool in being completely ignorant of the semantic domain: it&#8217;s simply (and wonderfully) a tool for creating and displaying charts generated from RRD datasets. I briefly missed the auto-generated charts from Torrus, but I found myself making much more data-dense charts as I set out to recreate them. Every single chart on my &#8220;dashboard&#8221; homepage is at least displaying multiple datasets, and all but one of them are using more or less complex calculated values as well. (The exception that comes to mind is the memory usage chart, which instead uses the RRD-native stacking functionality, as well as using base-1024 instead of base-1000 for scaling.)</p>
<p>So far, several months in, I&#8217;ve been very happy with drraw. Its URLs are a little ugly, and if it weren&#8217;t for FSVS I&#8217;d need a solution for backing up any important chart definitions, but the flexibility is great: it&#8217;s trivial to make ad hoc modifications to a chart to test a theory or reveal a trend, then abandon them or update the saved definition if they work out.</p>
<h2>In Closing</h2>
<p>I have the utmost respect for anyone who&#8217;s made it this far. I&#8217;d be happy to share configuration details with anyone who wants to try this approach (or a modified version); I&#8217;d also love to hear from anyone with better ideas. I certainly haven&#8217;t done an exhaustive survey of the available software; this is pretty much <a href="http://en.wikipedia.org/wiki/Satisficing" target="_blank">satisficing</a> rather than optimizing. My standards are pretty high in terms of data fidelity, and at least moderate in terms of system overhead, but beyond that I wanted to get this monitoring up and running, then get back to my programming projects.</p>
<p>Next time I&#8217;ll try to introduce my latest long-running hobby project, a pure .Net (and Mono) implementation of the UPnP MediaServer protocol stack, and maybe sketch some of the twists and turns between having an interesting idea and actually having working software. Thanks for reading.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/exerciseforthereader.wordpress.com/73/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/exerciseforthereader.wordpress.com/73/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/exerciseforthereader.wordpress.com/73/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/exerciseforthereader.wordpress.com/73/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/exerciseforthereader.wordpress.com/73/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/exerciseforthereader.wordpress.com/73/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/exerciseforthereader.wordpress.com/73/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/exerciseforthereader.wordpress.com/73/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/exerciseforthereader.wordpress.com/73/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/exerciseforthereader.wordpress.com/73/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/exerciseforthereader.wordpress.com/73/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/exerciseforthereader.wordpress.com/73/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/exerciseforthereader.wordpress.com/73/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/exerciseforthereader.wordpress.com/73/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=exerciseforthereader.wordpress.com&amp;blog=5637329&amp;post=73&amp;subd=exerciseforthereader&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://exerciseforthereader.wordpress.com/2009/06/27/the-ugly-truth/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">Seth</media:title>
		</media:content>
	</item>
		<item>
		<title>Server Monitoring with Pretty Pictures</title>
		<link>http://exerciseforthereader.wordpress.com/2009/06/20/server-monitoring-with-pretty-pictures/</link>
		<comments>http://exerciseforthereader.wordpress.com/2009/06/20/server-monitoring-with-pretty-pictures/#comments</comments>
		<pubDate>Sat, 20 Jun 2009 18:40:12 +0000</pubDate>
		<dc:creator>Seth Porter</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://exerciseforthereader.wordpress.com/?p=47</guid>
		<description><![CDATA[(Here are the pretty pictures. The actual discussion is after the break.) (And okay, maybe they aren&#8217;t that pretty, but I&#8217;d say they&#8217;re more aesthetic than you could reasonably expect for monitoring health stats on a Linux server. Further defensive parentheticals will be reserved for later in the post.) For a while now I&#8217;ve been [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=exerciseforthereader.wordpress.com&amp;blog=5637329&amp;post=47&amp;subd=exerciseforthereader&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>(Here are the pretty pictures. The actual discussion is after the break.) (And okay, maybe they aren&#8217;t <em>that</em> pretty, but I&#8217;d say they&#8217;re more aesthetic than you could reasonably expect for monitoring health stats on a Linux server. Further defensive parentheticals will be reserved for later in the post.)<br />
<img class="size-full" src="http://exerciseforthereader.files.wordpress.com/2009/06/freespace-28-hours.png?w=397&#038;h=165" border="0" alt="" width="397" height="165" align="center" /><br />
<img class="size-full" src="http://exerciseforthereader.files.wordpress.com/2009/06/cpu-28-hours.png?w=397&#038;h=165" border="0" alt="" width="397" height="165" align="center" /><br />
<img class="size-full" src="http://exerciseforthereader.files.wordpress.com/2009/06/memory-28-hours.png?w=397&#038;h=165" border="0" alt="" width="397" height="165" align="center" /><br />
<img class="size-full" src="http://exerciseforthereader.files.wordpress.com/2009/06/temps-28-hours.png?w=397&#038;h=165" border="0" alt="" width="397" height="165" align="center" /></p>
<p>For a while now I&#8217;ve been meaning to post something about Calliope, my (Debian) Linux server at home. I&#8217;ve got a nice draft somewhere about all the useful services I&#8217;ve got running, why I chose the packages I did, and so forth. At the end of the day, though, the basic take-away is &#8220;pick some services you want to run, install them, and Google till you get them to work&#8221;. (I&#8217;ll probably post it someday, though perhaps not after giving it such a heart-warming buildup.)</p>
<p>Anyway, the more I think about it, the most distinctive part of Calliope isn&#8217;t the  actual services she provides, but rather the tools I&#8217;ve assembled for keeping an eye on her. This isn&#8217;t like a desktop box, where I&#8217;m sitting at the console or the machine is turned off. Instead, most of my interaction is indirect — listening to <a title="music on the PS3" href="http://mediatomb.cc/" target="_blank">music on the PS3</a>, or looking at files shared through <a title="Windows networking" href="http://www.samba.org" target="_blank">Windows networking</a> or Apache, or even just acquiring a network address through <a title="DHCP" href="http://www.thekelleys.org.uk/dnsmasq/doc.html" target="_blank">DHCP</a>. The common thread in all these cases is that I&#8217;ll notice abrupt failure, but I&#8217;m not directly logged in to see notifications or status messages.</p>
<p>One traditional solution has always been e-mail. I send myself nightly notifications of backup success, mostly because it gives me a warm fuzzy feeling to know that my <a title="Subversion" href="http://subversion.tigris.org" target="_blank">Subversion</a> repository is safely in at least two places (and on a recent trip, I found it a surprisingly reassuring touch of home), but fundamentally I&#8217;m not prepared to page through long logs or status reports on my phone (where I read most of my e-mail). In fact, I&#8217;m not prepared to do that even on my desktop or netbook, unless I already know there&#8217;s a problem (and remember, theonly readily visible symptoms of <em>problem </em>are &#8220;slow&#8221; or &#8220;failed to connect&#8221;).</p>
<p>So to summarize, I&#8217;ve got an uninvolved admin staff (myself), who wants things to Just  Work, and doesn&#8217;t want to have to explain to his wife that the internet is down right now because he was  in the middle of a project when he got bored with it. Fortunately, I&#8217;ve got Debian-stable as a pretty damn rock solid baseline to build from, so most problems will be the result of misconfiguration, user error, or mechanical failure. (The last is also a challenge, since the box is out in the hallway with the cats&#8217; litter box — not a lot of foot traffic to notice things like fan failure or hard drive Squeaks of Doom.) Oh, and because I don&#8217;t do Linux server admin for a day job, I&#8217;m not necessarily going to be able to distinguish between dire-sounding-but-routine conditions and actual symptoms, since I lack a good intuitive baseline.</p>
<p>Anyway, enough exploration of the problem space. (Well, never enough, but at some point requirements analysis turns into plain old griping.) I actually have a solution that&#8217;s working pretty well for me so far, and is probably the biggest difference between this box and previous Windows servers I&#8217;ve set up.</p>
<h2><span id="more-47"></span>Dashboard Health Charts</h2>
<p>At the beginning of the post, I showed the charts I see when I turn on my computer in the morning to check weather and news; I&#8217;ll repeat them here. These are abbreviated versions of the full dataset, just enough to give me a quick picture of anything that&#8217;s going drastically wrong.<br />
<img class="size-full" src="http://exerciseforthereader.files.wordpress.com/2009/06/freespace-28-hours.png?w=397&#038;h=165" border="0" alt="" width="397" height="165" align="center" /><br />
<img class="size-full" src="http://exerciseforthereader.files.wordpress.com/2009/06/cpu-28-hours.png?w=397&#038;h=165" border="0" alt="" width="397" height="165" align="center" /><br />
<img class="size-full" src="http://exerciseforthereader.files.wordpress.com/2009/06/memory-28-hours.png?w=397&#038;h=165" border="0" alt="" width="397" height="165" align="center" /><br />
<img class="size-full" src="http://exerciseforthereader.files.wordpress.com/2009/06/temps-28-hours.png?w=397&#038;h=165" border="0" alt="" width="397" height="165" align="center" /></p>
<p style="text-align:left;">(In real usage, these are a 2&#215;2 grid, but that breaks the margins here.) From the top, we see percentage of free space on various hard drive volumes, CPU utilization, memory usage, and system temperatures, all over the last 28 hours.</p>
<p style="text-align:left;">These particular charts show a pretty boring day. You can see the CPU spike at midnight from cron jobs, and Friday evening when I was actually using the machine. I can&#8217;t remember off-hand the reason for the circa 6 am spike, but it&#8217;s not unexpected. Temperatures are drift a little higher than usual, but that&#8217;s echoing the outdoor temps (the lower grey line on that chart).</p>
<p style="text-align:left;">Some technically inclined readers may be thinking that 10% utilization is awfully high for an idle box; what&#8217;s not shown on this chart is that the CPU freq is governing itself down to 300 MHz when it&#8217;s idle. Sometime I need to get some empirical evidence on whether this is a better trade (for power saving) than keeping the freq up and having the box strictly idle more often. A better chart would probably multiple the utilization percentage by the CPU frequency scaling; maybe I&#8217;ll try that one of these days, but I suspect that the current setup has much the same effect as a logarithmic chart — pulling the &#8220;10% at 300 MHz&#8221; and &#8220;100% at 2.4 GHz&#8221; samples closer to the middle, which makes for finer relative detail, even as it destroys absolute comparability.</p>
<h2 style="text-align:left;">Anomalies</h2>
<p style="text-align:left;">In summary, in the time it takes me to decide if I&#8217;m checking weather or CNN, I&#8217;ve already got a quick gut sense that Calliope is basically healthy and happy. For comparison, here&#8217;s a (somewhat simulated) chart of what I saw at on 6/8, or rather what I would have seen if I hadn&#8217;t been just back from a trip and catching up on my jetlag. Imagine that the bars are the same 5 minute-ish accuracy seen above; I&#8217;ll discuss the progressive degradation later. (Because I&#8217;m working quickly, this is also a full chart with legend, rather than the abbreviated version I see on the daily dashboard.)</p>
<p style="text-align:left;"><img class="aligncenter size-full wp-image-57" title="CPU Utilization - Prolonged Spike" src="http://exerciseforthereader.files.wordpress.com/2009/06/cpu-raid-sync.png?w=450&#038;h=167" alt="CPU Utilization - Prolonged Spike" width="450" height="167" />Anyway, here we see an approximately 4 hour long spike in CPU utilization, at a time when I certainly wasn&#8217;t doing anything interactively. For a cross check, here&#8217;s the temperature chart for the same period:</p>
<p style="text-align:left;">
<div id="attachment_58" class="wp-caption aligncenter" style="width: 460px"><img class="size-full wp-image-58" title="temps-raid-sync" src="http://exerciseforthereader.files.wordpress.com/2009/06/temps-raid-sync.png?w=450&#038;h=220" alt="Temperature Spike" width="450" height="220" /><p class="wp-caption-text">Temperature Spike</p></div>
<p style="text-align:left;">(I&#8217;m somewhat tipping my hand about being able to drill into this information, what with the legends and all, but pretend you&#8217;re just seeing the dashboard version.) We see a significant spike in CPU temperature over the same period, as well as a small rise in overall system temperatures. I&#8217;ll refrain from posting the drive freespace and memory charts, since they didn&#8217;t really show any correlated activity. (Which in itself says something: this probably wasn&#8217;t a massive spam run or anything, since I would expect to see a lot of memory usage if a user process was taking up that kind of CPU time for four hours.)</p>
<p style="text-align:left;">The first time I saw this pattern, I was a little panicked. There was some good news, though:</p>
<ul>
<li>I knew this wasn&#8217;t routine, since I&#8217;d been seeing these charts for weeks and knew what to expect</li>
<li>I had good data on the start and end of the spike, letting me go straight to the right part of the log files</li>
<li>I had some idea of what <em>hadn&#8217;t</em> happened, based on the lack of signal in the disk and memory charts</li>
</ul>
<p>To cut to the chase, it turns out that as configured on Debian, mdraid (the Linux RAID subsystem) does a full resynch of all RAID-ed drives on the first Sunday of every month. (Basically, this is reading the data and checksums from the three drives involved and making sure that they actually agree; sort of a sanity check that what&#8217;s ending up on disk is the same data that we&#8217;re sending.) Once I figured that out, I decided that I approved, and now I expect that spike every month. (In fact, I&#8217;d be concerned if it <em>weren&#8217;t</em> there.) Which is exactly the point — having an easily interpreted set of charts in my face every day, along with longitudinal data to provide a baseline, lets me get on with my life with some expectation that the server is doing the same.</p>
<h2>Historical Baseline</h2>
<p>As I say, I see these charts most days, which means I&#8217;m accumulating a baseline behind my eyes. However, Calliope also records longitudinal data for posterity. (As you saw above in the &#8220;RAID spike&#8221; charts, the temporal resolution progressively degrades; as promised, I&#8217;ll eventually talk about this.) The disk space charts are pretty boring over time; they mostly serve as a record of kernel upgrades and significant data transfers (like getting our wedding videos onto the RAID drive). CPU utilization is a little more interesting:</p>
<div id="attachment_59" class="wp-caption aligncenter" style="width: 460px"><img class="size-full wp-image-59" title="cpu-one-month" src="http://exerciseforthereader.files.wordpress.com/2009/06/cpu-one-month.png?w=450&#038;h=167" alt="CPU Utilization - Past Month" width="450" height="167" /><p class="wp-caption-text">CPU Utilization - Past Month</p></div>
<p>The periodic nature of background nightly and weekly tasks is clearly visible, as is the periodicity of my own usage. You&#8217;ll note that peak usage is over the theoretical 200% cap (100% per CPU). This is because the chart is individually taking the max value of the various utilization types in the aggregation time span, then stacking them. It&#8217;s not technically correct, but it serves its purpose. I could plot averages or minima, either overlaid on the same chart or as separate charts, but then I&#8217;d probably have to use lines instead of the pretty bars (which I think help for the quick visual read).</p>
<p>For prettiness (at least if you&#8217;re into that sort of thing), it&#8217;s hard to beat the memory chart. There&#8217;s not much drama here, but that&#8217;s the good news: a long term growth in the red region would indicate a persistent memory leak, and I&#8217;d have to build some system to kill and restart the offended processes (or just reboot periodically).</p>
<p><img class="aligncenter size-full wp-image-60" title="Memory Usage - Past 4 Months" src="http://exerciseforthereader.files.wordpress.com/2009/06/memory-4-months.png?w=450&#038;h=177" alt="Memory Usage - Past 4 Months" width="450" height="177" />Basically what you see in the memory chart is the reboot frequency, when everything resets to zero. Beyond that, the dark green is free-free, while the bright green is disk cache. So mostly you can see how quickly the system ends up reading four gig from disk that the kernel decides is worth caching. That white line down the middle is the result of missing samples; as I recall that&#8217;s when I shut the machine down to move it into the hallway, and incidentally hook it up to an uninterruptible power supply.</p>
<p>For the last of the &#8220;core&#8221; charts, here are two longer-term temperature graphs (past week and past month):</p>
<p><img class="aligncenter size-full wp-image-61" title="Temperatures - 1 week" src="http://exerciseforthereader.files.wordpress.com/2009/06/temps-1-week.png?w=450&#038;h=220" alt="Temperatures - 1 week" width="450" height="220" /><img class="aligncenter size-full wp-image-62" title="Temperatures - 1 month" src="http://exerciseforthereader.files.wordpress.com/2009/06/temps-1-month.png?w=450&#038;h=220" alt="Temperatures - 1 month" width="450" height="220" />There&#8217;s a nice periodicity here. The grey ambient line is really outside temperature (I don&#8217;t remember if it&#8217;s at PIT or Allegheny County Airport), so it&#8217;s not local temp but it&#8217;s a decent proxy for general climate trends. Someday I&#8217;ll get an in-house temperature sensor (probably <a title="1-wire" href="http://www.hobby-boards.com/catalog/main_page.php" target="_blank">1-wire</a>, that stuff sounds pretty neat — I didn&#8217;t even know I <em>had</em> gardening automation needs!), but for the moment this is good enough. I think it would be possible to calculate the thermal &#8220;half-life&#8221; (I don&#8217;t know the formal term; I mean the notionally constant time for the difference between interior and exterior temperatures to be halved) of our house, or at least that hallway, based on the lateral displacement between exterior temps and their reflection in the case-internal temperatures. Maybe someday I&#8217;ll get around to it, and maybe offset the two data streams to align them. (Or get really fancy and strip out the correlation term, leaving normalized case internal temps&#8230; but that&#8217;s probably a bad idea because the <a title="magic smoke" href="http://en.wikipedia.org/wiki/Magic_smoke" target="_blank">magic smoke</a> doesn&#8217;t care about whether it&#8217;s weather-caused or activity-caused.)</p>
<h2>Other Datasets</h2>
<p>So far I&#8217;ve talked a lot about those four charts. There&#8217;s a good reason; I chose them because they should reveal several classes of resource exhaustion problems, and serve as pretty good proxies for overall system activity. In fact, as a friend at work pointed out, the temperature data is probably a pretty good stealth- / spy-ware detection scheme: lots of software will try to hide from system logs, but at some level you can&#8217;t do anything with a compromised box without generating some heat (and it would be peculiarly paranoid piece of software that spent a lot of effort on spoofing the CPU thermo-sensors).</p>
<p>In any event, those are the charts I look at every day, and they tell me a lot. However, they are not the only datasets I&#8217;m gathering. A few examples:</p>
<div id="attachment_63" class="wp-caption aligncenter" style="width: 460px"><img class="size-full wp-image-63" title="dns-1-week" src="http://exerciseforthereader.files.wordpress.com/2009/06/dns-1-week.png?w=450&#038;h=150" alt="DNS Queries and Results - 1 Week" width="450" height="150" /><p class="wp-caption-text">DNS Queries and Results - 1 Week</p></div>
<p>This chart shows DNS (Domain Name Service — mapping names like &#8220;www.cnn.com&#8221; to a numeric address) activity and success or failure. I mostly keep this one around as a monitor not on Calliope itself, but rather on the rest of the network. Many types of malware will at some point have to do some name resolution, and some will result in an absolute flood of DNS queries. Likewise, there&#8217;s a chance that this would detect someone connecting to my wireless network and piggybacking on my internet connection. Right now all looks quiet; you can see pretty clearly that I do most of my computer work in the middle of the evening.</p>
<p>I&#8217;ve also got similar charts for disk and network adapter activity, but they&#8217;re remarkably uninteresting — with at most two users connecting, and very little cache contention, they only register above threshold values if I&#8217;m streaming video or the like. The data gathering tool I use to collect ambient temperature information is hitting weather.com, and incidentally collects wind speed, humidity and barometric pressure; vaguely interesting, but nothing that&#8217;s not already available on the web. At various times I&#8217;ve gathered stats on Apache utilization, but again the load is mostly too low to even show up on the default scales (&#8220;queries per second&#8221; is a little ambitious when you hit a site maybe 50 times a day).</p>
<p>There is one important set of health stats which I record, even though I don&#8217;t look at them too often: the reported motherboard voltages of the various power supply lines. This is a great example of why gathering longitudinal data is so important; honestly, I couldn&#8217;t tell you what level of deviation I&#8217;d expect on the 1.5V line (and when I look at instantaneous stats on my desktop using SpeedFan, all I can say is &#8220;yeah, that&#8217;s kind of near 1.5V&#8230;&#8221;). However, with a baseline from when the computer was known to be working, I can pretty easily spot changes in the trend or disturbing variations. Here are three such charts. First, the latest 28 hour window:</p>
<p><img class="aligncenter size-full wp-image-64" title="Motherboard Voltages - 28 hours" src="http://exerciseforthereader.files.wordpress.com/2009/06/voltages-28-hours.png?w=450&#038;h=230" alt="Motherboard Voltages - 28 hours" width="450" height="230" />To get everything on the same chart, I&#8217;ve roughly normalized the voltages (by subtracting off the nominal voltage). Some of these are so stably off-center that I suspect my correction terms may be wrong (for example, is Vcore really 1.5 volts or is it perhaps supposed to be 1.525V?), but I&#8217;m really just trying to get them all in the same area so I can compare deltas. (Similarly, one could argue that I should be showing percentage deviation rather than absolute, but that would require me to actually make sure what the design-spec voltages really are.)</p>
<p>My primary take-away from this chart is that the jitter is really quite small in absolute terms; the 12V line is noisiest over time (probably partly due to varying fan loads), and even then it&#8217;s only drifting in a range of 0.022V.</p>
<p>To see the correlation with the other data, and see if these values change under load, let&#8217;s examine that same 28 hour interval with the RAID sync that we looked at above:</p>
<div id="attachment_65" class="wp-caption aligncenter" style="width: 460px"><img class="size-full wp-image-65" title="voltages-raid-sync" src="http://exerciseforthereader.files.wordpress.com/2009/06/voltages-raid-sync.png?w=450&#038;h=230" alt="Motherboard Voltages - RAID Sync time period" width="450" height="230" /><p class="wp-caption-text">Motherboard Voltages - RAID Sync time period</p></div>
<p>Wow, that&#8217;s a nice correlation with the temperature and CPU load charts. The 12V line drops most in absolute terms, probably driving the fans, but we can see that everyone took a hit. Not out of spec, I don&#8217;t think, but enough to make me wonder if in the long term I might want a little more power supply now that I&#8217;ve jammed this box full of disk drives.</p>
<p>For the final voltage chart, let&#8217;s look at all data available (four months worth):</p>
<div id="attachment_66" class="wp-caption aligncenter" style="width: 460px"><img class="size-full wp-image-66" title="voltages-4-months" src="http://exerciseforthereader.files.wordpress.com/2009/06/voltages-4-months.png?w=450&#038;h=230" alt="Motherboard Voltages - 4 month period" width="450" height="230" /><p class="wp-caption-text">Motherboard Voltages - 4 month period</p></div>
<p>Okay, there&#8217;s a pretty clear change in the middle of this one. Fortunately, I think I know the reason; recall the Memory Utilization chart for the same period, when I mentioned that I&#8217;d moved the box and also put it on a UPS? By my guess, this is a pretty graphic depiction of the benefits of active voltage regulation rather than running off raw wall power. (I think it also moved to a different circuit, so it&#8217;s possible that this is really showing the benefits of not being on the same circuit as the microwave oven. I guess I could have controlled for that, testing with the UPS on the same circuit first, but we <em>really</em> wanted the server out of the living room.) Again we see the benefits of historical data: I couldn&#8217;t have told you what an acceptable or expected level of jitter was on the +5V line, but I can surely see that it has stabilized a great deal.</p>
<h2>Coming Attractions</h2>
<p>I&#8217;m realizing that this post has gotten a lot longer than I originally thought, so I&#8217;m going to break my promise. I won&#8217;t discuss the implementation of this (although there are some strong hints in the watermarking on the charts); instead I&#8217;ll use that as incentive to post sooner than six months from now. I hope this has been somewhat interesting, and perhaps suggested some ways to get more value out of self-monitoring stats than taking a quick look at SpeedFan and saying &#8220;Yup, that&#8217;s a reported voltage all right!&#8221;</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/exerciseforthereader.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/exerciseforthereader.wordpress.com/47/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/exerciseforthereader.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/exerciseforthereader.wordpress.com/47/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/exerciseforthereader.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/exerciseforthereader.wordpress.com/47/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/exerciseforthereader.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/exerciseforthereader.wordpress.com/47/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/exerciseforthereader.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/exerciseforthereader.wordpress.com/47/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/exerciseforthereader.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/exerciseforthereader.wordpress.com/47/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/exerciseforthereader.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/exerciseforthereader.wordpress.com/47/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=exerciseforthereader.wordpress.com&amp;blog=5637329&amp;post=47&amp;subd=exerciseforthereader&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://exerciseforthereader.wordpress.com/2009/06/20/server-monitoring-with-pretty-pictures/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">Seth</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/06/freespace-28-hours.png" medium="image" />

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/06/cpu-28-hours.png" medium="image" />

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/06/memory-28-hours.png" medium="image" />

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/06/temps-28-hours.png" medium="image" />

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/06/freespace-28-hours.png" medium="image" />

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/06/cpu-28-hours.png" medium="image" />

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/06/memory-28-hours.png" medium="image" />

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/06/temps-28-hours.png" medium="image" />

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/06/cpu-raid-sync.png" medium="image">
			<media:title type="html">CPU Utilization - Prolonged Spike</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/06/temps-raid-sync.png" medium="image">
			<media:title type="html">temps-raid-sync</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/06/cpu-one-month.png" medium="image">
			<media:title type="html">cpu-one-month</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/06/memory-4-months.png" medium="image">
			<media:title type="html">Memory Usage - Past 4 Months</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/06/temps-1-week.png" medium="image">
			<media:title type="html">Temperatures - 1 week</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/06/temps-1-month.png" medium="image">
			<media:title type="html">Temperatures - 1 month</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/06/dns-1-week.png" medium="image">
			<media:title type="html">dns-1-week</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/06/voltages-28-hours.png" medium="image">
			<media:title type="html">Motherboard Voltages - 28 hours</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/06/voltages-raid-sync.png" medium="image">
			<media:title type="html">voltages-raid-sync</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2009/06/voltages-4-months.png" medium="image">
			<media:title type="html">voltages-4-months</media:title>
		</media:content>
	</item>
		<item>
		<title>Vista Sleep Problems</title>
		<link>http://exerciseforthereader.wordpress.com/2008/12/07/vista-sleep-problems/</link>
		<comments>http://exerciseforthereader.wordpress.com/2008/12/07/vista-sleep-problems/#comments</comments>
		<pubDate>Sun, 07 Dec 2008 23:36:54 +0000</pubDate>
		<dc:creator>Seth Porter</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://exerciseforthereader.wordpress.com/?p=42</guid>
		<description><![CDATA[I don&#8217;t think this really counts as a blog without a post about Vista (or XP) sleep and hibernate problems. So, here goes. Several months ago, my Vista box stopped being able to go to sleep. It tries to, everything spins down for a moment, but then it immediately restarts and comes back up in [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=exerciseforthereader.wordpress.com&amp;blog=5637329&amp;post=42&amp;subd=exerciseforthereader&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I don&#8217;t think this really counts as a blog without a post about Vista (or XP) sleep and hibernate problems. So, here goes.<span id="more-42"></span></p>
<p>Several months ago, my Vista box stopped being able to go to sleep. It tries to, everything spins down for a moment, but then it immediately restarts and comes back up in the &#8220;just awakened&#8221; state. I can even hear it happening from another room (when the machine tries to sleep automatically), because the fans go full-on for a moment (under BIOS control) before Windows takes over and they idle back to their normal quiet state. (I&#8217;ve got a new case, the <a href="http://www.antec.com/usa/productDetails.php?lan=us&amp;id=15900">Antec 900</a>, which I love — vastly quieter than my old server tower, which had five 80mm fans and sounded like a jet taking off, all the time — but it&#8217;s pretty loud when that big ol&#8217; fan on top spins up to full speed and the two 120s over the drives max out.)</p>
<p>Anyway, I just ignored it for a long time, since the common solutions from Google didn&#8217;t help, and I couldn&#8217;t figure out what was triggering it. I tried the obvious suspects, like disabling Wake On LAN (though I actually kind of <em>want</em> Wake On LAN, but it was worth a try), but they didn&#8217;t help. Looking through Event Viewer didn&#8217;t give any hint as to why the machine had woken up; as far as I can tell, Vista thinks it&#8217;s doing what I told it to, so isn&#8217;t logging it.</p>
<p>But then a comment on a blog led me to the &#8220;<a href="http://technet.microsoft.com/en-us/library/cc748940.aspx">powercfg</a>&#8221; command line tool. Apparently this was shipped in XP and 2003, but at that point it <a href="http://support.microsoft.com/kb/324347">appears to have only supported power scheme management</a>. However, the Vista version has a <code>-lastwake</code> option, which &#8220;<em>Reports information about the event that woke the computer from the last sleep transition.</em>&#8221;  Exactly the information I was missing! So it turned out that, for some reason, my keyboard (a wireless USB Logitech job) was waking the machine up. Disabling the keyboard&#8217;s ability to wake up the computer (via Device Manager) was sufficient to let it go to sleep and stay there.</p>
<p>This is still a somewhat unfortunate solution, since I would kind of <em>like</em> to be able to wake the computer up without reaching down for the power button, but given the choice I&#8217;ll take being able to sleep at all. I&#8217;m also losing network connectivity on wake, which is a well-known problem with nVidia chipsets. But I&#8217;m going to bask in the newfound sleepiness of my machine for a few days before attacking that one.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/exerciseforthereader.wordpress.com/42/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/exerciseforthereader.wordpress.com/42/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/exerciseforthereader.wordpress.com/42/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/exerciseforthereader.wordpress.com/42/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/exerciseforthereader.wordpress.com/42/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/exerciseforthereader.wordpress.com/42/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/exerciseforthereader.wordpress.com/42/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/exerciseforthereader.wordpress.com/42/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/exerciseforthereader.wordpress.com/42/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/exerciseforthereader.wordpress.com/42/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/exerciseforthereader.wordpress.com/42/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/exerciseforthereader.wordpress.com/42/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/exerciseforthereader.wordpress.com/42/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/exerciseforthereader.wordpress.com/42/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=exerciseforthereader.wordpress.com&amp;blog=5637329&amp;post=42&amp;subd=exerciseforthereader&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://exerciseforthereader.wordpress.com/2008/12/07/vista-sleep-problems/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">Seth</media:title>
		</media:content>
	</item>
		<item>
		<title>Shadow Matrices for Geometry</title>
		<link>http://exerciseforthereader.wordpress.com/2008/12/03/shadow-matrices-for-geometry/</link>
		<comments>http://exerciseforthereader.wordpress.com/2008/12/03/shadow-matrices-for-geometry/#comments</comments>
		<pubDate>Wed, 03 Dec 2008 05:17:11 +0000</pubDate>
		<dc:creator>Seth Porter</dc:creator>
				<category><![CDATA[3D Graphics]]></category>

		<guid isPermaLink="false">http://exerciseforthereader.wordpress.com/?p=31</guid>
		<description><![CDATA[It seems like I&#8217;m about to head into the dark territory of F# &#8220;quotations&#8221;, which apparently let you play compiler without all that tedious parsing. (Sorry for the absurdly shallow interpretation, but I haven&#8217;t played with them much yet.) Anyway, before I get into that, I thought I&#8217;d write up my progress on getting nicely [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=exerciseforthereader.wordpress.com&amp;blog=5637329&amp;post=31&amp;subd=exerciseforthereader&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>It seems like I&#8217;m about to head into the dark territory of F# &#8220;quotations&#8221;, which apparently let you play compiler without all that tedious parsing. (Sorry for the absurdly shallow interpretation, but I haven&#8217;t played with them much yet.) Anyway, before I get into that, I thought I&#8217;d write up my progress on getting nicely rendered space curves.</p>
<h3>Segmented Cylinders</h3>
<p>Last post, I&#8217;d gotten a unit cylinder to render halfway decently, after some compromises (and throwing more triangles at the thing). After that, I had to translate and rotate them where I wanted them. That should have been a trivial step (&#8220;I have a unit vector along the <em>x</em> axis, please map it over here&#8221;), but turned out to be more trouble than it should have been. (I won&#8217;t tell the full story, but here&#8217;s a quick runthrough.) The <a href="http://msdn.microsoft.com/en-us/library/bb975261.aspx" target="_blank">Matrix.CreateWorld</a> method looked very promising indeed, but kept squashing out any <em>z</em> component (for reasons which became clear later; at the time I was passing the z unit vector as my &#8220;up vector&#8221;). After some hunting, and reading far more than I ever wanted to about quaternions, I fell back to a simpler approach: I want to overlay the 0-1 line on the <em>x</em> axis onto some line <em>p0</em> to <em>p1</em>. Clearly, I need to translate by <em>p0</em> and scale by |<em>p1-p0</em>| (that&#8217;s supposed to be the length of the line, if my pseudo-typography isn&#8217;t coming through). In almost all cases, I also need to rotate; from basic vector math, the axis of rotation will be the <a href="http://en.wikipedia.org/wiki/Cross_product">cross product</a> <em>i</em> × (<em>p1-p0</em>) (I can&#8217;t get the little hat over the i, but that&#8217;s the unit vector in the <em>x</em> direction). The amount of the rotation will be the <a href="http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm">angle between the vectors</a>: <em>acos(i • (p1-p0))</em>. (I&#8217;m particularly fond of UK-based sites, since they tend to refer to &#8220;maths&#8221;. Juvenile, I know.) This all works fine except for the case when <em>p0</em> and <em>p1</em> actually lie on the x axis already; in that case, the cross product goes to all zeros, which was what was flattening out my matrices from CreateWorld (at least I think so; I never went back to test the theory). So I ended up with a scale, a conditional rotation, and then a translation. I was sad about the conditional — even though modern shaders can handle conditionals, it still feels like a mark of shame. There&#8217;s probably some way to be clever about this; after all, <strong>any</strong> axis of rotation will do just fine if you&#8217;re rotating zero degrees. But I was in a hurry to get something rendering again, so I gave up for the moment.</p>
<p>Anyway, this was enough to get me from oddly-lit unit cylinders all the way up to this:</p>
<div id="attachment_32" class="wp-caption alignnone" style="width: 373px"><a href="http://exerciseforthereader.files.wordpress.com/2008/12/sandworm.png"><img class="size-full wp-image-32" title="sandworm" src="http://exerciseforthereader.files.wordpress.com/2008/12/sandworm.png?w=363&#038;h=317" alt="Curve as discrete cylinder segments" width="363" height="317" /></a><p class="wp-caption-text">Sandworm: Curve as discrete cylinder segments</p></div>
<p>In this case, I&#8217;m rendering the first Hermite basis function, since I had code lying around to calculate it. With 20 samples, the curve looks quite smooth (all things considered), but it&#8217;s discontinuous, and gets into worse trouble near the ends. (In areas of high curvature, the abruptly changing normals at lines of overlap look distinctly <a href="http://www.xianarmoury.net/gallery/images/ArticulatedLeg02.jpg" target="_blank">articulated</a>, rather than like a smooth curve.) So the next step was to get at least C0 continuity, and try to do something about the normals.</p>
<p><span id="more-31"></span></p>
<h3>Beveled Cylinders</h3>
<p>At this point I was on a roll with matrices. Nothing feels as much like a triumph as finally succeeding at a seemingly trivial task that took you all Thanksgiving afternoon (between moments of wincing at the Lions). I decided I wanted the cylinders to join along the plane which passes through the actual endpoint <em>p_n</em>, and whose normal is the average of the incoming and outgoing vectors, as seen in the following (atrocious) Paint diagram:</p>
<div id="attachment_33" class="wp-caption alignnone" style="width: 266px"><a href="http://exerciseforthereader.files.wordpress.com/2008/12/bad_paint_diagram.png"><img class="size-full wp-image-33" title="bad_paint_diagram" src="http://exerciseforthereader.files.wordpress.com/2008/12/bad_paint_diagram.png?w=256&#038;h=256" alt="The incoming and outgoing position vectors determine the plane" width="256" height="256" /></a><p class="wp-caption-text">The incoming and outgoing position vectors determine the plane</p></div>
<p>The plan is to virtually slice the cylinders along that plane. (Note that the average of the incoming and outgoing position vectors was chosen so that both cylinders would be sliced at the same angle; otherwise the diagonal sections wouldn&#8217;t match up.) This means that approximately half the vertices will be placed farther along the position vector than they were in the sandworm version, and half will fall short of their positions there. This approach preserves the cross-section of the cylinder — at any point, a cut normal to the long axis of the cylinder would show a perfect circle or a segment of one — but potentially allows arbitrary position error at the endpoints. In particular, if two segments meet at a very narrow angle, the outermost points may have to be projected a very long way in space to get to that common plane. (There are alternative strategies, as I consider later on; first I just wanted to get <strong>one</strong> of them to work. Besides, meeting at such a narrow angle is a pretty good indicator of insufficient tessellation in the first place; either it is just a nasty curve, or we&#8217;re sampling too sparsely in an area of high curvature.)</p>
<p>I should stop at this point to note the obvious: I could quite simply guarantee C(0) continuity by emitting multiple cylinder segments as a continuous strip, rather than transforming a single cylinder to a series of locations. I didn&#8217;t want to start with that approach, however, because I wanted to have a good justification for why both segments should share those endpoints, rather than simply force majeure. I also liked being able to play with different matrices for each end of the cylinder, which would have been trickier if they were all passed in a single batch. (Not insurmountably so, but I wanted to focus on the geometry, not on instancing techniques.)</p>
<p>Anyway, I had a clear description of where I wanted the cylinder endpoints to end up. Now the trick was to get them there. The two ends are necessarily independent, since the meeting angles at opposite ends of a segment have nothing naturally in common (although now that I think about it, that would be an interesting tessellation heuristic; even then it would probably be an upper limit, rather than a fixed value). I&#8217;d just been reading about geometry instancing, trying to figure out how I was going to deal with tens of thousands of these cylinders running around, so the natural approach was to pass an array or arrays of shader parameters. The x coordinates of the cylinder vertices are all 0 or 1, so I can use them to index the arrays, and then be freely able to specify as many parameters as I need for each end independently. (I was a little surprised at using a floating point coordinate as an array index, but it works fine, and seems to be the standard approach.)</p>
<p>So now the ends of the cylinders are decoupled. I&#8217;m trying to project the vertices of each end onto a (different) plane, so the natural thing to do is to pass an array of two matrices, one for each end. Matrices are good at projections, after all. Trouble is, the projection that comes to mind would all project the points along the normal to the plane of projection — an orthographic projection operates this way. But I want to project <em>along the cylinder</em> and intersect the plane wherever that happens, rather than taking the shortest path. (Note that projecting along the plane&#8217;s normal would end up distorting the cross section of the former &#8220;cylinder&#8221;; in most cases I think it would turn into an extruded ellipse instead of a circle.) But just as I started trying to work out the math from scratch (and old linear algebra texts), something made me look at the static constructors available on the <a href="http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.matrix.aspx">Matrix</a> class again. Lo and behold, there&#8217;s the CreateShadow method: &#8220;Creates a <a id="ctl00_rs1_mainContentContainer_ctl01" href="http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.matrix.aspx">Matrix</a> that flattens geometry into a specified <a id="ctl00_rs1_mainContentContainer_ctl02" href="http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.plane.aspx">Plane</a> as if casting a shadow from a specified light source.&#8221; Using the long axis of the cylinder as my &#8220;light source&#8221; direction, and the plane described above as the projection plane, this fits the bill perfectly! (There are some follow-on problems, but first pretty pictures from when I was still happy this was working.)</p>
<div id="attachment_35" class="wp-caption alignnone" style="width: 359px"><a href="http://exerciseforthereader.files.wordpress.com/2008/12/smooth_curve_n10.png"><img class="size-full wp-image-35" title="smooth_curve_n10" src="http://exerciseforthereader.files.wordpress.com/2008/12/smooth_curve_n10.png?w=349&#038;h=235" alt="A smoothly-connected curve with 10 samples" width="349" height="235" /></a><p class="wp-caption-text">A smoothly-connected curve with 10 samples</p></div>
<p>This looks pretty good for only 10 samples. In a larger version you can see the specular highlight &#8220;bleed&#8221; a little along the knuckle of the vertex in the bottom right, but this is at least partly due to the abrupt change in the angle per pixel rate, as I talked about in my previous post.</p>
<p>Here is a wireframe version, where you can quite clearly see the endcaps of the cylinders being extended and contracted around the sample points:</p>
<div id="attachment_34" class="wp-caption alignnone" style="width: 376px"><a href="http://exerciseforthereader.files.wordpress.com/2008/12/wireframe_cylinders.png"><img class="size-full wp-image-34" title="wireframe_cylinders" src="http://exerciseforthereader.files.wordpress.com/2008/12/wireframe_cylinders.png?w=366&#038;h=291" alt="Wireframe cylinders, showing effects of projection matrix" width="366" height="291" /></a><p class="wp-caption-text">Wireframe cylinders, showing effects of projection matrix</p></div>
<p>All is not altogether wine and roses, however. There are fundamental problems when the local radius of the curve is tighter than the radius of the cylinder: the &#8220;tube&#8221; starts to overlap itself and develop strange buckles and creases. There also seems to be an additional problem, because I&#8217;m not sure that that by itself would explain all the oddities in this badly-formed sine wave:</p>
<div id="attachment_36" class="wp-caption alignnone" style="width: 354px"><a href="http://exerciseforthereader.files.wordpress.com/2008/12/bad_sine_wave.png"><img class="size-full wp-image-36" title="bad_sine_wave" src="http://exerciseforthereader.files.wordpress.com/2008/12/bad_sine_wave.png?w=344&#038;h=334" alt="Sine wave showing self-intersection, positional error" width="344" height="334" /></a><p class="wp-caption-text">Sine wave showing self-intersection, positional error</p></div>
<p>Sad to say, this test also demonstrates the problems of arbitrary positional error which I mentioned earlier; the massive &#8220;hoods&#8221; at either end don&#8217;t do a great job of reflecting the shape of the curve (and have strangely messed-up normals). I think part of the problem here is that I locked the free ends of each curve (where there&#8217;s only one segment, hence no average plane) to the vertical axis. This looks very pretty on curves like the Hermite function above, and makes for good screenshots of the [0..1] region, but I suspect from this picture that I&#8217;d do better to use the one segment I do have, rather than an arbitrary fixed value.</p>
<h3>An Afterword: Normals</h3>
<p>An issue with this approach is how it handles normals. I intentionally used the average of the as-tessellated position vectors, <em>not</em> the analytical tangent, to choose the plane which is the locus of the endpoints. The goal was to improve quality when the as-sampled and analytical tangents diverge. First, consider a sine wave which is only sampled at the ±1 points. In each case, the analytical tangent is zero. However, we necessarily have to travel vertically to get to the next <em>sampled</em> point. Using the analytical tangent would tend to produce a shearing effect on the cylinder, while the as-sampled approach gives a nicely angled corner. As a second example, consider the same sine wave, but only sampled when it crosses the axis. Every sample is zero, but using the analytical tangent would have the seams slanting back and forth to no particular gain.</p>
<p>The trouble, of course, is that my normals are getting flattened into the same plane as the vertices; this effectively gives me OpenGL-style &#8220;computed normals&#8221; as the average of the adjoining segments. (Note that I&#8217;m not 100% sure <em>where</em> my normals are actually ending up; this description agrees with what they look like, but I&#8217;ve been burned by that before. The point of confusion is what effect I&#8217;m producing by transforming my (non-homogenous) normal vectors by the upper-left 3&#215;3 matrix, after multiplying in the shadow matrix. It sure looks like they&#8217;re getting projected into the plane, but I don&#8217;t want to swear to it.)</p>
<p>To go a step further, I would want to calculate how much the analytical tangent at the point deviates from the as-sampled tangent, and use that correction factor as the basis for an additional rotation of the normals (potentially rotating back out of the shared plane). I have not yet pursued this approach because the whole strategy is assuming the availability of the previous and next point in the tessellation, and I haven&#8217;t yet decided how well that will scale to serious instancing. (I did play with it, passing the un-shadow-matrixed translate/scale/rotate matrix as a third matrix in the array, and got some tidy-looking curves looking like they were made from segments of PVC pipe, but that wasn&#8217;t really the goal.)</p>
<p>However, before I get into trying to solve that puzzle, I want better control over what I&#8217;m doing. I should probably shell out the $99 for nVidia&#8217;s shader debugger, but I&#8217;m much more interested in being able to write my shader code in F#, to evaluate on either the GPU or the host processor. I suspect that this exercise will be a good chance to get back to my functional programming roots, give me a pretty deep understanding of F# mechanics, and also serve as a good introduction to the nuances of shader evaluation.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/exerciseforthereader.wordpress.com/31/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/exerciseforthereader.wordpress.com/31/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/exerciseforthereader.wordpress.com/31/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/exerciseforthereader.wordpress.com/31/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/exerciseforthereader.wordpress.com/31/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/exerciseforthereader.wordpress.com/31/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/exerciseforthereader.wordpress.com/31/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/exerciseforthereader.wordpress.com/31/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/exerciseforthereader.wordpress.com/31/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/exerciseforthereader.wordpress.com/31/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/exerciseforthereader.wordpress.com/31/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/exerciseforthereader.wordpress.com/31/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/exerciseforthereader.wordpress.com/31/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/exerciseforthereader.wordpress.com/31/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=exerciseforthereader.wordpress.com&amp;blog=5637329&amp;post=31&amp;subd=exerciseforthereader&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://exerciseforthereader.wordpress.com/2008/12/03/shadow-matrices-for-geometry/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">Seth</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2008/12/sandworm.png" medium="image">
			<media:title type="html">sandworm</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2008/12/bad_paint_diagram.png" medium="image">
			<media:title type="html">bad_paint_diagram</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2008/12/smooth_curve_n10.png" medium="image">
			<media:title type="html">smooth_curve_n10</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2008/12/wireframe_cylinders.png" medium="image">
			<media:title type="html">wireframe_cylinders</media:title>
		</media:content>

		<media:content url="http://exerciseforthereader.files.wordpress.com/2008/12/bad_sine_wave.png" medium="image">
			<media:title type="html">bad_sine_wave</media:title>
		</media:content>
	</item>
	</channel>
</rss>
