Games of my youth#

My dad is selling the family house, so I just received a bunch of boxes with a bunch of old stuff I hadn't seen in years. One box contained all my old Commodore 64 5.25" disks (unfortunately, the C64 was nowhere to be found). Looking at these disks brought back a lot of memories of a LOT of hours spent playing them.

  • SuperStar Ice Hockey (way ahead of its time, included multi-season franchise mode, with player trades, drafts, training, etc)
  • M.U.L.E.
  • QuantumLink - recently revived, kinda
  • GEOS - made my C64 as slick as my friend's new Macintosh - except that mine had color!
  • Zork III - these used to be available free online, but I think Activision has pulled them, with an eye towards making some bucks off nostalgic geeks.
  • Bard's Tale III - one of the great RPGs, before RPG was watered down to mean "a game that allows you to level-up your character". Not to be confused with the recent PS2/XBOX game that soiled a once good name.
  • Wasteland - the coolest RPG of the day (yeah, Bard's Tale gets points for being first, but Wasteland had style). It was later "unofficially" revived as Fallout 2, which did an admirable job or recreating the fun of the original series.
  • Dragon Wars - an unofficial successor to the Bard's Tale series - it never held my attention the way BT3 and Wasteland did.

Now I need to get one of those parallel cables to hook up a 1541 drive and copy these disk images to VICE.

Saturday, November 19, 2005 8:28:04 PM (Central Standard Time, UTC-06:00) #    Comments [2]  | 

 

Microsoft playing fair, while Google tries to lock in?#

I know its hip to bash on the cool, successful company, so I'm trying my hardest not to let this post come off that way. I was surprised by this behavior, and will try to present the facts.

I'm using Internet Explorer 7 Beta. It includes a search box next to the address bar (just like firefox). It defaults to MSN Search, but surprisingly, it also includes a drop down that lets you change to AOL, Yahoo, Google, or Ask Jeeves. I selected Google once, it worked as expected, but the next time I launched IE, it was set back to MSN Search. Without digging much further, I figured that was just how it had to be... Microsoft was giving space to the others, but still asserting its control.

Today when I browsed to the Google homepage, I got a little DHTML pop-up window that said something to the effect of "hey, you're using IE7, wanna change the default for your searchbox to use Google?" Perfect, I had wanted to do that, and I guess they figured out how. So I press OK.  I restarted IE7, and sure enough, my default search was now Google. Thanks Google.

Except, a funny thing happened when I let Google change my settings. That list of alternate search engines that Microsoft had provided, for the user's benefit, was now replaced by a single choice: Google. Yes, I wanted Google as my default, but I never said I wanted Google as the only choice! That's annoying.

That is when I noticed the Search Settings... menu option at the bottom of the search bar's menu. It includes a Restore Defaults... button, which does exactly that.  I clicked it, and all of my search engines were back (and MSN Search was back to being the default). From that Search Settings screen, I selected Google, and clicked Set Default. Now Google was my default search engine, AND I still had the choice of selecting a different engine from the drop down. That is what I wanted. Why didn't Google give me what I wanted?

Sunday, November 13, 2005 12:34:49 AM (Central Standard Time, UTC-06:00) #    Comments [1]  | 

 

Tips for migrating .TEXT to dasBlog#

A little while ago, I made the move from the .TEXT blogging software to dasBlog. Migrating the actual content was pretty straightforward (as mentioned in the previous post). The problem was that any existing links to my content that existed out in the wild would no longer resolve, since .TEXT used a different URL format for identifying posts. Additionally, the URL for my RSS feed changed, so any aggregators that tried to pull from my site would get an error, and probably eventually drop me.
It turns out that both of these problems were relatively easy to solve. I credit the dasBlog development team for making a flexible platform.

To allow .TEXT permalink posts to resolve, I simply added the following entry to the end of the newtelligence.DasBlog.UrlMapper section of web.config:
<!-- .TEXT archive compatibility -->
<!-- Translates
  FROM: /blog/archive/2004/07/27/194.aspx
  TO: /blog/default.aspx?date=2004-07-27
-->
<add matchExpression =
"(?&lt;basedir&gt;.*?)/archive/(?&lt;year&gt;\d{4})/(?&lt;month&gt;\d{2})/(?&lt;day&gt;\d{2})/(?&lt;postid&gt;\d+)\.aspx"
 mapTo="{basedir}/default.aspx?date={year}-{month}-{day}" />       

Now, an old .TEXT url out in the wild like http://flimflan.com/blog/archive/2004/07/27/194.aspx will correctly resolve to the corresponding post in dasBlog.


To allow the .TEXT feed URL to resolve (Rss.aspx), I changed this existing entry in the UrlMapper section from:
<add matchExpression="(?&lt;basedir&gt;.*?)/rss\.ashx"  mapTo="{basedir}/SyndicationService.asmx/GetRss?" />

to:
<add matchExpression="(?&lt;basedir&gt;.*?)/rss\.as[hp]x" mapTo="{basedir}/SyndicationService.asmx/GetRss?" />

Now if only there was a way to migrate that skin I spent so much time on...
Tuesday, November 08, 2005 9:48:08 PM (Central Standard Time, UTC-06:00) #    Comments [1]  | 

 

Fixing my connection pooling benchmarks#

The numbers in my last post were a little misleading (as you might expect from un-scientific homebrew benchmarks). I showed that ExplicitOpen (2.5 seconds) was slightly faster than ImplicitOpen (2.9 seconds), but both were significantly faster than NoConnectionPooling (7.5 seconds). The whole point of the test was to see how the performance of running 2 queries within a method could vary, based on different approaches. However, in order to get a larger sample size, I ran the methods within a loop for 1000 iterations. It was intended to just give me more test runs, but the loop actually had a side effect. When connection pooling was enabled (for ExplicitOpen and ImplicitOpen), the same connection was used for all 1000 iterations. I had only wanted the same connection to be used for the 2 queries within the methods. So when I turned connection pooling off, the dramatic difference wasn’t because running the 2 queries was much slower – it was because I was now making 2000 connections to the database instead of 1.

If I wanted to compare the performance of running the 2 queries with connection pooling on and off, within a loop, I would need to make sure each iteration of the loop used a new connection in all 3 scenarios (ExplicitOpen, ImplicitOpen, NoConnectionPooling).
An easy way to force a new connection is to change the connection string. I changed the signature of each of the methods to accept an integer argument:

static void ExplicitOpen(int iteration)

I then added an Application Name property to the connection string; altering the application name for each iteration:

"data source=(local);initial catalog=issuevision;integrated security=true;application name=TestCP" + iteration.ToString()

The new results:

ExplicitOpen 9.0
ImplicitOpen 9.5
NoConnectionPooling 7.6

These results show that ExplicitOpen is still faster than ImplicitOpen, but now NoConnectionPooling is much faster than the other 2. How can this be? Well, since none of the scenarios are reusing a connection across iterations, you gain an advantage by removing the connection pooling overhead by explicitly disabling it in the connection string.

The original conclusion was correct (ExplicitOpen is slightly faster than ImplicitOpen), but it is difficult to measure the relative performance with connection pooling turned off. The results of running a single iteration of each method vary too widely to draw any conclusions -- you need the multiple iterations for things to average out. But once you introduce multiple iterations, you blur the effect of connection pooling.

As a bonus, we can now conclude that if you know you are not going to re-use a connection (rare, unless each user of your application is given their own database login), it is better to turn off connection pooling explicitly.

Friday, November 04, 2005 11:12:58 AM (Central Standard Time, UTC-06:00) #    Comments [0]  | 

 

Do you believe in connection pooling?#

David hayden's post about explicitly opening SqlConnection objects when doing multiple SqlDataAdapter.Fill calls didn't sit well with me. The premise is that if you are going to make multiple calls to Fill(), you should open the connection first yourself, to avoid Fill() opening and closing the connection for each call. I'll quote his conclusion:

"...in the case of multiple back-to-back Fill requests to the DataAdapter, it is more performant to explicitly open the connection in the beginning so that each Fill request on the DataAdapter does not open and close the database connection, resulting in the database connection being opened and closed several times."

The reason it doesn't sit well with me, is that I believe in connection pooling. I don't know all of the gory details of how it works under the hood, but I believe it exists. I believe that when I call SqlConnection.Open(), I am not necessarily creating a new network connection to the database - I may just be re-using an existing connection that is sitting idle in the pool.

But he was quoting Sahil's Pro ADO.NET 2.0, and I have no doubt that Sahil knows more about ADO and SQL Server than I do, so I started to doubt my belief.  Maybe connection pooling really DOESN'T exist! Time to get some cold hard facts, (in the form of completely un-scientific homebrew benchmarks).

The test harness:

static void Main(string[] args)
{
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
for (int i = 0; i < 1000; i++)
{
ExplicitOpen();
//ImplicitOpen();
}
sw.Stop();
Console.WriteLine(sw.Elapsed);
}

Very simple. Run one of the methods a thousand times, and report the cumulative elapsed time.  Comment it out, un-comment the other one, and re-run.

The code for the two different methods are almost exactly the same. I only made very minor changes to the code from David's post, to account for the fact that I didn't have the pubs database handy (I used the IssueVision database from the DevDays 2004 sample app).

Here is the code for ExplicitOpen():

static void ExplicitOpen()
{
using (SqlConnection connection = new SqlConnection("data source=(local);initial catalog=issuevision;integrated security=true;"))
{
SqlCommand sqlCat = connection.CreateCommand();
sqlCat.CommandText = "Select * from issues";
SqlCommand sqlProd = connection.CreateCommand();
sqlProd.CommandText = "Select * from staffers";

SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = sqlCat;
DataSet dataset = new DataSet();

connection.Open();
adapter.Fill(dataset, "Issues");
adapter.SelectCommand = sqlProd;
adapter.Fill(dataset, "Staffers");
connection.Close();
}
}

ImplicitOpen() is exactly the same, only the connection.Open() and connection.Close() lines are removed.

Running ExplicitOpen() 1000 times took an average of 2.5 seconds. Running ImplicitOpen() 1000 times took an everage of 2.9 seconds. I ran them both multiple times and the numbers were always consistent, so I think they are somewhat believable.
How about that. Opening the connection explicitly IS a bit faster. So does that mean connection pooling doesn't exist?

I opened the Profiler tool included with SQL Server 2000 and created a connection to my database with the default profiling template. I removed the looping in the main method so that the method would only be called once.  This is what I saw when I ran ExplicitOpen():

Audit Login
SQL:BatchCompleted   Select * from issues
SQL:BatchCompleted   Select * from staffers
Audit Logout

This is what I saw when I ran ImplicitOpen():

Audit Login
SQL:BatchCompleted   Select * from issues
RPC:Completed        exec sp_reset_connection
SQL:BatchCompleted   Select * from staffers
Audit Logout

Aha! As you can see, there is still only 1 connection being made (a single Audit Login and Audit Logout). So it looks like we're both right. There is always 1 connection, but explictly opening is still slightly faster. The difference is the call to sp_reset_connection (which is undocumented in Books Online) which cleans up the connection so it can be re-used.

So, if I could get rid of that call to sp_reset_connection, could I get the same performance as ExplicitOpen()? I copied ImplicitOpen() to a new method and named it ImplicitOpenNoReset(). The only change I made was appending "connection reset=false;" to the end of the connection string. Running 1000 iterations took 2.6 seconds. Much closer to ExplicitOpen(), but there is still a bit of overhead. (Warning: I have no idea how safe or advisable it is to disable the connection reset - do not interpret this as a recommendation for improving your connection pooling performance for general usage - it was just for the purposes of this test.)

Finally, to prove to myself that connection pooling really does exist, and really does help, I created a new copy of ImplicitOpen() named NoConnectionPooling(). The only difference is the connection string includes "pooling=false;". Running 1000 iterations took... 7.5 seconds! Ouch.

My take away is that connection pooling really exists, it really does help you, and in general, you do not have to worry about maximing the use of an open SqlConnection object by keeping it around for multiple queries. But if you have to squeeze out the absolute best performance possible, you will get a slight gain by calling Open() once when you have consecutive queries. Thanks to David for a thought-provoking post.

Update: I discovered a flaw in my benchmarking approach which skewed some of these results. I wrote up the details in a new post.

Thursday, November 03, 2005 11:17:56 PM (Central Standard Time, UTC-06:00) #    Comments [3]  | 

 

All content © 2008, Joshua Flanagan
About this site
Send mail to the author(s) Contact me
Feed your aggregator (RSS 2.0)
Joshua Flanagan
I have been developing software professionally for 10 years; focusing on .NET since its release. I use this site to interact with, and contribute to, the .NET software development community.
Microsoft Certified Application Developer

On this page
Archives
Rest of the world

Acknowledgements

Powered by: newtelligence dasBlog 1.9.7170.677

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Site theme based on the essence design by Jelle Druyts