diff --git a/src/sst/core/Makefile.am b/src/sst/core/Makefile.am index 3114200af..de095c549 100644 --- a/src/sst/core/Makefile.am +++ b/src/sst/core/Makefile.am @@ -94,6 +94,7 @@ nobase_dist_sst_HEADERS = \ serialization/serializable_base.h \ serialization/serialize.h \ serialization/serialize_impl_fwd.h \ + serialization/objectMap.h \ serialization/impl/serialize_array.h \ serialization/impl/serialize_atomic.h \ serialization/impl/ser_buffer_accessor.h \ @@ -101,6 +102,7 @@ nobase_dist_sst_HEADERS = \ serialization/impl/serialize_list.h \ serialization/impl/serialize_map.h \ serialization/impl/serialize_multiset.h \ + serialization/impl/mapper.h \ serialization/impl/packer.h \ serialization/impl/serialize_priority_queue.h \ serialization/impl/serialize_set.h \ @@ -213,6 +215,7 @@ sst_core_sources = \ ssthandler.cc \ sstpart.cc \ timeVortex.cc \ + serialization/objectMap.cc \ serialization/serializable_base.cc \ serialization/serializable.cc \ serialization/serializer.cc \ diff --git a/src/sst/core/baseComponent.cc b/src/sst/core/baseComponent.cc index 1c3680443..262517757 100644 --- a/src/sst/core/baseComponent.cc +++ b/src/sst/core/baseComponent.cc @@ -28,6 +28,7 @@ #include "sst/core/timeLord.h" #include "sst/core/unitAlgebra.h" #include "sst/core/warnmacros.h" +#include "sst/core/serialization/serialize.h" #include @@ -853,6 +854,9 @@ BaseComponent::serialize_order(SST::Core::Serialization::serializer& ser) } break; } + case SST::Core::Serialization::serializer::MAP: + // Add your code here + break; } } @@ -863,7 +867,7 @@ namespace pvt { static const long null_ptr_id = -1; void -size_basecomponent(serializable_base* s, serializer& ser) +SerializeBaseComponentHelper::size_basecomponent(serializable_base* s, serializer& ser) { long dummy = 0; ser.size(dummy); @@ -871,7 +875,7 @@ size_basecomponent(serializable_base* s, serializer& ser) } void -pack_basecomponent(serializable_base* s, serializer& ser) +SerializeBaseComponentHelper::pack_basecomponent(serializable_base* s, serializer& ser) { if ( s ) { long cls_id = s->cls_id(); @@ -885,7 +889,7 @@ pack_basecomponent(serializable_base* s, serializer& ser) } void -unpack_basecomponent(serializable_base*& s, serializer& ser) +SerializeBaseComponentHelper::unpack_basecomponent(serializable_base*& s, serializer& ser) { long cls_id; ser.unpack(cls_id); @@ -897,6 +901,36 @@ unpack_basecomponent(serializable_base*& s, serializer& ser) } } +void +SerializeBaseComponentHelper::map_basecomponent(serializable_base*& s, serializer& ser, const char* name) +{ + if ( s ) { + BaseComponent* comp = static_cast(s); + ObjectMapClass* obj_map = new ObjectMapClass(s, s->cls_name()); + ser.report_object_map(obj_map); + ser.mapper().map_hierarchy_start(name, obj_map); + + // Put in any subcomponents first + for ( auto it = comp->my_info->subComponents.begin(); it != comp->my_info->subComponents.end(); ++it ) { + sst_map_object(ser, it->second.component, it->second.getShortName().c_str()); + it->second.serialize_comp(ser); + } + + // Put in ComponentInfo data + ObjectMap* my_info_dir = new ObjectMapHierarchyOnly(); + ser.mapper().map_hierarchy_start("my_info", my_info_dir); + ser.mapper().setNextObjectReadOnly(); + sst_map_object(ser, const_cast(comp->my_info->id), "id"); + ser.mapper().setNextObjectReadOnly(); + sst_map_object(ser, const_cast(comp->my_info->type), "type"); + sst_map_object(ser, comp->my_info->defaultTimeBase, "defaultTimeBase"); + ser.mapper().map_hierarchy_end(); // for my_info_dir + + s->serialize_order(ser); + ser.mapper().map_hierarchy_end(); // obj_map + } +} + } // namespace pvt } // namespace Serialization } // namespace Core diff --git a/src/sst/core/baseComponent.h b/src/sst/core/baseComponent.h index d67b25a1b..9e034b871 100644 --- a/src/sst/core/baseComponent.h +++ b/src/sst/core/baseComponent.h @@ -47,6 +47,15 @@ class SubComponentSlotInfo; class TimeConverter; class UnitAlgebra; + +namespace Core { +namespace Serialization { +namespace pvt { +class SerializeBaseComponentHelper; +} // namespace pvt +} // namespace Serialization +} // namespace Core + /** * Main component object for the simulation. */ @@ -878,6 +887,9 @@ class BaseComponent : public SST::Core::Serialization::serializable_base std::vector getComponentProfileTools(const std::string& point); private: + friend class Core::Serialization::pvt::SerializeBaseComponentHelper; + + ComponentInfo* my_info = nullptr; Simulation_impl* sim_ = nullptr; bool isExtension = false; @@ -1094,13 +1106,21 @@ namespace Serialization { namespace pvt { -void size_basecomponent(serializable_base* s, serializer& ser); +class SerializeBaseComponentHelper +{ +public: + static void size_basecomponent(serializable_base* s, serializer& ser); + + static void pack_basecomponent(serializable_base* s, serializer& ser); -void pack_basecomponent(serializable_base* s, serializer& ser); + static void unpack_basecomponent(serializable_base*& s, serializer& ser); -void unpack_basecomponent(serializable_base*& s, serializer& ser); + static void map_basecomponent(serializable_base*& s, serializer& ser, const char* name); +}; + } // namespace pvt + template class serialize_impl::value>::type> { @@ -1111,17 +1131,26 @@ class serialize_impl(s); switch ( ser.mode() ) { case serializer::SIZER: - pvt::size_basecomponent(sp, ser); + pvt::SerializeBaseComponentHelper::size_basecomponent(sp, ser); break; case serializer::PACK: - pvt::pack_basecomponent(sp, ser); + pvt::SerializeBaseComponentHelper::pack_basecomponent(sp, ser); break; case serializer::UNPACK: - pvt::unpack_basecomponent(sp, ser); + pvt::SerializeBaseComponentHelper::unpack_basecomponent(sp, ser); + break; + case serializer::MAP: + // Add your code here break; } s = static_cast(sp); } + + void operator()(T*& s, serializer& ser, const char* name) + { + serializable_base* sp = static_cast(s); + pvt::SerializeBaseComponentHelper::map_basecomponent(sp, ser, name); + } }; } // namespace Serialization diff --git a/src/sst/core/componentInfo.cc b/src/sst/core/componentInfo.cc index 5c0cf32e6..59ef16c6f 100644 --- a/src/sst/core/componentInfo.cc +++ b/src/sst/core/componentInfo.cc @@ -267,6 +267,9 @@ ComponentInfo::serialize_order(SST::Core::Serialization::serializer& ser) } break; } + case SST::Core::Serialization::serializer::MAP: + // Add your code here + break; } // Only the parent Component will call serialize_comp directly. diff --git a/src/sst/core/componentInfo.h b/src/sst/core/componentInfo.h index d9280b1a2..e4e60d9fc 100644 --- a/src/sst/core/componentInfo.h +++ b/src/sst/core/componentInfo.h @@ -33,6 +33,14 @@ class ConfigStatistic; class Simulation_impl; class TimeConverter; +namespace Core { +namespace Serialization { +namespace pvt { +class SerializeBaseComponentHelper; +} // namespace pvt +} // namespace Serialization +} // namespace Core + class ComponentInfo { @@ -55,6 +63,7 @@ class ComponentInfo friend class Simulation_impl; friend class BaseComponent; friend class ComponentInfoMap; + friend class Core::Serialization::pvt::SerializeBaseComponentHelper; /** Component ID. @@ -204,6 +213,12 @@ class ComponentInfo return real_comp->getName(); } + /** + Get the short name for this SubComponent (name not including + any parents, so just slot_name[index]) + */ + inline std::string getShortName() const { return name.substr(name.find_last_of(':')+1); } + inline const std::string& getSlotName() const { return slot_name; } inline int getSlotNum() const { return slot_num; } diff --git a/src/sst/core/interfaces/TestEvent.h b/src/sst/core/interfaces/TestEvent.h index a1923bd02..ddd3ccbeb 100644 --- a/src/sst/core/interfaces/TestEvent.h +++ b/src/sst/core/interfaces/TestEvent.h @@ -20,7 +20,7 @@ namespace Interfaces { /** Test Event * Useful for early-testing of components. */ -class TestEvent : public SST::Event, public SST::Core::Serialization::serializable_type +class TestEvent : public SST::Event { public: TestEvent(); diff --git a/src/sst/core/interfaces/simpleNetwork.h b/src/sst/core/interfaces/simpleNetwork.h index 948a00acd..d96505487 100644 --- a/src/sst/core/interfaces/simpleNetwork.h +++ b/src/sst/core/interfaces/simpleNetwork.h @@ -49,7 +49,7 @@ class SimpleNetwork : public SubComponent /** * Represents both network sends and receives */ - class Request : public SST::Core::Serialization::serializable, SST::Core::Serialization::serializable_type + class Request : public SST::Core::Serialization::serializable { public: diff --git a/src/sst/core/link.cc b/src/sst/core/link.cc index 32b35bde7..904bdc340 100644 --- a/src/sst/core/link.cc +++ b/src/sst/core/link.cc @@ -114,8 +114,9 @@ SST::Core::Serialization::serialize_impl::operator()(Link*& s, SST::Core: // If I'm a polling link, I need to serialize my // pair's send_queue. For HANDLER and SYNC links, the // send_queue will be reinitialized after restart - PollingLinkQueue* queue = dynamic_cast(s->pair_link->send_queue); - ser& queue; + // TODO: Fix PollingLinkQueue serialization + // PollingLinkQueue* queue = dynamic_cast(s->pair_link->send_queue); + // ser& queue; } // My delivery_info is stored in my pair_link. @@ -232,9 +233,10 @@ SST::Core::Serialization::serialize_impl::operator()(Link*& s, SST::Core: // pair's send_queue. For now, I will store it in my // own send_queue variable and swap once we have both // links. - PollingLinkQueue* queue; - ser& queue; - s->send_queue = queue; + // TODO - Fix PollingLinkQueue serialization + // PollingLinkQueue* queue; + // ser& queue; + // s->send_queue = queue; } else { s->send_queue = Simulation_impl::getSimulation()->getTimeVortex(); @@ -276,9 +278,17 @@ SST::Core::Serialization::serialize_impl::operator()(Link*& s, SST::Core: // ser & s->profile_tools; } break; + case serializer::MAP: + // Add your code here + break; } } +void +SST::Core::Serialization::serialize_impl::operator()(Link*& s, SST::Core::Serialization::serializer& ser, const char* name) +{ + // TODO: Implement Link mapping mode +} /** * Null Event. Used when nullptr is passed into any of the send diff --git a/src/sst/core/link.h b/src/sst/core/link.h index 9c0ea0530..ae82fd140 100644 --- a/src/sst/core/link.h +++ b/src/sst/core/link.h @@ -43,6 +43,7 @@ class SST::Core::Serialization::serialize_impl friend class serialize; // Function implemented in link.cc void operator()(Link*& s, SST::Core::Serialization::serializer& ser); + void operator()(Link*& s, SST::Core::Serialization::serializer& ser, const char* name); }; diff --git a/src/sst/core/main.cc b/src/sst/core/main.cc index 5486e0c5e..2236d4eac 100644 --- a/src/sst/core/main.cc +++ b/src/sst/core/main.cc @@ -71,6 +71,250 @@ using namespace SST::Partition; using namespace std; using namespace SST; +// Object to walk the ObjectMap hierarchy +#include "sst/core/from_string.h" + +class ObjectExplorer +{ + SST::Core::Serialization::ObjectMap* obj_; + bool done = false; + + std::vector tokenize(std::vector& tokens, const std::string& input) + { + std::istringstream iss(input); + std::string token; + + while (iss >> token) { + tokens.push_back(token); + } + + return tokens; + } + + void pwd(std::vector& UNUSED(tokens)) { + // std::string path = obj_->getName(); + // std::string slash("/"); + // // path = slash + path; + // SST::Core::Serialization::ObjectMap* curr = obj_->getParent(); + // while ( curr != nullptr ) { + // path = curr->getName() + slash + path; + // curr = curr->getParent(); + // } + + printf("%s (%s)\n",obj_->getFullName().c_str(), obj_->getType().c_str()); + } + + void ls(std::vector& UNUSED(tokens)) { + // if ( obj_->isContainer() ) { + // printf("Object is vector of size: %zu\n", obj_->num_vars()); + // return; + // } + + std::vector> vars = obj_->getVariables(); + for ( auto& x : vars ) { + if ( x.second->isFundamental() ) { + printf("%s = %s (%s)\n", x.first.c_str(), x.second->get().c_str(), x.second->getType().c_str()); + } + else { + printf("%s/ (%s)\n", x.first.c_str(), x.second->getType().c_str()); + } + } + } + + void cd(std::vector& tokens) { + if ( tokens.size() != 2 ) { + printf("Invalid format for cd command (cd )\n"); + return; + } + + // Check for .. + if ( tokens[1] == ".." ) { + auto* parent = obj_->selectParent(); + if ( parent == nullptr ) { + printf("Already at top of object hierarchy\n"); + return; + } + obj_ = parent; + return; + } + + fflush(stdout); + SST::Core::Serialization::ObjectMap* new_obj = obj_->selectVariable(tokens[1]); + fflush(stdout); + + if ( !new_obj ) { + printf("Unknown object in cd command: %s\n", tokens[1].c_str()); + return; + } + + if ( new_obj->isFundamental() ) { + printf("Object %s is a fundamental type so you cannot cd into it\n", tokens[1].c_str()); + new_obj->selectParent(); + return; + } + + obj_ = new_obj; + } + + void print(std::vector& tokens) { + // Index in tokens array where we may find the variable name + size_t var_index = 1; + + // See if have a -r or not + int recurse = 0; + std::string tok = tokens[1]; + if (tok.size() >= 2 && tok[0] == '-' && tok[1] == 'r') { + // Got a -r + std::string num = tok.substr(2); + if ( num.size() != 0 ) { + try { + recurse = from_string(num); + } + catch ( std::invalid_argument& e ) { + printf("Invalid number format specified with -r: %s\n", tok.c_str()); + return; + } + } + else { + recurse = 4; // default -r depth + } + + var_index = 2; + } + + if ( tokens.size() == var_index ) { + // Print current object + obj_->print(recurse); + return; + } + + if ( tokens.size() != (var_index + 1) ) { + printf("Invalid format for print command (print [-rN] [])\n"); + return; + } + + bool found = obj_->printVariable(tokens[var_index], recurse); + if ( !found ) { + printf("Unknown object in print command: %s\n", tokens[1].c_str()); + return; + } + + // // if ( obj_->isContainer() ) { + // // printf("%s\n", obj_->get(tokens[1]).c_str()); + // // return; + // // } + + // auto* var = obj_->selectVariable(tokens[1]); + // if ( !var ) { + // printf("Unknown object in print command: %s\n", tokens[1].c_str()); + // return; + // } + + // if ( !var->isFundamental() ) { + // var->print(); + // // printf("Invalid object in print command: %s is not a fundamental type\n", tokens[1].c_str()); + // var->selectParent(); + // return; + // } + // printf("%s\n", var->get().c_str()); + // var->selectParent(); + } + + + void set(std::vector& tokens) { + if ( tokens.size() != 3 ) { + printf("Invalid format for set command (set )\n"); + return; + } + + if ( obj_->isContainer() ) { + bool found = false; + bool read_only = false; + obj_->set(tokens[1], tokens[2], found, read_only); + if ( !found ) printf("Unknown object in set command: %s\n", tokens[1].c_str()); + if ( read_only ) printf("Object specified in set command is read-only: %s\n", tokens[1].c_str()); + return; + } + + auto* var = obj_->selectVariable(tokens[1]); + if ( !var ) { + printf("Unknown object in set command: %s\n", tokens[1].c_str()); + return; + } + + if ( var->isReadOnly() ) { + printf("Object specified in set command is read-only: %s\n", tokens[1].c_str()); + var->selectParent(); + return; + } + + if ( !var->isFundamental() ) { + printf("Invalid object in set command: %s is not a fundamental type\n", tokens[1].c_str()); + var->selectParent(); + return; + } + + try { + var->set(tokens[2]); + } + catch (exception& e) { + printf("Invalid format: %s\n", tokens[2].c_str()); + } + var->selectParent(); + } + + + void dispatch_cmd(std::string cmd) + { + std::vector tokens; + tokenize(tokens, cmd); + + if ( tokens[0] == "exit" || tokens[0] == "quit" ) { + printf("Exiting ObjectExplorer\n"); + done = true; + } + else if ( tokens[0] == "pwd" ) { + pwd(tokens); + } + else if ( tokens[0] == "ls" ) { + ls(tokens); + } + else if ( tokens[0] == "cd" ) { + cd(tokens); + } + else if ( tokens[0] == "print" ) { + print(tokens); + } + else if ( tokens[0] == "set" ) { + set(tokens); + } + else { + printf("Unknown command: %s\n", tokens[0].c_str()); + } + } + +public: + ObjectExplorer(SST::Core::Serialization::ObjectMap* obj) : + obj_(obj) + { + } + + void explore() + { + printf("Exploring object: %s\n", obj_->getName().c_str()); + done = false; + + std::string line; + while ( !done ) { + printf("> "); + std::getline(std::cin,line); + dispatch_cmd(line); + } + } +}; + + + static SST::Output g_output; @@ -577,6 +821,12 @@ start_simulation(uint32_t tid, SimThreadInfo_t& info, Core::ThreadSafe::Barrier& info.build_time = start_run - start_build; } + // DEMO: Before run, get the object map and run the object explorer + SST::Core::Serialization::ObjectMap* obj_map = sim->getComponentObjectMap(); + ObjectExplorer* ex = new ObjectExplorer(obj_map); + ex->explore(); + + /* Run Simulation */ if ( info.config->runMode() == SimulationRunMode::RUN || info.config->runMode() == SimulationRunMode::BOTH ) { sim->run(); @@ -656,9 +906,221 @@ start_simulation(uint32_t tid, SimThreadInfo_t& info, Core::ThreadSafe::Barrier& delete sim; } +///////////////////// +#include "sst/core/serialization/serializable.h" + +class MapSerTestBase : public SST::Core::Serialization::serializable +{ +public: + MapSerTestBase() : + SST::Core::Serialization::serializable() + {} + + virtual void print() = 0; + + void serialize_order(SST::Core::Serialization::serializer& UNUSED(ser)) override {} + + ImplementVirtualSerializable(MapSerTestBase) + +}; + +class MapSerTest : public MapSerTestBase +{ +public: + uint16_t ser1 = 0; + std::string ser2 = ""; + + MapSerTest() : + MapSerTestBase() + {} + + MapSerTest(uint16_t ser1, const std::string& ser2): + MapSerTestBase(), + ser1(ser1), + ser2(ser2) + { + } + + void print() override + { + printf(" ser1 = %" PRIu16 "\n", ser1); + printf(" ser2 = %s\n", ser2.c_str()); + } + + void serialize_order(SST::Core::Serialization::serializer& ser) override + { + MapSerTestBase::serialize_order(ser); + SST_SER(ser1); + SST_SER(ser2); + } + + ImplementSerializable(MapSerTest) +}; + +class MapTest; + +class MapSubTest { +public: + int sub1 = 0; + char sub2 = '0'; + std::string sub3; + float sub4; + MapSerTestBase* sub5 = nullptr; + MapTest* parent = nullptr; + + MapSubTest() + { + sub5 = new MapSerTest(79, "serializable"); + } + + void serialize_order(SST::Core::Serialization::serializer& ser) + { + SST_SER(sub1); + SST_SER(sub2); + SST_SER(sub3); + ser & sub4; + SST_SER(sub5); + SST_SER(parent); + // ser & sub5; + } + + void print() + { + printf(" sub1 = %d\n", sub1); + printf(" sub2 = %c\n", sub2); + printf(" sub3 = %s\n", sub3.c_str()); + printf(" sub4 = %f\n", sub4); + printf(" sub5:\n"); + sub5->print(); + + } +}; + +class MapTest { +public: + SimTime_t var1 = 0; + double var2 = 0.0; + UnitAlgebra unitalgebra; + MapSubTest subtest; + std::vector var3; + std::vector subtest_vec; + + MapTest() + { + unitalgebra.init("10GHz"); + subtest_vec.push_back(&subtest); + subtest.parent = this; + } + + void serialize_order(SST::Core::Serialization::serializer& ser) + { + SST_SER(var1); + SST_SER(var2); + SST_SER(unitalgebra); + SST_SER(subtest); + SST_SER(var3); + SST_SER(subtest_vec); + } + + void print() + { + printf("var1 = %" PRIu64 "\n", var1); + printf("var2 = %f\n", var2); + printf("subtest:\n"); + subtest.print(); + printf("var3:\n"); + for ( auto x : var3 ) printf(" %d\n", x); + } +}; + +// template +// struct etest { + +// void operator()(int a, T*& b, SST::Core::Serialization::serializer& c) {} +// // void foo() {printf("foo\n");} +// void bar() {printf("bar\n");} +// }; + + int main(int argc, char* argv[]) { + printf("%zu\n",sizeof(std::string)); + + MapTest map_test; + + SST::Core::Serialization::serializer ser; + SST::Core::Serialization::ObjectMap* obj_map = new SST::Core::Serialization::ObjectMapClass(); + ser.enable_pointer_tracking(); + ser.start_mapping(obj_map); + + + map_test.var1 = 5; + map_test.var2 = 10.1; + map_test.var3.push_back(2); + map_test.var3.push_back(4); + map_test.var3.push_back(6); + + map_test.subtest.sub1 = 15; + map_test.subtest.sub2 = 'd'; + map_test.subtest.sub3 = "hello"; + map_test.subtest.sub4 = 275.6; + + printf("Calling serializer in mapping mode:\n"); + sst_map_object(ser, map_test, "map_test"); + // map_test.serialize_order(ser); + + // auto& vars = obj_map->select("map_test")->getVariables(); + // printf("Variables mapped:\n"); + // for ( auto* x : vars ) { + // printf(" %s, %s\n", x->getName().c_str(), x->getType().c_str()); + // if ( !x->isFundamental() ) { + // for ( auto* y : x->getVariables() ) { + // printf(" %s, %s\n", y->getName().c_str(), y->getType().c_str()); + // } + // } + // } + printf("\n\n"); + + printf("Contents of map_test before running ObjectExplorer:\n"); + map_test.print(); + printf("\n\n"); + + printf("Starting ObjectExplorer:\n\n"); + ObjectExplorer* ex = new ObjectExplorer(obj_map); + ex->explore(); + + + printf("Contents of map_test after running ObjectExplorer:\n"); + map_test.print(); + + + printf("Serializing map_test...\n\n"); + char* buffer; + size_t size; + ser.start_sizing(); + map_test.serialize_order(ser); + + size = ser.size(); + buffer = new char[size]; + + ser.start_packing(buffer, size); + map_test.serialize_order(ser); + + MapTest maptest2; + printf("map_test2 (empty) before deserialization:\n"); + maptest2.print(); + printf("\n\n"); + ser.start_unpacking(buffer,size); + + maptest2.serialize_order(ser); + printf("map_test2 after deserialization:\n"); + maptest2.print(); + + // exit(1); + + + #ifdef SST_CONFIG_HAVE_MPI // Initialize MPI MPI_Init(&argc, &argv); diff --git a/src/sst/core/params.cc b/src/sst/core/params.cc index 1f82b4828..1dd50b84b 100644 --- a/src/sst/core/params.cc +++ b/src/sst/core/params.cc @@ -284,6 +284,9 @@ Params::serialize_order(SST::Core::Serialization::serializer& ser) for ( auto x : globals ) data.push_back(&global_params[x]); break; + case SST::Core::Serialization::serializer::MAP: + // Add your code here + break; } } diff --git a/src/sst/core/pollingLinkQueue.cc b/src/sst/core/pollingLinkQueue.cc index f6a12fcc4..9ae9bc253 100644 --- a/src/sst/core/pollingLinkQueue.cc +++ b/src/sst/core/pollingLinkQueue.cc @@ -84,6 +84,9 @@ PollingLinkQueue::serialize_order(SST::Core::Serialization::serializer& ser) data.insert(activity); } } + case SST::Core::Serialization::serializer::MAP: + // Add your code here + break; } } diff --git a/src/sst/core/serialization/impl/mapper.h b/src/sst/core/serialization/impl/mapper.h new file mode 100644 index 000000000..a45a2b237 --- /dev/null +++ b/src/sst/core/serialization/impl/mapper.h @@ -0,0 +1,120 @@ +// 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. + +#ifndef SST_CORE_SERIALIZATION_IMPL_MAPPER_H +#define SST_CORE_SERIALIZATION_IMPL_MAPPER_H + +#ifndef SST_INCLUDING_SERIALIZER_H +#warning \ + "The header file sst/core/serialization/impl/mapper.h should not be directly included as it is not part of the stable public API. The file is included in sst/core/serialization/serializer.h" +#endif + +#include "sst/core/serialization/objectMap.h" + +#include +#include +#include + +namespace SST { +namespace Core { +namespace Serialization { +namespace pvt { + +class ser_mapper +{ + std::vector obj_; + bool next_item_read_only = false; + +public: + // template + // void map_primitive(T& t, const char* name) + void map_primitive(const std::string& name, ObjectMap* map) + { + obj_.back()->addVariable(name, map); + if ( next_item_read_only ) { + next_item_read_only = false; + map->setReadOnly(); + } + } + + void map_container(const std::string& name, ObjectMap* map) + { + obj_.back()->addVariable(name, map); + for ( int i = 0; i < indent; ++i ) printf(" "); + printf("Mapping container %s (type = %s), at address %p\n", + map->getName().c_str(), ObjectMap::demangle_name(map->getType().c_str()).c_str(), map->getAddr()); + if ( next_item_read_only ) { + next_item_read_only = false; + } + } + + void map_existing_object(const std::string& name, ObjectMap* map) + { + obj_.back()->addVariable(name, map); + if ( next_item_read_only ) { + next_item_read_only = false; + } + } + + // template + // void map_hierarchy_start(T& t, const char* name) + void map_hierarchy_start(const std::string& name, ObjectMap* map) + { + obj_.back()->addVariable(name, map); + obj_.push_back(map); + + // printf("Mapping hierarchy %s (type = %s), at address %p\n", name, demangle_name(typeid(T).name()).c_str(), &t); + indent++; + if ( next_item_read_only ) { + next_item_read_only = false; + } + } + + void map_hierarchy_end(/*const char* name*/) + { + // // Need to check to make sure we are ending the one we started + // if ( obj_->getName() != name ) { + // // Error + // } + // obj_ = obj_->getParent(); + obj_.pop_back(); + indent--; + } + + void init(ObjectMap* object) + { + obj_.push_back(object); + } + + void reset() + { + obj_.clear(); + } + + /** + * @brief pack_buffer + * @param buf Must be non-null + * @param size Must be non-zero + */ + void map_buffer(void* buf, int size); + + void setNextObjectReadOnly() { next_item_read_only = true; } + +private: + int indent = 0; +}; + +} // namespace pvt +} // namespace Serialization +} // namespace Core +} // namespace SST + +#endif // SST_CORE_SERIALIZATION_IMPL_MAPPER_H diff --git a/src/sst/core/serialization/impl/serialize_atomic.h b/src/sst/core/serialization/impl/serialize_atomic.h index bc6aae1e7..4d946f918 100644 --- a/src/sst/core/serialization/impl/serialize_atomic.h +++ b/src/sst/core/serialization/impl/serialize_atomic.h @@ -54,6 +54,9 @@ class serialize> v.store(val); break; } + case serializer::MAP: + // Add your code here + break; } } }; diff --git a/src/sst/core/serialization/impl/serialize_deque.h b/src/sst/core/serialization/impl/serialize_deque.h index e457cb266..37eaf0c8b 100644 --- a/src/sst/core/serialization/impl/serialize_deque.h +++ b/src/sst/core/serialization/impl/serialize_deque.h @@ -65,6 +65,9 @@ class serialize> } break; } + case serializer::MAP: + // Add your code here + break; } } }; diff --git a/src/sst/core/serialization/impl/serialize_list.h b/src/sst/core/serialization/impl/serialize_list.h index 13559e800..d10fd86aa 100644 --- a/src/sst/core/serialization/impl/serialize_list.h +++ b/src/sst/core/serialization/impl/serialize_list.h @@ -68,6 +68,9 @@ class serialize> } break; } + case serializer::MAP: + // Add your code here + break; } } }; diff --git a/src/sst/core/serialization/impl/serialize_map.h b/src/sst/core/serialization/impl/serialize_map.h index dd1d2eecc..7cb9d500e 100644 --- a/src/sst/core/serialization/impl/serialize_map.h +++ b/src/sst/core/serialization/impl/serialize_map.h @@ -20,12 +20,22 @@ #include "sst/core/serialization/serializer.h" #include +#include #include namespace SST { namespace Core { namespace Serialization { +/** + Class used to map std::map + */ +// template +// class ObjectMapMap : public ObjectMapWithChildren +// { + +// }; + template class serialize> { @@ -73,6 +83,9 @@ class serialize> } break; } + case serializer::MAP: + // Add your code here + break; } } }; @@ -124,6 +137,9 @@ class serialize> } break; } + case serializer::MAP: + // Add your code here + break; } } }; diff --git a/src/sst/core/serialization/impl/serialize_multiset.h b/src/sst/core/serialization/impl/serialize_multiset.h index 3b956b646..698169863 100644 --- a/src/sst/core/serialization/impl/serialize_multiset.h +++ b/src/sst/core/serialization/impl/serialize_multiset.h @@ -69,6 +69,9 @@ class serialize> } break; } + case serializer::MAP: + // Add your code here + break; } } }; @@ -116,6 +119,9 @@ class serialize> } break; } + case serializer::MAP: + // Add your code here + break; } } }; diff --git a/src/sst/core/serialization/impl/serialize_priority_queue.h b/src/sst/core/serialization/impl/serialize_priority_queue.h index f4abd17a6..e8a0c5664 100644 --- a/src/sst/core/serialization/impl/serialize_priority_queue.h +++ b/src/sst/core/serialization/impl/serialize_priority_queue.h @@ -79,6 +79,9 @@ class serialize> } break; } + case serializer::MAP: + // Add your code here + break; } } }; diff --git a/src/sst/core/serialization/impl/serialize_set.h b/src/sst/core/serialization/impl/serialize_set.h index 1b23ba33f..541906298 100644 --- a/src/sst/core/serialization/impl/serialize_set.h +++ b/src/sst/core/serialization/impl/serialize_set.h @@ -69,6 +69,9 @@ class serialize> } break; } + case serializer::MAP: + // Add your code here + break; } } }; @@ -116,6 +119,9 @@ class serialize> } break; } + case serializer::MAP: + // Add your code here + break; } } }; diff --git a/src/sst/core/serialization/impl/serialize_string.h b/src/sst/core/serialization/impl/serialize_string.h index a0f6c04b3..80279114b 100644 --- a/src/sst/core/serialization/impl/serialize_string.h +++ b/src/sst/core/serialization/impl/serialize_string.h @@ -23,11 +23,64 @@ namespace SST { namespace Core { namespace Serialization { +class ObjectMapString : public ObjectMap +{ +protected: + std::string* addr_; + +public: + + /** + Get the address of the represented object + + @return address of represented object + */ + void* getAddr() override { return addr_; } + + std::string get() override { + return *addr_; + } + + void set_impl(const std::string& value) override + { + *addr_ = value; + } + + virtual bool isFundamental() override { return true; } + + /** + Get the list of child variables contained in this ObjectMap, + which in this case will be empty. + + @return Refernce to vector containing ObjectMaps for this + ObjectMap's child variables. This vector will be empty because + strings have no children + */ + const std::vector>& getVariables() override { return emptyVars; } + + std::string getType() override + { + // The demangled name for std::string is ridiculously long, so + // just return "std::string" + return "std::string"; + } + + ObjectMapString(std::string* addr) : + ObjectMap(), + addr_(addr) + {} +}; + template <> class serialize_impl { public: void operator()(std::string& str, serializer& ser) { ser.string(str); } + void operator()(std::string& str, serializer& ser, const char* name) + { + ObjectMapString* obj_map = new ObjectMapString(&str); + ser.mapper().map_primitive(name, obj_map); + } }; } // namespace Serialization diff --git a/src/sst/core/serialization/impl/serialize_vector.h b/src/sst/core/serialization/impl/serialize_vector.h index 132de0a84..f614eb912 100644 --- a/src/sst/core/serialization/impl/serialize_vector.h +++ b/src/sst/core/serialization/impl/serialize_vector.h @@ -19,18 +19,67 @@ #include "sst/core/serialization/serializer.h" +#include #include namespace SST { namespace Core { namespace Serialization { -template -class serialize> + +/** + Class used to map std::vectors. + */ +template +class ObjectMapVector : public ObjectMapWithChildren { - typedef std::vector Vector; +protected: + + std::vector* addr_; public: + // virtual std::string get(const std::string& var) override + // { + // if constexpr ( std::is_fundamental_v || std::is_base_of_v ) { + // int index = SST::Core::from_string(var); + // return std::to_string(vector()->at(index)); + // } + // return ""; + // } + + // virtual void set(const std::string& var, const std::string& value) override + // { + // if constexpr ( std::is_fundamental_v ) { + // int index = SST::Core::from_string(var); + // vector()->at(index) = SST::Core::from_string(value); + // } + // else if constexpr ( std::is_base_of_v ) { + // int index = SST::Core::from_string(var); + // vector()->at(index) = value; + // } + // } + + bool isContainer() override { return true; } + + std::string getType() override { return demangle_name(typeid(std::vector).name()); } + + void* getAddr() override { return addr_; } + + ObjectMapVector(std::vector* addr) : + ObjectMapWithChildren(), + addr_(addr) + {} +}; + + +template +class serialize_impl> +{ + template + friend class serialize; + + typedef std::vector Vector; + void operator()(Vector& v, serializer& ser) { switch ( ser.mode() ) { @@ -53,20 +102,39 @@ class serialize> v.resize(s); break; } + case serializer::MAP: + // If this version of operator() is called during mapping + // mode, then the variable being mapped did not provide a + // name, which means no ObjectMap will be created. + break; } for ( size_t i = 0; i < v.size(); ++i ) { ser& v[i]; } } + + void operator()(Vector& v, serializer& ser, const char* name) + { + if ( ser.mode() != serializer::MAP ) return operator()(v,ser); + + ObjectMapVector* obj_map = new ObjectMapVector(&v); + ser.mapper().map_hierarchy_start(name, obj_map); + for ( size_t i = 0; i < v.size(); ++i ) { + sst_map_object(ser, v[i], std::to_string(i).c_str()); + } + ser.mapper().map_hierarchy_end(); + } }; template <> -class serialize> +class serialize_impl> { + template + friend class serialize; + typedef std::vector Vector; -public: void operator()(Vector& v, serializer& ser) { switch ( ser.mode() ) { @@ -103,8 +171,30 @@ class serialize> } break; } + case serializer::MAP: + // If this version of operator() is called during mapping + // mode, then the variable being mapped did not provide a + // name, which means no ObjectMap will be created. + break; } } + + // TODO: Add support for mapping vector. The weird way they + // pack the bits means we'll likely need to have a special case of + // ObjectMapVector that knows how to handle the packing. + + // void operator()(Vector& v, serializer& ser, const char* name) + // { + // if ( ser.mode() != serializer::MAP ) return operator()(v,ser); + + // ObjectMapVector* obj_map = new ObjectMapVector(&v); + // ser.mapper().map_hierarchy_start(name, obj_map); + // for ( size_t i = 0; i < v.size(); ++i ) { + // sst_map_object(ser, v[i], std::to_string(i).c_str()); + // } + // ser.mapper().map_hierarchy_end(); + // } + }; diff --git a/src/sst/core/serialization/objectMap.cc b/src/sst/core/serialization/objectMap.cc new file mode 100644 index 000000000..4f1dbf816 --- /dev/null +++ b/src/sst/core/serialization/objectMap.cc @@ -0,0 +1,53 @@ +// 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/serialization/objectMap.h" + +#include + +namespace SST { +namespace Core { +namespace Serialization { + +// Static variable instantiation +std::vector> ObjectMap::emptyVars; + + +std::string +ObjectMap::demangle_name(const char* name) +{ + int status; + + char* demangledName = abi::__cxa_demangle(name, nullptr, nullptr, &status); + if (status == 0) { + std::string ret(demangledName); + std::free(demangledName); + + // // Find the position of the first '<' character + // size_t pos = ret.find('<'); + // if (pos != std::string::npos) { + // // Extract the base class name + // return ret.substr(0, pos); + // } + + // // If no '<' character found, return the original name + return ret; + } else { + return ""; + } +} + + +} // namespace Serialization +} // namespace Core +} // namespace SST diff --git a/src/sst/core/serialization/objectMap.h b/src/sst/core/serialization/objectMap.h new file mode 100644 index 000000000..420e9c4c3 --- /dev/null +++ b/src/sst/core/serialization/objectMap.h @@ -0,0 +1,757 @@ +// 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. + +#ifndef SST_CORE_SERIALIZATION_OBJECTMAP_H +#define SST_CORE_SERIALIZATION_OBJECTMAP_H + +#include "sst/core/from_string.h" +#include "sst/core/warnmacros.h" + +// REMOVE ME +#include "sst/core/output.h" + +#include +#include + +namespace SST { +namespace Core { +namespace Serialization { + +class ObjectMap; + +// Metadata object that each ObjectMap has a pointer to in order to +// track the hierarchy information while traversing the data +// structures. This is used because a given object can be pointed to +// by multiple other objects, so we need to track the "path" through +// which we got to the object so we can traverse back up the object +// hierarchy. +struct ObjectMapMetaData +{ + /** + Parent object that contained this object and through which it + was selected. + */ + ObjectMap* parent; + + /** + Name of this object in the context of the currently set parent + */ + std::string name; + + /** + Constructor for intializing data memebers + */ + ObjectMapMetaData(ObjectMap* parent, const std::string& name): + parent(parent), + name(name) + {} +}; + +/** + Class created by the serializer mapping mode used to map the + variables for objects. This allows access to read and write the + mapped variables. The base class is used for non-fundamental and + non-container types, but there is a templated child class used for + fundameentals and containers. The templating is needed so that the + type information can be embedded in the code for reading and + writing. + */ +class ObjectMap +{ +protected: + + // Static empty variable vector for use by versions that don't + // have variables (i.e. are fundamentals or classes treated as + // fundamentals. This is needed because getVariables() returns a + // reference to the vector. + static std::vector> emptyVars; + + // ObjectMap(const std::string& name, void* addr) : name_(name), addr_(addr) {} + + /** + Metedata object for walking the object hierarchy. When this + object is selected by a parent object, a metadata object will + be added. The metadata contains a pointer to the parent and + the name of this object in the context of the parent. If this + object is selected and the metadata is non a nullptr, then we + have hit a loop in the data structure. + + Under normal circumstances, the metadata allows you to get the + full path of the object according to how you walked the + hierarchy, and allows you to return to the parent object. If a + loop is detected on select, then the full path of the object + will return to the highest level path and the metadata from + that path to the current path will be erased. + */ + ObjectMapMetaData* mdata = nullptr; + + + /** + Indicates wheter or not the variable is read-only + */ + bool read_only = false; + + /** + Parent of this ObjectMap. If parent is nullptr, then this is + the top level of hierarchy + */ + // ObjectMap* parent_ = nullptr; + + /** + Name of the variable as given to the serializer. This uses the + SST_SER and SST_SER_AS_PTR macros which pass both the variable + and the stringized name to the serializer. + */ + // std::string name_ = ""; + + /** + Address of the variable for reading and writing + */ + // void* addr_ = nullptr; + + /** + Type of the variable as given by the demangled version of + typeif.name() for the type. + */ + // std::string type_ = ""; + + /** + Vector of variables contained within this ObjectMap. This is + empty for fundamentals and containers + */ + // std::vector variables_; + + + /** + Select the specified ObjectMap as a child variable with the + given name. It is the caller's responsibility to ensure that + they are only calling this on an ObjectMap returned from the + current ObjectMap's getVariables() call. Otherwise, the + behavior is unspecified. This function is primarily used to + recurse the hierarchy for the print() function. + + @return ObjectMap* that is pased in if no loopback is detected, + nullptr otherwise. + + */ + ObjectMap* selectVariable(const std::string& name, ObjectMap* var) + { + // Found the variable, make sure we haven't created a + // loop + if ( var->mdata ) { + // Loop detected + return nullptr; + } + // No loop, set the metadata and return it + var->mdata = new ObjectMapMetaData(this,name); + return var; + } + + /** + Function implemented by derived classes to implement set(). No + need to check for read_only, that is done in set(). + */ + virtual void set_impl(const std::string& UNUSED(value)) {} + + +public: + /** + Default constructor primarily used for the "top" object in the hierarchy + */ + // ObjectMap() : name_("") {} + ObjectMap() {} + + + inline bool isReadOnly() { return read_only; } + inline void setReadOnly() { read_only = true; } + + /** + Constructor for ObjectMap + + @param name Name of the variable + @param addr Address of the variable + @param type Type of the variable as returned by typeid.name() + */ + // ObjectMap(const std::string& name, void* addr, const std::string& type) : + // name_(name), + // addr_(addr), + // type_(demangle_name(type.c_str())) + // {} + + /** + Get the name of the variable represented by this ObjectMap + + @return Name of variable + */ + std::string getName() + { + // printf("name = %s\n", mdata->name.c_str()); + // printf("parent = %p\n", mdata->parent); + if ( mdata ) { + return mdata->name; + } + return ""; + } + + /** + Get the full hierarchical name of the variable represented by + this ObjectMap, based on the path taken to get to this object. + + @return Full hierarchical name of variable + */ + std::string getFullName() + { + if ( !mdata ) return ""; + + std::string fullname = mdata->name; + std::string slash("/"); + // path = slash + path; + ObjectMapMetaData* curr = mdata->parent->mdata; + while ( curr != nullptr ) { + fullname = curr->name + slash + fullname; + curr = curr->parent->mdata; + } + return fullname; + } + + /** + Get the type of the variable represented by the ObjectMap + + @return Type of variable + */ + virtual std::string getType() = 0; + + /** + Get the address of the variable represented by the ObjectMap + + @return Address of varaible + */ + virtual void* getAddr() = 0; + + + /** + Get the list of child variables contained in this ObjectMap + + @return Refernce to vector containing ObjectMaps for this + ObjectMap's child variables. Fundamental types will return the + same empty vector. + */ + virtual const std::vector>& getVariables() { return emptyVars; } + + + + /************ Functions for walking the Object Hierarchy ************/ + + /** + Get the parent for this ObjectMap + + @return Parent for this ObjectMap + */ + ObjectMap* selectParent() + { + ObjectMap* ret = mdata->parent; + if ( nullptr == ret ) { + printf("No metadata found in selectParent()\n"); + return nullptr; + } + mdata = nullptr; + return ret; + } + + /** + Get the ObjectMap for the specified variable + + @return ObjectMap for specified variable, if it exists, this + otherwise + */ + ObjectMap* selectVariable(std::string name) + { + ObjectMap* var = findVariable(name); + + // If we get nullptr back, then it didn't exist. Just return this + if ( nullptr == var ) return this; + + // See if this creates a loop + + if ( var->mdata ) { + printf("Found a loop\n"); + // Loop detected. We will need to remove all the + // mdata elements from this object back up from + // parent to parent until we get to the object we + // are selecting. This will reset the hierachy to + // the more shallow one. + ObjectMap* current = this; + ObjectMap* parent = mdata->parent; + delete current->mdata; + current->mdata = nullptr; + while ( parent != var ) { + // TODO: check for parent == nullptr, which + // would be the case where we didn't detect + // the loop going back up the chain. This + // would mean the metadata was corrupted + // somehow. + current = parent; + parent = current->mdata->parent; + // Clear the metadata for current + delete current->mdata; + current->mdata = nullptr; + } + return var; + } + + // No loop, set the metadata and return it + var->mdata = new ObjectMapMetaData(this, name); + return var; + } + + + /** + Adds a varaible to this ObjectMap + + @param obj ObjectMap to add as a variable + */ + virtual void addVariable(const std::string& UNUSED(name), ObjectMap* UNUSED(obj)) {} + + // /** + // Set the parent for this ObjectMap + + // @param obj ObjectMap to set as parent + // */ + // void addParent(ObjectMap* obj) { parent_ = obj; } + + + /************ Functions for getting/setting Object's Value *************/ + + /** + Get the value of the variable as a string. NOTE: this function + is only valid for ObjectMaps that represent fundamental types + or classes treated as fundamental types. + + @return Value of the represented variable as a string + */ + virtual std::string get() { return ""; } + + /** + Sets the value of the variable represented by the ObjectMap to + the specified value, which is represented as a string. The + templated child classes for fundamentals will know how to + convert the string to a value of the approproprite type. NOTE: + this fucntion is only value for ObjectMaps that represent + fundamental types or classes treated as fundamentatl types. + */ + void set(const std::string& value) + { + if ( read_only ) return; + else set_impl(value); + } + + /** + Gets the value of the specified variable as a string. NOTE: + this function is only valid for ObjectMaps that represent + non-fundamental types or classes not treated as fundamental + types. + + @return Value of the specified variable as a string + */ + virtual std::string get(const std::string& var) + { + ObjectMap* obj = selectVariable(var); + if ( nullptr == obj ) return ""; + std::string ret = obj->get(); + obj->selectParent(); + return ret; + } + + /** + Sets the value of the specified variable to the specified + value, which is represented as a string. The templated child + classes for fundamentals will know how to convert the string to + a value of the approproprite type. NOTE: this fucntion is only + valuid for ObjectMaps that represent non-fundamental types or + classes not treated as fundamentatl types (i.e. they must have + childrent). + */ + virtual void set(const std::string& var, const std::string& value, bool& found, bool& read_only) + { + ObjectMap* obj = selectVariable(var); + if ( nullptr == obj ) { + found = false; + return; + } + found = true; + if ( obj->isReadOnly() ) { + read_only = true; + return; + } + read_only = false; + obj->set(value); + obj->selectParent(); + } + + // /** + // Get the number of variables in the ObjectMap + + // @return Number of variables added to the ObjectMap + // */ + // virtual size_t num_vars() { return variables_.size(); } + + /** + Check to see if this ObjectMap represents a fundamental or a + class treated as a fundamental. + + @return true if this ObjectMap represents a fundamental or + class treated as a fundamental, false otherwise + */ + virtual bool isFundamental() { return false; } + + /** + Check to see if this ObjectMap represents a container + + @return true if this ObjectMap represents a container, false + otherwise + */ + virtual bool isContainer() { return false; } + + + + virtual ~ObjectMap() + { + // for ( auto* x : variables_ ) + // delete x; + // variables_.clear(); + } + + /** + Static function to demangle type names returned from typeid.name() + + @return demangled name + */ + static std::string demangle_name(const char* name); + + /** + Print information for the specified variable. + + @param name name of variable to print + @param recurse number of levels to recurse (default is 0) + + @return true if variable is found, false otherwise + */ + virtual bool printVariable(std::string name, int recurse = 0) + { + ObjectMap* var = findVariable(name); + if ( nullptr == var ) return false; + + // Check to see if this is a loopback + if ( nullptr != var->mdata ) { + // Found a loop + printf("%s (%s) = \n", name.c_str(), var->getType().c_str()); + return true; + } + var->activate(this, name); + var->printRecursive(name, 0, recurse); + var->deactivate(); + return true; + } + + /** + Print the variable information. The name of the variable must + be passed in so that we don't need to use the metadata, which + is used to keep track of the path selected through the object + hierarchy. + */ + virtual void print(int recurse = 0) + { + printRecursive(mdata->name, 0, recurse); + } + + // virtual void print(std::string name = "", int level = 0, bool recurse = true) + // { + // if ( mdata ) name = mdata->name; + // std::string indent = std::string(level, ' '); + // if ( isFundamental() ) { + // printf("%s%s = %s (%s)\n", indent.c_str(), name.c_str(), get().c_str(), getType().c_str()); + // return; + // } + + // // if ( isContainer() ) { + // // printf("%s%s (%s)\n", indent.c_str(), name_.c_str(), type_.c_str()); + // // return; + // // } + + // printf("%s%s (%s)\n", indent.c_str(), name.c_str(), getType().c_str()); + + // if ( recurse ) { + // for ( auto& x : getVariables() ) { + // // ObjectMap* sel = selectVariable(x.first, x.second); + // // bool loop = ( nullptr != sel->mdata ); + // bool loop = ( nullptr != x.second->mdata ); + // if ( loop ) { + // printf("%s %s (%s) = \n", indent.c_str(), x.first.c_str(), x.second->getType().c_str()); + // } + // else { + // x.second->print(x.first, level + 1, true); + // // x.second->selectParent(); + // } + // } + // } + // } + +private: + + inline void activate(ObjectMap* parent, const std::string& name) + { + mdata = new ObjectMapMetaData(parent,name); + } + + inline void deactivate() + { + delete mdata; + mdata = nullptr; + } + + inline ObjectMap* findVariable(const std::string& name) + { + const std::vector>& variables = getVariables(); + for ( auto& x : variables ) { + if ( x.first == name ) { + return x.second; + } + } + return nullptr; + } + + void printRecursive(const std::string& name, int level, int recurse) + { + std::string indent = std::string(level, ' '); + if ( isFundamental() ) { + printf("%s%s = %s (%s)\n", indent.c_str(), name.c_str(), get().c_str(), getType().c_str()); + return; + } + + printf("%s%s (%s)\n", indent.c_str(), name.c_str(), getType().c_str()); + + if ( level <= recurse ) { + for ( auto& x : getVariables() ) { + bool loop = ( nullptr != x.second->mdata ); + if ( loop ) { + printf("%s %s (%s) = \n", indent.c_str(), x.first.c_str(), x.second->getType().c_str()); + } + else { + x.second->activate(this, name); + x.second->printRecursive(x.first, level + 1, recurse); + x.second->deactivate(); + } + } + } + + } + +}; + + +/** + ObjectMap object for non-fundamental, non-container types. This + class allows for child variables. + */ +class ObjectMapWithChildren : public ObjectMap +{ +protected: + + std::vector> variables_; + + ObjectMapWithChildren() : ObjectMap() {} + +public: + + /** + Adds a variable to this ObjectMap + + @param obj ObjectMap to add as a variable + */ + void addVariable(const std::string& name, ObjectMap* obj) override { variables_.push_back(std::make_pair(name,obj)); } + + + /** + Get the list of child variables contained in this ObjectMap + + @return Refernce to vector containing ObjectMaps for this + ObjectMap's child variables. pair.first is the name of the + variable in the context of this object. + */ + const std::vector>& getVariables() override { return variables_; } + +}; + + +/** + ObjectMap object to create a level of hierarchy that doesn't + represent a specific object. This can be used to create views of + data that don't align specifically with the underlying data + structures. + */ +class ObjectMapHierarchyOnly : public ObjectMapWithChildren +{ +public: + + ObjectMapHierarchyOnly() : + ObjectMapWithChildren() + {} + + /** + Returns empty string since there is no underlying object being + represented + + @return empty string + */ + std::string getType() override { return ""; } + + /** + Returns nullptr since there is no underlying object being + represented + + @return nullptr + */ + void* getAddr() override { return nullptr; } + +}; + + +/** + ObjectMap object for non-fundamental, non-container types. This + class allows for child variables. + */ +class ObjectMapClass : public ObjectMapWithChildren +{ +protected: + + /** + Type of the variable as given by the demangled version of + typeif.name() for the type. + */ + std::string type_; + + /** + Address of the variable for reading and writing + */ + void* addr_ = nullptr; + +public: + + ObjectMapClass() : + ObjectMapWithChildren() + {} + + ObjectMapClass(void* addr, const std::string& type) : + ObjectMapWithChildren(), + type_(demangle_name(type.c_str())), + addr_(addr) + {} + + /** + Get the type of the represented object + + @return type of represented object + */ + std::string getType() override { return type_; } + + /** + Get the address of the represented object + + @return address of represented object + */ + void* getAddr() override { return addr_; } + +}; + + +/** + ObjectMap object fundamental types, and classes treated as + fundamental types. In order for an object to be treated as a + fundamental, it must be printable using std::to_string() and + assignable using SST::Core::from_string(). +*/ +template +class ObjectMapFundamental : public ObjectMap +{ +protected: + + /** + Address of the variable for reading and writing + */ + T* addr_ = nullptr; + +public: + virtual std::string get() override { return std::to_string(*addr_); } + virtual void set_impl(const std::string& value) override + { + *addr_ = SST::Core::from_string(value); + } + + bool isFundamental() override { return true; } + + /** + Get the address of the variable represented by the ObjectMap + + @return Address of varaible + */ + void* getAddr() override { return addr_; } + + + // ObjectMapFundamental(const std::string& name, void* addr) : + // ObjectMap(name, addr) + // { + // type_ = demangle_name(typeid(T).name()); + // } + + /** + Get the list of child variables contained in this ObjectMap, + which in this case will be empty. + + @return Refernce to vector containing ObjectMaps for this + ObjectMap's child variables. This vector will be empty because + fundamentals have no children + */ + const std::vector>& getVariables() override { return emptyVars; } + + ObjectMapFundamental(T* addr) : + ObjectMap(), + addr_(addr) + {} + + std::string getType() override + { + return demangle_name(typeid(T).name()); + } +}; + + +// /** +// Class to walk the ObjectMap hierarchy. +// */ +// class ObjectMapWalker +// { +// public: +// ObjectMapWalker(ObjectMap* top); + +// selectVariable(); +// selectParent(); + +// set(); +// get(); + +// }; + + +} // namespace Serialization +} // namespace Core +} // namespace SST + +#endif // SST_CORE_SERIALIZATION_OBJECTMAP_H diff --git a/src/sst/core/serialization/serializable.cc b/src/sst/core/serialization/serializable.cc index 0523773db..09fc4ac9f 100644 --- a/src/sst/core/serialization/serializable.cc +++ b/src/sst/core/serialization/serializable.cc @@ -12,6 +12,8 @@ #include "sst_config.h" #include "sst/core/serialization/serializable.h" +// REMOVE: For TraceFunction +#include "sst/core/output.h" #include @@ -57,6 +59,25 @@ unpack_serializable(serializable_base*& s, serializer& ser) } } +void +map_serializable(serializable_base*& s, serializer& ser, const char* name) +{ + TraceFunction trace(CALL_INFO_LONG, false); + if ( s ) { + trace.output("name = %s\n", name); + trace.output("cls_name = %s\n", s->cls_name()); + SST::Core::Serialization::ObjectMap* obj_map = new SST::Core::Serialization::ObjectMapClass(s, s->cls_name()); + trace.output("Made it to line %d\n", __LINE__); + ser.report_object_map(obj_map); + ser.mapper().map_hierarchy_start(name, obj_map); + trace.output("Made it to line %d\n", __LINE__); + s->serialize_order(ser); + trace.output("Made it to line %d\n", __LINE__); + ser.mapper().map_hierarchy_end(); + trace.output("Made it to line %d\n", __LINE__); + } +} + } // namespace pvt } // namespace Serialization } // namespace Core diff --git a/src/sst/core/serialization/serializable.h b/src/sst/core/serialization/serializable.h index db084f96c..51c89e811 100644 --- a/src/sst/core/serialization/serializable.h +++ b/src/sst/core/serialization/serializable.h @@ -44,6 +44,8 @@ void pack_serializable(serializable_base* s, serializer& ser); void unpack_serializable(serializable_base*& s, serializer& ser); +void map_serializable(serializable_base*& s, serializer& ser, const char* name); + } // namespace pvt @@ -67,6 +69,29 @@ class serialize_impl< case serializer::UNPACK: pvt::unpack_serializable(sp, ser); break; + case serializer::MAP: + // No mapping without a name + break; + } + s = static_cast(sp); + } + + void operator()(T*& s, serializer& ser, const char* name) + { + serializable_base* sp = static_cast(s); + switch ( ser.mode() ) { + case serializer::SIZER: + pvt::size_serializable(sp, ser); + break; + case serializer::PACK: + pvt::pack_serializable(sp, ser); + break; + case serializer::UNPACK: + pvt::unpack_serializable(sp, ser); + break; + case serializer::MAP: + pvt::map_serializable(sp, ser, name); + break; } s = static_cast(sp); } @@ -88,6 +113,9 @@ serialize_intrusive_ptr(T*& t, serializer& ser) pvt::unpack_serializable(s, ser); t = dynamic_cast(s); break; + case serializer::MAP: + // Add your code here + break; } } @@ -103,6 +131,14 @@ class serialize_impl< // serialize_intrusive_ptr(tmp, ser); t.serialize_order(ser); } + + inline void operator()(T& UNUSED(t), serializer& UNUSED(ser), const char* UNUSED(name)) + { + // FIXME: For now do nothing + // // T* tmp = &t; + // // serialize_intrusive_ptr(tmp, ser); + // t.serialize_order(ser); + } }; diff --git a/src/sst/core/serialization/serializable_base.h b/src/sst/core/serialization/serializable_base.h index 6b4cbb0dc..48b303de9 100644 --- a/src/sst/core/serialization/serializable_base.h +++ b/src/sst/core/serialization/serializable_base.h @@ -134,8 +134,9 @@ class serializable_base static void serializable_abort(uint32_t line, const char* file, const char* func, const char* obj); }; + template -class serializable_type +class [[deprecated ("serializable_type is deprecated and will be removed in SST 15")]] serializable_type {}; #define ImplementVirtualSerializable(obj) \ @@ -280,10 +281,6 @@ const uint32_t serializable_builder_impl::cls_id_ = #define DeclareSerializable(obj) -// Serialization macros for checkpoint/debug serialization -#define SST_SER(obj) ser& obj; -#define SST_SER_AS_PTR(obj) ser | obj; - //#include "sst/core/serialization/serialize_serializable_base.h" #endif diff --git a/src/sst/core/serialization/serialize.h b/src/sst/core/serialization/serialize.h index 95d21adcf..807b2fdfc 100644 --- a/src/sst/core/serialization/serialize.h +++ b/src/sst/core/serialization/serialize.h @@ -12,39 +12,39 @@ #ifndef SST_CORE_SERIALIZATION_SERIALIZE_H #define SST_CORE_SERIALIZATION_SERIALIZE_H +#include "sst/core/from_string.h" +#include "sst/core/serialization/objectMap.h" #include "sst/core/serialization/serializer.h" #include "sst/core/warnmacros.h" #include #include #include +#include namespace SST { namespace Core { namespace Serialization { +// Workaround for use with static_assert(), since static_assert(false) +// will always assert, even when in an untaken if constexpr path. +// This can be used in any serialize_impl class, if needed/ +template +constexpr bool dependent_false = false; + /** - Base serialize class. This is the default, which if hit will - static_assert. All other instances are partial specializations of - this class and do all the real serialization. + Base serialize class. + + This class also acts as the default case, which if hit will check + to see if this is an otherwise uncaught non-polymorphic class. If + it is, it will just attempt to call the serialize_order() function. + All other instances are partial specializations of this class and + do all the real serialization. */ template class serialize_impl { public: - // inline void operator()(T& UNUSED(t), serializer& UNUSED(ser)) - // { - // // If the default gets called, then it's actually invalid - // // because we don't know how to serialize it. - - // // This is a bit strange, but if I just do a - // // static_assert(false) it always triggers, but if I use - // // std::is_* then it seems to only trigger if something expands - // // to this version of the template. - // // static_assert(false,"Trying to serialize an object that is not serializable."); - // static_assert(std::is_fundamental::value, "Trying to serialize an object that is not serializable."); - // static_assert(!std::is_fundamental::value, "Trying to serialize an object that is not serializable."); - // } inline void operator()(T& t, serializer& ser) { @@ -52,7 +52,7 @@ class serialize_impl if constexpr ( std::is_pointer_v ) { // If it falls through to the default, let's check to see if it's // a non-polymorphic class and try to call serialize_order - if constexpr ( std::is_class_v> && !std::is_polymorphic_v> ) { + if constexpr ( std::is_class_v::type> && !std::is_polymorphic_v::type> ) { if ( ser.mode() == serializer::UNPACK ) { t = new typename std::remove_pointer::type(); ser.report_new_pointer(reinterpret_cast(t)); @@ -60,9 +60,7 @@ class serialize_impl t->serialize_order(ser); } else { - static_assert(std::is_fundamental::value, "Trying to serialize an object that is not serializable."); - static_assert( - !std::is_fundamental::value, "Trying to serialize an object that is not serializable."); + static_assert(dependent_false, "Trying to serialize an object that is not serializable."); } } else { @@ -70,34 +68,55 @@ class serialize_impl // a non-polymorphic class and try to call serialize_order if constexpr ( std::is_class_v && !std::is_polymorphic_v ) { t.serialize_order(ser); } else { - static_assert(std::is_fundamental::value, "Trying to serialize an object that is not serializable."); - static_assert( - !std::is_fundamental::value, "Trying to serialize an object that is not serializable."); + static_assert(dependent_false, "Trying to serialize an object that is not serializable."); } } } -}; + inline void operator()(T& t, serializer& ser, const char* name) + { + // This is the fall through case. Check to see if it's a pointer: + if constexpr ( std::is_pointer_v ) { + // If it falls through to the default, let's check to see if it's + // a non-polymorphic class and try to call serialize_order + if constexpr ( std::is_class_v::type> && !std::is_polymorphic_v::type> ) { + if ( ser.mode() == serializer::UNPACK ) { + t = new typename std::remove_pointer::type(); + ser.report_new_pointer(reinterpret_cast(t)); + } + if ( ser.mode() == serializer::MAP ) { + // No need to map a nullptr + if ( nullptr == t ) return; + SST::Core::Serialization::ObjectMap* map = new SST::Core::Serialization::ObjectMapClass(t, typeid(T).name()); + ser.report_object_map(map); + ser.mapper().map_hierarchy_start(name, map); + } + t->serialize_order(ser); + if ( ser.mode() == serializer::MAP ) ser.mapper().map_hierarchy_end(); + } + else { + static_assert(dependent_false, "Trying to serialize an object that is not serializable."); + } + } + else { + // If it falls through to the default, let's check to see if it's + // a non-polymorphic class and try to call serialize_order + if constexpr ( std::is_class_v && !std::is_polymorphic_v ) { + if ( ser.mode() == serializer::MAP ) { + SST::Core::Serialization::ObjectMap* map = new SST::Core::Serialization::ObjectMapClass(&t, typeid(T).name()); + ser.report_object_map(map); + ser.mapper().map_hierarchy_start(name, map); + } + t.serialize_order(ser); + if ( ser.mode() == serializer::MAP ) ser.mapper().map_hierarchy_end(); + } + else { + static_assert(dependent_false, "Trying to serialize an object that is not serializable."); + } + } + } -// template -// class serialize_impl::value, bool> = -// true> -// { -// public: -// inline void operator()(T& t, serializer& ser) -// { -// // If it falls through to the default, let's check to see if it's -// // a non-polymorphic class and try to call serialize_order -// if constexpr ( std::is_class_v && !std::is_polymorphic_v /*&& std::is_same_v::type, void>*/) { -// t.serialize_order(ser); -// } -// else { -// static_assert(std::is_fundamental::value, "Trying to serialize an object that is not serializable."); -// static_assert(!std::is_fundamental::value, "Trying to serialize an object that is not serializable."); -// } -// } -// }; +}; /** @@ -111,6 +130,9 @@ class serialize { public: inline void operator()(T& t, serializer& ser) { return serialize_impl()(t, ser); } + inline void operator()(T& t, serializer& ser, const char* name) + { + return serialize_impl()(t, ser, name); } /** This will track the pointer to the object if pointer tracking @@ -164,6 +186,9 @@ class serialize ser.report_real_pointer(ptr_stored, ptr); serialize_impl()(t, ser); + case serializer::MAP: + // Add your code here + break; } } }; @@ -202,6 +227,7 @@ class serialize if ( !ser.check_pointer_pack(ptr) ) { serialize_impl()(t, ser); } break; case serializer::UNPACK: + { // Get the ptr and check to see if we've already deserialized uintptr_t ptr_stored; ser.unpack(ptr_stored); @@ -222,18 +248,49 @@ class serialize ser.report_real_pointer(ptr_stored, reinterpret_cast(t)); } } + case serializer::MAP: + // Add your code here + break; + } + } + + inline void operator()(T*& t, serializer& ser, const char* name) + { + // We are a pointer, need to see if tracking is turned on + // if ( !ser.is_pointer_tracking_enabled() ) return serialize_impl()(t, ser); + // The name version of the function is only used in mapping + // mode. If it's not mapping mode, it's an error. + // TODO: Add error and exit + if ( ser.mode() != serializer::MAP ) return; + + ObjectMap* map = ser.check_pointer_map(reinterpret_cast(t)); + if ( map != nullptr ) { + // If we've already seen this object, just add the + // existing ObjectMap to the parent. + ser.mapper().map_existing_object(name, map); + return; + } + serialize_impl()(t,ser,name); } }; + /** Version of serialize that works for fundamental types and enums. */ + template class serialize_impl::value || std::is_enum::value>::type> { template friend class serialize; inline void operator()(T& t, serializer& ser) { ser.primitive(t); } + + inline void operator()(T& t, serializer& ser, const char* name) + { + ObjectMapFundamental* obj_map = new ObjectMapFundamental(&t); + ser.mapper().map_primitive(name, obj_map); + } }; /** @@ -250,6 +307,12 @@ class serialize_impl ser.primitive(bval); t = bool(bval); } + + inline void operator()(bool& t, serializer& ser, const char* name) + { + ObjectMapFundamental* obj_map = new ObjectMapFundamental(&t); + ser.mapper().map_primitive(name, obj_map); + } }; /** @@ -278,6 +341,9 @@ class serialize_impl::value | t = new T(); ser.primitive(*t); break; + case serializer::MAP: + // Add your code here + break; } } }; @@ -313,8 +379,9 @@ class serialize_impl> // } // }; -// All calls to serialize objects need to go through this function so -// that pointer tracking can be done +// All calls to serialize objects need to go through one of the +// following functions, or through the serialize template so that +// pointer tracking can be done. template inline void operator&(serializer& ser, T& t) @@ -328,10 +395,34 @@ operator|(serializer& ser, T& t) { serialize().serialize_and_track_pointer(t, ser); } + +template +inline void +sst_map_object(serializer& ser, T& t, const char* name) +{ + // This function is only used in mapping mode. If we're not in + // mapping mode, we will just call into the basic + // serialize()(t,ser) path. + if ( ser.mode() == serializer::MAP ) { + serialize()(t,ser,name); + } + else { + serialize()(t,ser); + } +} + +// Serialization macros for checkpoint/debug serialization +// #define SST_SER(obj) ser& obj; +#define SST_SER(obj) sst_map_object(ser, obj, #obj); +#define SST_SER_AS_PTR(obj) ser | obj; + } // namespace Serialization } // namespace Core } // namespace SST +// These includes have guards to print warnings if they are included +// independent of this file. Set the #define that will disable the +// warnings. #define SST_INCLUDING_SERIALIZE_H #include "sst/core/serialization/impl/serialize_array.h" #include "sst/core/serialization/impl/serialize_atomic.h" @@ -342,6 +433,8 @@ operator|(serializer& ser, T& t) #include "sst/core/serialization/impl/serialize_set.h" #include "sst/core/serialization/impl/serialize_string.h" #include "sst/core/serialization/impl/serialize_vector.h" +// Reenble warnings for including the above file independent of this +// file. #undef SST_INCLUDING_SERIALIZE_H #endif // SST_CORE_SERIALIZATION_SERIALIZE_H diff --git a/src/sst/core/serialization/serializer.cc b/src/sst/core/serialization/serializer.cc index 9c399df27..41289c16a 100644 --- a/src/sst/core/serialization/serializer.cc +++ b/src/sst/core/serialization/serializer.cc @@ -74,6 +74,7 @@ ser_sizer::size_string(std::string& str) } // namespace pvt + void serializer::string(std::string& str) { @@ -93,6 +94,8 @@ serializer::string(std::string& str) unpacker_.unpack_string(str); break; } + case MAP: + break; } } diff --git a/src/sst/core/serialization/serializer.h b/src/sst/core/serialization/serializer.h index 3d0ad0470..15f722e3a 100644 --- a/src/sst/core/serialization/serializer.h +++ b/src/sst/core/serialization/serializer.h @@ -12,10 +12,16 @@ #ifndef SST_CORE_SERIALIZATION_SERIALIZER_H #define SST_CORE_SERIALIZATION_SERIALIZER_H +// These includes have guards to print warnings if they are included +// independent of this file. Set the #define that will disable the +// warnings. #define SST_INCLUDING_SERIALIZER_H +#include "sst/core/serialization/impl/mapper.h" #include "sst/core/serialization/impl/packer.h" #include "sst/core/serialization/impl/sizer.h" #include "sst/core/serialization/impl/unpacker.h" +// Reenble warnings for including the above file independent of this +// file. #undef SST_INCLUDING_SERIALIZER_H #include @@ -37,12 +43,14 @@ namespace Serialization { class serializer { public: - typedef enum { SIZER, PACK, UNPACK } SERIALIZE_MODE; + enum SERIALIZE_MODE { SIZER, PACK, UNPACK, MAP }; public: serializer() : mode_(SIZER) // just sizing by default {} + pvt::ser_mapper& mapper() { return mapper_; } + pvt::ser_packer& packer() { return packer_; } pvt::ser_unpacker& unpacker() { return unpacker_; } @@ -94,6 +102,8 @@ class serializer case UNPACK: unpacker_.unpack(t); break; + case MAP: + break; } } @@ -118,6 +128,8 @@ class serializer ::memcpy(arr, charstr, N * sizeof(T)); break; } + case MAP: + break; } } @@ -152,6 +164,8 @@ class serializer } break; } + case MAP: + break; } } @@ -191,6 +205,12 @@ class serializer ser_pointer_map.clear(); } + void start_mapping(ObjectMap* obj) + { + mapper_.init(obj); + mode_ = MAP; + } + size_t size() const { switch ( mode_ ) { @@ -200,6 +220,8 @@ class serializer return packer_.size(); case UNPACK: return unpacker_.size(); + case MAP: + break; } return 0; } @@ -222,6 +244,13 @@ class serializer return 0; } + ObjectMap* check_pointer_map(uintptr_t ptr) + { + auto it = ser_pointer_map.find(ptr); + if ( it != ser_pointer_map.end() ) { return reinterpret_cast(it->second); } + return nullptr; + } + inline void report_new_pointer(uintptr_t real_ptr) { ser_pointer_map[split_key] = real_ptr; } inline void report_real_pointer(uintptr_t ptr, uintptr_t real_ptr) { ser_pointer_map[ptr] = real_ptr; } @@ -230,16 +259,23 @@ class serializer inline bool is_pointer_tracking_enabled() { return enable_ptr_tracking_; } + inline void report_object_map(ObjectMap* ptr) + { + ser_pointer_map[reinterpret_cast(ptr->getAddr())] = reinterpret_cast(ptr); + } + protected: // only one of these is going to be valid for this serializer // not very good class design, but a little more convenient pvt::ser_packer packer_; pvt::ser_unpacker unpacker_; pvt::ser_sizer sizer_; + pvt::ser_mapper mapper_; SERIALIZE_MODE mode_; bool enable_ptr_tracking_ = false; std::set ser_pointer_set; + // Used for unpacking and mapping std::map ser_pointer_map; uintptr_t split_key; }; diff --git a/src/sst/core/shared/sharedArray.h b/src/sst/core/shared/sharedArray.h index 9c04a30d3..15cfa720e 100644 --- a/src/sst/core/shared/sharedArray.h +++ b/src/sst/core/shared/sharedArray.h @@ -227,6 +227,9 @@ class SharedArray : public SharedObject data = manager.getSharedObjectData(name); break; } + case SST::Core::Serialization::serializer::MAP: + // Add your code here + break; }; } ImplementSerializable(SST::Shared::SharedArray) @@ -618,6 +621,9 @@ class SharedArray : public SharedObject data = manager.getSharedObjectData(name); break; } + case SST::Core::Serialization::serializer::MAP: + // Add your code here + break; }; } ImplementSerializable(SST::Shared::SharedArray) diff --git a/src/sst/core/shared/sharedMap.h b/src/sst/core/shared/sharedMap.h index fb242989d..53fc5f11f 100644 --- a/src/sst/core/shared/sharedMap.h +++ b/src/sst/core/shared/sharedMap.h @@ -239,6 +239,9 @@ class SharedMap : public SharedObject data = manager.getSharedObjectData(name); break; } + case SST::Core::Serialization::serializer::MAP: + // Add your code here + break; }; } ImplementSerializable(SST::Shared::SharedMap) diff --git a/src/sst/core/shared/sharedSet.h b/src/sst/core/shared/sharedSet.h index a147fccca..1639ad644 100644 --- a/src/sst/core/shared/sharedSet.h +++ b/src/sst/core/shared/sharedSet.h @@ -207,6 +207,9 @@ class SharedSet : public SharedObject data = manager.getSharedObjectData(name); break; } + case SST::Core::Serialization::serializer::MAP: + // Add your code here + break; }; } ImplementSerializable(SST::Shared::SharedSet) diff --git a/src/sst/core/simulation.cc b/src/sst/core/simulation.cc index 1ad5b4861..ace4f810c 100644 --- a/src/sst/core/simulation.cc +++ b/src/sst/core/simulation.cc @@ -1308,6 +1308,22 @@ Simulation_impl::intializeProfileTools(const std::string& config) #endif } +SST::Core::Serialization::ObjectMap* +Simulation_impl::getComponentObjectMap() +{ + SST::Core::Serialization::serializer ser; + SST::Core::Serialization::ObjectMapClass* obj_map = new SST::Core::Serialization::ObjectMapClass(); + ser.enable_pointer_tracking(); + ser.start_mapping(obj_map); + for ( auto comp = compInfoMap.begin(); comp != compInfoMap.end(); comp++ ) { + ComponentInfo* compinfo = *comp; + // ser& compinfo->component; + sst_map_object(ser, compinfo->component, compinfo->getName().c_str()); + } + return obj_map; +} + + void Simulation_impl::scheduleCheckpoint() { diff --git a/src/sst/core/simulation_impl.h b/src/sst/core/simulation_impl.h index 378c8f977..f4fc03cb4 100644 --- a/src/sst/core/simulation_impl.h +++ b/src/sst/core/simulation_impl.h @@ -64,6 +64,10 @@ class StatisticOutput; class StatisticProcessingEngine; } // namespace Statistics +namespace Serialization { +class ObjectMap; +} // namespace Serialization + /** * Main control class for a SST Simulation. * Provides base features for managing the simulation @@ -72,6 +76,8 @@ class Simulation_impl { public: + SST::Core::Serialization::ObjectMap* getComponentObjectMap(); + /******** Public API inherited from Simulation ********/ /** Get the run mode of the simulation (e.g. init, run, both etc) */ SimulationRunMode getSimulationMode() const { return runMode; }; diff --git a/src/sst/core/statapi/statbase.h b/src/sst/core/statapi/statbase.h index 37fa2842d..b9f096f32 100644 --- a/src/sst/core/statapi/statbase.h +++ b/src/sst/core/statapi/statbase.h @@ -607,7 +607,7 @@ class serialize_impl*> { template friend class serialize; - void operator()(Statistics::Statistic*& s, serializer& ser) + void operator()(Statistics::Statistic*& s, serializer& ser, const char* UNUSED(name) = nullptr) { // For sizer and pack, need to get the information needed // to create a new statistic of the correct type on unpack. @@ -642,8 +642,16 @@ class serialize_impl*> if ( stattype != "sst.NullStatistic" ) { SST::Stat::pvt::registerStatWithEngineOnRestart(s); } break; } + case serializer::MAP: + // Mapping mode not supported for stats + break; } } + + // void operator()(Statistics::Statistic*& UNUSED(s), serializer& UNUSED(ser), const char* UNUSED(name)) + // { + // // Mapping mode not supported for stats + // } }; } // namespace Serialization diff --git a/src/sst/core/timeConverter.h b/src/sst/core/timeConverter.h index cc37ef6e6..a1bb8fe62 100644 --- a/src/sst/core/timeConverter.h +++ b/src/sst/core/timeConverter.h @@ -72,7 +72,7 @@ class SST::Core::Serialization::serialize_impl template friend class serialize; // Function implemented in timeLord.cc - void operator()(TimeConverter*& s, SST::Core::Serialization::serializer& ser); + void operator()(TimeConverter*& s, SST::Core::Serialization::serializer& ser, const char* name = nullptr); }; } // namespace SST diff --git a/src/sst/core/timeLord.cc b/src/sst/core/timeLord.cc index 2b9131bb1..b0b5fcf55 100644 --- a/src/sst/core/timeLord.cc +++ b/src/sst/core/timeLord.cc @@ -182,9 +182,68 @@ TimeConverter::getPeriod() const return Simulation_impl::getTimeLord()->getTimeBase() * factor; } +namespace Core { +namespace Serialization { + +template<> +class ObjectMapFundamental : public ObjectMap +{ +protected: + + /** + Address of the variable for reading and writing + */ + TimeConverter** addr_ = nullptr; + +public: + + // We'll treat this as a period when printing + std::string get() override + { + TimeLord* timelord = Simulation_impl::getTimeLord(); + UnitAlgebra base = timelord->getTimeBase(); + base *= (*addr_)->getFactor(); + return base.toStringBestSI(); + } + + void set_impl(const std::string& value) override { return; } + + // We'll act like we're a fundamental type + bool isFundamental() override { return true; } + + /** + Get the address of the variable represented by the ObjectMap + + @return Address of varaible + */ + void* getAddr() override { return addr_; } + + + /** + Get the list of child variables contained in this ObjectMap, + which in this case will be empty. + + @return Refernce to vector containing ObjectMaps for this + ObjectMap's child variables. This vector will be empty because + fundamentals have no children + */ + const std::vector>& getVariables() override { return emptyVars; } + + ObjectMapFundamental(TimeConverter** addr) : + ObjectMap(), + addr_(addr) + {} + + std::string getType() override + { + return demangle_name(typeid(TimeConverter).name()); + } +}; + + void -SST::Core::Serialization::serialize_impl::operator()( - TimeConverter*& s, SST::Core::Serialization::serializer& ser) +serialize_impl::operator()( + TimeConverter*& s, SST::Core::Serialization::serializer& ser, const char* name) { SimTime_t factor = 0; @@ -196,6 +255,7 @@ SST::Core::Serialization::serialize_impl::operator()( ser& factor; break; case serializer::UNPACK: + { ser& factor; // If we put in a nullptr, return a nullptr @@ -212,5 +272,15 @@ SST::Core::Serialization::serialize_impl::operator()( s = timelord->getTimeConverter(base); break; } + case serializer::MAP: + printf("Mapping a UnitAlgebra\n"); + ObjectMap* obj_map = new ObjectMapFundamental(&s); + ser.mapper().map_primitive(name, obj_map); + break; + } } + +} // namespace Serialization +} // namespace Core + } // namespace SST diff --git a/src/sst/core/timeVortex.h b/src/sst/core/timeVortex.h index 2e526987b..5010bb1ed 100644 --- a/src/sst/core/timeVortex.h +++ b/src/sst/core/timeVortex.h @@ -85,6 +85,9 @@ class SST::Core::Serialization::serialize_impl case serializer::UNPACK: TV::pvt::unpack_timevortex(s, ser); break; + case serializer::MAP: + // Add your code here + break; } } }; diff --git a/src/sst/core/unitAlgebra.h b/src/sst/core/unitAlgebra.h index 5beaa0293..9681f68d8 100644 --- a/src/sst/core/unitAlgebra.h +++ b/src/sst/core/unitAlgebra.h @@ -15,6 +15,7 @@ #define SST_CORE_UNITALGEBRA_H #include "sst/core/decimal_fixedpoint.h" +#include "sst/core/serialization/objectMap.h" #include "sst/core/serialization/serializable.h" #include "sst/core/serialization/serializer.h" #include "sst/core/sst_types.h" @@ -103,9 +104,7 @@ class Units * Allows operations such as multiplying a frequency by 2. * */ -class UnitAlgebra : - public SST::Core::Serialization::serializable, - public SST::Core::Serialization::serializable_type +class UnitAlgebra /*: public SST::Core::Serialization::serializable */ { private: Units unit; @@ -227,7 +226,7 @@ class UnitAlgebra : double getDoubleValue() const; bool isValueZero() const; - void serialize_order(SST::Core::Serialization::serializer& ser) override + void serialize_order(SST::Core::Serialization::serializer& ser)/* override */ { // Do the unit ser& unit.numerator; @@ -251,9 +250,12 @@ class UnitAlgebra : value = sst_big_num(s); break; } + case SST::Core::Serialization::serializer::MAP: + // Add your code here + break; } } - ImplementSerializable(SST::UnitAlgebra) + // ImplementSerializable(SST::UnitAlgebra) public: /** Base exception for all exception classes in UnitAlgebra @@ -403,6 +405,89 @@ operator<<(std::ostream& os, const Units& r) return os; } + +namespace Core { +namespace Serialization { + +template<> +class ObjectMapFundamental : public ObjectMap +{ +protected: + + /** + Address of the variable for reading and writing + */ + UnitAlgebra* addr_ = nullptr; + +public: + std::string get() override { return addr_->toStringBestSI(); } + void set_impl(const std::string& value) override { addr_->init(value); } + + // We'll act like we're a fundamental type + bool isFundamental() override { return true; } + + /** + Get the address of the variable represented by the ObjectMap + + @return Address of varaible + */ + void* getAddr() override { return addr_; } + + + /** + Get the list of child variables contained in this ObjectMap, + which in this case will be empty. + + @return Refernce to vector containing ObjectMaps for this + ObjectMap's child variables. This vector will be empty because + fundamentals have no children + */ + const std::vector>& getVariables() override { return emptyVars; } + + ObjectMapFundamental(UnitAlgebra* addr) : + ObjectMap(), + addr_(addr) + {} + + std::string getType() override + { + return demangle_name(typeid(UnitAlgebra).name()); + } +}; + +template <> +class serialize_impl +{ + template + friend class serialize; + + void operator()(UnitAlgebra& ua, serializer& ser) + { + switch ( ser.mode() ) { + case serializer::SIZER: + case serializer::PACK: + case serializer::UNPACK: + ua.serialize_order(ser); + break; + case serializer::MAP: + // Add your code here + break; + } + } + + void operator()(UnitAlgebra& ua, serializer& ser, const char* name) + { + printf("Mapping a UnitAlgebra\n"); + ObjectMap* obj_map = new ObjectMapFundamental(&ua); + ser.mapper().map_primitive(name, obj_map); + } +}; + + +} // namespace Serialization +} // namespace Core + + } // namespace SST #endif // SST_CORE_UNITALGEBRA_H