Saturday, February 6, 2010

TPL and Parallel.ForEach in .Net 3.5 using Reactive Extensions for .NET (Rx)

The next version of the .Net framework and Visual Studio both have some pretty cool features to help programmers work with multiple cores, which is great but doesn’t help the majority of us that are stuck with .Net 3.5 for the foreseeable future. Luckily Erik Meijer and the Cloud Programability Team have back ported the Parallel Extensions Framework (PFX) to .Net 3.5 and Silverlight 3 as part of the Reactive Extensions for .NET (Rx). Rx adds the IObservable<T> and IObserver<T> interfaces, which are the mathematical duality of the IEnumerable<T> and IEnumerator<T> and provide tools for doing Reactive Programming. There are many different ways to use Rx, but internally they all use the Task Parallel Library (TPL) as the “special sauce” to automate processing tasks across multiple threads.

Parallel.ForEach is a part of the TPL that can be used to unroll an outer loop and have it run across multiple threads. Take the following example. This is standard single threaded code that loops through a collection of 2 card Texas Holdem starting hands and evaluates all possible 7 card hands that include those two cards:

There are over 2 million hands in the inner loop, which gets run once for each of the possible starting hands in the outer loop. There are 12 offsuit starting hands and 4 suited starting hands with an Ace and a King, which means that the outer loop would run 16 times, however those 16 executions are separate and could easily be run across multiple threads. That is where Parallel.ForEach comes in. Here is the same code, which will automatically be scheduled across multiple threads:

The bulk of the code is the same, with the only changes being that the inner block gets converted into a Lambda Expression (could have also used a delegate) and instead of incrementing lCount in the inner loop we increment a local loop variable and then atomically add it to the global value. We could have used System.Threading.Interlocked.Increment to atomically increment lCount inside the inner loop, but this adds a lot of unneeded locks that slow down all the threads. Keeping a local copy of the values and only locking once at the end provides much better performance.

And with those few small changes we are able to start using multiple threads, which on my local machine with 4 cores and 8 threads ended up decreasing the processing time from 1.55 seconds to 0.67 seconds and more than doubling the number of hands processed per second from 16,420,998 to 37,816,595.

If you want to start using the TPL you can download it here and add a reference to the System.Threading.dll located in the “C:\Program Files (x86)\Microsoft Reactive Extensions\Redist\DesktopV2” folder. And while you are at it you might as well play around with Rx too!

Enjoy!

Wednesday, January 20, 2010

VS2010 Parallel Computing Features Tour: Wow!

Microsoft Visual Studio 2010 and .NET Framework 4.0 are in beta 2 right now and should be available in a few months, but after watching videos about the features of C# 4.0 and the features of Visual Studio 2010 I don’t know how much longer I can wait! I just finished watching a video about the parallel computing features in VS2010 and I seriously am drooling over the multi-core programming tools available in the next release! C# 4.0 was introduced by Anders Hejlsberg at PDC 2008, but it is great to see it finally coming to fruition. And with .NET 4 splitting the download into Client and Full profiles it now can be downloaded and installed on most machines at about half the size (30-40MB vs 70-160MB for .NET 3.5).

Thursday, December 3, 2009

Watin 2.0 and Gallio 3.1 in x64 environment: fixing System.Reflection.ReflectionTypeLoadException and System.Runtime.InteropServices.COMException "The interface is unknown" issues

We use Gallio/MbUnit and Watin at my work for unit testing of an ASP.NET website, as it provides excellent reports including the raw Watin events (click, type, select) and screenshots for failed cases. Today I spent a few hours trying to get the project working on my new Windows 7 x64 development machine, and things did not start out very well. When I first tried to load the project in the Gallio Icarus runner none of the unit tests showed up and it indicated that an exception was thrown while exploring tests. I tried using both the x64 and x86 versions of Gallio/MbUnit, and even tried using the TestDriven.NET loader from within Visual Studio, but couldn’t get anything to work. Here is the full error message for Google’s sake:

