TOP

{--------------------------------------------------------------------

Author: J.M.Wehlou


Description:
    Represents one counter object and a collection of counters
    There are only two types of counters implemented:
    delta counters and raw counters. I implemented those
    in two separate classes just to illustrate how to provide
    for different types, even though these particular two
    types would be trivial to implement with one and the same
    class.
    What is not implemented here are multiple instances of
    counters, for example. Most of the other types of counters
    aren't here either, but I think that the two simple types
    you do have here actually cover practically everything
    you will need to do with performance counting.

--------------------------------------------------------------------}

unit PerfCounters;

interface

uses
  Windows,
  Contnrs,
  Winperf;

type
  TPerfCounters = class;

// ------------------------------------------------------------------

TPerfCounter = class
  fParent : TPerfCounters;
  fCD : PERF_COUNTER_DEFINITION;
public
  constructor Create(parent: TPerfCounters; uCounterNameTitleIndex: DWORD;
    uCounterHelpTitleIndex: DWORD; iDefaultScale: integer;
    uDetailLevel: DWORD; uCounterType: DWORD; uCounterSize: DWORD; uCounterOffset: DWORD);
  function GetCounterBlockSize(): DWORD;
  procedure CollectDefinition(var pvData: pointer; var cbTotalBytes: DWORD);
  procedure CollectCounterValue(var pvData: pointer; var cbTotalBytes: DWORD); virtual; abstract;
  procedure SetValue(uValue: DWORD); virtual; abstract;
end;

// ------------------------------------------------------------------

TRawCounter = class(TPerfCounter)
  fValue : DWORD;
public
  constructor Create(parent: TPerfCounters; uCounterNameTitleIndex: DWORD;
    uCounterHelpTitleIndex: DWORD; iDefaultScale: integer;
    uDetailLevel: DWORD; uValue: DWORD; uCounterOffset: DWORD);
  procedure CollectCounterValue(var pvData: pointer; var cbTotalBytes: DWORD); override;
  procedure SetValue(uValue: DWORD); override;
end;

// ------------------------------------------------------------------

TDeltaCounter = class(TPerfCounter)
  fValue : DWORD;
public
  constructor Create(parent: TPerfCounters; uCounterNameTitleIndex: DWORD;
    uCounterHelpTitleIndex: DWORD; iDefaultScale: integer;
    uDetailLevel: DWORD; uValue: DWORD; uCounterOffset: DWORD);
  procedure CollectCounterValue(var pvData: pointer; var cbTotalBytes: DWORD); override;
  procedure SetValue(uValue: DWORD); override;
end;

// ------------------------------------------------------------------

TPerfCounters = class
  fl : TObjectList;
  fPOT : PERF_OBJECT_TYPE;
  fNumCounters : DWORD;
  fNextCounterOffset : DWORD;
public
  constructor Create(uObjectNameTitleIndex: DWORD; uObjectHelpTitleIndex: DWORD;
    uDetailLevel: DWORD; iDefaultCounter: longint);
  destructor Destroy; override;
  procedure AddRawCounter(uCounterNameTitleIndex: DWORD;
    uCounterHelpTitleIndex: DWORD; iDefaultScale: integer;
    uDetailLevel: DWORD; uValue: DWORD);
  procedure AddDeltaCounter(uCounterNameTitleIndex: DWORD;
    uCounterHelpTitleIndex: DWORD; iDefaultScale: integer;
    uDetailLevel: DWORD; uValue: DWORD);
  procedure SetValue(iIndex: integer; uValue: DWORD);
  function GetCounterBlockSize(): DWORD;
  function GetDefinitionSize(): DWORD;
  function GetCount(): integer;
  procedure Collect(var pvData: pointer; var cbTotalBytes: DWORD);
end;

// ==================================================================

implementation

// ------------------------------------------------------------------
// help functions

