From 27c71518e129a778411e977e403a0b2c36b88536 Mon Sep 17 00:00:00 2001 From: Scott Hemmert Date: Wed, 18 Dec 2024 17:08:05 -0700 Subject: [PATCH 1/3] Attach Points (#1185) * Abstracted the profiling points for events and clocks so that they now consist of AttachPoints and a base profiling class. Tools now use multiple inheritance to get the AttachPoints and tool type base class they need. This was done in preparation for using those AttachPoints in other types of tools. Also added a profiling testsuite to the core testing; profiling testing is not yet comprehensive and is only run in serial for now. --- src/sst/core/Makefile.am | 1 - src/sst/core/baseComponent.cc | 6 +- src/sst/core/clock.h | 2 +- src/sst/core/event.h | 2 +- src/sst/core/link.cc | 39 +- src/sst/core/link.h | 43 +- .../core/profile/clockHandlerProfileTool.cc | 10 +- .../core/profile/clockHandlerProfileTool.h | 21 +- .../core/profile/eventHandlerProfileTool.cc | 25 +- .../core/profile/eventHandlerProfileTool.h | 31 +- src/sst/core/simulation.cc | 8 +- src/sst/core/sst_types.h | 12 + src/sst/core/ssthandler.cc | 30 - src/sst/core/ssthandler.h | 729 ++++++++++++------ tests/Makefile.inc | 5 + .../test_Profiling_event_component.out | 44 ++ .../refFiles/test_Profiling_event_global.out | 29 + .../test_Profiling_event_subcomponent.out | 92 +++ tests/refFiles/test_Profiling_event_type.out | 29 + tests/testsuite_default_profiling.py | 73 ++ 20 files changed, 907 insertions(+), 324 deletions(-) delete mode 100644 src/sst/core/ssthandler.cc create mode 100644 tests/refFiles/test_Profiling_event_component.out create mode 100644 tests/refFiles/test_Profiling_event_global.out create mode 100644 tests/refFiles/test_Profiling_event_subcomponent.out create mode 100644 tests/refFiles/test_Profiling_event_type.out create mode 100644 tests/testsuite_default_profiling.py diff --git a/src/sst/core/Makefile.am b/src/sst/core/Makefile.am index 3367928f7..f3fe09f38 100644 --- a/src/sst/core/Makefile.am +++ b/src/sst/core/Makefile.am @@ -216,7 +216,6 @@ sst_core_sources = \ unitAlgebra.cc \ module.cc \ realtime.cc \ - ssthandler.cc \ sstpart.cc \ timeVortex.cc \ serialization/objectMap.cc \ diff --git a/src/sst/core/baseComponent.cc b/src/sst/core/baseComponent.cc index 69ecf79a4..bb86b2f7f 100644 --- a/src/sst/core/baseComponent.cc +++ b/src/sst/core/baseComponent.cc @@ -129,7 +129,7 @@ BaseComponent::registerClock_impl(TimeConverter* tc, Clock::HandlerBase* handler for ( auto* tool : tools ) { ClockHandlerMetaData mdata(my_info->getID(), getName(), getType()); // Add the receive profiler to the handler - handler->addProfileTool(tool, mdata); + handler->attachTool(tool, mdata); } // if regAll is true set tc as the default for the component and @@ -295,10 +295,10 @@ BaseComponent::configureLink(const std::string& name, TimeConverter* time_base, EventHandlerMetaData mdata(my_info->getID(), getName(), getType(), name); // Add the receive profiler to the handler - if ( tool->profileReceives() ) handler->addProfileTool(tool, mdata); + if ( tool->profileReceives() ) handler->attachTool(tool, mdata); // Add the send profiler to the link - if ( tool->profileSends() ) tmp->addProfileTool(tool, mdata); + if ( tool->profileSends() ) tmp->attachTool(tool, mdata); } } if ( nullptr != time_base ) diff --git a/src/sst/core/clock.h b/src/sst/core/clock.h index 43fcb1009..f556be5d7 100644 --- a/src/sst/core/clock.h +++ b/src/sst/core/clock.h @@ -120,7 +120,7 @@ class Clock : public Action }; -class ClockHandlerMetaData : public HandlerMetaData +class ClockHandlerMetaData : public AttachPointMetaData { public: const ComponentId_t comp_id; diff --git a/src/sst/core/event.h b/src/sst/core/event.h index 92b694d98..86bf10f42 100644 --- a/src/sst/core/event.h +++ b/src/sst/core/event.h @@ -217,7 +217,7 @@ class EmptyEvent : public Event ImplementSerializable(SST::EmptyEvent) }; -class EventHandlerMetaData : public HandlerMetaData +class EventHandlerMetaData : public AttachPointMetaData { public: const ComponentId_t comp_id; diff --git a/src/sst/core/link.cc b/src/sst/core/link.cc index ac962918d..e8382631a 100644 --- a/src/sst/core/link.cc +++ b/src/sst/core/link.cc @@ -461,28 +461,6 @@ class NullEvent : public Event }; -class LinkSendProfileToolList -{ -public: - LinkSendProfileToolList() {} - - inline void eventSent(Event* ev) - { - for ( auto& x : tools ) { - x.first->eventSent(x.second, ev); - } - } - - void addProfileTool(SST::Profile::EventHandlerProfileTool* tool, const EventHandlerMetaData& mdata) - { - auto key = tool->registerHandler(mdata); - tools.push_back(std::make_pair(tool, key)); - } - -private: - std::vector> tools; -}; - Link::Link(LinkId_t tag) : send_queue(nullptr), delivery_info(0), @@ -631,7 +609,7 @@ Link::replaceFunctor(Event::HandlerBase* functor) type = HANDLER; if ( pair_link->delivery_info ) { auto* handler = reinterpret_cast(pair_link->delivery_info); - functor->transferProfilingInfo(handler); + functor->transferAttachedToolInfo(handler); delete handler; } pair_link->delivery_info = reinterpret_cast(functor); @@ -663,7 +641,13 @@ Link::send_impl(SimTime_t delay, Event* event) event->addRecvComponent(pair_link->comp, pair_link->ctype, pair_link->port); #endif - if ( profile_tools ) profile_tools->eventSent(event); + if ( profile_tools ) { + for ( auto& x : *profile_tools ) { + x.first->eventSent(x.second, event); + // Check to see if the event was deleted. If so, return. + if ( nullptr == event ) return; + } + } send_queue->insert(event); } @@ -803,10 +787,11 @@ Link::createUniqueGlobalLinkName(RankInfo local_rank, uintptr_t local_ptr, RankI } void -Link::addProfileTool(SST::Profile::EventHandlerProfileTool* tool, const EventHandlerMetaData& mdata) +Link::attachTool(AttachPoint* tool, const AttachPointMetaData& mdata) { - if ( !profile_tools ) profile_tools = new LinkSendProfileToolList(); - profile_tools->addProfileTool(tool, mdata); + if ( !profile_tools ) profile_tools = new ToolList(); + auto key = tool->registerLinkAttachTool(mdata); + profile_tools->push_back(std::make_pair(tool, key)); } diff --git a/src/sst/core/link.h b/src/sst/core/link.h index fa4a97bad..b02cbdc74 100644 --- a/src/sst/core/link.h +++ b/src/sst/core/link.h @@ -28,7 +28,6 @@ class LinkPair; class Simulation_impl; class UnitAlgebra; -class LinkSendProfileToolList; namespace Profile { class EventHandlerProfileTool; @@ -56,6 +55,43 @@ class alignas(64) Link friend class SST::Core::Serialization::serialize_impl; public: + /** + Attach point for inspecting, modifying or dropping events + sent on the Link. + + NOTE: Using the Link::AttachPoint will noticeably affect the + performance of sending events on Links and it is recommended + that, if possible, Event::HandlerBase::AttachPoint or + Event::HandlerBase::InterceptPoint be used instead. + */ + class AttachPoint + { + public: + /** + Function that will be called when an attach point is + registered with the tool implementing the attach point. + The metadata passed in will be dependent on what type of + tool this is attached to. The uintptr_t returned from this + function will be passed into the eventSent() function. + + @param mdata Metadata to be passed into the tool + + @return Opaque key that will be passed back into + eventSent() to identify the source of the call + */ + virtual uintptr_t registerLinkAttachTool(const AttachPointMetaData& mdata) = 0; + + /** + Function that will be called when an event is sent on a + link with registered attach points. If ev is set to + nullptr, then the event will not be delivered and the tool + should delete the original event. + + @param key Opaque key returned from registerLinkAttachTool() + */ + virtual void eventSent(uintptr_t key, Event*& ev) = 0; + }; + friend class LinkPair; friend class RankSync; friend class ThreadSync; @@ -285,10 +321,11 @@ class alignas(64) Link createUniqueGlobalLinkName(RankInfo local_rank, uintptr_t local_ptr, RankInfo remote_rank, uintptr_t remote_ptr); - void addProfileTool(SST::Profile::EventHandlerProfileTool* tool, const EventHandlerMetaData& mdata); + void attachTool(AttachPoint* tool, const AttachPointMetaData& mdata); - LinkSendProfileToolList* profile_tools; + using ToolList = std::vector>; + ToolList* profile_tools; #ifdef __SST_DEBUG_EVENT_TRACKING__ diff --git a/src/sst/core/profile/clockHandlerProfileTool.cc b/src/sst/core/profile/clockHandlerProfileTool.cc index a760478c5..94d93c0db 100644 --- a/src/sst/core/profile/clockHandlerProfileTool.cc +++ b/src/sst/core/profile/clockHandlerProfileTool.cc @@ -23,7 +23,7 @@ namespace SST { namespace Profile { -ClockHandlerProfileTool::ClockHandlerProfileTool(const std::string& name, Params& params) : HandlerProfileToolAPI(name) +ClockHandlerProfileTool::ClockHandlerProfileTool(const std::string& name, Params& params) : ProfileTool(name) { std::string level = params.find("level", "type"); if ( level == "global" ) @@ -41,7 +41,7 @@ ClockHandlerProfileTool::ClockHandlerProfileTool(const std::string& name, Params } std::string -ClockHandlerProfileTool::getKeyForHandler(const HandlerMetaData& mdata) +ClockHandlerProfileTool::getKeyForHandler(const AttachPointMetaData& mdata) { const ClockHandlerMetaData& data = dynamic_cast(mdata); @@ -71,13 +71,13 @@ ClockHandlerProfileToolCount::ClockHandlerProfileToolCount(const std::string& na {} uintptr_t -ClockHandlerProfileToolCount::registerHandler(const HandlerMetaData& mdata) +ClockHandlerProfileToolCount::registerHandler(const AttachPointMetaData& mdata) { return reinterpret_cast(&counts_[getKeyForHandler(mdata)]); } void -ClockHandlerProfileToolCount::handlerStart(uintptr_t key) +ClockHandlerProfileToolCount::beforeHandler(uintptr_t key, const Cycle_t& UNUSED(cycle)) { (*reinterpret_cast(key))++; } @@ -101,7 +101,7 @@ ClockHandlerProfileToolTime::ClockHandlerProfileToolTime(const std::string& n template uintptr_t -ClockHandlerProfileToolTime::registerHandler(const HandlerMetaData& mdata) +ClockHandlerProfileToolTime::registerHandler(const AttachPointMetaData& mdata) { return reinterpret_cast(×_[getKeyForHandler(mdata)]); } diff --git a/src/sst/core/profile/clockHandlerProfileTool.h b/src/sst/core/profile/clockHandlerProfileTool.h index 2902c80f6..295be1d04 100644 --- a/src/sst/core/profile/clockHandlerProfileTool.h +++ b/src/sst/core/profile/clockHandlerProfileTool.h @@ -26,10 +26,10 @@ namespace SST { namespace Profile { -class ClockHandlerProfileTool : public HandlerProfileToolAPI +class ClockHandlerProfileTool : public ProfileTool, public Clock::HandlerBase::AttachPoint { public: - SST_ELI_REGISTER_PROFILETOOL_DERIVED_API(SST::Profile::ClockHandlerProfileTool, SST::HandlerProfileToolAPI, Params&) + SST_ELI_REGISTER_PROFILETOOL_DERIVED_API(SST::Profile::ClockHandlerProfileTool, SST::Profile::ProfileTool, Params&) SST_ELI_DOCUMENT_PARAMS( { "level", "Level at which to track profile (global, type, component, subcomponent)", "type" }, @@ -39,8 +39,13 @@ class ClockHandlerProfileTool : public HandlerProfileToolAPI ClockHandlerProfileTool(const std::string& name, Params& params); + // Default implementations of attach point functions for profile + // tools that don't use them + void beforeHandler(uintptr_t UNUSED(key), const Cycle_t& UNUSED(cycle)) override {} + void afterHandler(uintptr_t UNUSED(key), const bool& UNUSED(remove)) override {} + protected: - std::string getKeyForHandler(const HandlerMetaData& mdata); + std::string getKeyForHandler(const AttachPointMetaData& mdata); Profile_Level profile_level_; }; @@ -66,9 +71,9 @@ class ClockHandlerProfileToolCount : public ClockHandlerProfileTool virtual ~ClockHandlerProfileToolCount() {} - uintptr_t registerHandler(const HandlerMetaData& mdata) override; + uintptr_t registerHandler(const AttachPointMetaData& mdata) override; - void handlerStart(uintptr_t key) override; + void beforeHandler(uintptr_t key, const Cycle_t& cycle) override; void outputData(FILE* fp) override; @@ -96,11 +101,11 @@ class ClockHandlerProfileToolTime : public ClockHandlerProfileTool virtual ~ClockHandlerProfileToolTime() {} - uintptr_t registerHandler(const HandlerMetaData& mdata) override; + uintptr_t registerHandler(const AttachPointMetaData& mdata) override; - void handlerStart(uintptr_t UNUSED(key)) override { start_time_ = T::now(); } + void beforeHandler(uintptr_t UNUSED(key), const Cycle_t& UNUSED(cycle)) override { start_time_ = T::now(); } - void handlerEnd(uintptr_t key) override + void afterHandler(uintptr_t key, const bool& UNUSED(remove)) override { auto total_time = T::now() - start_time_; clock_data_t* entry = reinterpret_cast(key); diff --git a/src/sst/core/profile/eventHandlerProfileTool.cc b/src/sst/core/profile/eventHandlerProfileTool.cc index b25a710a3..ebac8027c 100644 --- a/src/sst/core/profile/eventHandlerProfileTool.cc +++ b/src/sst/core/profile/eventHandlerProfileTool.cc @@ -23,7 +23,7 @@ namespace SST { namespace Profile { -EventHandlerProfileTool::EventHandlerProfileTool(const std::string& name, Params& params) : HandlerProfileToolAPI(name) +EventHandlerProfileTool::EventHandlerProfileTool(const std::string& name, Params& params) : ProfileTool(name) { std::string level = params.find("level", "type"); if ( level == "global" ) @@ -46,7 +46,7 @@ EventHandlerProfileTool::EventHandlerProfileTool(const std::string& name, Params } std::string -EventHandlerProfileTool::getKeyForHandler(const HandlerMetaData& mdata) +EventHandlerProfileTool::getKeyForHandler(const AttachPointMetaData& mdata) { const EventHandlerMetaData& data = dynamic_cast(mdata); @@ -78,19 +78,25 @@ EventHandlerProfileToolCount::EventHandlerProfileToolCount(const std::string& na {} uintptr_t -EventHandlerProfileToolCount::registerHandler(const HandlerMetaData& mdata) +EventHandlerProfileToolCount::registerHandler(const AttachPointMetaData& mdata) +{ + return reinterpret_cast(&counts_[getKeyForHandler(mdata)]); +} + +uintptr_t +EventHandlerProfileToolCount::registerLinkAttachTool(const AttachPointMetaData& mdata) { return reinterpret_cast(&counts_[getKeyForHandler(mdata)]); } void -EventHandlerProfileToolCount::handlerStart(uintptr_t key) +EventHandlerProfileToolCount::beforeHandler(uintptr_t key, const Event* UNUSED(event)) { reinterpret_cast(key)->recv_count++; } void -EventHandlerProfileToolCount::eventSent(uintptr_t key, Event* UNUSED(ev)) +EventHandlerProfileToolCount::eventSent(uintptr_t key, Event*& UNUSED(ev)) { reinterpret_cast(key)->send_count++; } @@ -120,7 +126,14 @@ EventHandlerProfileToolTime::EventHandlerProfileToolTime(const std::string& n template uintptr_t -EventHandlerProfileToolTime::registerHandler(const HandlerMetaData& mdata) +EventHandlerProfileToolTime::registerHandler(const AttachPointMetaData& mdata) +{ + return reinterpret_cast(×_[getKeyForHandler(mdata)]); +} + +template +uintptr_t +EventHandlerProfileToolTime::registerLinkAttachTool(const AttachPointMetaData& mdata) { return reinterpret_cast(×_[getKeyForHandler(mdata)]); } diff --git a/src/sst/core/profile/eventHandlerProfileTool.h b/src/sst/core/profile/eventHandlerProfileTool.h index 9c5ac6c2d..509d454f4 100644 --- a/src/sst/core/profile/eventHandlerProfileTool.h +++ b/src/sst/core/profile/eventHandlerProfileTool.h @@ -14,6 +14,7 @@ #include "sst/core/eli/elementinfo.h" #include "sst/core/event.h" +#include "sst/core/link.h" #include "sst/core/sst_types.h" #include "sst/core/ssthandler.h" #include "sst/core/warnmacros.h" @@ -26,10 +27,10 @@ namespace SST { namespace Profile { -class EventHandlerProfileTool : public HandlerProfileToolAPI +class EventHandlerProfileTool : public ProfileTool, public Event::HandlerBase::AttachPoint, public Link::AttachPoint { public: - SST_ELI_REGISTER_PROFILETOOL_DERIVED_API(SST::Profile::EventHandlerProfileTool, SST::HandlerProfileToolAPI, Params&) + SST_ELI_REGISTER_PROFILETOOL_DERIVED_API(SST::Profile::EventHandlerProfileTool, SST::Profile::ProfileTool, Params&) SST_ELI_DOCUMENT_PARAMS( { "level", "Level at which to track profile (global, type, component, subcomponent)", "type" }, @@ -42,13 +43,19 @@ class EventHandlerProfileTool : public HandlerProfileToolAPI EventHandlerProfileTool(const std::string& name, Params& params); - virtual void eventSent(uintptr_t UNUSED(key), Event* UNUSED(ev)) {} bool profileSends() { return profile_sends_; } bool profileReceives() { return profile_receives_; } + // Default implementations of attach point functions for profile + // tools that don't use them + void beforeHandler(uintptr_t UNUSED(key), const Event* UNUSED(event)) override {} + void afterHandler(uintptr_t UNUSED(key)) override {} + void eventSent(uintptr_t UNUSED(key), Event*& UNUSED(ev)) override {} + + protected: - std::string getKeyForHandler(const HandlerMetaData& mdata); + std::string getKeyForHandler(const AttachPointMetaData& mdata); Profile_Level profile_level_; bool track_ports_; @@ -86,10 +93,11 @@ class EventHandlerProfileToolCount : public EventHandlerProfileTool virtual ~EventHandlerProfileToolCount() {} - uintptr_t registerHandler(const HandlerMetaData& mdata) override; + uintptr_t registerHandler(const AttachPointMetaData& mdata) override; + uintptr_t registerLinkAttachTool(const AttachPointMetaData& mdata) override; - void handlerStart(uintptr_t key) override; - void eventSent(uintptr_t UNUSED(key), Event* UNUSED(ev)) override; + void beforeHandler(uintptr_t key, const SST::Event* event) override; + void eventSent(uintptr_t UNUSED(key), Event*& UNUSED(ev)) override; void outputData(FILE* fp) override; @@ -118,11 +126,12 @@ class EventHandlerProfileToolTime : public EventHandlerProfileTool virtual ~EventHandlerProfileToolTime() {} - uintptr_t registerHandler(const HandlerMetaData& mdata) override; + uintptr_t registerHandler(const AttachPointMetaData& mdata) override; + uintptr_t registerLinkAttachTool(const AttachPointMetaData& mdata) override; - void handlerStart(uintptr_t UNUSED(key)) override { start_time_ = T::now(); } + void beforeHandler(uintptr_t UNUSED(key), const Event* UNUSED(event)) override { start_time_ = T::now(); } - void handlerEnd(uintptr_t key) override + void afterHandler(uintptr_t key) override { auto total_time = T::now() - start_time_; event_data_t* entry = reinterpret_cast(key); @@ -130,7 +139,7 @@ class EventHandlerProfileToolTime : public EventHandlerProfileTool entry->recv_count++; } - void eventSent(uintptr_t key, Event* UNUSED(ev)) override { reinterpret_cast(key)->send_count++; } + void eventSent(uintptr_t key, Event*& UNUSED(ev)) override { reinterpret_cast(key)->send_count++; } void outputData(FILE* fp) override; diff --git a/src/sst/core/simulation.cc b/src/sst/core/simulation.cc index 8ad51c6aa..0da7e5f76 100644 --- a/src/sst/core/simulation.cc +++ b/src/sst/core/simulation.cc @@ -1994,16 +1994,18 @@ Simulation_impl::printProfilingInfo(FILE* fp) // Print out a header if printing to stdout if ( fp == stdout && my_rank.rank == 0 && my_rank.thread == 0 ) { fprintf(fp, "\n------------------------------------------------------------\n"); - fprintf(fp, "Profiling Output:\n"); + fprintf(fp, "Profiling Output:\n\n"); } + fprintf(fp, "-----------------------------\n"); + // Print the rank and thread. Profiling output is serialized // through both ranks and threads. - fprintf(fp, "Rank = %" PRIu32 ", thread = %" PRIu32 ":\n", my_rank.rank, my_rank.thread); + fprintf(fp, "Rank = %" PRIu32 ", thread = %" PRIu32 ":\n\n", my_rank.rank, my_rank.thread); for ( auto tool : profile_tools ) { - fprintf(fp, "\n"); tool.second->outputData(fp); + fprintf(fp, "\n"); } // Print footer if printing on stdout diff --git a/src/sst/core/sst_types.h b/src/sst/core/sst_types.h index 7f2a19f07..af2b726d1 100644 --- a/src/sst/core/sst_types.h +++ b/src/sst/core/sst_types.h @@ -63,6 +63,18 @@ enum class SimulationRunMode { BOTH /*!< Default. Both initialize and Run the simulation */ }; +/** + Struct used as a base class for all AttachPoint metadata passed to + registration functions. Needed so that dynamic cast can be used + since different tools may pass different metadata through the + AttachPoints. + */ +struct AttachPointMetaData +{ + AttachPointMetaData() {} + virtual ~AttachPointMetaData() {} +}; + } // namespace SST #endif // SST_CORE_SST_TYPES_H diff --git a/src/sst/core/ssthandler.cc b/src/sst/core/ssthandler.cc deleted file mode 100644 index 359b65f2c..000000000 --- a/src/sst/core/ssthandler.cc +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2009-2024 NTESS. Under the terms -// of Contract DE-NA0003525 with NTESS, the U.S. -// Government retains certain rights in this software. -// -// Copyright (c) 2009-2024, 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/ssthandler.h" - -#include "sst/core/sst_types.h" - -#include -#include - -namespace SST { - -std::atomic SSTHandlerBaseProfile::HandlerProfileToolList::id_counter(1); - -SSTHandlerBaseProfile::HandlerProfileToolList::HandlerProfileToolList() -{ - my_id = id_counter.fetch_add(1); -} - -} // namespace SST diff --git a/src/sst/core/ssthandler.h b/src/sst/core/ssthandler.h index d6cdd3c37..3e9125ebf 100644 --- a/src/sst/core/ssthandler.h +++ b/src/sst/core/ssthandler.h @@ -20,38 +20,6 @@ namespace SST { class Params; -/** - Just a tag class for the various metadata that will need to be - stored in the simulation object to allow ProfileTools to get the - data they need. - */ -class HandlerMetaData -{ -public: - virtual ~HandlerMetaData() {} -}; - - -/** - Base class for Profile tools for Handlers -*/ -class HandlerProfileToolAPI : public Profile::ProfileTool -{ -public: - // Register with ELI as base API - SST_ELI_REGISTER_PROFILETOOL_API(SST::HandlerProfileToolAPI, Params&) - -protected: - HandlerProfileToolAPI(const std::string& name) : Profile::ProfileTool(name) {} - ~HandlerProfileToolAPI() {} - -public: - virtual uintptr_t registerHandler(const HandlerMetaData& mdata) = 0; - - virtual void handlerStart(uintptr_t UNUSED(key)) {} - virtual void handlerEnd(uintptr_t UNUSED(key)) {} -}; - // This file contains base classes for use as various handlers (object // encapsulating callback functions) in SST. These handlers are // checkpointable and encapsulate a pointer to an object and a pointer @@ -74,7 +42,7 @@ class HandlerProfileToolAPI : public Profile::ProfileTool // Note: Until support for legacy handlers are removed, the new-style // handlers should use Handler2Base and Handler2 as the preferred -// names. After legacy support is remoed with SST 15, both Handler +// names. After legacy support is removed with SST 15, both Handler // and Handler2 should both point to the new style handlers. Handler2 // will be deprecated from SST 15 until SST 16, when Handler will be // the approved name. @@ -121,162 +89,565 @@ class HandlerProfileToolAPI : public Profile::ProfileTool // new Class::Handler2(this, 1) -/// Functor classes for Event handling +/********************************************************************** + * Base class templates for handlers. The base functionlity includes + * the common API for all handlers. It also includes management of + * attach points. + * + * There are 4 total expansions of the template across 2 classes, + * based on whether their return and arg values are void or non-void. + * Each of these also define the appropriate Attach and/or Intercept + * points. + **********************************************************************/ -class SSTHandlerBaseProfile : public SST::Core::Serialization::serializable +/** + Base template for handlers which take a class defined argument. + + This default expansion covers the case of non-void return + type. This version does not support intercepts. +*/ +template +class SSTHandlerBase : public SST::Core::Serialization::serializable { -protected: - // This class will hold the id for the handler and the profiling - // tools attached to it, if profiling is enabled for this handler. - class HandlerProfileToolList +public: + /** + Attach Point to get notified when a handler starts and stops. + This class is used in conjuction with a Tool type base class to + create various tool types to attach to the handler. + */ + class AttachPoint { - static std::atomic id_counter; - HandlerId_t my_id; - public: - HandlerProfileToolList(); + AttachPoint() {} + virtual ~AttachPoint() {} - void handlerStart() - { - for ( auto& x : tools ) - x.first->handlerStart(x.second); - } - void handlerEnd() - { - for ( auto& x : tools ) - x.first->handlerEnd(x.second); - } + /** + Function that will be called when a handler is registered + with the tool implementing the attach point. The metadata + passed in will be dependent on what type of tool this is + attached to. The uintptr_t returned from this function + will be passed into the beforeHandler() and afterHandler() + functions. + + @param mdata Metadata to be passed into the tool + + @return Opaque key that will be passed back into + beforeHandler() and afterHandler() to identify the source + of the calls + */ + virtual uintptr_t registerHandler(const AttachPointMetaData& mdata) = 0; /** - Adds a profile tool the the list and registers this handler - with the profile tool - */ - void addProfileTool(HandlerProfileToolAPI* tool, const HandlerMetaData& mdata) - { - auto key = tool->registerHandler(mdata); - tools.push_back(std::make_pair(tool, key)); - } + Function to be called before the handler is called. - HandlerId_t getId() { return my_id; } + @key uintptr_t returned from registerHandler() when handler + was registered with the tool + @arg argument that will be passed to the handler function. + If argT is a pointer, this will be passed as a const + pointer, if not, it will be passed as a const reference + */ + virtual void beforeHandler( + uintptr_t key, + std::conditional_t, const std::remove_pointer_t*, const argT&> arg) = 0; - private: - std::vector> tools; + /** + Function to be called after the handler is called. The key + passed in is the uintptr_t returned from registerHandler() + + @param key uintptr_t returned from registerHandler() when + handler was registered with the tool + + @param ret_value value that was returned by the handler. If + retunT is a pointer, this will be passed as a const + pointer, if not, it will be passed as a const reference + */ + virtual void afterHandler( + uintptr_t key, + std::conditional_t, const std::remove_pointer_t*, const returnT&> + ret_value) = 0; }; - // List of profiling tools attached to this handler - HandlerProfileToolList* profile_tools; +private: + using ToolList = std::vector>; + ToolList* attached_tools = nullptr; +protected: + // Implementation of operator() to be done in child classes + virtual returnT operator_impl(argT) = 0; public: - SSTHandlerBaseProfile() : profile_tools(nullptr) {} + virtual ~SSTHandlerBase() {} - virtual ~SSTHandlerBaseProfile() + inline returnT operator()(argT arg) { - if ( profile_tools ) delete profile_tools; + if ( !attached_tools ) return operator_impl(arg); + + // Tools attached + for ( auto& x : *attached_tools ) + x.first->beforeHandler(x.second, arg); + + returnT ret = operator_impl(arg); + + for ( auto& x : *attached_tools ) + x.first->afterHandler(x.second, ret); + + return ret; } - void addProfileTool(HandlerProfileToolAPI* tool, const HandlerMetaData& mdata) + /** + Attaches a tool to the AttachPoint + + @param tool Tool to attach + + @param mdata Metadata to pass to the tool + */ + void attachTool(AttachPoint* tool, const AttachPointMetaData& mdata) { - if ( !profile_tools ) profile_tools = new HandlerProfileToolList(); - profile_tools->addProfileTool(tool, mdata); + if ( !attached_tools ) attached_tools = new ToolList(); + + auto key = tool->registerHandler(mdata); + attached_tools->push_back(std::make_pair(tool, key)); } - void transferProfilingInfo(SSTHandlerBaseProfile* handler) + /** + Transfers attached tools from existing handler + */ + void transferAttachedToolInfo(SSTHandlerBase* handler) { - if ( handler->profile_tools ) { - profile_tools = handler->profile_tools; - handler->profile_tools = nullptr; + if ( handler->attached_tools ) { + attached_tools = handler->attached_tools; + handler->attached_tools = nullptr; } } +private: + ImplementVirtualSerializable(SSTHandlerBase) +}; + + +/** + Base template for handlers which take an class defined argument. + + This expansion covers the case of void return type. This version + supports intercepts. +*/ +template +class SSTHandlerBase : public SST::Core::Serialization::serializable +{ +public: /** - Get the ID for this Handler. Handler IDs are only used for - profiling, so if this function is called, it will also set - things up to accept ProfileTools. + Attach Point to get notified when a handler starts and stops. + This class is used in conjuction with a Tool type base class to + create various tool types to attach to the handler. */ - HandlerId_t getId() + class AttachPoint { - if ( !profile_tools ) profile_tools = new HandlerProfileToolList(); - return profile_tools->getId(); - } + public: + AttachPoint() {} + virtual ~AttachPoint() {} - ImplementVirtualSerializable(SSTHandlerBaseProfile) -}; + /** + Function that will be called when a handler is registered + with the tool implementing the attach point. The metadata + passed in will be dependent on what type of tool this is + attached to. The uintptr_t returned from this function + will be passed into the beforeHandler() and afterHandler() + functions. + @param mdata Metadata to be passed into the tool -/// Handlers with 1 handler defined argument to callback from caller -template -class SSTHandlerBase : public SSTHandlerBaseProfile -{ + @return Opaque key that will be passed back into + beforeHandler() and afterHandler() to identify the source + of the calls + */ + virtual uintptr_t registerHandler(const AttachPointMetaData& mdata) = 0; + + /** + Function to be called before the handler is called. + + @key uintptr_t returned from registerHandler() when handler + was registered with the tool + + @arg argument that will be passed to the handler function. + If argT is a pointer, this will be passed as a const + pointer, if not, it will be passed as a const reference + */ + virtual void beforeHandler( + uintptr_t key, + std::conditional_t, const std::remove_pointer_t*, const argT&> arg) = 0; + + /** + Function to be called after the handler is called. The key + passed in is the uintptr_t returned from registerHandler() + + @param key uintptr_t returned from registerHandler() when + handler was registered with the tool + */ + virtual void afterHandler(uintptr_t key) = 0; + }; + + + /** + Attach Point to intercept the data being delivered by a + Handler. Class is not usable for Handlers that don't take a + parameter and/or return a value + */ + class InterceptPoint + { + public: + /** + Function that will be called when a handler is registered + with the tool implementing the intercept attach point. The + metadata passed in will be dependent on what type of tool + this is attached to. The uintptr_t returned from this + function will be passed into the intercept() function. + + @param mdata Metadata to be passed into the tool + + @return Opaque key that will be passed back into + intercept() calls + */ + virtual uintptr_t registerHandlerIntercept(const AttachPointMetaData& mdata) = 0; + + /** + Function that will be called before the event handler to + let the attach point intercept the data. The data can be + modified, and if cancel is set to true, the handler will + not be executed. If cancel is set to true and the + ownership of a pointer is passed by the call to the + handler, then the function should also delete the data. + + @param key Key that was returned from + registerHandlerIntercept() function + + @param data Data that is to be passed to the handler + + @param[out] cancel Set to true if the handler delivery + should be cancelled. + */ + virtual void interceptHandler(uintptr_t key, argT& data, bool& cancel) = 0; + }; + +private: + struct ToolList + { + std::vector> attach_tools; + std::vector> intercept_tools; + }; + ToolList* attached_tools = nullptr; + +protected: // Implementation of operator() to be done in child classes - virtual returnT operator_impl(argT) = 0; + virtual void operator_impl(argT) = 0; public: - ~SSTHandlerBase() {} + virtual ~SSTHandlerBase() {} - inline returnT operator()(argT arg) + inline void operator()(argT arg) { - if ( profile_tools ) { - if constexpr ( std::is_void_v ) { - profile_tools->handlerStart(); - operator_impl(arg); - profile_tools->handlerEnd(); - return; - } - else { - profile_tools->handlerStart(); - auto ret = operator_impl(arg); - profile_tools->handlerEnd(); - return ret; + if ( !attached_tools ) return operator_impl(arg); + + // Tools attached + for ( auto& x : attached_tools->attach_tools ) + x.first->beforeHandler(x.second, arg); + + // Check any intercepts + + bool cancel = false; + for ( auto& x : attached_tools->intercept_tools ) { + x.first->interceptHandler(x.second, arg, cancel); + if ( cancel ) { + // Handler cancelled; need to break since arg may + // no longer be valid and no other intercepts + // should be called + break; } } - return operator_impl(arg); + if ( !cancel ) { operator_impl(arg); } + + for ( auto& x : attached_tools->attach_tools ) + x.first->afterHandler(x.second); + + return; + } + + + /** + Attaches a tool to the AttachPoint + + @param tool Tool to attach + + @param mdata Metadata to pass to the tool + */ + void attachTool(AttachPoint* tool, const AttachPointMetaData& mdata) + { + if ( !attached_tools ) attached_tools = new ToolList(); + + auto key = tool->registerHandler(mdata); + attached_tools->attach_tools.push_back(std::make_pair(tool, key)); } + + /** + Transfers attached tools from existing handler + */ + void transferAttachedToolInfo(SSTHandlerBase* handler) + { + if ( handler->attached_tools ) { + attached_tools = handler->attached_tools; + handler->attached_tools = nullptr; + } + } + +private: ImplementVirtualSerializable(SSTHandlerBase) }; -/// Handlers with no arguments to callback from caller +/** + Base template for handlers which don't take a class defined + argument. + + This expansion covers the case of non-void return type. This + version does not support intercepts. +*/ template -class SSTHandlerBase : public SSTHandlerBaseProfile +class SSTHandlerBase : public SST::Core::Serialization::serializable { +public: + /** + Attach Point to get notified when a handler starts and stops. + This class is used in conjuction with a Tool type base class to + create various tool types to attach to the handler. + */ + class AttachPoint + { + public: + AttachPoint() {} + virtual ~AttachPoint() {} + + /** + Function that will be called when a handler is registered + with the tool implementing the attach point. The metadata + passed in will be dependent on what type of tool this is + attached to. The uintptr_t returned from this function + will be passed into the beforeHandler() and afterHandler() + functions. + + @param mdata Metadata to be passed into the tool + + @return Opaque key that will be passed back into + beforeHandler() and afterHandler() to identify the source + of the calls + */ + virtual uintptr_t registerHandler(const AttachPointMetaData& mdata) = 0; + + /** + Function to be called before the handler is called. + + @key uintptr_t returned from registerHandler() when handler + was registered with the tool + */ + virtual void beforeHandler(uintptr_t key) = 0; + + /** + Function to be called after the handler is called. The key + passed in is the uintptr_t returned from registerHandler() + + @param key uintptr_t returned from registerHandler() when + handler was registered with the tool + + @param ret_value value that was returned by the handler. If + retunT is a pointer, this will be passed as a const + pointer, if not, it will be passed as a const reference + */ + virtual void afterHandler( + uintptr_t key, + std::conditional_t, const std::remove_pointer_t*, const returnT&> + ret_value) = 0; + }; + +private: + using ToolList = std::vector>; + ToolList* attached_tools = nullptr; protected: + // Implementation of operator() to be done in child classes virtual returnT operator_impl() = 0; public: - SSTHandlerBase() {} - - /** Handler function */ virtual ~SSTHandlerBase() {} inline returnT operator()() { - if ( profile_tools ) { - if constexpr ( std::is_void_v ) { - profile_tools->handlerStart(); - operator_impl(); - profile_tools->handlerEnd(); - return; - } - else { - profile_tools->handlerStart(); - auto ret = operator_impl(); - profile_tools->handlerEnd(); - return ret; - } + if ( attached_tools ) { + for ( auto& x : *attached_tools ) + x.first->beforeHandler(x.second); + + returnT ret = operator_impl(); + + for ( auto& x : *attached_tools ) + x.first->afterHandler(x.second, ret); + + return ret; } return operator_impl(); } + + /** + Attaches a tool to the AttachPoint + + @param tool Tool to attach + + @param mdata Metadata to pass to the tool + */ + void attachTool(AttachPoint* tool, const AttachPointMetaData& mdata) + { + if ( !attached_tools ) attached_tools = new ToolList(); + + auto key = tool->registerHandler(mdata); + attached_tools->push_back(std::make_pair(tool, key)); + } + + /** + Transfers attached tools from existing handler + */ + void transferAttachedToolInfo(SSTHandlerBase* handler) + { + if ( handler->attached_tools ) { + attached_tools = handler->attached_tools; + handler->attached_tools = nullptr; + } + } + +private: + ImplementVirtualSerializable(SSTHandlerBase) +}; + + +/** + Base template for handlers which don't take a class defined + argument. + + This expansion covers the case of void return type. This version + does not support intercepts. +*/ +template <> +class SSTHandlerBase : public SST::Core::Serialization::serializable +{ +public: + /** + Attach Point to get notified when a handler starts and stops. + This class is used in conjuction with a Tool type base class to + create various tool types to attach to the handler. + */ + class AttachPoint + { + public: + AttachPoint() {} + virtual ~AttachPoint() {} + + /** + Function that will be called when a handler is registered + with the tool implementing the attach point. The metadata + passed in will be dependent on what type of tool this is + attached to. The uintptr_t returned from this function + will be passed into the beforeHandler() and afterHandler() + functions. + + @param mdata Metadata to be passed into the tool + + @return Opaque key that will be passed back into + beforeHandler() and afterHandler() to identify the source + of the calls + */ + virtual uintptr_t registerHandler(const AttachPointMetaData& mdata) = 0; + + /** + Function to be called before the handler is called. + + @key uintptr_t returned from registerHandler() when handler + was registered with the tool + */ + virtual void beforeHandler(uintptr_t key) = 0; + + /** + Function to be called after the handler is called. The key + passed in is the uintptr_t returned from registerHandler() + + @param key uintptr_t returned from registerHandler() when + handler was registered with the tool + */ + virtual void afterHandler(uintptr_t key) = 0; + }; + +private: + using ToolList = std::vector>; + ToolList* attached_tools = nullptr; + +protected: + // Implementation of operator() to be done in child classes + virtual void operator_impl() = 0; + +public: + virtual ~SSTHandlerBase() {} + + inline void operator()() + { + if ( attached_tools ) { + for ( auto& x : *attached_tools ) + x.first->beforeHandler(x.second); + + operator_impl(); + + for ( auto& x : *attached_tools ) + x.first->afterHandler(x.second); + + return; + } + return operator_impl(); + } + + /** + Attaches a tool to the AttachPoint + + @param tool Tool to attach + + @param mdata Metadata to pass to the tool + */ + void attachTool(AttachPoint* tool, const AttachPointMetaData& mdata) + { + if ( !attached_tools ) attached_tools = new ToolList(); + + auto key = tool->registerHandler(mdata); + attached_tools->push_back(std::make_pair(tool, key)); + } + + /** + Transfers attached tools from existing handler + */ + void transferAttachedToolInfo(SSTHandlerBase* handler) + { + if ( handler->attached_tools ) { + attached_tools = handler->attached_tools; + handler->attached_tools = nullptr; + } + } + +private: ImplementVirtualSerializable(SSTHandlerBase) }; -/************************************** +/********************************************************************** * Legacy Handlers - **************************************/ + * + * These handlers do not support checkpointing and will be removed in + * SST 15. + **********************************************************************/ +template +using SSTHandlerBaseNoArgs = SSTHandlerBase; /** * Handler class with user-data argument */ @@ -332,68 +703,6 @@ class SSTHandler : public SSTHandlerBase -class SSTHandlerBaseNoArgs : public SSTHandlerBaseProfile -{ - -protected: - virtual returnT operator_impl() = 0; - -public: - SSTHandlerBaseNoArgs() {} - - /** Handler function */ - virtual ~SSTHandlerBaseNoArgs() {} - - inline returnT operator()() - { - if ( profile_tools ) { - if constexpr ( std::is_void_v ) { - profile_tools->handlerStart(); - operator_impl(); - profile_tools->handlerEnd(); - return; - } - else { - profile_tools->handlerStart(); - auto ret = operator_impl(); - profile_tools->handlerEnd(); - return ret; - } - } - return operator_impl(); - } - ImplementVirtualSerializable(SSTHandlerBaseNoArgs) -}; - - -template <> -class SSTHandlerBaseNoArgs : public SSTHandlerBaseProfile -{ - -protected: - virtual void operator_impl() = 0; - -public: - SSTHandlerBaseNoArgs() {} - - /** Handler function */ - virtual ~SSTHandlerBaseNoArgs() {} - - inline void operator()() - { - if ( profile_tools ) { - profile_tools->handlerStart(); - operator_impl(); - profile_tools->handlerEnd(); - return; - } - return operator_impl(); - } - - ImplementVirtualSerializable(SSTHandlerNoArgs) -}; /** * Event Handler class with user-data argument @@ -414,7 +723,7 @@ class SSTHandlerNoArgs : public SSTHandlerBaseNoArgs * @param data - Additional argument to pass to handler */ SSTHandlerNoArgs(classT* const object, PtrMember member, dataT data) : - SSTHandlerBaseNoArgs(), + SSTHandlerBase(), object(object), member(member), data(data) @@ -443,7 +752,7 @@ class SSTHandlerNoArgs : public SSTHandlerBaseNoArgs(), + SSTHandlerBase(), member(member), object(object) {} @@ -454,9 +763,11 @@ class SSTHandlerNoArgs : public SSTHandlerBaseNoArgs { - // This has to be dependent on a tenplate, otherwise it always + // This has to be dependent on a template, otherwise it always // assers. Need to make sure it covers both cases to assert // if this template is expanded. static_assert(std::is_fundamental::value, "Mismatched handler templates."); @@ -479,8 +790,6 @@ class SSTHandler2 : public SSTHandlerBase */ template class SSTHandler2 : public SSTHandlerBase -// template -// class SSTHandler2 : public SSTHandlerBase { private: classT* object; @@ -596,36 +905,6 @@ class SSTHandler2 : public SSTHandlerBase -class SSTHandlerNoArgs : public SSTHandlerBaseNoArgs -{ -private: - typedef returnT (classT::*PtrMember)(); - const PtrMember member; - classT* object; - -public: - /** Constructor - * @param object - Pointer to Object upon which to call the handler - * @param member - Member function to call as the handler - */ - SSTHandlerNoArgs(classT* const object, PtrMember member) : - SSTHandlerBaseNoArgs(), - member(member), - object(object) - {} - - void operator_impl() override { return (object->*member)(); } - - NotSerializable(SSTHandlerNoArgs) -}; -#endif - } // namespace SST #endif // SST_CORE_SSTHANDLER_H diff --git a/tests/Makefile.inc b/tests/Makefile.inc index 193f6a738..1d53a3a3d 100644 --- a/tests/Makefile.inc +++ b/tests/Makefile.inc @@ -11,6 +11,7 @@ EXTRA_DIST += \ tests/testsuite_default_Output.py \ tests/testsuite_default_ParamComponent.py \ tests/testsuite_default_PerfComponent.py \ + tests/testsuite_default_profiling.py \ tests/testsuite_default_RNGComponent.py \ tests/testsuite_default_RealTime.py \ tests/testsuite_default_SharedObject.py \ @@ -61,6 +62,10 @@ EXTRA_DIST += \ tests/refFiles/test_Output_TraceFunction.out \ tests/refFiles/test_Output_TraceFunction_IndentMarker.out \ tests/refFiles/test_ParamComponent.out \ + tests/refFiles/test_Profiling_event_global.out \ + tests/refFiles/test_Profiling_event_type.out \ + tests/refFiles/test_Profiling_event_component.out \ + tests/refFiles/test_Profiling_event_subcomponent.out \ tests/refFiles/test_MessageGeneratorComponent.out \ tests/refFiles/test_MemPool_overflow.out \ tests/refFiles/test_MemPool_undeleted_items.out \ diff --git a/tests/refFiles/test_Profiling_event_component.out b/tests/refFiles/test_Profiling_event_component.out new file mode 100644 index 000000000..7593473d3 --- /dev/null +++ b/tests/refFiles/test_Profiling_event_component.out @@ -0,0 +1,44 @@ +15 received 39587 messages +14 received 39778 messages +13 received 40293 messages +12 received 40349 messages +11 received 39780 messages +10 received 40013 messages +9 received 40303 messages +8 received 40432 messages +7 received 39715 messages +6 received 39834 messages +5 received 40182 messages +4 received 40600 messages +3 received 39372 messages +2 received 39561 messages +1 received 39952 messages +0 received 40185 messages + +------------------------------------------------------------ +Profiling Output: + +----------------------------- +Rank = 0, thread = 0: + +events +Name, recv count +component0, 40185 +component1, 39952 +component10, 40013 +component11, 39780 +component12, 40349 +component13, 40293 +component14, 39778 +component15, 39587 +component2, 39561 +component3, 39372 +component4, 40600 +component5, 40182 +component6, 39834 +component7, 39715 +component8, 40432 +component9, 40303 + +------------------------------------------------------------ +Simulation is complete, simulated time: 10 us diff --git a/tests/refFiles/test_Profiling_event_global.out b/tests/refFiles/test_Profiling_event_global.out new file mode 100644 index 000000000..e4bc75762 --- /dev/null +++ b/tests/refFiles/test_Profiling_event_global.out @@ -0,0 +1,29 @@ +15 received 39587 messages +14 received 39778 messages +13 received 40293 messages +12 received 40349 messages +11 received 39780 messages +10 received 40013 messages +9 received 40303 messages +8 received 40432 messages +7 received 39715 messages +6 received 39834 messages +5 received 40182 messages +4 received 40600 messages +3 received 39372 messages +2 received 39561 messages +1 received 39952 messages +0 received 40185 messages + +------------------------------------------------------------ +Profiling Output: + +----------------------------- +Rank = 0, thread = 0: + +events +Name, recv count +global, 639936 + +------------------------------------------------------------ +Simulation is complete, simulated time: 10 us diff --git a/tests/refFiles/test_Profiling_event_subcomponent.out b/tests/refFiles/test_Profiling_event_subcomponent.out new file mode 100644 index 000000000..e1539e57d --- /dev/null +++ b/tests/refFiles/test_Profiling_event_subcomponent.out @@ -0,0 +1,92 @@ +15 received 39587 messages +14 received 39778 messages +13 received 40293 messages +12 received 40349 messages +11 received 39780 messages +10 received 40013 messages +9 received 40303 messages +8 received 40432 messages +7 received 39715 messages +6 received 39834 messages +5 received 40182 messages +4 received 40600 messages +3 received 39372 messages +2 received 39561 messages +1 received 39952 messages +0 received 40185 messages + +------------------------------------------------------------ +Profiling Output: + +----------------------------- +Rank = 0, thread = 0: + +events +Name, recv count +component0:ports[0], 9908 +component0:ports[1], 9888 +component0:ports[2]:port, 10280 +component0:ports[3]:port, 10109 +component10:ports[0], 9981 +component10:ports[1], 10137 +component10:ports[2]:port, 9962 +component10:ports[3]:port, 9933 +component11:ports[0], 10082 +component11:ports[1], 9970 +component11:ports[2]:port, 9773 +component11:ports[3]:port, 9955 +component12:ports[0], 10184 +component12:ports[1], 10030 +component12:ports[2]:port, 10083 +component12:ports[3]:port, 10052 +component13:ports[0], 9893 +component13:ports[1], 10086 +component13:ports[2]:port, 10209 +component13:ports[3]:port, 10105 +component14:ports[0], 9881 +component14:ports[1], 10025 +component14:ports[2]:port, 9868 +component14:ports[3]:port, 10004 +component15:ports[0], 9948 +component15:ports[1], 9999 +component15:ports[2]:port, 9850 +component15:ports[3]:port, 9790 +component1:ports[0], 9848 +component1:ports[1], 10180 +component1:ports[2]:port, 9865 +component1:ports[3]:port, 10059 +component2:ports[0], 9833 +component2:ports[1], 9902 +component2:ports[2]:port, 9903 +component2:ports[3]:port, 9923 +component3:ports[0], 9877 +component3:ports[1], 9769 +component3:ports[2]:port, 9824 +component3:ports[3]:port, 9902 +component4:ports[0], 10287 +component4:ports[1], 10108 +component4:ports[2]:port, 10161 +component4:ports[3]:port, 10044 +component5:ports[0], 9941 +component5:ports[1], 10313 +component5:ports[2]:port, 9993 +component5:ports[3]:port, 9935 +component6:ports[0], 9829 +component6:ports[1], 10042 +component6:ports[2]:port, 9884 +component6:ports[3]:port, 10079 +component7:ports[0], 9903 +component7:ports[1], 10058 +component7:ports[2]:port, 9952 +component7:ports[3]:port, 9802 +component8:ports[0], 10068 +component8:ports[1], 10054 +component8:ports[2]:port, 10204 +component8:ports[3]:port, 10106 +component9:ports[0], 10155 +component9:ports[1], 10139 +component9:ports[2]:port, 10025 +component9:ports[3]:port, 9984 + +------------------------------------------------------------ +Simulation is complete, simulated time: 10 us diff --git a/tests/refFiles/test_Profiling_event_type.out b/tests/refFiles/test_Profiling_event_type.out new file mode 100644 index 000000000..0ae199d24 --- /dev/null +++ b/tests/refFiles/test_Profiling_event_type.out @@ -0,0 +1,29 @@ +15 received 39587 messages +14 received 39778 messages +13 received 40293 messages +12 received 40349 messages +11 received 39780 messages +10 received 40013 messages +9 received 40303 messages +8 received 40432 messages +7 received 39715 messages +6 received 39834 messages +5 received 40182 messages +4 received 40600 messages +3 received 39372 messages +2 received 39561 messages +1 received 39952 messages +0 received 40185 messages + +------------------------------------------------------------ +Profiling Output: + +----------------------------- +Rank = 0, thread = 0: + +events +Name, recv count +coreTestElement.message_mesh.message_port, 639936 + +------------------------------------------------------------ +Simulation is complete, simulated time: 10 us diff --git a/tests/testsuite_default_profiling.py b/tests/testsuite_default_profiling.py new file mode 100644 index 000000000..7b4b65876 --- /dev/null +++ b/tests/testsuite_default_profiling.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2009-2024 NTESS. Under the terms +# of Contract DE-NA0003525 with NTESS, the U.S. +# Government retains certain rights in this software. +# +# Copyright (c) 2009-2024, 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. + +import os +import sys + +from sst_unittest import * +from sst_unittest_support import * + + +class testcase_Profiling(SSTTestCase): + + def setUp(self): + super(type(self), self).setUp() + # Put test based setup code here. it is called once before every test + + def tearDown(self): + # Put test based teardown code here. it is called once after every test + super(type(self), self).tearDown() + +### + + parallelerr = "Test only suports serial execution" + + @unittest.skipIf(testing_check_get_num_ranks() > 1, parallelerr) + @unittest.skipIf(testing_check_get_num_threads() > 1, parallelerr) + def test_event_global(self): + self.profiling_test_template("event_global", "events:sst.profile.handler.event.count(level=global)[event]") + + @unittest.skipIf(testing_check_get_num_ranks() > 1, parallelerr) + @unittest.skipIf(testing_check_get_num_threads() > 1, parallelerr) + def test_event_component(self): + self.profiling_test_template("event_component", "events:sst.profile.handler.event.count(level=component)[event]") + + @unittest.skipIf(testing_check_get_num_ranks() > 1, parallelerr) + @unittest.skipIf(testing_check_get_num_threads() > 1, parallelerr) + def test_event_subcomponent(self): + self.profiling_test_template("event_subcomponent", "events:sst.profile.handler.event.count(level=subcomponent)[event]") + + @unittest.skipIf(testing_check_get_num_ranks() > 1, parallelerr) + @unittest.skipIf(testing_check_get_num_threads() > 1, parallelerr) + def test_event_type(self): + self.profiling_test_template("event_type", "events:sst.profile.handler.event.count(level=type)[event]") + + +##### + + def profiling_test_template(self, testtype, profile_options): + testsuitedir = self.get_testsuite_dir() + outdir = test_output_get_run_dir() + + options = "--model-options=\"4 4\" --enable-profiling=\"{0}\"".format(profile_options); + + # Set the various file paths + sdlfile = "{0}/test_MessageMesh.py".format(testsuitedir) + reffile = "{0}/refFiles/test_Profiling_{1}.out".format(testsuitedir, testtype) + outfile = "{0}/test_Profiling_{1}.out".format(outdir, testtype) + + self.run_sst(sdlfile, outfile, other_args=options) + + # Perform the test + cmp_result = testing_compare_sorted_diff(testtype, outfile, reffile) + self.assertTrue(cmp_result, "Output/Compare file {0} does not match Reference File {1}".format(outfile, reffile)) From 6775737a16131a72214c7f1ab145108ea818530a Mon Sep 17 00:00:00 2001 From: Eric Berquist <727571+berquist@users.noreply.github.com> Date: Fri, 20 Dec 2024 14:22:40 -0500 Subject: [PATCH 2/3] test_engine.py: add type annotations (#1187) --- src/sst/core/testingframework/test_engine.py | 29 ++++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/sst/core/testingframework/test_engine.py b/src/sst/core/testingframework/test_engine.py index b3e3fbe57..b9ed6c1d4 100644 --- a/src/sst/core/testingframework/test_engine.py +++ b/src/sst/core/testingframework/test_engine.py @@ -22,12 +22,14 @@ import argparse import shutil import configparser -from typing import Any, Dict, List +import multiprocessing +from typing import Any, Dict, List, Union import test_engine_globals from sst_unittest import * from sst_unittest_support import * from test_engine_unittest import * +from test_engine_support import OSCommand ################################################################################ @@ -120,10 +122,10 @@ def __init__(self, sst_core_bin_dir: str, test_mode: int) -> None: self._fail_fast = False self._keep_output_dir = False self._list_discovered_testsuites_mode = False - self._list_of_searchable_testsuite_paths = [] - self._list_of_specific_testnames = [] - self._testsuite_types_list = [] - self._testsuite_wildcards_list = [] + self._list_of_searchable_testsuite_paths: List[str] = [] + self._list_of_specific_testnames: List[str] = [] + self._testsuite_types_list: List[str] = [] + self._testsuite_wildcards_list: List[str] = [] self._sst_core_bin_dir = sst_core_bin_dir self._test_mode = test_mode self._sst_full_test_suite = unittest.TestSuite() @@ -204,7 +206,7 @@ def _build_tests_list_helper(self, suite: SSTTestSuite) -> List[Any]: Args: suite (SSTTestSuite): The suites to be split up. """ - tests = list(iterate_tests(suite)) + tests = list(iterate_tests(suite)) # type: ignore [name-defined] return tests ################################################################################ @@ -297,7 +299,7 @@ def _parse_arguments(self) -> None: #### - def _decode_parsed_arguments(self, args, parser): + def _decode_parsed_arguments(self, args: argparse.Namespace, parser: argparse.ArgumentParser) -> None: """ Decode the parsed arguments into their class or global variables. Args: @@ -720,7 +722,13 @@ def _create_output_dir(self, out_dir: str) -> bool: #### - def _dump_testsuite_list(self, suite, log_normal=False, show_suites=False, iterlevel=0): + def _dump_testsuite_list( + self, + suite: Union[unittest.TestSuite, unittest.TestCase], + log_normal: bool = False, + show_suites: bool = False, + iterlevel: int = 0, + ) -> None: """ Recursively log all tests in a TestSuite. Args: @@ -744,7 +752,10 @@ def _dump_testsuite_list(self, suite, log_normal=False, show_suites=False, iterl #### - def _prune_unwanted_tests(self, suite): + def _prune_unwanted_tests( + self, + suite: Union[unittest.TestSuite, unittest.TestCase], + ) -> unittest.TestSuite: """ Recursively remove any tests that dont match the name Args: From 357aa440be377abb8d01b657a7dc66c8e3c23acf Mon Sep 17 00:00:00 2001 From: Scott Hemmert Date: Fri, 20 Dec 2024 13:55:38 -0700 Subject: [PATCH 3/3] Added missing attachInterceptTool() call to SSTHandlerBase. Also added printf in sst_exit to suppress unused variable warning. (#1188) --- src/sst/core/simulation.cc | 4 +++- src/sst/core/ssthandler.h | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/sst/core/simulation.cc b/src/sst/core/simulation.cc index 0da7e5f76..552cf021a 100644 --- a/src/sst/core/simulation.cc +++ b/src/sst/core/simulation.cc @@ -2088,7 +2088,9 @@ SST_Exit(int exit_code) static int exit_once = (exit(exit_code), 0); #endif - // Should never get here + // Should never get here, but need to use exit_once to avoid + // compiler warning + printf("exit_once = %d\n", exit_once); std::terminate(); } diff --git a/src/sst/core/ssthandler.h b/src/sst/core/ssthandler.h index 3e9125ebf..0ef2c8780 100644 --- a/src/sst/core/ssthandler.h +++ b/src/sst/core/ssthandler.h @@ -388,6 +388,21 @@ class SSTHandlerBase : public SST::Core::Serialization::serializable attached_tools->attach_tools.push_back(std::make_pair(tool, key)); } + /** + Attaches a tool to the AttachPoint + + @param tool Tool to attach + + @param mdata Metadata to pass to the tool + */ + void attachInterceptTool(InterceptPoint* tool, const AttachPointMetaData& mdata) + { + if ( !attached_tools ) attached_tools = new ToolList(); + + auto key = tool->registerHandlerIntercept(mdata); + attached_tools->intercept_tools.push_back(std::make_pair(tool, key)); + } + /** Transfers attached tools from existing handler */