Additionally, there is a new "About GMinder" window that displays the version of GMinder that you are using, accessible from the system tray.
As always, thank you for your suggestions and feedback!


We know that .NET performs optimizations when accessing rectangular arrays, but for sequential access should the inner loop be on the first or second index? Is there even a difference?
The Code
using System;class Program{static void Main(string[] args)
{ int size = 512; int count = 1000;int[,] array = new int[size, size];
int total = 0;var watch = System.Diagnostics.Stopwatch.StartNew();
for (int i = 0; i < count; i++)
for (int x = 0; x < size; x++)
for (int y = 0; y < size; y++)
total += array[x, y];
watch.Stop();
Console.WriteLine(String.Format("Sequential access by [x,y]: {0}ms", watch.ElapsedMilliseconds));watch = System.Diagnostics.Stopwatch.StartNew();
for (int i = 0; i < count; i++)
for (int x = 0; x < size; x++)
for (int y = 0; y < size; y++)
total += array[y, x];
watch.Stop();
Console.WriteLine(String.Format("Sequential access by [y,x]: {0}ms", watch.ElapsedMilliseconds));Console.WriteLine(total);
Console.Read();
}
}
The Output
Sequential access by [x,y]: 825ms Sequential access by [y,x]: 2414ms 0
What a difference! Incrementing the first index in the inner loop takes almost 3 times longer, probably because there are so many more cache misses.
The Verdict
For best performance, process your rectangular arrays by incrementing the first index in an outer loop, and the second index in an inner loop.
One of my projects is a perfect candidate for concurrency. There is a collection of entities that each need to be processed, and each can be processed independently. For the sake of Separation of Concerns, I developed a WorkManager class dedicated to performing an action on the elements of an enumeration. Before I spill the code, here is how it is used:
Entity[] myCollection = LoadEntities();
WorkManager manager = new WorkManager();manager.ForEach(myCollection, e => e.Process());
Note the lambda expression above. It means that for each Entity in myCollection, the code will execute its Process method. The program will create a separate thread for each processor, and evenly distribute the workload across the threads.
And without further delay, the WorkManager class:
One thing I love about WSUS is the ability to monitor the presence of clients. It gives me a good approximation of the last time a computer was on the network. I often use this information to help me clean missing computers out of Active Directory.
But what about when a computer is removed from the domain before it is removed from WSUS? Rather than manually checking, I wrote an IronPython script that compares the list of computers in Active Directory with the computers on WSUS. When I run this script, it lists computers that should be removed from WSUS, and deletes them for me (after prompting).
In my current programming project, I've embedded IronPython in a C# program. I thought I would share the basics of embedding a scripting engine. I imagine the process would be the same for any language that uses the DLR (Dynamic Language Runtime), like IronRuby. Here is a sample using IronPython 2.0 Beta 5.
using System;using IronPython.Hosting;using Microsoft.Scripting;using Microsoft.Scripting.Hosting;public class Program
{ // Delegate matching the signature of the factorial functiondelegate int FactorialDelegate(int n);
static void Main(string[] args)
{ // Our factorial functionstring[] lines = {"def factorial(n):",
" for i in range(1, n):", " n = n * i", " return n"};string code = String.Join("\r", lines);
// Instantiate the IronPython environmentScriptEngine engine = Python.CreateEngine();
// Create a scope/module to work inScriptScope scope = engine.CreateScope();
// A little preparationScriptSource source = engine.CreateScriptSourceFromString(code, SourceCodeKind.Statements);
// Compile the codeCompiledCode compiled = source.Compile();
// Execute the code in the scopecompiled.Execute(scope);
//Now the factorial function exists in the IronPython environment. Let's use it. // Set x = 5 scope.SetVariable("x", 5); // print factorial(x) ScriptSource print = engine.CreateScriptSourceFromString("print factorial(x)", SourceCodeKind.SingleStatement); print.Execute(scope); //outputs 120 // Get the result from IronPythonint result1 = scope.Execute<int>("factorial(6)");
Console.WriteLine(result1); //outputs 720 // We can also call the function directly from C# FactorialDelegate factorial = scope.GetVariable<FactorialDelegate>("factorial"); int result2 = factorial(7); Console.WriteLine(result2); //outputs 5040Console.Read();
}
}
Today a friend and I were reflecting through System.Math (courtesy of IronPython) and we noticed the BigMul method:
Math.BigMul(Int32, Int32) : Int64
Why have a method just for multiplication? It seems to be a trivial reason to add a method to the .NET framework. After all, multiplication with casting does the same thing:
(long)a * (long)b
Being optimistic, I suggested that perhaps Microsoft's BigMul is implementing a faster and more efficient multiplication algorithm. Maybe there is a clever way to multiply two 32 bit numbers without explicit casting to 64 bit. Naturally, I wrote a simple speed test.
static void Main(string[] args)
{ int a = 40993; int b = 69872; long c = 0;DateTime start;
TimeSpan length;
Console.WriteLine("Inline multiplication");start = DateTime.Now;
for (int i = 0; i < 1000000000; i++)
c = (long)a * (long)b;
length = DateTime.Now - start;
Console.WriteLine(c);
Console.WriteLine(length.ToString());
Console.WriteLine();
Console.WriteLine("Math.BigMul");start = DateTime.Now;
for (int i = 0; i < 1000000000; i++)
c = Math.BigMul(a, b);
length = DateTime.Now - start;
Console.WriteLine(c);
Console.WriteLine(length.ToString());
Console.WriteLine();
Console.Read();
}
The results were not encouraging.


I released a new version (1.2.7) of GMinder today, with the following improvements:
The new Quick Add feature
I recommend installing this new version, especially if a previous version had given you trouble.
Thank you for all your suggestions and feedback!