SST  11.0.0
StructuralSimulationToolkit
sharedSet.h
1 // Copyright 2009-2021 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-2021, 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_CORE_SHARED_SHAREDSET_H
13 #define SST_CORE_CORE_SHARED_SHAREDSET_H
14 
15 #include "sst/core/sst_types.h"
16 #include "sst/core/shared/sharedObject.h"
17 
18 #include <set>
19 
20 namespace SST {
21 namespace Shared {
22 
23 /**
24  SharedSet class. The class is templated to allow for an array
25  of any non-pointer type. The type must be serializable.
26  */
27 template <typename valT>
28 class SharedSet : public SharedObject {
29  static_assert(!std::is_pointer<valT>::value, "Cannot use a pointer type as value with SharedSet");
30 
31  // Forward declaration. Defined below
32  class Data;
33 
34 public:
35 
36  SharedSet() :
37  SharedObject(), published(false), data(nullptr)
38  {}
39 
40  ~SharedSet() {
41  // data does not need to be deleted since the
42  // SharedObjectManager owns the pointer
43  }
44 
45 
46  /**
47  Initialize the SharedSet.
48 
49  @param obj_name Name of the object. This name is how the
50  object is uniquely identified across ranks.
51 
52  @param verify_mode Specifies how multiply written data should
53  be verified. Since the underlying set knows if the data has
54  already been written, FE_VERIFY and INIT_VERIFY simply use this
55  built-in mechanism to know when an item has previously been
56  written. When these modes are enabled, multiply written data
57  must match what was written before. When NO_VERIFY is passed,
58  no verification will occur. This is mostly useful when you can
59  guarantee that multiple elements won't write the same value and
60  you want to do in-place modifications as you initialize.
61  VERIFY_UNINITIALIZED is a reserved value and should not be
62  passed.
63 
64  @return returns the number of instances that have intialized
65  themselve before this instance on this MPI rank.
66  */
67  int initialize(const std::string& obj_name, verify_type v_type) {
68  if ( data ) {
70  CALL_INFO,1,"ERROR: called initialize() of SharedSet %s more than once\n",obj_name.c_str());
71  }
72 
73  data = manager.getSharedObjectData<Data>(obj_name);
74  int ret = incShareCount(data);
75  data->setVerify(v_type);
76  return ret;
77  }
78 
79  /*** Typedefs and functions to mimic parts of the vector API ***/
80  typedef typename std::set<valT>::const_iterator const_iterator;
81  typedef typename std::set<valT>::const_reverse_iterator const_reverse_iterator;
82 
83  /**
84  Get the size of the set.
85 
86  @return size of the set
87  */
88  inline size_t size() const { return data->getSize(); }
89 
90  /**
91  Tests if the set is empty.
92 
93  @return true if set is empty, false otherwise
94  */
95  inline bool empty() const { return data->set.empty(); }
96 
97 
98  /**
99  Counts elements with a specific value. Becuase this is not a
100  multiset, it will either return 1 or 0.
101 
102  @return Count of elements with specified value
103  */
104  size_t count (const valT& k) const {
105  return data->set.count(k);
106  }
107 
108  /**
109  Get const_iterator to beginning of underlying set
110  */
111  const_iterator begin() const {
112  return data->set.cbegin();
113  }
114 
115  /**
116  Get const_iterator to end of underlying set
117  */
118  const_iterator end() const {
119  return data->set.cend();
120  }
121 
122  /**
123  Get const_reverse_iterator to beginning of underlying set
124  */
125  const_reverse_iterator rbegin() const {
126  return data->set.crbegin();
127  }
128 
129  /**
130  Get const_reverse_iterator to end of underlying set
131  */
132  const_reverse_iterator rend() const {
133  return data->set.crend();
134  }
135 
136 
137  /**
138  Indicate that the calling element has written all the data it
139  plans to write. Writing to the set through this instance
140  after publish() is called will create an error.
141  */
142  void publish() {
143  if ( published ) return;
144  published = true;
145  incPublishCount(data);
146  }
147 
148  /**
149  Check whether all instances of this SharedSet have called
150  publish(). NOTE: Is is possible that this could return true
151  one round, but false the next if a new instance of the
152  SharedSet was initialized but not published after the last
153  call.
154  */
156  return data->isFullyPublished();
157  }
158 
159 
160  /**
161  Insert data to the set. This function is thread-safe, as a
162  mutex is used to ensure only one insert at a time.
163 
164  @param val value of the insert
165  */
166  inline void insert(const valT& value) {
167  if ( published ) {
169  CALL_INFO,1,"ERROR: insert into SharedSet %s after publish() was called\n",
170  data->getName().c_str());
171  }
172  return data->write(value);
173  }
174 
175  /**
176  Searches the SharedSet for an element equivalent to value and
177  returns a const iterator to it if found, otherwise it returns
178  an iterator to SharedSet::end.
179 
180  @param value value to search for
181 
182  NOTE: This function does not use a mutex, so it is possible to
183  get invalid results if another thread is simulateously writing
184  to the set. However, after the init() phase of simulation is
185  complete (in setup() and beyond), this is always a safe
186  operation. If reading during init() and you can't guarantee
187  that all elements have already written all elements to the
188  SharedSet, use mutex_find() to guarantee thread safety.
189 
190  @return read-only iterator to data referenced by value
191  */
192  inline const_iterator find(const valT& value) const {
193  return data->find(value);
194  }
195 
196  /**
197  Searches the SharedSet for an element equivalent to value and
198  returns a const iterator to it if found, otherwise it returns
199  an iterator to SharedSet::end. This version of find is always thread safe (@see
200  find()).
201 
202  @param value value to search for
203 
204  @return read-only iterator to data reference by value
205  */
206  inline const valT& mutex_find(const valT& value) const {
207  return data->mutex_read(value);
208  }
209 
210 
211 private:
212  bool published;
213  Data* data;
214 
215 
216  class Data : public SharedObjectData {
217 
218  // Forward declaration. Defined below
219  class ChangeSet;
220 
221  public:
222 
223  std::set<valT> set;
224  ChangeSet* change_set;
225 
226  verify_type verify;
227 
228  Data(const std::string& name) :
229  SharedObjectData(name),
230  change_set(nullptr),
231  verify(VERIFY_UNINITIALIZED)
232  {
233  if ( Simulation::getSimulation()->getNumRanks().rank > 1 ) {
234  change_set = new ChangeSet(name);
235  }
236  }
237 
238  ~Data() {
239  delete change_set;
240  }
241 
242  void setVerify(verify_type v_type) {
243  if ( v_type != verify && verify != VERIFY_UNINITIALIZED ) {
245  CALL_INFO,1,"ERROR: Type different verify_types specified for SharedSet %s\n",name.c_str());
246  }
247  verify = v_type;
248  if ( change_set ) change_set->setVerify(v_type);
249  }
250 
251  size_t getSize() const {
252  std::lock_guard<std::mutex> lock(mtx);
253  return set.size();
254  }
255 
256  void update_write(const valT& value) {
257  // Don't need to mutex because this is only ever called
258  // from one thread at a time, with barrier before and
259  // after, or from write(), which does mutex.
260  auto success = set.insert(value);
261  if ( !success.second ) {
262  // Wrote to a value that already existed
263  if ( verify != NO_VERIFY && !(value == *(success.first)) ) {
265  CALL_INFO, 1, "ERROR: wrote two non-equal values to same set item in SharedSet %s\n",name.c_str());
266  }
267  }
268  }
269 
270  void write(const valT& value) {
271  // std::lock_guard<std::mutex> lock(mtx);
272  check_lock_for_write("SharedSet");
273  update_write(value);
274  if ( change_set ) change_set->addChange(value);
275  }
276 
277  // Inline the read since it may be called often during run().
278  // This read is not protected from data races in the case
279  // where the set may be simulataeously written by another
280  // thread. If there is a danger of simultaneous access
281  // during init, use the mutex_read function until after the
282  // init phase.
283  inline const_iterator find(const valT& value) {
284  return set.find(value);
285  }
286 
287  // Mutexed read for use if you are resizing the array as you go
288  inline const valT& mutex_find(const valT& value) {
289  std::lock_guard<std::mutex> lock(mtx);
290  auto ret = set.find(value);
291  return ret;
292  }
293 
294  // Functions inherited from SharedObjectData
295  virtual SharedObjectChangeSet* getChangeSet() override {
296  return change_set;
297  }
298  virtual void resetChangeSet() override {
299  change_set->clear();
300  }
301 
302  private:
303  class ChangeSet : public SharedObjectChangeSet {
304 
305  std::set<valT> changes;
306  verify_type verify;
307 
308  void serialize_order(SST::Core::Serialization::serializer& ser) override {
309  SharedObjectChangeSet::serialize_order(ser);
310  ser & changes;
311  ser & verify;
312  }
313 
314  ImplementSerializable(SST::Shared::SharedSet<valT>::Data::ChangeSet);
315 
316  public:
317  // For serialization
318  ChangeSet() :
319  SharedObjectChangeSet(),
320  verify(VERIFY_UNINITIALIZED)
321  {}
322  ChangeSet(const std::string& name) :
323  SharedObjectChangeSet(name),
324  verify(VERIFY_UNINITIALIZED)
325  {}
326 
327  void addChange(const valT& value) {
328  changes.insert(value);
329  }
330 
331  void setVerify(verify_type v_type) {
332  verify = v_type;
333  }
334 
335  void applyChanges(SharedObjectDataManager* manager) override {
336  auto data = manager->getSharedObjectData<Data>(getName());
337  data->setVerify(verify);
338  for ( auto x : changes ) {
339  data->update_write(x);
340  }
341  }
342 
343  void clear() override {
344  changes.clear();
345  }
346  };
347  };
348 
349 
350 
351 };
352 
353 } // namespace Shared
354 } // namespace SST
355 
356 #endif
This class is basically a wrapper for objects to declare the order in which their members should be s...
Definition: serializer.h:35
Definition: sharedObject.h:263
static Simulation * getSimulation()
Return a pointer to the singleton instance of the Simulation.
Definition: simulation.cc:52
SharedSet class.
Definition: sharedSet.h:28
Definition: sharedRegionImpl.h:31
void lock()
Called by the core when writing to shared regions is no longer allowed.
Definition: sharedObject.h:185
size_t size() const
Get the size of the set.
Definition: sharedSet.h:88
size_t count(const valT &k) const
Counts elements with a specific value.
Definition: sharedSet.h:104
const std::string & getName()
Get the name of the shared data the changeset should be applied to.
Definition: sharedObject.h:68
const_iterator begin() const
Get const_iterator to beginning of underlying set.
Definition: sharedSet.h:111
const_iterator end() const
Get const_iterator to end of underlying set.
Definition: sharedSet.h:118
verify_type
Enum of verify types.
Definition: sharedObject.h:271
const_reverse_iterator rend() const
Get const_reverse_iterator to end of underlying set.
Definition: sharedSet.h:132
const_reverse_iterator rbegin() const
Get const_reverse_iterator to beginning of underlying set.
Definition: sharedSet.h:125
bool isFullyPublished()
Check whether all instances of this SharedSet have called publish().
Definition: sharedSet.h:155
void fatal(uint32_t line, const char *file, const char *func, int exit_code, const char *format,...) const
Output the fatal message with formatting as specified by the format parameter.
Definition: output.cc:155
const_iterator find(const valT &value) const
Searches the SharedSet for an element equivalent to value and returns a const iterator to it if found...
Definition: sharedSet.h:192
void publish()
Indicate that the calling element has written all the data it plans to write.
Definition: sharedSet.h:142
virtual void applyChanges(SharedObjectDataManager *UNUSED(manager))=0
Apply the changes to the name shared data.
static Output & getSimulationOutput()
Return the base simulation Output class instance.
Definition: simulation.cc:70
const valT & mutex_find(const valT &value) const
Searches the SharedSet for an element equivalent to value and returns a const iterator to it if found...
Definition: sharedSet.h:206
int initialize(const std::string &obj_name, verify_type v_type)
Initialize the SharedSet.
Definition: sharedSet.h:67
void insert(const valT &value)
Insert data to the set.
Definition: sharedSet.h:166
Base class for holding SharedObject data.
Definition: sharedObject.h:87
bool empty() const
Tests if the set is empty.
Definition: sharedSet.h:95