[error] An exception was thrown while exploring tests.
Location: D:\SVN_Development\OQA Unit Testing\OQA Testing Framework\OQA Testing Framework\bin\Debug\OQA Testing Framework.EXE
Reference: OQA Testing Framework, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Details: System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information. 
   at System.Reflection.Module._GetTypesInternal(StackCrawlMark& stackMark) 
   at System.Reflection.Assembly.GetTypes() 
   at Gallio.Common.Reflection.Impl.NativeAssemblyWrapper.GetTypes() in c:\RelEng\Projects\MbUnit v3.1\Work\src\Gallio\Gallio\Common\Reflection\Impl\NativeAssemblyWrapper.cs:line 72 
   at Gallio.Framework.Pattern.TestAssemblyPatternAttribute.PopulateChildrenImmediately(IPatternScope assemblyScope, IAssemblyInfo assembly) in c:\RelEng\Projects\MbUnit v3.1\Work\src\Gallio\Gallio\Framework\Pattern\TestAssemblyPatternAttribute.cs:line 147 
   at Gallio.Framework.Pattern.TestAssemblyPatternAttribute.Consume(IPatternScope containingScope, ICodeElementInfo codeElement, Boolean skipChildren) in c:\RelEng\Projects\MbUnit v3.1\Work\src\Gallio\Gallio\Framework\Pattern\TestAssemblyPatternAttribute.cs:line 75 
   at Gallio.Framework.Pattern.DefaultPatternEvaluator.Consume(IPatternScope containingScope, ICodeElementInfo codeElement, Boolean skipChildren, IPattern defaultPrimaryPattern) in c:\RelEng\Projects\MbUnit v3.1\Work\src\Gallio\Gallio\Framework\Pattern\DefaultPatternEvaluator.cs:line 153

The error message indicates that it is due to an issue with missing assemblies, and suggested that you make sure the CopyLocal option is set to true for all 3rd party references, but that didn’t help either. Finally I created a test project and started ripping the original project to peaces to find out why it was failing. Turns out it worked fine if I remove a reference to an interface stored in the Watin.Core.Dll assembly, so I setup a workaround and was finally able to load the tests. Only problem was that it would fail whenever the test tried to load Watin. At this point I figured it had to be an issue with the Watin dll, and it turns out that it was simply trying to load an x64 version of the library that doesn’t actually exist (the library is x86 only). This link suggested setting Visual Studio to use x86 as the build platform type instead of “Any CPU”, and once I did that the original project started working. Yay!

It didn’t take long though for something else to fail, as it threw an exception as soon as one of the tests tried to access the Document object. This time the exception was System.Runtime.InteropServices.COMException with Message="The interface is unknown. (Exception from HRESULT: 0x800706B5)" coming from mshtml.HTMLDocumentClass.IHTMLDocument2_get_url(). Another quick search lead to another StackOverflow answer suggesting to run Visual Studio as an Administrator. That seem to do the trick!

So if you are using an x64 machine to do unit testing with Gallio, MbUnit, and Watin, make sure to set the platform to x86 and make sure to run Visual Studio and Icarus as an Administrator! I should probably get back to working on those unit tests now :-P

Enjoy!

Tuesday, November 10, 2009

Channel 9 Full Screen Video Player: My first Bookmarklet

I really enjoy watching videos from Channel 9, Microsoft’s community site that targets users and developers. It is a great way to keep updated on the latest technologies and learn more about future products before they come out. The only thing that I don’t like is that the website is not very user friendly for people that have multiple monitors. This surprises me, as most developers that I know use at least two monitors, sometimes three or four. Even after their recent layout change, which increased the size of the video player significantly, the embedded video player is still too small to be able to read code from screencasts. There is of course a full screen button, but this doesn’t really work when multitasking on multiple monitors as it will close as soon as you click on another browser or window on another screen. Both Silverlight and Flash have this issue, which they consider to be a security feature, but it renders the full screen mode worthless useless you stop using your second monitor while watching the video.

