(C++)自プロセスのCPU使用率をプログラムで計算したい
Posted: 2014年7月19日(土) 16:01
こんにちは。Kettyです(^^)
C++で自プロセス(DXライブラリを使用したアプリ)のCPU使用率(%)を求めたく、
PDHカウンタでクエリ発行して取得するというやり方を以下URLを参考に、
CPU使用率をウィンドウ内に表示するように実装してみました。
http://eternalwindows.jp/windevelop/pdh/pdh05.html
http://atelier-peppe.jp/programTips/MFC/MFC_26.html
しかし、タスクマネージャーのプロセスタブのCPU列に表示される値とマッチしません。
マッチさせたいのですが、どこが間違っていますか?
あるいは、考え方自体が誤っておりますか?
OS:Windows 7 64bit Home Edition
Visual Studio2010 Express Edition
※DXライブラリを使用しています
以下、ソースとなります。
およそ0.5秒おきに、自プロセスとtotalのそれぞれのPDHカウンタ値を採取して、CPU使用率を算出しています。
マルチコアにも対応するためにはtotalで割る必要があると以下に記されていたので割り算しています。
http://ameblo.jp/led-sue/entry-10896834648.html
これを実行しますと、私の環境では
タスクマネージャーのプロセスタブのCPU列では00~01が表示されますが、
アプリのウィンドウ内には3.1~9.5などという値が表示されてしまいます。
よろしくお願いします。
C++で自プロセス(DXライブラリを使用したアプリ)のCPU使用率(%)を求めたく、
PDHカウンタでクエリ発行して取得するというやり方を以下URLを参考に、
CPU使用率をウィンドウ内に表示するように実装してみました。
http://eternalwindows.jp/windevelop/pdh/pdh05.html
http://atelier-peppe.jp/programTips/MFC/MFC_26.html
しかし、タスクマネージャーのプロセスタブのCPU列に表示される値とマッチしません。
マッチさせたいのですが、どこが間違っていますか?
あるいは、考え方自体が誤っておりますか?
OS:Windows 7 64bit Home Edition
Visual Studio2010 Express Edition
※DXライブラリを使用しています
以下、ソースとなります。
およそ0.5秒おきに、自プロセスとtotalのそれぞれのPDHカウンタ値を採取して、CPU使用率を算出しています。
マルチコアにも対応するためにはtotalで割る必要があると以下に記されていたので割り算しています。
http://ameblo.jp/led-sue/entry-10896834648.html
#include <vector>
#include <pdh.h>
#pragma comment(lib, "pdh.lib")
#include <DxLib.h>
using namespace std ;
// 画面サイズ
static const int SCREEN_W = 640 ;
static const int SCREEN_H = 480 ;
// FPS
static const int FPS = 60 ;
// CPU使用率再計測時間(秒)
static const int CPU_UPDATE_TIME = FPS * 0.5 ; // だいたい0.5秒ごとに更新してみる
// FPS管理クラス
// Dixqさんのものを移植しただけです dixq.net/rp/43.html
class FpsManager
{
public:
// コンストラクタ
FpsManager()
{
// 初期化
vecRecord_.resize( FPS, 0 ) ;
frameCounter_ = 0 ;
base0tCounter_ = 0 ;
//average_ = 0 ;
}
// デストラクタ
~FpsManager(){}
// FPSを調整する
void Adjust()
{
// この関数内部で使うタイミング変数
static int timing_ = 0 ;
// 待つべき時間を求める
int waitMillisecond = 0 ;
// 60フレーム中の1フレーム目のとき
if( frameCounter_ == 0 )
{
// 完全に最初なら
if( timing_ == 0 )
{
// 待つべき時間=なし
waitMillisecond = 0 ;
}
else
{
// 待つべき時間=前回記録した時間を元に計算
waitMillisecond = base0tCounter_ + 1000 - DxLib::GetNowCount() ;
}
}
// 上記以外のとき
else
{
// 待つべき時間=現在あるべき時刻-現在の時刻
waitMillisecond = static_cast<int>( base0tCounter_ + frameCounter_ * ( 1000.0 / FPS ) ) - DxLib::GetNowCount() ;
}
// 待つべき時間だけ待つ
if( waitMillisecond > 0 )
{
Sleep( waitMillisecond ) ;
}
// 現在時間を取得
const int gnt = DxLib::GetNowCount() ;
// 60フレームに1度基準を作る
if( frameCounter_ == 0 )
{
base0tCounter_ = gnt ;
}
//1周した時間を記録
vecRecord_[frameCounter_] = gnt - timing_ ;
// タイミング更新
timing_ = gnt ;
// 60フレーム中の最終フレームのときのみ平均計算
if( frameCounter_ == FPS - 1 )
{
average_ = 0;
for( int i=0; i<FPS; ++i )
{
average_ += vecRecord_[i] ;
}
average_ /= FPS ;
}
// フレームカウンタ更新
frameCounter_ = ( ++frameCounter_ ) % FPS ;
}
// FPS測定値を取得する
double GetFps()
{
if( average_ > 0 )
{
return 1000.0 / average_ ;
}
else
{
return 0.0 ;
}
}
private :
// 平均を計算するための記録用変数(60回の1周時間を記録)
vector<int> vecRecord_ ;
// フレームのカウンタ
int frameCounter_ ;
// 60フレームに1回基準となる時刻を記録する変数
int base0tCounter_ ;
// 平均fps
double average_ ;
} ;
// CPU使用率管理クラス
class CpuManager
{
public:
// コンストラクタ
CpuManager() : isInitSuccess_( false )
{
cpuUseRate_ = 0.0 ;
//--------------------------------------
// 自プロセスのクエリデータを生成
//--------------------------------------
queryDataOwn_ = new QUERY_DATA ;
// 新規クエリを作成
PdhOpenQuery( NULL, 0, &queryDataOwn_->hQuery ) ;
PdhAddCounter( queryDataOwn_->hQuery, TEXT( "\\Process(CpuUseRateTest)\\% Processor Time" ), 0, &queryDataOwn_->hCounter ) ;
// この時点での値を取得
PdhGetRawCounterValue( queryDataOwn_->hCounter, NULL, &queryDataOwn_->rawValueStack ) ;
//--------------------------------------
// Totalのクエリデータを生成
//--------------------------------------
queryDataTotal_ = new QUERY_DATA ;
// 新規クエリを作成
PdhOpenQuery( NULL, 0, &queryDataTotal_->hQuery ) ;
PdhAddCounter( queryDataTotal_->hQuery, TEXT( "\\Process(_Total)\\% Processor Time" ), 0, &queryDataTotal_->hCounter ) ;
// この時点での値を取得
PdhGetRawCounterValue( queryDataTotal_->hCounter, NULL, &queryDataTotal_->rawValueStack ) ;
// 初期化成功
isInitSuccess_ = true ;
}
// デストラクタ
~CpuManager()
{
// 後始末
PdhCloseQuery( queryDataOwn_ ) ;
PdhCloseQuery( queryDataTotal_ ) ;
delete queryDataOwn_ ;
delete queryDataTotal_ ;
}
// 更新する
void Update()
{
// 初期化失敗していれば処理しない
if( isInitSuccess_ == false ){ return ; }
// 現在値
PDH_RAW_COUNTER rawValue ;
//--------------------------------------
// 自プロセスのデータを更新
//--------------------------------------
// データ収集
PdhCollectQueryData( queryDataOwn_->hQuery ) ;
// この時点での値を取得
PdhGetRawCounterValue( queryDataOwn_->hCounter, NULL, &rawValue ) ;
// この時点での値と前回の値から計測して結果をdouble型にフォーマットする
PdhCalculateCounterFromRawValue( queryDataOwn_->hCounter, PDH_FMT_DOUBLE, &rawValue, &queryDataOwn_->rawValueStack, &queryDataOwn_->fmtValue ) ;
// この時点での値を保持
queryDataOwn_->rawValueStack = rawValue ;
//--------------------------------------
// Totalのデータを更新
//--------------------------------------
// データ収集
PdhCollectQueryData( queryDataTotal_->hQuery ) ;
// この時点での値を取得
PdhGetRawCounterValue( queryDataTotal_->hCounter, NULL, &rawValue ) ;
// この時点での値と前回の値から計測して結果をdouble型にフォーマットする
PdhCalculateCounterFromRawValue( queryDataTotal_->hCounter, PDH_FMT_DOUBLE, &rawValue, &queryDataTotal_->rawValueStack, &queryDataTotal_->fmtValue ) ;
// この時点での値を保持
queryDataTotal_->rawValueStack = rawValue ;
// CPU使用率をパーセントで設定する
const double own = queryDataOwn_->fmtValue.doubleValue ;
const double total = queryDataTotal_->fmtValue.doubleValue ;
cpuUseRate_ = ( own / total ) * 100 ; // 自プロセスの使用率÷Totalの使用率
}
// CPU使用率をパーセントで取得する
double GetCpuUseRate()
{
return cpuUseRate_ ;
}
private :
// PDHクエリ関連をまとめるための構造体
struct QUERY_DATA
{
PDH_HQUERY hQuery ; // クエリ
PDH_HCOUNTER hCounter ; // クエリで取得する項目を表すオブジェクト
PDH_RAW_COUNTER rawValueStack ; // 現在値(最新値)を保持する変数
PDH_FMT_COUNTERVALUE fmtValue ; // 現在値と前回値とを比較して得られる値
} ;
// PDHクエリデータ
QUERY_DATA *queryDataOwn_ ; // 自プロセスのProcessor Time(CPU使用率)
QUERY_DATA *queryDataTotal_ ; // TotalのProcessor Time(CPU使用率)
// CPU使用率(%)
double cpuUseRate_ ;
// 初期化成功フラグ
bool isInitSuccess_ ;
};
// Main関数
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
// DXライブラリのログ出力をしない
DxLib::SetOutApplicationLogValidFlag( FALSE ) ;
// ウィンドウモードで起動
DxLib::ChangeWindowMode( TRUE ) ;
// 画面モード設定
DxLib::SetGraphMode( SCREEN_W, SCREEN_H, 32 ) ;
// ウィンドウを最小化しても常に動くようにする
DxLib::SetAlwaysRunFlag( TRUE ) ;
// DXライブラリ初期化処理
if( DxLib::DxLib_Init() == -1 ){ return -1 ; }
// 画像を読み込み
int graphHandle = DxLib::LoadGraph( "Test1.png" ) ;
// フォント設定
int fontHandle = DxLib::CreateFontToHandle( "メイリオ", 20, DX_FONTTYPE_ANTIALIASING ) ;
const int fontColor = DxLib::GetColor( 255, 255, 255 ) ;
// FPS管理クラスのインスタンス生成
FpsManager *fpsManager = new FpsManager() ;
// CPU使用率管理クラスのインスタンス生成
CpuManager *cpuManager = new CpuManager() ;
// CPU使用率用の更新カウンター
int cnt = 0 ;
// メインループ(ESCで終了)
while( DxLib::ProcessMessage() == 0 && DxLib::CheckHitKey( KEY_INPUT_ESCAPE ) == 0 )
{
// 画面クリア
DxLib::ClsDrawScreen();
// CPU使用率再算出用カウンター更新
++cnt ;
// 既定時間ごとにCPU使用率を更新する
if( cnt == CPU_UPDATE_TIME )
{
cpuManager->Update() ;
cnt = 0 ;
}
// 画像を描画
DxLib::DrawGraph( 100, 100, graphHandle, TRUE ) ;
// CPU使用率表示
DxLib::DrawFormatStringToHandle( 0, 0, fontColor, fontHandle, "[%.1f]", cpuManager->GetCpuUseRate() ) ;
// FPS表示
DxLib::DrawFormatStringToHandle( 0, SCREEN_H - 20, fontColor, fontHandle, "[%.1f]", fpsManager->GetFps() ) ;
// FPS調整
fpsManager->Adjust();
}
// クラスのインスタンス破棄
delete fpsManager ;
delete cpuManager ;
// DXライブラリ終了処理
DxLib::DxLib_End() ;
// ソフトの終了
return 0 ;
}
タスクマネージャーのプロセスタブのCPU列では00~01が表示されますが、
アプリのウィンドウ内には3.1~9.5などという値が表示されてしまいます。
よろしくお願いします。