Monday, March 30, 2009

Visual Studio 2008 Product Comparison

The Visual Studio product page appears to have no comparison chart that spans all product editions. This is quite an omission for a product line that costs anywhere from $0 (for the Express editions) to $10939 (for Team Suite with an MSDN subscription). A range I would also describe as going from "outrageously amazing" to "poking developers in the eyes with toothpicks". If you dig around for a while, there is at least a price comparison chart on the site. However, you have to venture further afield for a clear feature comparison chart on the general Microsoft download site.

One price step that interests me is between Professional and Team System Developer. These are likely to be the two editions most commonly compared by price conscious code shops. If you use Team Foundation Server, you will need to add a Client Access License to Professional, which takes the total to $800 + $500 = $1300. Feature wise Developer edition gives you:

  • Code Profiling
  • Code Analysis (including check-in policies and spell checking)
  • Code Coverage

With Developer you are also required to buy MSDN Premium, so the total cost is $5469. Professional + CAL + MSDN Premium is $2500. So you have to ask yourself if MSDN Premium is worth it, and if the extra Developer features are then worth doubling your investment.

Tuesday, March 24, 2009

101 LINQ Samples

(via MSDN)

Saturday, March 21, 2009

Virtual Earth Silverlight Map Control CTP

The long anticipated Silverlight control for Virtual Earth took a step closer yesterday with the release of a very mature CTP. The experience is nearly identical to the old HTML map (which they call the AJAX map), but with the smoothness of Silverlight's DeepZoom. They also have an interactive SDK, just like the old one, with clear migration hints.

The really exciting thing about it is the fact that you can render any aribtrary Silverlight XAML on top of the map. This opens up Google Earth quality content in a browser, which raises the stakes yet again in the GIS war. Add this to the location awareness zeitgeist and we have some interesting times ahead.

I'm still confused about how they plan to maintain both the Silverlight and VE3D platforms. Is the goal ultimately a single platform? Given that one is based on managed DirectX and one is based on the Silverlight XAML subset (which doesn't do 3D), I can see no technical middle ground. Perhaps they will harmonize the SDK's to make it easy to write for both, but not knowing which to bet on makes me uncomfortable.

Interactive SDK (you probably need to register with Microsoft Connect)

Chris Pendleton @ MIX with the nerds wot wrote it. Some nice examples of the free-form XAML layering.

BSG Corner Clipper

To celebrate the end of BSG this weekend, and to learn how ASP.NET services work, I have written a web service that will clip off the corners of your images (JPEG or PNG) in a BSG stylie. Behold:



I've added the source code below in case you are interested. It was written very quickly, so don't expect production quality, but it illustrates how easy these services are to write:

<%@ WebHandler Language="C#" Class="Handler" %>

using System;
using System.Web;
using System.Net;
using System.Drawing;
using System.Drawing.Imaging;

public class Handler : IHttpHandler
{
ImageFormat ParseImageExtension(string src)
{
string ext = src.Substring(src.LastIndexOf('.') + 1);
if (ext == "gif")
{
return ImageFormat.Gif;
}
else if (ext == "png")
{
return ImageFormat.Png;
}
else if (ext == "jpg")
{
return ImageFormat.Jpeg;
}
else if (ext == "jpeg")
{
return ImageFormat.Jpeg;
}
return null;
}

string ImageFormat2ContentType(ImageFormat imageFormat)
{
return "image/" + imageFormat.ToString();
}

public void ProcessRequest (HttpContext context)
{
// Get the src parameter
var src = context.Request.Params["src"];

// Get the corner color (optional)
var color = context.Request.Params["color"];
if (color == null)
{
color = "White";
}
// Get the size of the corner
var corner = context.Request.Params["corner"];
int cornerSize = -1;
if (corner != null)
{
Int32.TryParse(corner, out cornerSize);
}
if (cornerSize < 1)
{
cornerSize = 20;
}

if (src != null)
{
// Extract the image type
var imageFormat = ParseImageExtension(src);
if(imageFormat != null)
{
// Request the source image
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(src);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
try
{
// Make a bitmap from the source image
using(var bitmap = Bitmap.FromStream(response.GetResponseStream()))
using(var b = new SolidBrush(Color.FromName(color)))
{
ClipCorners(bitmap, b, cornerSize);
System.IO.MemoryStream buffer = new System.IO.MemoryStream();
bitmap.Save(buffer, imageFormat);
context.Response.ContentType = ImageFormat2ContentType(imageFormat);
context.Response.BinaryWrite(buffer.ToArray());
context.Response.End();
}
}
finally
{
response.Close();
}
}
}
}

void ClipCorners(Image image, Brush b, int r)
{
using (var g = Graphics.FromImage(image))
{
g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
int w = image.Width;
int h = image.Height;
if (r >= w)
{
r = w / 10;
}
if (r >= h)
{
r = h / 10;
}
if (r > 0)
{
g.FillPolygon(b, new Point[]
{
new Point(0, 0),
new Point(0, r),
new Point(r, 0)
});
g.FillPolygon(b, new Point[]
{
new Point(w, 0),
new Point(w - r, 0),
new Point(w, r)
});
g.FillPolygon(b, new Point[]
{
new Point(0, h),
new Point(0, h - r),
new Point(r, h)
});
g.FillPolygon(b, new Point[]
{
new Point(w, h),
new Point(w, h - r),
new Point(w - r, h)
});
}
}
}

public bool IsReusable {
get {
return false;
}
}

}

