diff --git a/src/sst/core/Makefile.am b/src/sst/core/Makefile.am index 16d27e546..782160b98 100644 --- a/src/sst/core/Makefile.am +++ b/src/sst/core/Makefile.am @@ -57,6 +57,7 @@ nobase_dist_sst_HEADERS = \ profile/clockHandlerProfileTool.h \ profile/eventHandlerProfileTool.h \ profile/syncProfileTool.h \ + profile/componentProfileTool.h \ rankInfo.h \ simulation.h \ sparseVectorMap.h \ @@ -82,6 +83,7 @@ nobase_dist_sst_HEADERS = \ eli/interfaceInfo.h \ eli/paramsInfo.h \ eli/portsInfo.h \ + eli/profilePointInfo.h \ eli/simpleInfo.h \ eli/statsInfo.h \ eli/subcompSlotInfo.h \ @@ -192,6 +194,7 @@ sst_core_sources = \ profile/clockHandlerProfileTool.cc \ profile/eventHandlerProfileTool.cc \ profile/syncProfileTool.cc \ + profile/componentProfileTool.cc \ simulation.cc \ stringize.cc \ subcomponent.cc \ diff --git a/src/sst/core/baseComponent.cc b/src/sst/core/baseComponent.cc index be364f0b2..3ee035dd5 100644 --- a/src/sst/core/baseComponent.cc +++ b/src/sst/core/baseComponent.cc @@ -112,11 +112,10 @@ BaseComponent::registerClock(const std::string& freq, Clock::HandlerBase* handle TimeConverter* tc = sim_->registerClock(freq, handler, CLOCKPRIORITY); // Check to see if there is a profile tool installed - auto* tool = sim_->getProfileTool(SST_PROFILE_TOOL_CLOCK); + auto tools = sim_->getProfileTool("clock"); - if ( tool != nullptr ) { + for ( auto* tool : tools ) { ClockHandlerMetaData mdata(my_info->getID(), getName(), getType()); - // Add the receive profiler to the handler handler->addProfileTool(tool, mdata); } @@ -136,11 +135,10 @@ BaseComponent::registerClock(const UnitAlgebra& freq, Clock::HandlerBase* handle TimeConverter* tc = sim_->registerClock(freq, handler, CLOCKPRIORITY); // Check to see if there is a profile tool installed - auto* tool = sim_->getProfileTool(SST_PROFILE_TOOL_CLOCK); + auto tools = sim_->getProfileTool("clock"); - if ( tool != nullptr ) { + for ( auto* tool : tools ) { ClockHandlerMetaData mdata(my_info->getID(), getName(), getType()); - // Add the receive profiler to the handler handler->addProfileTool(tool, mdata); } @@ -160,11 +158,10 @@ BaseComponent::registerClock(TimeConverter* tc, Clock::HandlerBase* handler, boo TimeConverter* tcRet = sim_->registerClock(tc, handler, CLOCKPRIORITY); // Check to see if there is a profile tool installed - auto* tool = sim_->getProfileTool(SST_PROFILE_TOOL_CLOCK); + auto tools = sim_->getProfileTool("clock"); - if ( tool != nullptr ) { + for ( auto* tool : tools ) { ClockHandlerMetaData mdata(my_info->getID(), getName(), getType()); - // Add the receive profiler to the handler handler->addProfileTool(tool, mdata); } @@ -303,8 +300,8 @@ BaseComponent::configureLink(const std::string& name, TimeConverter* time_base, tmp->setFunctor(handler); // Check to see if there is a profile tool installed - auto* tool = sim_->getProfileTool(SST_PROFILE_TOOL_EVENT); - if ( tool != nullptr ) { + auto tools = sim_->getProfileTool("event"); + for ( auto& tool : tools ) { EventHandlerMetaData mdata(my_info->getID(), getName(), getType(), name); // Add the receive profiler to the handler @@ -589,7 +586,7 @@ BaseComponent::vfatal( std::string type_tree = my_info->getType(); ComponentInfo* parent = my_info->parent_info; while ( parent != nullptr ) { - type_tree = parent->type + "/" + type_tree; + type_tree = parent->type + "." + type_tree; parent = parent->parent_info; } @@ -839,4 +836,10 @@ BaseComponent::performGlobalStatisticOutput() sim_->getStatisticsProcessingEngine()->performGlobalStatisticOutput(false); } +std::vector +BaseComponent::getComponentProfileTools(const std::string& point) +{ + return sim_->getProfileTool(point); +} + } // namespace SST diff --git a/src/sst/core/baseComponent.h b/src/sst/core/baseComponent.h index 7eeaf6582..124fc753d 100644 --- a/src/sst/core/baseComponent.h +++ b/src/sst/core/baseComponent.h @@ -17,6 +17,7 @@ #include "sst/core/eli/elementinfo.h" #include "sst/core/event.h" #include "sst/core/oneshot.h" +#include "sst/core/profile/componentProfileTool.h" #include "sst/core/simulation.h" #include "sst/core/sst_types.h" #include "sst/core/statapi/statbase.h" @@ -486,6 +487,32 @@ class BaseComponent */ void performGlobalStatisticOutput(); + /** Registers a profiling point. + This function will register a profiling point. + @param point Point to resgister + @return Either a pointer to a created T::ProfilePoint or nullptr if not enabled. + */ + template + typename T::ProfilePoint* registerProfilePoint(const std::string& pointName) + { + std::string full_point_name = getType() + "." + pointName; + auto tools = getComponentProfileTools(full_point_name); + if ( tools.size() == 0 ) return nullptr; + + typename T::ProfilePoint* ret = new typename T::ProfilePoint(); + for ( auto* x : tools ) { + T* tool = dynamic_cast(x); + if ( nullptr == tool ) { + // Not the right type, fatal + fatal( + CALL_INFO_LONG, 1, "ERROR: wrong type of profiling tool for profiling point %s)\n", + pointName.c_str()); + } + ret->registerProfilePoint(tool, pointName, getId(), getName(), getType()); + } + return ret; + } + /** Loads a module from an element Library * @param type Fully Qualified library.moduleName * @param params Parameters the module should use for configuration @@ -820,6 +847,8 @@ class BaseComponent // Return the Units for the statisticName from the ElementInfoStatistic // std::string getComponentInfoStatisticUnits(const std::string& statisticName) const; + std::vector getComponentProfileTools(const std::string& point); + private: ComponentInfo* my_info = nullptr; Simulation_impl* sim_ = nullptr; diff --git a/src/sst/core/component.h b/src/sst/core/component.h index 552f35e5b..d61bdfda7 100644 --- a/src/sst/core/component.h +++ b/src/sst/core/component.h @@ -41,6 +41,7 @@ class Component : public BaseComponent ELI::ProvidesPorts, ELI::ProvidesSubComponentSlots, ELI::ProvidesStats, + ELI::ProvidesProfilePoints, ELI::ProvidesAttributes) /** Constructor. Generally only called by the factory class. diff --git a/src/sst/core/config.cc b/src/sst/core/config.cc index 06b2d1b6a..24a53b2fb 100644 --- a/src/sst/core/config.cc +++ b/src/sst/core/config.cc @@ -994,7 +994,7 @@ ConfigHelper::usage() } const char sdl_indicator[] = "(S)"; - const uint32_t sdl_start = 33; + const uint32_t sdl_start = 34; const uint32_t desc_start = sdl_start + sizeof(sdl_indicator); const uint32_t desc_width = MAX_WIDTH - desc_start; @@ -1014,9 +1014,9 @@ ConfigHelper::usage() } uint32_t npos = 0; - if ( sstOptions[i].opt.val ) { npos += fprintf(stderr, " -%c, ", (char)sstOptions[i].opt.val); } + if ( sstOptions[i].opt.val ) { npos += fprintf(stderr, "-%c ", (char)sstOptions[i].opt.val); } else { - npos += fprintf(stderr, " "); + npos += fprintf(stderr, " "); } npos += fprintf(stderr, "--%s", sstOptions[i].opt.name); if ( sstOptions[i].opt.has_arg != no_argument ) { npos += fprintf(stderr, "=%s", sstOptions[i].argName); } diff --git a/src/sst/core/eli/elementinfo.cc b/src/sst/core/eli/elementinfo.cc index 94a4a10a4..11f840af1 100644 --- a/src/sst/core/eli/elementinfo.cc +++ b/src/sst/core/eli/elementinfo.cc @@ -78,6 +78,16 @@ ProvidesSubComponentSlots::toString(std::ostream& os) const } } +void +ProvidesProfilePoints::toString(std::ostream& os) const +{ + os << " Profile Points (" << getProfilePoints().size() << " total)\n"; + for ( auto& item : getProfilePoints() ) { + os << " " << item.name << ": " << (item.description == nullptr ? "" : item.description) << " [" + << (item.superclass == nullptr ? "" : item.superclass) << "]\n"; + } +} + void ProvidesStats::toString(std::ostream& os) const { diff --git a/src/sst/core/eli/elementinfo.h b/src/sst/core/eli/elementinfo.h index ca44d2776..2f5366b27 100644 --- a/src/sst/core/eli/elementinfo.h +++ b/src/sst/core/eli/elementinfo.h @@ -20,6 +20,7 @@ #include "sst/core/eli/interfaceInfo.h" #include "sst/core/eli/paramsInfo.h" #include "sst/core/eli/portsInfo.h" +#include "sst/core/eli/profilePointInfo.h" #include "sst/core/eli/simpleInfo.h" #include "sst/core/eli/statsInfo.h" #include "sst/core/eli/subcompSlotInfo.h" diff --git a/src/sst/core/eli/elibase.h b/src/sst/core/eli/elibase.h index 1bbbcb850..365c551ec 100644 --- a/src/sst/core/eli/elibase.h +++ b/src/sst/core/eli/elibase.h @@ -70,14 +70,19 @@ struct ElementInfoSubComponentSlot const char* superclass; }; +struct ElementInfoProfilePoint +{ + const char* name; + const char* description; + const char* superclass; +}; + struct ElementInfoAttribute { const char* name; const char* value; }; -typedef ElementInfoSubComponentSlot ElementInfoSubComponentHook; - namespace ELI { // Function used to combine the parent and child ELI information. diff --git a/src/sst/core/eli/profilePointInfo.h b/src/sst/core/eli/profilePointInfo.h new file mode 100644 index 000000000..661be0af7 --- /dev/null +++ b/src/sst/core/eli/profilePointInfo.h @@ -0,0 +1,89 @@ +// Copyright 2009-2022 NTESS. Under the terms +// of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. +// +// Copyright (c) 2009-2022, NTESS +// All rights reserved. +// +// This file is part of the SST software package. For license +// information, see the LICENSE file in the top level directory of the +// distribution. + +#ifndef SST_CORE_ELI_PROFILEPOINTINFO_H +#define SST_CORE_ELI_PROFILEPOINTINFO_H + +#include "sst/core/eli/elibase.h" + +#include +#include + +namespace SST { +namespace ELI { + +template +struct InfoProfilePoints +{ + static const std::vector& get() + { + static std::vector var = {}; + return var; + } +}; + +template +struct InfoProfilePoints::type> +{ + static const std::vector& get() { return T::ELI_getProfilePoints(); } +}; + +class ProvidesProfilePoints +{ +public: + const std::vector& getProfilePoints() const { return points_; } + + void toString(std::ostream& os) const; + + template + void outputXML(XMLNode* node) const + { + int idx = 0; + for ( const ElementInfoProfilePoint& point : points_ ) { + auto* element = new XMLNode("ProfilePoint"); + element->SetAttribute("Index", idx); + element->SetAttribute("Name", point.name); + element->SetAttribute("Description", point.description ? point.description : "none"); + element->SetAttribute("Interface", point.superclass ? point.superclass : "none"); + node->LinkEndChild(element); + ++idx; + } + } + +protected: + template + ProvidesProfilePoints(T* UNUSED(t)) : points_(InfoProfilePoints::get()) + {} + +private: + std::vector points_; +}; + +} // namespace ELI +} // namespace SST + +// clang-format off +#define SST_ELI_DOCUMENT_PROFILE_POINTS(...) \ + static const std::vector& ELI_getProfilePoints() \ + { \ + static std::vector var = { __VA_ARGS__ }; \ + auto parent = SST::ELI::InfoProfilePoints< \ + std::conditional<(__EliDerivedLevel > __EliBaseLevel), __LocalEliBase, __ParentEliBase>::type>::get(); \ + SST::ELI::combineEliInfo(var, parent); \ + return var; \ + } +// clang-format on +#define SST_ELI_DELETE_PROFILE_POINT(point) \ + { \ + point, nullptr, nullptr \ + } + +#endif // SST_CORE_ELI_PROFILEPOINTINFO_H diff --git a/src/sst/core/factory.cc b/src/sst/core/factory.cc index 609365495..fb45631c8 100644 --- a/src/sst/core/factory.cc +++ b/src/sst/core/factory.cc @@ -386,6 +386,48 @@ Factory::GetComponentInfoStatisticUnits(const std::string& type, const std::stri return nullptr; } +bool +Factory::isProfilePointValid(const std::string& type, const std::string& point) +{ + std::string elemlib, elem; + std::tie(elemlib, elem) = parseLoadName(type); + // ensure library is already loaded... + if ( loaded_libraries.find(elemlib) == loaded_libraries.end() ) { findLibrary(elemlib); } + + const std::vector* pointNames = nullptr; + + // Check to see if library is loaded into new + // ElementLibraryDatabase + auto* lib = ELI::InfoDatabase::getLibrary(elemlib); + std::stringstream err; + if ( lib ) { + auto* compInfo = lib->getInfo(elem); + if ( compInfo ) { pointNames = &compInfo->getProfilePoints(); } + } + if ( nullptr == pointNames ) { + auto* lib = ELI::InfoDatabase::getLibrary(elemlib); + if ( lib ) { + auto* subcompInfo = lib->getInfo(elem); + if ( subcompInfo ) { pointNames = &subcompInfo->getProfilePoints(); } + } + } + + std::string tmp = elemlib + "." + elem; + + if ( pointNames == nullptr ) { + out.fatal( + CALL_INFO, 1, "can't find requested component or subcomponent '%s' when searching for profile point\n ", + tmp.c_str()); + return false; + } + + for ( auto p : *pointNames ) { + if ( p.name == point ) return true; + } + return false; +} + + Module* Factory::CreateModule(const std::string& type, Params& params) { diff --git a/src/sst/core/factory.h b/src/sst/core/factory.h index c096fabb3..e847087ff 100644 --- a/src/sst/core/factory.h +++ b/src/sst/core/factory.h @@ -308,6 +308,13 @@ class Factory */ std::string GetComponentInfoStatisticUnits(const std::string& type, const std::string& statisticName); + /** Get a list of allowed ports for a given component type. + * @param type - Type of component in lib.name format + * @param point = Profile point to check + * @return True if this is a valid profile point + */ + bool isProfilePointValid(const std::string& type, const std::string& point); + private: friend int ::main(int argc, char** argv); diff --git a/src/sst/core/model/element_python.cc b/src/sst/core/model/element_python.cc index c10d2c226..3da6dbeb6 100644 --- a/src/sst/core/model/element_python.cc +++ b/src/sst/core/model/element_python.cc @@ -66,7 +66,12 @@ abortOnPyErr(uint32_t line, const char* file, const char* func, uint32_t exit_co while ( ptb != nullptr ) { // Filename #ifdef SST_CONFIG_HAVE_PYTHON3 +// API change for code frames starting at 3.9 +#if PY_MINOR_VERSION < 9 stream << "File \"" << PyUnicode_AsUTF8(ptb->tb_frame->f_code->co_filename) << "\", "; +#else + stream << "File \"" << PyUnicode_AsUTF8(PyFrame_GetCode(ptb->tb_frame)->co_filename) << "\", "; +#endif #else stream << "File \"" << PyString_AsString(ptb->tb_frame->f_code->co_filename) << "\", "; #endif @@ -74,7 +79,12 @@ abortOnPyErr(uint32_t line, const char* file, const char* func, uint32_t exit_co stream << "line " << ptb->tb_lineno << ", "; // Module name #ifdef SST_CONFIG_HAVE_PYTHON3 +// API change for code frames starting at 3.9 +#if PY_MINOR_VERSION < 9 stream << PyUnicode_AsUTF8(ptb->tb_frame->f_code->co_name) << "\n"; +#else + stream << PyUnicode_AsUTF8(PyFrame_GetCode(ptb->tb_frame)->co_name) << "\n"; +#endif #else stream << PyString_AsString(ptb->tb_frame->f_code->co_name) << "\n"; #endif diff --git a/src/sst/core/model/python/pymodel.cc b/src/sst/core/model/python/pymodel.cc index 57199e97a..97ed1b9f5 100644 --- a/src/sst/core/model/python/pymodel.cc +++ b/src/sst/core/model/python/pymodel.cc @@ -1046,24 +1046,43 @@ SSTPythonModelDefinition::initModel( CALL_INFO, 2, 0, "SST loading a Python model from script: %s / [%s]\n", script_file.c_str(), local_script_name.c_str()); + #if PY_MAJOR_VERSION >= 3 // Add sst module to the Python interpreter as a built in PyImport_AppendInittab("sst", &PyInit_sst); -#endif - - // Get the Python scripting engine started - Py_Initialize(); -#if PY_MAJOR_VERSION >= 3 +#if PY_MINOR_VERSION >= 11 + { + PyConfig config; + PyConfig_InitPythonConfig(&config); + // Set to zero so that we can get environment variables in the + // script + config.isolated = 0; + // Set to zero so it won't parse out the first argument of + // argv + config.parse_argv = 0; + // Set argc and argv + PyConfig_SetBytesArgv(&config, argc, argv); + // Get the Python scripting engine started + Py_InitializeFromConfig(&config); + } +#else // Set arguments; Python3 takes wchar_t* arg instead of char* wchar_t** wargv = (wchar_t**)PyMem_Malloc(sizeof(wchar_t*) * argc); - for ( int i = 0; i < argc; i++ ) + for ( int i = 0; i < argc; i++ ) { wargv[i] = Py_DecodeLocale(argv[i], nullptr); + } + + // Get the Python scripting engine started + Py_Initialize(); PySys_SetArgv(argc, wargv); +#endif PyRun_SimpleString("import sys\n" "import sst\n" "sys.meta_path.append(sst.ModuleLoader())\n"); #else + // Get the Python scripting engine started + Py_Initialize(); PySys_SetArgv(argc, argv); // Add sst module to the Python interpreter as a built in PyInit_sst(); diff --git a/src/sst/core/profile/clockHandlerProfileTool.cc b/src/sst/core/profile/clockHandlerProfileTool.cc index f32961b03..52665c07e 100644 --- a/src/sst/core/profile/clockHandlerProfileTool.cc +++ b/src/sst/core/profile/clockHandlerProfileTool.cc @@ -22,10 +22,9 @@ namespace SST { namespace Profile { -ClockHandlerProfileTool::ClockHandlerProfileTool(ProfileToolId_t id, const std::string& name, Params& params) : - HandlerProfileToolAPI(id, name) +ClockHandlerProfileTool::ClockHandlerProfileTool(const std::string& name, Params& params) : HandlerProfileToolAPI(name) { - std::string level = params.find("level", "component"); + std::string level = params.find("level", "type"); if ( level == "global" ) profile_level_ = Profile_Level::Global; else if ( level == "type" ) @@ -66,9 +65,8 @@ ClockHandlerProfileTool::getKeyForHandler(const HandlerMetaData& mdata) return key; } -ClockHandlerProfileToolCount::ClockHandlerProfileToolCount( - ProfileToolId_t id, const std::string& name, Params& params) : - ClockHandlerProfileTool(id, name, params) +ClockHandlerProfileToolCount::ClockHandlerProfileToolCount(const std::string& name, Params& params) : + ClockHandlerProfileTool(name, params) {} uintptr_t @@ -87,7 +85,7 @@ ClockHandlerProfileToolCount::handlerStart(uintptr_t key) void ClockHandlerProfileToolCount::outputData(FILE* fp) { - fprintf(fp, "%s (id = %" PRIu64 ")\n", name.c_str(), my_id); + fprintf(fp, "%s\n", name.c_str()); fprintf(fp, "Name, count\n"); for ( auto& x : counts_ ) { fprintf(fp, "%s, %" PRIu64 "\n", x.first.c_str(), x.second); @@ -96,9 +94,8 @@ ClockHandlerProfileToolCount::outputData(FILE* fp) template -ClockHandlerProfileToolTime::ClockHandlerProfileToolTime( - ProfileToolId_t id, const std::string& name, Params& params) : - ClockHandlerProfileTool(id, name, params) +ClockHandlerProfileToolTime::ClockHandlerProfileToolTime(const std::string& name, Params& params) : + ClockHandlerProfileTool(name, params) {} template @@ -112,7 +109,7 @@ template void ClockHandlerProfileToolTime::outputData(FILE* fp) { - fprintf(fp, "%s (id = %" PRIu64 ")\n", name.c_str(), my_id); + fprintf(fp, "%s\n", name.c_str()); fprintf(fp, "Name, count, handler time (s), avg. handler time (ns)\n"); for ( auto& x : times_ ) { fprintf( @@ -134,8 +131,8 @@ class ClockHandlerProfileToolTimeHighResolution : public ClockHandlerProfileTool "Profiler that will time handlers using a high resolution clock" ) - ClockHandlerProfileToolTimeHighResolution(ProfileToolId_t id, const std::string& name, Params& params) : - ClockHandlerProfileToolTime(id, name, params) + ClockHandlerProfileToolTimeHighResolution(const std::string& name, Params& params) : + ClockHandlerProfileToolTime(name, params) {} ~ClockHandlerProfileToolTimeHighResolution() {} @@ -155,8 +152,8 @@ class ClockHandlerProfileToolTimeSteady : public ClockHandlerProfileToolTime(id, name, params) + ClockHandlerProfileToolTimeSteady(const std::string& name, Params& params) : + ClockHandlerProfileToolTime(name, params) {} ~ClockHandlerProfileToolTimeSteady() {} diff --git a/src/sst/core/profile/clockHandlerProfileTool.h b/src/sst/core/profile/clockHandlerProfileTool.h index 987e3096b..1e3b09e5f 100644 --- a/src/sst/core/profile/clockHandlerProfileTool.h +++ b/src/sst/core/profile/clockHandlerProfileTool.h @@ -32,12 +32,12 @@ class ClockHandlerProfileTool : public HandlerProfileToolAPI SST_ELI_REGISTER_PROFILETOOL_DERIVED_API(SST::Profile::ClockHandlerProfileTool, SST::HandlerProfileToolAPI, Params&) SST_ELI_DOCUMENT_PARAMS( - { "level", "Level at which to track profile (global, type, component, subcomponent)", "component" }, + { "level", "Level at which to track profile (global, type, component, subcomponent)", "type" }, ) enum class Profile_Level { Global, Type, Component, Subcomponent }; - ClockHandlerProfileTool(ProfileToolId_t id, const std::string& name, Params& params); + ClockHandlerProfileTool(const std::string& name, Params& params); protected: std::string getKeyForHandler(const HandlerMetaData& mdata); @@ -62,7 +62,7 @@ class ClockHandlerProfileToolCount : public ClockHandlerProfileTool "Profiler that will count calls to handler functions" ) - ClockHandlerProfileToolCount(ProfileToolId_t id, const std::string& name, Params& params); + ClockHandlerProfileToolCount(const std::string& name, Params& params); virtual ~ClockHandlerProfileToolCount() {} @@ -92,7 +92,7 @@ class ClockHandlerProfileToolTime : public ClockHandlerProfileTool }; public: - ClockHandlerProfileToolTime(ProfileToolId_t id, const std::string& name, Params& params); + ClockHandlerProfileToolTime(const std::string& name, Params& params); virtual ~ClockHandlerProfileToolTime() {} diff --git a/src/sst/core/profile/componentProfileTool.cc b/src/sst/core/profile/componentProfileTool.cc new file mode 100644 index 000000000..afa481bcc --- /dev/null +++ b/src/sst/core/profile/componentProfileTool.cc @@ -0,0 +1,178 @@ +// Copyright 2009-2022 NTESS. Under the terms +// of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. +// +// Copyright (c) 2009-2022, NTESS +// All rights reserved. +// +// This file is part of the SST software package. For license +// information, see the LICENSE file in the top level directory of the +// distribution. + +#include "sst_config.h" + +#include "sst/core/profile/componentProfileTool.h" + +#include "sst/core/output.h" +#include "sst/core/sst_types.h" + +#include + +namespace SST { +namespace Profile { + + +ComponentProfileTool::ComponentProfileTool(const std::string& name, Params& params) : ProfileTool(name) +{ + std::string level = params.find("level", "type"); + if ( level == "global" ) + profile_level_ = Profile_Level::Global; + else if ( level == "type" ) + profile_level_ = Profile_Level::Type; + else if ( level == "component" ) + profile_level_ = Profile_Level::Component; + else if ( level == "subcomponent" ) + profile_level_ = Profile_Level::Subcomponent; + else { + Output::getDefaultObject().fatal( + CALL_INFO_LONG, 1, "ERROR: unsupported level specified for ComponentProfileTool: %s\n", level.c_str()); + } + track_points_ = params.find("track_points", "true"); +} + +std::string +ComponentProfileTool::getKeyForCodeSegment( + const std::string& point, ComponentId_t UNUSED(id), const std::string& name, const std::string& type) +{ + std::string key; + switch ( profile_level_ ) { + case Profile_Level::Global: + key = "global"; + break; + case Profile_Level::Type: + key = type; + break; + case Profile_Level::Component: + // Get just the component name, no subcomponents + key = name.substr(0, name.find(":")); + break; + case Profile_Level::Subcomponent: + key = name; + break; + default: + break; + } + + if ( track_points_ ) key = key + "/" + point; + return key; +} + + +ComponentCodeSegmentProfileTool::ComponentCodeSegmentProfileTool(const std::string& name, Params& params) : + ComponentProfileTool(name, params) +{} + + +ComponentCodeSegmentProfileToolCount::ComponentCodeSegmentProfileToolCount(const std::string& name, Params& params) : + ComponentCodeSegmentProfileTool(name, params) +{} + +uintptr_t +ComponentCodeSegmentProfileToolCount::registerProfilePoint( + const std::string& point, ComponentId_t id, const std::string& name, const std::string& type) +{ + return reinterpret_cast(&counts_[getKeyForCodeSegment(point, id, name, type)]); +} + +void +ComponentCodeSegmentProfileToolCount::codeSegmentStart(uintptr_t key) +{ + (*reinterpret_cast(key))++; +} + +void +ComponentCodeSegmentProfileToolCount::outputData(FILE* fp) +{ + fprintf(fp, "%s\n", name.c_str()); + fprintf(fp, "Name, Count\n"); + for ( auto& x : counts_ ) { + fprintf(fp, "%s", x.first.c_str()); + fprintf(fp, ", %" PRIu64 "\n", x.second); + } +} + + +template +ComponentCodeSegmentProfileToolTime::ComponentCodeSegmentProfileToolTime(const std::string& name, Params& params) : + ComponentCodeSegmentProfileTool(name, params) +{} + +template +uintptr_t +ComponentCodeSegmentProfileToolTime::registerProfilePoint( + const std::string& point, ComponentId_t id, const std::string& name, const std::string& type) +{ + return reinterpret_cast(×_[getKeyForCodeSegment(point, id, name, type)]); +} + +template +void +ComponentCodeSegmentProfileToolTime::outputData(FILE* fp) +{ + fprintf(fp, "%s\n", name.c_str()); + fprintf(fp, "Name, count, time (s), avg time (ns)\n"); + for ( auto& x : times_ ) { + fprintf(fp, "%s", x.first.c_str()); + fprintf( + fp, ", %" PRIu64 ", %lf, %" PRIu64 "\n", x.second.count, ((double)x.second.time) / 1000000000.0, + x.second.count == 0 ? 0 : x.second.time / x.second.count); + } +} + + +class ComponentCodeSegmentProfileToolTimeHighResolution : + public ComponentCodeSegmentProfileToolTime +{ +public: + SST_ELI_REGISTER_PROFILETOOL( + ComponentCodeSegmentProfileToolTimeHighResolution, + SST::Profile::ComponentCodeSegmentProfileTool, + "sst", + "profile.component.codesegment.time.high_resolution", + SST_ELI_ELEMENT_VERSION(0, 1, 0), + "Profiler that will time component code segments using a high resolution clock" + ) + + ComponentCodeSegmentProfileToolTimeHighResolution(const std::string& name, Params& params) : + ComponentCodeSegmentProfileToolTime(name, params) + {} + + ~ComponentCodeSegmentProfileToolTimeHighResolution() {} + + SST_ELI_EXPORT(ComponentCodeSegmentProfileToolTimeHighResolution) +}; + +class ComponentCodeSegmentProfileToolTimeSteady : public ComponentCodeSegmentProfileToolTime +{ +public: + SST_ELI_REGISTER_PROFILETOOL( + ComponentCodeSegmentProfileToolTimeSteady, + SST::Profile::ComponentCodeSegmentProfileTool, + "sst", + "profile.component.codesegment.time.steady", + SST_ELI_ELEMENT_VERSION(0, 1, 0), + "Profiler that will time component code segments using a steady clock" + ) + + ComponentCodeSegmentProfileToolTimeSteady(const std::string& name, Params& params) : + ComponentCodeSegmentProfileToolTime(name, params) + {} + + ~ComponentCodeSegmentProfileToolTimeSteady() {} + + SST_ELI_EXPORT(ComponentCodeSegmentProfileToolTimeSteady) +}; + + +} // namespace Profile +} // namespace SST diff --git a/src/sst/core/profile/componentProfileTool.h b/src/sst/core/profile/componentProfileTool.h new file mode 100644 index 000000000..7479e8b49 --- /dev/null +++ b/src/sst/core/profile/componentProfileTool.h @@ -0,0 +1,194 @@ +// Copyright 2009-2022 NTESS. Under the terms +// of Contract DE-NA0003525 with NTESS, the U.S. +// Government retains certain rights in this software. +// +// Copyright (c) 2009-2022, NTESS +// All rights reserved. +// +// This file is part of the SST software package. For license +// information, see the LICENSE file in the top level directory of the +// distribution. + +#ifndef SST_CORE_PROFILE_COMPONENTPROFILETOOL_H +#define SST_CORE_PROFILE_COMPONENTPROFILETOOL_H + +#include "sst/core/eli/elementinfo.h" +#include "sst/core/profile/profiletool.h" +#include "sst/core/sst_types.h" +#include "sst/core/warnmacros.h" + +#include +#include + +namespace SST { + +class BaseComponent; + +namespace Profile { + +// Base class for profiling tools designed to profile in Components +// and SubComponents. For these types of profiling tools, you can +// trace at various levels: + +// 1 - Global: all profiling will be consolidated into one global +// profile + +// 2 - Type: all profiling will be consolidated into one profile per +// (Sub)Component type. + +// 3 - Component: profiling will be consolidated at the Component +// level and all SubComponent data will be consolidated with its +// parent component + +// 4 - SubComponent: profiling will be consolidated at the +// SubComponent level +class ComponentProfileTool : public ProfileTool +{ +public: + SST_ELI_REGISTER_PROFILETOOL_DERIVED_API(SST::Profile::ComponentProfileTool, SST::Profile::ProfileTool, Params&) + + SST_ELI_DOCUMENT_PARAMS( + { "level", "Level at which to track profile (global, type, component, subcomponent)", "type" }, + { "track_points", "Determines whether independent profiling points are tracked", "true" }, + ) + + enum class Profile_Level { Global, Type, Component, Subcomponent }; + + ComponentProfileTool(const std::string& name, Params& params); + + + virtual uintptr_t registerProfilePoint( + const std::string& point, ComponentId_t id, const std::string& name, const std::string& type) = 0; + std::string + getKeyForCodeSegment(const std::string& point, ComponentId_t id, const std::string& name, const std::string& type); + +protected: + Profile_Level profile_level_; + +private: + bool track_points_; +}; + + +// Profiler API designed to profile code segments in Components and +// SubComponents +class ComponentCodeSegmentProfileTool : public ComponentProfileTool +{ + friend class BaseComponent; + +public: + SST_ELI_REGISTER_PROFILETOOL_DERIVED_API(SST::Profile::ComponentCodeSegmentProfileTool, SST::Profile::ComponentProfileTool, Params&) + + ComponentCodeSegmentProfileTool(const std::string& name, Params& params); + + virtual void codeSegmentStart(uintptr_t UNUSED(key)) {} + virtual void codeSegmentEnd(uintptr_t UNUSED(key)) {} + + class ProfilePoint + { + public: + ProfilePoint() {} + ~ProfilePoint() {} + + inline void codeSegmentStart() + { + for ( auto& x : tools ) { + x.first->codeSegmentStart(x.second); + } + } + inline void codeSegmentEnd() + { + for ( auto& x : tools ) { + x.first->codeSegmentEnd(x.second); + } + } + + void registerProfilePoint( + ComponentCodeSegmentProfileTool* tool, const std::string& point, ComponentId_t id, const std::string& name, + const std::string& type) + { + uintptr_t key = tool->registerProfilePoint(point, id, name, type); + tools.push_back(std::make_pair(tool, key)); + } + + private: + std::vector> tools; + }; +}; + +/** + Profile tool that will count the number of times a handler is + called + */ +class ComponentCodeSegmentProfileToolCount : public ComponentCodeSegmentProfileTool +{ + +public: + SST_ELI_REGISTER_PROFILETOOL( + ComponentCodeSegmentProfileToolCount, + SST::Profile::ComponentCodeSegmentProfileTool, + "sst", + "profile.component.codesegment.count", + SST_ELI_ELEMENT_VERSION(0, 1, 0), + "Profiler that will count times through a marked code segment" + ) + + ComponentCodeSegmentProfileToolCount(const std::string& name, Params& params); + + virtual ~ComponentCodeSegmentProfileToolCount() {} + + uintptr_t registerProfilePoint( + const std::string& point, ComponentId_t id, const std::string& name, const std::string& type) override; + + void codeSegmentStart(uintptr_t key) override; + + void outputData(FILE* fp) override; + +private: + std::map counts_; +}; + +/** + Profile tool that will count the number of times a handler is + called + */ +template +class ComponentCodeSegmentProfileToolTime : public ComponentCodeSegmentProfileTool +{ + struct segment_data_t + { + uint64_t time; + uint64_t count; + + segment_data_t() : time(0), count(0) {} + }; + +public: + ComponentCodeSegmentProfileToolTime(const std::string& name, Params& params); + + virtual ~ComponentCodeSegmentProfileToolTime() {} + + uintptr_t registerProfilePoint( + const std::string& point, ComponentId_t id, const std::string& name, const std::string& type) override; + + void codeSegmentStart(uintptr_t UNUSED(key)) override { start_time_ = T::now(); } + + void codeSegmentEnd(uintptr_t key) override + { + auto total_time = T::now() - start_time_; + segment_data_t* entry = reinterpret_cast(key); + entry->time += std::chrono::duration_cast(total_time).count(); + entry->count++; + } + + void outputData(FILE* fp) override; + +private: + typename T::time_point start_time_; + std::map times_; +}; + +} // namespace Profile +} // namespace SST + +#endif // SST_CORE_PROFILE_COMPONENTPROFILETOOL_H diff --git a/src/sst/core/profile/eventHandlerProfileTool.cc b/src/sst/core/profile/eventHandlerProfileTool.cc index 052231a80..9fb75fb46 100644 --- a/src/sst/core/profile/eventHandlerProfileTool.cc +++ b/src/sst/core/profile/eventHandlerProfileTool.cc @@ -22,10 +22,9 @@ namespace SST { namespace Profile { -EventHandlerProfileTool::EventHandlerProfileTool(ProfileToolId_t id, const std::string& name, Params& params) : - HandlerProfileToolAPI(id, name) +EventHandlerProfileTool::EventHandlerProfileTool(const std::string& name, Params& params) : HandlerProfileToolAPI(name) { - std::string level = params.find("level", "component"); + std::string level = params.find("level", "type"); if ( level == "global" ) profile_level_ = Profile_Level::Global; else if ( level == "type" ) @@ -73,9 +72,8 @@ EventHandlerProfileTool::getKeyForHandler(const HandlerMetaData& mdata) return key; } -EventHandlerProfileToolCount::EventHandlerProfileToolCount( - ProfileToolId_t id, const std::string& name, Params& params) : - EventHandlerProfileTool(id, name, params) +EventHandlerProfileToolCount::EventHandlerProfileToolCount(const std::string& name, Params& params) : + EventHandlerProfileTool(name, params) {} uintptr_t @@ -100,7 +98,7 @@ EventHandlerProfileToolCount::eventSent(uintptr_t key, Event* UNUSED(ev)) void EventHandlerProfileToolCount::outputData(FILE* fp) { - fprintf(fp, "%s (id = %" PRIu64 ")\n", name.c_str(), my_id); + fprintf(fp, "%s\n", name.c_str()); fprintf(fp, "Name"); if ( profile_receives_ ) fprintf(fp, ", recv count"); if ( profile_sends_ ) fprintf(fp, ", send count"); @@ -115,9 +113,8 @@ EventHandlerProfileToolCount::outputData(FILE* fp) template -EventHandlerProfileToolTime::EventHandlerProfileToolTime( - ProfileToolId_t id, const std::string& name, Params& params) : - EventHandlerProfileTool(id, name, params) +EventHandlerProfileToolTime::EventHandlerProfileToolTime(const std::string& name, Params& params) : + EventHandlerProfileTool(name, params) {} template @@ -131,7 +128,7 @@ template void EventHandlerProfileToolTime::outputData(FILE* fp) { - fprintf(fp, "%s (id = %" PRIu64 ")\n", name.c_str(), my_id); + fprintf(fp, "%s\n", name.c_str()); fprintf(fp, "Name"); if ( profile_receives_ ) fprintf(fp, ", recv count, recv time (s), avg. recv time (ns)"); if ( profile_sends_ ) fprintf(fp, ", send count"); @@ -160,8 +157,8 @@ class EventHandlerProfileToolTimeHighResolution : public EventHandlerProfileTool "Profiler that will time handlers using a high resolution clock" ) - EventHandlerProfileToolTimeHighResolution(ProfileToolId_t id, const std::string& name, Params& params) : - EventHandlerProfileToolTime(id, name, params) + EventHandlerProfileToolTimeHighResolution(const std::string& name, Params& params) : + EventHandlerProfileToolTime(name, params) {} ~EventHandlerProfileToolTimeHighResolution() {} @@ -181,8 +178,8 @@ class EventHandlerProfileToolTimeSteady : public EventHandlerProfileToolTime(id, name, params) + EventHandlerProfileToolTimeSteady(const std::string& name, Params& params) : + EventHandlerProfileToolTime(name, params) {} ~EventHandlerProfileToolTimeSteady() {} diff --git a/src/sst/core/profile/eventHandlerProfileTool.h b/src/sst/core/profile/eventHandlerProfileTool.h index 23816ec42..381bd4e70 100644 --- a/src/sst/core/profile/eventHandlerProfileTool.h +++ b/src/sst/core/profile/eventHandlerProfileTool.h @@ -32,7 +32,7 @@ class EventHandlerProfileTool : public HandlerProfileToolAPI SST_ELI_REGISTER_PROFILETOOL_DERIVED_API(SST::Profile::EventHandlerProfileTool, SST::HandlerProfileToolAPI, Params&) SST_ELI_DOCUMENT_PARAMS( - { "level", "Level at which to track profile (global, type, component, subcomponent)", "component" }, + { "level", "Level at which to track profile (global, type, component, subcomponent)", "type" }, { "track_ports", "Controls whether to track by individual ports", "false" }, { "profile_sends", "Controls whether sends are profiled (due to location of profiling point in the code, turning on send profiling will incur relatively high overhead)", "false" }, { "profile_receives", "Controls whether receives are profiled", "true" }, @@ -40,7 +40,7 @@ class EventHandlerProfileTool : public HandlerProfileToolAPI enum class Profile_Level { Global, Type, Component, Subcomponent }; - EventHandlerProfileTool(ProfileToolId_t id, const std::string& name, Params& params); + EventHandlerProfileTool(const std::string& name, Params& params); virtual void eventSent(uintptr_t UNUSED(key), Event* UNUSED(ev)) {} @@ -82,7 +82,7 @@ class EventHandlerProfileToolCount : public EventHandlerProfileTool "Profiler that will count calls to handler functions" ) - EventHandlerProfileToolCount(ProfileToolId_t id, const std::string& name, Params& params); + EventHandlerProfileToolCount(const std::string& name, Params& params); virtual ~EventHandlerProfileToolCount() {} @@ -114,7 +114,7 @@ class EventHandlerProfileToolTime : public EventHandlerProfileTool }; public: - EventHandlerProfileToolTime(ProfileToolId_t id, const std::string& name, Params& params); + EventHandlerProfileToolTime(const std::string& name, Params& params); virtual ~EventHandlerProfileToolTime() {} diff --git a/src/sst/core/profile/profiletool.cc b/src/sst/core/profile/profiletool.cc index b62098cc9..a31939235 100644 --- a/src/sst/core/profile/profiletool.cc +++ b/src/sst/core/profile/profiletool.cc @@ -24,7 +24,7 @@ SST_ELI_DEFINE_INFO_EXTERN(ProfileTool) SST_ELI_DEFINE_CTOR_EXTERN(ProfileTool) -ProfileTool::ProfileTool(ProfileToolId_t id, const std::string& name) : my_id(id), name(name) {} +ProfileTool::ProfileTool(const std::string& name) : name(name) {} } // namespace Profile } // namespace SST diff --git a/src/sst/core/profile/profiletool.h b/src/sst/core/profile/profiletool.h index aecd02a0d..d98cc56ab 100644 --- a/src/sst/core/profile/profiletool.h +++ b/src/sst/core/profile/profiletool.h @@ -32,23 +32,20 @@ class ProfileTool public: SST_ELI_DECLARE_BASE(ProfileTool) // maybe declare extern to limit compile times?? - SST_ELI_DECLARE_CTOR_EXTERN(ProfileToolId_t, const std::string&) + SST_ELI_DECLARE_CTOR_EXTERN(const std::string&, Params&) SST_ELI_DECLARE_INFO_EXTERN( ELI::ProvidesInterface, ELI::ProvidesParams) - ProfileTool(ProfileToolId_t id, const std::string& name); + ProfileTool(const std::string& name); virtual ~ProfileTool() {} - ProfileToolId_t getId() { return my_id; } - std::string getName() { return name; } virtual void outputData(FILE* fp) = 0; protected: - const uint64_t my_id; const std::string name; }; @@ -60,11 +57,11 @@ class ProfileTool // it #define SST_ELI_REGISTER_PROFILETOOL_API(cls, ...) \ SST_ELI_DECLARE_NEW_BASE(SST::Profile::ProfileTool,::cls) \ - SST_ELI_NEW_BASE_CTOR(ProfileToolId_t,const std::string&,##__VA_ARGS__) + SST_ELI_NEW_BASE_CTOR(const std::string&,##__VA_ARGS__) #define SST_ELI_REGISTER_PROFILETOOL_DERIVED_API(cls, base, ...) \ SST_ELI_DECLARE_NEW_BASE(::base,::cls) \ - SST_ELI_NEW_BASE_CTOR(ProfileToolId_t,const std::string&,##__VA_ARGS__) + SST_ELI_NEW_BASE_CTOR(const std::string&,##__VA_ARGS__) #define SST_ELI_REGISTER_PROFILETOOL(cls, interface, lib, name, version, desc) \ SST_ELI_REGISTER_DERIVED(::interface,cls,lib,name,ELI_FORWARD_AS_ONE(version),desc) \ diff --git a/src/sst/core/profile/syncProfileTool.cc b/src/sst/core/profile/syncProfileTool.cc index 22d006568..ea6147ecb 100644 --- a/src/sst/core/profile/syncProfileTool.cc +++ b/src/sst/core/profile/syncProfileTool.cc @@ -22,13 +22,9 @@ namespace SST { namespace Profile { -SyncProfileTool::SyncProfileTool(ProfileToolId_t id, const std::string& name, Params& UNUSED(params)) : - ProfileTool(id, name) -{} +SyncProfileTool::SyncProfileTool(const std::string& name, Params& UNUSED(params)) : ProfileTool(name) {} -SyncProfileToolCount::SyncProfileToolCount(ProfileToolId_t id, const std::string& name, Params& params) : - SyncProfileTool(id, name, params) -{} +SyncProfileToolCount::SyncProfileToolCount(const std::string& name, Params& params) : SyncProfileTool(name, params) {} void SyncProfileToolCount::syncManagerStart() @@ -40,21 +36,20 @@ SyncProfileToolCount::syncManagerStart() void SyncProfileToolCount::outputData(FILE* fp) { - fprintf(fp, "%s (id = %" PRIu64 ")\n", name.c_str(), my_id); + fprintf(fp, "%s\n", name.c_str()); fprintf(fp, " SyncManager Count = %" PRIu64 "\n", syncmanager_count); } template -SyncProfileToolTime::SyncProfileToolTime(ProfileToolId_t id, const std::string& name, Params& params) : - SyncProfileTool(id, name, params) +SyncProfileToolTime::SyncProfileToolTime(const std::string& name, Params& params) : SyncProfileTool(name, params) {} template void SyncProfileToolTime::outputData(FILE* fp) { - fprintf(fp, "%s (id = %" PRIu64 ")\n", name.c_str(), my_id); + fprintf(fp, "%s\n", name.c_str()); fprintf(fp, " SyncManager Count = %" PRIu64 "\n", syncmanager_count); fprintf(fp, " Total SyncManager Time = %lfs\n", (float)syncmanager_time / 1000000000.0); fprintf(fp, " Average SyncManager Time = %" PRIu64 "ns\n", syncmanager_time / syncmanager_count); @@ -73,8 +68,8 @@ class SyncProfileToolTimeHighResolution : public SyncProfileToolTime(id, name, params) + SyncProfileToolTimeHighResolution(const std::string& name, Params& params) : + SyncProfileToolTime(name, params) {} ~SyncProfileToolTimeHighResolution() {} @@ -94,8 +89,8 @@ class SyncProfileToolTimeSteady : public SyncProfileToolTime(id, name, params) + SyncProfileToolTimeSteady(const std::string& name, Params& params) : + SyncProfileToolTime(name, params) {} ~SyncProfileToolTimeSteady() {} diff --git a/src/sst/core/profile/syncProfileTool.h b/src/sst/core/profile/syncProfileTool.h index 39223b59f..3f59971a9 100644 --- a/src/sst/core/profile/syncProfileTool.h +++ b/src/sst/core/profile/syncProfileTool.h @@ -36,7 +36,7 @@ class SyncProfileTool : public ProfileTool ) // enum class Profile_Level { Global, Type, Component, Subcomponent }; - SyncProfileTool(ProfileToolId_t id, const std::string& name, Params& params); + SyncProfileTool(const std::string& name, Params& params); virtual void syncManagerStart() {} virtual void syncManagerEnd() {} @@ -60,7 +60,7 @@ class SyncProfileToolCount : public SyncProfileTool "Profiler that will count calls to sync" ) - SyncProfileToolCount(ProfileToolId_t id, const std::string& name, Params& params); + SyncProfileToolCount(const std::string& name, Params& params); virtual ~SyncProfileToolCount() {} @@ -80,7 +80,7 @@ template class SyncProfileToolTime : public SyncProfileTool { public: - SyncProfileToolTime(ProfileToolId_t id, const std::string& name, Params& params); + SyncProfileToolTime(const std::string& name, Params& params); virtual ~SyncProfileToolTime() {} diff --git a/src/sst/core/simulation.cc b/src/sst/core/simulation.cc index 0a1190a72..49e35a5b8 100644 --- a/src/sst/core/simulation.cc +++ b/src/sst/core/simulation.cc @@ -172,7 +172,7 @@ Simulation_impl::createSimulation(Config* config, RankInfo my_rank, RankInfo num instanceMap[tid] = instance; instanceVec.resize(num_ranks.thread); instanceVec[my_rank.thread] = instance; - instance->intializeDefaultProfileTools(config->enabledProfiling()); + instance->intializeProfileTools(config->enabledProfiling()); return instance; } @@ -333,9 +333,9 @@ Simulation_impl::processGraphInfo(ConfigGraph& graph, const RankInfo& UNUSED(myR new SyncManager(my_rank, num_ranks, minPartTC = minPartToTC(min_part), min_part, interThreadLatencies); // Check to see if the SyncManager profile tool is installed - auto* tool = getProfileTool(SST_PROFILE_TOOL_SYNC); + auto tools = getProfileTool("sync"); - if ( tool != nullptr ) { + for ( auto& tool : tools ) { // Add the receive profiler to the handler syncManager->addProfileTool(tool); } @@ -1066,14 +1066,14 @@ Simulation_impl::resizeBarriers(uint32_t nthr) finishBarrier.resize(nthr); } - void -Simulation_impl::intializeDefaultProfileTools(const std::string& config) +Simulation_impl::intializeProfileTools(const std::string& config) { + if ( config == "" ) return; // Need to parse the profile string. Format is: - // point=type(key=value,key=value); point=type(...) + // profiler_name:profiler_type=(key=value,key=value)[point,point]; ... - // type is optional. If not specified, a default will be used. Params are optional. + // params are optional // First split on semicolon std::vector tokens; @@ -1081,37 +1081,70 @@ Simulation_impl::intializeDefaultProfileTools(const std::string& config) for ( auto& x : tokens ) { // Need to get the profile point name, type and params - std::string point; + std::string name; std::string type; std::string param_str; + std::string points; + // Find the name to use for the profiler. This is the name + // that will be printed in the output auto start = 0; auto end = x.find(":"); - point = x.substr(start, end - start); - trim(point); - if ( end != std::string::npos ) { - // type was specifed, get it - start = end + 1; - end = x.find("(", start); - type = x.substr(start, end - start); + if ( end == std::string::npos ) { + // error in format, missing profiler name + sim_output.fatal( + CALL_INFO_LONG, 1, + "ERROR: Invalid format for argument passed to --enable-profiling. Argument should be a " + "semi-colon " + "separated list where each item specified details for a given profiling point using the " + "following format: point=type(key=value,key=value,...). Params are optional and can only be " + "specified if a type is supplied. Type is also optional and a default type will be used if " + "not specified.\n"); + } + + name = x.substr(start, end - start); + trim(name); + // Get the profiler info. This will be everything from the + // current position to '['. This will include the type, plus + // any optional parameters + std::string profiler_info; + start = end + 1; + end = x.find("[", start); + if ( end == std::string::npos ) { + // format error, no profile points specified + } + + profiler_info = x.substr(start, end - start); + trim(profiler_info); + + // get the profile points string + start = end + 1; + end = x.find("]", start); + if ( end == std::string::npos ) { + // format error, no end square bracket + } + + points = x.substr(start, end - start); + trim(points); + + // Need to get the profiler type and parameters + start = 0; + end = profiler_info.find("(", start); + if ( end == std::string::npos ) { + // No parameters + type = profiler_info; + } + else { + type = profiler_info.substr(start, end - start); trim(type); - if ( end != std::string::npos ) { - // Get the params - start = end + 1; - end = x.find(")", start); - if ( end == std::string::npos ) { - sim_output.fatal( - CALL_INFO_LONG, 1, - "ERROR: Invalid format for argument passed to --enable-profiling. Argument should be a " - "semi-colon " - "separated list where each item specified details for a given profiling point using the " - "following format: point=type(key=value,key=value,...). Params are optional and can only be " - "specified if a type is supplied. Type is also optional and a default type will be used if " - "not specified.\n"); - } - param_str = x.substr(start, end - start); - trim(param_str); + + start = end + 1; + end = profiler_info.find(")", start); + if ( end == std::string::npos ) { + // Format error, not end paran } + param_str = profiler_info.substr(start, end - start); + trim(param_str); } Params params; @@ -1130,35 +1163,58 @@ Simulation_impl::intializeDefaultProfileTools(const std::string& config) } } - // Initialize the point - if ( point == "" ) { - // Do nothing + // Need to initialize the profile_tool. If it's already + // there, then error since you can't reuse the same tool name. + if ( profile_tools.count(name) == 0 ) { + auto* tool = Factory::getFactory()->CreateProfileTool(type, name, params); + profile_tools[name] = tool; } - else if ( point == "event" ) { - if ( type == "" ) type = "sst.profile.handler.event.time.high_resolution"; - auto* tool = Factory::getFactory()->CreateProfileTool( - type, SST_PROFILE_TOOL_EVENT, "Default Event Handler Profile Tool", params); - profile_tools[SST_PROFILE_TOOL_EVENT] = tool; - } - else if ( point == "clock" ) { - if ( type == "" ) type = "sst.profile.handler.clock.time.high_resolution"; - auto* tool = Factory::getFactory()->CreateProfileTool( - type, SST_PROFILE_TOOL_CLOCK, "Default Clock Handler Profile Tool", params); - profile_tools[SST_PROFILE_TOOL_CLOCK] = tool; + else { + // Error, can't reuse tool name + sim_output.fatal(CALL_INFO_LONG, 1, "ERROR: Cannot reuse tool name: %s\n", name.c_str()); } - else if ( point == "sync" ) { - if ( type == "" ) type = "sst.profile.sync.time.high_resolution"; - auto* tool = Factory::getFactory()->CreateProfileTool( - type, SST_PROFILE_TOOL_SYNC, "Default SYNC Profile Tool", params); - profile_tools[SST_PROFILE_TOOL_SYNC] = tool; + + // Now, parse the points + std::vector point_tokens; + SST::tokenize(point_tokens, points, ",", true); + + for ( auto& tok : point_tokens ) { + // Check to see if this is a valid profile point + std::string p(tok); + SST::trim(p); + auto index = p.find_last_of("."); + + bool valid = false; + if ( index == std::string::npos ) { + // No do, see if it's one of the built-in points + if ( p == "clock" || p == "event" || p == "sync" ) { valid = true; } + } + else { + // Get the type and the point + std::string type = p.substr(0, index); + std::string point = p.substr(index + 1); + if ( Factory::getFactory()->isProfilePointValid(type, point) ) { valid = true; } + } + + if ( !valid ) + sim_output.fatal(CALL_INFO_LONG, 1, "ERROR: Invalid profile point specified: %s\n", tok.c_str()); + + profiler_map[p].push_back(name); } - else { - // FATAL - sim_output.fatal( - CALL_INFO_LONG, 1, "ERROR: Unknown profiling point specified with --enable-profiling: %s\n", - point.c_str()); + } + +#if 0 + printf("Profile tools:\n"); + for ( auto& x : profile_tools ) { + printf(" %s\n", x.first.c_str()); + } + printf("Profile points:\n"); + for ( auto& x : profiler_map ) { + for ( auto& y : x.second ) { + printf(" %s -> %s\n", x.first.c_str(), y.c_str()); } } +#endif } void diff --git a/src/sst/core/simulation_impl.h b/src/sst/core/simulation_impl.h index cb9d8110d..1e8795afb 100644 --- a/src/sst/core/simulation_impl.h +++ b/src/sst/core/simulation_impl.h @@ -34,12 +34,6 @@ /* Forward declare for Friendship */ extern int main(int argc, char** argv); -// #defines for the various default profile tools -#define SST_PROFILE_TOOL_EVENT 1 -#define SST_PROFILE_TOOL_CLOCK 2 -#define SST_PROFILE_TOOL_SYNC 3 -#define SST_PROFILE_TOOL_CUSTOM_START 4 - namespace SST { #define _SIM_DBG(fmt, args...) __DBG(DBG_SIM, Sim, fmt, ##args) @@ -388,27 +382,51 @@ class Simulation_impl : public Simulation /** Performance Tracking Information **/ - void intializeDefaultProfileTools(const std::string& config); + void intializeProfileTools(const std::string& config); - std::map profile_tools; + std::map profile_tools; + // Maps the component profile points to profiler names + std::map> profiler_map; template - T* getProfileTool(uint64_t id) + std::vector getProfileTool(std::string point) { + std::vector ret; try { - SST::Profile::ProfileTool* val = profile_tools.at(id); - T* ret = dynamic_cast(val); - if ( !ret ) { - // Not the right type, fatal - Output::getDefaultObject().fatal( - CALL_INFO_LONG, 1, "INTERNAL ERROR: wrong type of profiling tool found (id = %" PRIu64 ")\n", id); + std::vector& profilers = profiler_map.at(point); + + for ( auto& x : profilers ) { + try { + SST::Profile::ProfileTool* val = profile_tools.at(x); + + T* tool = dynamic_cast(val); + if ( !tool ) { + // Not the right type, fatal + Output::getDefaultObject().fatal( + CALL_INFO_LONG, 1, + "ERROR: wrong type of profiling tool found (name = %s). Check to make sure the profiling " + "points enabled for this tool accept the type specified\n", + x.c_str()); + } + ret.push_back(tool); + } + catch ( std::out_of_range& e ) { + // This shouldn't happen. If it does, then something + // didn't get initialized correctly. + Output::getDefaultObject().fatal( + CALL_INFO_LONG, 1, + "INTERNAL ERROR: ProfileTool refered to in profiler_map not found in profile_tools map\n"); + return ret; + } } - return ret; } catch ( std::out_of_range& e ) { - // Not there, return nullptr - return nullptr; + // point not turned on, return nullptr + return ret; } + + + return ret; } diff --git a/src/sst/core/sst_types.h b/src/sst/core/sst_types.h index 75031638c..e8930f497 100644 --- a/src/sst/core/sst_types.h +++ b/src/sst/core/sst_types.h @@ -21,7 +21,6 @@ typedef uint64_t ComponentId_t; typedef uint64_t StatisticId_t; typedef uint32_t LinkId_t; typedef uint64_t HandlerId_t; -typedef uint64_t ProfileToolId_t; typedef uint64_t Cycle_t; typedef uint64_t SimTime_t; typedef double Time_t; diff --git a/src/sst/core/ssthandler.h b/src/sst/core/ssthandler.h index d7028ee85..1ad328dda 100644 --- a/src/sst/core/ssthandler.h +++ b/src/sst/core/ssthandler.h @@ -35,10 +35,10 @@ class HandlerProfileToolAPI : public Profile::ProfileTool { public: // Register with ELI as base API - SST_ELI_REGISTER_PROFILETOOL_API(SST::HandlerProfileToolAPI, ProfileToolId_t, const std::string&) + SST_ELI_REGISTER_PROFILETOOL_API(SST::HandlerProfileToolAPI, Params&) protected: - HandlerProfileToolAPI(ProfileToolId_t id, const std::string& name) : Profile::ProfileTool(id, name) {} + HandlerProfileToolAPI(const std::string& name) : Profile::ProfileTool(name) {} ~HandlerProfileToolAPI() {} public: diff --git a/src/sst/core/subcomponent.h b/src/sst/core/subcomponent.h index 08ee56729..5bf7a0249 100644 --- a/src/sst/core/subcomponent.h +++ b/src/sst/core/subcomponent.h @@ -40,6 +40,7 @@ class SubComponent : public BaseComponent ELI::ProvidesPorts, ELI::ProvidesSubComponentSlots, ELI::ProvidesStats, + ELI::ProvidesProfilePoints, ELI::ProvidesAttributes) SubComponent(ComponentId_t id);