Bug 769431 - Correlate power data from Intel Power Gadget in performance profiles. r=BenWa

This commit is contained in:
Joe Olivas 2013-10-08 10:05:25 -04:00
parent c7d2a6d1e4
commit 4594f145f4
7 changed files with 508 additions and 0 deletions

View File

@ -0,0 +1,310 @@
/*
* Copyright 2013, Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author: Joe Olivas <joseph.k.olivas@intel.com>
*/
#include "nsDebug.h"
#include "nsString.h"
#include "IntelPowerGadget.h"
#include "prenv.h"
IntelPowerGadget::IntelPowerGadget() :
libpowergadget(nullptr),
Initialize(nullptr),
GetNumNodes(nullptr),
GetMsrName(nullptr),
GetMsrFunc(nullptr),
ReadMSR(nullptr),
WriteMSR(nullptr),
GetIAFrequency(nullptr),
GetTDP(nullptr),
GetMaxTemperature(nullptr),
GetThresholds(nullptr),
GetTemperature(nullptr),
ReadSample(nullptr),
GetSysTime(nullptr),
GetRDTSC(nullptr),
GetTimeInterval(nullptr),
GetBaseFrequency(nullptr),
GetPowerData(nullptr),
StartLog(nullptr),
StopLog(nullptr),
GetNumMsrs(nullptr),
packageMSR(-1),
cpuMSR(-1),
freqMSR(-1),
tempMSR(-1)
{
}
bool
IntelPowerGadget::Init()
{
bool success = false;
const char *path = PR_GetEnv("IPG_Dir");
nsCString ipg_library;
if (path && *path) {
ipg_library.Append(path);
ipg_library.AppendLiteral("/");
ipg_library.AppendLiteral(PG_LIBRARY_NAME);
libpowergadget = PR_LoadLibrary(ipg_library.get());
}
if(libpowergadget) {
Initialize = (IPGInitialize) PR_FindFunctionSymbol(libpowergadget, "IntelEnergyLibInitialize");
GetNumNodes = (IPGGetNumNodes) PR_FindFunctionSymbol(libpowergadget, "GetNumNodes");
GetMsrName = (IPGGetMsrName) PR_FindFunctionSymbol(libpowergadget, "GetMsrName");
GetMsrFunc = (IPGGetMsrFunc) PR_FindFunctionSymbol(libpowergadget, "GetMsrFunc");
ReadMSR = (IPGReadMSR) PR_FindFunctionSymbol(libpowergadget, "ReadMSR");
WriteMSR = (IPGWriteMSR) PR_FindFunctionSymbol(libpowergadget, "WriteMSR");
GetIAFrequency = (IPGGetIAFrequency) PR_FindFunctionSymbol(libpowergadget, "GetIAFrequency");
GetTDP = (IPGGetTDP) PR_FindFunctionSymbol(libpowergadget, "GetTDP");
GetMaxTemperature = (IPGGetMaxTemperature) PR_FindFunctionSymbol(libpowergadget, "GetMaxTemperature");
GetThresholds = (IPGGetThresholds) PR_FindFunctionSymbol(libpowergadget, "GetThresholds");
GetTemperature = (IPGGetTemperature) PR_FindFunctionSymbol(libpowergadget, "GetTemperature");
ReadSample = (IPGReadSample) PR_FindFunctionSymbol(libpowergadget, "ReadSample");
GetSysTime = (IPGGetSysTime) PR_FindFunctionSymbol(libpowergadget, "GetSysTime");
GetRDTSC = (IPGGetRDTSC) PR_FindFunctionSymbol(libpowergadget, "GetRDTSC");
GetTimeInterval = (IPGGetTimeInterval) PR_FindFunctionSymbol(libpowergadget, "GetTimeInterval");
GetBaseFrequency = (IPGGetBaseFrequency) PR_FindFunctionSymbol(libpowergadget, "GetBaseFrequency");
GetPowerData = (IPGGetPowerData) PR_FindFunctionSymbol(libpowergadget, "GetPowerData");
StartLog = (IPGStartLog) PR_FindFunctionSymbol(libpowergadget, "StartLog");
StopLog = (IPGStopLog) PR_FindFunctionSymbol(libpowergadget, "StopLog");
GetNumMsrs = (IPGGetNumMsrs) PR_FindFunctionSymbol(libpowergadget, "GetNumMsrs");
}
if(Initialize) {
Initialize();
int msrCount = GetNumberMsrs();
wchar_t name[1024] = {0};
for(int i = 0; i < msrCount; ++i) {
GetMsrName(i, name);
int func = 0;
GetMsrFunc(i, &func);
// MSR for frequency
if(wcscmp(name, L"CPU Frequency") == 0 && (func == 0)) {
this->freqMSR = i;
}
// MSR for Package
else if(wcscmp(name, L"Processor") == 0 && (func == 1)) {
this->packageMSR = i;
}
// MSR for CPU
else if(wcscmp(name, L"IA") == 0 && (func == 1)) {
this->cpuMSR = i;
}
// MSR for Temperature
else if(wcscmp(name, L"Package") == 0 && (func == 2)) {
this->tempMSR = i;
}
}
// Grab one sample at startup for a diff
TakeSample();
success = true;
}
return success;
}
IntelPowerGadget::~IntelPowerGadget()
{
if(libpowergadget) {
NS_WARNING("Unloading PowerGadget library!\n");
PR_UnloadLibrary(libpowergadget);
libpowergadget = nullptr;
Initialize = nullptr;
GetNumNodes = nullptr;
GetMsrName = nullptr;
GetMsrFunc = nullptr;
ReadMSR = nullptr;
WriteMSR = nullptr;
GetIAFrequency = nullptr;
GetTDP = nullptr;
GetMaxTemperature = nullptr;
GetThresholds = nullptr;
GetTemperature = nullptr;
ReadSample = nullptr;
GetSysTime = nullptr;
GetRDTSC = nullptr;
GetTimeInterval = nullptr;
GetBaseFrequency = nullptr;
GetPowerData = nullptr;
StartLog = nullptr;
StopLog = nullptr;
GetNumMsrs = nullptr;
}
}
int
IntelPowerGadget::GetNumberNodes()
{
int nodes = 0;
if(GetNumNodes) {
int ok = GetNumNodes(&nodes);
}
return nodes;
}
int
IntelPowerGadget::GetNumberMsrs()
{
int msrs = 0;
if(GetNumMsrs) {
int ok = GetNumMsrs(&msrs);
}
return msrs;
}
int
IntelPowerGadget::GetCPUFrequency(int node)
{
int frequency = 0;
if(GetIAFrequency) {
int ok = GetIAFrequency(node, &frequency);
}
return frequency;
}
double
IntelPowerGadget::GetTdp(int node)
{
double tdp = 0.0;
if(GetTDP) {
int ok = GetTDP(node, &tdp);
}
return tdp;
}
int
IntelPowerGadget::GetMaxTemp(int node)
{
int maxTemperatureC = 0;
if(GetMaxTemperature) {
int ok = GetMaxTemperature(node, &maxTemperatureC);
}
return maxTemperatureC;
}
int
IntelPowerGadget::GetTemp(int node)
{
int temperatureC = 0;
if(GetTemperature) {
int ok = GetTemperature(node, &temperatureC);
}
return temperatureC;
}
int
IntelPowerGadget::TakeSample()
{
int ok = 0;
if(ReadSample) {
ok = ReadSample();
}
return ok;
}
uint64_t
IntelPowerGadget::GetRdtsc()
{
uint64_t rdtsc = 0;
if(GetRDTSC) {
int ok = GetRDTSC(&rdtsc);
}
return rdtsc;
}
double
IntelPowerGadget::GetInterval()
{
double interval = 0.0;
if(GetTimeInterval) {
int ok = GetTimeInterval(&interval);
}
return interval;
}
double
IntelPowerGadget::GetCPUBaseFrequency(int node)
{
double freq = 0.0;
if(GetBaseFrequency) {
int ok = GetBaseFrequency(node, &freq);
}
return freq;
}
double
IntelPowerGadget::GetTotalPackagePowerInWatts()
{
int nodes = GetNumberNodes();
double totalPower = 0.0;
for(int i = 0; i < nodes; ++i) {
totalPower += GetPackagePowerInWatts(i);
}
return totalPower;
}
double
IntelPowerGadget::GetPackagePowerInWatts(int node)
{
int numResult = 0;
double result[] = {0.0, 0.0, 0.0};
if(GetPowerData && packageMSR != -1) {
int ok = GetPowerData(node, packageMSR, result, &numResult);
}
return result[0];
}
double
IntelPowerGadget::GetTotalCPUPowerInWatts()
{
int nodes = GetNumberNodes();
double totalPower = 0.0;
for(int i = 0; i < nodes; ++i) {
totalPower += GetCPUPowerInWatts(i);
}
return totalPower;
}
double
IntelPowerGadget::GetCPUPowerInWatts(int node)
{
int numResult = 0;
double result[] = {0.0, 0.0, 0.0};
if(GetPowerData && cpuMSR != -1) {
int ok = GetPowerData(node, cpuMSR, result, &numResult);
}
return result[0];
}
double
IntelPowerGadget::GetTotalGPUPowerInWatts()
{
int nodes = GetNumberNodes();
double totalPower = 0.0;
for(int i = 0; i < nodes; ++i) {
totalPower += GetGPUPowerInWatts(i);
}
return totalPower;
}
double
IntelPowerGadget::GetGPUPowerInWatts(int node)
{
return 0.0;
}

