Skip to content
This repository was archived by the owner on May 29, 2025. It is now read-only.

Commit d76e1a6

Browse files
randomasciiBruce Dawson
authored andcommitted
Command-line tool for monitoring Intel power MSRs
The CPowerStatusMonitor class is mostly a copy of the same class in UIforETW, modify to suit the command-line environment. Generalizing it to allow code sharing is left as an exercise for the reader, but doesn't really seem worth it. This tool prints various power and temperature stats occasionally. There are no options.
1 parent 85eecc8 commit d76e1a6

File tree

10 files changed

+444
-1
lines changed

10 files changed

+444
-1
lines changed

PowerMon/PowerMon.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include "stdafx.h"
2+
#include <string>
3+
4+
#include "PowerStatus.h"
5+
6+
const int kSamplingInterval = 2000;
7+
8+
int _tmain(int argc, _TCHAR* argv[])
9+
{
10+
CPowerStatusMonitor monitor;
11+
if (!monitor.IsInitialized())
12+
{
13+
printf("Couldn't find Intel Power Gadget. Make sure it is installed and IPG_Dir environment variable is visible to this process.\n");
14+
return 0;
15+
}
16+
17+
for (;;)
18+
{
19+
monitor.SampleCPUPowerState();
20+
Sleep(kSamplingInterval);
21+
wprintf(L"\n");
22+
}
23+
24+
return 0;
25+
}

PowerMon/PowerMon.sln

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 2013
4+
VisualStudioVersion = 12.0.31101.0
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerMon", "PowerMon.vcxproj", "{06F58C67-77E3-493A-B463-88888CCA6B1D}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Win32 = Debug|Win32
11+
Release|Win32 = Release|Win32
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{06F58C67-77E3-493A-B463-88888CCA6B1D}.Debug|Win32.ActiveCfg = Debug|Win32
15+
{06F58C67-77E3-493A-B463-88888CCA6B1D}.Debug|Win32.Build.0 = Debug|Win32
16+
{06F58C67-77E3-493A-B463-88888CCA6B1D}.Release|Win32.ActiveCfg = Release|Win32
17+
{06F58C67-77E3-493A-B463-88888CCA6B1D}.Release|Win32.Build.0 = Release|Win32
18+
EndGlobalSection
19+
GlobalSection(SolutionProperties) = preSolution
20+
HideSolutionNode = FALSE
21+
EndGlobalSection
22+
EndGlobal

PowerMon/PowerMon.vcxproj

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<ItemGroup Label="ProjectConfigurations">
4+
<ProjectConfiguration Include="Debug|Win32">
5+
<Configuration>Debug</Configuration>
6+
<Platform>Win32</Platform>
7+
</ProjectConfiguration>
8+
<ProjectConfiguration Include="Release|Win32">
9+
<Configuration>Release</Configuration>
10+
<Platform>Win32</Platform>
11+
</ProjectConfiguration>
12+
</ItemGroup>
13+
<PropertyGroup Label="Globals">
14+
<ProjectGuid>{06F58C67-77E3-493A-B463-88888CCA6B1D}</ProjectGuid>
15+
<Keyword>Win32Proj</Keyword>
16+
<RootNamespace>PowerMon</RootNamespace>
17+
</PropertyGroup>
18+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
19+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
20+
<ConfigurationType>Application</ConfigurationType>
21+
<UseDebugLibraries>true</UseDebugLibraries>
22+
<PlatformToolset>v140</PlatformToolset>
23+
<CharacterSet>Unicode</CharacterSet>
24+
</PropertyGroup>
25+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
26+
<ConfigurationType>Application</ConfigurationType>
27+
<UseDebugLibraries>false</UseDebugLibraries>
28+
<PlatformToolset>v140</PlatformToolset>
29+
<WholeProgramOptimization>true</WholeProgramOptimization>
30+
<CharacterSet>Unicode</CharacterSet>
31+
</PropertyGroup>
32+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
33+
<ImportGroup Label="ExtensionSettings">
34+
</ImportGroup>
35+
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
36+
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
37+
</ImportGroup>
38+
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
39+
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
40+
</ImportGroup>
41+
<PropertyGroup Label="UserMacros" />
42+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
43+
<LinkIncremental>true</LinkIncremental>
44+
</PropertyGroup>
45+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
46+
<LinkIncremental>false</LinkIncremental>
47+
</PropertyGroup>
48+
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
49+
<ClCompile>
50+
<PrecompiledHeader>Use</PrecompiledHeader>
51+
<WarningLevel>Level3</WarningLevel>
52+
<Optimization>Disabled</Optimization>
53+
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
54+
<SDLCheck>true</SDLCheck>
55+
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
56+
</ClCompile>
57+
<Link>
58+
<SubSystem>Console</SubSystem>
59+
<GenerateDebugInformation>true</GenerateDebugInformation>
60+
</Link>
61+
</ItemDefinitionGroup>
62+
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
63+
<ClCompile>
64+
<WarningLevel>Level3</WarningLevel>
65+
<PrecompiledHeader>Use</PrecompiledHeader>
66+
<Optimization>MaxSpeed</Optimization>
67+
<FunctionLevelLinking>true</FunctionLevelLinking>
68+
<IntrinsicFunctions>true</IntrinsicFunctions>
69+
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
70+
<SDLCheck>true</SDLCheck>
71+
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
72+
</ClCompile>
73+
<Link>
74+
<SubSystem>Console</SubSystem>
75+
<GenerateDebugInformation>true</GenerateDebugInformation>
76+
<EnableCOMDATFolding>true</EnableCOMDATFolding>
77+
<OptimizeReferences>true</OptimizeReferences>
78+
</Link>
79+
</ItemDefinitionGroup>
80+
<ItemGroup>
81+
<ClInclude Include="PowerStatus.h" />
82+
<ClInclude Include="stdafx.h" />
83+
<ClInclude Include="targetver.h" />
84+
</ItemGroup>
85+
<ItemGroup>
86+
<ClCompile Include="PowerMon.cpp" />
87+
<ClCompile Include="PowerStatus.cpp" />
88+
<ClCompile Include="stdafx.cpp">
89+
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
90+
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
91+
</ClCompile>
92+
</ItemGroup>
93+
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
94+
<ImportGroup Label="ExtensionTargets">
95+
</ImportGroup>
96+
</Project>

