GetFEM  5.5
dal_static_stored_objects.cc
1 /*===========================================================================
2 
3  Copyright (C) 2002-2026 Yves Renard
4 
5  This file is a part of GetFEM
6 
7  GetFEM is free software; you can redistribute it and/or modify it
8  under the terms of the GNU Lesser General Public License as published
9  by the Free Software Foundation; either version 3 of the License, or
10  (at your option) any later version along with the GCC Runtime Library
11  Exception either version 3.1 or (at your option) any later version.
12  This program is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15  License and GCC Runtime Library Exception for more details.
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program. If not, see https://www.gnu.org/licenses/.
18 
19 ===========================================================================*/
20 
21 
23 #include "getfem/dal_singleton.h"
24 #include <map>
25 #include <list>
26 #include <set>
27 #include <algorithm>
28 #include <deque>
29 
30 
31 namespace dal {
32 
33  // 0 = only undestroyed, 1 = Normal, 2 very noisy,
34 #define DAL_STORED_OBJECT_DEBUG_NOISY 2
35 
36 #if DAL_STORED_OBJECT_DEBUG
37 
38  static bool dal_static_stored_tab_valid__ = true;
39 
40  #define STORED_ASSERT(test, message) GMM_ASSERT1(test, message);
41  #define ON_STORED_DEBUG(expression) expression;
42 
43  static std::map <const static_stored_object *, std::string> _created_objects;
44  static std::map <const static_stored_object *, std::string> _added_objects;
45  static std::map <const static_stored_object *, std::string> _deleted_objects;
46 
47 
48  void stored_debug_created(const static_stored_object *o,
49  const std::string &name) {
50  if (dal_static_stored_tab_valid__) {
51  _created_objects[o] = name;
52 # if DAL_STORED_OBJECT_DEBUG_NOISY > 1
53  cout << "Created " << name << " : " << o << endl;
54 # endif
55  }
56  }
57  void stored_debug_added(const static_stored_object *o) {
58  if (dal_static_stored_tab_valid__) {
59  auto it = _created_objects.find(o);
60  if (it == _created_objects.end()) {
61  _added_objects[o] = "";
62 # if DAL_STORED_OBJECT_DEBUG_NOISY > 0
63  cout << "Adding an unknown object " << o << " of type "
64  << typeid(*o).name() << " add DAL_STORED_OBJECT_DEBUG_CREATED"
65  "(o, name) in its constructor" << endl;
66 # endif
67  } else {
68  _added_objects[o] = it->second;
69  _created_objects.erase(it);
70 # if DAL_STORED_OBJECT_DEBUG_NOISY > 1
71  cout << "Added " << it->second << " : " << o << endl;
72 # endif
73  }
74  if (_deleted_objects.size()) {
75  cout << endl << "Number of stored objects: " << _added_objects.size()
76  << endl << "Number of unstored created objects: "
77  << _created_objects.size() << endl
78  << "Number of undestroyed object: "
79  << _deleted_objects.size() << endl;
80  for (auto &x : _deleted_objects)
81  cout << "UNDESTROYED OBJECT " << x.second << " : " << x.first << endl;
82  }
83  }
84  }
85 
86  void stored_debug_deleted(const static_stored_object *o) {
87  if (dal_static_stored_tab_valid__) {
88  auto it = _added_objects.find(o);
89  if (it == _added_objects.end()) {
90  cout << "Deleting an unknown object ! " << o << endl;
91  _deleted_objects[o] = "";
92  } else {
93  _deleted_objects[o] = it->second;
94  _added_objects.erase(it);
95 # if DAL_STORED_OBJECT_DEBUG_NOISY > 1
96  cout << "Deleted " << it->second << " : " << o << endl;
97 # endif
98  }
99  }
100  }
101 
102  void stored_debug_destroyed(const static_stored_object *o,
103  const std::string &name) {
104  if (dal_static_stored_tab_valid__) {
105  auto it = _deleted_objects.find(o);
106  if (it == _deleted_objects.end()) {
107  it = _created_objects.find(o);
108  if (it == _created_objects.end()) {
109  it = _added_objects.find(o);
110  if (it == _added_objects.end()) {
111  cout << "Destroy an unknown object ! " << o << " name given : "
112  << name << endl;
113  } else {
114  _added_objects.erase(it);
115  cout << "Destroy a non deleted object !! " << o << " name given : "
116  << name << endl;
117  }
118  } else {
119 # if DAL_STORED_OBJECT_DEBUG_NOISY > 1
120  cout << "Destroy an unadded object " << it->second << " : "
121  << o << endl;
122 # endif
123  _created_objects.erase(it);
124  }
125  } else {
126 # if DAL_STORED_OBJECT_DEBUG_NOISY > 1
127  cout << "Destroy " << it->second << " : " << o << " name given : "
128  << name << endl;
129 # endif
130  _deleted_objects.erase(it);
131  }
132 
133  }
134  }
135 
136 #else
137  #define STORED_ASSERT(test, message)
138  #define ON_STORED_DEBUG(expression)
139 #endif
140 
141  // Gives a pointer to a key of an object from its pointer, while looking in the storage of
142  // a specific thread
143  pstatic_stored_object_key key_of_stored_object(pstatic_stored_object o, size_t thread){
144  auto& stored_keys = singleton<stored_object_tab>::instance(thread).stored_keys_;
145  STORED_ASSERT(dal_static_stored_tab_valid__, "Too late to do that");
146  auto it = stored_keys.find(o);
147  if (it != stored_keys.end()) return it->second;
148  return nullptr;
149  }
150 
151  // gives a key of the stored object while looking in the storage of other threads
152  pstatic_stored_object_key key_of_stored_object_other_threads(pstatic_stored_object o){
153  for(size_t thread = 0; thread != singleton<stored_object_tab>::num_threads(); ++thread)
154  {
155  if (thread == singleton<stored_object_tab>::this_thread()) continue;
156  auto key = key_of_stored_object(o,thread);
157  if (key) return key;
158  }
159  return nullptr;
160  }
161 
162  pstatic_stored_object_key key_of_stored_object(pstatic_stored_object o){
163  auto key = key_of_stored_object(o, singleton<stored_object_tab>::this_thread());
164  if (key) return key;
166  key_of_stored_object_other_threads(o) : nullptr;
167  return nullptr;
168  }
169 
170  bool exists_stored_object(pstatic_stored_object o){
171  auto& stored_keys = singleton<stored_object_tab>::instance().stored_keys_;
172  ON_STORED_DEBUG(if (!dal_static_stored_tab_valid__) return false)
173  return (stored_keys.find(o) != stored_keys.end());
174  }
175 
176  pstatic_stored_object search_stored_object(pstatic_stored_object_key k){
177  auto& stored_objects = singleton<stored_object_tab>::instance();
178  ON_STORED_DEBUG(if (!dal_static_stored_tab_valid__) return nullptr)
179  return stored_objects.search_stored_object(k);
180  }
181 
182  pstatic_stored_object search_stored_object_on_all_threads(pstatic_stored_object_key k){
183  auto& stored_objects = singleton<stored_object_tab>::instance();
184  ON_STORED_DEBUG(if (!dal_static_stored_tab_valid__) return nullptr)
185  auto p = stored_objects.search_stored_object(k);
186  if (p) return p;
187  if (singleton<stored_object_tab>::num_threads() == 1) return nullptr;
188  for(size_t thread = 0; thread < singleton<stored_object_tab>::num_threads(); ++thread){
189  if (thread == singleton<stored_object_tab>::this_thread()) continue;
190  auto& other_objects = singleton<stored_object_tab>::instance(thread);
191  p = other_objects.search_stored_object(k);
192  if (p) return p;
193  }
194  return nullptr;
195  }
196 
197  std::pair<stored_object_tab::iterator, stored_object_tab::iterator>
198  iterators_of_object(pstatic_stored_object o){
199  for(size_t thread = 0; thread != singleton<stored_object_tab>::num_threads(); ++thread){
200  auto& stored_objects = singleton<stored_object_tab>::instance(thread);
201  ON_STORED_DEBUG(if (!dal_static_stored_tab_valid__) continue;)
202  auto it = stored_objects.iterator_of_object_(o);
203  if (it != stored_objects.end()) return {it, stored_objects.end()};
204  }
207  }
208 
209 
211  for(size_t thread = 0; thread != singleton<stored_object_tab>::num_threads(); ++thread){
212  auto& stored_objects = singleton<stored_object_tab>::instance(thread);
213  ON_STORED_DEBUG(if (!dal_static_stored_tab_valid__) continue;)
214  auto& stored_keys = stored_objects.stored_keys_;
215 
216  GMM_ASSERT1(stored_objects.size() == stored_keys.size(),
217  "keys and objects tables don't match");
218  for (auto &&pair : stored_keys){
219  auto itos = iterators_of_object(pair.first);
220  GMM_ASSERT1(itos.first != itos.second, "Key without object is found");
221  }
222  for (auto &&pair : stored_objects){
223  auto itos = iterators_of_object(pair.second.p);
224  GMM_ASSERT1(itos.first != itos.second, "Object has key but cannot be found");
225  }
226  }
227  }
228 
229  void add_dependency(pstatic_stored_object o1,
230  pstatic_stored_object o2) {
231  bool dep_added = false;
232  for(size_t thread = 0; thread != singleton<stored_object_tab>::num_threads(); ++thread){
233  auto& stored_objects = singleton<stored_object_tab>::instance(thread);
234  ON_STORED_DEBUG(if (!dal_static_stored_tab_valid__) return)
235  if ((dep_added = stored_objects.add_dependency_(o1,o2))) break;
236  }
237  GMM_ASSERT1(dep_added, "Failed to add dependency between " << o1
238  << " of type " << typeid(*o1).name() << " and " << o2
239  << " of type " << typeid(*o2).name() << ". ");
240 
241  bool dependent_added = false;
242  for(size_t thread = 0; thread != singleton<stored_object_tab>::num_threads(); ++thread){
243  auto& stored_objects = singleton<stored_object_tab>::instance(thread);
244  if ((dependent_added = stored_objects.add_dependent_(o1,o2))) break;
245  }
246  GMM_ASSERT1(dependent_added, "Failed to add dependent between " << o1
247  << " of type " << typeid(*o1).name() << " and " << o2
248  << " of type " << typeid(*o2).name() << ". ");
249  }
250 
251 
252 
253  /*remove a dependency (from storages of all threads).
254  Return true if o2 has no more dependent object. */
255  bool del_dependency(pstatic_stored_object o1, pstatic_stored_object o2){
256  bool dep_deleted = false;
257  for(size_t thread = 0; thread != singleton<stored_object_tab>::num_threads(); ++thread){
258  auto& stored_objects = singleton<stored_object_tab>::instance(thread);
259  ON_STORED_DEBUG(if (!dal_static_stored_tab_valid__) return false)
260  if ((dep_deleted = stored_objects.del_dependency_(o1,o2))) break;
261  }
262  GMM_ASSERT1(dep_deleted, "Failed to delete dependency between " << o1 << " of type "
263  << typeid(*o1).name() << " and " << o2 << " of type "
264  << typeid(*o2).name() << ". ");
265 
266  bool dependent_deleted = false;
267  bool dependent_empty = false;
268  for(size_t thread = 0; thread != singleton<stored_object_tab>::num_threads(); ++thread){
269  auto& stored_objects = singleton<stored_object_tab>::instance(thread);
270  dependent_deleted = stored_objects.del_dependent_(o1,o2);
271  if (dependent_deleted){
272  dependent_empty = stored_objects.has_dependent_objects(o2);
273  break;
274  }
275  }
276  GMM_ASSERT1(dependent_deleted, "Failed to delete dependent between " << o1 << " of type "
277  << typeid(*o1).name() << " and " << o2 << " of type "
278  << typeid(*o2).name() << ". ");
279 
280  return dependent_empty;
281  }
282 
283  void add_stored_object(pstatic_stored_object_key k, pstatic_stored_object o,
284  permanence perm) {
285  STORED_ASSERT(dal_static_stored_tab_valid__, "Too late to add an object");
286  auto& stored_objects = singleton<stored_object_tab>::instance();
287  stored_objects.add_stored_object(k,o,perm);
288  }
289 
290  void basic_delete(std::list<pstatic_stored_object> &to_delete){
291  auto& stored_objects_this_thread = singleton<stored_object_tab>::instance();
292 
293  ON_STORED_DEBUG(if (!dal_static_stored_tab_valid__) return)
294  stored_objects_this_thread.basic_delete_(to_delete);
295 
296  if (!to_delete.empty()){ //need to delete from other threads
297  for(size_t thread = 0; thread != singleton<stored_object_tab>::num_threads(); ++thread){
298  if (thread == singleton<stored_object_tab>::this_thread()) continue;
299  auto& stored_objects = singleton<stored_object_tab>::instance(thread);
300  stored_objects.basic_delete_(to_delete);
301  if (to_delete.empty()) break;
302  }
303  }
305  if (!to_delete.empty()) GMM_WARNING1("Not all objects were deleted");
306  }
307  else{GMM_ASSERT1(to_delete.empty(), "Could not delete objects");}
308  }
309 
310  void del_stored_objects(std::list<pstatic_stored_object> &to_delete,
311  bool ignore_unstored) {
312 
313  GLOBAL_OMP_GUARD
314 
315  ON_STORED_DEBUG(if (dal_static_stored_tab_valid__) return);
316 
317  std::list<pstatic_stored_object>::iterator it, itnext;
318  for (it = to_delete.begin(); it != to_delete.end(); it = itnext) {
319  itnext = it; itnext++;
320 
321  auto itos = iterators_of_object(*it);
322  if (itos.first == itos.second) {
323  if (ignore_unstored) to_delete.erase(it);
324  else if (getfem::me_is_multithreaded_now()) {
325  GMM_WARNING1("This object is (already?) not stored : "<< it->get()
326  << " typename: " << typeid(*it->get()).name()
327  << "(which could happen in multithreaded code and is OK)");
328  } else {
329  GMM_ASSERT1(false, "This object is not stored : " << it->get()
330  << " typename: " << typeid(*it->get()).name());
331  }
332  }
333  else itos.first->second.valid = false;
334  }
335 
336  for (auto &&pobj : to_delete) {
337  if (pobj) {
338  auto itos = iterators_of_object(pobj);
339  GMM_ASSERT1(itos.first != itos.second, "An object disapeared !");
340  itos.first->second.valid = false;
341  auto second_dep = itos.first->second.dependencies;
342  for (const auto &pdep : second_dep) {
343  if (del_dependency(pobj, pdep)) {
344  auto itods = iterators_of_object(pdep);
345  if (itods.first->second.perm == AUTODELETE_STATIC_OBJECT
346  && itods.first->second.valid) {
347  itods.first->second.valid = false;
348  to_delete.push_back(pdep);
349  }
350  }
351  }
352  for (auto &&pdep : itos.first->second.dependent_object) {
353  auto itods = iterators_of_object(pdep);
354  if (itods.first != itods.second) {
355  GMM_ASSERT1(itods.first->second.perm != PERMANENT_STATIC_OBJECT,
356  "Trying to delete a permanent object " << pdep);
357  if (itods.first->second.valid) {
358  itods.first->second.valid = false;
359  to_delete.push_back(itods.first->second.p);
360  }
361  }
362  }
363  }
364  }
365  basic_delete(to_delete);
366  }
367 
368  void del_stored_object(const pstatic_stored_object &o, bool ignore_unstored){
369  std::list<pstatic_stored_object> to_delete;
370  to_delete.push_back(o);
371  del_stored_objects(to_delete, ignore_unstored);
372  }
373 
374 
375  void del_stored_objects(permanence perm){
376  std::list<pstatic_stored_object> to_delete;
377  for(size_t thread = 0; thread != singleton<stored_object_tab>::num_threads(); ++thread){
378  auto& stored_objects = singleton<stored_object_tab>::instance(thread);
379  ON_STORED_DEBUG(if (!dal_static_stored_tab_valid__) continue;)
380  if (perm == PERMANENT_STATIC_OBJECT) perm = STRONG_STATIC_OBJECT;
381  for (auto &&pair : stored_objects){
382  if (pair.second.perm >= perm) to_delete.push_back(pair.second.p);
383  }
384  }
385  del_stored_objects(to_delete, false);
386  }
387 
388  void list_stored_objects(std::ostream &ost){
389  for(size_t thread = 0; thread != singleton<stored_object_tab>::num_threads(); ++thread){
390  auto& stored_keys = singleton<stored_object_tab>::instance(thread).stored_keys_;
391  ON_STORED_DEBUG(if (!dal_static_stored_tab_valid__) continue;)
392  if (stored_keys.begin() == stored_keys.end())
393  ost << "No static stored objects" << endl;
394  else ost << "Static stored objects" << endl;
395  for (const auto &t : stored_keys)
396  ost << "Object: " << t.first << " typename: "
397  << typeid(*(t.first)).name() << endl;
398  }
399  }
400 
401  size_t nb_stored_objects(void){
402  long num_objects = 0;
403  for(size_t thread = 0; thread != singleton<stored_object_tab>::num_threads(); ++thread){
404  auto& stored_keys = singleton<stored_object_tab>::instance(thread).stored_keys_;
405  ON_STORED_DEBUG(if (!dal_static_stored_tab_valid__) continue;)
406  num_objects += stored_keys.size();
407  }
408  return num_objects;
409  }
410 
411 /**
412  STATIC_STORED_TAB -------------------------------------------------------
413 */
416  locks_{}, stored_keys_{}{
417  ON_STORED_DEBUG(dal_static_stored_tab_valid__ = true;)
418  }
419 
420  stored_object_tab::~stored_object_tab(){
421  ON_STORED_DEBUG(dal_static_stored_tab_valid__ = false;)
422  }
423 
424  pstatic_stored_object
425  stored_object_tab::search_stored_object(pstatic_stored_object_key k) const{
426  auto guard = locks_.get_lock();
427  auto it = find(enr_static_stored_object_key(k));
428  return (it != end()) ? it->second.p : nullptr;
429  }
430 
431  bool stored_object_tab::add_dependency_(pstatic_stored_object o1,
432  pstatic_stored_object o2){
433  auto guard = locks_.get_lock();
434  auto it = stored_keys_.find(o1);
435  if (it == stored_keys_.end()) return false;
436  auto ito1 = find(it->second);
437  GMM_ASSERT1(ito1 != end(), "Object has a key, but cannot be found");
438  ito1->second.dependencies.insert(o2);
439  return true;
440  }
441 
442  void stored_object_tab::add_stored_object(pstatic_stored_object_key k,
443  pstatic_stored_object o, permanence perm){
444  DAL_STORED_OBJECT_DEBUG_ADDED(o.get());
445  auto guard = locks_.get_lock();
446  GMM_ASSERT1(stored_keys_.find(o) == stored_keys_.end(),
447  "This object has already been stored, possibly with another key");
448  stored_keys_[o] = k;
449  insert(std::make_pair(enr_static_stored_object_key(k),
450  enr_static_stored_object(o, perm)));
452  GMM_ASSERT2(stored_keys_.size() == size() && t != size_t(-1),
453  "stored_keys are not consistent with stored_object tab");
454  }
455 
456  bool stored_object_tab::add_dependent_(pstatic_stored_object o1,
457  pstatic_stored_object o2){
458  auto guard = locks_.get_lock();
459  auto it = stored_keys_.find(o2);
460  if (it == stored_keys_.end()) return false;
461  auto ito2 = find(it->second);
462  GMM_ASSERT1(ito2 != end(), "Object has a key, but cannot be found");
463  ito2->second.dependent_object.insert(o1);
464  return true;
465  }
466 
467  bool stored_object_tab::del_dependency_(pstatic_stored_object o1,
468  pstatic_stored_object o2){
469  auto guard = locks_.get_lock();
470  auto it1 = stored_keys_.find(o1);
471  if (it1 == stored_keys_.end()) return false;
472  auto ito1 = find(it1->second);
473  GMM_ASSERT1(ito1 != end(), "Object has a key, but cannot be found");
474  ito1->second.dependencies.erase(o2);
475  return true;
476  }
477 
478  stored_object_tab::iterator stored_object_tab
479  ::iterator_of_object_(pstatic_stored_object o){
480  auto itk = stored_keys_.find(o);
481  if (itk == stored_keys_.end()) return end();
482  auto ito = find(itk->second);
483  GMM_ASSERT1(ito != end(), "Object has a key, but is not stored");
484  return ito;
485  }
486 
487  bool stored_object_tab::del_dependent_(pstatic_stored_object o1,
488  pstatic_stored_object o2){
489  auto guard = locks_.get_lock();
490  auto it2 = stored_keys_.find(o2);
491  if (it2 == stored_keys_.end()) return false;
492  auto ito2 = find(it2->second);
493  GMM_ASSERT1(ito2 != end(), "Object has a key, but cannot be found");
494  ito2->second.dependent_object.erase(o1);
495  return true;
496  }
497 
498  bool stored_object_tab::exists_stored_object(pstatic_stored_object o) const{
499  auto guard = locks_.get_lock();
500  return (stored_keys_.find(o) != stored_keys_.end());
501  }
502 
503  bool stored_object_tab::has_dependent_objects(pstatic_stored_object o) const{
504  auto guard = locks_.get_lock();
505  auto it = stored_keys_.find(o);
506  GMM_ASSERT1(it != stored_keys_.end(), "Object is not stored");
507  auto ito = find(it->second);
508  GMM_ASSERT1(ito != end(), "Object has a key, but cannot be found");
509  return ito->second.dependent_object.empty();
510  }
511 
512  void stored_object_tab::basic_delete_(std::list<pstatic_stored_object> &to_delete){
513  auto guard = locks_.get_lock();
514  for (auto it = to_delete.begin(); it != to_delete.end();){
515  DAL_STORED_OBJECT_DEBUG_DELETED(it->get());
516  auto itk = stored_keys_.find(*it);
517  auto ito = end();
518  if (itk != stored_keys_.end()){
519  ito = find(itk->second);
520  stored_keys_.erase(itk);
521  }
522  if (ito != end()){
523  erase(ito);
524  it = to_delete.erase(it);
525  } else ++it;
526  }
527  }
528 
529 }/* end of namespace dal */
static size_type this_thread()
this thread number according to the threading policy of the singleton
static T & instance()
Instance from the current thread.
static size_type num_threads()
number of threads this singleton is distributed on.
A simple singleton implementation.
Stores interdependent getfem objects.
Dynamic Array Library.
void del_stored_objects(std::list< pstatic_stored_object > &to_delete, bool ignore_unstored)
Delete a list of objects and their dependencies.
void add_stored_object(pstatic_stored_object_key k, pstatic_stored_object o, permanence perm)
Add an object with two optional dependencies.
void test_stored_objects(void)
Test the validity of the whole global storage.
void add_dependency(pstatic_stored_object o1, pstatic_stored_object o2)
Add a dependency, object o1 will depend on object o2.
bool del_dependency(pstatic_stored_object o1, pstatic_stored_object o2)
remove a dependency.
size_t nb_stored_objects(void)
Return the number of stored objects (for debugging purpose).
void list_stored_objects(std::ostream &ost)
Show a list of stored objects (for debugging purpose).
void del_stored_object(const pstatic_stored_object &o, bool ignore_unstored)
Delete an object and the object which depend on it.
pstatic_stored_object search_stored_object(pstatic_stored_object_key k)
Gives a pointer to an object from a key pointer.
bool exists_stored_object(pstatic_stored_object o)
Test if an object is stored.
bool me_is_multithreaded_now()
is the program running in the parallel section
Definition: getfem_omp.cc:105
Pointer to a key with a coherent order.
Pointer to an object with the dependencies.
stored_object_tab()
STATIC_STORED_TAB ----------------------------------------------------—.