From a9f16aaa395320c94aa2611f797d64ee56d68b79 Mon Sep 17 00:00:00 2001 From: Germain Haugou Date: Sat, 20 Nov 2021 17:26:57 +0100 Subject: [PATCH 1/3] [POWER] Cleaning-out power modeling --- engine/include/vp/power/implementation.hpp | 20 + engine/include/vp/power/power.hpp | 293 ++-- engine/include/vp/power/power_engine.hpp | 4 + engine/python/vp_runner.py | 1422 -------------------- engine/src/power/power.cpp | 23 +- engine/vp/power_engine_impl.cpp | 4 - 6 files changed, 240 insertions(+), 1526 deletions(-) delete mode 100644 engine/python/vp_runner.py diff --git a/engine/include/vp/power/implementation.hpp b/engine/include/vp/power/implementation.hpp index 048e4d4..a471b3f 100644 --- a/engine/include/vp/power/implementation.hpp +++ b/engine/include/vp/power/implementation.hpp @@ -28,6 +28,26 @@ #include "vp/power/power_engine.hpp" +inline void vp::power_source::power_on() +{ + if (!this->is_on) + this->trace->incr_power(this->quantum, this->is_leakage); + this->is_on = true; +} + +inline void vp::power_source::power_off() +{ + if (this->is_on) + this->trace->incr_power(-this->quantum, this->is_leakage); + this->is_on = false; +} + +inline void vp::power_source::account_event() +{ + this->trace->account_quantum(this->quantum); +} + + inline void vp::power_trace::account_quantum(double quantum) { this->incr(quantum); diff --git a/engine/include/vp/power/power.hpp b/engine/include/vp/power/power.hpp index f2c73ee..d30b652 100644 --- a/engine/include/vp/power/power.hpp +++ b/engine/include/vp/power/power.hpp @@ -15,111 +15,210 @@ * limitations under the License. */ -/* +/* * Authors: Germain Haugou, GreenWaves Technologies (germain.haugou@greenwaves-technologies.com) */ -#ifndef __VP_POWER_POWER_HPP__ -#define __VP_POWER_POWER_HPP__ +#pragma once #include "json.hpp" #include "vp/vp_data.hpp" -namespace vp { - - #define VP_POWER_DEFAULT_TEMP 25 - #define VP_POWER_DEFAULT_VOLT 1.2 - #define VP_POWER_DEFAULT_FREQ 50 - - class Linear_table; - - class power_engine; - - class power_trace - { - public: - int init(component *top, std::string name); - - inline bool get_active() { return trace.get_event_active(); } - - inline void account_quantum(double quantum); - - void set_power(double quantum, bool is_leakage); - - void incr(double quantum, bool is_leakage=false); - - inline double get_value(); - - inline double get_total(); - - inline double get_total_leakage(); - - bool is_dumped() { return this->dumped; } - - power_trace *get_top_trace(); - - void clear(); - - void flush(); - - void dump(FILE *file); - - void collect(); - - void reg_top_trace(vp::power_trace *trace); - void reg_child_trace(vp::power_trace *trace); - - void get(double *dynamic, double *leakage); - - vp::trace trace; - - private: - void account_power(); - void account_leakage_power(); - - component *top; - power_trace *top_trace = NULL; - std::vector child_traces; - double value; - double total; - double total_leakage; - int64_t timestamp; - int64_t last_clear_timestamp; - - double current_power; - int64_t current_power_timestamp; - - double current_leakage_power; - int64_t current_leakage_power_timestamp; - - bool dumped; - }; - - class power_source - { - friend class component_power; - - public: - inline void account_event() { this->trace->account_quantum(this->quantum); } - inline void power_on() { if (!this->is_on) this->trace->set_power(this->quantum, this->is_leakage); this->is_on = true; } - inline void power_off() { if (this->is_on) this->trace->set_power(-this->quantum, this->is_leakage); this->is_on = false; } - - inline double get_quantum() { return this->quantum; } - +/** + * @brief Power framework + * + * Power is modeled through 2 classes, one for declaring sources of power consumptions + * and another one for collecting consumed power from sources. + * A note on method visibility: all the global functions are there for the HW models + * to model HW power consumption while protected methods are there for the engine + * to manage the overall power framework. + * + */ - protected: - int init(component *top, std::string name, js::config *config, power_trace *trace, bool is_leakage); - void setup(double temp, double volt, double freq); +namespace vp +{ + +#define VP_POWER_DEFAULT_TEMP 25 +#define VP_POWER_DEFAULT_VOLT 1.2 +#define VP_POWER_DEFAULT_FREQ 50 + + class Linear_table; + class power_engine; + class power_source; + class power_trace; + + /** + * @brief Used to model a power source + * + * A power source is a piece of hardware which is consuming energy. + * This class can be instantiated any time as needed to model all the ways + * an IP is consuming energy. + * It can be used for dynamic or leakage power, or for both at the same time, since + * they are accounted separetly. + * For dynamic power it can be used either as a quantum-based power source or + * as background power source. + * A quantum-based power source will consume energy only when an event is triggered. + * A background power source will constantly consume power as soon as it is on. + * A leakage power source is similar to a background power source, but is just accounted + * differently in the power report. + */ + class power_source + { + friend class component_power; + + public: + /** + * @brief Account the event + * + * This should be used in quantum-based power source to trigger the consumption + * of a quantum of energy. + * This will just add the quantum of energy to the current consumed energy. + */ + inline void account_event(); + + /** + * @brief Start accounting power + * + * This should be used either for a background dynamic power or for leakage + * to start accounting the associated power. + * The power is accounted until the power source is turned off. + * This is actually converted to energy and accounted on the total of energy + * anytime current power is changed or source is turned off. + */ + inline void power_on(); + + /** + * @brief Stop accounting power + * + * This will trigger the accounting of energy for the current windows + * and stop accounting power until it is turned on again. + */ + inline void power_off(); + + protected: + /** + * @brief Initialize a power source + * + * @param top Component containing the power source. + * @param name Name of the power source, used in traces. + * @param data Configuration of the power source, giving power numbers. + * @param trace Power trace where this source should account power consumed. + * @param is_leakage True if this source is consuming leakage power, false if it is dynamic power. + */ + int init(component *top, std::string name, js::config *config, power_trace *trace, bool is_leakage); + + /** + * @brief Set temperature, voltage and frequency + * + * The power source will adapt its power number according to the given characteristics. + * + * @param temp Temperature + * @param volt Voltage + * @param freq Frequency + */ + void setup(double temp, double volt, double freq); + + private: + Linear_table *table = NULL; // Table of power values for all supported temperatures and voltages + // imported from the json configuration given when trace was initialized. + double quantum; // Current quantumm of energy. Only valid in quantum-based power sources. + // The current value is estimated depending on voltage and temperature according + // to the provided json configuration. + component *top; // Top component containing the power source + power_trace *trace; // Power trace where the power consumption should be reported. + bool is_on = false; // True is the source is on and backgroun-power and leakage should be reported + bool is_leakage; // True is the power source is for leakage + }; + + + /** + * @brief Used for tracing power consumption + * + * This class can be used to gather the power consumption of several power sources and + * trace it through VCD traces and power reports. + * Each power source must be associated to a power trace and a power trace can be associated + * to one ore more power traces. + */ + class power_trace + { + friend class power_source; + friend class component_power; + friend class power_engine; + + public: + /** + * @brief Init the trace + * + * @param top Component containing the power trace. + * @param name Name of the power trace. It will be used in traces and in the power report + */ + int init(component *top, std::string name); + + /** + * @brief Return if the trace is enabled + * + * @return true if the trace is active and should account power + * @return false if the trace is inactive and any activity should be ignored + */ + inline bool get_active() { return trace.get_event_active(); } + + + inline double get_value(); + + inline double get_total(); + + inline double get_total_leakage(); + + bool is_dumped() { return this->dumped; } + + power_trace *get_top_trace(); + + void clear(); + + void flush(); + + void dump(FILE *file); + + void collect(); + + void reg_top_trace(vp::power_trace *trace); + void reg_child_trace(vp::power_trace *trace); + + void get(double *dynamic, double *leakage); + + vp::trace trace; + + void incr_power(double power_incr, bool is_leakage); + + inline void account_quantum(double quantum); + + private: + // Compute the energy spent on the current windows and account it to the total amount of energy. + // This should be called everytime the current power is updated or before it is dumped. + void account_power(); + void account_leakage_power(); + void incr(double quantum, bool is_leakage = false); + + + component *top; + power_trace *top_trace = NULL; + std::vector child_traces; + double value; + double total; + double total_leakage; + int64_t timestamp; + int64_t last_clear_timestamp; + + double current_power; // Power of the current power. This is used to account the energy over the period + // being measured. Everytime it is updated, the energy should be computed + // and the timestamp updated. + int64_t current_power_timestamp; // Indicate the timestamp of the last time the energy was accounted + // This is used everytime power is updated or dumped to compute the energy spent + // over the period. + double current_leakage_power; + int64_t current_leakage_power_timestamp; - private: - Linear_table *table = NULL; - double quantum; - component *top; - power_trace *trace; - bool is_on = false; - bool is_leakage; - }; + bool dumped; + }; }; - -#endif \ No newline at end of file diff --git a/engine/include/vp/power/power_engine.hpp b/engine/include/vp/power/power_engine.hpp index d4a95cc..fd2f0e7 100644 --- a/engine/include/vp/power/power_engine.hpp +++ b/engine/include/vp/power/power_engine.hpp @@ -40,6 +40,10 @@ namespace vp { virtual void stop_capture() {} virtual void reg_trace(vp::power_trace *trace) {} + + std::vector traces; + + vp::component *time_engine; }; }; diff --git a/engine/python/vp_runner.py b/engine/python/vp_runner.py deleted file mode 100644 index 4b57971..0000000 --- a/engine/python/vp_runner.py +++ /dev/null @@ -1,1422 +0,0 @@ -# -# Copyright (C) 2020 GreenWaves Technologies, SAS, ETH Zurich and -# University of Bologna -# -# 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. -# - -# -# Authors: Germain Haugou, GreenWaves Technologies (germain.haugou@greenwaves-technologies.com) -# - -import vp_core -import runner.stim_utils -from os import listdir -from os.path import isfile, join, isdir -import os.path - -from plp_platform import * -import runner.plp_flash_stimuli as plp_flash_stimuli -import shlex -import json_tools as js -import pulp_config -from prettytable import PrettyTable -import imp -import ctypes - -import gtkw_new - -gtkw_colors = [ -"alice blue", -"AliceBlue", -"antique white", -"AntiqueWhite", -"AntiqueWhite1", -"AntiqueWhite2", -"AntiqueWhite3", -"AntiqueWhite4", -"aquamarine", -"aquamarine1", -"aquamarine2", -"aquamarine3", -"aquamarine4", -"azure", -"azure1", -"azure2", -"azure3", -"azure4", -"beige", -"bisque", -"bisque1", -"bisque2", -"bisque3", -"bisque4", -"black", -"blanched almond", -"BlanchedAlmond", -"blue", -"blue violet", -"blue1", -"blue2", -"blue3", -"blue4", -"BlueViolet", -"brown", -"brown1", -"brown2", -"brown3", -"brown4", -"burlywood", -"burlywood1", -"burlywood2", -"burlywood3", -"burlywood4", -"cadet blue", -"CadetBlue", -"CadetBlue1", -"CadetBlue2", -"CadetBlue3", -"CadetBlue4", -"chartreuse", -"chartreuse1", -"chartreuse2", -"chartreuse3", -"chartreuse4", -"chocolate", -"chocolate1", -"chocolate2", -"chocolate3", -"chocolate4", -"coral", -"coral1", -"coral2", -"coral3", -"coral4", -"cornflower blue", -"CornflowerBlue", -"cornsilk", -"cornsilk1", -"cornsilk2", -"cornsilk3", -"cornsilk4", -"cyan", -"cyan1", -"cyan2", -"cyan3", -"cyan4", -"dark blue", -"dark cyan", -"dark goldenrod", -"dark gray", -"dark green", -"dark grey", -"dark khaki", -"dark magenta", -"dark olive green", -"dark orange", -"dark orchid", -"dark red", -"dark salmon", -"dark sea green", -"dark slate blue", -"dark slate gray", -"dark slate grey", -"dark turquoise", -"dark violet", -"DarkBlue", -"DarkCyan", -"DarkGoldenrod", -"DarkGoldenrod1", -"DarkGoldenrod2", -"DarkGoldenrod3", -"DarkGoldenrod4", -"DarkGray", -"DarkGreen", -"DarkGrey", -"DarkKhaki", -"DarkMagenta", -"DarkOliveGreen", -"DarkOliveGreen1", -"DarkOliveGreen2", -"DarkOliveGreen3", -"DarkOliveGreen4", -"DarkOrange", -"DarkOrange1", -"DarkOrange2", -"DarkOrange3", -"DarkOrange4", -"DarkOrchid", -"DarkOrchid1", -"DarkOrchid2", -"DarkOrchid3", -"DarkOrchid4", -"DarkRed", -"DarkSalmon", -"DarkSeaGreen", -"DarkSeaGreen1", -"DarkSeaGreen2", -"DarkSeaGreen3", -"DarkSeaGreen4", -"DarkSlateBlue", -"DarkSlateGray", -"DarkSlateGray1", -"DarkSlateGray2", -"DarkSlateGray3", -"DarkSlateGray4", -"DarkSlateGrey", -"DarkTurquoise", -"DarkViolet", -"deep pink", -"deep sky blue", -"DeepPink", -"DeepPink1", -"DeepPink2", -"DeepPink3", -"DeepPink4", -"DeepSkyBlue", -"DeepSkyBlue1", -"DeepSkyBlue2", -"DeepSkyBlue3", -"DeepSkyBlue4", -"dim gray", -"dim grey", -"DimGray", -"DimGrey", -"dodger blue", -"DodgerBlue", -"DodgerBlue1", -"DodgerBlue2", -"DodgerBlue3", -"DodgerBlue4", -"firebrick", -"firebrick1", -"firebrick2", -"firebrick3", -"firebrick4", -"floral white", -"FloralWhite", -"forest green", -"ForestGreen", -"gainsboro", -"ghost white", -"GhostWhite", -"gold", -"gold1", -"gold2", -"gold3", -"gold4", -"goldenrod", -"goldenrod1", -"goldenrod2", -"goldenrod3", -"goldenrod4", -"gray", -"gray0", -"gray1", -"gray10", -"gray100", -"gray11", -"gray12", -"gray13", -"gray14", -"gray15", -"gray16", -"gray17", -"gray18", -"gray19", -"gray2", -"gray20", -"gray21", -"gray22", -"gray23", -"gray24", -"gray25", -"gray26", -"gray27", -"gray28", -"gray29", -"gray3", -"gray30", -"gray31", -"gray32", -"gray33", -"gray34", -"gray35", -"gray36", -"gray37", -"gray38", -"gray39", -"gray4", -"gray40", -"gray41", -"gray42", -"gray43", -"gray44", -"gray45", -"gray46", -"gray47", -"gray48", -"gray49", -"gray5", -"gray50", -"gray51", -"gray52", -"gray53", -"gray54", -"gray55", -"gray56", -"gray57", -"gray58", -"gray59", -"gray6", -"gray60", -"gray61", -"gray62", -"gray63", -"gray64", -"gray65", -"gray66", -"gray67", -"gray68", -"gray69", -"gray7", -"gray70", -"gray71", -"gray72", -"gray73", -"gray74", -"gray75", -"gray76", -"gray77", -"gray78", -"gray79", -"gray8", -"gray80", -"gray81", -"gray82", -"gray83", -"gray84", -"gray85", -"gray86", -"gray87", -"gray88", -"gray89", -"gray9", -"gray90", -"gray91", -"gray92", -"gray93", -"gray94", -"gray95", -"gray96", -"gray97", -"gray98", -"gray99", -"green", -"green yellow", -"green1", -"green2", -"green3", -"green4", -"GreenYellow", -"grey", -"grey0", -"grey1", -"grey10", -"grey100", -"grey11", -"grey12", -"grey13", -"grey14", -"grey15", -"grey16", -"grey17", -"grey18", -"grey19", -"grey2", -"grey20", -"grey21", -"grey22", -"grey23", -"grey24", -"grey25", -"grey26", -"grey27", -"grey28", -"grey29", -"grey3", -"grey30", -"grey31", -"grey32", -"grey33", -"grey34", -"grey35", -"grey36", -"grey37", -"grey38", -"grey39", -"grey4", -"grey40", -"grey41", -"grey42", -"grey43", -"grey44", -"grey45", -"grey46", -"grey47", -"grey48", -"grey49", -"grey5", -"grey50", -"grey51", -"grey52", -"grey53", -"grey54", -"grey55", -"grey56", -"grey57", -"grey58", -"grey59", -"grey6", -"grey60", -"grey61", -"grey62", -"grey63", -"grey64", -"grey65", -"grey66", -"grey67", -"grey68", -"grey69", -"grey7", -"grey70", -"grey71", -"grey72", -"grey73", -"grey74", -"grey75", -"grey76", -"grey77", -"grey78", -"grey79", -"grey8", -"grey80", -"grey81", -"grey82", -"grey83", -"grey84", -"grey85", -"grey86", -"grey87", -"grey88", -"grey89", -"grey9", -"grey90", -"grey91", -"grey92", -"grey93", -"grey94", -"grey95", -"grey96", -"grey97", -"grey98", -"grey99", -"honeydew", -"honeydew1", -"honeydew2", -"honeydew3", -"honeydew4", -"hot pink", -"HotPink", -"HotPink1", -"HotPink2", -"HotPink3", -"HotPink4", -"indian red", -"IndianRed", -"IndianRed1", -"IndianRed2", -"IndianRed3", -"IndianRed4", -"ivory", -"ivory1", -"ivory2", -"ivory3", -"ivory4", -"khaki", -"khaki1", -"khaki2", -"khaki3", -"khaki4", -"lavender", -"lavender blush", -"LavenderBlush", -"LavenderBlush1", -"LavenderBlush2", -"LavenderBlush3", -"LavenderBlush4", -"lawn green", -"LawnGreen", -"lemon chiffon", -"LemonChiffon", -"LemonChiffon1", -"LemonChiffon2", -"LemonChiffon3", -"LemonChiffon4", -"light blue", -"light coral", -"light cyan", -"light goldenrod", -"light goldenrod yellow", -"light gray", -"light green", -"light grey", -"light pink", -"light salmon", -"light sea green", -"light sky blue", -"light slate blue", -"light slate gray", -"light slate grey", -"light steel blue", -"light yellow", -"LightBlue", -"LightBlue1", -"LightBlue2", -"LightBlue3", -"LightBlue4", -"LightCoral", -"LightCyan", -"LightCyan1", -"LightCyan2", -"LightCyan3", -"LightCyan4", -"LightGoldenrod", -"LightGoldenrod1", -"LightGoldenrod2", -"LightGoldenrod3", -"LightGoldenrod4", -"LightGoldenrodYellow", -"LightGray", -"LightGreen", -"LightGrey", -"LightPink", -"LightPink1", -"LightPink2", -"LightPink3", -"LightPink4", -"LightSalmon", -"LightSalmon1", -"LightSalmon2", -"LightSalmon3", -"LightSalmon4", -"LightSeaGreen", -"LightSkyBlue", -"LightSkyBlue1", -"LightSkyBlue2", -"LightSkyBlue3", -"LightSkyBlue4", -"LightSlateBlue", -"LightSlateGray", -"LightSlateGrey", -"LightSteelBlue", -"LightSteelBlue1", -"LightSteelBlue2", -"LightSteelBlue3", -"LightSteelBlue4", -"LightYellow", -"LightYellow1", -"LightYellow2", -"LightYellow3", -"LightYellow4", -"lime green", -"LimeGreen", -"linen", -"magenta", -"magenta1", -"magenta2", -"magenta3", -"magenta4", -"maroon", -"maroon1", -"maroon2", -"maroon3", -"maroon4", -"medium aquamarine", -"medium blue", -"medium orchid", -"medium purple", -"medium sea green", -"medium slate blue", -"medium spring green", -"medium turquoise", -"medium violet red", -"MediumAquamarine", -"MediumBlue", -"MediumOrchid", -"MediumOrchid1", -"MediumOrchid2", -"MediumOrchid3", -"MediumOrchid4", -"MediumPurple", -"MediumPurple1", -"MediumPurple2", -"MediumPurple3", -"MediumPurple4", -"MediumSeaGreen", -"MediumSlateBlue", -"MediumSpringGreen", -"MediumTurquoise", -"MediumVioletRed", -"midnight blue", -"MidnightBlue", -"mint cream", -"MintCream", -"misty rose", -"MistyRose", -"MistyRose1", -"MistyRose2", -"MistyRose3", -"MistyRose4", -"moccasin", -"navajo white", -"NavajoWhite", -"NavajoWhite1", -"NavajoWhite2", -"NavajoWhite3", -"NavajoWhite4", -"navy", -"navy blue", -"NavyBlue", -"old lace", -"OldLace", -"olive drab", -"OliveDrab", -"OliveDrab1", -"OliveDrab2", -"OliveDrab3", -"OliveDrab4", -"orange", -"orange red", -"orange1", -"orange2", -"orange3", -"orange4", -"OrangeRed", -"OrangeRed1", -"OrangeRed2", -"OrangeRed3", -"OrangeRed4", -"orchid", -"orchid1", -"orchid2", -"orchid3", -"orchid4", -"pale goldenrod", -"pale green", -"pale turquoise", -"pale violet red", -"PaleGoldenrod", -"PaleGreen", -"PaleGreen1", -"PaleGreen2", -"PaleGreen3", -"PaleGreen4", -"PaleTurquoise", -"PaleTurquoise1", -"PaleTurquoise2", -"PaleTurquoise3", -"PaleTurquoise4", -"PaleVioletRed", -"PaleVioletRed1", -"PaleVioletRed2", -"PaleVioletRed3", -"PaleVioletRed4", -"papaya whip", -"PapayaWhip", -"peach puff", -"PeachPuff", -"PeachPuff1", -"PeachPuff2", -"PeachPuff3", -"PeachPuff4", -"peru", -"pink", -"pink1", -"pink2", -"pink3", -"pink4", -"plum", -"plum1", -"plum2", -"plum3", -"plum4", -"powder blue", -"PowderBlue", -"purple", -"purple1", -"purple2", -"purple3", -"purple4", -"red", -"red1", -"red2", -"red3", -"red4", -"rosy brown", -"RosyBrown", -"RosyBrown1", -"RosyBrown2", -"RosyBrown3", -"RosyBrown4", -"royal blue", -"RoyalBlue", -"RoyalBlue1", -"RoyalBlue2", -"RoyalBlue3", -"RoyalBlue4", -"saddle brown", -"SaddleBrown", -"salmon", -"salmon1", -"salmon2", -"salmon3", -"salmon4", -"sandy brown", -"SandyBrown", -"sea green", -"SeaGreen", -"SeaGreen1", -"SeaGreen2", -"SeaGreen3", -"SeaGreen4", -"seashell", -"seashell1", -"seashell2", -"seashell3", -"seashell4", -"sienna", -"sienna1", -"sienna2", -"sienna3", -"sienna4", -"sky blue", -"SkyBlue", -"SkyBlue1", -"SkyBlue2", -"SkyBlue3", -"SkyBlue4", -"slate blue", -"slate gray", -"slate grey", -"SlateBlue", -"SlateBlue1", -"SlateBlue2", -"SlateBlue3", -"SlateBlue4", -"SlateGray", -"SlateGray1", -"SlateGray2", -"SlateGray3", -"SlateGray4", -"SlateGrey", -"snow", -"snow1", -"snow2", -"snow3", -"snow4", -"spring green", -"SpringGreen", -"SpringGreen1", -"SpringGreen2", -"SpringGreen3", -"SpringGreen4", -"steel blue", -"SteelBlue", -"SteelBlue1", -"SteelBlue2", -"SteelBlue3", -"SteelBlue4", -"tan", -"tan1", -"tan2", -"tan3", -"tan4", -"thistle", -"thistle1", -"thistle2", -"thistle3", -"thistle4", -"tomato", -"tomato1", -"tomato2", -"tomato3", -"tomato4", -"turquoise", -"turquoise1", -"turquoise2", -"turquoise3", -"turquoise4", -"violet", -"violet red", -"VioletRed", -"VioletRed1", -"VioletRed2", -"VioletRed3", -"VioletRed4", -"wheat", -"wheat1", -"wheat2", -"wheat3", -"wheat4", -"white", -"white smoke", -"WhiteSmoke", -"yellow", -"yellow green", -"yellow1", -"yellow2", -"yellow3", -"yellow4", -"YellowGreen" -] - -class Trace(object): - - def __init__(self, tag, name, width=None): - self.tag = tag - self.name = name - self.width = width - self.vcd_name = name - self.vp_name = '/' + name.replace('.', '/') - if width is not None: - self.vcd_name = self.vcd_name + width - - def get_vcd(self): - return self.vcd_name - - def get_vp(self): - return self.vp_name - - -class Trace_pool(object): - - def __init__(self): - self.traces = [] - - def get(self, tag, name, width=None): - trace = Trace(tag, name, width) - self.traces.append(trace) - return trace.get_vcd() - - def get_traces(self, tags=None): - if tags is None: - return self.traces - else: - result = [] - for trace in self.traces: - if trace.tag is None or trace.tag in tags: - result.append(trace) - return result - - -def gen_gtkw_core_traces(gtkw, tp, path): - gtkw.trace(tp.get('pc', path + '.pc', '[31:0]'), 'pc') - gtkw.trace(tp.get('asm', path + '.asm'), 'asm') - gtkw.trace(tp.get('debug', path + '.func'), 'func') - gtkw.trace(tp.get('debug', path + '.inline_func'), 'inline_func') - gtkw.trace(tp.get('debug', path + '.file'), 'file') - gtkw.trace(tp.get('debug', path + '.line', '[31:0]'), 'line', datafmt='dec') - with gtkw.group('events', closed=True): - gtkw.trace(tp.get('core_events', path + '.pcer_cycles'), 'cycles') - gtkw.trace(tp.get('core_events', path + '.pcer_instr'), 'instr') - gtkw.trace(tp.get('core_events', path + '.pcer_ld_stall'), 'ld_stall') - gtkw.trace(tp.get('core_events', path + '.pcer_jmp_stall'), 'jmp_stall') - gtkw.trace(tp.get('core_events', path + '.pcer_imiss'), 'imiss') - gtkw.trace(tp.get('core_events', path + '.pcer_ld'), 'ld') - gtkw.trace(tp.get('core_events', path + '.pcer_st'), 'st') - gtkw.trace(tp.get('core_events', path + '.pcer_jump'), 'jump') - gtkw.trace(tp.get('core_events', path + '.pcer_branch'), 'branch') - gtkw.trace(tp.get('core_events', path + '.pcer_taken_branch'), 'taken_branch') - gtkw.trace(tp.get('core_events', path + '.pcer_rvc'), 'rvc') - gtkw.trace(tp.get('core_events', path + '.pcer_ld_ext'), 'ld_ext') - gtkw.trace(tp.get('core_events', path + '.pcer_st_ext'), 'st_ext') - gtkw.trace(tp.get('core_events', path + '.pcer_ld_ext_cycles'), 'ld_ext_cycles') - gtkw.trace(tp.get('core_events', path + '.pcer_st_ext_cycles'), 'st_ext_cycles') - gtkw.trace(tp.get('core_events', path + '.pcer_tcdm_cont'), 'tcdm_cont') - gtkw.trace(tp.get('core_events', path + '.misaligned'), 'misaligned') - - -def gen_gtkw_icache_traces(gtkw, tp, path, nb_ways, nb_sets): - gtkw.trace(tp.get('refill', path + '.refill', '[31:0]'), 'refill') - gtkw.trace(tp.get('input', path + '.port_0', '[31:0]'), 'input') - for way in range(0, nb_ways): - with gtkw.group('way_%d' % way, closed=True): - for line in range(0, nb_sets): - name = 'tag_%d' % line - gtkw.trace(tp.get(name, path + '.set_%d.line_%d' % (way, line), '[31:0]'), name) - - - -def check_user_traces(gtkw, tp, path, user_traces): - if user_traces is not None: - traces = user_traces.get_items() - if traces is not None: - for name, trace in user_traces.get_items().items(): - view_path = trace.get_str('view_path') - - if view_path.find('.') == -1: - parent = None - name = view_path - else: - parent, name = view_path.rsplit('.', 1) - - if parent == path: - tag = trace.get_str('tag') - vcd_path = trace.get_str('vcd_path') - trace_filter = trace.get_str('filter') - if trace_filter is not None: - trace_filter = os.path.join(os.getcwd(), trace_filter) - - width = None - if vcd_path.find('[') != -1: - vcd_path, width = vcd_path.split('[') - width = '[' + width - - gtkw.trace(tp.get(tag, vcd_path, width), view_path, datafmt='dec', translate_filter_file=trace_filter) - - -def gen_gtkw_vector(gtkw, path, name, traces=[], trace_filter=None): - vector_traces = [] - - for trace in traces: - for i in range(0, 8): - vector_traces.append('(%d)%s' % (i, trace[0])) - - vector_filer = os.path.join(os.getcwd(), '%s.%s.txt' % (path, name)) - - with open(vector_filer, 'w') as file: - for i in range(0, len(traces)+1): - file.write('%2d ?CadetBlue?ACTIVE\n' % i) - - with gtkw.vector(name, traces=vector_traces, extraflags=['popcnt', 'closed'], color='green', datafmt='dec', translate_filter_file=vector_filer): - - for trace in traces: - gtkw.trace(trace[0], trace[1], translate_filter_file=trace_filter) - - -def gen_rt_traces_for_cluster(config, gv_config, cluster, cluster_alias): - nb_pe = config.get_int('**/%s/nb_pe' % cluster) - for i in range(0, nb_pe): - pe_conf = { - 'tag': 'overview', - 'type': 'int', - 'path': '/user/runtime/%s/pe%d' % (cluster_alias, i), - 'vcd_path': 'user.runtime.%s.pe%d[31:0]' % (cluster_alias, i), - 'view_path': 'overview.%s.runtime.pe%d' % (cluster, i), - 'filter': 'rt_state.txt' - } - - gv_config.set('events/include_regex/%s_pe%d' % (cluster, i), pe_conf) - - - -def gen_rt_traces(config, gv_config): - nb_cluster = config.get_int('**/nb_cluster') - - if nb_cluster is not None: - for cid in range(0, nb_cluster): - gen_rt_traces_for_cluster(config, gv_config, 'cluster' if cid == 0 else 'cluster_%d' % cid, 'cluster_%d' % cid) - - - -def gen_gtkw_files(config, gv_config): - nb_pe = config.get_int('**/cluster/nb_pe') - - user_traces = gv_config.get('**/events/traces') - tags = gv_config.get('**/events/tags').get_dict() - - gen_rt_traces(config, gv_config) - - # Remove trace file so that we can switch between regular file and fifo - if os.path.exists('all.vcd'): - os.remove('all.vcd') - - core_state_file = os.path.join(os.getcwd(), 'core_state.txt') - rt_state_file = os.path.join(os.getcwd(), 'rt_state.txt') - all_state_file = os.path.join(os.getcwd(), 'all_state.txt') - - with open(core_state_file, 'w') as file: - file.write('01 ?CadetBlue?ACTIVE\n') - - with open(all_state_file, 'w') as file: - for i in range(0, len(gtkw_colors)): - file.write('%d ?%s?ACTIVE\n' % (i, gtkw_colors[i])) - - with open(rt_state_file, 'w') as file: - file.write('0 ?DarkSlateGray3?ENTRY\n') - file.write('1 ?CadetBlue?FORK\n') - file.write('2 ?DarkSlateGrey?BARRIER\n') - file.write('3 ?DarkSlateGrey?CRITICAL\n') - file.write('4 ?DarkSlateGrey?DMA_PUSH\n') - file.write('5 ?DarkSlateGrey?DMA_WAIT\n') - - tp = Trace_pool() - - if len(gv_config.get('events/include_regex').get()) != 0 or gv_config.get_bool('events/enabled'): - path = os.path.join(os.getcwd(), 'view.gtkw') - with open(path, 'w') as file: - gtkw = gtkw_new.GTKWSave(file) - - gtkw.dumpfile('all.vcd') - - with gtkw.group('overview'): - check_user_traces(gtkw, tp, 'overview', user_traces) - with gtkw.group('soc'): - check_user_traces(gtkw, tp, 'overview.soc', user_traces) - gtkw.trace(tp.get('overview', 'sys.board.chip.soc.fc.state', '[7:0]'), 'fc', translate_filter_file=core_state_file) - - gen_gtkw_vector(gtkw, 'sys.board.chip.soc', 'udma', trace_filter=core_state_file, traces=[ - [tp.get('overview', 'sys.board.chip.soc.udma.spim0_rx.state', '[7:0]'), 'spim0_rx'], - [tp.get('overview', 'sys.board.chip.soc.udma.spim0_tx.state', '[7:0]'), 'spim0_tx'], - [tp.get('overview', 'sys.board.chip.soc.udma.spim1_rx.state', '[7:0]'), 'spim1_rx'], - [tp.get('overview', 'sys.board.chip.soc.udma.spim1_tx.state', '[7:0]'), 'spim1_tx'], - [tp.get('overview', 'sys.board.chip.soc.udma.hyper0_rx.state', '[7:0]'),'hyper0_rx' ], - [tp.get('overview', 'sys.board.chip.soc.udma.hyper0_tx.state', '[7:0]'), 'hyper0_tx'], - [tp.get('overview', 'sys.board.chip.soc.udma.i2c0_rx.state', '[7:0]'), 'ic20_rx'], - [tp.get('overview', 'sys.board.chip.soc.udma.i2c0_tx.state', '[7:0]'), 'ic20_tx'], - [tp.get('overview', 'sys.board.chip.soc.udma.i2c1_rx.state', '[7:0]'), 'ic21_rx'], - [tp.get('overview', 'sys.board.chip.soc.udma.i2c1_tx.state', '[7:0]'), 'i2c1_tx'], - [tp.get('overview', 'sys.board.chip.soc.udma.i2s0_rx.state', '[7:0]'), 'i2s0_rx'], - [tp.get('overview', 'sys.board.chip.soc.udma.i2s0_tdm_0.state', '[7:0]'), 'i2s0_tdm_0'], - [tp.get('overview', 'sys.board.chip.soc.udma.i2s0_tdm_1.state', '[7:0]'), 'i2s0_tdm_1'], - [tp.get('overview', 'sys.board.chip.soc.udma.i2s0_tdm_2.state', '[7:0]'), 'i2s0_tdm_2'], - [tp.get('overview', 'sys.board.chip.soc.udma.i2s0_tdm_3.state', '[7:0]'), 'i2s0_tdm_3'], - [tp.get('overview', 'sys.board.chip.soc.udma.i2s0_tdm_4.state', '[7:0]'), 'i2s0_tdm_4'], - [tp.get('overview', 'sys.board.chip.soc.udma.i2s0_tdm_5.state', '[7:0]'), 'i2s0_tdm_5'], - [tp.get('overview', 'sys.board.chip.soc.udma.i2s0_tdm_6.state', '[7:0]'), 'i2s0_tdm_6'], - [tp.get('overview', 'sys.board.chip.soc.udma.i2s0_tdm_7.state', '[7:0]'), 'i2s0_tdm_7'], - [tp.get('overview', 'sys.board.chip.soc.udma.uart0_rx.state', '[7:0]'), 'uart0_rx'], - [tp.get('overview', 'sys.board.chip.soc.udma.uart0_tx.state', '[7:0]'), 'uart0_tx'], - [tp.get('overview', 'sys.board.chip.soc.udma.cpi0_rx.state', '[7:0]'), 'cpi0_rx'] - ]) - - gtkw.trace(tp.get('overview', 'sys.board.chip.soc_clock.period'), 'period') - gtkw.trace(tp.get('clock', 'sys.board.chip.soc_clock.cycles'), 'cycles') - - if nb_pe is not None: - with gtkw.group('cluster'): - check_user_traces(gtkw, tp, 'overview.cluster', user_traces) - for i in range(0, nb_pe): - gtkw.trace(tp.get('overview', 'sys.board.chip.cluster.pe%d.state' % i, '[7:0]'), 'pe_%d' % i, translate_filter_file=core_state_file) - - gen_gtkw_vector(gtkw, 'sys.board.chip.cluster', 'dma', trace_filter=core_state_file, traces=[ - [tp.get('overview', 'sys.board.chip.cluster.dma.channel_0', '[7:0]'), 'channel_0'], - [tp.get('overview', 'sys.board.chip.cluster.dma.channel_1', '[7:0]'), 'channel_1'], - [tp.get('overview', 'sys.board.chip.cluster.dma.channel_2', '[7:0]'), 'channel_2'], - [tp.get('overview', 'sys.board.chip.cluster.dma.channel_3', '[7:0]'), 'channel_3'], - [tp.get('overview', 'sys.board.chip.cluster.dma.channel_4', '[7:0]'), 'channel_4'], - [tp.get('overview', 'sys.board.chip.cluster.dma.channel_5', '[7:0]'), 'channel_5'], - [tp.get('overview', 'sys.board.chip.cluster.dma.channel_6', '[7:0]'), 'channel_6'], - [tp.get('overview', 'sys.board.chip.cluster.dma.channel_7', '[7:0]'), 'channel_7'], - [tp.get('overview', 'sys.board.chip.cluster.dma.channel_8', '[7:0]'), 'channel_8'], - [tp.get('overview', 'sys.board.chip.cluster.dma.channel_9', '[7:0]'), 'channel_9'], - [tp.get('overview', 'sys.board.chip.cluster.dma.channel_10', '[7:0]'), 'channel_10'], - [tp.get('overview', 'sys.board.chip.cluster.dma.channel_11', '[7:0]'), 'channel_11'], - [tp.get('overview', 'sys.board.chip.cluster.dma.channel_12', '[7:0]'), 'channel_12'], - [tp.get('overview', 'sys.board.chip.cluster.dma.channel_13', '[7:0]'), 'channel_13'], - [tp.get('overview', 'sys.board.chip.cluster.dma.channel_14', '[7:0]'), 'channel_14'], - [tp.get('overview', 'sys.board.chip.cluster.dma.channel_15', '[7:0]'), 'channel_15'], - ]) - - gtkw.trace(tp.get('overview', 'sys.board.chip.cluster_clock.period'), 'period') - gtkw.trace(tp.get('clock', 'sys.board.chip.cluster_clock.cycles'), 'cycles') - - with gtkw.group('runtime', closed=True): - check_user_traces(gtkw, tp, 'overview.cluster.runtime', user_traces) - - with gtkw.group('stats', closed=True): - check_user_traces(gtkw, tp, 'overview.cluster.stats', user_traces) - for i in range(0, nb_pe): - gtkw.trace(tp.get('overview', 'sys.board.chip.cluster.pe%d.ipc_stat' % i), 'pe%d_ipc' % i, extraflags=['analog_step', 'analog_fullscale']) - - with gtkw.group('chip', closed=True): - check_user_traces(gtkw, tp, 'chip', user_traces) - with gtkw.group('fc', closed=True): - check_user_traces(gtkw, tp, 'chip.fc', user_traces) - gen_gtkw_core_traces(gtkw, tp, 'sys.board.chip.soc.fc') - - if config.get('**/fc_icache') is not None: - with gtkw.group('fc_icache', closed=True): - check_user_traces(gtkw, tp, 'chip.fc_icache', user_traces) - gen_gtkw_icache_traces(gtkw, tp, 'sys.board.chip.soc.fc_icache', 1< 0: - binary = binary[0] - else: - binary = None - - if plp_flash_stimuli.genFlashImage( - raw_stim=self.get_flash_preload_file(), - bootBinary=binary, - comps=comps, - raw_fs=raw_fs, - verbose=self.get_json().get('**/runner/verbose').get(), - archi=self.get_json().get('**/pulp_chip_family').get(), - flashType=self.get_json().get('**/runner/flash_type').get(), - encrypt=encrypted, aesKey=aes_key, aesIv=aes_iv): - return -1 - - if self.get_json().get('**/efuse') is not None: - efuse = runner.stim_utils.Efuse(self.get_json(), verbose=self.get_json().get('**/runner/verbose').get()) - efuse.gen_stim_txt('efuse_preload.data') - - autorun_conf = self.get_json().get('**/debug_bridge/autorun') - if autorun_conf is not None and autorun_conf.get_bool() and not self.config.getOption('reentrant'): - - with open('autorun_config.json', 'w') as file: - file.write(self.get_json().dump_to_string()) - - options = self.get_json().get_child_str('**/debug_bridge/options') - if options is None: - options = '' - - cmd_options = ['pulp-run-bridge', '--dir=%s' % self.config.getOption('dir'), '--config-file=%s/autorun_config.json' % self.config.getOption('dir'), '--options=%s' % options] - if self.get_json().get_child_bool('**/runner/wait_pulp_run'): - cmd_options.append('--wait-pulp-run') - - os.execlp(*cmd_options) - - - autorun = self.get_json().get('**/debug_bridge/autorun') - bridge_active = self.get_json().get('**/debug_bridge/active') - - self.get_json().set('**/debug_bridge/cable/type', 'jtag-proxy') - - bridge = autorun is not None and autorun.get_bool() or \ - self.get_json().get('**/gdb/active').get_bool() or \ - bridge_active is not None and bridge_active.get_bool() - - if bridge: - self.get_json().get('**/jtag_proxy').set('active', True) - self.get_json().get('gvsoc').set('use_external_bridge', True) - - if not self.get_json().get_child_bool('**/runner/wait_pulp_run'): - self.get_json().get('gvsoc').set('no_exit', True) - - if not bridge and self.get_json().get_child_str('**/runner/boot-mode') != 'bridge' and self.get_json().get_child_str('**/runner/boot-mode').find('rom') == -1 and self.get_json().get_child_str('**/runner/boot-mode') != 'jtag': - binaries = self.get_json().get('**/runner/binaries').get_dict() - for binary in binaries: - self.get_json().get('**/plt_loader').set('binaries', binary) - - if self.gen_rom_stimuli: - self.get_json().get('**/soc/rom').set('stim_file', 'stimuli/rom.bin') - - if self.get_json().get('**/efuse') is not None: - self.get_json().get('**/soc/efuse').set('stim_file', 'efuse_preload.data') - - if self.gen_flash_stimuli: - if self.get_json().get('**/spiflash') is not None: - self.get_json().get('**/spiflash').set('stim_file', self.get_flash_preload_file()) - if self.get_json().get('**/mram') is not None: - self.get_json().get('**/soc/mram').set('stim_file', self.get_flash_preload_file()) - - - if self.get_json().get_child_str('**/runner/boot-mode') != 'rom' and not bridge: - set_pc_addr = self.get_json().get_child_int('**/loader/set_pc_addr') - if set_pc_addr != None: - self.get_json().get('**/plt_loader').set('set_pc_addr', '0x%x' % set_pc_addr) - set_pc_offset = self.get_json().get_child_str('**/loader/set_pc_offset') - if set_pc_offset != None: - self.get_json().get('**/plt_loader').set('set_pc_offset', set_pc_offset) - start_addr = self.get_json().get_child_int('**/loader/start_addr') - if start_addr != None: - self.get_json().get('**/plt_loader').set('start_addr', '0x%x' % start_addr) - start_value = self.get_json().get_child_int('**/loader/start_value') - if start_value != None: - self.get_json().get('**/plt_loader').set('start_value', '0x%x' % start_value) - - files_conf = self.get_json().get('**/fs/files') - if self.get_json().get('**/flash/preload_file') is None and ((files_conf is not None and len(files_conf.get_dict())) or self.get_json().get_child_bool('**/runner/boot_from_flash')): - if self.get_json().get('**/flash') is not None: - self.get_json().get('**/flash').set('preload_file', self.get_flash_preload_file()) - - gvsoc_config = self.get_json().get('gvsoc') - - debug_mode = gvsoc_config.get_bool('traces/enabled') or gvsoc_config.get_bool('events/enabled') or len(gvsoc_config.get('traces/include_regex').get()) != 0 or len(gvsoc_config.get('events/include_regex').get()) != 0 - self.get_json().get('**/gvsoc').set('debug-mode', debug_mode) - - plt_config = os.path.join(os.getcwd(), 'plt_config.json') - os.environ['PULP_CONFIG_FILE'] = plt_config - - gen_gtkw_files(self.get_json(), gvsoc_config) - - with open('plt_config.json', 'w') as file: - file.write(self.get_json().dump_to_string()) - - return 0 - - def run(self): - - gvsoc_config = self.get_json().get('gvsoc') - - debug_mode = gvsoc_config.get_bool('traces/enabled') or gvsoc_config.get_bool('events/enabled') or len(gvsoc_config.get('traces/include_regex').get()) != 0 or len(gvsoc_config.get('events/include_regex').get()) != 0 - - if debug_mode: - launcher = 'gvsoc_launcher_debug' - else: - launcher = 'gvsoc_launcher' - - plt_config = os.path.join(os.getcwd(), 'plt_config.json') - - os.environ['PULP_CONFIG_FILE'] = plt_config - - if self.args.cmd: - print ('GVSOC command:') - print ('%s --config=%s' % (launcher, plt_config)) - return 0 - else: - return os.execvp(launcher, [launcher, '--config=' + plt_config]) - - - def power(self): - if os.system('power_report_extract --report=power_report.csv --dump --config=plt_config.json --output=power_synthesis.txt') != 0: - return -1 - - return 0 diff --git a/engine/src/power/power.cpp b/engine/src/power/power.cpp index c08a393..ba0fc16 100644 --- a/engine/src/power/power.cpp +++ b/engine/src/power/power.cpp @@ -351,22 +351,35 @@ void vp::power_trace::reg_top_trace(vp::power_trace *trace) } } + void vp::power_trace::account_power() { + // We need to compute the energy spent on the current windows. + + // First measure the duration of the windows int64_t diff = this->top->get_time() - this->current_power_timestamp; + if (diff > 0) { + // Then energy based on the current power. Note that this can work only if the + // power was constant over the period, which is the case, since this function is called + // before any modification to the power. double energy = this->current_power * diff; + // First account on upper trace if any if (this->top_trace) { this->top_trace->incr(energy); } + // Then on this trace this->total += energy; + + // And update the timestamp to the current one to start a new window this->current_power_timestamp = this->top->get_time(); } } + void vp::power_trace::account_leakage_power() { int64_t diff = this->top->get_time() - this->current_leakage_power_timestamp; @@ -382,17 +395,21 @@ void vp::power_trace::account_leakage_power() } } -void vp::power_trace::set_power(double quantum, bool is_leakage) +void vp::power_trace::incr_power(double power_incr, bool is_leakage) { + // Leakage and dynamic are handled differently since they are reported separately, + // In both cases, first compute the power on current period, start a new one, + // and change the power so that it is constant over the period, to properly + // compute the energy. if (is_leakage) { this->account_leakage_power(); - this->current_leakage_power += quantum; + this->current_leakage_power += power_incr; } else { this->account_power(); - this->current_power += quantum; + this->current_power += power_incr; } } diff --git a/engine/vp/power_engine_impl.cpp b/engine/vp/power_engine_impl.cpp index 66a5e84..10be657 100644 --- a/engine/vp/power_engine_impl.cpp +++ b/engine/vp/power_engine_impl.cpp @@ -59,10 +59,6 @@ class power_manager : public vp::power_engine void reg_trace(vp::power_trace *trace); -private: - std::vector traces; - - vp::component *time_engine; }; From 8a9b1993fa14a772168e3634cb30958de22f4970 Mon Sep 17 00:00:00 2001 From: Germain Haugou Date: Mon, 22 Nov 2021 19:01:46 +0100 Subject: [PATCH 2/3] [POWER] Cleaning-out power modeling --- engine/CMakeLists.txt | 5 +- engine/include/vp/component.hpp | 2 +- engine/include/vp/power/component_power.hpp | 53 +- engine/include/vp/power/implementation.hpp | 84 ++- engine/include/vp/power/power.hpp | 304 +++++------ engine/include/vp/power/power_engine.hpp | 31 +- engine/src/power/component_power.cpp | 112 ++++ engine/src/power/power.cpp | 535 -------------------- engine/src/power/power_engine.cpp | 203 ++++++++ engine/src/power/power_source.cpp | 101 ++++ engine/src/power/power_trace.cpp | 156 ++++++ engine/src/vp.cpp | 15 + engine/vp/CMakeLists.txt | 5 - engine/vp/power_engine_impl.cpp | 178 ------- engine/vp/trace_domain_impl.cpp | 20 +- models/cpu/iss/vp/include/iss_wrapper.hpp | 8 +- models/cpu/iss/vp/src/iss_wrapper.cpp | 14 +- models/memory/memory_impl.cpp | 43 +- models/utils/composite_impl.cpp | 11 +- 19 files changed, 902 insertions(+), 978 deletions(-) create mode 100644 engine/src/power/component_power.cpp delete mode 100644 engine/src/power/power.cpp create mode 100644 engine/src/power/power_engine.cpp create mode 100644 engine/src/power/power_source.cpp create mode 100644 engine/src/power/power_trace.cpp delete mode 100644 engine/vp/power_engine_impl.cpp diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 228ae8c..4bac325 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -12,7 +12,10 @@ set(GVSOC_ENGINE_CXX_SRCS "src/clock/clock.cpp" "src/vp.cpp" "src/proxy.cpp" - "src/power/power.cpp" + "src/power/power_engine.cpp" + "src/power/component_power.cpp" + "src/power/power_trace.cpp" + "src/power/power_source.cpp" "src/launcher.cpp" ) diff --git a/engine/include/vp/component.hpp b/engine/include/vp/component.hpp index 6520593..0d4cf90 100644 --- a/engine/include/vp/component.hpp +++ b/engine/include/vp/component.hpp @@ -525,7 +525,7 @@ namespace vp { virtual std::string handle_command(Gv_proxy *proxy, FILE *req_file, FILE *reply_file, std::vector args, std::string req) { return ""; } component_trace traces; - component_power power; + vp::power::component_power power; trace warning; diff --git a/engine/include/vp/power/component_power.hpp b/engine/include/vp/power/component_power.hpp index e21878a..dc94966 100644 --- a/engine/include/vp/power/component_power.hpp +++ b/engine/include/vp/power/component_power.hpp @@ -15,7 +15,7 @@ * limitations under the License. */ -/* +/* * Authors: Germain Haugou, GreenWaves Technologies (germain.haugou@greenwaves-technologies.com) */ @@ -28,43 +28,50 @@ using namespace std; -namespace vp { - - class power_trace; - class power_source; +namespace vp +{ - class component_power - { + namespace power + { + class power_trace; + class power_source; - public: + class component_power + { - component_power(component &top); + public: + component_power(component &top); - power_engine *get_engine() { return power_manager; } + power::engine *get_engine() { return power_manager; } - void post_post_build(); + void post_post_build(); - void pre_start(); + void pre_start(); - int new_event(std::string name, power_source *source, js::config *config, power_trace *trace, bool is_leakage=false); + int new_power_source(std::string name, power_source *source, js::config *config, power_trace *trace=NULL); - int new_leakage_event(std::string name, power_source *source, js::config *config, power_trace *trace) { return this->new_event(name, source, config, trace, true); } + int new_power_trace(std::string name, power_trace *trace); - int new_trace(std::string name, power_trace *trace); + vp::power::power_trace *power_get_power_trace() { return &this->power_trace; } + //protected: + void power_get_energy_from_childs(double *dynamic, double *leakage); - void reg_top_trace(vp::power_trace *trace); + void dump(FILE *file, double total); + void dump_child_traces(FILE *file, double total); - protected: + private: + void power_get_energy_from_self_and_childs(double *dynamic, double *leakage); - private: - component ⊤ + component ⊤ - std::vector traces; + vp::power::power_trace power_trace; - power_engine *power_manager = NULL; - }; + std::vector traces; -}; + power::engine *power_manager = NULL; + }; + }; +}; #endif diff --git a/engine/include/vp/power/implementation.hpp b/engine/include/vp/power/implementation.hpp index a471b3f..f5b6c24 100644 --- a/engine/include/vp/power/implementation.hpp +++ b/engine/include/vp/power/implementation.hpp @@ -27,34 +27,94 @@ #include "vp/vp_data.hpp" #include "vp/power/power_engine.hpp" +namespace vp { -inline void vp::power_source::power_on() + namespace power { + + class Linear_volt_table + { + public: + Linear_volt_table(double temp, js::config *config); + inline double get(double frequency) { return any; } + + double volt; + + private: + double any; + }; + + + + class Linear_temp_table + { + public: + Linear_temp_table(double temp, js::config *config); + double get(double volt, double frequency); + + double temp; + + private: + std::vector volt_tables; + }; + + + + class Linear_table + { + public: + Linear_table(js::config *config); + double get(double temp, double volt, double frequency); + + private: + std::vector temp_tables; + }; + + }; + +}; + + +inline void vp::power::power_source::leakage_power_start() { if (!this->is_on) - this->trace->incr_power(this->quantum, this->is_leakage); + this->trace->incr_leakage_power(this->quantum); this->is_on = true; } -inline void vp::power_source::power_off() +inline void vp::power::power_source::leakage_power_stop() { if (this->is_on) - this->trace->incr_power(-this->quantum, this->is_leakage); + this->trace->incr_leakage_power(-this->quantum); this->is_on = false; } -inline void vp::power_source::account_event() +inline void vp::power::power_source::dynamic_power_start() +{ + if (!this->is_on) + this->trace->incr_dynamic_power(this->quantum); + this->is_on = true; +} + +inline void vp::power::power_source::dynamic_power_stop() +{ + if (this->is_on) + this->trace->incr_dynamic_power(-this->quantum); + this->is_on = false; +} + +inline void vp::power::power_source::account_event() { this->trace->account_quantum(this->quantum); } -inline void vp::power_trace::account_quantum(double quantum) +inline void vp::power::power_trace::account_quantum(double quantum) { this->incr(quantum); this->trace.event_real_pulse(this->top->get_period(), quantum, 0); } -inline double vp::power_trace::get_value() +inline double vp::power::power_trace::get_value() { if (this->timestamp < this->top->get_time()) { @@ -64,22 +124,16 @@ inline double vp::power_trace::get_value() return this->value; } -inline double vp::power_trace::get_total() +inline double vp::power::power_trace::get_total() { this->account_power(); return this->total; } -inline double vp::power_trace::get_total_leakage() +inline double vp::power::power_trace::get_total_leakage() { this->account_leakage_power(); return this->total_leakage; } -inline void vp::power_trace::flush() -{ - this->account_power(); - this->account_leakage_power(); -} - #endif \ No newline at end of file diff --git a/engine/include/vp/power/power.hpp b/engine/include/vp/power/power.hpp index d30b652..8415ae0 100644 --- a/engine/include/vp/power/power.hpp +++ b/engine/include/vp/power/power.hpp @@ -29,196 +29,196 @@ * * Power is modeled through 2 classes, one for declaring sources of power consumptions * and another one for collecting consumed power from sources. - * A note on method visibility: all the global functions are there for the HW models - * to model HW power consumption while protected methods are there for the engine - * to manage the overall power framework. + * A note on method visibility: all the public functions are there for the HW models + * to model HW power consumption while protected methods are there for the classes + * belonging to vp::power, to manage the overall power framework. * */ namespace vp { + namespace power + { + #define VP_POWER_DEFAULT_TEMP 25 #define VP_POWER_DEFAULT_VOLT 1.2 #define VP_POWER_DEFAULT_FREQ 50 - class Linear_table; - class power_engine; - class power_source; - class power_trace; - - /** - * @brief Used to model a power source - * - * A power source is a piece of hardware which is consuming energy. - * This class can be instantiated any time as needed to model all the ways - * an IP is consuming energy. - * It can be used for dynamic or leakage power, or for both at the same time, since - * they are accounted separetly. - * For dynamic power it can be used either as a quantum-based power source or - * as background power source. - * A quantum-based power source will consume energy only when an event is triggered. - * A background power source will constantly consume power as soon as it is on. - * A leakage power source is similar to a background power source, but is just accounted - * differently in the power report. - */ - class power_source - { - friend class component_power; - - public: - /** - * @brief Account the event - * - * This should be used in quantum-based power source to trigger the consumption - * of a quantum of energy. - * This will just add the quantum of energy to the current consumed energy. - */ - inline void account_event(); - - /** - * @brief Start accounting power - * - * This should be used either for a background dynamic power or for leakage - * to start accounting the associated power. - * The power is accounted until the power source is turned off. - * This is actually converted to energy and accounted on the total of energy - * anytime current power is changed or source is turned off. - */ - inline void power_on(); + class Linear_table; + class engine; + class power_source; + class power_trace; + class component_power; /** - * @brief Stop accounting power - * - * This will trigger the accounting of energy for the current windows - * and stop accounting power until it is turned on again. - */ - inline void power_off(); - - protected: - /** - * @brief Initialize a power source + * @brief Used to model a power source * - * @param top Component containing the power source. - * @param name Name of the power source, used in traces. - * @param data Configuration of the power source, giving power numbers. - * @param trace Power trace where this source should account power consumed. - * @param is_leakage True if this source is consuming leakage power, false if it is dynamic power. + * A power source is a piece of hardware which is consuming energy. + * This class can be instantiated any time as needed to model all the ways + * an IP is consuming energy. + * It can be used for dynamic or leakage power, or for both at the same time, since + * they are accounted separetly. + * For dynamic power it can be used either as a quantum-based power source or + * as background power source. + * A quantum-based power source will consume energy only when an event is triggered. + * A background power source will constantly consume power as soon as it is on. + * A leakage power source is similar to a background power source, but is just accounted + * differently in the power report. */ - int init(component *top, std::string name, js::config *config, power_trace *trace, bool is_leakage); - - /** - * @brief Set temperature, voltage and frequency - * - * The power source will adapt its power number according to the given characteristics. - * - * @param temp Temperature - * @param volt Voltage - * @param freq Frequency - */ - void setup(double temp, double volt, double freq); - - private: - Linear_table *table = NULL; // Table of power values for all supported temperatures and voltages - // imported from the json configuration given when trace was initialized. - double quantum; // Current quantumm of energy. Only valid in quantum-based power sources. - // The current value is estimated depending on voltage and temperature according - // to the provided json configuration. - component *top; // Top component containing the power source - power_trace *trace; // Power trace where the power consumption should be reported. - bool is_on = false; // True is the source is on and backgroun-power and leakage should be reported - bool is_leakage; // True is the power source is for leakage - }; + class power_source + { + // Only classes from vp::power are allowed as friends + friend class vp::power::component_power; + + public: + /** + * @brief Account the event + * + * This should be used in quantum-based power source to trigger the consumption + * of a quantum of energy. + * This will just add the quantum of energy to the current consumed energy. + */ + inline void account_event(); + + /** + * @brief Start accounting power + * + * This should be used either for a background dynamic power or for leakage + * to start accounting the associated power. + * The power is accounted until the power source is turned off. + * This is actually converted to energy and accounted on the total of energy + * anytime current power is changed or source is turned off. + */ + inline void leakage_power_start(); + inline void dynamic_power_start(); + + /** + * @brief Stop accounting power + * + * This will trigger the accounting of energy for the current windows + * and stop accounting power until it is turned on again. + */ + inline void leakage_power_stop(); + inline void dynamic_power_stop(); + + protected: + /** + * @brief Initialize a power source + * + * @param top Component containing the power source. + * @param name Name of the power source, used in traces. + * @param data Configuration of the power source, giving power numbers. + * @param trace Power trace where this source should account power consumed. + */ + int init(component *top, std::string name, js::config *config, power_trace *trace); + + /** + * @brief Set temperature, voltage and frequency + * + * The power source will adapt its power number according to the given characteristics. + * + * @param temp Temperature + * @param volt Voltage + * @param freq Frequency + */ + void setup(double temp, double volt, double freq); + + private: + Linear_table *table = NULL; // Table of power values for all supported temperatures and voltages + // imported from the json configuration given when trace was initialized. + double quantum; // Current quantumm of energy. Only valid in quantum-based power sources. + // The current value is estimated depending on voltage and temperature according + // to the provided json configuration. + component *top; // Top component containing the power source + power_trace *trace; // Power trace where the power consumption should be reported. + bool is_on = false; // True is the source is on and backgroun-power and leakage should be reported + }; - /** - * @brief Used for tracing power consumption - * - * This class can be used to gather the power consumption of several power sources and - * trace it through VCD traces and power reports. - * Each power source must be associated to a power trace and a power trace can be associated - * to one ore more power traces. - */ - class power_trace - { - friend class power_source; - friend class component_power; - friend class power_engine; - - public: - /** - * @brief Init the trace - * - * @param top Component containing the power trace. - * @param name Name of the power trace. It will be used in traces and in the power report - */ - int init(component *top, std::string name); - /** - * @brief Return if the trace is enabled + * @brief Used for tracing power consumption * - * @return true if the trace is active and should account power - * @return false if the trace is inactive and any activity should be ignored + * This class can be used to gather the power consumption of several power sources and + * trace it through VCD traces and power reports. + * Each power source must be associated to a power trace and a power trace can be associated + * to one ore more power traces. */ - inline bool get_active() { return trace.get_event_active(); } - + class power_trace + { + // Only classes from vp::power are allowed as friends + friend class vp::power::power_source; + friend class vp::power::engine; + friend class vp::power::component_power; - inline double get_value(); + public: + /** + * @brief Init the trace + * + * @param top Component containing the power trace. + * @param name Name of the power trace. It will be used in traces and in the power report + */ + int init(component *top, std::string name); - inline double get_total(); + /** + * @brief Return if the trace is enabled + * + * @return true if the trace is active and should account power + * @return false if the trace is inactive and any activity should be ignored + */ + inline bool get_active() { return trace.get_event_active(); } - inline double get_total_leakage(); + void dump(FILE *file); - bool is_dumped() { return this->dumped; } + protected: - power_trace *get_top_trace(); + inline double get_value(); - void clear(); + inline double get_total(); - void flush(); + inline double get_total_leakage(); - void dump(FILE *file); + bool is_dumped() { return this->dumped; } - void collect(); + void clear(); - void reg_top_trace(vp::power_trace *trace); - void reg_child_trace(vp::power_trace *trace); + void get_power(double *dynamic, double *leakage); + void get_energy(double *dynamic, double *leakage); - void get(double *dynamic, double *leakage); + vp::trace trace; - vp::trace trace; + void incr_dynamic_power(double power_incr); + void incr_leakage_power(double power_incr); - void incr_power(double power_incr, bool is_leakage); + inline void account_quantum(double quantum); - inline void account_quantum(double quantum); + private: + // Compute the energy spent on the current windows and account it to the total amount of energy. + // This should be called everytime the current power is updated or before it is dumped. + void account_power(); + void account_leakage_power(); + void incr(double quantum); - private: - // Compute the energy spent on the current windows and account it to the total amount of energy. - // This should be called everytime the current power is updated or before it is dumped. - void account_power(); - void account_leakage_power(); - void incr(double quantum, bool is_leakage = false); + component *top; + double value; + double total; + double total_leakage; + int64_t timestamp; + int64_t last_clear_timestamp; - component *top; - power_trace *top_trace = NULL; - std::vector child_traces; - double value; - double total; - double total_leakage; - int64_t timestamp; - int64_t last_clear_timestamp; + double current_power; // Power of the current power. This is used to account the energy over the period + // being measured. Everytime it is updated, the energy should be computed + // and the timestamp updated. + int64_t current_power_timestamp; // Indicate the timestamp of the last time the energy was accounted + // This is used everytime power is updated or dumped to compute the energy spent + // over the period. + double current_leakage_power; + int64_t current_leakage_power_timestamp; - double current_power; // Power of the current power. This is used to account the energy over the period - // being measured. Everytime it is updated, the energy should be computed - // and the timestamp updated. - int64_t current_power_timestamp; // Indicate the timestamp of the last time the energy was accounted - // This is used everytime power is updated or dumped to compute the energy spent - // over the period. - double current_leakage_power; - int64_t current_leakage_power_timestamp; + bool dumped; + }; - bool dumped; }; }; diff --git a/engine/include/vp/power/power_engine.hpp b/engine/include/vp/power/power_engine.hpp index fd2f0e7..a2402eb 100644 --- a/engine/include/vp/power/power_engine.hpp +++ b/engine/include/vp/power/power_engine.hpp @@ -15,7 +15,7 @@ * limitations under the License. */ -/* +/* * Authors: Germain Haugou, GreenWaves Technologies (germain.haugou@greenwaves-technologies.com) */ @@ -28,24 +28,31 @@ #include #include -namespace vp { +namespace vp +{ + + namespace power + { - class power_engine : public component - { - public: - power_engine(js::config *config); + class engine + { + public: + engine(vp::component *top); - virtual void start_capture() {} + void start_capture(); - virtual void stop_capture() {} + void stop_capture(); - virtual void reg_trace(vp::power_trace *trace) {} + void reg_trace(vp::power::power_trace *trace); - std::vector traces; + private: + std::vector traces; - vp::component *time_engine; - }; + vp::component *time_engine; + vp::component *top; + }; + }; }; #endif diff --git a/engine/src/power/component_power.cpp b/engine/src/power/component_power.cpp new file mode 100644 index 0000000..3dab4f4 --- /dev/null +++ b/engine/src/power/component_power.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2020 GreenWaves Technologies, SAS, ETH Zurich and + * University of Bologna + * + * 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. + */ + +/* + * Authors: Germain Haugou, GreenWaves Technologies (germain.haugou@greenwaves-technologies.com) + */ + +#include "vp/vp.hpp" +#include "vp/trace/trace.hpp" + +vp::power::component_power::component_power(vp::component &top) + : top(top) +{ +} + +void vp::power::component_power::post_post_build() +{ + + top.reg_step_pre_start(std::bind(&component_power::pre_start, this)); +} + +void vp::power::component_power::pre_start() +{ + this->new_power_trace("power_trace", &this->power_trace); + + power_manager = (vp::power::engine *)top.get_service("power"); + + for (auto trace : this->traces) + { + this->get_engine()->reg_trace(trace); + } +} + +int vp::power::component_power::new_power_trace(std::string name, vp::power::power_trace *trace) +{ + if (trace->init(&top, name)) + return -1; + + this->traces.push_back(trace); + + return 0; +} + +int vp::power::component_power::new_power_source(std::string name, power_source *source, js::config *config, vp::power::power_trace *trace) +{ + if (trace == NULL) + { + trace = &this->power_trace; + } + + if (source->init(&top, name, config, trace)) + return -1; + + source->setup(VP_POWER_DEFAULT_TEMP, VP_POWER_DEFAULT_VOLT, VP_POWER_DEFAULT_FREQ); + + return 0; +} + + +void vp::power::component_power::power_get_energy_from_childs(double *dynamic, double *leakage) +{ + for (auto &x : this->top.get_childs()) + { + x->power.power_get_energy_from_self_and_childs(dynamic, leakage); + } +} + +void vp::power::component_power::power_get_energy_from_self_and_childs(double *dynamic, double *leakage) +{ + for (auto &x : this->traces) + { + double trace_dynamic, trace_leakage; + x->get_energy(&trace_dynamic, &trace_leakage); + *dynamic += trace_dynamic; + *leakage += trace_leakage; + } + + this->power_get_energy_from_childs(dynamic, leakage); +} + +void vp::power::component_power::dump(FILE *file, double total) +{ + for (auto x:this->traces) + { + double dynamic, leakage; + x->get_power(&dynamic, &leakage); + fprintf(file, "%s; %.12f; %.12f; %.12f; %.6f\n", x->trace.get_full_path().c_str(), dynamic, leakage, dynamic + leakage, (dynamic + leakage) / total); + } +} + + +void vp::power::component_power::dump_child_traces(FILE *file, double total) +{ + for (auto &x : this->top.get_childs()) + { + x->power.dump(file, total); + } +} diff --git a/engine/src/power/power.cpp b/engine/src/power/power.cpp deleted file mode 100644 index ba0fc16..0000000 --- a/engine/src/power/power.cpp +++ /dev/null @@ -1,535 +0,0 @@ -/* - * Copyright (C) 2020 GreenWaves Technologies, SAS, ETH Zurich and - * University of Bologna - * - * 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. - */ - -/* - * Authors: Germain Haugou, GreenWaves Technologies (germain.haugou@greenwaves-technologies.com) - */ - -#include "vp/vp.hpp" -#include "vp/trace/trace.hpp" - -namespace vp { - - class Linear_volt_table - { - public: - Linear_volt_table(double temp, js::config *config); - inline double get(double frequency) { return any; } - - double volt; - - private: - double any; - }; - - - - class Linear_temp_table - { - public: - Linear_temp_table(double temp, js::config *config); - double get(double volt, double frequency); - - double temp; - - private: - std::vector volt_tables; - }; - - - - class Linear_table - { - public: - Linear_table(js::config *config); - double get(double temp, double volt, double frequency); - - private: - std::vector temp_tables; - }; - -}; - - - -vp::Linear_volt_table::Linear_volt_table(double volt, js::config *config) -{ - this->volt = volt; - - for (auto& x:config->get_childs()) - { - if (x.first == "any") - { - this->any = std::stod(x.second->get_str()); - } - else - { - throw std::logic_error("Only any frequency is allowed for now"); - } - } -} - -double vp::Linear_temp_table::get(double volt, double frequency) -{ - int low_index = -1, high_index = -1; - - // Go through the temperatures to find the one just below and the one - // just above - for (unsigned int i=0; ivolt_tables.size(); i++) - { - if (this->volt_tables[i]->volt == volt) - { - low_index = high_index = i; - break; - } - - if (this->volt_tables[i]->volt > volt) - { - high_index = i; - break; - } - - low_index = i; - } - - if (high_index == -1) - high_index = low_index; - - if (low_index == -1) - low_index = high_index; - - double value; - if (high_index == low_index) - { - value = this->volt_tables[low_index]->get(frequency); - } - else - { - double low_volt = this->volt_tables[low_index]->volt; - double high_volt = this->volt_tables[high_index]->volt; - - double value_at_low_volt = this->volt_tables[low_index]->get(frequency); - double value_at_high_volt = this->volt_tables[high_index]->get(frequency); - - double volt_ratio = (volt - low_volt) / (high_volt - low_volt); - value = (value_at_high_volt - value_at_low_volt)*volt_ratio + value_at_low_volt; - } - return value; -} - -vp::Linear_temp_table::Linear_temp_table(double temp, js::config *config) -{ - this->temp = temp; - - for (auto& x:config->get_childs()) - { - volt_tables.push_back(new Linear_volt_table(std::stod(x.first), x.second)); - } -} - -vp::Linear_table::Linear_table(js::config *config) -{ - for (auto& x:config->get_childs()) - { - temp_tables.push_back(new Linear_temp_table(std::stod(x.first), x.second)); - } -} - -double vp::Linear_table::get(double temp, double volt, double frequency) -{ - int low_temp_index = -1, high_temp_index = -1; - - // Go through the temperatures to find the one just below and the one - // just above - for (unsigned int i=0; itemp_tables.size(); i++) - { - if (this->temp_tables[i]->temp == temp) - { - low_temp_index = high_temp_index = i; - break; - } - - if (this->temp_tables[i]->temp > temp) - { - high_temp_index = i; - break; - } - - low_temp_index = i; - } - - if (high_temp_index == -1) - high_temp_index = low_temp_index; - - if (low_temp_index == -1) - low_temp_index = high_temp_index; - - double value; - - if (high_temp_index == low_temp_index) - { - value = this->temp_tables[low_temp_index]->get(volt, frequency); - } - else - { - double low_temp = this->temp_tables[low_temp_index]->temp; - double high_temp = this->temp_tables[high_temp_index]->temp; - - double value_at_low_temp = this->temp_tables[low_temp_index]->get(volt, frequency); - double value_at_high_temp = this->temp_tables[high_temp_index]->get(volt, frequency); - - double temp_ratio = (temp - low_temp) / (high_temp - low_temp); - value = (value_at_high_temp - value_at_low_temp)*temp_ratio + value_at_low_temp; - } - return value; -} - -vp::component_power::component_power(vp::component &top) -: top(top) -{ -} - - - -void vp::component_power::post_post_build() -{ - power_manager = (vp::power_engine *)top.get_service("power"); - top.reg_step_pre_start(std::bind(&component_power::pre_start, this)); -} - - -void vp::component_power::pre_start() -{ - for (auto trace: this->traces) - { - this->get_engine()->reg_trace(trace); - } -} - - -int vp::component_power::new_trace(std::string name, power_trace *trace) -{ - if (trace->init(&top, name)) - return -1; - - this->traces.push_back(trace); - - return 0; -} - - -int vp::component_power::new_event(std::string name, power_source *source, js::config *config, power_trace *trace, bool is_leakage) -{ - if (source->init(&top, name, config, trace, is_leakage)) - return -1; - - source->setup(VP_POWER_DEFAULT_TEMP, VP_POWER_DEFAULT_VOLT, VP_POWER_DEFAULT_FREQ); - - return 0; -} - - -int vp::power_trace::init(component *top, std::string name) -{ - this->top = top; - top->traces.new_trace_event_real(name, &this->trace); - this->value = 0; - this->total = 0; - this->total_leakage = 0; - this->timestamp = 0; - this->trace.event_real(0); - //this->top->power.get_engine()->reg_trace(this); - - this->current_power = 0; - this->current_power_timestamp = 0; - - this->current_leakage_power = 0; - this->current_leakage_power_timestamp = 0; - - return 0; -} - - -void vp::power_trace::clear() -{ - this->dumped = false; - this->total = this->get_value(); - this->total_leakage = 0; - this->last_clear_timestamp = this->top->get_time(); - this->current_power_timestamp = this->top->get_time(); - this->current_leakage_power_timestamp = this->top->get_time(); -} - -void vp::power_trace::get(double *dynamic, double *leakage) -{ - this->dumped = true; - - *dynamic = this->get_total() / (this->top->get_time() - this->last_clear_timestamp); - - *leakage = this->get_total_leakage() / (this->top->get_time() - this->last_clear_timestamp); -} - -void vp::power_trace::dump(FILE *file) -{ - for (auto x: child_traces) - { - x->flush(); - } - - - fprintf(file, "Trace path; Dynamic power (W); Leakage power (W); Total (W); Percentage\n"); - - double dynamic, leakage; - this->get(&dynamic, &leakage); - double total = dynamic + leakage; - - fprintf(file, "%s; %.12f; %.12f; %.12f; 1.0\n", this->trace.get_full_path().c_str(), dynamic, leakage, total); - - if (this->child_traces.size()) - { - for (auto x:this->child_traces) - { - x->get(&dynamic, &leakage); - - fprintf(file, "%s; %.12f; %.12f; %.12f; %.6f\n", x->trace.get_full_path().c_str(), dynamic, leakage, dynamic + leakage, (dynamic + leakage) / total); - } - } - fprintf(file, "\n"); - -} - -void vp::power_trace::incr(double quantum, bool is_leakage) -{ - this->get_value(); - - if (is_leakage) - { - this->total_leakage += quantum; - } - else - { - this->value += quantum; - this->total += quantum; - } - - if (this->top_trace) - this->top_trace->incr(quantum, is_leakage); - - if (this->top->get_clock()) - { - if (!is_leakage) - this->trace.event_real_pulse(this->top->get_period(), this->value, 0); - } -} - - -void vp::power_trace::collect() -{ - this->top->power.reg_top_trace(this); -} - -void vp::power_trace::reg_top_trace(vp::power_trace *trace) -{ - if (this->top_trace == NULL) - { - this->top_trace = trace; - trace->reg_child_trace(this); - } -} - - -void vp::power_trace::account_power() -{ - // We need to compute the energy spent on the current windows. - - // First measure the duration of the windows - int64_t diff = this->top->get_time() - this->current_power_timestamp; - - if (diff > 0) - { - // Then energy based on the current power. Note that this can work only if the - // power was constant over the period, which is the case, since this function is called - // before any modification to the power. - double energy = this->current_power * diff; - - // First account on upper trace if any - if (this->top_trace) - { - this->top_trace->incr(energy); - } - // Then on this trace - this->total += energy; - - // And update the timestamp to the current one to start a new window - this->current_power_timestamp = this->top->get_time(); - } -} - - -void vp::power_trace::account_leakage_power() -{ - int64_t diff = this->top->get_time() - this->current_leakage_power_timestamp; - if (diff > 0) - { - double energy = this->current_leakage_power * diff; - if (this->top_trace) - { - this->top_trace->incr(energy, true); - } - this->total_leakage += energy; - this->current_leakage_power_timestamp = this->top->get_time(); - } -} - -void vp::power_trace::incr_power(double power_incr, bool is_leakage) -{ - // Leakage and dynamic are handled differently since they are reported separately, - // In both cases, first compute the power on current period, start a new one, - // and change the power so that it is constant over the period, to properly - // compute the energy. - if (is_leakage) - { - this->account_leakage_power(); - this->current_leakage_power += power_incr; - } - else - { - this->account_power(); - this->current_power += power_incr; - } -} - -void vp::power_trace::reg_child_trace(vp::power_trace *trace) -{ - this->child_traces.push_back(trace); -} - -vp::power_trace *vp::power_trace::get_top_trace() -{ - if (this->top_trace == NULL) - return this; - else - return this->top_trace; -} - - -void vp::power_source::setup(double temp, double volt, double freq) -{ - this->quantum = this->table->get(temp, volt, freq); -} - - - -int vp::power_source::init(component *top, std::string name, js::config *config, vp::power_trace *trace, bool is_leakage) -{ - - this->top = top; - this->trace = trace; - this->is_leakage = is_leakage; - - try - { - if (config == NULL) - { - //snprintf(vp_error, VP_ERROR_SIZE, "Didn't find power trace (name: %s)", name.c_str()); - return -1; - } - - js::config *type_cfg = config->get("type"); - if (type_cfg == NULL) - { - //snprintf(vp_error, VP_ERROR_SIZE, "Didn't find power trace type (name: %s)", name.c_str()); - return -1; - } - - js::config *unit_cfg = config->get("unit"); - if (unit_cfg == NULL) - { - //snprintf(vp_error, VP_ERROR_SIZE, "Didn't find power trace unit (name: %s)", name.c_str()); - return -1; - } - - - if (unit_cfg->get_str() == "pJ") - { - - } - else if (unit_cfg->get_str() == "W") - { - - } - else - { - snprintf(vp_error, VP_ERROR_SIZE, "Unknown unit (name: %s, unit: %s)", name.c_str(), unit_cfg->get_str().c_str()); - return -1; - } - - - if (type_cfg->get_str() == "linear") - { - js::config *values = config->get("values"); - if (values == NULL) - { - snprintf(vp_error, VP_ERROR_SIZE, "Didn't find any value for linear power model"); - return -1; - } - - this->table = new Linear_table(values); - } - else - { - snprintf(vp_error, VP_ERROR_SIZE, "%s", type_cfg->get_str().c_str()); - return -1; - } - } - catch (std::logic_error &e) - { - snprintf(vp_error, VP_ERROR_SIZE, "%s", e.what()); - return -1; - } - - return 0; -} - - -void vp::component_power::reg_top_trace(vp::power_trace *trace) -{ - for (auto& x: this->traces) - { - if (x != trace) - { - x->reg_top_trace(trace); - } - } - - for (auto& x: this->top.get_childs()) - { - x->power.reg_top_trace(trace); - } - -} - - -void vp::component::dump_traces_recursive(FILE *file) -{ - this->dump_traces(file); - - for (auto& x: this->get_childs()) - { - x->dump_traces_recursive(file); - } -} diff --git a/engine/src/power/power_engine.cpp b/engine/src/power/power_engine.cpp new file mode 100644 index 0000000..606b9e0 --- /dev/null +++ b/engine/src/power/power_engine.cpp @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2020 GreenWaves Technologies, SAS, ETH Zurich and + * University of Bologna + * + * 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. + */ + +/* + * Authors: Germain Haugou, GreenWaves Technologies (germain.haugou@greenwaves-technologies.com) + */ + +#include "vp/vp.hpp" +#include "vp/trace/trace.hpp" + + + +vp::power::Linear_volt_table::Linear_volt_table(double volt, js::config *config) +{ + this->volt = volt; + + for (auto& x:config->get_childs()) + { + if (x.first == "any") + { + this->any = std::stod(x.second->get_str()); + } + else + { + throw std::logic_error("Only any frequency is allowed for now"); + } + } +} + +double vp::power::Linear_temp_table::get(double volt, double frequency) +{ + int low_index = -1, high_index = -1; + + // Go through the temperatures to find the one just below and the one + // just above + for (unsigned int i=0; ivolt_tables.size(); i++) + { + if (this->volt_tables[i]->volt == volt) + { + low_index = high_index = i; + break; + } + + if (this->volt_tables[i]->volt > volt) + { + high_index = i; + break; + } + + low_index = i; + } + + if (high_index == -1) + high_index = low_index; + + if (low_index == -1) + low_index = high_index; + + double value; + if (high_index == low_index) + { + value = this->volt_tables[low_index]->get(frequency); + } + else + { + double low_volt = this->volt_tables[low_index]->volt; + double high_volt = this->volt_tables[high_index]->volt; + + double value_at_low_volt = this->volt_tables[low_index]->get(frequency); + double value_at_high_volt = this->volt_tables[high_index]->get(frequency); + + double volt_ratio = (volt - low_volt) / (high_volt - low_volt); + value = (value_at_high_volt - value_at_low_volt)*volt_ratio + value_at_low_volt; + } + return value; +} + +vp::power::Linear_temp_table::Linear_temp_table(double temp, js::config *config) +{ + this->temp = temp; + + for (auto& x:config->get_childs()) + { + volt_tables.push_back(new Linear_volt_table(std::stod(x.first), x.second)); + } +} + +vp::power::Linear_table::Linear_table(js::config *config) +{ + for (auto& x:config->get_childs()) + { + temp_tables.push_back(new Linear_temp_table(std::stod(x.first), x.second)); + } +} + +double vp::power::Linear_table::get(double temp, double volt, double frequency) +{ + int low_temp_index = -1, high_temp_index = -1; + + // Go through the temperatures to find the one just below and the one + // just above + for (unsigned int i=0; itemp_tables.size(); i++) + { + if (this->temp_tables[i]->temp == temp) + { + low_temp_index = high_temp_index = i; + break; + } + + if (this->temp_tables[i]->temp > temp) + { + high_temp_index = i; + break; + } + + low_temp_index = i; + } + + if (high_temp_index == -1) + high_temp_index = low_temp_index; + + if (low_temp_index == -1) + low_temp_index = high_temp_index; + + double value; + + if (high_temp_index == low_temp_index) + { + value = this->temp_tables[low_temp_index]->get(volt, frequency); + } + else + { + double low_temp = this->temp_tables[low_temp_index]->temp; + double high_temp = this->temp_tables[high_temp_index]->temp; + + double value_at_low_temp = this->temp_tables[low_temp_index]->get(volt, frequency); + double value_at_high_temp = this->temp_tables[high_temp_index]->get(volt, frequency); + + double temp_ratio = (temp - low_temp) / (high_temp - low_temp); + value = (value_at_high_temp - value_at_low_temp)*temp_ratio + value_at_low_temp; + } + return value; +} + + + + + +void vp::power::engine::reg_trace(vp::power::power_trace *trace) +{ + this->traces.push_back(trace); +} + + + +void vp::power::engine::start_capture() +{ + for (auto trace : this->traces) + { + trace->clear(); + } +} + + + +void vp::power::engine::stop_capture() +{ + FILE *file = fopen("power_report.csv", "w"); + if (file == NULL) + { + //vp_warning_always(&this->warning, "Failed to open power report file (path: %s)\n", "power_report.csv"); + return; + } + + this->top->dump_traces_recursive(file); +} + + + + + +vp::power::engine::engine(vp::component *top) +{ + this->top = top; + top->new_service("power", this); +} + + + diff --git a/engine/src/power/power_source.cpp b/engine/src/power/power_source.cpp new file mode 100644 index 0000000..5972673 --- /dev/null +++ b/engine/src/power/power_source.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2020 GreenWaves Technologies, SAS, ETH Zurich and + * University of Bologna + * + * 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. + */ + +/* + * Authors: Germain Haugou, GreenWaves Technologies (germain.haugou@greenwaves-technologies.com) + */ + +#include "vp/vp.hpp" +#include "vp/trace/trace.hpp" + + +void vp::power::power_source::setup(double temp, double volt, double freq) +{ + this->quantum = this->table->get(temp, volt, freq); +} + + + +int vp::power::power_source::init(component *top, std::string name, js::config *config, vp::power::power_trace *trace) +{ + + this->top = top; + this->trace = trace; + + try + { + if (config == NULL) + { + //snprintf(vp_error, VP_ERROR_SIZE, "Didn't find power trace (name: %s)", name.c_str()); + return -1; + } + + js::config *type_cfg = config->get("type"); + if (type_cfg == NULL) + { + //snprintf(vp_error, VP_ERROR_SIZE, "Didn't find power trace type (name: %s)", name.c_str()); + return -1; + } + + js::config *unit_cfg = config->get("unit"); + if (unit_cfg == NULL) + { + //snprintf(vp_error, VP_ERROR_SIZE, "Didn't find power trace unit (name: %s)", name.c_str()); + return -1; + } + + + if (unit_cfg->get_str() == "pJ") + { + + } + else if (unit_cfg->get_str() == "W") + { + + } + else + { + snprintf(vp_error, VP_ERROR_SIZE, "Unknown unit (name: %s, unit: %s)", name.c_str(), unit_cfg->get_str().c_str()); + return -1; + } + + + if (type_cfg->get_str() == "linear") + { + js::config *values = config->get("values"); + if (values == NULL) + { + snprintf(vp_error, VP_ERROR_SIZE, "Didn't find any value for linear power model"); + return -1; + } + + this->table = new Linear_table(values); + } + else + { + snprintf(vp_error, VP_ERROR_SIZE, "%s", type_cfg->get_str().c_str()); + return -1; + } + } + catch (std::logic_error &e) + { + snprintf(vp_error, VP_ERROR_SIZE, "%s", e.what()); + return -1; + } + + return 0; +} diff --git a/engine/src/power/power_trace.cpp b/engine/src/power/power_trace.cpp new file mode 100644 index 0000000..e9e1951 --- /dev/null +++ b/engine/src/power/power_trace.cpp @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2020 GreenWaves Technologies, SAS, ETH Zurich and + * University of Bologna + * + * 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. + */ + +/* + * Authors: Germain Haugou, GreenWaves Technologies (germain.haugou@greenwaves-technologies.com) + */ + +#include "vp/vp.hpp" +#include "vp/trace/trace.hpp" + + +int vp::power::power_trace::init(component *top, std::string name) +{ + this->top = top; + top->traces.new_trace_event_real(name, &this->trace); + this->value = 0; + this->total = 0; + this->total_leakage = 0; + this->timestamp = 0; + this->trace.event_real(0); + //this->top->power.get_engine()->reg_trace(this); + + this->current_power = 0; + this->current_power_timestamp = 0; + + this->current_leakage_power = 0; + this->current_leakage_power_timestamp = 0; + + return 0; +} + + +void vp::power::power_trace::clear() +{ + this->dumped = false; + this->total = this->get_value(); + this->total_leakage = 0; + this->last_clear_timestamp = this->top->get_time(); + this->current_power_timestamp = this->top->get_time(); + this->current_leakage_power_timestamp = this->top->get_time(); +} + +void vp::power::power_trace::get_energy(double *dynamic, double *leakage) +{ + *dynamic = this->get_total(); + *leakage = this->get_total_leakage(); +} + +void vp::power::power_trace::get_power(double *dynamic, double *leakage) +{ + this->dumped = true; + + double childs_dynamic=0, childs_leakage=0; + this->top->power.power_get_energy_from_childs(&childs_dynamic, &childs_leakage); + + *dynamic = (childs_dynamic + this->get_total()) / (this->top->get_time() - this->last_clear_timestamp); + + *leakage = (childs_leakage + this->get_total_leakage()) / (this->top->get_time() - this->last_clear_timestamp); +} + +void vp::power::power_trace::dump(FILE *file) +{ + fprintf(file, "Trace path; Dynamic power (W); Leakage power (W); Total (W); Percentage\n"); + + double dynamic, leakage; + this->get_power(&dynamic, &leakage); + double total = dynamic + leakage; + + fprintf(file, "%s; %.12f; %.12f; %.12f; 1.0\n", this->trace.get_full_path().c_str(), dynamic, leakage, total); + + this->top->power.dump_child_traces(file, total); + + fprintf(file, "\n"); + +} + +void vp::power::power_trace::incr(double quantum) +{ + this->get_value(); + + this->value += quantum; + this->total += quantum; + + if (this->top->get_clock()) + { + this->trace.event_real_pulse(this->top->get_period(), this->value, 0); + } +} + + +void vp::power::power_trace::account_power() +{ + // We need to compute the energy spent on the current windows. + + // First measure the duration of the windows + int64_t diff = this->top->get_time() - this->current_power_timestamp; + + if (diff > 0) + { + // Then energy based on the current power. Note that this can work only if the + // power was constant over the period, which is the case, since this function is called + // before any modification to the power. + double energy = this->current_power * diff; + + this->total += energy; + + // And update the timestamp to the current one to start a new window + this->current_power_timestamp = this->top->get_time(); + } +} + + +void vp::power::power_trace::account_leakage_power() +{ + int64_t diff = this->top->get_time() - this->current_leakage_power_timestamp; + if (diff > 0) + { + double energy = this->current_leakage_power * diff; + this->total_leakage += energy; + this->current_leakage_power_timestamp = this->top->get_time(); + } +} + +void vp::power::power_trace::incr_dynamic_power(double power_incr) +{ + // Leakage and dynamic are handled differently since they are reported separately, + // In both cases, first compute the power on current period, start a new one, + // and change the power so that it is constant over the period, to properly + // compute the energy. + this->account_power(); + this->current_power += power_incr; +} + +void vp::power::power_trace::incr_leakage_power(double power_incr) +{ + // Leakage and dynamic are handled differently since they are reported separately, + // In both cases, first compute the power on current period, start a new one, + // and change the power so that it is constant over the period, to properly + // compute the energy. + this->account_leakage_power(); + this->current_leakage_power += power_incr; +} diff --git a/engine/src/vp.cpp b/engine/src/vp.cpp index de17d0b..fa0af21 100644 --- a/engine/src/vp.cpp +++ b/engine/src/vp.cpp @@ -1620,6 +1620,19 @@ void vp::component::create_comps() } } + + +void vp::component::dump_traces_recursive(FILE *file) +{ + this->dump_traces(file); + + for (auto& x: this->get_childs()) + { + x->dump_traces_recursive(file); + } +} + + vp::component *vp::__gv_create(std::string config_path, struct gv_conf *gv_conf) { setenv("PULP_CONFIG_FILE", config_path.c_str(), 1); @@ -1663,6 +1676,8 @@ vp::component *vp::__gv_create(std::string config_path, struct gv_conf *gv_conf) vp::component *instance = constructor(js_config); + new vp::power::engine(instance); + instance->set_vp_config(gv_config); instance->set_gv_conf(gv_conf); diff --git a/engine/vp/CMakeLists.txt b/engine/vp/CMakeLists.txt index c12a0ed..b2e6d6a 100644 --- a/engine/vp/CMakeLists.txt +++ b/engine/vp/CMakeLists.txt @@ -5,11 +5,6 @@ vp_model(NAME clock_domain_impl SOURCES "clock_domain_impl.cpp" ) -vp_model(NAME power_engine_impl - PREFIX ${VP_PREFIX} - SOURCES "power_engine_impl.cpp" - ) - vp_model(NAME time_domain_impl PREFIX ${VP_PREFIX} SOURCES "time_engine.cpp" diff --git a/engine/vp/power_engine_impl.cpp b/engine/vp/power_engine_impl.cpp deleted file mode 100644 index 10be657..0000000 --- a/engine/vp/power_engine_impl.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2020 GreenWaves Technologies, SAS, ETH Zurich and - * University of Bologna - * - * 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. - */ - -/* - * Authors: Germain Haugou, GreenWaves Technologies (germain.haugou@greenwaves-technologies.com) - */ - -#include -#include -#include -#include -#include -#include - - - -class power_manager : public vp::power_engine -{ -public: - power_manager(js::config *config); - - void pre_pre_build(); - - int build(); - - void run(); - - int64_t step(int64_t timestamp); - - void quit(int status); - - void pause(); - - void req_stop_exec(); - - void register_exec_notifier(vp::Notifier *notifier); - - void stop_exec(); - - int join(); - - void start_capture(); - - void stop_capture(); - - void reg_trace(vp::power_trace *trace); - -}; - - - -void power_manager::run() -{ - this->time_engine->run(); -} - - - -int64_t power_manager::step(int64_t timestamp) -{ - return this->time_engine->step(timestamp); -} - - - -void power_manager::quit(int status) -{ - this->time_engine->quit(status); -} - - - -void power_manager::pause() -{ - this->time_engine->pause(); -} - -void power_manager::stop_exec() -{ - this->time_engine->stop_exec(); -} - -void power_manager::req_stop_exec() -{ - this->time_engine->req_stop_exec(); -} - -void power_manager::register_exec_notifier(vp::Notifier *notifier) -{ - this->time_engine->register_exec_notifier(notifier); -} - - -int power_manager::join() -{ - return this->time_engine->join(); -} - - - -void power_manager::start_capture() -{ - for (auto trace : this->traces) - { - trace->clear(); - } -} - - - -void power_manager::stop_capture() -{ - FILE *file = fopen("power_report.csv", "w"); - if (file == NULL) - { - vp_warning_always(&this->warning, "Failed to open power report file (path: %s)\n", "power_report.csv"); - return; - } - - this->dump_traces_recursive(file); -} - - - -void power_manager::reg_trace(vp::power_trace *trace) -{ - this->traces.push_back(trace); -} - - - -vp::power_engine::power_engine(js::config *config) - : vp::component(config) -{ -} - - - -void power_manager::pre_pre_build() -{ - this->new_service("power", static_cast(this)); -} - - - -power_manager::power_manager(js::config *config) - : vp::power_engine(config) -{ -} - - - -int power_manager::build() -{ - this->time_engine = this->new_component("", this->get_js_config(), "vp.time_domain_impl"); - return 0; -} - - - -extern "C" vp::component *vp_constructor(js::config *config) -{ - return new power_manager(config); -} diff --git a/engine/vp/trace_domain_impl.cpp b/engine/vp/trace_domain_impl.cpp index c33a3ef..182e9a4 100644 --- a/engine/vp/trace_domain_impl.cpp +++ b/engine/vp/trace_domain_impl.cpp @@ -92,7 +92,7 @@ class trace_domain : public vp::trace_engine std::vector init_traces; std::unordered_map trace_files; - vp::component *power_engine; + vp::component *time_engine; FILE *trace_file; }; @@ -129,42 +129,42 @@ trace_domain::trace_domain(js::config *config) void trace_domain::run() { - this->power_engine->run(); + this->time_engine->run(); } int64_t trace_domain::step(int64_t timestamp) { - return this->power_engine->step(timestamp); + return this->time_engine->step(timestamp); } void trace_domain::quit(int status) { - this->power_engine->quit(status); + this->time_engine->quit(status); } void trace_domain::pause() { - this->power_engine->pause(); + this->time_engine->pause(); } void trace_domain::stop_exec() { - this->power_engine->stop_exec(); + this->time_engine->stop_exec(); } void trace_domain::req_stop_exec() { - this->power_engine->req_stop_exec(); + this->time_engine->req_stop_exec(); } void trace_domain::register_exec_notifier(vp::Notifier *notifier) { - this->power_engine->register_exec_notifier(notifier); + this->time_engine->register_exec_notifier(notifier); } int trace_domain::join() { - return this->power_engine->join(); + return this->time_engine->join(); } void trace_domain::check_trace_active(vp::trace *trace, int event) @@ -313,7 +313,7 @@ void trace_domain::pre_pre_build() int trace_domain::build() { - this->power_engine = this->new_component("", this->get_js_config(), "vp.power_engine_impl"); + this->time_engine = this->new_component("", this->get_js_config(), "vp.time_domain_impl"); js::config *config = get_js_config()->get("gvsoc"); diff --git a/models/cpu/iss/vp/include/iss_wrapper.hpp b/models/cpu/iss/vp/include/iss_wrapper.hpp index 321ac78..ac739ef 100644 --- a/models/cpu/iss/vp/include/iss_wrapper.hpp +++ b/models/cpu/iss/vp/include/iss_wrapper.hpp @@ -141,11 +141,9 @@ class iss_wrapper : public vp::component, vp::Gdbserver_core vp::reg_1 step_mode; vp::reg_1 do_step; - vp::power_trace power_trace; - - std::vector insn_groups_power; - vp::power_source clock_gated_power; - vp::power_source leakage_power; + std::vector insn_groups_power; + vp::power::power_source clock_gated_power; + vp::power::power_source leakage_power; vp::trace state_event; vp::trace pc_trace_event; diff --git a/models/cpu/iss/vp/src/iss_wrapper.cpp b/models/cpu/iss/vp/src/iss_wrapper.cpp index 8dd7af9..3edd8a6 100644 --- a/models/cpu/iss/vp/src/iss_wrapper.cpp +++ b/models/cpu/iss/vp/src/iss_wrapper.cpp @@ -105,7 +105,7 @@ do { \ \ iss_insn_t *insn = _this->cpu.current_insn; \ int cycles = func(_this); \ - if (_this->power_trace.get_active()) \ + if (_this->power.power_get_power_trace()->get_active()) \ { \ _this->insn_groups_power[_this->cpu.prev_insn->decoder_item->u.insn.power_group].account_event(); \ } \ @@ -1304,8 +1304,6 @@ int iss_wrapper::build() traces.new_trace_event_real("ipc_stat", &ipc_stat_event); - power.new_trace("power_trace", &power_trace); - this->new_reg("bootaddr", &this->bootaddr_reg, get_config_int("boot_addr")); this->new_reg("fetch_enable", &this->fetch_enable_reg, get_js_config()->get("fetch_enable")->get_bool()); @@ -1323,16 +1321,16 @@ int iss_wrapper::build() this->insn_groups_power.resize(config->get_size()); for (int i=0; iget_size(); i++) { - power.new_event("power_insn_" + std::to_string(i), &this->insn_groups_power[i], config->get_elem(i), &power_trace); + power.new_power_source("power_insn_" + std::to_string(i), &this->insn_groups_power[i], config->get_elem(i)); } } else { this->insn_groups_power.resize(1); - power.new_event("power_insn", &this->insn_groups_power[0], this->get_js_config()->get("**/insn"), &power_trace); + power.new_power_source("power_insn", &this->insn_groups_power[0], this->get_js_config()->get("**/insn")); } - power.new_event("power_clock_gated", &clock_gated_power, this->get_js_config()->get("**/clock_gated"), &power_trace); - power.new_leakage_event("leakage", &leakage_power, this->get_js_config()->get("**/leakage"), &power_trace); + power.new_power_source("power_clock_gated", &clock_gated_power, this->get_js_config()->get("**/clock_gated")); + power.new_power_source("leakage", &leakage_power, this->get_js_config()->get("**/leakage")); data.set_resp_meth(&iss_wrapper::data_response); data.set_grant_meth(&iss_wrapper::data_grant); @@ -1433,7 +1431,7 @@ void iss_wrapper::start() INIT_LIST_HEAD(&this->trdb_packet_list); #endif - this->leakage_power.power_on(); + this->leakage_power.leakage_power_start(); this->gdbserver = (vp::Gdbserver_engine *)this->get_service("gdbserver"); diff --git a/models/memory/memory_impl.cpp b/models/memory/memory_impl.cpp index 2427f67..164308e 100644 --- a/models/memory/memory_impl.cpp +++ b/models/memory/memory_impl.cpp @@ -60,15 +60,14 @@ class memory : public vp::component bool power_trigger; bool powered_up; - vp::power_trace power_trace; - vp::power_source idle_power; - vp::power_source read_8_power; - vp::power_source read_16_power; - vp::power_source read_32_power; - vp::power_source write_8_power; - vp::power_source write_16_power; - vp::power_source write_32_power; - vp::power_source leakage_power; + vp::power::power_source idle_power; + vp::power::power_source read_8_power; + vp::power::power_source read_16_power; + vp::power::power_source read_32_power; + vp::power::power_source write_8_power; + vp::power::power_source write_16_power; + vp::power::power_source write_32_power; + vp::power::power_source leakage_power; vp::clock_event *power_event; int64_t last_access_timestamp; @@ -85,7 +84,7 @@ void memory::power_callback(void *__this, vp::clock_event *event) memory *_this = (memory *)__this; if (_this->last_access_timestamp < _this->get_time()) { - _this->idle_power.power_on(); + _this->idle_power.dynamic_power_start(); } } @@ -121,7 +120,7 @@ vp::io_req_status_e memory::req(void *__this, vp::io_req *req) _this->next_packet_start = MAX(_this->next_packet_start, cycles) + duration; } - if (_this->power_trace.get_active()) + if (_this->power.power_get_power_trace()->get_active()) { _this->last_access_timestamp = _this->get_time(); @@ -224,16 +223,14 @@ int memory::build() js::config *config = get_js_config()->get("power_trigger"); this->power_trigger = config != NULL && config->get_bool(); - if (power.new_trace("power_trace", &power_trace)) return -1; - - power.new_leakage_event("leakage", &leakage_power, this->get_js_config()->get("**/leakage"), &power_trace); - power.new_event("idle", &idle_power, this->get_js_config()->get("**/idle"), &power_trace); - power.new_event("read_8", &read_8_power, this->get_js_config()->get("**/read_8"), &power_trace); - power.new_event("read_16", &read_16_power, this->get_js_config()->get("**/read_16"), &power_trace); - power.new_event("read_32", &read_32_power, this->get_js_config()->get("**/read_32"), &power_trace); - power.new_event("write_8", &write_8_power, this->get_js_config()->get("**/write_8"), &power_trace); - power.new_event("write_16", &write_16_power, this->get_js_config()->get("**/write_16"), &power_trace); - power.new_event("write_32", &write_32_power, this->get_js_config()->get("**/write_32"), &power_trace); + power.new_power_source("leakage", &leakage_power, this->get_js_config()->get("**/leakage")); + power.new_power_source("idle", &idle_power, this->get_js_config()->get("**/idle")); + power.new_power_source("read_8", &read_8_power, this->get_js_config()->get("**/read_8")); + power.new_power_source("read_16", &read_16_power, this->get_js_config()->get("**/read_16")); + power.new_power_source("read_32", &read_32_power, this->get_js_config()->get("**/read_32")); + power.new_power_source("write_8", &write_8_power, this->get_js_config()->get("**/write_8")); + power.new_power_source("write_16", &write_16_power, this->get_js_config()->get("**/write_16")); + power.new_power_source("write_32", &write_32_power, this->get_js_config()->get("**/write_32")); power_event = this->event_new(memory::power_callback); @@ -290,8 +287,8 @@ void memory::start() } } - this->leakage_power.power_on(); - this->idle_power.power_on(); + this->leakage_power.leakage_power_start(); + this->idle_power.dynamic_power_start(); this->last_access_timestamp = -1; } diff --git a/models/utils/composite_impl.cpp b/models/utils/composite_impl.cpp index 4b8d41d..dfbe793 100644 --- a/models/utils/composite_impl.cpp +++ b/models/utils/composite_impl.cpp @@ -44,8 +44,6 @@ class composite : public vp::component private: void add_port(std::string name, vp::port *port); std::map ports; - - vp::power_trace power_trace; }; @@ -58,7 +56,7 @@ composite::composite(js::config *config) void composite::dump_traces(FILE *file) { - this->power_trace.dump(file); + this->power.power_get_power_trace()->dump(file); } @@ -68,19 +66,12 @@ int composite::build() this->create_ports(); this->create_bindings(); - if (this->power.new_trace("power_trace", &this->power_trace)) - return -1; - return 0; } void composite::start() { - //if (this->get_clock()) - { - this->power_trace.collect(); - } } From 3e48a10c13e7e3a65ab7cd0f32fded003cdb48b5 Mon Sep 17 00:00:00 2001 From: Germain Haugou Date: Wed, 24 Nov 2021 09:32:21 +0100 Subject: [PATCH 3/3] [POWER] Cleaning-out power modeling --- engine/include/gv/power.hpp | 393 ++++++++++++++++++ engine/include/vp/component.hpp | 6 +- engine/include/vp/power/component_power.hpp | 77 ---- engine/include/vp/power/power.hpp | 224 ---------- engine/include/vp/power/power_engine.hpp | 2 +- engine/include/vp/power/power_source.hpp | 71 ++++ .../{implementation.hpp => power_table.hpp} | 69 +-- engine/include/vp/power/power_trace.hpp | 55 +++ engine/include/vp/vp.hpp | 4 +- engine/include/vp/vp_data.hpp | 2 +- engine/src/power/component_power.cpp | 54 ++- engine/src/power/power_engine.cpp | 2 +- engine/src/power/power_source.cpp | 155 ++++--- engine/src/power/power_trace.cpp | 128 ++++-- engine/src/vp.cpp | 12 +- models/cpu/iss/vp/src/iss_wrapper.cpp | 4 +- models/memory/memory_impl.cpp | 14 +- models/utils/composite_impl.cpp | 2 +- 18 files changed, 775 insertions(+), 499 deletions(-) create mode 100644 engine/include/gv/power.hpp delete mode 100644 engine/include/vp/power/component_power.hpp delete mode 100644 engine/include/vp/power/power.hpp create mode 100644 engine/include/vp/power/power_source.hpp rename engine/include/vp/power/{implementation.hpp => power_table.hpp} (52%) create mode 100644 engine/include/vp/power/power_trace.hpp diff --git a/engine/include/gv/power.hpp b/engine/include/gv/power.hpp new file mode 100644 index 0000000..7d75625 --- /dev/null +++ b/engine/include/gv/power.hpp @@ -0,0 +1,393 @@ +/* + * Copyright (C) 2020 GreenWaves Technologies, SAS, ETH Zurich and + * University of Bologna + * + * 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. + */ + +/* + * Authors: Germain Haugou, GreenWaves Technologies (germain.haugou@greenwaves-technologies.com) + */ + +#pragma once + +#include "json.hpp" +#include "vp/vp_data.hpp" + +/** + * @brief Power framework + * + * Power is modeled through 2 classes, one for declaring sources of power consumptions + * and another one for collecting consumed power from sources. + * A note on method visibility: all the public functions are there for the HW models + * to model HW power consumption while protected methods are there for the classes + * belonging to vp::power, to manage the overall power framework. + * + */ + +namespace vp +{ + + namespace power + { + +#define VP_POWER_DEFAULT_TEMP 25 +#define VP_POWER_DEFAULT_VOLT 1.2 +#define VP_POWER_DEFAULT_FREQ 50 + + class Linear_table; + class engine; + class power_source; + class power_trace; + class component_power; + + /** + * @brief Used to model a power source + * + * A power source is a piece of hardware which is consuming energy. + * This class can be instantiated any time as needed to model all the ways + * an IP is consuming energy. + * It can be used for dynamic or leakage power, or for both at the same time, since + * they are accounted separatly. + * For dynamic power it can be used either as a quantum-based power source or + * as background power source. + * A quantum-based power source will consume energy only when an event is triggered. + * A background power source will constantly consume power as soon as it is on. + * A leakage power source is similar to a background power source, but is just accounted + * differently in the power report. + */ + class power_source + { + // Only classes from vp::power are allowed as friends + friend class vp::power::component_power; + + public: + /** + * @brief Account the the current energy quantum + * + * This should be used in quantum-based power source to trigger the consumption + * of a quantum of energy. + * The accounted quantum is the current one, estimated from the current temperature + * and voltage. + * This will just add the quantum of energy to the current consumed energy. + */ + inline void account_energy_quantum(); + + /** + * @brief Start accounting background power + * + * This should be used for a background dynamic power to start accounting the associated power. + * The power is accounted until the background power is stopped. + * The accounted power is the current one, estimated from the current temperature + * and voltage. + * This is actually converted to energy and accounted on the total of energy + * anytime current power is changed or power is stopped. + */ + inline void dynamic_power_start(); + + /** + * @brief Stop accounting background power + * + * This will trigger the accounting of energy for the current windows + * and stop accounting power until it is started again. + */ + inline void dynamic_power_stop(); + + /** + * @brief Start accounting leakage + * + * This should be used for leakage to start accounting the associated power. + * The power is accounted until the leakage is stopped. + * The accounted leakage is the current one, estimated from the current temperature + * and voltage. + * This is actually converted to energy and accounted on the total of energy + * anytime current power is changed or leakage is stopped. + */ + inline void leakage_power_start(); + + /** + * @brief Stop accounting leakage + * + * This will trigger the accounting of energy for the current windows + * and stop accounting leakage until it is started again. + */ + inline void leakage_power_stop(); + + protected: + /** + * @brief Initialize a power source + * + * This method is reserved for methods belonging to namespace vp::power. + * + * @param top Component containing the power source. + * @param name Name of the power source, used in traces. + * @param config Configuration of the power source, giving power numbers. + * @param trace Power trace where this source should account power consumed. + */ + int init(component *top, std::string name, js::config *config, power_trace *trace); + + /** + * @brief Set temperature, voltage and frequency + * + * The power source will adapt its power number according to the given characteristics. + * This method is reserved for methods belonging to namespace vp::power. + * + * @param temp Temperature + * @param volt Voltage + * @param freq Frequency + */ + void setup(double temp, double volt, double freq); + + private: + Linear_table *table = NULL; // Table of power values for all supported temperatures and voltages + // imported from the json configuration given when trace was initialized. + double quantum; // Current quantumm of energy, for quantum-based power consumption. + // The current value is estimated depending on voltage and temperature according + // to the provided json configuration. + double background_power; // Current background power, for background-based power consumption. + // The current value is estimated depending on voltage and temperature according + // to the provided json configuration. + double leakage; // Current leakage power, for leakage-based power consumption. + // The current value is estimated depending on voltage and temperature according + // to the provided json configuration. + component *top; // Top component containing the power source + power_trace *trace; // Power trace where the power consumption should be reported. + bool is_on = false; // True is the source is on and backgroun-power and leakage should be reported + }; + + + /** + * @brief Used for tracing power consumption + * + * This class can be used to gather the power consumption of several power sources and + * trace it through VCD traces and power reports. + * Each power source must be associated to a power trace and a power trace can be associated + * to one ore more power traces. + * A power trace is automatically created with each component and is the default trace associated + * to any power source created in this component. Additional traces can also be created + * to give finer granularity to the power consumption in the reports. + */ + class power_trace + { + // Only classes from vp::power are allowed as friends + friend class vp::power::power_source; + friend class vp::power::engine; + friend class vp::power::component_power; + + public: + /** + * @brief Init the trace + * + * @param top Component containing the power trace. + * @param name Name of the power trace. It will be used in traces and in the power report + */ + int init(component *top, std::string name); + + /** + * @brief Return if the trace is enabled + * + * @return true if the trace is active and should account power + * @return false if the trace is inactive and any activity should be ignored + */ + inline bool get_active() { return trace.get_event_active(); } + + /** + * @brief Dump the trace + * + * This allowss dumping the power consumption of this trace to a file. + * This also dumps the consumption of the traces of the child components + * to get the hierarchical distribution. + * + * @param file File descriptor where the trace should. + */ + void dump(FILE *file); + + void set_parent(power_trace *parent); + + protected: + + /** + * @brief Start monitoring power for report generation. + * + * This will clear all pending power values so that a new report starts + * to be generating within a window which start when this method is + * called. + * It can be called several time to generate several reports, each one + * on a different time window. + * This method is reserved for methods belonging to namespace vp::power. + * + * @param file File descriptor where the trace should. + */ + void report_start(); + + inline double get_power() { return this->current_power; } + + /** + * @brief Report the average power consumed on the active window. + * + * The time duration of the active window (starting at the time where + * report_start was called) is computed, the average power estimated + * on this window and returned (both dynamic and leakage). + * This method is reserved for methods belonging to namespace vp::power. + * + * @param dynamic Dynamic power consumed on the time window is reported here. + * @param leakage Leakage power consumed on the time window is reported here. + */ + void get_report_power(double *dynamic, double *leakage); + + /** + * @brief Report the energy consumed on the active window. + * + * The time duration of the active window (starting at the time where + * report_start was called) is computed, the total amount of energy consumed + * estimated on this window and returned (both dynamic and leakage). + * This method is reserved for methods belonging to namespace vp::power. + * + * @param dynamic Dynamic power consumed on the time window is reported here. + * @param leakage Leakage power consumed on the time window is reported here. + */ + void get_report_energy(double *dynamic, double *leakage); + + /** + * @brief Increment the current dynamic background power. + * + * The dynamic background power is incremented by the specified value + * to reflect a change in power consumption. + * Note that this power is consumed constantly until it is modified again. + * This can be used to model some power consumed in background activity + * (e.g. a core in idle mode). + * This method is reserved for methods belonging to namespace vp::power. + * + * @param power_inc Power increase. Can be negative to reflect a decrease. + */ + void inc_dynamic_power(double power_inc); + + /** + * @brief Increment the current leakage power. + * + * The leakage power is incremented by the specified value + * to reflect a change in power consumption. + * Note that this power is consumed constantly until it is modified again. + * This can be used to model the leakage power which is consumed in background + * as soon as an IP is on. + * This method is reserved for methods belonging to namespace vp::power. + * + * @param power_inc Power increase. Can be negative to reflect a decrease. + */ + void inc_leakage_power(double power_incr); + + /** + * @brief Increment the current energy consumed. + * + * The amount of energy consumed is increased by the specified amount of + * energy (in joule) to reflect that an event occured and consumed some + * energy (like a memory access). + * This method is reserved for methods belonging to namespace vp::power. + * + * @param power_inc Power increase. Can be negative to reflect a decrease. + */ + void inc_dynamic_energy(double energy); + + private: + // Regularly, current power consumption is converted into energy and added + // to the total amount of energy consumed, for example when the current power + // consumption is modified. + // Calling this function will do this conversion for the dynamic part of the + // power consumed. + void account_dynamic_power(); + + // Regularly, current power consumption is converted into energy and added + // to the total amount of energy consumed, for example when the current power + // consumption is modified. + // Calling this function will do this conversion for the leakage part of the + // power consumed. + void account_leakage_power(); + + inline double get_dynamic_energy_for_cycle(); + inline void flush_dynamic_energy_for_cycle(); + + inline double get_dynamic_energy(); + + inline double get_leakage_energy(); + + // Dump VCD trace reporting the powr consumption + // This should be called everytime the energy consumed in the current cycle + // or the current backgroun or leakage power is modified. + void dump_vcd_trace(); + + static void trace_handler(void *__this, vp::clock_event *event); + + + component *top; + power_trace *parent; + vp::clock_event *trace_event; + + vp::trace trace; // Trace used for reporting power in VCD traces + double dynamic_energy_for_cycle; + double total_dynamic_energy; + double total_leakage_energy; + int64_t timestamp; + int64_t report_start_timestamp; + + double current_dynamic_power; // Power of the current power. This is used to account the energy over the period + // being measured. Everytime it is updated, the energy should be computed + // and the timestamp updated. + int64_t current_dynamic_power_timestamp; // Indicate the timestamp of the last time the energy was accounted + // This is used everytime power is updated or dumped to compute the energy spent + // over the period. + double current_leakage_power; + int64_t current_leakage_power_timestamp; + + double current_power; + }; + + + class component_power + { + friend class power_trace; + + public: + component_power(component &top); + + power::engine *get_engine() { return engine; } + + void build(); + + int new_power_source(std::string name, power_source *source, js::config *config, power_trace *trace=NULL); + + int new_power_trace(std::string name, power_trace *trace); + + vp::power::power_trace *get_power_trace() { return &this->power_trace; } + + protected: + void get_energy_from_childs(double *dynamic, double *leakage); + double get_power_from_childs(); + + void dump(FILE *file, double total); + void dump_child_traces(FILE *file, double total); + + private: + void get_energy_from_self_and_childs(double *dynamic, double *leakage); + double get_power_from_self_and_childs(); + + component ⊤ + + vp::power::power_trace power_trace; + + std::vector traces; + + power::engine *engine = NULL; + }; + }; + +}; diff --git a/engine/include/vp/component.hpp b/engine/include/vp/component.hpp index 0d4cf90..dd336a5 100644 --- a/engine/include/vp/component.hpp +++ b/engine/include/vp/component.hpp @@ -35,7 +35,7 @@ #include "vp/itf/clk.hpp" #include "vp/clock/component_clock.hpp" #include "vp/trace/component_trace.hpp" -#include "vp/power/component_power.hpp" +#include "gv/power.hpp" #include "json.hpp" #include @@ -424,7 +424,7 @@ namespace vp { void dump_traces_recursive(FILE *file); - + component *get_parent() { return this->parent; } inline js::config *get_js_config() { return comp_js_config; } js::config *get_vp_config(); @@ -457,6 +457,7 @@ namespace vp { config *import_config(const char *config_string); void reg_step_pre_start(std::function callback); + void register_build_callback(std::function callback); void post_post_build(); @@ -557,6 +558,7 @@ namespace vp { component *parent = NULL; vector> pre_start_callbacks; + vector> build_callbacks; vector regs; bool reset_done_from_itf; diff --git a/engine/include/vp/power/component_power.hpp b/engine/include/vp/power/component_power.hpp deleted file mode 100644 index dc94966..0000000 --- a/engine/include/vp/power/component_power.hpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2020 GreenWaves Technologies, SAS, ETH Zurich and - * University of Bologna - * - * 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. - */ - -/* - * Authors: Germain Haugou, GreenWaves Technologies (germain.haugou@greenwaves-technologies.com) - */ - -#ifndef __VP_TRACE_COMPONENT_POWER_HPP__ -#define __VP_TRACE_COMPONENT_POWER_HPP__ - -#include "vp/component.hpp" -#include "vp/power/power.hpp" -#include "json.hpp" - -using namespace std; - -namespace vp -{ - - namespace power - { - class power_trace; - class power_source; - - class component_power - { - - public: - component_power(component &top); - - power::engine *get_engine() { return power_manager; } - - void post_post_build(); - - void pre_start(); - - int new_power_source(std::string name, power_source *source, js::config *config, power_trace *trace=NULL); - - int new_power_trace(std::string name, power_trace *trace); - - vp::power::power_trace *power_get_power_trace() { return &this->power_trace; } - //protected: - void power_get_energy_from_childs(double *dynamic, double *leakage); - - void dump(FILE *file, double total); - void dump_child_traces(FILE *file, double total); - - private: - void power_get_energy_from_self_and_childs(double *dynamic, double *leakage); - - component ⊤ - - vp::power::power_trace power_trace; - - std::vector traces; - - power::engine *power_manager = NULL; - }; - }; - -}; - -#endif diff --git a/engine/include/vp/power/power.hpp b/engine/include/vp/power/power.hpp deleted file mode 100644 index 8415ae0..0000000 --- a/engine/include/vp/power/power.hpp +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (C) 2020 GreenWaves Technologies, SAS, ETH Zurich and - * University of Bologna - * - * 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. - */ - -/* - * Authors: Germain Haugou, GreenWaves Technologies (germain.haugou@greenwaves-technologies.com) - */ - -#pragma once - -#include "json.hpp" -#include "vp/vp_data.hpp" - -/** - * @brief Power framework - * - * Power is modeled through 2 classes, one for declaring sources of power consumptions - * and another one for collecting consumed power from sources. - * A note on method visibility: all the public functions are there for the HW models - * to model HW power consumption while protected methods are there for the classes - * belonging to vp::power, to manage the overall power framework. - * - */ - -namespace vp -{ - - namespace power - { - -#define VP_POWER_DEFAULT_TEMP 25 -#define VP_POWER_DEFAULT_VOLT 1.2 -#define VP_POWER_DEFAULT_FREQ 50 - - class Linear_table; - class engine; - class power_source; - class power_trace; - class component_power; - - /** - * @brief Used to model a power source - * - * A power source is a piece of hardware which is consuming energy. - * This class can be instantiated any time as needed to model all the ways - * an IP is consuming energy. - * It can be used for dynamic or leakage power, or for both at the same time, since - * they are accounted separetly. - * For dynamic power it can be used either as a quantum-based power source or - * as background power source. - * A quantum-based power source will consume energy only when an event is triggered. - * A background power source will constantly consume power as soon as it is on. - * A leakage power source is similar to a background power source, but is just accounted - * differently in the power report. - */ - class power_source - { - // Only classes from vp::power are allowed as friends - friend class vp::power::component_power; - - public: - /** - * @brief Account the event - * - * This should be used in quantum-based power source to trigger the consumption - * of a quantum of energy. - * This will just add the quantum of energy to the current consumed energy. - */ - inline void account_event(); - - /** - * @brief Start accounting power - * - * This should be used either for a background dynamic power or for leakage - * to start accounting the associated power. - * The power is accounted until the power source is turned off. - * This is actually converted to energy and accounted on the total of energy - * anytime current power is changed or source is turned off. - */ - inline void leakage_power_start(); - inline void dynamic_power_start(); - - /** - * @brief Stop accounting power - * - * This will trigger the accounting of energy for the current windows - * and stop accounting power until it is turned on again. - */ - inline void leakage_power_stop(); - inline void dynamic_power_stop(); - - protected: - /** - * @brief Initialize a power source - * - * @param top Component containing the power source. - * @param name Name of the power source, used in traces. - * @param data Configuration of the power source, giving power numbers. - * @param trace Power trace where this source should account power consumed. - */ - int init(component *top, std::string name, js::config *config, power_trace *trace); - - /** - * @brief Set temperature, voltage and frequency - * - * The power source will adapt its power number according to the given characteristics. - * - * @param temp Temperature - * @param volt Voltage - * @param freq Frequency - */ - void setup(double temp, double volt, double freq); - - private: - Linear_table *table = NULL; // Table of power values for all supported temperatures and voltages - // imported from the json configuration given when trace was initialized. - double quantum; // Current quantumm of energy. Only valid in quantum-based power sources. - // The current value is estimated depending on voltage and temperature according - // to the provided json configuration. - component *top; // Top component containing the power source - power_trace *trace; // Power trace where the power consumption should be reported. - bool is_on = false; // True is the source is on and backgroun-power and leakage should be reported - }; - - - /** - * @brief Used for tracing power consumption - * - * This class can be used to gather the power consumption of several power sources and - * trace it through VCD traces and power reports. - * Each power source must be associated to a power trace and a power trace can be associated - * to one ore more power traces. - */ - class power_trace - { - // Only classes from vp::power are allowed as friends - friend class vp::power::power_source; - friend class vp::power::engine; - friend class vp::power::component_power; - - public: - /** - * @brief Init the trace - * - * @param top Component containing the power trace. - * @param name Name of the power trace. It will be used in traces and in the power report - */ - int init(component *top, std::string name); - - /** - * @brief Return if the trace is enabled - * - * @return true if the trace is active and should account power - * @return false if the trace is inactive and any activity should be ignored - */ - inline bool get_active() { return trace.get_event_active(); } - - void dump(FILE *file); - - protected: - - inline double get_value(); - - inline double get_total(); - - inline double get_total_leakage(); - - bool is_dumped() { return this->dumped; } - - void clear(); - - void get_power(double *dynamic, double *leakage); - void get_energy(double *dynamic, double *leakage); - - vp::trace trace; - - void incr_dynamic_power(double power_incr); - void incr_leakage_power(double power_incr); - - inline void account_quantum(double quantum); - - private: - // Compute the energy spent on the current windows and account it to the total amount of energy. - // This should be called everytime the current power is updated or before it is dumped. - void account_power(); - void account_leakage_power(); - void incr(double quantum); - - - component *top; - double value; - double total; - double total_leakage; - int64_t timestamp; - int64_t last_clear_timestamp; - - double current_power; // Power of the current power. This is used to account the energy over the period - // being measured. Everytime it is updated, the energy should be computed - // and the timestamp updated. - int64_t current_power_timestamp; // Indicate the timestamp of the last time the energy was accounted - // This is used everytime power is updated or dumped to compute the energy spent - // over the period. - double current_leakage_power; - int64_t current_leakage_power_timestamp; - - bool dumped; - }; - - }; - -}; diff --git a/engine/include/vp/power/power_engine.hpp b/engine/include/vp/power/power_engine.hpp index a2402eb..180ca41 100644 --- a/engine/include/vp/power/power_engine.hpp +++ b/engine/include/vp/power/power_engine.hpp @@ -24,7 +24,7 @@ #include "vp/vp_data.hpp" #include "vp/component.hpp" -#include "vp/power/power.hpp" +#include "gv/power.hpp" #include #include diff --git a/engine/include/vp/power/power_source.hpp b/engine/include/vp/power/power_source.hpp new file mode 100644 index 0000000..4f0a13e --- /dev/null +++ b/engine/include/vp/power/power_source.hpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2020 GreenWaves Technologies, SAS, ETH Zurich and + * University of Bologna + * + * 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. + */ + +/* + * Authors: Germain Haugou, GreenWaves Technologies (germain.haugou@greenwaves-technologies.com) + */ + + +#pragma once + +#include "vp/vp_data.hpp" +#include "vp/power/power_engine.hpp" + + +inline void vp::power::power_source::leakage_power_start() +{ + if (!this->is_on && this->leakage != -1) + { + this->trace->inc_leakage_power(this->leakage); + } + this->is_on = true; +} + +inline void vp::power::power_source::leakage_power_stop() +{ + if (this->is_on && this->leakage != -1) + { + this->trace->inc_leakage_power(-this->leakage); + } + this->is_on = false; +} + +inline void vp::power::power_source::dynamic_power_start() +{ + if (!this->is_on && this->background_power != -1) + { + this->trace->inc_dynamic_power(this->background_power); + } + this->is_on = true; +} + +inline void vp::power::power_source::dynamic_power_stop() +{ + if (this->is_on && this->background_power != -1) + { + this->trace->inc_dynamic_power(-this->background_power); + } + this->is_on = false; +} + +inline void vp::power::power_source::account_energy_quantum() +{ + if (this->quantum != -1) + { + this->trace->inc_dynamic_energy(this->quantum); + } +} diff --git a/engine/include/vp/power/implementation.hpp b/engine/include/vp/power/power_table.hpp similarity index 52% rename from engine/include/vp/power/implementation.hpp rename to engine/include/vp/power/power_table.hpp index f5b6c24..27547f5 100644 --- a/engine/include/vp/power/implementation.hpp +++ b/engine/include/vp/power/power_table.hpp @@ -20,9 +20,7 @@ */ - -#ifndef __VP_POWER_IMPLEMENTATION_HPP__ -#define __VP_POWER_IMPLEMENTATION_HPP__ +#pragma once #include "vp/vp_data.hpp" #include "vp/power/power_engine.hpp" @@ -72,68 +70,3 @@ namespace vp { }; }; - - -inline void vp::power::power_source::leakage_power_start() -{ - if (!this->is_on) - this->trace->incr_leakage_power(this->quantum); - this->is_on = true; -} - -inline void vp::power::power_source::leakage_power_stop() -{ - if (this->is_on) - this->trace->incr_leakage_power(-this->quantum); - this->is_on = false; -} - -inline void vp::power::power_source::dynamic_power_start() -{ - if (!this->is_on) - this->trace->incr_dynamic_power(this->quantum); - this->is_on = true; -} - -inline void vp::power::power_source::dynamic_power_stop() -{ - if (this->is_on) - this->trace->incr_dynamic_power(-this->quantum); - this->is_on = false; -} - -inline void vp::power::power_source::account_event() -{ - this->trace->account_quantum(this->quantum); -} - - -inline void vp::power::power_trace::account_quantum(double quantum) -{ - this->incr(quantum); - this->trace.event_real_pulse(this->top->get_period(), quantum, 0); -} - -inline double vp::power::power_trace::get_value() -{ - if (this->timestamp < this->top->get_time()) - { - this->timestamp = this->top->get_time(); - this->value = 0; - } - return this->value; -} - -inline double vp::power::power_trace::get_total() -{ - this->account_power(); - return this->total; -} - -inline double vp::power::power_trace::get_total_leakage() -{ - this->account_leakage_power(); - return this->total_leakage; -} - -#endif \ No newline at end of file diff --git a/engine/include/vp/power/power_trace.hpp b/engine/include/vp/power/power_trace.hpp new file mode 100644 index 0000000..7db5914 --- /dev/null +++ b/engine/include/vp/power/power_trace.hpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2020 GreenWaves Technologies, SAS, ETH Zurich and + * University of Bologna + * + * 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. + */ + +/* + * Authors: Germain Haugou, GreenWaves Technologies (germain.haugou@greenwaves-technologies.com) + */ + + +#pragma once + +#include "vp/vp_data.hpp" +#include "vp/power/power_engine.hpp" + + + +inline double vp::power::power_trace::get_dynamic_energy_for_cycle() +{ + this->flush_dynamic_energy_for_cycle(); + return this->dynamic_energy_for_cycle; +} + +inline void vp::power::power_trace::flush_dynamic_energy_for_cycle() +{ + if (this->timestamp < this->top->get_time()) + { + this->timestamp = this->top->get_time(); + this->dynamic_energy_for_cycle = 0; + } +} + +inline double vp::power::power_trace::get_dynamic_energy() +{ + this->account_dynamic_power(); + return this->total_dynamic_energy; +} + +inline double vp::power::power_trace::get_leakage_energy() +{ + this->account_leakage_power(); + return this->total_leakage_energy; +} diff --git a/engine/include/vp/vp.hpp b/engine/include/vp/vp.hpp index f994359..79199c9 100644 --- a/engine/include/vp/vp.hpp +++ b/engine/include/vp/vp.hpp @@ -27,6 +27,8 @@ #include "vp/implementation.hpp" #include "vp/trace/implementation.hpp" #include "vp/clock/implementation.hpp" -#include "vp/power/implementation.hpp" +#include "vp/power/power_trace.hpp" +#include "vp/power/power_source.hpp" +#include "vp/power/power_table.hpp" #endif diff --git a/engine/include/vp/vp_data.hpp b/engine/include/vp/vp_data.hpp index cec3c27..cbccf92 100644 --- a/engine/include/vp/vp_data.hpp +++ b/engine/include/vp/vp_data.hpp @@ -26,6 +26,6 @@ #include "vp/component.hpp" #include "vp/clock/clock_event.hpp" #include "vp/clock/clock_engine.hpp" -#include "vp/power/power.hpp" +#include "gv/power.hpp" #endif diff --git a/engine/src/power/component_power.cpp b/engine/src/power/component_power.cpp index 3dab4f4..77aed0c 100644 --- a/engine/src/power/component_power.cpp +++ b/engine/src/power/component_power.cpp @@ -27,17 +27,11 @@ vp::power::component_power::component_power(vp::component &top) { } -void vp::power::component_power::post_post_build() -{ - - top.reg_step_pre_start(std::bind(&component_power::pre_start, this)); -} - -void vp::power::component_power::pre_start() +void vp::power::component_power::build() { this->new_power_trace("power_trace", &this->power_trace); - power_manager = (vp::power::engine *)top.get_service("power"); + this->engine = (vp::power::engine *)top.get_service("power"); for (auto trace : this->traces) { @@ -45,6 +39,7 @@ void vp::power::component_power::pre_start() } } + int vp::power::component_power::new_power_trace(std::string name, vp::power::power_trace *trace) { if (trace->init(&top, name)) @@ -71,25 +66,49 @@ int vp::power::component_power::new_power_source(std::string name, power_source } -void vp::power::component_power::power_get_energy_from_childs(double *dynamic, double *leakage) +double vp::power::component_power::get_power_from_childs() +{ + double result = 0.0; + for (auto &x : this->top.get_childs()) + { + result += x->power.get_power_from_self_and_childs(); + } + return result; +} + +double vp::power::component_power::get_power_from_self_and_childs() +{ + double result = 0.0; + + for (auto &x : this->traces) + { + result += x->get_power(); + } + + result += this->get_power_from_childs(); + + return result; +} + +void vp::power::component_power::get_energy_from_childs(double *dynamic, double *leakage) { for (auto &x : this->top.get_childs()) { - x->power.power_get_energy_from_self_and_childs(dynamic, leakage); + x->power.get_energy_from_self_and_childs(dynamic, leakage); } } -void vp::power::component_power::power_get_energy_from_self_and_childs(double *dynamic, double *leakage) +void vp::power::component_power::get_energy_from_self_and_childs(double *dynamic, double *leakage) { for (auto &x : this->traces) { double trace_dynamic, trace_leakage; - x->get_energy(&trace_dynamic, &trace_leakage); + x->get_report_energy(&trace_dynamic, &trace_leakage); *dynamic += trace_dynamic; *leakage += trace_leakage; } - this->power_get_energy_from_childs(dynamic, leakage); + this->get_energy_from_childs(dynamic, leakage); } void vp::power::component_power::dump(FILE *file, double total) @@ -97,8 +116,13 @@ void vp::power::component_power::dump(FILE *file, double total) for (auto x:this->traces) { double dynamic, leakage; - x->get_power(&dynamic, &leakage); - fprintf(file, "%s; %.12f; %.12f; %.12f; %.6f\n", x->trace.get_full_path().c_str(), dynamic, leakage, dynamic + leakage, (dynamic + leakage) / total); + x->get_report_power(&dynamic, &leakage); + double percentage = 0.0; + if (total != 0.0) + { + percentage = (dynamic + leakage) / total; + } + fprintf(file, "%s; %.12f; %.12f; %.12f; %.6f\n", x->trace.get_full_path().c_str(), dynamic, leakage, dynamic + leakage, percentage); } } diff --git a/engine/src/power/power_engine.cpp b/engine/src/power/power_engine.cpp index 606b9e0..ca8d978 100644 --- a/engine/src/power/power_engine.cpp +++ b/engine/src/power/power_engine.cpp @@ -171,7 +171,7 @@ void vp::power::engine::start_capture() { for (auto trace : this->traces) { - trace->clear(); + trace->report_start(); } } diff --git a/engine/src/power/power_source.cpp b/engine/src/power/power_source.cpp index 5972673..6720047 100644 --- a/engine/src/power/power_source.cpp +++ b/engine/src/power/power_source.cpp @@ -25,77 +25,118 @@ void vp::power::power_source::setup(double temp, double volt, double freq) { - this->quantum = this->table->get(temp, volt, freq); -} - - - -int vp::power::power_source::init(component *top, std::string name, js::config *config, vp::power::power_trace *trace) -{ - - this->top = top; - this->trace = trace; - - try - { - if (config == NULL) + if (this->quantum != -1) { - //snprintf(vp_error, VP_ERROR_SIZE, "Didn't find power trace (name: %s)", name.c_str()); - return -1; + this->quantum = this->table->get(temp, volt, freq); } - - js::config *type_cfg = config->get("type"); - if (type_cfg == NULL) + if (this->background_power != -1) { - //snprintf(vp_error, VP_ERROR_SIZE, "Didn't find power trace type (name: %s)", name.c_str()); - return -1; + this->background_power = this->table->get(temp, volt, freq); } - - js::config *unit_cfg = config->get("unit"); - if (unit_cfg == NULL) + if (this->leakage != -1) { - //snprintf(vp_error, VP_ERROR_SIZE, "Didn't find power trace unit (name: %s)", name.c_str()); - return -1; + this->leakage = this->table->get(temp, volt, freq); } +} - if (unit_cfg->get_str() == "pJ") - { - } - else if (unit_cfg->get_str() == "W") - { - - } - else - { - snprintf(vp_error, VP_ERROR_SIZE, "Unknown unit (name: %s, unit: %s)", name.c_str(), unit_cfg->get_str().c_str()); - return -1; - } +int vp::power::power_source::init(component *top, std::string name, js::config *source_config, vp::power::power_trace *trace) +{ + this->top = top; + this->trace = trace; + this->quantum = -1; + this->background_power = -1; + this->leakage = -1; - if (type_cfg->get_str() == "linear") + if (source_config == NULL) { - js::config *values = config->get("values"); - if (values == NULL) - { - snprintf(vp_error, VP_ERROR_SIZE, "Didn't find any value for linear power model"); + //snprintf(vp_error, VP_ERROR_SIZE, "Didn't find power trace (name: %s)", name.c_str()); return -1; - } - - this->table = new Linear_table(values); } - else + + for (auto elem: source_config->get_childs()) { - snprintf(vp_error, VP_ERROR_SIZE, "%s", type_cfg->get_str().c_str()); - return -1; + js::config *config = elem.second; + bool is_leakage = false; + + if (elem.first == "dynamic") + { + + } + else if (elem.first == "leakage") + { + is_leakage = true; + } + else + { + top->get_trace()->fatal("Unknown power source type: %s\n", elem.first.c_str()); + return -1; + } + + try + { + js::config *type_cfg = config->get("type"); + if (type_cfg == NULL) + { + //snprintf(vp_error, VP_ERROR_SIZE, "Didn't find power trace type (name: %s)", name.c_str()); + return -1; + } + + js::config *unit_cfg = config->get("unit"); + if (unit_cfg == NULL) + { + //snprintf(vp_error, VP_ERROR_SIZE, "Didn't find power trace unit (name: %s)", name.c_str()); + return -1; + } + + + if (unit_cfg->get_str() == "pJ") + { + this->quantum = 0; + } + else if (unit_cfg->get_str() == "W") + { + if (is_leakage) + { + this->leakage = 0; + } + else + { + this->background_power = 0; + } + } + else + { + snprintf(vp_error, VP_ERROR_SIZE, "Unknown unit (name: %s, unit: %s)", name.c_str(), unit_cfg->get_str().c_str()); + return -1; + } + + + if (type_cfg->get_str() == "linear") + { + js::config *values = config->get("values"); + if (values == NULL) + { + snprintf(vp_error, VP_ERROR_SIZE, "Didn't find any value for linear power model"); + return -1; + } + + this->table = new Linear_table(values); + } + else + { + snprintf(vp_error, VP_ERROR_SIZE, "%s", type_cfg->get_str().c_str()); + return -1; + } + } + catch (std::logic_error &e) + { + snprintf(vp_error, VP_ERROR_SIZE, "%s", e.what()); + return -1; + } } - } - catch (std::logic_error &e) - { - snprintf(vp_error, VP_ERROR_SIZE, "%s", e.what()); - return -1; - } - - return 0; + + return 0; } diff --git a/engine/src/power/power_trace.cpp b/engine/src/power/power_trace.cpp index e9e1951..4c48e37 100644 --- a/engine/src/power/power_trace.cpp +++ b/engine/src/power/power_trace.cpp @@ -27,49 +27,65 @@ int vp::power::power_trace::init(component *top, std::string name) { this->top = top; top->traces.new_trace_event_real(name, &this->trace); - this->value = 0; - this->total = 0; - this->total_leakage = 0; + this->dynamic_energy_for_cycle = 0; + this->total_dynamic_energy = 0; + this->total_leakage_energy = 0; this->timestamp = 0; + this->set_parent(NULL); this->trace.event_real(0); //this->top->power.get_engine()->reg_trace(this); - this->current_power = 0; - this->current_power_timestamp = 0; + this->current_dynamic_power = 0; + this->current_dynamic_power_timestamp = 0; this->current_leakage_power = 0; this->current_leakage_power_timestamp = 0; + this->trace_event = this->top->event_new((void *)this, vp::power::power_trace::trace_handler); + + vp::component *component = top->get_parent(); + if (component) + { + this->set_parent(component->power.get_power_trace()); + } + return 0; } -void vp::power::power_trace::clear() +void vp::power::power_trace::trace_handler(void *__this, vp::clock_event *event) { - this->dumped = false; - this->total = this->get_value(); - this->total_leakage = 0; - this->last_clear_timestamp = this->top->get_time(); - this->current_power_timestamp = this->top->get_time(); - this->current_leakage_power_timestamp = this->top->get_time(); + vp::power::power_trace *_this = (vp::power::power_trace *)__this; + _this->dump_vcd_trace(); } -void vp::power::power_trace::get_energy(double *dynamic, double *leakage) + +void vp::power::power_trace::report_start() { - *dynamic = this->get_total(); - *leakage = this->get_total_leakage(); + // Since the report start may be triggered in the middle of several events + // for power consumptions, include what has already be accounted + // in the same cycle. + this->total_dynamic_energy = this->get_dynamic_energy_for_cycle(); + this->total_leakage_energy = 0; + this->report_start_timestamp = this->top->get_time(); + this->current_dynamic_power_timestamp = this->top->get_time(); + this->current_leakage_power_timestamp = this->top->get_time(); } -void vp::power::power_trace::get_power(double *dynamic, double *leakage) +void vp::power::power_trace::get_report_energy(double *dynamic, double *leakage) { - this->dumped = true; + *dynamic = this->get_dynamic_energy(); + *leakage = this->get_leakage_energy(); +} +void vp::power::power_trace::get_report_power(double *dynamic, double *leakage) +{ double childs_dynamic=0, childs_leakage=0; - this->top->power.power_get_energy_from_childs(&childs_dynamic, &childs_leakage); + this->top->power.get_energy_from_childs(&childs_dynamic, &childs_leakage); - *dynamic = (childs_dynamic + this->get_total()) / (this->top->get_time() - this->last_clear_timestamp); + *dynamic = (childs_dynamic + this->get_dynamic_energy()) / (this->top->get_time() - this->report_start_timestamp); - *leakage = (childs_leakage + this->get_total_leakage()) / (this->top->get_time() - this->last_clear_timestamp); + *leakage = (childs_leakage + this->get_leakage_energy()) / (this->top->get_time() - this->report_start_timestamp); } void vp::power::power_trace::dump(FILE *file) @@ -77,7 +93,7 @@ void vp::power::power_trace::dump(FILE *file) fprintf(file, "Trace path; Dynamic power (W); Leakage power (W); Total (W); Percentage\n"); double dynamic, leakage; - this->get_power(&dynamic, &leakage); + this->get_report_power(&dynamic, &leakage); double total = dynamic + leakage; fprintf(file, "%s; %.12f; %.12f; %.12f; 1.0\n", this->trace.get_full_path().c_str(), dynamic, leakage, total); @@ -88,38 +104,49 @@ void vp::power::power_trace::dump(FILE *file) } -void vp::power::power_trace::incr(double quantum) -{ - this->get_value(); - - this->value += quantum; - this->total += quantum; - if (this->top->get_clock()) - { - this->trace.event_real_pulse(this->top->get_period(), this->value, 0); - } +void vp::power::power_trace::dump_vcd_trace() +{ + if (this->top->get_clock()) + { + double power = this->get_dynamic_energy_for_cycle() / this->top->get_period(); + double power_background = this->current_dynamic_power + this->current_leakage_power; + double childs_power = this->top->power.get_power_from_childs(); + + this->current_power = power + power_background + childs_power; + + this->trace.event_real(current_power); + + if (!this->trace_event->is_enqueued() && power > 0) + { + this->top->event_enqueue(this->trace_event, 1); + } + if (this->parent) + { + this->parent->dump_vcd_trace(); + } + } } -void vp::power::power_trace::account_power() +void vp::power::power_trace::account_dynamic_power() { // We need to compute the energy spent on the current windows. // First measure the duration of the windows - int64_t diff = this->top->get_time() - this->current_power_timestamp; + int64_t diff = this->top->get_time() - this->current_dynamic_power_timestamp; if (diff > 0) { // Then energy based on the current power. Note that this can work only if the // power was constant over the period, which is the case, since this function is called // before any modification to the power. - double energy = this->current_power * diff; + double energy = this->current_dynamic_power * diff; - this->total += energy; + this->total_dynamic_energy += energy; // And update the timestamp to the current one to start a new window - this->current_power_timestamp = this->top->get_time(); + this->current_dynamic_power_timestamp = this->top->get_time(); } } @@ -130,22 +157,35 @@ void vp::power::power_trace::account_leakage_power() if (diff > 0) { double energy = this->current_leakage_power * diff; - this->total_leakage += energy; + this->total_leakage_energy += energy; this->current_leakage_power_timestamp = this->top->get_time(); } } -void vp::power::power_trace::incr_dynamic_power(double power_incr) + +void vp::power::power_trace::inc_dynamic_energy(double quantum) +{ + this->flush_dynamic_energy_for_cycle(); + + this->dynamic_energy_for_cycle += quantum; + this->total_dynamic_energy += quantum; + + this->dump_vcd_trace(); +} + + +void vp::power::power_trace::inc_dynamic_power(double power_incr) { // Leakage and dynamic are handled differently since they are reported separately, // In both cases, first compute the power on current period, start a new one, // and change the power so that it is constant over the period, to properly // compute the energy. - this->account_power(); - this->current_power += power_incr; + this->account_dynamic_power(); + this->current_dynamic_power += power_incr; } -void vp::power::power_trace::incr_leakage_power(double power_incr) + +void vp::power::power_trace::inc_leakage_power(double power_incr) { // Leakage and dynamic are handled differently since they are reported separately, // In both cases, first compute the power on current period, start a new one, @@ -154,3 +194,9 @@ void vp::power::power_trace::incr_leakage_power(double power_incr) this->account_leakage_power(); this->current_leakage_power += power_incr; } + + +void vp::power::power_trace::set_parent(power_trace *parent) +{ + this->parent = parent; +} diff --git a/engine/src/vp.cpp b/engine/src/vp.cpp index fa0af21..271e007 100644 --- a/engine/src/vp.cpp +++ b/engine/src/vp.cpp @@ -163,10 +163,14 @@ void vp::component::reg_step_pre_start(std::function callback) this->pre_start_callbacks.push_back(callback); } +void vp::component::register_build_callback(std::function callback) +{ + this->build_callbacks.push_back(callback); +} + void vp::component::post_post_build() { traces.post_post_build(); - power.post_post_build(); } void vp::component::final_bind() @@ -1384,6 +1388,12 @@ void vp::component::build_instance(std::string name, vp::component *parent) this->pre_pre_build(); this->pre_build(); this->build(); + this->power.build(); + + for (auto x : build_callbacks) + { + x(); + } } diff --git a/models/cpu/iss/vp/src/iss_wrapper.cpp b/models/cpu/iss/vp/src/iss_wrapper.cpp index 3edd8a6..4559223 100644 --- a/models/cpu/iss/vp/src/iss_wrapper.cpp +++ b/models/cpu/iss/vp/src/iss_wrapper.cpp @@ -105,9 +105,9 @@ do { \ \ iss_insn_t *insn = _this->cpu.current_insn; \ int cycles = func(_this); \ - if (_this->power.power_get_power_trace()->get_active()) \ + if (_this->power.get_power_trace()->get_active()) \ { \ - _this->insn_groups_power[_this->cpu.prev_insn->decoder_item->u.insn.power_group].account_event(); \ + _this->insn_groups_power[_this->cpu.prev_insn->decoder_item->u.insn.power_group].account_energy_quantum(); \ } \ trdb_record_instruction(_this, insn); \ if (cycles >= 0) \ diff --git a/models/memory/memory_impl.cpp b/models/memory/memory_impl.cpp index 164308e..4f7b748 100644 --- a/models/memory/memory_impl.cpp +++ b/models/memory/memory_impl.cpp @@ -120,27 +120,27 @@ vp::io_req_status_e memory::req(void *__this, vp::io_req *req) _this->next_packet_start = MAX(_this->next_packet_start, cycles) + duration; } - if (_this->power.power_get_power_trace()->get_active()) + if (_this->power.get_power_trace()->get_active()) { _this->last_access_timestamp = _this->get_time(); if (req->get_is_write()) { if (size == 1) - _this->write_8_power.account_event(); + _this->write_8_power.account_energy_quantum(); else if (size == 2) - _this->write_16_power.account_event(); + _this->write_16_power.account_energy_quantum(); else if (size == 4) - _this->write_32_power.account_event(); + _this->write_32_power.account_energy_quantum(); } else { if (size == 1) - _this->read_8_power.account_event(); + _this->read_8_power.account_energy_quantum(); else if (size == 2) - _this->read_16_power.account_event(); + _this->read_16_power.account_energy_quantum(); else if (size == 4) - _this->read_32_power.account_event(); + _this->read_32_power.account_energy_quantum(); } if (!_this->power_event->is_enqueued()) diff --git a/models/utils/composite_impl.cpp b/models/utils/composite_impl.cpp index dfbe793..907075e 100644 --- a/models/utils/composite_impl.cpp +++ b/models/utils/composite_impl.cpp @@ -56,7 +56,7 @@ composite::composite(js::config *config) void composite::dump_traces(FILE *file) { - this->power.power_get_power_trace()->dump(file); + this->power.get_power_trace()->dump(file); }