Saturday, March 14, 2009

Little Twit

I've finally got around to sorting out my Little Twit site. It now has its own URL and a proper background service that does the scanning (long lived threads in ASP.NET are frowned upon, so it needed to be a Windows service, technical-blah-blah-blah, etc...)

Little Twit lists all the available Twitter names of 1, 2, 3, and 4 letters in length (all the 4's is still scanning at the moment). The list is dynamic, so it either shows you what it has so far or the last complete scan, if it has made one. It is designed to help people looking for short Twitter names (just in case that wasn't obvious).

The service uses the Twitter REST API, but I notice that some supposedly taken names have no corresponding user page. They are in some sort of deactivation limbo I guess.

One interesting thing I noticed was that the number of two-letter names was about 44 when I started (about a month ago), and now it is down to 16 (0j 0q 0y 3o 4y 5j 5v 6l 6o 6y 7p 7y 8h 8k 8w 8y). If I could be bothered I would record and chart the trends, but I'm not sure it would tell you anything more than I have too much time on my hands.

Its just for fun, but suggestions are welcome.

Tuesday, March 10, 2009

JIT Optimization and Inconsistent Results

FPU Discrepancies


Everyone who has spent time at the coal-face of numerical programming knows that floating point numbers are the devils plaything. Add up any list of floats one way then another way and you will get a different answer. Even when you think you are doing a calculation one way, it may come out another. Common causes include:

  1. Optimization. The most common difference is between debug and release builds, where the compiler has reordered operations for pipeline efficiency.

  2. Parallelism. When computing hetrogenous tasks, it is typical to keep a TODO list and give out jobs to threads as they become free. This inevitably means that jobs will be done in slightly different orders, and if the result is accumulated in any way, the answer will vary.

  3. Co-processors. Modern CPUs have exotic built in commands (i.e. dedicated silicon) for numeric processing, such as SSE and 3DNow!. It is possible for the compiler to use these pipelines for one formulation of an algorithm, but not for another, resulting in different answers. Typically these instructions are disabled in debug mode but not in release mode (see 1).


So which answer is right? All of them and none of them. At least no answer is any better than any other, and anyway the inputs were already approximations before you even started. The alternative to this single-point approach is interval arithmetic, and every time I have these problems I hear Bill Walster laughing at me.

We Are All Doomed!


Once you are comfortable that you understand the source and magnitude of the differences, you apply a suitable tolerance to any comparison of the answer and off you go.

You weren't trying to compare the floats directly were you? [whacks back of hand with ruler]

The Complier Strikes Back


I recently discovered a new mode where this problem can occur: JIT optimization. Coming from a C++ background I am used to the compiler doing more-or-less what I tell it to, and the compiled code staying the same from machine to machine. JIT compilation means that is no longer the case: the same IL will end up as different machine code on different machines and on the same machine under different circumstances (more on that later).