PowerMon/PowerMon.vcxproj.filters

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<ItemGroup>
4+
<Filter Include="Source Files">
5+
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
6+
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
7+
</Filter>
8+
<Filter Include="Header Files">
9+
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
10+
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
11+
</Filter>
12+
<Filter Include="Resource Files">
13+
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
14+
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
15+
</Filter>
16+
</ItemGroup>
17+
<ItemGroup>
18+
<ClInclude Include="stdafx.h">
19+
<Filter>Header Files</Filter>
20+
</ClInclude>
21+
<ClInclude Include="targetver.h">
22+
<Filter>Header Files</Filter>
23+
</ClInclude>
24+
<ClInclude Include="PowerStatus.h">
25+
<Filter>Header Files</Filter>
26+
</ClInclude>
27+
</ItemGroup>
28+
<ItemGroup>
29+
<ClCompile Include="stdafx.cpp">
30+
<Filter>Source Files</Filter>
31+
</ClCompile>
32+
<ClCompile Include="PowerStatus.cpp">
33+
<Filter>Source Files</Filter>
34+
</ClCompile>
35+
<ClCompile Include="PowerMon.cpp">
36+
<Filter>Source Files</Filter>
37+
</ClCompile>
38+
</ItemGroup>
39+
</Project>

PowerMon/PowerStatus.cpp

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/*
2+
Copyright 2015 Google Inc. All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
#include "stdafx.h"
18+
#include <string>
19+
20+
#include "PowerStatus.h"
21+
22+
// These correspond to the funcID values returned by GetMsrFunc
23+
// They are documented here:
24+
// https://software.intel.com/en-us/blogs/2014/01/07/using-the-intel-power-gadget-30-api-on-windows
25+
// Sample code from there was used to help create the Power Gadget API
26+
// code.
27+
const int MSR_FUNC_FREQ = 0;
28+
const int MSR_FUNC_POWER = 1;
29+
const int MSR_FUNC_TEMP = 2;
30+
const int MSR_FUNC_MAX_POWER = 3; /* ????? */
31+
32+
void CPowerStatusMonitor::SampleCPUPowerState()
33+
{
34+
if (!IntelEnergyLibInitialize || !GetNumMsrs || !GetMsrName || !GetMsrFunc ||
35+
!GetPowerData || !ReadSample)
36+
{
37+
return;
38+
}
39+
40+
int numMSRs = 0;
41+
GetNumMsrs(&numMSRs);
42+
ReadSample();
43+
for (int i = 0; i < numMSRs; ++i)
44+
{
45+
int funcID;
46+
wchar_t MSRName[1024];
47+
GetMsrFunc(i, &funcID);
48+
GetMsrName(i, MSRName);
49+
50+
int nData;
51+
double data[3] = {};
52+
GetPowerData(0, i, data, &nData);
53+
54+
if (funcID == MSR_FUNC_FREQ)
55+
{
56+
wprintf(L"%s = %4.0f MHz\n", MSRName, data[0]);
57+
}
58+
else if (funcID == MSR_FUNC_POWER)
59+
{
60+
// Round to nearest .0001 to avoid distracting excess precision.
61+
data[0] = round(data[0] * 10000) / 10000;
62+
data[2] = round(data[2] * 10000) / 10000;
63+
wprintf(L"%s Power (W) = %3.2f\n", MSRName, data[0]);
64+
wprintf(L"%s Energy(J) = %3.2f\n", MSRName, data[1]);
65+
wprintf(L"%s Energy(mWh)=%3.2f\n", MSRName, data[2]);
66+
}
67+
else if (funcID == MSR_FUNC_TEMP)
68+
{
69+
// The 3.02 version of Intel Power Gadget seems to report the temperature
70+
// in F instead of C.
71+
wprintf(L"%s Temp (C) = %3.0f (max is %3.0f)\n", MSRName, data[0], (double)maxTemperature_);
72+
}
73+
else if (funcID == MSR_FUNC_MAX_POWER)
74+
{
75+
//wprintf(L"%s Max Power (W) = %3.0f\n", MSRName, data[0]);
76+
}
77+
else
78+
{
79+
//wprintf(L"Unused funcID %d\n", funcID);
80+
}
81+
}
82+
}
83+
84+
CPowerStatusMonitor::CPowerStatusMonitor()
85+
{
86+
// If Intel Power Gadget is installed then use it to get CPU power data.
87+
#if _M_X64
88+
PCWSTR dllName = L"\\EnergyLib64.dll";
89+
#else
90+
PCWSTR dllName = L"\\EnergyLib32.dll";
91+
#endif
92+
#pragma warning(disable : 4996)
93+
PCWSTR powerGadgetDir = _wgetenv(L"IPG_Dir");
94+
if (powerGadgetDir)
95+
energyLib_ = LoadLibrary((std::wstring(powerGadgetDir) + dllName).c_str());
96+
if (energyLib_)
97+
{
98+
IntelEnergyLibInitialize = (IntelEnergyLibInitialize_t)GetProcAddress(energyLib_, "IntelEnergyLibInitialize");
99+
GetNumMsrs = (GetNumMsrs_t)GetProcAddress(energyLib_, "GetNumMsrs");
100+
GetMsrName = (GetMsrName_t)GetProcAddress(energyLib_, "GetMsrName");
101+
GetMsrFunc = (GetMsrFunc_t)GetProcAddress(energyLib_, "GetMsrFunc");
102+
GetPowerData = (GetPowerData_t)GetProcAddress(energyLib_, "GetPowerData");
103+
ReadSample = (ReadSample_t)GetProcAddress(energyLib_, "ReadSample");
104+
auto GetMaxTemperature = (GetMaxTemperature_t)GetProcAddress(energyLib_, "GetMaxTemperature");
105+
if (IntelEnergyLibInitialize && ReadSample)
106+
{
107+
if (IntelEnergyLibInitialize())
108+
{
109+
if (GetMaxTemperature)
110+
GetMaxTemperature(0, &maxTemperature_);
111+
ReadSample();
112+
}
113+
else
114+
{
115+
// Mark the library as unavailable if Initialize fails
116+
ClearEnergyLibFunctionPointers();
117+
}
118+
}
119+
}
120+
}
121+
122+
void CPowerStatusMonitor::ClearEnergyLibFunctionPointers()
123+
{
124+
IntelEnergyLibInitialize = nullptr;
125+
GetNumMsrs = nullptr;
126+
GetMsrName = nullptr;
127+
GetMsrFunc = nullptr;
128+
GetPowerData = nullptr;
129+
ReadSample = nullptr;
130+
}

