00001 // Copyright 2009-2010 Sandia Corporation. Under the terms 00002 // of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. 00003 // Government retains certain rights in this software. 00004 // 00005 // Copyright (c) 2009-2010, Sandia Corporation 00006 // All rights reserved. 00007 // 00008 // This file is part of the SST software package. For license 00009 // information, see the LICENSE file in the top level directory of the 00010 // distribution. 00011 00012 00013 #ifndef SST_COMPONENT_H 00014 #define SST_COMPONENT_H 00015 00016 #include <cmath> 00017 #include <iostream> 00018 #include <list> 00019 00020 #if defined(__x86_64__) && defined(__APPLE__) && !defined(__USE_ISOC99) 00021 // Boost interval sometimes doesn't detect the correct method for 00022 // manipulating FP rounting on MacOS 00023 #define __USE_ISOC99 1 00024 #include <boost/numeric/interval.hpp> 00025 #undef __USE_ISOC99 00026 #else 00027 #include <boost/numeric/interval.hpp> 00028 #endif 00029 #include <boost/io/ios_state.hpp> 00030 00031 #include <sst/core/sst.h> 00032 #include <sst/core/linkMap.h> 00033 #include <sst/core/clockHandler.h> 00034 #include <sst/core/timeConverter.h> 00035 00036 namespace io_interval { // from boost interval io example (io_wide) 00037 template<class T, class Policies, class CharType, class CharTraits> 00038 std::basic_ostream<CharType, CharTraits> 00039 &operator<<(std::basic_ostream<CharType, CharTraits> &stream, 00040 const boost::numeric::interval<T, Policies> &value) 00041 { 00042 if (empty(value)) { 00043 return stream << "nothing"; 00044 } else if (singleton(value)) { 00045 boost::io::ios_precision_saver state(stream, std::numeric_limits<T>::digits10); 00046 return stream << lower(value); 00047 } else if (zero_in(value)) { 00048 return stream << "0~"; 00049 } else { 00050 std::streamsize p = stream.precision(); 00051 p = (p > 15) ? 15 : p - 1; 00052 double eps = 1.0; for(; p > 0; --p) { eps /= 10; } 00053 T eps2 = static_cast<T>(eps / 2) * norm(value); 00054 boost::numeric::interval<T, Policies> r = widen(value, eps2); 00055 //return stream << '[' << lower(r) << ',' << upper(r) << ']'; 00056 return stream << median(r) << " ± " << width(r)/2; 00057 } 00058 } 00059 } 00060 00061 namespace SST { 00062 00063 #define _COMP_DBG( fmt, args...) __DBG( DBG_COMP, Component, fmt, ## args ) 00064 00065 typedef boost::numeric::interval<double> I; 00066 00067 typedef struct 00068 { 00069 //I internalPower; 00070 //I switchingPower; 00071 I TDP; //thermal dynamic power 00072 I runtimeDynamicPower; 00073 I leakagePower; //=threshold leakage + gate leakage 00074 I peak; 00075 I currentPower; //=leakage + rumtimeDynamic 00076 I averagePower; 00077 I totalEnergy; 00078 int currentCycle; 00079 }Pdissipation_t; 00080 00081 typedef std::map<ComponentId_t, Pdissipation_t> PowerDatabase; 00082 00083 00084 /** 00085 * Main component object for the simulation. 00086 * All models inherit from this. 00087 */ 00088 class Component { 00089 public: 00090 typedef std::map<std::string,std::string> Params_t; 00091 00092 typedef std::map<std::string, int> Monitors; 00093 00094 00095 /** List of common statistics that components want to be monitored. 00096 When editting the list, make sure to edit the vector, stats_name, 00097 in Component::getDataID() as well. */ 00098 enum stats {/*McPAT counters*/ 00099 core_temperature,branch_read, branch_write, RAS_read, RAS_write, 00100 il1_read, il1_readmiss, IB_read, IB_write, BTB_read, BTB_write, 00101 int_win_read, int_win_write, fp_win_read, fp_win_write, ROB_read, ROB_write, 00102 iFRAT_read, iFRAT_write, iFRAT_search, fFRAT_read, fFRAT_write, fFRAT_search, iRRAT_write, fRRAT_write, 00103 ifreeL_read, ifreeL_write, ffreeL_read, ffreeL_write, idcl_read, fdcl_read, 00104 dl1_read, dl1_readmiss, dl1_write, dl1_writemiss, LSQ_read, LSQ_write, 00105 itlb_read, itlb_readmiss, dtlb_read, dtlb_readmiss, 00106 int_regfile_reads, int_regfile_writes, float_regfile_reads, float_regfile_writes, RFWIN_read, RFWIN_write, 00107 bypass_access, router_access, 00108 L2_read, L2_readmiss, L2_write, L2_writemiss, L3_read, L3_readmiss, L3_write, L3_writemiss, 00109 L1Dir_read, L1Dir_readmiss, L1Dir_write, L1Dir_writemiss, L2Dir_read, L2Dir_readmiss, L2Dir_write, L2Dir_writemiss, 00110 memctrl_read, memctrl_write, 00111 /*sim-panalyzer counters*/ 00112 alu_access, fpu_access, mult_access, io_access, 00113 /*zesto counters */ 00114 cache_load_lookups, cache_load_misses, cache_store_lookups, cache_store_misses, writeback_lookups, writeback_misses, prefetch_lookups, prefetch_misses, 00115 prefetch_insertions, prefetch_useful_insertions, MSHR_occupancy /* Miss Status Handling Registers total occupancy */, 00116 MSHR_full_cycles /* number of cycles when full */, WBB_insertions /* total writebacks */, WBB_victim_insertions /* total non-dirty insertions */, 00117 WBB_combines /* number eliminated due to write combining */, WBB_occupancy /* total occupancy */, WBB_full_cycles /* number of cycles when full */, 00118 WBB_hits, WBB_victim_hits, core_lookups, core_misses, MSHR_combos 00119 }; 00120 00121 00122 /** Constructor. Generally only called by the factory class. 00123 @param id Unique component ID 00124 @param sim Pointer to the global simulation object */ 00125 Component( ComponentId_t id ); 00126 virtual ~Component() = 0; 00127 /** Returns unique component ID */ 00128 inline ComponentId_t Id() { return _id; } 00129 /** Component's type, set by the factory when the object is created. 00130 It is identical to the configuration string used to create the 00131 component. I.e. the XML "<component id="aFoo"><foo>..." would 00132 generate a component from libfoo.so and set component::type to 00133 "foo" */ 00134 std::string type; 00135 /** List of id of introspectors that monitor this component. */ 00136 std::list<ComponentId_t> MyIntroList; 00137 00138 00139 /** Called after all components have been constructed, but before 00140 simulation time has begun. */ 00141 virtual int Setup( ) { return 0; } 00142 /** Called after simulation completes, but before objects are 00143 destroyed. A good place to print out statistics. */ 00144 virtual int Finish( ) { return 0; } 00145 00146 virtual bool Status( ) { return 0; } 00147 00148 // Power 00149 /** Central power/energy database that stores power dissipation data 00150 (including current power, total energy, peak power, etc) of the components 00151 on the same rank.*/ 00152 static PowerDatabase PDB; 00153 /** Register/update power dissipation data in the central power database 00154 @param pusage Structure that contains power dissipation data of a component */ 00155 void regPowerStats(Pdissipation_t pusage); 00156 /** Read power dissipation data of this component from database 00157 @param c Pointer to the component that one whats to query power 00158 from the central power database */ 00159 Pdissipation_t readPowerStats(Component* c); 00160 00161 //Introspector 00162 /** Get the period set by defaultTimeBase, which is usually set by Component::registerClock(). 00163 This can be used by clever components to ensure they only compute statistics data when needed. 00164 Returns the time between two handler function calls. (For introspectors, this means time 00165 between introspections.) */ 00166 SimTime_t getFreq() {return defaultTimeBase->getFactor();} 00167 /** Add the statistical integer data to the map of monitors 00168 for this component. The map, monitorINT, stores both the name and the ID of the integer data. 00169 @param paramName Description of the integer data*/ 00170 void registerMonitorInt(std::string dataName); 00171 /** Arbitrary statistical integer data monitoring. Returns a pair<> which indicates 00172 if the component has a monitor associated with the string 00173 indicated by "dataName", and (if so) the ID of the integer data. 00174 @param dataName Description of the integer data*/ 00175 std::pair<bool, int> ifMonitorIntData(std::string dataName); 00176 /** Add the statistical double data to the map of monitors 00177 for this component. The map, monitorDOUBLE, stores both the name and the ID of the double data. 00178 @param dataName Description of the double data*/ 00179 void registerMonitorDouble(std::string dataName); 00180 /** Arbitrary statistical double data monitoring. Returns a pair<> which indicates 00181 if the component has a monitor associated with the string 00182 indicated by "dataName", and (if so) the ID of the double data. 00183 @param dataName Description of the double data*/ 00184 std::pair<bool, int> ifMonitorDoubleData(std::string dataName); 00185 /** Add the "id" of a introspector to an internal list, MyIntroList. 00186 Indicates the introspector monitors the component. 00187 @param id ID of the introspector that monitors the component*/ 00188 void addToIntroList(ComponentId_t id); 00189 /** Check if current is the time for the component to push/report data (e.g. power) 00190 by querying its introspector. 00191 @param current Current cycle from component's view 00192 @param type Component type of the introspector that component queries about push frequency*/ 00193 bool isTimeToPush(Cycle_t current, const char *type); 00194 /** Return the value of the integer data indicated by "dataID" and "index" (if the data structure is a table). 00195 Each component type needs to implement its own getIntData. The function is usually called by introspector pull 00196 mechanism. 00197 @param dataID ID of the integer data 00198 @param index of the table (if the data structure is a table); default is set to 0 */ 00199 virtual uint64_t getIntData(int dataID, int index=0){ return 0;} 00200 /** Return the value of the double data indicated by "dataID" and "index" (if the data structure is a table). 00201 Each component type needs to implement its own getDoubleData. The function is usually called by introspector pull 00202 mechanism. 00203 @param dataID ID of the integer data 00204 @param index of the table (if the data structure is a table); default is set to 0 */ 00205 virtual double getDoubleData(int dataID, int index=0){ return 0;} 00206 /** Returns the ID of the data associated with the string indicated by "dataName". 00207 This function is usually called in Component::registerMonitorInt() or Component::registerMonitorDouble(). 00208 @param dataName Description of the integer data*/ 00209 int getDataID(std::string dataName); 00210 00211 protected: 00212 /** Unique ID */ 00213 ComponentId_t _id; 00214 /** Timebase used if no other timebase is specified for calls like 00215 Component::getCurrentSimTime(). Often set by Component::registerClock() 00216 function */ 00217 TimeConverter* defaultTimeBase; 00218 00219 Component() { } 00220 00221 /** Manually set the default detaulTimeBase */ 00222 void setDefaultTimeBase(TimeConverter *tc) { 00223 defaultTimeBase = tc; 00224 } 00225 00226 /** Database of integer monitors (arbitrary integer data that a 00227 compopent wishes to be monitored) available through 00228 Component::getMonitorIntData() */ 00229 Monitors monitorINT; 00230 /** Database of double monitors (arbitrary double data that a 00231 compopent wishes to be monitored) available through 00232 Component::getMonitorDoubleData() */ 00233 Monitors monitorDOUBLE; 00234 00235 Link* selfLink( std::string name, EventHandler_t* handler = NULL ); 00236 00237 00238 public: 00239 Link* LinkAdd( std::string name, EventHandler_t* handler = NULL ); 00240 /** Registers a clock for this component. 00241 @param freq Frequency for the clock in SI units 00242 @param handler Pointer to ClockHandler_t which is to be invoked 00243 at the specified interval 00244 @param regAll Should this clock perioud be used as the default 00245 time base for all of the links connected to this component 00246 */ 00247 TimeConverter* registerClock( std::string freq, ClockHandler_t* handler, 00248 bool regAll = true); 00249 void unregisterClock(TimeConverter *tc, ClockHandler_t* handler); 00250 00251 /** Registers a default time base for the component and optionally 00252 sets the the component's links to that timebase. Useful for 00253 components which do not have a clock, but would like a default 00254 timebase. 00255 @params base Frequency for the clock in SI units 00256 @params regAll Should this clock perioud be used as the default 00257 time base for all of the links connected to this component 00258 */ 00259 TimeConverter* registerTimeBase( std::string base, bool regAll = true); 00260 00261 /** return the time since the simulation began in units specified by 00262 the parameter. 00263 @param tc TimeConverter specificing the units */ 00264 SimTime_t getCurrentSimTime(TimeConverter *tc); 00265 /** return the time since the simulation began in the default timebase */ 00266 SimTime_t getCurrentSimTime() { 00267 return getCurrentSimTime(defaultTimeBase); 00268 } 00269 /** return the time since the simulation began in timebase specified 00270 @param base Timebase frequency in SI Units */ 00271 SimTime_t getCurrentSimTime(std::string base); 00272 00273 /** Utility function to return the time since the simulation began in nanoseconds */ 00274 SimTime_t getCurrentSimTimeNano(); 00275 /** Utility function to return the time since the simulation began in microseconds */ 00276 SimTime_t getCurrentSimTimeMicro(); 00277 /** Utility function to return the time since the simulation began in milliseconds */ 00278 SimTime_t getCurrentSimTimeMilli(); 00279 00280 /** Register that the simulation should not end until this component 00281 says it is OK to. Calling this function (generally done in 00282 Component::Setup()) increments a global counter. Calls to 00283 Component::unregisterExit() decrement the counter. The 00284 simulation cannot end unless this counter reaches zero, or the 00285 simulation time limit is reached. This counter is synchonized 00286 periodically with the other nodes. 00287 00288 @sa Component::unregisterExit() 00289 */ 00290 bool registerExit(); 00291 /** Indicate permission for the simulation to end. This function is 00292 the mirror of Component::registerExit(). It decrements the 00293 global counter, which, upon reaching zero, indicates that the 00294 simulation can terminate. @sa Component::registerExit() */ 00295 bool unregisterExit(); 00296 00297 private: 00298 00299 LinkMap* myLinks; 00300 00301 friend class boost::serialization::access; 00302 template<class Archive> 00303 void serialize(Archive& ar, const unsigned int version) { 00304 boost::serialization::base_object<LinkMap>(*this); 00305 ar & BOOST_SERIALIZATION_NVP( _id ); 00306 } 00307 }; 00308 00309 typedef std::map< ComponentId_t, Component* > CompMap_t; 00310 typedef std::deque< Component* > CompQueue_t; 00311 00312 /* 00313 inline int 00314 Connect(Component* c1, std::string c1_name, Cycle_t lat1, 00315 Component* c2, std::string c2_name, Cycle_t lat2 ) 00316 { 00317 _COMP_DBG( "(forward) Connecting link \"%s\" with link \"%s\"\n", c1_name.c_str(), c2_name.c_str() ); 00318 Link *l2= c2->LinkGet( c2_name ); 00319 if ( l2 == NULL ) return 1; 00320 c1->LinkConnect( c1_name, l2, lat1 ); 00321 00322 _COMP_DBG( "(reverse) Connecting link \"%s\" with link \"%s\"\n", c2_name.c_str(), c1_name.c_str() ); 00323 Link *l1= c1->LinkGet( c1_name ); 00324 if ( l1 == NULL ) return 1; 00325 c2->LinkConnect( c2_name, l1, lat2 ); 00326 00327 return 0; 00328 } 00329 00330 inline int 00331 Connect(Component* c1, std::string c1_name, 00332 Component* c2, std::string c2_name ) 00333 { 00334 return Connect(c1,c1_name,1,c2,c2_name,1); 00335 } 00336 */ 00337 } 00338 00339 #endif