Visual Studio 2010 and .NET 4.0 are almost released, one of the new things that ship with this release is Parallel Programming. Since you can’t buy a machine anymore with just one core it is time that we developers get intimate with concurrent programming. I decided to play around with this a little today, this is not a real technical post, I mostly show you how you can get started and what new tools are available.
Getting to know Parallel Programming with the .NET Framework 4
The best way to learn about new additions to a framework is to look at some code. There are 22 samples for Parallel Programming with the .NET Framework 4 available on the msdn code library. You can download the .NET Framework 4 Parallel Programming samples here: Samples for Parallel Programming with the .NET Framework 4
Here is a screen shot of the Mandelbrot Fractals sample.
If you run the sample on a 2 core machine you will see that the parallel execution is about 60% faster than the sequential one.
After I was done with the Mandelbrot Fractals sample, I decided to open up the ComputePi sample, after all it is Pi day today (2010.3.14)
Here is the code for the different ways of calculating Pi which is part of the ComputePi sample.
Estimates the value of PI using a LINQ-based implementation.
static double SerialLinqPi()
{
double step = 1.0 / (double)num_steps;
return (from i in Enumerable.Range(0, num_steps)
let x = (i + 0.5) * step
select 4.0 / (1.0 + x * x)).Sum() * step;
}
Estimates the value of PI using a PLINQ-based implementation.
static double ParallelLinqPi()
{
double step = 1.0 / (double)num_steps;
return (from i in ParallelEnumerable.Range(0, num_steps)
let x = (i + 0.5) * step
select 4.0 / (1.0 + x * x)).Sum() * step;
}
Estimates the value of PI using a for loop.
static double SerialPi()
{
double sum = 0.0;
double step = 1.0 / (double)num_steps;
for (int i = 0; i < num_steps; i++)
{
double x = (i + 0.5) * step;
sum = sum + 4.0 / (1.0 + x * x);
}
return step * sum;
}
Estimates the value of PI using a Parallel.For.
static double ParallelPi()
{
double sum = 0.0;
double step = 1.0 / (double)num_steps;
object monitor = new object();
Parallel.For(0, num_steps, () => 0.0, (i, state, local) =>
{
double x = (i + 0.5) * step;
return local + 4.0 / (1.0 + x * x);
}, local => { lock (monitor) sum += local; });
return step * sum;
}
Estimates the value of PI using a Parallel.ForEach and a range partitioner.
static double ParallelPartitionerPi()
{
double sum = 0.0;
double step = 1.0 / (double)num_steps;
object monitor = new object();
Parallel.ForEach(Partitioner.Create(0, num_steps), () => 0.0, (range, state, local) =>
{
for (int i = range.Item1; i < range.Item2; i++)
{
double x = (i + 0.5) * step;
local += 4.0 / (1.0 + x * x);
}
return local;
}, local => { lock (monitor) sum += local; });
return step * sum;
}
}
Here are the results when you run the sample. The first column is the time in seconds and the second column has the method name.
03.3369869: SerialLinqPi 02.1516130: ParallelLinqPi 01.0522855: SerialPi 00.6457441: ParallelPi 00.7098180: ParallelPartitionerPi
Again these were from my dual core laptop, you might get a bigger difference if you run it on a quad core box.
Profiling Performance
Visual Studio 2010 ships with a couple of tools that will make your life easier if you do parallel programming. Launch the Performance Wizard from Tools–>Launch Performance Wizard
After that a wizard will launch and you will see a window like the one in the sreenshot below
Pick concurrency and visualize the behaviour of a multithreaded application.
After you are done, start your app and when you close the app, reports will be generated.
If you don’t see the reports then do the following; click on View–>Other Windows–>Performance Explorer.
FYI, You need to run as admin to generate these report and if you are on a 64bit machine then you need to set the platform target to x86 in order to be able to generate these reports. I was greeted with the following message: To enable complete call stacks on x64 platforms, executive paging must be disabled. A reboot is then required. To make this change, click “Yes”, save your work, and then reboot. For more information, see http://go.microsoft.com/fwlink/?LinkId=157265 . After I rebooted everything worked.
There are 3 types of reports that you will see. Here is what the CPU Utilization report looks like.
There is a report for threads
Finally there is also a report for cores
Instead of having 20 images embedded I decided that a video would be more useful. This video is about 1 minute and 52 seconds and it shows you what the tool looks like when I am clicking around in it.
Here is the HD Video version, I would suggest you click on the video and watch in on YouTube in 720P full screen format
Learning more about Concurrency Profiling and Parallel Programming
To finalize this post, here are some links to technical resources that will help you with Concurrency Profiling and Parallel Programming.
The Visual Studio Performance Tools (Profiler) msdn forum
The Parallel Computing, Profiling and Debugging blog
Below is a 10 part blog post series by Reed Copsey, Jr about parallelism in .net
Part 2, Simple Imperative Data Parallelism
Part 3, Imperative Data Parallelism: Early Termination
Part 4, Imperative Data Parallelism: Aggregation
Part 6, Declarative Data Parallelism
Part 7, Some Differences between PLINQ and LINQ to Objects
Part 9, Configuration in PLINQ and TPL
Part 10, Cancellation in PLINQ and the Parallel class
So hopefully this post will spark your interest and you will take a look at these interesting technologies and tools.
Happy π day ,and today is also Albert Einstein’s birthday.