View File

@ -0,0 +1,150 @@
/*
* Copyright 2013, Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author: Joe Olivas <joseph.k.olivas@intel.com>
*/
#ifndef profiler_IntelPowerGadget_h
#define profiler_IntelPowerGadget_h
#ifdef _MSC_VER
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h>
#endif
#include "prlink.h"
typedef int (*IPGInitialize) ();
typedef int (*IPGGetNumNodes) (int *nNodes);
typedef int (*IPGGetNumMsrs) (int *nMsr);
typedef int (*IPGGetMsrName) (int iMsr, wchar_t *szName);
typedef int (*IPGGetMsrFunc) (int iMsr, int *pFuncID);
typedef int (*IPGReadMSR) (int iNode, unsigned int address, uint64_t *value);
typedef int (*IPGWriteMSR) (int iNode, unsigned int address, uint64_t value);
typedef int (*IPGGetIAFrequency) (int iNode, int *freqInMHz);
typedef int (*IPGGetTDP) (int iNode, double *TDP);
typedef int (*IPGGetMaxTemperature) (int iNode, int *degreeC);
typedef int (*IPGGetThresholds) (int iNode, int *degree1C, int *degree2C);
typedef int (*IPGGetTemperature) (int iNode, int *degreeC);
typedef int (*IPGReadSample) ();
typedef int (*IPGGetSysTime) (void *pSysTime);
typedef int (*IPGGetRDTSC) (uint64_t *pTSC);
typedef int (*IPGGetTimeInterval) (double *pOffset);
typedef int (*IPGGetBaseFrequency) (int iNode, double *pBaseFrequency);
typedef int (*IPGGetPowerData) (int iNode, int iMSR, double *pResult, int *nResult);
typedef int (*IPGStartLog) (wchar_t *szFileName);
typedef int (*IPGStopLog) ();
#if defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64)
#define PG_LIBRARY_NAME "EnergyLib64"
#else
#define PG_LIBRARY_NAME "EnergyLib32"
#endif
class IntelPowerGadget
{
public:
IntelPowerGadget();
~IntelPowerGadget();
// Fails if initialization is incomplete
bool Init();
// Returns the number of packages on the system
int GetNumberNodes();
// Returns the number of MSRs being tracked
int GetNumberMsrs();
// Given a node, returns the temperature
int GetCPUFrequency(int);
// Returns the TDP of the given node
double GetTdp(int);
// Returns the maximum temperature for the given node
int GetMaxTemp(int);
// Returns the current temperature in degrees C
// of the given node
int GetTemp(int);
// Takes a sample of data. Must be called before
// any current data is retrieved.
int TakeSample();
// Gets the timestamp of the most recent sample
uint64_t GetRdtsc();
// returns number of seconds between the last
// two samples
double GetInterval();
// Returns the base frequency for the given node
double GetCPUBaseFrequency(int node);
// Returns the combined package power for all
// packages on the system for the last sample.
double GetTotalPackagePowerInWatts();
double GetPackagePowerInWatts(int node);
// Returns the combined CPU power for all
// packages on the system for the last sample.
// If the reading is not available, returns 0.0
double GetTotalCPUPowerInWatts();
double GetCPUPowerInWatts(int node);
// Returns the combined GPU power for all
// packages on the system for the last sample.
// If the reading is not available, returns 0.0
double GetTotalGPUPowerInWatts();
double GetGPUPowerInWatts(int node);
private:
PRLibrary *libpowergadget;
IPGInitialize Initialize;
IPGGetNumNodes GetNumNodes;
IPGGetNumMsrs GetNumMsrs;
IPGGetMsrName GetMsrName;
IPGGetMsrFunc GetMsrFunc;
IPGReadMSR ReadMSR;
IPGWriteMSR WriteMSR;
IPGGetIAFrequency GetIAFrequency;
IPGGetTDP GetTDP;
IPGGetMaxTemperature GetMaxTemperature;
IPGGetThresholds GetThresholds;
IPGGetTemperature GetTemperature;
IPGReadSample ReadSample;
IPGGetSysTime GetSysTime;
IPGGetRDTSC GetRDTSC;
IPGGetTimeInterval GetTimeInterval;
IPGGetBaseFrequency GetBaseFrequency;
IPGGetPowerData GetPowerData;
IPGStartLog StartLog;
IPGStopLog StopLog;
int packageMSR;
int cpuMSR;
int freqMSR;
int tempMSR;
};
#endif // profiler_IntelPowerGadget_h

