SST  11.0.0
StructuralSimulationToolkit
sharedMap.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_SHAREDMAP_H
13 #define SST_CORE_CORE_SHARED_SHAREDMAP_H
14 
15 #include "sst/core/sst_types.h"
16 #include "sst/core/shared/sharedObject.h"
17 
18 #include <map>
19 
20 namespace SST {
21 namespace Shared {
22 
23 /**
24  SharedMap class. The class is templated to allow for Map of any
25  non-pointer type as value. The type must be serializable.
26  */
27 template <typename keyT, typename valT>
28 class SharedMap : public SharedObject {
29  static_assert(!std::is_pointer<valT>::value, "Cannot use a pointer type as value with SharedMap");
30 
31  // Forward declaration. Defined below
32  class Data;
33 
34 public:
35 
36  SharedMap() :
37  SharedObject(), published(false), data(nullptr)
38  {}
39 
40  ~SharedMap() {
41  // data does not need to be deleted since the
42  // SharedObjectManager owns the pointer
43  }
44 
45 
46  /**
47  Initialize the SharedMap.
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 map 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 = FE_VERIFY) {
68  if ( data ) {
70  CALL_INFO,1,"ERROR: called initialize() of SharedMap %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::map<keyT,valT>::const_iterator const_iterator;
81  typedef typename std::map<keyT,valT>::const_reverse_iterator const_reverse_iterator;
82 
83  /**
84  Get the size of the map.
85 
86  @return size of the map
87  */
88  inline size_t size() const { return data->getSize(); }
89 
90  /**
91  Tests if the map is empty.
92 
93  @return true if map is empty, false otherwise
94  */
95  inline bool empty() const { return data->map.empty(); }
96 
97 
98  /**
99  Counts elements with a specific key. Becuase this is not a
100  multimap, it will either return 1 or 0.
101 
102  @return Count of elements with specified key
103  */
104  size_t count (const keyT& k) const {
105  return data->map.count(k);
106  }
107 
108  /**
109  Searches the container for an element with a key equivalent to
110  k and returns an iterator to it if found, otherwise it returns
111  an iterator to SharedMap::end().
112 
113  @param key key to search for
114  */
115  const_iterator find (const keyT& key) const {
116  return data->map.find(key);
117  }
118 
119  /**
120  Get const_iterator to beginning of underlying map
121  */
122  const_iterator begin() const {
123  return data->map.cbegin();
124  }
125 
126  /**
127  Get const_iterator to end of underlying map
128  */
129  const_iterator end() const {
130  return data->map.cend();
131  }
132 
133  /**
134  Get const_reverse_iterator to beginning of underlying map
135  */
136  const_reverse_iterator rbegin() const {
137  return data->map.crbegin();
138  }
139 
140  /**
141  Get const_reverse_iterator to end of underlying map
142  */
143  const_reverse_iterator rend() const {
144  return data->map.crend();
145  }
146 
147  /**
148  Returns an iterator pointing to the first element in the
149  container whose key is not considered to go before k (i.e.,
150  either it is equivalent or goes after).
151 
152  @param key key to compare to
153  */
154  inline const_iterator lower_bound(const keyT& key) const {
155  return data->map.lower_bound(key);
156  }
157 
158  /**
159  Returns an iterator pointing to the first element in the
160  container whose key is considered to go after k.
161 
162  @param key key to compare to
163  */
164  inline const_iterator upper_bound(const keyT& key) const {
165  return data->map.lower_bound(key);
166  }
167 
168  /**
169  Indicate that the calling element has written all the data it
170  plans to write. Writing to the map through this instance
171  after publish() is called will create an error.
172  */
173  void publish() {
174  if ( published ) return;
175  published = true;
176  incPublishCount(data);
177  }
178 
179  /**
180  Check whether all instances of this SharedMap have called
181  publish(). NOTE: Is is possible that this could return true
182  one round, but false the next if a new instance of the
183  SharedMap was initialized but not published after the last
184  call.
185  */
187  return data->isFullyPublished();
188  }
189 
190 
191  /**
192  Write data to the map. This function is thread-safe, as a
193  mutex is used to ensure only one write at a time.
194 
195  @param key key of the write
196 
197  @param value value to be written
198  */
199  inline void write(const keyT& key, const valT& value) {
200  if ( published ) {
202  CALL_INFO,1,"ERROR: write to SharedMap %s after publish() was called\n",
203  data->getName().c_str());
204  }
205  return data->write(key, value);
206  }
207 
208  /**
209  Read data from the map. This returns a const reference, so is
210  read only. If the key is not in the map, an out_of_range
211  exception will be thrown.
212 
213  NOTE: This function does not use a mutex, so it is possible to
214  get invalid results if another thread is simulateously writing
215  to the map. However, after the init() phase of simulation is
216  complete (in setup() and beyond), this is always a safe
217  operation. If reading during init() and you can't guarantee
218  that all elements have already written all elements to the
219  SharedMap, use mutex_read() to guarantee thread safety.
220 
221  @param key key to read
222 
223  @return const reference to data referenced by key
224 
225  @exception std::out_of_range key is not found in map
226  */
227  inline const valT& operator[](const keyT& key) const {
228  return data->read(key);
229  }
230 
231  /**
232  Read data from the map. This returns a const reference, so
233  is read only. This version of read is always thread safe (@see
234  operator[]). If the key is not in the map, an out_of_range
235  exception will be thrown.
236 
237  @param key key to read
238 
239  @return const reference to data at index
240 
241  @exception std::out_of_range key is not found in map
242  */
243  inline const valT& mutex_read(const keyT& key) const {
244  return data->mutex_read(key);
245  }
246 
247 
248 private:
249  bool published;
250  Data* data;
251 
252 
253  class Data : public SharedObjectData {
254 
255  // Forward declaration. Defined below
256  class ChangeSet;
257 
258  public:
259 
260  std::map<keyT,valT> map;
261  ChangeSet* change_set;
262  verify_type verify;
263 
264  Data(const std::string& name) :
265  SharedObjectData(name),
266  change_set(nullptr),
267  verify(VERIFY_UNINITIALIZED)
268  {
269  if ( Simulation::getSimulation()->getNumRanks().rank > 1 ) {
270  change_set = new ChangeSet(name);
271  }
272  }
273 
274  ~Data() {
275  delete change_set;
276  }
277 
278  void setVerify(verify_type v_type) {
279  if ( v_type != verify && verify != VERIFY_UNINITIALIZED ) {
281  CALL_INFO,1,"ERROR: Two different verify_types specified for SharedMap %s\n",name.c_str());
282  }
283  verify = v_type;
284  if ( change_set ) change_set->setVerify(v_type);
285  }
286 
287  size_t getSize() const {
288  return map.size();
289  }
290 
291  void update_write(const keyT& key, const valT& value) {
292  // Don't need to mutex because this is only ever called
293  // from one thread at a time, with barrier before and
294  // after, or from write(), which does mutex.
295  auto success = map.insert(std::make_pair(key,value));
296  if ( !success.second ) {
297  // Wrote to a key that already existed
298  if ( verify != NO_VERIFY && value != success.first->second ) {
300  CALL_INFO, 1, "ERROR: wrote two different values to same key in SharedMap %s\n",name.c_str());
301  }
302  }
303  }
304 
305  void write(const keyT& key, const valT& value) {
306  std::lock_guard<std::mutex> lock(mtx);
307  check_lock_for_write("SharedMap");
308  update_write(key,value);
309  if ( change_set ) change_set->addChange(key,value);
310  }
311 
312  // Inline the read since it may be called often during run().
313  // This read is not protected from data races in the case
314  // where the map may be simulataeously written by another
315  // thread. If there is a danger of simultaneous access
316  // during init, use the mutex_read function until after the
317  // init phase.
318  inline const valT& read(const keyT& key) {
319  return map.at(key);
320  }
321 
322  // Mutexed read for use if you are resizing the array as you go
323  inline const valT& mutex_read(const keyT& key) {
324  std::lock_guard<std::mutex> lock(mtx);
325  auto ret = map.at(key);
326  return ret;
327  }
328 
329  // Functions inherited from SharedObjectData
330  virtual SharedObjectChangeSet* getChangeSet() override {
331  return change_set;
332  }
333  virtual void resetChangeSet() override {
334  change_set->clear();
335  }
336 
337  private:
338  class ChangeSet : public SharedObjectChangeSet {
339 
340  std::map<keyT,valT> changes;
341  verify_type verify;
342 
343  void serialize_order(SST::Core::Serialization::serializer& ser) override {
344  SharedObjectChangeSet::serialize_order(ser);
345  ser & changes;
346  ser & verify;
347  }
348 
350 
351  public:
352  // For serialization
353  ChangeSet() :
354  SharedObjectChangeSet(),
355  verify(VERIFY_UNINITIALIZED)
356  {}
357  ChangeSet(const std::string& name) :
358  SharedObjectChangeSet(name),
359  verify(VERIFY_UNINITIALIZED)
360  {}
361 
362  void addChange(const keyT& key, const valT& value) {
363  changes[key] = value;
364  }
365 
366  void setVerify(verify_type v_type) {
367  verify = v_type;
368  }
369 
370  void applyChanges(SharedObjectDataManager* manager) override {
371  auto data = manager->getSharedObjectData<Data>(getName());
372  data->setVerify(verify);
373  for ( auto x : changes ) {
374  data->update_write(x.first, x.second);
375  }
376  }
377 
378  void clear() override {
379  changes.clear();
380  }
381  };
382  };
383 
384 
385 
386 };
387 
388 } // namespace Shared
389 } // namespace SST
390 
391 #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
bool empty() const
Tests if the map is empty.
Definition: sharedMap.h:95
const_reverse_iterator rbegin() const
Get const_reverse_iterator to beginning of underlying map.
Definition: sharedMap.h:136
Definition: sharedRegionImpl.h:31
void lock()
Called by the core when writing to shared regions is no longer allowed.
Definition: sharedObject.h:185
const_iterator begin() const
Get const_iterator to beginning of underlying map.
Definition: sharedMap.h:122
const std::string & getName()
Get the name of the shared data the changeset should be applied to.
Definition: sharedObject.h:68
bool isFullyPublished()
Check whether all instances of this SharedMap have called publish().
Definition: sharedMap.h:186
const_reverse_iterator rend() const
Get const_reverse_iterator to end of underlying map.
Definition: sharedMap.h:143
int initialize(const std::string &obj_name, verify_type v_type=FE_VERIFY)
Initialize the SharedMap.
Definition: sharedMap.h:67
SharedMap class.
Definition: sharedMap.h:28
const valT & mutex_read(const keyT &key) const
Read data from the map.
Definition: sharedMap.h:243
verify_type
Enum of verify types.
Definition: sharedObject.h:271
const_iterator find(const keyT &key) const
Searches the container for an element with a key equivalent to k and returns an iterator to it if fou...
Definition: sharedMap.h:115
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
size_t size() const
Get the size of the map.
Definition: sharedMap.h:88
void write(const keyT &key, const valT &value)
Write data to the map.
Definition: sharedMap.h:199
size_t count(const keyT &k) const
Counts elements with a specific key.
Definition: sharedMap.h:104
const_iterator lower_bound(const keyT &key) const
Returns an iterator pointing to the first element in the container whose key is not considered to go ...
Definition: sharedMap.h:154
const valT & operator[](const keyT &key) const
Read data from the map.
Definition: sharedMap.h:227
void publish()
Indicate that the calling element has written all the data it plans to write.
Definition: sharedMap.h:173
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_iterator upper_bound(const keyT &key) const
Returns an iterator pointing to the first element in the container whose key is considered to go afte...
Definition: sharedMap.h:164
const_iterator end() const
Get const_iterator to end of underlying map.
Definition: sharedMap.h:129
Base class for holding SharedObject data.
Definition: sharedObject.h:87