・レジストリデータを使ってのモニタの実際
それではコードを書きますが、レジストリデータを使ってカウンタデータを 取得するクラスを作り、コンソールでそのクラスを使うことにします。仕様はオブジェクト名、 カウンタ名、インスタンス名、親インスタンス名、インスタンスインデックスを与えて クラスインスタンスを作成後、GetCounterValueを実行するとカウンタデータを返却する 単純なものとします。
VSのファイル(F)→新規作成(N)からプロジェクト(P)を選択してください。 ダイアログが表示されるのでVisual C++のWin32コンソールアプリケーションを選択して、 任意のプロジェクト名を入れてください。アプリケーションウィザードで以下のようにしてください。
アプリケーションの種類 | :コンソールアプリケーション |
追加のオプション | :プリコンパイル済みヘッダー |
共通ヘッダーファイルを追加 | :なし |
プロジェクトができたら、stdafx.hができているのでファイルを開いて最後の行に
#include <windows.h>
を追加してください。
次に実装の中心になるパフォーマンスデータを取得するクラスを作成します。プロジェクト(P)→ クラスの追加(C)でC++クラスを追加してください。クラス名は「CPerfMoniReg」です。
PerfMoniReg.hに以下を記述してください。
//PerfMoniReg.h------------------------------------------------------------------------ #pragma once //レジストリのオブジェクト,カウンタのインデックスリストが格納されているパス #define PERF_IDX_LIST_JP "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\PerfLib\\011" #define PERF_IDX_LIST_EN "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\PerfLib\\009" //未処理データ保持用(未処理データの計算にはこの構造体の各メンバの値が必要) typedef struct tagRAW_COUNTER_VAL { //未処理カウンタデータ LONGLONG CounterVal; //100ナノ秒単位のサンプリング時間(PERF_DATA_BLOCKのPerfTime100nSecメンバより取得) LARGE_INTEGER PerfTime100nSec; //サンプリング時間(PERF_DATA_BLOCKのPerfTimeメンバより取得) //但しカウンタタイプのタイマのタイプがPERF_OBJECT_TIMERの時はPERF_OBJECT_TYPEの //PerfTimeメンバから取得(winperf.h参照) LARGE_INTEGER PerfTime; //サンプリング周波数(PERF_DATA_BLOCKのPerfFreqメンバより取得) //但しカウンタタイプのタイマのタイプがPERF_OBJECT_TIMERの時はPERF_OBJECT_TYPEの //PerfFreqメンバから取得(winperf.h参照) LARGE_INTEGER PerfFreq; //カウンタベース値が必要なタイプのカウンタのベース値、又は通常では精度が不十分な //タイマが必要なタイプのカウンタ(PERF_PRECISION_xxxx_TIMER)の高精度のタイム //スタンプ値を取得 LONGLONG BasePrecisionVal; } RAW_COUNTER_VAL; //カウンタデータの表示形式 typedef enum tagFMT_COUNTER { FMT_UNKNOWN, //不明 FMT_LONG, //32ビット整数表示形式 FMT_LONGLONG, //64ビット整数表示形式 FMT_DOUBLE, //浮動小数点表示形式 FMT_ANSISTRING, //アスキー文字列表示形式 FMT_WIDESTRING //Unicode文字列表示形式 } FMT_COUNTER; //カウンタデータ結果出力用 typedef struct tagCOUNTER_VAL { union //fmtCounterタイプに従ってメンバを選択 { LONG longValue; double doubleValue; LONGLONG largeValue; LPCSTR ansiStringValue; LPCWSTR wideStringValue; }; DWORD dwCouterType; //カウンタタイプ(winperf.h参照) FMT_COUNTER fmtCounter; } COUNTER_VAL; //レジストリインターフェイスを利用したカウンタデータ取得クラス class CPerfMoniReg { //メンバ変数///////////////////////////////////////////////////// protected: DWORD m_dwObjectIdx; //オブジェクト名ID DWORD m_dwCounterIdx; //カウンタ名ID LPTSTR m_pszInstance; //インスタンス名 LPTSTR m_pszParentInst; //親インスタンス名 DWORD m_dwInstIdx; //インスタンスインデックス LPTSTR m_pszTextBuffer; //テキストタイプカウンタ用バッファ RAW_COUNTER_VAL m_NewRawCntr; //新しい未処理カウンタデータ RAW_COUNTER_VAL m_OldRawCntr; //直近の未処理カウンタデータ //メンバ関数//////////////////////////////////////////////////// private: CPerfMoniReg(CPerfMoniReg & obj); //コピーコンストラクタ protected: //オブジェクト名/カウンタ名からオブジェクト/カウンタインデックス取得 //(メンバm_dwObjectIdx, m_dwCounterIdxにインデックス取得) BOOL GetObjectCounterIdx(IN LPCTSTR pszObject, IN LPCTSTR pszCounter); //GetObjectCounterIdxで取得したオブジェクトIndex(m_dwObjectIdx)から //PERF_DATA_BLOCKを先頭とするパフォーマンス情報の取得(使用後は*ppPerfDataをdeleteする) BOOL GetPerfObjectDef(OUT PERF_DATA_BLOCK **ppPerfData, OUT PERF_OBJECT_TYPE **ppPerfObject); //インスタンスの親オブジェクトIndex/親インスタンスIndexが //親インスタンス名(m_pszParentInst)と合致しているか int CheckParentInst(IN const PERF_INSTANCE_DEFINITION *pPerfInst, IN const PERF_DATA_BLOCK *pPerfData); //インスタンス名(m_pszInstance)とその親インスタンス名(m_pszParentInst)から //親オブジェクトIndex・親インスタンスIndex取得 BOOL GetParentObjInstIdx(IN const PERF_OBJECT_TYPE *pPerfObject, IN const PERF_DATA_BLOCK *pPerfData, OUT DWORD *pdwParentObjIdx, OUT DWORD *pdwParentInstIdx, IN OUT DWORD *pdwNumParentInst); //親インスタンスIndex検索(親インスタンスIndexのリスト内でマッチするIndex検索) BOOL MatchParentInstIdx(IN const DWORD dwParentInstIdx, IN const DWORD *pdwParentInstList, IN const DWORD dwNum); //インスタンス名(m_pszInstance), 親インスタンス名(m_pszParentInst), インスタンスIndex //(m_dwInstIdx)からカウンタデータの取得対象のインスタンス特定 PERF_INSTANCE_DEFINITION *SpecifyInstanceDef(IN const PERF_OBJECT_TYPE *pPerfObject, IN const PERF_DATA_BLOCK *pPerfData); //カウンタベース値の取得 LONGLONG GetBasePrecisionCounter(IN const PERF_COUNTER_DEFINITION *pPerfCounter, IN const PERF_COUNTER_BLOCK *pCntrBlock); //カウンタデータ計算 BOOL CalculateCounter(IN const PERF_COUNTER_DEFINITION *pPerfCounter, OUT COUNTER_VAL & counterval); public: //デフォルトコンストラクタ CPerfMoniReg(); //引数付コンストラクタ CPerfMoniReg(LPTSTR pszObject, //カウンタオブジェクト名 LPTSTR pszCounter, //カウンタ名 LPTSTR pszInstance = NULL, //インスタンス名 LPTSTR pszParentInst = NULL, //親インスタンス名 DWORD dwInstIdx = -1); //インスタンスインデックス //デストラクタ ~CPerfMoniReg(); //初期化(オブジェクトインデックス,カウンタインデックス //インスタンス名,親インスタンス名,インスタンスインデックス初期化) BOOL Initialize(LPTSTR pszObject, //カウンタオブジェクト名 LPTSTR pszCounter, //カウンタ名 LPTSTR pszInstance = NULL, //インスタンス名 LPTSTR pszParentInst = NULL, //親インスタンス名 DWORD dwInstIdx = -1); //インスタンスインデックス //カウンタデータ取得 BOOL GetCounterValue(OUT COUNTER_VAL & counterval); }; |
各関数の多くが、モニタ対象のPERF_OBJECT_TYPE、PERF_COUNTER_DEFINITION、 PERF_INSTANCE_DEFINITIONを特定するためのものです。各メンバの機能の概略を書いておきますので、 以下の実装ファイルで内容を確認してください。
分類 | メンバ | 機能 |
変数 | m_dwObjectIdx〜m_dwInstIdx | 初期に与えらたオブジェクト名、カウンタ名に関しては データ構造1を参照してインデックスを格納し、 他はそのままデータをコピー。 |
変数 | m_pszTextBuffer | 文字列をカウンタデータとするカウンタタイプのデータ保持用 |
変数 | m_NewRawCntr〜m_OldRawCntr | 最新とその前に取得した未処理カウンタデータ保持用 |
protected 関数 |
GetObjectCounterIdx | 初期に与えられたオブジェクト名、カウンタ名からインデックスを取得(Initializeで使用) |
protected 関数 |
GetPerfObjectDef | オブジェクトインデックス(m_dwObjectIdx)からRegQueryValueExを呼んで、 PERF_DATA_BLOCK以下のデータブロックを取得後、目的のPERF_OBJECT_TYPEを特定 |
protected 関数 |
CheckParentInst |
第一引数で指定したPERF_INSTANCE_DEFINITIONのParentObjectTitleIndexメンバ、
ParentObjectInstanceメンバが示すPERF_INSTANCE_DEFINITIONのインスタンス名が初期に
与えらたインスタンス名(m_pszParentInst)と一致しているか (GetParentObjInstIdx関数で使用) |
proteced 関数 |
GetParentObjInstIdx |
初期に与えられたインスタンス名から、PERF_INSTANCE_DEFINITIONのParentObjectTitleIndex、
PrenentObjectInstanceメンバが指すPERF_INSTANCE_DEFINITIONのインスタンス名が、
目的の親インスタンス名と一致する組合せの取得。 (例 Threadオブジェクトのインスタンス名"0"でi親インスタンスがiexploreの場合。 親オブジェクトProcessで、インスタンス名がiexploreであるインスタンスインデックスが3, 5, 8 のとき、Processオブジェクトのインデックス 230と親インスタンスインデックスの 配列3,5,8が返却される。) |
protected 関数 |
MatchParentInstIdx |
第一引数で指定したPERF_INSTANCE_DEFINITIONのParentObjectInstanceメンバの値が
GetParentObjInstIdx関数で取得した親インスタンスのリスト内にあるかの確認。 (第一引数の親インスタンスインデックス値をもつPERF_INSTANCE_DEFINITIONが目的の 親インスタンス名を持つ子インスタンスであるかの確認) (SpecifyInstanceDefで使用される) |
protected 関数 |
SpecifyInstanceDef | 初期に与えられたインスタンス名(m_pszInstance)、親インスタンス名(m_pszParentInst)、 インスタンスインデックス(m_dwInstIdx)から目的のPERF_INSTANCE_DEFINITIONを特定。 |
protected 関数 |
GetBasePrecisionCounter | ベースカウンタ、又は高精度タイマを使用するタイプのカウンタのベースカウンタデータ、 高精度タイムスタンプデータを取得。 |
protected 関数 |
CalculateCounter | インスタンスを持つオブジェクトの場合はSpecifyInstanceDefを使って、持たない オブジェクトの場合はGetPerfObjectDefのみを使って得たPERF_COUNTER_BLOCKから取得した 未処理データ(m_NewRawCntr、m_OldRawCntr)と他の時間要素を利用してカウンタデータを計算。 |
public 関数 |
Initialize | 初期に与えられたオブジェクト名、カウンタ名はインデックスに変換し、 他は文字列としてクラス内に保持。 |
public 関数 |
GetCounterValue | GetPerfObjectDefでPERF_DATA_BLOCK以下のカウンタデータを含むメモリブロックを 取得し、上記関数を使って最終的なカウンタデータを出力。 |
//PerfMoniReg.cpp------------------------------------------------------------------------ #include "StdAfx.h" #include "PerfMoniReg.h" //デフォルトコンストラクタ CPerfMoniReg::CPerfMoniReg() : m_dwObjectIdx(0) , m_dwCounterIdx(0) , m_pszInstance(NULL) , m_pszParentInst(NULL) , m_dwInstIdx(-1) , m_pszTextBuffer(NULL) { ::memset(&m_NewRawCntr, 0, sizeof(RAW_COUNTER_VAL)); ::memset(&m_OldRawCntr, 0, sizeof(RAW_COUNTER_VAL)); } //コピーコンストラクタ CPerfMoniReg::CPerfMoniReg(CPerfMoniReg &obj) { } //引数付きコンストラクタ CPerfMoniReg::CPerfMoniReg(LPTSTR pszObject, LPTSTR pszCounter, LPTSTR pszInstance /*= NULL*/, LPTSTR pszParentInst /*=NULL*/, DWORD dwInstIdx /*= -1*/) : m_dwObjectIdx(0) , m_dwCounterIdx(0) , m_pszInstance(NULL) , m_pszParentInst(NULL) , m_dwInstIdx(-1) , m_pszTextBuffer(NULL) { ::memset(&m_NewRawCntr, 0, sizeof(RAW_COUNTER_VAL)); ::memset(&m_OldRawCntr, 0, sizeof(RAW_COUNTER_VAL)); Initialize(pszObject, pszCounter, pszInstance, pszParentInst, dwInstIdx); } //デストラクタ CPerfMoniReg::~CPerfMoniReg() { if (m_pszInstance) delete [] m_pszInstance; if (m_pszParentInst) delete [] m_pszParentInst; if (m_pszTextBuffer) delete [] m_pszTextBuffer; } /*初期化(オブジェクトインデックス,カウンタインデックス インスタンス名,親インスタンス名,インスタンスインデックス初期化) 引数 pszObject カウンタオブジェクト名 pszCounter カウンタ名 pszInstance インスタンス名(インスタンスがないオブジェクトはNULL) pszParentInst 親インスタンス名(親インスタンスがないオブジェクトはNULL) dwInstIdx インスタンスインデックス(単一インスタンスのときは-1) 戻値 オブジェクト、カウンタインデックスが取得でき、インスタンスの各要素がコピー できたときTRUE*/ BOOL CPerfMoniReg::Initialize(LPTSTR pszObject, LPTSTR pszCounter, LPTSTR pszInstance /*= NULL*/, LPTSTR pszParentInst /*= NULL*/, DWORD dwInstIdx /*= -1*/) { BOOL bRet = FALSE; do { //カウンタオブジェクト/カウンタインデックス取得 if (! GetObjectCounterIdx(pszObject, pszCounter)) break; //インスタンス名/親インスタンス名をメンバ変数にコピー const TCHAR *pszSrc[] = {pszInstance, pszParentInst}; TCHAR **ppszDst[] = {&m_pszInstance, &m_pszParentInst}; for (int i=0; i< sizeof pszSrc / sizeof pszSrc[0]; i++) { if ( *ppszDst[i] ) delete [] *ppszDst[i]; if (! pszSrc[i]) { *ppszDst[i] = NULL; } else { size_t size = _tcslen(pszSrc[i]) + 1; *ppszDst[i] = new TCHAR[size]; if ( _tcscpy_s( *ppszDst[i], size, pszSrc[i]) ) { delete [] *ppszDst[i]; *ppszDst[i] = NULL; break; } } } //インスタンスインデックス取得 m_dwInstIdx = dwInstIdx; bRet = TRUE; } while(0); if (! bRet) { m_dwObjectIdx = m_dwCounterIdx = 0; m_dwInstIdx = -1; if (m_pszInstance) {delete [] m_pszInstance; m_pszInstance = NULL;} if (m_pszParentInst) {delete [] m_pszParentInst; m_pszParentInst = NULL;} } return bRet; } /*オブジェクト名/カウンタ名からオブジェクト/カウンタインデックス取得 (メンバm_dwObjectIdx, m_dwCounterIdxにインデックス取得) (HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\PerfLib\011から取得) 引数 pszObject オブジェクト名 pszCounter カウンタ名 戻値がTRUEの時 メンバm_dwObjectIdx, m_dwCounterIdxに値が格納される FALSE メンバm_dwObjectIdx, m_dwCounterIdxにが格納される*/ BOOL CPerfMoniReg::GetObjectCounterIdx(IN LPCTSTR pszObject, IN LPCTSTR pszCounter) { BOOL bRet = FALSE; HKEY hPerfKey = 0; //カウンタインデックスリストが //格納されたレジストリへのハンドル DWORD dwMaxEntryDataLen = 0; //カウンタレジストリリストのバイト数 DWORD dwRegType = REG_MULTI_SZ; LPTSTR pszIdxList = NULL; //カウンタインデックスリストへの //ポインタ BOOL bFlgObj = FALSE; //対象PERF_OBJECT_TYPE検索フラグ BOOL bFlgCnt = FALSE; //対象PERF_COUNTER_DEFINITION //検索フラグ PERF_DATA_BLOCK *pPerfData = NULL; //対象PERF_OBJECT_TYPEを含む //PERF_DATA_BLOCKへのポインタ PERF_OBJECT_TYPE *pPerfObj = NULL; //対象PERF_OBJECT_TYPEへのポインタ PERF_COUNTER_DEFINITION *pPerfCntr = NULL; //対象PERF_COUNTER_DEFINITION //へのポインタ do { //オブジェクト名&カウンタ名対応インデックスのMULTI_SZ文字列エントリのハンドル取得 if ( ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(PERF_IDX_LIST_JP), 0, KEY_READ, &hPerfKey) != ERROR_SUCCESS ) break; //エントリデータの最大文字列の最大バイト数取得 if ( ::RegQueryInfoKey(hPerfKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dwMaxEntryDataLen, NULL, NULL) != ERROR_SUCCESS ) break; //エントリデータの領域確保 pszIdxList = (LPTSTR) new BYTE[dwMaxEntryDataLen]; //オブジェクト&カウンタの名前,インデックスMULTI_SZ文字列取得 if ( ::RegQueryValueEx(hPerfKey, _T("Counter"), NULL, &dwRegType, (LPBYTE)pszIdxList, &dwMaxEntryDataLen) != ERROR_SUCCESS ) break; //pszObjectに対応するインデックス取得---------------------------------- for ( LPTSTR pTemp = pszIdxList; ! bFlgObj && *pTemp != 0; pTemp += (lstrlen(pTemp) + 1) ) { DWORD dwIdx = _tstol(pTemp); //インデックス取得 pTemp += lstrlen(pTemp) + 1; //対応オブジェクト名 if ( _tcsicmp(pTemp, pszObject) == 0 ) { m_dwObjectIdx = dwIdx; bFlgObj = TRUE; } } if ( ! bFlgObj ) break; //pszCounterに対応するインデックス取得-------------------------------- if (! GetPerfObjectDef(&pPerfData, &pPerfObj) ) break; //最初のカウンタ pPerfCntr = (PPERF_COUNTER_DEFINITION)((PBYTE)pPerfObj + pPerfObj->HeaderLength); for (DWORD i=0; i<pPerfObj->NumCounters; i++) { //pszIdxListから一致するカウンタ名検索 for (LPTSTR pTemp = pszIdxList; *pTemp != 0; pTemp += (lstrlen(pTemp) + 1)) { DWORD dwIdx = _tstol(pTemp); pTemp += lstrlen(pTemp) + 1; /*PERF_COUNTER_DEFINITIONのカウンタインデックスとレジストリから取得した インデックス(dwIdx)が一致し、かつdwIdxに対応するカウンタ名がpszCounter に一致した場合はdwIdxが取得対象カウンタインデックス*/ if (pPerfCntr->CounterNameTitleIndex == dwIdx && _tcsicmp(pTemp, pszCounter) == 0) { m_dwCounterIdx = dwIdx; bFlgCnt = TRUE; break; } } if (bFlgCnt) break; //次のカウンタ pPerfCntr = (PPERF_COUNTER_DEFINITION) ((PBYTE)pPerfCntr + pPerfCntr->ByteLength); } if (! bFlgCnt) break; bRet = TRUE; } while(0); if (hPerfKey) ::RegCloseKey(hPerfKey); if (pszIdxList) delete [] pszIdxList; if (pPerfData) delete [] pPerfData; if (! bRet) m_dwObjectIdx = m_dwCounterIdx = 0; return bRet; } /*GetObjectCounterIdxで取得したオブジェクトIndex(m_dwObjectIdx)から PERF_DATA_BLOCKを先頭とするパフォーマンス情報の取得(使用後は*ppPerfDataをdeleteする事) 引数 ppPerfData m_dwObjectIdxからオブジェクトのパフォーマンス情報である PERF_DATA_BLOCKへのポインタのアドレス(出力) ppPerfObject オブジェクトインデックス(m_dwObjectIdx)に対応する PERF_OBJECT_TYPEへのポインタのアドレス(出力) 戻値 成功時 TRUE 失敗時 *ppPerfData, *ppPerfObjectがNULLにセットされFALSEを返却 仕様 *ppPerfDataが指す領域はこの関数で確保される。 使用後は*ppPerfDataが指す領域を開放すること *ppPerfObjectは*ppPerfDataが指す領域内のアドレスなので*ppPerfDataを開放した後は このポインタを使用しないこと*/ BOOL CPerfMoniReg::GetPerfObjectDef(OUT PERF_DATA_BLOCK **ppPerfData, OUT PERF_OBJECT_TYPE **ppPerfObject) { DWORD dwSize = 102400; //対象PERF_OBJECT_TYPEを含む //データブロックサイズ DWORD dwTempSize = 102400; //一時データブロックサイズ格納用 TCHAR strObjectIdx[10]; //オブジェクトIndexの文字列 //(RegQueryValueExで使用) PERF_DATA_BLOCK *pPerfData = NULL; //取得対象PERF_DATA_BLOCKへのポインタ PERF_OBJECT_TYPE *pPerfObject = NULL; //取得対象PERF_OBJECT_TYPE(PERF_DATA_BLOCK内) BOOL bRet = FALSE; do { if (! m_dwObjectIdx) break; if ( _stprintf_s(strObjectIdx, 10, _T("%d"), m_dwObjectIdx) == -1) break; //PERF_DATA_BLOCK取得 pPerfData = (PPERF_DATA_BLOCK) new BYTE[dwSize]; while ( ::RegQueryValueEx(HKEY_PERFORMANCE_DATA, strObjectIdx, NULL, NULL, (LPBYTE)pPerfData, &dwTempSize) == ERROR_MORE_DATA ) { if (pPerfData) delete [] pPerfData; dwSize += 51200; dwTempSize = dwSize; pPerfData = (PPERF_DATA_BLOCK) new BYTE[dwSize]; } //最初のオブジェクト pPerfObject = (PPERF_OBJECT_TYPE)((PBYTE)pPerfData + pPerfData->HeaderLength); for (DWORD i=0; i<pPerfData->NumObjectTypes; i++) { if (pPerfObject->ObjectNameTitleIndex == m_dwObjectIdx) { bRet = TRUE; break; } //次のオブジェクト pPerfObject = (PPERF_OBJECT_TYPE) ((PBYTE)pPerfObject + pPerfObject->TotalByteLength); } } while(0); if (! bRet) //失敗時 { if (pPerfData) delete [] pPerfData; *ppPerfData = NULL; *ppPerfObject = NULL; } else //成功時 { *ppPerfData = pPerfData; *ppPerfObject = pPerfObject; } return bRet; } /*インスタンスの親オブジェクトIndex/親インスタンスIndexが 親インスタンス名(m_pszParentInst)と 一致しているか 引数 pPerfInst 親オブジェクトIndex/親インスタンスIndexがメンバである PERF_INSTANCE_DEFINITION pPerfData 第一引数(pPerfInst)の親オブジェクト(ParentObjectTitleIndex)メンバに 合致するPERF_OBJECT_TYPEを含むPERF_DATA_BLOCKへのポインタ 戻値 pPerfInstのParentObjectTitleIndex, ParentObjectInstanceが示すインスタンス名が メンバm_pszParentInstと一致した場合は1、一致しない場合は0, エラー時、pPerfInstの親オブジェクトIndex/親インスタンスIndexに対応するインスタンス がない時、又は親インスタンス名(m_pszParentInst)がない時-1*/ int CPerfMoniReg::CheckParentInst(IN const PERF_INSTANCE_DEFINITION *pPerfInst, IN const PERF_DATA_BLOCK *pPerfData) { int nRet = -1; PERF_OBJECT_TYPE *pPerfParentObj = NULL; //pPerfInstの親オブジェクトである //PERF_OBJECT_TYPEへのポインタ PERF_INSTANCE_DEFINITION *pPerfParentInst = NULL; //pPerfInstの親インスタンスである //PERF_INSTANCE_DEFINTIONへのポインタ PERF_COUNTER_BLOCK *pCntrBlock = NULL; BOOL bFindParentObj = FALSE; //親オブジェクト検索フラグ if (! pPerfInst || ! m_pszParentInst || ! pPerfData) return nRet; //最初の親オブジェクト pPerfParentObj = (PPERF_OBJECT_TYPE)((PBYTE)pPerfData + pPerfData->HeaderLength); for (DWORD i=0; i<pPerfData->NumObjectTypes; i++) { if (pPerfParentObj->ObjectNameTitleIndex == pPerfInst->ParentObjectTitleIndex) { bFindParentObj = TRUE; break; } //次の親オブジェクト pPerfParentObj = (PPERF_OBJECT_TYPE) ((PBYTE)pPerfParentObj + pPerfParentObj->TotalByteLength); } if (! bFindParentObj) return nRet; if (pPerfParentObj->NumInstances <= 0) return nRet; //最初の親インスタンス pPerfParentInst = (PPERF_INSTANCE_DEFINITION) ((PBYTE)pPerfParentObj + pPerfParentObj->DefinitionLength); for (LONG i=0; i<pPerfParentObj->NumInstances; i++) { if ((DWORD)i == pPerfInst->ParentObjectInstance) { _tcsicmp(m_pszParentInst, (TCHAR *)((PBYTE)pPerfParentInst + pPerfParentInst->NameOffset) ) == 0 ? nRet = 1 : nRet = 0; break; } //次の親インスタンス pCntrBlock = (PPERF_COUNTER_BLOCK) ((PBYTE)pPerfParentInst + pPerfParentInst->ByteLength); pPerfParentInst = (PPERF_INSTANCE_DEFINITION) ((PBYTE)pCntrBlock + pCntrBlock->ByteLength); } return nRet; } /*インスタンス名(m_pszInstance)とその親インスタンス名(m_pszParentInst)から 親オブジェクトIndex・親インスタンスIndex取得 (親インスタンスIndexは複数の場合あり) (PERF_INSTANCE_DEFINITIONのParentObjectTitleIndex, ParentObjectInstanceの値を取得) 引数 pPerfObject 指定カウンタオブジェクトのPERF_OBJECT_TYPEへのポインタ (GetPerfObjectDefで取得) pPerfData 親オブジェクトを含むPERF_DATA_BLOCKへのポインタ pdwParentObjIdx インスタンス名(m_pszInstance)の親インスタンス名(m_pszParentInst)に 対応する親オブジェクトIndexを受取るポインタ pdwParentInstIdx インスタンス名(m_pszInstance)の親インスタンス名(m_pszParentInst)に 対応する親インスタンスIndexの配列を受取るポインタ (配列の領域は呼び出し側で確保) pdwNumParentInst 第四引数の配列の要素数を指定。成功したときは親インスタンス数を受取る (pdwParentInstIdxの要素数) 戻値 パフォーマンスオブジェクト, インスタンス名、その親インスタンス名から、 PERF_INSTANCE_DEFINITIONの親オブジェクトIndex, 親インスタンスIndex配列が取得できた時TRUE (pdwParentInstIdxがNULL又は*pdwNumParentInstがの場合は、*pdwParentObjIdxの値と pdwParentInstIdxの要素数(pdwNumParentInstの値)が取得できたときはTRUE) それ以外(対象のインスタンスや親インスタンスがないなど)はFALSE 仕様 第三/四/五引数は呼び出し側で領域を確保してそのアドレスを指定すること pdwParentInstIdxがNULL, 又は*pdwNumParentInstがの場合は、親オブジェクトidx, 親インスタンス数のみを返却。 親インスタンス数分だけ確保された領域へのポインタをpdwParentInstIdxに指定し、 その要素数をpdwNumParentInstに指定すると、親インスタンスIndexが pdwParentInstIdxに格納される。 失敗したときは*pdwParentObjIdxは,pdwParentIdxのすべての要素はにセットされる (pdwParentIdxは要素が呼び出し側で確保されている場合)*/ BOOL CPerfMoniReg::GetParentObjInstIdx(IN const PERF_OBJECT_TYPE *pPerfObject, IN const PERF_DATA_BLOCK *pPerfData, OUT DWORD *pdwParentObjIdx, OUT DWORD *pdwParentInstIdx, IN OUT DWORD *pdwNumParentInst) { PERF_INSTANCE_DEFINITION *pPerfInst = NULL; //取得対象インスタンス //へのポインタ PERF_COUNTER_BLOCK *pCntrBlock = NULL; BOOL bRet = FALSE; DWORD dwNumParentInstance = 0; //親インスタンス数 BOOL bErr = FALSE; do { //親オブジェクトIndex初期化 if (pdwParentObjIdx) *pdwParentObjIdx = 0; //親インスタンス配列初期化 if (pdwNumParentInst && *pdwNumParentInst > 0 && pdwParentInstIdx) ::memset(pdwParentInstIdx, 0, *pdwNumParentInst * sizeof(DWORD)); //引数チェック if (! pPerfObject || ! m_pszInstance || ! m_pszParentInst || ! pPerfData || ! pdwParentObjIdx || ! pdwNumParentInst) break; //インスタンス存在確認 if (pPerfObject->NumInstances <= 0) break; //最初のインスタンス pPerfInst = (PPERF_INSTANCE_DEFINITION) ((PBYTE)pPerfObject + pPerfObject->DefinitionLength); for (LONG i=0; i<pPerfObject->NumInstances; i++) { //pPerfInstのインスタンス名とm_pszInstanceが一致 if (_tcsicmp(m_pszInstance, (TCHAR *)((PBYTE)pPerfInst + pPerfInst->NameOffset)) == 0 ) { //pPerfInstのParentObjectTitleIndex,ParentObjectInstanceメンバが指す //親インスタンス名がメンバm_pszParentInstと一致 if ( CheckParentInst(pPerfInst, pPerfData) == 1) { //親オブジェクトIndex設定 if (! *pdwParentObjIdx) *pdwParentObjIdx = pPerfInst->ParentObjectTitleIndex; else { if (*pdwParentObjIdx != pPerfInst->ParentObjectTitleIndex) { bErr = TRUE; break; } } //親インスタンスIndex設定(配列が呼び出し側で確保されている場合) if (pdwParentInstIdx != NULL && *pdwNumParentInst > 0) { //配列確保要素数を超えた時 if (dwNumParentInstance >= *pdwNumParentInst) { bErr = TRUE; break; } pdwParentInstIdx[dwNumParentInstance] = pPerfInst->ParentObjectInstance; } dwNumParentInstance++; } } //次のインスタンス pCntrBlock = (PPERF_COUNTER_BLOCK)((PBYTE)pPerfInst + pPerfInst->ByteLength); pPerfInst = (PPERF_INSTANCE_DEFINITION) ((PBYTE)pCntrBlock + pCntrBlock->ByteLength); } if (bErr || ! dwNumParentInstance) //エラー又は親インスタンスがない時 break; bRet = TRUE; } while(0); if (! bRet) //失敗時 { if (pdwParentObjIdx) *pdwParentObjIdx = 0; if (pdwNumParentInst && *pdwNumParentInst > 0 && pdwParentInstIdx) ::memset(pdwParentInstIdx, 0, *pdwNumParentInst * sizeof(DWORD)); } else //成功時 { *pdwNumParentInst = dwNumParentInstance; } return bRet; } /*親インスタンスIndex検索(親インスタンスIndexのリスト内でマッチするIndex検索) 引数 dwParentInstIdx 検索対象の親インスタンスIndex pdwParentInstList 親インスタンスの配列(GetParentObjInstIdxを実行して受取る pdwParentInstIdxの値) dwNum 第二引数の要素数 (GetParentObjInstIdxの*pdwNumParentInst) 戻値 dwParentInstIdxがpdwParentInstList内に存在すればTRUE*/ BOOL CPerfMoniReg::MatchParentInstIdx(IN const DWORD dwParentInstIdx, IN const DWORD *pdwParentInstList, IN const DWORD dwNum) { BOOL bRet = FALSE; if (! dwParentInstIdx || ! pdwParentInstList || ! dwNum) return bRet; for (DWORD i=0; i<dwNum; i++) { if (dwParentInstIdx == pdwParentInstList[i]) { bRet = TRUE; break; } } return bRet; } /*インスタンス名(m_pszInstance), 親インスタンス名(m_pszParentInst), インスタンスIndex (m_dwInstIdx)からカウンタデータの取得対象のインスタンス特定 引数 pPerfObject 取得対象のカウンタオブジェクトへのポインタ pPerfData 親インスタンスのオブジェクトであるPERF_OBJECT_TYPEを含む PERF_DATA_BLOCKへのポインタ 戻値 特定できた場合はPERF_INSTANCE_DEFINITIONへのポインタ(pPerfObjectの領域内) 特定できない場合(インスタンスがないオブジェクトの場合を含む)はNULL*/ PERF_INSTANCE_DEFINITION *CPerfMoniReg::SpecifyInstanceDef (IN const PERF_OBJECT_TYPE *pPerfObject, IN const PERF_DATA_BLOCK *pPerfData) { PERF_INSTANCE_DEFINITION *pPerfInst = NULL; PERF_COUNTER_BLOCK *pCntrBlock = NULL; DWORD dwParentObjIdx = 0; //PERF_INSTANCE_DEFINITIONの //ParentObjectTitleIndex値 DWORD *pdwParentInstIdx = NULL; //PERF_INSTANCE_DEFINITIONの //ParentObjectInstance値の //配列(要素を動的に確保) DWORD dwNumParentInst = 0; //pdwParentInstIdxの要素数 DWORD dwInstIdx = 0; //インスタンスIndexカウンタ PERF_INSTANCE_DEFINITION *pReturn = NULL; if (! pPerfData || ! pPerfObject) return NULL; if (pPerfObject->NumInstances <= 0) //インスタンスがない時 return NULL; if (! m_pszInstance) return NULL; //親インスタンスのインスタンス数を取得 if ( GetParentObjInstIdx(pPerfObject, pPerfData, &dwParentObjIdx, NULL, &dwNumParentInst) ) { pdwParentInstIdx = new DWORD[dwNumParentInst]; //インスタンスの親オブジェクトIndex, 親インスタンスIndexの配列取得 GetParentObjInstIdx(pPerfObject, pPerfData, &dwParentObjIdx, pdwParentInstIdx, &dwNumParentInst); } //最初のインスタンス pPerfInst = (PPERF_INSTANCE_DEFINITION) ((PBYTE)pPerfObject + pPerfObject->DefinitionLength); for (int i=0; i<pPerfObject->NumInstances; i++) { //インスタンス名一致 if (_tcsicmp( m_pszInstance, (TCHAR *)((PBYTE)pPerfInst + pPerfInst->NameOffset)) == 0 ) { //親インスタンスあり if (pPerfInst->ParentObjectTitleIndex > 0) { //親インスタンス一致 if (pPerfInst->ParentObjectTitleIndex == dwParentObjIdx && MatchParentInstIdx(pPerfInst->ParentObjectInstance, pdwParentInstIdx, dwNumParentInst) ) { if (m_dwInstIdx == -1) //単一インスタンス { pReturn = pPerfInst; break; } else //マルチインスタンス { if (m_dwInstIdx == dwInstIdx) //マルチインスタンスIndex一致 { pReturn = pPerfInst; break; } else //マルチインスタンスIndex不一致 { dwInstIdx++; } } } //親インスタンスなし } else { if (m_dwInstIdx == -1) //単一インスタンス { pReturn = pPerfInst; break; } else //マルチインスタンス { if (m_dwInstIdx == dwInstIdx) //マルチインスタンスIndex一致 { pReturn = pPerfInst; break; } else //マルチインスタンスIndex不一致 { dwInstIdx++; } } } } //インスタンス名一致 //次のインスタンス pCntrBlock = (PPERF_COUNTER_BLOCK)((PBYTE)pPerfInst + pPerfInst->ByteLength); pPerfInst = (PPERF_INSTANCE_DEFINITION) ((PBYTE)pCntrBlock + pCntrBlock->ByteLength); } //インスタンスイテレーション if (pdwParentInstIdx) { delete [] pdwParentInstIdx; pdwParentInstIdx = NULL; } return pReturn; } /*カウンタベース値/高精度タイムスタンプの取得 引数 pPerfCounter 取得対象カウンタ定義へのポインタ pCntrBlock 対象オブジェクトのカウンタデータ先頭へのポインタ 戻値 カウンタベースがあるカウンタタイプに関しては未処理カウンタベース値を返却 カウンタベースがない場合やエラー時は0*/ LONGLONG CPerfMoniReg::GetBasePrecisionCounter(const PERF_COUNTER_DEFINITION *pPerfCounter, const PERF_COUNTER_BLOCK *pCntrBlock) { //ベースカウンタ/Precisionタイムスタンプへのポインタ PERF_COUNTER_DEFINITION *pPerfBasePrecCntr = NULL; //pPerfCounterがベースカウンタ又はPrecisionタイムスタンプを //必要としているカウンタかどうか BOOL bMatchType = FALSE; //ベースカウンタ,Precisionタイムスタンプ値へのポインタ void *pBasePrecisionCounterVal = NULL; LONGLONG largeReturn = 0; //カウンタベースを使用するカウンタタイプかの確認 switch (pPerfCounter->CounterType) { //カウンタベースに依存するカウンタタイプ case PERF_AVERAGE_BULK: case PERF_AVERAGE_TIMER: case PERF_100NSEC_MULTI_TIMER: case PERF_100NSEC_MULTI_TIMER_INV: case PERF_COUNTER_MULTI_TIMER: case PERF_COUNTER_MULTI_TIMER_INV: case PERF_RAW_FRACTION: case PERF_SAMPLE_FRACTION: case PERF_LARGE_RAW_FRACTION: break; //高精度なサンプリング時間が必要なカウンタタイプ case PERF_PRECISION_SYSTEM_TIMER: case PERF_PRECISION_100NS_TIMER: case PERF_PRECISION_OBJECT_TIMER: break; default: return largeReturn; } //ベースカウンタのPERF_COUNTER_DEFINITIONの取得 //(取得対象カウンタの次のカウンタがベースカウンタ, //又はPERF_PRECISION_TIMESTAMPタイプのカウンタ) pPerfBasePrecCntr = (PPERF_COUNTER_DEFINITION) ((PBYTE)pPerfCounter + pPerfCounter->ByteLength); //カウンタベース/Precisionタイプのカウンタタイプの確認 switch (pPerfCounter->CounterType) { case PERF_AVERAGE_BULK: case PERF_AVERAGE_TIMER: if (pPerfBasePrecCntr->CounterType == PERF_AVERAGE_BASE) bMatchType = TRUE; break; case PERF_100NSEC_MULTI_TIMER: case PERF_100NSEC_MULTI_TIMER_INV: case PERF_COUNTER_MULTI_TIMER: case PERF_COUNTER_MULTI_TIMER_INV: if (pPerfBasePrecCntr->CounterType == PERF_COUNTER_MULTI_BASE) bMatchType = TRUE; break; case PERF_RAW_FRACTION: if (pPerfBasePrecCntr->CounterType == PERF_RAW_BASE) bMatchType = TRUE; break; case PERF_SAMPLE_FRACTION: if (pPerfBasePrecCntr->CounterType == PERF_SAMPLE_BASE) bMatchType = TRUE; break; case PERF_LARGE_RAW_FRACTION: if (pPerfBasePrecCntr->CounterType == PERF_LARGE_RAW_BASE) bMatchType = TRUE; break; //サンプリング時間に高精度が必要なカウンタタイプ case PERF_PRECISION_SYSTEM_TIMER: case PERF_PRECISION_100NS_TIMER: case PERF_PRECISION_OBJECT_TIMER: if (pPerfBasePrecCntr->CounterType == PERF_PRECISION_TIMESTAMP) bMatchType = TRUE; break; } if (! bMatchType) return largeReturn; //カウンタベース/Precisionタイプの先頭位置 pBasePrecisionCounterVal = (PBYTE)pCntrBlock + pPerfBasePrecCntr->CounterOffset; //カウンタベース/Precisionタイプのサイズ switch (pPerfBasePrecCntr->CounterType & 0x00000300) { case PERF_SIZE_DWORD: case PERF_SIZE_VARIABLE_LEN: largeReturn = *((DWORD *)pBasePrecisionCounterVal); break; case PERF_SIZE_LARGE: largeReturn = *((LONGLONG *)pBasePrecisionCounterVal); break; //case PERF_SIZE_ZERO: default: break; } return largeReturn; } /*カウンタデータ計算 (メンバm_NewRawCntr, m_OldRawCntrからカウンタタイプによって 異なる計算方法でカウンタ値を計算) 引数 pPerfCounter 取得対象カウンタ定義へのポインタ(カウンタタイプが含まれている) counterval 計算後の結果出力するCOUNTER_VAL型の参照 戻値 pPerfCounterが指すカウンタタイプがwinperf.h内に存在し、かつ計算が正常に行われて countervalに出力できた時はTRUE, それ以外はFALSE(countervalのすべての値は)*/ BOOL CPerfMoniReg::CalculateCounter(IN const PERF_COUNTER_DEFINITION *pPerfCounter, OUT COUNTER_VAL &counterval) { BOOL bRet = FALSE; //初期化 ::memset(&counterval, 0, sizeof(COUNTER_VAL)); //カウンタタイプ取得 counterval.dwCouterType = pPerfCounter->CounterType; //カウンタ計算 switch (pPerfCounter->CounterType) { case PERF_COUNTER_COUNTER : //(ex)PhysicalDisk\Disk Transfers/sec case PERF_COUNTER_BULK_COUNT : //(ex)System\File Read Bytes/sec case PERF_SAMPLE_COUNTER : if ( m_NewRawCntr.PerfFreq.QuadPart != 0 && m_NewRawCntr.PerfTime.QuadPart - m_OldRawCntr.PerfTime.QuadPart != 0 ) { double dblTime = ( (double)m_NewRawCntr.PerfTime.QuadPart - (double)m_OldRawCntr.PerfTime.QuadPart ) / (double)m_NewRawCntr.PerfFreq.QuadPart; counterval.doubleValue = ((double)m_NewRawCntr.CounterVal - (double)m_OldRawCntr.CounterVal) / dblTime; //表示フォーマット counterval.fmtCounter = FMT_DOUBLE; bRet = TRUE; } break; case PERF_COUNTER_TIMER : //(ex).Net CLR Loading\% Time Loading if (m_NewRawCntr.PerfTime.QuadPart - m_OldRawCntr.PerfTime.QuadPart != 0) { double dblCntr = (double)m_NewRawCntr.CounterVal - (double)m_OldRawCntr.CounterVal; double dblTime = (double)m_NewRawCntr.PerfTime.QuadPart - (double)m_OldRawCntr.PerfTime.QuadPart; counterval.doubleValue = 100 * dblCntr / dblTime; //表示フォーマット counterval.fmtCounter = FMT_DOUBLE; bRet = TRUE; } break; case PERF_COUNTER_QUEUELEN_TYPE : case PERF_COUNTER_LARGE_QUEUELEN_TYPE : case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE : case PERF_OBJ_TIME_TIMER : if (m_NewRawCntr.PerfTime.QuadPart - m_OldRawCntr.PerfTime.QuadPart != 0) { double dblCntr = (double)m_NewRawCntr.CounterVal - (double)m_OldRawCntr.CounterVal; double dblTime = (double)m_NewRawCntr.PerfTime.QuadPart - (double)m_OldRawCntr.PerfTime.QuadPart; counterval.doubleValue = dblCntr / dblTime; //表示フォーマット counterval.fmtCounter = FMT_DOUBLE; bRet = TRUE; } break; case PERF_COUNTER_100NS_QUEUELEN_TYPE : //(ex)PhysicalDisk\Avg. Disk Queue Length if (m_NewRawCntr.PerfTime100nSec.QuadPart - m_OldRawCntr.PerfTime100nSec.QuadPart != 0) { double dblCntr = (double)m_NewRawCntr.CounterVal - (double)m_OldRawCntr.CounterVal; double dblTime = (double)m_NewRawCntr.PerfTime100nSec.QuadPart - (double)m_OldRawCntr.PerfTime100nSec.QuadPart; counterval.doubleValue = dblCntr / dblTime; //表示フォーマット counterval.fmtCounter = FMT_DOUBLE; bRet = TRUE; } break; case PERF_COUNTER_TEXT : if (pPerfCounter->CounterSize > 0) { LPTSTR pszBuf = (LPTSTR) new BYTE[pPerfCounter->CounterSize + 2]; if (_tcscpy_s(pszBuf, pPerfCounter->CounterSize + 2, reinterpret_cast<LPTSTR>(m_NewRawCntr.CounterVal)) != 0 ) { delete [] pszBuf; pszBuf = NULL; break; } if (m_pszTextBuffer) { delete [] m_pszTextBuffer; m_pszTextBuffer = NULL; } m_pszTextBuffer = pszBuf; counterval.wideStringValue = m_pszTextBuffer; //表示フォーマット counterval.fmtCounter = FMT_WIDESTRING; bRet = TRUE; } break; case PERF_COUNTER_RAWCOUNT : //(ex)LogicalDisk\Free Megabytes case PERF_COUNTER_RAWCOUNT_HEX : //(ex)Thread\Start Address counterval.longValue = static_cast<LONG>(m_NewRawCntr.CounterVal); //表示フォーマット counterval.fmtCounter = FMT_LONG; bRet = TRUE; break; case PERF_COUNTER_LARGE_RAWCOUNT : //(ex)Memory\Available Bytes case PERF_COUNTER_LARGE_RAWCOUNT_HEX : counterval.largeValue = m_NewRawCntr.CounterVal; //表示フォーマット counterval.fmtCounter = FMT_LONGLONG; bRet = TRUE; break; case PERF_SAMPLE_FRACTION : //(ex)Cache\Pin Read Hits % if (m_NewRawCntr.BasePrecisionVal - m_OldRawCntr.BasePrecisionVal != 0) { double dblBase = (double)m_NewRawCntr.BasePrecisionVal - (double)m_OldRawCntr.BasePrecisionVal; double dblCntr = (double)m_NewRawCntr.CounterVal - (double)m_OldRawCntr.CounterVal; counterval.doubleValue = 100 * dblCntr / dblBase; //表示フォーマット counterval.fmtCounter = FMT_DOUBLE; bRet = TRUE; } break; case PERF_COUNTER_TIMER_INV : if (m_NewRawCntr.PerfTime.QuadPart - m_OldRawCntr.PerfTime.QuadPart != 0) { double dblCntr = (double)m_NewRawCntr.CounterVal - (double)m_OldRawCntr.CounterVal; double dblTime = (double)m_NewRawCntr.PerfTime.QuadPart - (double)m_OldRawCntr.PerfTime.QuadPart; counterval.doubleValue = 100 * ( (double)1 - dblCntr / dblTime ); //表示フォーマット counterval.fmtCounter = FMT_DOUBLE; bRet = TRUE; } break; case PERF_AVERAGE_TIMER : //(ex)PhysicalDisk\Avg. Disk sec/Transfer if (m_NewRawCntr.PerfFreq.QuadPart != 0 && m_NewRawCntr.BasePrecisionVal - m_OldRawCntr.BasePrecisionVal != 0 ) { double dblCntr = (double)m_NewRawCntr.CounterVal - (double)m_OldRawCntr.CounterVal; double dblBase = (double)m_NewRawCntr.BasePrecisionVal - (double)m_OldRawCntr.BasePrecisionVal; counterval.doubleValue = (dblCntr / (double)m_NewRawCntr.PerfFreq.QuadPart) / dblBase; //表示フォーマット counterval.fmtCounter = FMT_DOUBLE; bRet = TRUE; } break; case PERF_AVERAGE_BULK : //(ex)PhysicalDisk\Avg. Disk Bytes/Transfer if (m_NewRawCntr.BasePrecisionVal - m_OldRawCntr.BasePrecisionVal != 0) { double dblCntr = (double)m_NewRawCntr.CounterVal - (double)m_OldRawCntr.CounterVal; double dblBase = (double)m_NewRawCntr.BasePrecisionVal - (double)m_OldRawCntr.BasePrecisionVal; counterval.doubleValue = dblCntr / dblBase; //表示フォーマット counterval.fmtCounter = FMT_DOUBLE; bRet = TRUE; } break; case PERF_100NSEC_TIMER : //(ex)Processor\% User Time if (m_NewRawCntr.PerfTime100nSec.QuadPart - m_OldRawCntr.PerfTime100nSec.QuadPart != 0) { double dblCntr = (double)m_NewRawCntr.CounterVal - (double)m_OldRawCntr.CounterVal; double dblTime = (double)m_NewRawCntr.PerfTime100nSec.QuadPart - (double)m_OldRawCntr.PerfTime100nSec.QuadPart; counterval.doubleValue = 100 * dblCntr / dblTime; //表示フォーマット counterval.fmtCounter = FMT_DOUBLE; bRet = TRUE; } break; case PERF_100NSEC_TIMER_INV : //(ex)Processor\% Processor Time if (m_NewRawCntr.PerfTime100nSec.QuadPart - m_OldRawCntr.PerfTime100nSec.QuadPart != 0) { double dblCntr = (double)m_NewRawCntr.CounterVal - (double)m_OldRawCntr.CounterVal; double dblTime = (double)m_NewRawCntr.PerfTime100nSec.QuadPart - (double)m_OldRawCntr.PerfTime100nSec.QuadPart; counterval.doubleValue = 100 * ( (double)1 - dblCntr / dblTime ); //表示フォーマット counterval.fmtCounter = FMT_DOUBLE; bRet = TRUE; } break; case PERF_COUNTER_MULTI_TIMER : do { if (m_NewRawCntr.PerfFreq.QuadPart == 0 || m_NewRawCntr.BasePrecisionVal == 0) break; double dblTime = ( (double)m_NewRawCntr.PerfTime.QuadPart - (double)m_OldRawCntr.PerfTime.QuadPart ) / (double)m_NewRawCntr.PerfFreq.QuadPart; if (dblTime == 0) break; double dblCntr = (double)m_NewRawCntr.CounterVal - (double)m_OldRawCntr.CounterVal; dblCntr /= dblTime; counterval.doubleValue = 100 * dblCntr / (double)m_NewRawCntr.BasePrecisionVal; //表示フォーマット counterval.fmtCounter = FMT_DOUBLE; bRet = TRUE; } while(0); break; case PERF_COUNTER_MULTI_TIMER_INV : do { if (m_NewRawCntr.PerfFreq.QuadPart == 0 || m_NewRawCntr.BasePrecisionVal == 0) break; double dblTime = ( (double)m_NewRawCntr.PerfTime.QuadPart - (double)m_OldRawCntr.PerfTime.QuadPart ) / (double)m_NewRawCntr.PerfFreq.QuadPart; if (dblTime == 0) break; double dblCntr = (double)m_NewRawCntr.CounterVal - (double)m_OldRawCntr.CounterVal; dblCntr /= dblTime; dblCntr = (double)m_NewRawCntr.BasePrecisionVal - dblCntr; counterval.doubleValue = 100 * dblCntr / (double)m_NewRawCntr.BasePrecisionVal; //表示フォーマット counterval.fmtCounter = FMT_DOUBLE; bRet = TRUE; } while(0); break; case PERF_100NSEC_MULTI_TIMER : do { if ( m_NewRawCntr.PerfTime100nSec.QuadPart - m_OldRawCntr.PerfTime100nSec.QuadPart == 0 || m_NewRawCntr.BasePrecisionVal == 0 ) break; double dblTime = (double)m_NewRawCntr.PerfTime100nSec.QuadPart - (double)m_OldRawCntr.PerfTime100nSec.QuadPart; double dblCntr = (double)m_NewRawCntr.CounterVal - (double)m_OldRawCntr.CounterVal; dblCntr /= dblTime; counterval.doubleValue = 100 * dblCntr / (double)m_NewRawCntr.BasePrecisionVal; //表示フォーマット counterval.fmtCounter = FMT_DOUBLE; bRet = TRUE; } while(0); break; case PERF_100NSEC_MULTI_TIMER_INV : do { if ( m_NewRawCntr.PerfTime100nSec.QuadPart - m_OldRawCntr.PerfTime100nSec.QuadPart == 0 || m_NewRawCntr.BasePrecisionVal == 0 ) break; double dblTime = (double)m_NewRawCntr.PerfTime100nSec.QuadPart - (double)m_OldRawCntr.PerfTime100nSec.QuadPart; double dblCntr = (double)m_NewRawCntr.CounterVal - (double)m_OldRawCntr.CounterVal; dblCntr /= dblTime; dblCntr = (double)m_NewRawCntr.BasePrecisionVal - dblCntr; counterval.doubleValue = 100 * dblCntr / (double)m_NewRawCntr.BasePrecisionVal; //表示フォーマット counterval.fmtCounter = FMT_DOUBLE; bRet = TRUE; } while(0); break; case PERF_RAW_FRACTION : //(ex)Paging File\% Usage Peak case PERF_LARGE_RAW_FRACTION : //(ex)MSSQL$SQLEXPRESS:Buffer Manager // \Buffer cache hit ratio if (m_NewRawCntr.BasePrecisionVal != 0) { counterval.doubleValue = 100 * (double)m_NewRawCntr.CounterVal / (double)m_NewRawCntr.BasePrecisionVal; //表示フォーマット counterval.fmtCounter = FMT_DOUBLE; bRet = TRUE; } break; case PERF_ELAPSED_TIME : //(ex)System\System Up Time if (m_NewRawCntr.PerfFreq.QuadPart != 0) { double dblCntr = (double)m_NewRawCntr.PerfTime.QuadPart - (double)m_NewRawCntr.CounterVal; counterval.doubleValue = dblCntr / (double)m_NewRawCntr.PerfFreq.QuadPart; //表示フォーマット counterval.fmtCounter = FMT_DOUBLE; bRet = TRUE; } break; case PERF_COUNTER_DELTA : counterval.longValue = (LONG)(m_NewRawCntr.CounterVal - m_OldRawCntr.CounterVal); //表示フォーマット counterval.fmtCounter = FMT_LONG; bRet = TRUE; break; case PERF_COUNTER_LARGE_DELTA : counterval.largeValue = m_NewRawCntr.CounterVal - m_OldRawCntr.CounterVal; //表示フォーマット counterval.fmtCounter = FMT_LONGLONG; bRet = TRUE; break; case PERF_PRECISION_100NS_TIMER : //(ex)PhysicalDisk\% Disk Time case PERF_PRECISION_SYSTEM_TIMER : case PERF_PRECISION_OBJECT_TIMER : if (m_NewRawCntr.BasePrecisionVal - m_OldRawCntr.BasePrecisionVal != 0) { double dblCntr = (double)m_NewRawCntr.CounterVal - (double)m_OldRawCntr.CounterVal; double dblBase = (double)m_NewRawCntr.BasePrecisionVal - (double)m_OldRawCntr.BasePrecisionVal; counterval.doubleValue = 100 * dblCntr / dblBase; //表示フォーマット counterval.fmtCounter = FMT_DOUBLE; bRet = TRUE; } break; case PERF_COUNTER_NODATA : bRet = TRUE; break; } return bRet; } /*カウンタデータ取得 引数 counterval カウンタ値の結果出力 戻値 カウンタデータが取得できたときはTRUE, 失敗時FALSE (失敗時はcountervalの各メンバはすべて0)*/ BOOL CPerfMoniReg::GetCounterValue(OUT COUNTER_VAL &counterval) { PERF_DATA_BLOCK *pPerfData = NULL; //取得対象のカウンタオブジェクトを含む //PERF_DATA_BLOCKへのポインタ PERF_OBJECT_TYPE *pPerfObject = NULL; //取得対象のカウンタオブジェクト PERF_COUNTER_DEFINITION *pTempCounter = NULL; //取得対象カウンタ検索用 PERF_COUNTER_DEFINITION *pPerfCounter = NULL; //取得対象カウンタ PERF_INSTANCE_DEFINITION *pPerfInst = NULL; //取得対象インスタンス PERF_COUNTER_BLOCK *pCntrBlock = NULL; //カウンタデータの先頭へのポインタ RAW_COUNTER_VAL rawcounter; //最新の未処理カウンタ値取得用 void *pCounterVal = NULL; //取得対象pCntrBlockの //カウンタ値へのポインタ ::memset(&counterval, 0, sizeof(COUNTER_VAL)); BOOL bRet = FALSE; do { if (! m_dwObjectIdx) break; //パフォーマンスデータ/オブジェクト取得 if (! GetPerfObjectDef(&pPerfData, &pPerfObject) ) break; //カウンタDefinition取得 pTempCounter = (PPERF_COUNTER_DEFINITION) ((PBYTE)pPerfObject + pPerfObject->HeaderLength); for (DWORD i=0; i<pPerfObject->NumCounters; i++) { if (m_dwCounterIdx == pTempCounter->CounterNameTitleIndex) { pPerfCounter = pTempCounter; break; } //次のカウンタ pTempCounter = (PPERF_COUNTER_DEFINITION) ((PBYTE)pTempCounter + pTempCounter->ByteLength); } if (! pPerfCounter) break; //インスタンスDefinition取得(インスタンスがある場合) if (pPerfObject->NumInstances > 0) //インスタンスあり { pPerfInst = SpecifyInstanceDef(pPerfObject, pPerfData); if (! pPerfInst) break; pCntrBlock = (PPERF_COUNTER_BLOCK)((PBYTE)pPerfInst + pPerfInst->ByteLength); } else //インスタンスなし { pCntrBlock = (PPERF_COUNTER_BLOCK) ((PBYTE)pPerfObject + pPerfObject->DefinitionLength); } //未処理データ取得用変数初期化 ::memset(&rawcounter, 0, sizeof(RAW_COUNTER_VAL)); //カウンタデータの先頭位置 pCounterVal = (PBYTE)pCntrBlock + pPerfCounter->CounterOffset; //-------------------------------------------------------------------- //カウンタデータの取得(rawcounterの各メンバの値取得) //(カウンタのデータサイズにより取得変更) switch (pPerfCounter->CounterType & 0x00000300) { case PERF_SIZE_DWORD: rawcounter.CounterVal = *((DWORD *)pCounterVal); break; case PERF_SIZE_LARGE: rawcounter.CounterVal = *((LONGLONG *)pCounterVal); break; case PERF_SIZE_VARIABLE_LEN: rawcounter.CounterVal = reinterpret_cast<LONGLONG>(pCounterVal); break; //case PERF_SIZE_ZERO: default: break; } //100 ナノ秒単位のサンプリング時間取得 rawcounter.PerfTime100nSec = pPerfData->PerfTime100nSec; //サンプリング時間/サンプリング周波数取得。 if ( (pPerfCounter->CounterType & 0x00300000) == PERF_OBJECT_TIMER ) { rawcounter.PerfTime = pPerfObject->PerfTime; rawcounter.PerfFreq = pPerfObject->PerfFreq; }else { rawcounter.PerfTime = pPerfData->PerfTime; rawcounter.PerfFreq = pPerfData->PerfFreq; } //カウンタベース/PERF_PRECISION_TIMESTAMPタイプのカウンタ値の取得 rawcounter.BasePrecisionVal = GetBasePrecisionCounter(pPerfCounter, pCntrBlock); //------------------------------------------------------------------------------ //メンバ変数に新旧データ入れ替え m_OldRawCntr = m_NewRawCntr; m_NewRawCntr = rawcounter; //Rawカウンタデータ(m_NewRawCntr, m_OldRawCntr)を使ってカウンタタイプに従って計算 if (! CalculateCounter(pPerfCounter, counterval)) break; bRet = TRUE; } while(0); if (pPerfData) delete [] pPerfData; return bRet; } |
以上でCPerfMoniRegの実装ができたので、これを使ってモニタしてみます。 プロジェクトを作成したときにできた、_tmain関数に以下のように記述してください。
// xxxxx.cpp : コンソールアプリケーションのエントリポイントを定義します。 // #include "stdafx.h" #include "PerfMoniReg.h" int _tmain(int argc, _TCHAR* argv[]) { CPerfMoniReg perfmonireg; int nErr = 0; static int i = 0; if (! perfmonireg.Initialize( _T("Processor"), _T("% Processor Time"), _T("_Total"), NULL, -1 ) ) { _tprintf(_T("Fail! Initialize Function\n")); return 1; } for (int k=0; k<50; k++) { COUNTER_VAL counterval; if (! perfmonireg.GetCounterValue(counterval) ) { _tprintf(_T("Can't Get Counter Data!")); nErr = 1; break; } if (counterval.fmtCounter == FMT_WIDESTRING) _tprintf(_T("counter_val%i [%s]\n"), ++i, counterval.wideStringValue); else if (counterval.fmtCounter == FMT_DOUBLE) _tprintf(_T("counter_val%i [%f]\n"), ++i, counterval.doubleValue); else if (counterval.fmtCounter == FMT_LONG) { //Numberタイプかつ16進数表示 if (!(counterval.dwCouterType & 0x00000C00) && !(counterval.dwCouterType & 0x000F0000)) _tprintf(_T("counter_val%i [%x]\n"), ++i, counterval.longValue); else _tprintf(_T("counter_val%i [%d]\n"), ++i, counterval.longValue); } else if (counterval.fmtCounter == FMT_LONGLONG) { //Numberタイプかつ16進数表示 if (!(counterval.dwCouterType & 0x00000C00) && !(counterval.dwCouterType & 0x000F0000)) _tprintf(_T("counter_val%i [%I64x]\n"), ++i, counterval.largeValue); else _tprintf(_T("counter_val%i [%I64d]\n"), ++i, counterval.largeValue); } else _tprintf(_T("Unknown %i\n"), ++i); ::Sleep(1000); } return nErr; } |
上記を実行するとプロセッサの使用率が1秒間隔で 20回表示されると思います。他のカウンタでもいろいろ試してみて下さい。 PDH系のAPIに例えると、CPerfMoniRegクラス1つでPdhMakeCounterPath、PdhGetRawCounterValueや PdhGetFormattedCounterValueなどの機能を詰め込んでいるとはいえ、かなり面倒です。 理屈がわかっていればPdh系APIを使ったほうがいいでしょうが、ここまでできるようになると、 あと少しの知識でカスタムなパフォーマンスカウンタを作れるようになるので、 そこまでやろうとされている方はレジストリインターフェイスでのパフォーマンスデータの 取得方法を理解されるのがいいでしょう。 もし、今度書く機会があれば独自のパフォーマンスカウンタを作成してみたいと思います。
[参考文献]
Windows Server 2003 Performance Counters Reference
http://technet.microsoft.com/ja-jp/library/cc776490(WS.10).aspx
未処理カウンタ データの計算
http://msdn.microsoft.com/ja-jp/library/cc366080.aspx