To fight back against non-determinism, we write unit tests that check the answers, and to do that we use exact comparison (I'm sorry I hit you on the hand with the ruler - comparison is fine for unit tests). The problem is that if the tolerance is too great, it might let in some of the other issues we discussed, principally parallel non-determinism. If a client of mine runs the same calculation, they expect the same answer. This problem can be magnified if the answers are used to inform optimization strategies that could take a design down significantly different paths. The Age of Empires team had similar issues when synchronizing simulations for multiple users.

The Problem


We have some simple trigonometric code that looks very straightforward:

double a4 = square(sin(dlon / 2));

The code was in C++/CLI (although this problem will equally manifest in C#). Function square() does what it says on the tin, and in all cases was inlined by the compiler.

When we fed in 0.0000189590943040496 we go two different answers depending on if the debugger was attached or detached:

0.0000000000898618142047701 (attached)
0.0000000000898618142047700 (detached)

Looking at the binary representation of these numbers we saw a single bit difference in the mantissa.

As an interesting aside, there were other instances that were different, but Double.ToString() converted to the same string (even with F30 as the conversion string for maximum representation). For instance, 40BFA439A6E6D034 and 40BFA439A6E6D033 (doubles in binary form) both come out as 8100.225202966530000000. Beware!

What could be different about having the IDE attached? Note that this was the same build with the same IL (this isn't some n00b debug vs. release issue).

The Joker In The (JIT) Pack (see what I did there?)


It turns out that when you load a CLR DLL, the JIT goes to work optimizing the code for performance, unless the IDE is attached (no inlining, no reordering, no MMX, etc...). This is so that the user can step through the code in a useful way, which even for non-optimized IL is a pretty amazing trick.

To get under the skin of the problem I needed to see the native code that was being executed in both scenarios. I added a breakpoint on the offending line and launched a debug session from the IDE. Ctrl + Alt + D brings up the annotated assembly code, which looked like this:

...
double a4 = square(sin(dlon/2));
00000443 fld qword ptr [ebp-20h]
00000449 fmul dword ptr ds:[08E239D0h]
0000044f fsin
00000451 fstp qword ptr [ebp+FFFFFF24h]
00000457 fld qword ptr [ebp+FFFFFF24h]
0000045d fstp qword ptr [ebp-40h]
...
00000482 fld qword ptr [ebp-40h]
00000485 fmul st,st(0)
...

[ebp-20h] contains dlon, and the answer ends up on in the FPU accumulator (ST0). The sequence of events is Load dlon, Multiply dlon by 0.5, Sin the result, Store the result, ..., Retrieve the result, Square the result. Critically the answer is stored in memory before being squared - this is relevant.

Now the optimized JIT. This was harder to get hold of and required changing a couple of IDE settings:



One setting stops the IDE supressing JIT optimization and the other stops the IDE complaining when it finds optimized code (it confuses it with 3rd party code).

This gave the following assembly code:


double a4 = square(sin(dlon/2));
00000183 fxch st(2)
...
00000188 fmul dword ptr ds:[086CB6C8h]
0000018e fsin
00000190 fxch st(1)
...
00000199 fmulp st(1),st

Critically this version of the calculation keeps the intermediate results on the FPU stack rather than dumping them into memory. Why is this significant? Because they are 80 bits wide, whereas the memory locations are 64 bits wide. The extended precision bits remain intact, and overflow into the LSB of the 64 bit mantissa causing our bit-flip.

Now What?


I am now comfortable that I understand the source of the problem, and that I know what an appropriate tolerance would be for comparison. It only has to catch LSB changes, so it can be very, very small. This will prevent other non-determinism problems sneaking past, that typically cause differences that are orders of magnitude greater.

Credits


I couldn't have found this without the timely assistance of Greg Young, who's posts (1 and 2) on the subject steered me to a resolution.

Friday, March 06, 2009

The First Horseman of Google's Apocalypse

TIP JAR is an incredibly lame demonstration of Google's Moderator platform.

Exhibits A through D:


"Pay your bills online to save on postage."

"Don’t grocery shop on an empty stomach or you may end up buying more than you need."

"Use old newspapers instead of paper towels with an eco-friendly cleaning product to wipe glass surfaces."

"Protip: To save gas, don't drive"


It obviously puts me in mind of Viz's Top Tips:


"A small coniferous tree in the corner of your living room is an excellent place to store Christmas decorations."

"Why waste money on expensive binoculars? Simply stand closer to the object you wish to observe."

"Hijackers. Avoid a long stressful siege and the risk of arrest, imprisonment or death by simply making sure you book a flight to your intended destination in the first place."

"Old contact lenses make ideal 'portholes' for small model boats."

"Increase the life of your carpets by rolling them up and keeping them in the garage."


Google! Make with the Mojo!

Now I am off to submit spurious advice to TIP JAR.

UPDATE: I've changed my mind. Voting on the "Please vote on this tip..." is the funniest thing I've done all day. If we get enough like-minded people together, this could be become an unlimited well-spring of funny.