Currently there are only two workarounds to the Silverlight/Flash full screen issue, both of which YouTube has already implemented using buttons at the top of the video player. The first is enlarging the video so that it takes up more of the page, and the second is opening it in a new page that can be resized to as large or small as you want. Alternatively you can use a different video player such as the embedded Windows Media Player, but while the WMV links on Channel 9 display full screen in the browser they sometimes have buffering or quality issues and cannot take advantage of the Smooth Streaming that the Silverlight player can offer. All I really wanted was a way to enlarge the video to fit the full width of the browser window, so I figured why not just write a script to do it?

Bookmarklets are essentially small snippets of javascript code that live in a browser’s favorites and do simple things like opening a Wikipedia box for searching, Subscribe/Share/Note the current webpage in Google Reader, using Google SideWiki, or adding any item to an Amazon Wishlist. Due to cross-site scripting restrictions implemented in most browsers they are relatively safe, so they shouldn’t be able to drain your bank account or spam all your friends on Facebook. Plus unlike Greasemonkey scripts they will only run when you click on the link in your favorites, so they won’t slow down or change your normal browsing habits. This seems like a perfect fit for resizing the Silverlight video player on Channel 9.

So after dissecting the way that the Google bookmarklets worked I started coding my own. If you want to try it out you can simply drag this link to your favorites (or right click and select "Add to Favorites"): C9FullScreen and then click on the new link that it created after browsing to your favorite Channel 9 video. To see how it works, here is the code that gets embedded into the C9FullScreen link:

And here is the script that gets injected into the page to resize the video:

And here is the result: A full screen video... Enjoy!

Sunday, November 8, 2009

Short .Net Reflector Training Video from Pluralsight

Today’s Simple-Talk newsletter had a video from http://www.pluralsight.com that talked about the basic features of Red Gate’s .NET Reflector. If you are not familiar with the .NET Reflector, I highly recommend you give it a try, as it is by far one of the best .NET tools available. This short 14 minute video walks you through most of the features of the program and shows you why it can be so useful. I’ve used .NET Reflector for system testing or when a library’s documentation is incomplete or out of date. The video doesn’t cover the Analyze feature for finding all class references and dependencies, and it doesn’t talk about all the cool plug-ins you can add, but it does provide a great introduction to a very powerful tool! 

Sunday, November 1, 2009

Texas Holdem Hand Equity Calculation in IronPython

This year I have been working in my free time to create easy to use Texas Holdem poker spreadsheets based on IronPython using Resolver One. These spreadsheets can be used to calculate Win/Tie/Loss odds, but some people like to use hand equity instead since it represents a player’s overall stake in the pot. Equity of 1.0 or 100% means that they will win the entire pot, where as equity of 0.5 (50%) or 0.25 (25%) means that they will split the pot with other players. You can again use Monte Carlo analysis to run a number of trials before all of the board cards are dealt to estimate a player’s current equity in the hand. This means that if during 4 trials I would win 2 of them and split the pot with one other player on the other 2, then my equity would be (1.0+1.0+0.5+0.5)/4 =  3/4 or 75%.

Calculating Win/Tie/Loss statistics on an independent player vs player basis is very simple, as the player’s pocket cards are evaluated against each opponent one at a time to show which opponent hands are stronger or weaker than your own. This does not take into account how the pocket cards of other opponents might change the odds, since in reality you usually play verse a table of opponents not just one opponent at a time. Changing the spreadsheet to work against the whole table would require changing the Monte Carlo simulation from a “row by row” analysis to a “table by table” analysis, where by you setup a table of opponents using a random hand for each player given the information that you have about their hand (AK, KK or QQ, Group1, etc..) and then generate a random 5 card hand based on the currently dealt cards.

