From e07445a58ec5356751e062049b2f6b4916df479b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Fri, 22 Apr 2016 11:50:39 +0200 Subject: [PATCH] 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 ). 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. --- DRAMSys/analyzer/scripts/plots.py | 2 +- DRAMSys/simulator/simulator.pro | 7 --- DRAMSys/simulator/src/simulation/Dram.h | 60 +++++++++++++++++-------- 3 files changed, 43 insertions(+), 26 deletions(-) diff --git a/DRAMSys/analyzer/scripts/plots.py b/DRAMSys/analyzer/scripts/plots.py index 6d9ddc21..c161140d 100755 --- a/DRAMSys/analyzer/scripts/plots.py +++ b/DRAMSys/analyzer/scripts/plots.py @@ -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) diff --git a/DRAMSys/simulator/simulator.pro b/DRAMSys/simulator/simulator.pro index 307a3ffc..2629ff42 100644 --- a/DRAMSys/simulator/simulator.pro +++ b/DRAMSys/simulator/simulator.pro @@ -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 diff --git a/DRAMSys/simulator/src/simulation/Dram.h b/DRAMSys/simulator/src/simulation/Dram.h index 62986456..8e025324 100644 --- a/DRAMSys/simulator/src/simulation/Dram.h +++ b/DRAMSys/simulator/src/simulation/Dram.h @@ -45,6 +45,7 @@ #include #include #include +#include #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 ). 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); }