Using average power values directly from DRAMPower.
Now we store the average power values directly obtained from the DRAMPower library into the database. Thus we do not have to divide energy by time to calculate them anymore (avoiding any possible lost of accuracy due to rounding). Other changes: - At the very beginning (zero clock cycles) the energy is 0, so the powerWindow thread wait first. - When working with floats, we have to decide ourselves what is an acceptable definition for "equal". Now we compare the energy value with a suitable error margin (0.00001). Now the assertion that ensures the energy is not zero is working properly. Notes: - The assert() function does nothing if NDEBUG is defined. - The total energy is provided by DRAMPower as a double. We accumulate the total energy for every window since we are clearing the library counters. Explanation about double precision: The double type ensures 15 decimal digits to represent a number. It does not matter if the digits are before or after the comma. Thus we only have rounding for numbers represented with more than 15 decimal digits. In more technical terms: An IEEE double has 53 significant bits (see also DBL_MANT_DIG in <cfloat>). That is approximately 15.95 decimal digits (log10(2^53)). The implementation sets the number of digits (DBL_DIG) to 15, not 16, because it has to round down.
This commit is contained in:
@@ -119,7 +119,7 @@ def power_window(connection, tracePath):
|
||||
for i in range(steps):
|
||||
result = cursor.fetchone()
|
||||
time[i] = float(result[0]) * 1000000000 # convertion of seconds to nanoseconds
|
||||
power[i] = float(result[1]) / 1000000000 # conversion of pW to mW
|
||||
power[i] = float(result[1]) # values are stored in mW
|
||||
|
||||
name = ntpath.basename(tracePath)
|
||||
basename, extension = os.path.splitext(name)
|
||||
|
||||
@@ -49,13 +49,6 @@ INCLUDEPATH += src/common/third_party/DRAMPower/src/libdrampower
|
||||
|
||||
DEFINES += TIXML_USE_STL
|
||||
DEFINES += SC_INCLUDE_DYNAMIC_PROCESSES
|
||||
release {
|
||||
DEFINES += NDEBUG
|
||||
}
|
||||
|
||||
#CONFIG += c++11
|
||||
#QMAKE_CXXFLAGS += -O0 -g
|
||||
#QMAKE_CXXFLAGS += -std=c++0x -O0 -g
|
||||
|
||||
unix:!macx {
|
||||
QMAKE_CXXFLAGS += -std=c++11 -O0 -g
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <tlm_utils/simple_target_socket.h>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include "../common/DebugManager.h"
|
||||
#include "../common/dramExtension.h"
|
||||
#include "../controller/core/TimingCalculation.h"
|
||||
@@ -71,8 +72,7 @@ struct Dram : sc_module
|
||||
enum sc_time_unit pWindowUnit = Configuration::getInstance().PowerWindowUnit;
|
||||
sc_time powerWindowSize = sc_time(pWindowSize, pWindowUnit);
|
||||
libDRAMPower *DRAMPower;
|
||||
double totalEnergy = 0;
|
||||
double sumOfEnergyWindows = 0;
|
||||
double sumOfEnergyWindows = 0.0;
|
||||
|
||||
// Error Model related:
|
||||
ErrorStorageMode ErrorStoreMode = Configuration::getInstance().ErrorStoreMode;
|
||||
@@ -199,14 +199,13 @@ struct Dram : sc_module
|
||||
DRAMPower->updateCounters(true);
|
||||
DRAMPower->calcEnergy();
|
||||
|
||||
double energy = sumOfEnergyWindows + DRAMPower->getEnergy().total_energy;
|
||||
double averagePower = energy / sc_time_stamp().to_seconds();
|
||||
double totalEnergy = sumOfEnergyWindows + DRAMPower->getEnergy().total_energy;
|
||||
// The energy is given in [pJ] and divided by [s] resulting in [pW] then converted to [mW]
|
||||
double averagePower = (totalEnergy / sc_time_stamp().to_seconds()) / 1e9;
|
||||
|
||||
tlmRecorder->recordPower(sc_time_stamp().to_seconds(), averagePower);
|
||||
|
||||
// Print Final Total Power Values
|
||||
cout << name() << string("\tTotal Energy: \t") + to_string(energy) + string("\t[pJ]") << endl;
|
||||
cout << name() << string("\tAverage Power: \t") + to_string(averagePower) + string("\t[pW]") << endl;
|
||||
// Print the final total energy and the average power for the simulation
|
||||
cout << name() << string("\tTotal Energy: \t") + to_string(totalEnergy) + string("\t[pJ]") << endl;
|
||||
cout << name() << string("\tAverage Power: \t") + to_string(averagePower) + string("\t[mW]") << endl;
|
||||
}
|
||||
|
||||
// Clean up:
|
||||
@@ -215,6 +214,14 @@ struct Dram : sc_module
|
||||
}
|
||||
}
|
||||
|
||||
// When working with floats, we have to decide ourselves what is an
|
||||
// acceptable definition for "equal". Here the number is compared with a
|
||||
// suitable error margin (0.00001).
|
||||
bool is_equal(double a, double b, const double epsilon = 1e-05)
|
||||
{
|
||||
return std::fabs(a - b) < epsilon;
|
||||
}
|
||||
|
||||
// This Thread is only triggered when Power Simulation is enabled.
|
||||
// It estimates the current average power which will be stored in the trace database for visualization purposes.
|
||||
void powerWindow()
|
||||
@@ -223,28 +230,45 @@ struct Dram : sc_module
|
||||
double currentTotalEnergy = 0;
|
||||
|
||||
do {
|
||||
unsigned long long c = sc_time_stamp().value() / Configuration::getInstance().memSpec.clk.value();
|
||||
// At the very beginning (zero clock cycles) the energy is 0, so we wait first
|
||||
wait(powerWindowSize);
|
||||
|
||||
DRAMPower->doCommand(MemCommand::NOP, 0, c);
|
||||
unsigned long long clk_cycles = sc_time_stamp().value() / Configuration::getInstance().memSpec.clk.value();
|
||||
|
||||
DRAMPower->doCommand(MemCommand::NOP, 0, clk_cycles);
|
||||
DRAMPower->updateCounters(false);
|
||||
DRAMPower->calcEnergy();
|
||||
|
||||
currentTotalEnergy = DRAMPower->getEnergy().total_energy;
|
||||
currentAveragePower = DRAMPower->getPower().average_power;
|
||||
|
||||
assert(currentTotalEnergy != 0);
|
||||
DRAMPower->clearCounters(clk_cycles);
|
||||
|
||||
DRAMPower->clearCounters(c);
|
||||
// During operation the energy should never be zero since the device is always consuming
|
||||
assert(!is_equal(currentTotalEnergy, 0.0));
|
||||
|
||||
// Accumulate the energy since we are clearing the library
|
||||
// counters.
|
||||
//
|
||||
// Here we use double values. The double type ensures 15 decimal
|
||||
// digits to represent a number. It does not matter if the digits
|
||||
// are before or after the comma. Thus we only have rounding for
|
||||
// numbers represented with more than 15 decimal digits.
|
||||
//
|
||||
// In more technical terms:
|
||||
// An IEEE double has 53 significant bits (see also DBL_MANT_DIG
|
||||
// in <cfloat>). That is approximately 15.95 decimal digits
|
||||
// (log10(2^53)). The implementation sets the number of digits
|
||||
// (DBL_DIG) to 15, not 16, because it has to round down.
|
||||
//
|
||||
sumOfEnergyWindows += currentTotalEnergy;
|
||||
// [pW] = [pJ] / [s] (here considering that DRAMPower provides the value always in pJ)
|
||||
currentAveragePower = currentTotalEnergy / powerWindowSize.to_seconds();
|
||||
|
||||
// Store the time (in seconds) and the current average power (in mW) into the database
|
||||
tlmRecorder->recordPower(sc_time_stamp().to_seconds(), currentAveragePower);
|
||||
|
||||
// Here considering that DRAMPower provides the energy in pJ and the power in mW
|
||||
printDebugMessage(string("\tCurrent Energy: \t") + to_string(currentTotalEnergy) + string("\t[pJ]"));
|
||||
printDebugMessage(string("\tAverage Power: \t") + to_string(currentAveragePower) + string("\t[pW]"));
|
||||
|
||||
wait(powerWindowSize);
|
||||
printDebugMessage(string("\tAverage Power 1: \t") + to_string(currentAveragePower) + string("\t[mW]"));
|
||||
} while(true);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user