View File

@ -390,6 +390,13 @@ void ThreadProfile::BuildJSObject(Builder& b,
}
}
break;
case 'p':
{
if (sample) {
b.DefineProperty(sample, "power", entry.mTagFloat);
}
}
break;
case 'f':
{
if (sample) {

View File

@ -530,6 +530,9 @@ void TableTicker::InplaceTick(TickSample* sample)
PseudoStack* stack = currThreadProfile.GetPseudoStack();
bool recordSample = true;
#if defined(XP_WIN)
bool powerSample = false;
#endif
/* Don't process the PeudoStack's markers or honour jankOnly if we're
immediately sampling the current thread. */
@ -543,6 +546,13 @@ void TableTicker::InplaceTick(TickSample* sample)
}
stack->updateGeneration(currThreadProfile.GetGenerationID());
#if defined(XP_WIN)
if (mProfilePower) {
mIntelPowerGadget->TakeSample();
powerSample = true;
}
#endif
if (mJankOnly) {
// if we are on a different event we can discard any temporary samples
// we've kept around
@ -588,6 +598,12 @@ void TableTicker::InplaceTick(TickSample* sample)
currThreadProfile.addTag(ProfileEntry('t', delta.ToMilliseconds()));
}
#if defined(XP_WIN)
if (powerSample) {
currThreadProfile.addTag(ProfileEntry('p', mIntelPowerGadget->GetTotalPackagePowerInWatts()));
}
#endif
if (sLastFrameNumber != sFrameNumber) {
currThreadProfile.addTag(ProfileEntry('f', sFrameNumber));
sLastFrameNumber = sFrameNumber;

View File

@ -6,6 +6,7 @@
#include "platform.h"
#include "ProfileEntry.h"
#include "mozilla/Mutex.h"
#include "IntelPowerGadget.h"
static bool
hasFeature(const char** aFeatures, uint32_t aFeatureCount, const char* aFeature) {
@ -50,6 +51,9 @@ class TableTicker: public Sampler {
, mSaveRequested(false)
, mUnwinderThread(false)
, mFilterCount(aFilterCount)
#if defined(XP_WIN)
, mIntelPowerGadget(nullptr)
#endif
{
mUseStackWalk = hasFeature(aFeatures, aFeatureCount, "stackwalk");
@ -57,12 +61,20 @@ class TableTicker: public Sampler {
mJankOnly = hasFeature(aFeatures, aFeatureCount, "jank");
mProfileJS = hasFeature(aFeatures, aFeatureCount, "js");
mProfileJava = hasFeature(aFeatures, aFeatureCount, "java");
mProfilePower = hasFeature(aFeatures, aFeatureCount, "power");
mProfileThreads = hasFeature(aFeatures, aFeatureCount, "threads");
mUnwinderThread = hasFeature(aFeatures, aFeatureCount, "unwinder") || sps_version2();
mAddLeafAddresses = hasFeature(aFeatures, aFeatureCount, "leaf");
mPrivacyMode = hasFeature(aFeatures, aFeatureCount, "privacy");
mAddMainThreadIO = hasFeature(aFeatures, aFeatureCount, "mainthreadio");
#if defined(XP_WIN)
if (mProfilePower) {
mIntelPowerGadget = new IntelPowerGadget();
mProfilePower = mIntelPowerGadget->Init();
}
#endif
// Deep copy aThreadNameFilters
mThreadNameFilters = new char*[aFilterCount];
for (uint32_t i = 0; i < aFilterCount; ++i) {
@ -104,6 +116,9 @@ class TableTicker: public Sampler {
}
}
}
#if defined(XP_WIN)
delete mIntelPowerGadget;
#endif
}
void RegisterThread(ThreadInfo* aInfo) {
@ -163,6 +178,7 @@ class TableTicker: public Sampler {
bool HasUnwinderThread() const { return mUnwinderThread; }
bool ProfileJS() const { return mProfileJS; }
bool ProfileJava() const { return mProfileJava; }
bool ProfilePower() const { return mProfilePower; }
bool ProfileThreads() const { return mProfileThreads; }
bool InPrivacyMode() const { return mPrivacyMode; }
bool AddMainThreadIO() const { return mAddMainThreadIO; }
@ -189,6 +205,7 @@ protected:
bool mProfileThreads;
bool mUnwinderThread;
bool mProfileJava;
bool mProfilePower;
// Keep the thread filter to check against new thread that
// are started while profiling
@ -196,5 +213,8 @@ protected:
uint32_t mFilterCount;
bool mPrivacyMode;
bool mAddMainThreadIO;
#if defined(XP_WIN)
IntelPowerGadget* mIntelPowerGadget;
#endif
};

View File

@ -65,6 +65,7 @@ if CONFIG['MOZ_ENABLE_PROFILER_SPS']:
]
elif CONFIG['OS_TARGET'] == 'WINNT':
SOURCES += [
'IntelPowerGadget.cpp',
'platform-win32.cc',
'shared-libraries-win32.cc',
]

View File

@ -606,6 +606,10 @@ const char** mozilla_sampler_get_features()
"privacy",
// Add main thread I/O to the profile
"mainthreadio",
#if defined(XP_WIN)
// Add power collection
"power",
#endif
NULL
};