PowerMon/PowerStatus.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
Copyright 2015 Google Inc. All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
#pragma once
18+
19+
// https://software.intel.com/en-us/blogs/2012/12/13/using-the-intel-power-gadget-api-on-mac-os-x
20+
typedef int(*IntelEnergyLibInitialize_t)();
21+
typedef int(*GetNumMsrs_t)(int* nMsr);
22+
typedef int(*GetMsrName_t)(int iMsr, wchar_t* szName);
23+
typedef int(*GetMsrFunc_t)(int iMsr, int* pFuncID);
24+
typedef int(*GetPowerData_t)(int iNode, int iMsr, double* pResult, int* nResult);
25+
typedef int(*ReadSample_t)();
26+
typedef int(*GetMaxTemperature_t)(int iNode, int* degreeC);
27+
28+
// This is mostly a copy of the CPowerStatusMonitor class from UIforETW.
29+
class CPowerStatusMonitor
30+
{
31+
public:
32+
CPowerStatusMonitor();
33+
34+
void SampleCPUPowerState();
35+
bool IsInitialized() const
36+
{
37+
return energyLib_ != nullptr;
38+
}
39+
40+
private:
41+
void ClearEnergyLibFunctionPointers();
42+
43+
HMODULE energyLib_ = nullptr;
44+
IntelEnergyLibInitialize_t IntelEnergyLibInitialize = nullptr;
45+
GetNumMsrs_t GetNumMsrs = nullptr;
46+
GetMsrName_t GetMsrName = nullptr;
47+
GetMsrFunc_t GetMsrFunc = nullptr;
48+
GetPowerData_t GetPowerData = nullptr;
49+
ReadSample_t ReadSample = nullptr;
50+
int maxTemperature_ = 0;
51+
52+
CPowerStatusMonitor& operator=(const CPowerStatusMonitor&) = delete;
53+
CPowerStatusMonitor(const CPowerStatusMonitor&) = delete;
54+
};

PowerMon/stdafx.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
Copyright 2015 Google Inc. All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
// stdafx.cpp : source file that includes just the standard includes
18+
// PowerMon.pch will be the pre-compiled header
19+
// stdafx.obj will contain the pre-compiled type information
20+
21+
#include "stdafx.h"
22+
23+
// TODO: reference any additional headers you need in STDAFX.H
24+
// and not in this file

0 commit comments

Comments
 (0)