Thursday, May 7, 2009

X-25M update

Coming up on a month of living with the X-25M SSD... Right after my original post, Intel released a firmware update to address the slowdown issues. I, of course, applied it immediately, with no issues.

A month later, things are still going great. The one nasty side effect is that this drive has RUINED me for working on anyone else's computer (including my home PC). Everything else just feels like molasses when compared to my work laptop.

I also have to be really careful with SQL Server performance. I was writing a little tool that did some LINQ to SQL stuff recently, and the way it was doing a GroupBy() hid the fact that it was doing hundreds of queries on the DB. Normally, I'd notice such a thing because what should be a lightning fast query would cause the machine to grind for a few seconds. With the SSD though, even the hundreds of queries came back lightning fast. I had to run SQL profiler to see what it was really doing- glad I did, because I was able to tweak the query to run fast on "normal" machines with a single DB query and do the fancy grouping behavior in memory after the fact.

Anyway, I'm still giving this thing two big fat thumbs up!

Fun with LINQ

I had a little problem at work today that smacked of "I bet there's a clever LINQ way to do this without using local variables and side effects". The problem: given a list of whatevers, create a dictionary of whatevers whose key is the original index in the list. Don't ask why- that'd take too long to explain.

After screwing around with a false start (yield return in the key selector lambda of ToDictionary- disallowed by the compiler), I came up with something really gross-looking using Aggregate. Then I posed the problem to a couple of coworkers. Here's what we all came up with. Which one do you think runs the fastest? The answer may surprise you.



using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<string> input = new List<string> { "1", "2", "3", "4", "5", "6" };

// #1: Matt's original with local var
var sw1 = Stopwatch.StartNew();

for (int i = 0; i < 4000000; i++)
{
int index = 0;

var dic = input.ToDictionary(k => index++);
}

sw1.Stop();

// #2: Matt's "yikes" version with .Aggregate
var sw2 = Stopwatch.StartNew();

for (int i = 0; i < 4000000; i++)
{
var dic = input.Aggregate(
new { Index = 0, Dictionary = new Dictionary() },
(a, t) => { a.Dictionary.Add(a.Index, t); return new { Index = a.Index + 1, Dictionary = a.Dictionary }; }
);
}

sw2.Stop();

// #3: James' "list ordinal hack" version
var sw3 = Stopwatch.StartNew();

for (int i = 0; i < 4000000; i++)
{
var dic2 =
input.Aggregate(new List<int>(), (lst, elt) => { lst.Add(lst.Count); return lst; })
.ToDictionary(k => k, v => input[v]);
}

sw3.Stop();

// #4: James' "nasty list hack + .Aggregate" version
var sw4 = Stopwatch.StartNew();

for (int i = 0; i < 4000000; i++)
{
var dic =
input.Aggregate(new Dictionary<int, string>(), (d, elt) => { d[d.Count] = elt; return d; });

}

sw4.Stop();

Console.WriteLine("Done. 1:{0}ms, 2:{1}ms, 3:{2}ms, 4:{3}ms", sw1.ElapsedMilliseconds, sw2.ElapsedMilliseconds, sw3.ElapsedMilliseconds, sw4.ElapsedMilliseconds);

Console.ReadKey();

}

}

}