procedure WriteMemBlock(const pSrc: pointer; const uSize: DWORD; var pvData: pointer;
    var
cbTotalBytes: DWORD);
begin
  copymemory(pvData, pSrc, uSize);
  pvData := ptr(cardinal(pvData) + uSize);
  cbTotalBytes := cbTotalBytes + uSize;
end;


// ==================================================================
{ TPerfCounter }

procedure TPerfCounter.CollectDefinition(var pvData: pointer;
  var cbTotalBytes: DWORD);
begin
  WriteMemBlock(@fCD, sizeof(fCD), pvData, cbTotalBytes);
end;

// ------------------------------------------------------------------

constructor TPerfCounter.Create(parent: TPerfCounters; uCounterNameTitleIndex: DWORD;
  uCounterHelpTitleIndex: DWORD; iDefaultScale: integer;
  uDetailLevel: DWORD; uCounterType: DWORD; uCounterSize: DWORD; uCounterOffset: DWORD);
begin
  fParent := parent;
  zeromemory(@fCD, sizeof(fCD));
  fCD.ByteLength := sizeof(fCD);
  fCD.CounterNameTitleIndex := uCounterNameTitleIndex;
  fCD.CounterHelpTitleIndex := uCounterHelpTitleIndex;
  fCD.DefaultScale := iDefaultScale;
  fCD.DetailLevel := uDetailLevel;
  fCD.CounterType := uCounterType;
  fCD.CounterSize := uCounterSize;
  fCD.CounterOffset := uCounterOffset;
end;

// ------------------------------------------------------------------

function TPerfCounter.GetCounterBlockSize: DWORD;
begin
  Result := fCD.CounterSize;
end;

// ==================================================================
{ TPerfCounters }

procedure TPerfCounters.AddDeltaCounter(uCounterNameTitleIndex,
  uCounterHelpTitleIndex: DWORD; iDefaultScale: integer; uDetailLevel,
  uValue: DWORD);
var
  tdc : TDeltaCounter;
begin
  tdc := TDeltaCounter.Create(self, uCounterNameTitleIndex, uCounterHelpTitleIndex,
  iDefaultScale, uDetailLevel, uValue, fNextCounterOffset);
  fNextCounterOffset := fNextCounterOffset + tdc.GetCounterBlockSize();
  fl.Add(tdc);
  Inc(fNumCounters);
end;

// ------------------------------------------------------------------

procedure TPerfCounters.AddRawCounter(uCounterNameTitleIndex: DWORD;
  uCounterHelpTitleIndex: DWORD; iDefaultScale: integer;
  uDetailLevel: DWORD; uValue: DWORD);
var
  trc : TRawCounter;
begin
  trc := TRawCounter.Create(self, uCounterNameTitleIndex, uCounterHelpTitleIndex,
  iDefaultScale, uDetailLevel, uValue, fNextCounterOffset);
  fNextCounterOffset := fNextCounterOffset + trc.GetCounterBlockSize();
  fl.Add(trc);
  Inc(fNumCounters);
end;

// ------------------------------------------------------------------

procedure TPerfCounters.Collect(var pvData: pointer; var cbTotalBytes: DWORD);
var
  i : integer;
  ctr : TPerfCounter;
  u : DWORD;
begin
  fPOT.HeaderLength := sizeof(fPOT);
  fPOT.DefinitionLength := fPOT.HeaderLength + GetDefinitionSize();
  fPOT.TotalByteLength := fPOT.DefinitionLength + GetCounterBlockSize();
  fPOT.NumCounters := fNumCounters;
  fPOT.NumInstances := -1;
  // the rest is zero

  cbTotalBytes := 0;
  WriteMemBlock(@fPOT, sizeof(fPOT), pvData, cbTotalBytes);

  for i := 0 to fl.Count - 1 do begin
    ctr := fl[i] as TPerfCounter;
    ctr.CollectDefinition(pvData, cbTotalBytes);
  end;

  u := GetCounterBlockSize();
  WriteMemBlock(@u, sizeof(u), pvData, cbTotalBytes);

  for i := 0 to fl.Count - 1 do begin
    ctr := fl[i] as TPerfCounter;
    ctr.CollectCounterValue(pvData, cbTotalBytes);
  end;

