SST  15.1.0
StructuralSimulationToolkit
sharedObject.h
1 // Copyright 2009-2025 NTESS. Under the terms
2 // of Contract DE-NA0003525 with NTESS, the U.S.
3 // Government retains certain rights in this software.
4 //
5 // Copyright (c) 2009-2025, NTESS
6 // All rights reserved.
7 //
8 // This file is part of the SST software package. For license
9 // information, see the LICENSE file in the top level directory of the
10 // distribution.
11 
12 #ifndef SST_CORE_SHARED_SHAREDOBJECT_H
13 #define SST_CORE_SHARED_SHAREDOBJECT_H
14 
15 #include "sst/core/output.h"
16 #include "sst/core/rankInfo.h"
17 #include "sst/core/serialization/serializable.h"
18 #include "sst/core/sst_types.h"
19 
20 #include <map>
21 #include <mutex>
22 #include <string>
23 
24 /* Forward declare for Friendship */
25 extern int main(int argc, char** argv);
26 
27 namespace SST {
28 
29 class Simulation_impl;
30 
31 namespace Shared {
32 
33 namespace Private {
34 Output& getSimulationOutput();
35 RankInfo getNumRanks();
36 } // namespace Private
37 
38 // NOTE: The classes in this header file are not part of the public
39 // API and can change at any time
40 
41 class SharedObjectDataManager;
42 
43 /**
44  This is the base class for holding data on changes made to the
45  shared data on each rank. This data will be serialized and shared
46  with all ranks in the simulation.
47  */
49 {
50 
51 public:
53  explicit SharedObjectChangeSet(const std::string& name) :
54  name(name)
55  {}
56 
57  /**
58  Apply the changes to the name shared data.
59 
60  @param manager The SharedObjectDataManager for the rank. This
61  is used to get the named shared data.
62  */
63  virtual void applyChanges(SharedObjectDataManager* manager) = 0;
64 
65  /**
66  Clears the data. Used after transfering data to other ranks to
67  prepare for the next round of init. Child classes should call
68  this version of clear() in there implementations.
69  */
70  virtual void clear() = 0;
71 
72  /**
73  Get the name of the shared data the changeset should be applied
74  to
75 
76  @return name of shared data to apply changes to
77  */
78  const std::string& getName() { return name; }
79 
80 protected:
81  void serialize_order(SST::Core::Serialization::serializer& ser) override { SST_SER(name); }
82 
83  ImplementVirtualSerializable(SharedObjectChangeSet);
84 
85 private:
86  std::string name;
87 };
88 
89 /**
90  Base class for holding SharedObject data. The base class is needed
91  so that we can have an API to manage unknown types of objects.
92 */
94 {
95 
96  friend class SharedObjectDataManager;
97  friend class SharedObject;
98 
99 public:
100  /**
101  Get the name of the SharedObject for this data
102 
103  @return name of data
104  */
105  const std::string& getName() { return name; }
106 
107  /**
108  Checks to see if all instances of this SharedObject have called
109  publish(). This is forced to true before the setup() phase of
110  simulation, as no more writes are allowed.
111 
112  @return true if all instances have called publish(), false
113  otherwise.
114  */
115  bool isFullyPublished() { return fully_published; }
116 
117  /**
118  Get the number of sharers for this data
119 
120  @return number of sharers
121  */
122  virtual int getShareCount() { return share_count; }
123 
124  /**
125  Get the number of instances that have called publish() on their
126  instance of the shared object
127 
128  @return number of instances that have called publish()
129  */
130  virtual int getPublishCount() { return publish_count; }
131 
132 protected:
133  std::string name;
134  int share_count;
135  int publish_count;
136  bool fully_published;
137  bool locked;
138 
139  // Mutex for locking across threads
140  mutable std::mutex mtx;
141 
142  // Check to see if object data is locked. If so, fatal
143  inline void check_lock_for_write(const std::string& obj)
144  {
145  if ( locked ) {
146  Private::getSimulationOutput().fatal(
147  CALL_INFO_LONG, 1, "ERROR: attempt to write to %s %s after init phase\n", obj.c_str(), name.c_str());
148  }
149  }
150 
151  /* Manage counts */
152 
153  /**
154  Increment the count of sharers. This should only be called
155  once per instance.
156  */
157  virtual int incShareCount()
158  {
159  std::lock_guard<std::mutex> lock(mtx);
160  int ret = share_count;
161  share_count++;
162  return ret;
163  }
164  /**
165  Increment the count of instances that have called publish.
166  This should only be called once per instance.
167  */
168  virtual void incPublishCount()
169  {
170  std::lock_guard<std::mutex> lock(mtx);
171  publish_count++;
172  }
173 
174  /* For merging across ranks */
175 
176  /**
177  Gets the changeset for this data on this rank. This is called
178  by the core when exchanging and merging data
179  */
180  virtual SharedObjectChangeSet* getChangeSet() = 0;
181 
182  /**
183  Resets the changeset for this data on this rank. This is called
184  by the core when exchanging and merging data
185  */
186  virtual void resetChangeSet() = 0;
187 
188  /**
189  Called by the core when writing to shared regions is no longer
190  allowed
191  */
192  void lock() { locked = true; }
193 
194  /**
195  Constructor for SharedObjectData
196 
197  @param name name of the SharedObject
198  */
199  explicit SharedObjectData(const std::string& name) :
200  name(name),
201  share_count(0),
202  publish_count(0),
203  fully_published(false),
204  locked(false)
205  {}
206 
207  SharedObjectData() {}
208 
209  /**
210  Destructor for SharedObjectData
211  */
212  virtual ~SharedObjectData() {}
213 
214  void serialize_order(SST::Core::Serialization::serializer& ser) override { SST_SER(name); }
215 
216  ImplementVirtualSerializable(SharedObjectData);
217 };
218 
219 class SharedObjectDataManager //: public SST::Core::Serialization::serializable
220 {
221 
222  std::map<std::string, SharedObjectData*> shared_data;
223 
224  // Mutex for locking across threads
225  static std::mutex mtx;
226  static std::mutex update_mtx;
227 
228  bool locked;
229 
230 public:
232  locked(false)
233  {}
234 
236  {
237  for ( auto x : shared_data ) {
238  delete x.second;
239  }
240  }
241 
242  template <typename T>
243  T* getSharedObjectData(const std::string name)
244  {
245  // Need to lock since we may be initializing the
246  // SharedData object.
247  std::lock_guard<std::mutex> lock(mtx);
248  if ( locked ) {
249  Private::getSimulationOutput().fatal(
250  CALL_INFO, 1, "Attempting to initialize SharedObject %s after the init() phase\n", name.c_str());
251  }
252  auto obj = shared_data.find(name);
253  if ( obj == shared_data.end() ) {
254  // Does not yet exist, create it
255  auto ret = new T(name);
256  shared_data[name] = ret;
257  return ret;
258  }
259 
260  // If it exists, make sure the types match
261  auto obj_cast = dynamic_cast<T*>(obj->second);
262 
263  if ( obj_cast == nullptr ) {
264  Private::getSimulationOutput().fatal(
265  CALL_INFO, 1, "ERROR: Shared object %s requested with two different types\n", name.c_str());
266  }
267 
268  return obj_cast;
269  }
270 
271  void updateState(bool finalize);
272 
273  void serialize_order(SST::Core::Serialization::serializer& ser) { SST_SER(shared_data); }
274 };
275 
277 {
278 
279 public:
280  /**
281  Enum of verify types.
282  */
283  enum verify_type { VERIFY_UNINITIALIZED, FE_VERIFY, INIT_VERIFY, NO_VERIFY };
284 
285  SharedObject() {}
286  virtual ~SharedObject() {}
287 
288  virtual void serialize_order(SST::Core::Serialization::serializer& UNUSED(ser)) override {}
289  ImplementSerializable(SST::Shared::SharedObject)
290 
291 protected:
292  friend class SST::Simulation_impl;
293 
294  // To enable main to initialize manager on restart
295  friend int ::main(int argc, char** argv);
296 
297  static SharedObjectDataManager manager;
298 
299  void incPublishCount(SharedObjectData* data) { data->incPublishCount(); }
300 
301  int incShareCount(SharedObjectData* data) { return data->incShareCount(); }
302 };
303 
304 } // namespace Shared
305 } // namespace SST
306 
307 #endif // SST_CORE_SHARED_SHAREDOBJECT_H
This class is basically a wrapper for objects to declare the order in which their members should be s...
Definition: serializer.h:42
virtual void applyChanges(SharedObjectDataManager *manager)=0
Apply the changes to the name shared data.
Definition: sharedObject.h:276
virtual SharedObjectChangeSet * getChangeSet()=0
Gets the changeset for this data on this rank.
virtual int getShareCount()
Get the number of sharers for this data.
Definition: sharedObject.h:122
void lock()
Called by the core when writing to shared regions is no longer allowed.
Definition: sharedObject.h:192
bool isFullyPublished()
Checks to see if all instances of this SharedObject have called publish().
Definition: sharedObject.h:115
const std::string & getName()
Get the name of the shared data the changeset should be applied to.
Definition: sharedObject.h:78
Definition: action.cc:18
SharedObjectData(const std::string &name)
Constructor for SharedObjectData.
Definition: sharedObject.h:199
verify_type
Enum of verify types.
Definition: sharedObject.h:283
Definition: serializable.h:23
virtual void incPublishCount()
Increment the count of instances that have called publish.
Definition: sharedObject.h:168
Definition: sharedObject.h:219
Main control class for a SST Simulation.
Definition: simulation_impl.h:122
virtual int getPublishCount()
Get the number of instances that have called publish() on their instance of the shared object...
Definition: sharedObject.h:130
virtual int incShareCount()
Increment the count of sharers.
Definition: sharedObject.h:157
const std::string & getName()
Get the name of the SharedObject for this data.
Definition: sharedObject.h:105
virtual void clear()=0
Clears the data.
virtual void resetChangeSet()=0
Resets the changeset for this data on this rank.
This is the base class for holding data on changes made to the shared data on each rank...
Definition: sharedObject.h:48
Base class for holding SharedObject data.
Definition: sharedObject.h:93
virtual ~SharedObjectData()
Destructor for SharedObjectData.
Definition: sharedObject.h:212