Hi,

I am trying to create a custom performance counter to monitor the average
length of a queue to a resource over time
(PerformanceCounterType.CounterPerTimeInterval64), eg. just like the system
"PhysicalDisk\Avg. Disk Queue Length" counter.  The counter needs to be such
that two clients with different sampling rates still get accurate results -
i.e. I should be able to setup an alert that gets the average queue length
over the last 5 minutes every 5 minutes, while having perfmon displaying the
average queue length for the last second every second.  This seems to be the
purpose of the PERF_COUNTER_QUEUELEN type, but it doesn't appear to be
implemented properly in .NET.  I've got other performance counters working
fine. Does anyone have any experience (managed or unmanaged) using a counter
like this?

First of all, there seems to be some confusion in the implementation of this
counter type whether it needs a base counter or not.  The documentation for
the PerformanceCounterType enum describes some performance counter types
that require a base counter type to be defined for the counter.  Eg.
AverageBase is required for AverageTimer32 and AverageCount64.  The
documentation does NOT list a base-counter type for the
CounterPerTimeInterval64 counter.  However, if I try to install a
performance counter of this type, I get "System.InvalidOperationException:
The Counter layout for the Category specified is invalid, a counter of the
type:  AverageCount64, AverageTimer32, CounterMultiTimer,
CounterMultiTimerInverse, CounterMultiTimer100Ns,
CounterMultiTimer100NsInverse, RawFraction, SampleFraction or SampleCounter
has to be immediately followed by any of the base counter types:
AverageBase, MultiBase, RawBase or SampleBase.".

Even reading existing counters of this type from .NET doesn't appear to work
properly.  If I create a PerformanceCounter( "PhysicalDisk", "Avg. Disk
Queue Length", "_Total" ) and read its values, I always get back 0 (even
though typeperf is showing me values around 1).  After doing some tests, and
sifting through the decompiled source, I believe this is because
CounterSampleCalculator.ComputeAverageBulk always returns 0 when
newSample.UnsignedBaseValue is 0 but
CounterDefinitionSample.IsMultupleCounterType returns false for
CounterPerTimeInterval64, and so base counter data isn't recorded.  I.e one
part of the code is expecting a base counter for counters of this type, but
other parts of the code aren't.

Even though counter data of this type can't be read properly in .NET, I'm
hoping I'll still be able to publish data of this type.  However, I'm having
trouble finding any good reference for the formula I should be using to
create the counter values.  The documentation for PERF_COUNTER_QUEUELEN at
[1] (and other WinPerf.h values) is the best reference I've found, and is
the only thing I've found that indicates there is some non-trivial
calculation required (as I had expected based on the math required for an
accurate value), which it calls the "Queue Length Space-Time Product
formula".  The description here is still a little vague, but based on it and
what is possible with perf counters, I believe the formula must be something
[2].  However, its difficult (impossible) to make use of this accurately
given the .NET perf counter implementation because it requires me to know
the timestamp value being used for a sample when calculating the value for
that sample.

Can anyone else shed any insight into this?  I'm I just going to be stuck
having to write an unmanaged perf counter if I want an accurate average
queue length counter?

Thanks,
    Rick

[1]
http://msdn.microsoft.com/library/en-us/perfmon/base/perf_counter_definition_str.asp

[2] Hypothesized queue length space-time product formula:

Q[i] is queue length at sample i   (only known to server)
t[i] is the timestamp for sample i  (included in sample reported to client)
N[i] is the raw counter value recorded for sample i  (calculated by server,
supplied to client)
Y[i] is the base counter value recorded for sample i

C[i,j,ts] is the avg. value calculated by the client (i.e. perfmon) for the
samples taken at time t[i] and t[j] at current time ts

Y[i] = Q[i]
  - as described by QUEUELEN docs
N[i] = N[i-1] + Q[i-1] * (t[i]-t[i-1])
  - incrementing the counter by the previous queue lenght times the time it
was at that value
  - new queue len is irrelevant because its been there for 0 time

C[i,j,ts] = ( (N[j]-N[i]) + Y[j]*(ts-t[j]) ) / ( ts - t[i] )
  - idea here is the numerator is queuelength*time and denominator is time
elapsed
  - i.e. counter tracks the area under the queuelen curve (the fcns
integral)
  - the client can, given any two samples, calculate the average queue
length
    between those two samples
  - the queue is likely to go down to 0 and stay there for an extended
period of time without generating any
    new N[i] values, so we also have the client factor in the current
instantaneous queue length (Y[i]) and the
    time elapsed since the last counter timestamp.

-------
Rick Byers                              http://www.kinitos.com/
Kinitos: Distributed .NET smart client management

===================================
This list is hosted by DevelopMentor�  http://www.develop.com
Some .NET courses you may be interested in:

NEW! Guerrilla ASP.NET, 26 Jan 2004, in Los Angeles
http://www.develop.com/courses/gaspdotnetls

View archives and manage your subscription(s) at http://discuss.develop.com

Reply via email to