end;

// ------------------------------------------------------------------

constructor TPerfCounters.Create(uObjectNameTitleIndex: DWORD; uObjectHelpTitleIndex: DWORD;
  uDetailLevel: DWORD; iDefaultCounter: longint);
begin
  fl := TObjectList.Create(True); // owns the objects
  fNextCounterOffset := sizeof(DWORD);
  zeromemory(@fPOT, sizeof(fPOT));
  fPOT.ObjectNameTitleIndex := uObjectNameTitleIndex;
  fPOT.ObjectHelpTitleIndex := uObjectHelpTitleIndex;
  fPOT.DetailLevel := uDetailLevel;
  fPOT.DefaultCounter := iDefaultCounter;
end;

// ------------------------------------------------------------------

destructor TPerfCounters.Destroy;
begin
  fl.Free;
  inherited;
end;

// ------------------------------------------------------------------

function TPerfCounters.GetCount: integer;
begin
  Result := fl.Count;
end;

// ------------------------------------------------------------------

function TPerfCounters.GetCounterBlockSize: DWORD;
var
  i : integer;
begin
  Result := sizeof(DWORD); // the initial length value itself
 
for i := 0 to fl.Count - 1 do
    Result := Result + (fl[i] as TPerfCounter).GetCounterBlockSize();
end;

// ------------------------------------------------------------------

function TPerfCounters.GetDefinitionSize: DWORD;
begin
  Result := fl.Count * sizeof(PERF_COUNTER_DEFINITION);
end;

// ------------------------------------------------------------------
procedure TPerfCounters.SetValue(iIndex: integer; uValue: DWORD);
begin
  (fl[iIndex] as TPerfCounter).SetValue(uValue);
end;

// ==================================================================
{ TRawCounter }

procedure TRawCounter.CollectCounterValue(var pvData: pointer;
  var cbTotalBytes: DWORD);
begin
  WriteMemBlock(@fValue, sizeof(fValue), pvData, cbTotalBytes);
end;

// ------------------------------------------------------------------

constructor TRawCounter.Create(parent: TPerfCounters; uCounterNameTitleIndex,
  uCounterHelpTitleIndex: DWORD; iDefaultScale: integer;
  uDetailLevel: DWORD; uValue: DWORD; uCounterOffset: DWORD);
begin
  inherited Create(parent, uCounterNameTitleIndex, uCounterHelpTitleIndex,
  iDefaultScale, uDetailLevel, PERF_COUNTER_RAWCOUNT, sizeof(DWORD), uCounterOffset);
  fValue := uValue;
end;

// ------------------------------------------------------------------

procedure TRawCounter.SetValue(uValue: DWORD);
begin
  inherited;
  fValue := uValue;
end;

// ==================================================================
{ TDeltaCounter }

procedure TDeltaCounter.CollectCounterValue(var pvData: pointer;
  var cbTotalBytes: DWORD);
begin
  WriteMemBlock(@fValue, sizeof(fValue), pvData, cbTotalBytes);
end;

// ------------------------------------------------------------------

constructor TDeltaCounter.Create(parent: TPerfCounters; uCounterNameTitleIndex,
  uCounterHelpTitleIndex: DWORD; iDefaultScale: integer;
  uDetailLevel: DWORD; uValue: DWORD; uCounterOffset: DWORD);
begin
  inherited Create(parent, uCounterNameTitleIndex, uCounterHelpTitleIndex,
  iDefaultScale, uDetailLevel, PERF_COUNTER_COUNTER, sizeof(DWORD), uCounterOffset);
  fValue := uValue;
end;

// ------------------------------------------------------------------

procedure TDeltaCounter.SetValue(uValue: DWORD);
begin
  inherited;
  fValue := uValue;
end;

// ------------------------------------------------------------------
end.