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:
Éder F. Zulian
2016-04-22 11:50:39 +02:00
parent f608eb970d
commit e07445a58e
3 changed files with 43 additions and 26 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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);
}