Archives for: October 2005
28/10/05
Cubism
Remember Rubik's cube? How about if it was... you know... LARGER? Watch this (hit Start): http://www.speedcubing.com/chris/20cube.html
23/10/05
Receive my blog posts by email (Thanks, Scott!)
A good hint by Scott Hanselman: FeedBlitz can publish my blog by email automatically. If you want to use it, just enter your email address in the small form on the left and hit the button, or click here.
DDD day 2 was a blast
Developer Developer Developer day 2 was yesterday and it was fantastic. I met a bunch of people there and at the geek dinner afterwards. If you were there and we didn't meet, bad luck... I'm sure we'll manage next time - or you could just drop me a line. Anyway, don't forget to leave your feedback about the event!
Calculating a running average
In a newsgroup I replied to a question about calculating average data throughput during data reception over the network. A simple average bytes per second calculation needs only a few lines of code:
int bytesTotal = 0;
int bytesPerSecond = 0;
DateTime startTime = DateTime.Now;
do {
bytesRead = receiveStream.Read( ... );
bytesTotal += bytesRead;
bytesPerSecond = bytesTotal / (DateTime.Now - startTime).TotalSeconds;
...
} while(bytesRead > 0);
The problem with this is that it may not render very exact values over a longer download period because actual network throughput tends to change a lot over WAN connections. It would be more accurate to work out an average over a number of most recent measured values instead. As this requires some handling of a store of measured samples, I decided to create a reusable class that can hold a number of samples in a ring buffer and calculate the current average from these samples. The class takes a weighting of each sample into account, because in scenarios like the one above it's not always guaranteed that new samples can be measured in an exact frequency. Here's the class:
public class RunningAverage {
public RunningAverage(int samplesCount) {
samples = new Sample[samplesCount];
for (int i = 0; i < samplesCount; i++)
samples[i] = new Sample( );
currentSample = 0;
}
class Sample {
public Sample( ) { }
public Sample(double weighting, double measuredValue) {
Set(weighting, measuredValue);
}
public void Set(double weighting, double measuredValue) {
this.weighting = weighting;
this.measuredValue = measuredValue;
isValid = true;
}
private double weighting;
public double Weighting { get { return weighting; } }
private double measuredValue;
public double MeasuredValue { get { return measuredValue; } }
private bool isValid;
public bool IsValid { get { return isValid; } }
}
Sample[] samples;
int currentSample;
public void AddSample(double weighting, double measuredValue) {
samples[currentSample++].Set(weighting, measuredValue);
if (currentSample >= samples.Length)
currentSample = 0;
}
public double GetCurrentAverage( ) {
double totalValue = 0;
double totalWeighting = 0;
foreach (Sample sample in samples)
if (sample.IsValid) {
totalValue += sample.MeasuredValue;
totalWeighting += sample.Weighting;
}
return totalValue / totalWeighting;
}
}
Now the receive loop above could look like this:
RunningAverage average = new RunningAverage(100);
DateTime timeStamp = DateTime.Now;
do {
bytesRead = receiveStream.Read( ... );
DateTime newTimeStamp = DateTime.Now;
average.AddSample(newTimeStamp.TotalSeconds - timeStamp.TotalSeconds, bytesRead);
timeStamp = newTimeStamp;
// access average.GetCurrentAverage() if needed
...
} while(bytesRead > 0);
18/10/05
Object pooling, part 8 - monitoring the pool's performance
This is the eighth article in my mini series about object pooling. Be sure to read part 1, part 2, part 3, part 4, part 5, part 6 and part 7 first.
So, although the number of downloads of the sample program hasn't been exactly great, I'm finally continuing the series. As I said in a previous article, I'd like to factor out the resizing behaviour - but before I do that, I want to integrate functionality that'll let me evaluate the pool's performance with regard to resizing, so I can assess the different resizing approaches reliably.
Fortunately performance monitoring is something that needs to be integrated into the pool implementation anyway and Windows has all the tools on board. So I only need to configure a few performance counters in Windows, make sure that these counters are updated with current numbers and the Windows performance monitoring frontend is available to the user to show it all in a nice graph. (I'm sure some of you have never heard of the performance monitor application - it's available on the Administrative tools menu and it's called, not surprisingly, Performance.)
Here's the download for the current version, including these changes: ObjectPooling-2.zip

And these are the changes - at the end of the pool class:
private string performanceCategoryName;
/// <summary>
/// Gets or sets a value indicating the name of the performance counter category.
/// </summary>
public string PerformanceCategoryName {
get {
return performanceCategoryName;
}
set {
if (performanceCategoryName != value) {
performanceCategoryName = value;
InvalidateCounters( );
}
}
}
private string performanceCounterNamePrefix;
/// <summary>
/// Gets or sets a value indicating a prefix that is used for all the performance
/// counters of this pool instance.
/// </summary>
public string PerformanceCounterNamePrefix {
get {
return performanceCounterNamePrefix;
}
set {
if (performanceCounterNamePrefix != value) {
performanceCounterNamePrefix = value;
InvalidateCounters( );
}
}
}
/// <summary>
/// Set the properties PerformanceCategoryName and PerformanceCounterNamePrefix to the values
/// passed in to the categoryName and counterNamePrefix parameters, then calls InitializeCounters().
/// </summary>
public void InitializeCounters(string categoryName, string counterNamePrefix) {
performanceCategoryName = categoryName;
performanceCounterNamePrefix = counterNamePrefix;
InitializeCounters( );
}
private const string STR_Poolsize = "Pool size";
private const string STR_PoolsizeHelp = "The current number of poolable objects.";
private const string STR_ObjectsInUse = "Objects in use";
private const string STR_ObjectsInUseHelp =
"The number of objects that are currently allocated to a pool user.";
PerformanceCounter poolSizeCounter;
PerformanceCounter inUseCounter;
/// <summary>
/// Initializes the performance counters according to the settings of the PerformanceCategoryName
/// and PerformanceCounterNamePrefix properties.
/// </summary>
public void InitializeCounters( ) {
if (PerformanceCounterCategory.Exists(performanceCategoryName))
PerformanceCounterCategory.Delete(performanceCategoryName);
CounterCreationDataCollection counters = new CounterCreationDataCollection( );
counters.Add(new CounterCreationData(performanceCounterNamePrefix + STR_Poolsize,
STR_PoolsizeHelp, PerformanceCounterType.NumberOfItems32));
counters.Add(new CounterCreationData(performanceCounterNamePrefix + STR_ObjectsInUse,
STR_ObjectsInUseHelp, PerformanceCounterType.NumberOfItems32));
PerformanceCounterCategory.Create(performanceCategoryName, "",
PerformanceCounterCategoryType.SingleInstance, counters);
poolSizeCounter = new PerformanceCounter(performanceCategoryName,
performanceCounterNamePrefix + STR_Poolsize, false);
inUseCounter = new PerformanceCounter(performanceCategoryName,
performanceCounterNamePrefix + STR_ObjectsInUse, false);
}
void InvalidateCounter(ref PerformanceCounter counter) {
if (counter != null) {
counter.Dispose( );
counter = null;
}
}
void InvalidateCounters( ) {
InvalidateCounter(ref poolSizeCounter);
InvalidateCounter(ref inUseCounter);
}
In the ExtendPoolBy method:
. . .
lock (poolLock) {
count = Math.Min(maxPoolSize - pool.Count, count);
for (int i = 0; i < count; i++) {
Slot slot = delayObjectCreation ? new Slot(objectFactory) :
new Slot(objectFactory.CreateObject( ));
pool.Add(slot);
}
if (poolSizeCounter != null)
poolSizeCounter.RawValue = pool.Count;
}
. . .
In the ShrinkPoolBy method:
. . .
if (poolSizeCounter != null)
poolSizeCounter.RawValue = pool.Count;
. . .
... and similar code for the other counter in the GetObject and ReleaseObject methods.