There are a lot of issues that you have to watch out for in this type of Multiway Isometric Ranged Equity Calculation, but the basics are simple so long as you have a method of comparing multiple player’s hands for a given board. The C# poker library that I use is mainly focused on heads-up hands, but it only took me about an hour to whip up a method that would take a board setup and a list of player pocket hands and return the scored value and equity for each hand as well as the highest ranked hand and a list of the winners. Here’s the code:

Here is a sample print-out when bPrintResults is True:

testBoard = ((288<< (13 * 3)) + (7<< (13 * 2))) #0b100100000000000000011100000000000000000000000000 is Ts 7s 4h 3h 2h
testHands = [3, 3 << 13, 3 << (13*2), int('1100',2)] #Hands: 3c 2c, 3d 2d, 3h 2h, and 4c 5c
(lstintScores, lstfEquity, intHighScore, lstHighScorers) = HandEquity(testBoard, testHands, True)

Start HandEquity with 4 hands and board cards: Ts 7s 4h 3h 2h
Best hand is 'Two pair, Three's and Two's with a Ten for a kicker' with 2 winner(s) getting 0.50 equity in the hand.
000: Hand 3c 2c HandScore=033622016 Equity=0.50
001: Hand 3d 2d HandScore=033622016 Equity=0.50
002: Hand 3h 2h HandScore=None        Equity=None
003: Hand 5c 4c HandScore=016942384 Equity=0.00

This is just a first step towards a full table Monte Carlo Simulator, but it gives you all of the details that are needed to find the winner(s) for a hand and calculate hand equity. The code used to generate a random board would be the same as in the other poker spreadsheets, but the player hand selection logic would need to use some sort of Round Robin algorithm to make sure that each player gets equal access to all of their possible pocket cards. Then you would use the HandEquity method to calculate the player’s equity for each hand and aggregate the results. My next goal is to change the spreadsheet code to use multiple threads, so I probably won’t tackle multi-way analysis anytime soon.

Thursday, October 1, 2009

Windows 7 Issues with JMicron JMB36X Controller in AHCI mode

I had a lot of issues when setting up a RAID controller when installing Windows 7 a few months ago, and today I had more problems trying to get an IDE drive to work in the same machine. The ASUS P6T motherboard has two hard drive controllers: one Intel ICH10R SATA controller for the 6 red SATA ports, and one JMicron controller for the two orange SATA ports and the single IDE connection. When I installed an old IDE hard drive to the JMicron controller, it was recognized in Windows but I was never able to format the drive. It kept saying that the window needed to be refreshed or that I needed to reboot the machine.

After trying a few times with no progress, I decided to check and see if there was any updated drivers on the ASUS website. Turns out there was a recent BIOS update for the JMB322 firmware, so I download it to a jump drive, rebooted the computer and used the EZ Flash 2 utility built into the BIOS to run the update (I love this feature!) After changing the ICH10R settings back to RAID and setting the volume to be the primary hard drive and default boot device I was able to load back into Windows, but now there was another issue: There were two JMicron JMB36X devices listed in the device manager and only one of them was working.

I tried removing both of them, thinking that one was a duplicate, but they both were detected again and one of them always listed “This device cannot start. (Code 10)” as the error message. The BIOS settings had the JMicron controller setup as AHCI mode, but no matter what I tried I could not get it to work. I even tried the latest drivers right from the JMicron website, but still nothing.

Finally I tried changing the JMicron Controller settings from AHCI to IDE, and it started working again. This time I could detect the drive and the formatting worked just fine. Seems like the P6T motherboard still has a few bugs to work out specifically with the SATA and IDE controllers when using Windows 7 64bit edition. If I had to do it again I would probably ditch the hardware RAID array and instead buy an SSD drive for much better performance and a lot less headaches trying to set things up.

Blog.TheG2.Net - Your guide to life in the Internet age.