GetFEM++  5.3
dal_static_stored_objects.cc
1 /*===========================================================================
2 
3  Copyright (C) 2002-2017 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, write to the Free Software Foundation,
18  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 
20 ===========================================================================*/
21 
22 
24 #include "getfem/dal_singleton.h"
25 #include <map>
26 #include <list>
27 #include <set>
28 #include <algorithm>
29 #include <deque>
30 
31 
32 namespace dal {
33 
34  // 0 = only undestroyed, 1 = Normal, 2 very noisy,
35 #define DAL_STORED_OBJECT_DEBUG_NOISY 2
36 
37 static bool dal_static_stored_tab_valid__ = true;
38 
39 #if DAL_STORED_OBJECT_DEBUG
40  static std::map <const static_stored_object *, std::string> _created_objects;
41  static std::map <const static_stored_object *, std::string> _added_objects;
42  static std::map <const static_stored_object *, std::string> _deleted_objects;
43 
44 
45  void stored_debug_created(const static_stored_object *o,
46  const std::string &name) {
47  if (dal_static_stored_tab_valid__) {
48  _created_objects[o] = name;
49 # if DAL_STORED_OBJECT_DEBUG_NOISY > 1
50  cout << "Created " << name << " : " << o << endl;
51 # endif
52  }
53  }
54  void stored_debug_added(const static_stored_object *o) {
55  if (dal_static_stored_tab_valid__) {
56  auto it = _created_objects.find(o);
57  if (it == _created_objects.end()) {
58  _added_objects[o] = "";
59 # if DAL_STORED_OBJECT_DEBUG_NOISY > 0
60  cout << "Adding an unknown object " << o << " of type "
61  << typeid(*o).name() << " add DAL_STORED_OBJECT_DEBUG_CREATED"
62  "(o, name) in its constructor" << endl;
63 # endif
64  } else {
65  _added_objects[o] = it->second;
66  _created_objects.erase(it);
67 # if DAL_STORED_OBJECT_DEBUG_NOISY > 1
68  cout << "Added " << it->second << " : " << o << endl;
69 # endif
70  }
71  if (_deleted_objects.size()) {
72  cout << endl << "Number of stored objects: " << _added_objects.size()
73  << endl << "Number of unstored created objects: "
74  << _created_objects.size() << endl
75  << "Number of undestroyed object: "
76  << _deleted_objects.size() << endl;
77  for (auto &x : _deleted_objects)
78  cout << "UNDESTROYED OBJECT " << x.second << " : " << x.first << endl;
79  }
80  }
81  }
82 
83  void stored_debug_deleted(const static_stored_object *o) {
84  if (dal_static_stored_tab_valid__) {
85  auto it = _added_objects.find(o);
86  if (it == _added_objects.end()) {
87  cout << "Deleting an unknown object ! " << o << endl;
88  _deleted_objects[o] = "";
89  } else {
90  _deleted_objects[o] = it->second;
91  _added_objects.erase(it);
92 # if DAL_STORED_OBJECT_DEBUG_NOISY > 1
93  cout << "Deleted " << it->second << " : " << o << endl;
94 # endif
95  }
96  }
97  }
98 
99  void stored_debug_destroyed(const static_stored_object *o,
100  const std::string &name) {
101  if (dal_static_stored_tab_valid__) {
102  auto it = _deleted_objects.find(o);
103  if (it == _deleted_objects.end()) {
104  it = _created_objects.find(o);
105  if (it == _created_objects.end()) {
106  it = _added_objects.find(o);
107  if (it == _added_objects.end()) {
108  cout << "Destroy an unknown object ! " << o << " name given : "
109  << name << endl;
110  } else {
111  _added_objects.erase(it);
112  cout << "Destroy a non deleted object !! " << o << " name given : "
113  << name << endl;
114  }
115  } else {
116 # if DAL_STORED_OBJECT_DEBUG_NOISY > 1
117  cout << "Destroy an unadded object " << it->second << " : "
118  << o << endl;
119 # endif
120  _created_objects.erase(it);
121  }
122  } else {
123 # if DAL_STORED_OBJECT_DEBUG_NOISY > 1
124  cout << "Destroy " << it->second << " : " << o << " name given : "
125  << name << endl;
126 # endif
127  _deleted_objects.erase(it);
128  }
129 
130  }
131  }
132 
133 
134 
135 
136 #endif
137 
138 
139 
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  {
145  stored_object_tab::stored_key_tab& stored_keys
146  = dal::singleton<stored_object_tab>::instance(thread).stored_keys_;
147  GMM_ASSERT1(dal_static_stored_tab_valid__, "Too late to do that");
148  stored_object_tab::stored_key_tab::iterator it = stored_keys.find(o);
149  if (it != stored_keys.end()) return it->second;
150  return 0;
151  }
152 
153  // gives a key of the stored object while looking in the storage of other threads
154  pstatic_stored_object_key key_of_stored_object_other_threads(pstatic_stored_object o)
155  {
156  for(size_t thread = 0; thread<getfem::num_threads();thread++)
157  {
158  if (thread == this_thread()) continue;
159  pstatic_stored_object_key key = key_of_stored_object(o,thread);
160  if (key) return key;
161  }
162  return 0;
163  }
164 
165  pstatic_stored_object_key key_of_stored_object(pstatic_stored_object o)
166  {
167  pstatic_stored_object_key key = key_of_stored_object(o,this_thread());
168  if (key) return key;
169  else return (num_threads() > 1) ? key_of_stored_object_other_threads(o) : 0;
170  return 0;
171  }
172 
173  bool exists_stored_object(pstatic_stored_object o)
174  {
175  stored_object_tab::stored_key_tab& stored_keys
177  if (dal_static_stored_tab_valid__) {
178  return (stored_keys.find(o) != stored_keys.end());
179  }
180  return false;
181  }
182 
183  pstatic_stored_object search_stored_object(pstatic_stored_object_key k)
184  {
185  stored_object_tab& stored_objects
187  if (dal_static_stored_tab_valid__) {
188  pstatic_stored_object p = stored_objects.search_stored_object(k);
189  if (p) return p;
190  }
191  return 0;
192  }
193 
194  std::pair<stored_object_tab::iterator, stored_object_tab::iterator> iterators_of_object(
195  pstatic_stored_object o)
196  {
197  for(size_t thread=0; thread < num_threads(); ++thread)
198  {
199  stored_object_tab& stored_objects
201  if (!dal_static_stored_tab_valid__) continue;
202  stored_object_tab::iterator it = stored_objects.iterator_of_object_(o);
203  if (it != stored_objects.end()) return {it, stored_objects.end()};
204  }
207  }
208 
209 
211  {
212  for(size_t thread = 0; thread < num_threads(); ++thread)
213  {
214  stored_object_tab& stored_objects
216  if (!dal_static_stored_tab_valid__) continue;
217  stored_object_tab::stored_key_tab& stored_keys = stored_objects.stored_keys_;
218 
219  GMM_ASSERT1(stored_objects.size() == stored_keys.size(),
220  "keys and objects tables don't match");
221  for (stored_object_tab::stored_key_tab::iterator it = stored_keys.begin();
222  it != stored_keys.end(); ++it)
223  {
224  auto itos = iterators_of_object(it->first);
225  GMM_ASSERT1(itos.first != itos.second, "Key without object is found");
226  }
227  for (stored_object_tab::iterator it = stored_objects.begin();
228  it != stored_objects.end(); ++it)
229  {
230  auto itos = iterators_of_object(it->second.p);
231  GMM_ASSERT1(itos.first != itos.second, "Object has key but cannot be found");
232  }
233  }
234  }
235 
236  void add_dependency(pstatic_stored_object o1,
237  pstatic_stored_object o2) {
238  bool dep_added = false;
239  for(size_t thread=0; thread < num_threads(); ++thread)
240  {
241  stored_object_tab& stored_objects
243  if (!dal_static_stored_tab_valid__) return;
244  if ((dep_added = stored_objects.add_dependency_(o1,o2))) break;
245  }
246  GMM_ASSERT1(dep_added, "Failed to add dependency between " << o1
247  << " of type " << typeid(*o1).name() << " and " << o2
248  << " of type " << typeid(*o2).name() << ". ");
249 
250  bool dependent_added = false;
251  for(size_t thread=0; thread < num_threads(); ++thread)
252  {
253  stored_object_tab& stored_objects
255  if ((dependent_added = stored_objects.add_dependent_(o1,o2))) break;
256  }
257  GMM_ASSERT1(dependent_added, "Failed to add dependent between " << o1
258  << " of type " << typeid(*o1).name() << " and " << o2
259  << " of type " << typeid(*o2).name() << ". ");
260  }
261 
262 
263 
264  /*remove a dependency (from storages of all threads).
265  Return true if o2 has no more dependent object. */
266  bool del_dependency(pstatic_stored_object o1,
267  pstatic_stored_object o2)
268  {
269  bool dep_deleted = false;
270  for(size_t thread=0; thread < num_threads(); ++thread)
271  {
272  stored_object_tab& stored_objects
274  if (!dal_static_stored_tab_valid__) return false;
275  if ((dep_deleted = stored_objects.del_dependency_(o1,o2))) break;
276  }
277  GMM_ASSERT1(dep_deleted, "Failed to delete dependency between " << o1 << " of type "
278  << typeid(*o1).name() << " and " << o2 << " of type " << typeid(*o2).name() << ". ");
279 
280  bool dependent_deleted = false;
281  bool dependent_empty = false;
282  for(size_t thread=0; thread < num_threads(); ++thread)
283  {
284  stored_object_tab& stored_objects
286  dependent_deleted = stored_objects.del_dependent_(o1,o2);
287  if (dependent_deleted)
288  {
289  dependent_empty = stored_objects.has_dependent_objects(o2);
290  break;
291  }
292  }
293  GMM_ASSERT1(dependent_deleted, "Failed to delete dependent between " << o1 << " of type "
294  << typeid(*o1).name() << " and " << o2 << " of type " << typeid(*o2).name() << ". ");
295 
296  return dependent_empty;
297  }
298 
299 
300  void add_stored_object(pstatic_stored_object_key k, pstatic_stored_object o,
301  permanence perm) {
302  GMM_ASSERT1(dal_static_stored_tab_valid__, "Too late to add an object");
303  stored_object_tab& stored_objects
305  if (dal_static_stored_tab_valid__)
306  stored_objects.add_stored_object(k,o,perm);
307  }
308 
309  void basic_delete(std::list<pstatic_stored_object> &to_delete) {
310  stored_object_tab& stored_objects_this_thread
312 
313  if (dal_static_stored_tab_valid__) {
314 
315  stored_objects_this_thread.basic_delete_(to_delete);
316 
317  if (!to_delete.empty()) //need to delete from other threads
318  {
319  for(size_t thread=0; thread < num_threads(); ++thread)
320  {
321  if (thread == this_thread()) continue;
322  stored_object_tab& stored_objects
324  stored_objects.basic_delete_(to_delete);
325  if (to_delete.empty()) break;
326  }
327  }
328  if (me_is_multithreaded_now())
329  {
330  if (!to_delete.empty()) GMM_WARNING1("Not all objects were deleted");
331  }
332  else
333  {
334  GMM_ASSERT1(to_delete.empty(), "Could not delete objects");
335  }
336  }
337  }
338 
339  void del_stored_objects(std::list<pstatic_stored_object> &to_delete,
340  bool ignore_unstored)
341  {
342  getfem::omp_guard lock;
343  GMM_NOPERATION(lock);
344  // stored_object_tab& stored_objects
345  // = dal::singleton<stored_object_tab>::instance();
346 
347  if (dal_static_stored_tab_valid__) {
348 
349  std::list<pstatic_stored_object>::iterator it, itnext;
350  for (it = to_delete.begin(); it != to_delete.end(); it = itnext) {
351  itnext = it; itnext++;
352 
353  auto itos = iterators_of_object(*it);
354  if (itos.first == itos.second) {
355  if (ignore_unstored)
356  to_delete.erase(it);
357  else
358  if (me_is_multithreaded_now()) {
359  GMM_WARNING1("This object is (already?) not stored : "<< it->get()
360  << " typename: " << typeid(*it->get()).name()
361  << "(which could happen in multithreaded code and is OK)");
362  } else {
363  GMM_ASSERT1(false, "This object is not stored : " << it->get()
364  << " typename: " << typeid(*it->get()).name());
365  }
366  }
367  else
368  itos.first->second.valid = false;
369  }
370 
371  for (pstatic_stored_object pobj : to_delete) {
372  if (pobj) {
373  auto itos = iterators_of_object(pobj);
374  GMM_ASSERT1(itos.first != itos.second, "An object disapeared !");
375  itos.first->second.valid = false;
376  auto second_dep = itos.first->second.dependencies;
377  for (const pstatic_stored_object pdep : second_dep) {
378  if (del_dependency(pobj, pdep)) {
379  auto itods = iterators_of_object(pdep);
380  if (itods.first->second.perm == AUTODELETE_STATIC_OBJECT
381  && itods.first->second.valid) {
382  itods.first->second.valid = false;
383  to_delete.push_back(pdep);
384  }
385  }
386  }
387  for (pstatic_stored_object
388  pdep : itos.first->second.dependent_object) {
389  auto itods = iterators_of_object(pdep);
390  if (itods.first != itods.second) {
391  GMM_ASSERT1(itods.first->second.perm != PERMANENT_STATIC_OBJECT,
392  "Trying to delete a permanent object " << pdep);
393  if (itods.first->second.valid) {
394  itods.first->second.valid = false;
395  to_delete.push_back(itods.first->second.p);
396  }
397  }
398  }
399  }
400  }
401  basic_delete(to_delete);
402  }
403  }
404 
405 
406  void del_stored_object(const pstatic_stored_object &o, bool ignore_unstored)
407  {
408  std::list<pstatic_stored_object> to_delete;
409  to_delete.push_back(o);
410  del_stored_objects(to_delete, ignore_unstored);
411  }
412 
413 
414  void del_stored_objects(permanence perm)
415  {
416  std::list<pstatic_stored_object> to_delete;
417  for(size_t thread=0; thread<getfem::num_threads();thread++)
418  {
419  stored_object_tab& stored_objects
421  if (!dal_static_stored_tab_valid__) continue;
422  if (perm == PERMANENT_STATIC_OBJECT) perm = STRONG_STATIC_OBJECT;
423  stored_object_tab::iterator it;
424  for (it = stored_objects.begin(); it != stored_objects.end(); ++it)
425  if (it->second.perm >= perm)
426  to_delete.push_back(it->second.p);
427  }
428  del_stored_objects(to_delete, false);
429  }
430 
431  void list_stored_objects(std::ostream &ost)
432  {
433  for(size_t thread=0; thread<getfem::num_threads();thread++)
434  {
435  stored_object_tab::stored_key_tab& stored_keys
436  = dal::singleton<stored_object_tab>::instance(thread).stored_keys_;
437  if (!dal_static_stored_tab_valid__) continue;
438  if (stored_keys.begin() == stored_keys.end())
439  ost << "No static stored objects" << endl;
440  else ost << "Static stored objects" << endl;
441  for (const auto &t : stored_keys)
442  ost << "Object: " << t.first << " typename: "
443  << typeid(*(t.first)).name() << endl;
444  }
445  }
446 
447  size_t nb_stored_objects(void)
448  {
449  long num_objects=0;
450  for(size_t thread=0;thread<getfem::num_threads(); ++thread)
451  {
452  stored_object_tab::stored_key_tab& stored_keys
453  = dal::singleton<stored_object_tab>::instance(thread).stored_keys_;
454  if (!dal_static_stored_tab_valid__) continue;
455  num_objects+=stored_keys.size();
456  }
457  return num_objects;
458  }
459 
460 
461 
462 
463 /**
464  STATIC_STORED_TAB -------------------------------------------------------
465 */
468  locks_(), stored_keys_()
469  { dal_static_stored_tab_valid__ = true; }
470 
471  stored_object_tab::~stored_object_tab()
472  { dal_static_stored_tab_valid__ = false; }
473 
474  pstatic_stored_object
475  stored_object_tab::search_stored_object(pstatic_stored_object_key k) const
476  {
477  getfem::local_guard guard = locks_.get_lock();
478  stored_object_tab::const_iterator it=find(enr_static_stored_object_key(k));
479  return (it != end()) ? it->second.p : 0;
480  }
481 
482  bool stored_object_tab::add_dependency_(pstatic_stored_object o1,
483  pstatic_stored_object o2)
484  {
485  getfem::local_guard guard = locks_.get_lock();
486  stored_key_tab::const_iterator it = stored_keys_.find(o1);
487  if (it == stored_keys_.end()) return false;
488  iterator ito1 = find(it->second);
489  GMM_ASSERT1(ito1 != end(), "Object has a key, but cannot be found");
490  ito1->second.dependencies.insert(o2);
491  return true;
492  }
493 
494  void stored_object_tab::add_stored_object(pstatic_stored_object_key k,
495  pstatic_stored_object o, permanence perm)
496  {
497  DAL_STORED_OBJECT_DEBUG_ADDED(o.get());
498  getfem::local_guard guard = locks_.get_lock();
499  GMM_ASSERT1(stored_keys_.find(o) == stored_keys_.end(),
500  "This object has already been stored, possibly with another key");
501  stored_keys_[o] = k;
502  insert(std::make_pair(enr_static_stored_object_key(k),
503  enr_static_stored_object(o, perm)));
504  size_t t = this_thread();
505  GMM_ASSERT2(stored_keys_.size() == size() && t != size_t(-1),
506  "stored_keys are not consistent with stored_object tab");
507  }
508 
509  bool stored_object_tab::add_dependent_(pstatic_stored_object o1,
510  pstatic_stored_object o2)
511  {
512  getfem::local_guard guard = locks_.get_lock();
513  stored_key_tab::const_iterator it = stored_keys_.find(o2);
514  if (it == stored_keys_.end()) return false;
515  iterator ito2 = find(it->second);
516  GMM_ASSERT1(ito2 != end(), "Object has a key, but cannot be found");
517  ito2->second.dependent_object.insert(o1);
518  return true;
519  }
520 
521  bool stored_object_tab::del_dependency_(pstatic_stored_object o1,
522  pstatic_stored_object o2)
523  {
524  getfem::local_guard guard = locks_.get_lock();
525  stored_key_tab::const_iterator it1 = stored_keys_.find(o1);
526  if (it1 == stored_keys_.end()) return false;
527  iterator ito1 = find(it1->second);
528  GMM_ASSERT1(ito1 != end(), "Object has a key, but cannot be found");
529  ito1->second.dependencies.erase(o2);
530  return true;
531  }
532 
533  stored_object_tab::iterator stored_object_tab::iterator_of_object_(pstatic_stored_object o)
534  {
535  stored_key_tab::const_iterator itk = stored_keys_.find(o);
536  if (itk == stored_keys_.end()) return end();
537  iterator ito = find(itk->second);
538  GMM_ASSERT1(ito != end(), "Object has a key, but is not stored");
539  return ito;
540  }
541 
542  bool stored_object_tab::del_dependent_(pstatic_stored_object o1,
543  pstatic_stored_object o2)
544  {
545  getfem::local_guard guard = locks_.get_lock();
546  stored_key_tab::const_iterator it2 = stored_keys_.find(o2);
547  if (it2 == stored_keys_.end()) return false;
548  iterator ito2 = find(it2->second);
549  GMM_ASSERT1(ito2 != end(), "Object has a key, but cannot be found");
550  ito2->second.dependent_object.erase(o1);
551  return true;
552  }
553 
554  bool stored_object_tab::exists_stored_object(pstatic_stored_object o) const
555  {
556  getfem::local_guard guard = locks_.get_lock();
557  return (stored_keys_.find(o) != stored_keys_.end());
558  }
559 
560  bool stored_object_tab::has_dependent_objects(pstatic_stored_object o) const
561  {
562  getfem::local_guard guard = locks_.get_lock();
563  stored_key_tab::const_iterator it = stored_keys_.find(o);
564  GMM_ASSERT1(it != stored_keys_.end(), "Object is not stored");
565  const_iterator ito = find(it->second);
566  GMM_ASSERT1(ito != end(), "Object has a key, but cannot be found");
567  return ito->second.dependent_object.empty();
568  }
569 
570 
571 
572  void stored_object_tab::basic_delete_
573  (std::list<pstatic_stored_object> &to_delete)
574  {
575  getfem::local_guard guard = locks_.get_lock();
576  std::list<pstatic_stored_object>::iterator it;
577  for (it = to_delete.begin(); it != to_delete.end(); )
578  {
579  DAL_STORED_OBJECT_DEBUG_DELETED(it->get());
580  stored_key_tab::iterator itk = stored_keys_.find(*it);
581  stored_object_tab::iterator ito = end();
582  if (itk != stored_keys_.end())
583  {
584  ito = find(itk->second);
585  stored_keys_.erase(itk);
586  }
587  if (ito != end())
588  {
589  erase(ito);
590  it = to_delete.erase(it);
591  } else {
592  ++it;
593  }
594  }
595  }
596 
597 
598 
599 }
Pointer to a key with a coherent order.
void test_stored_objects(void)
Test the validity of the whole global storage.
Stores interdependent getfem objects.
stored_object_tab()
STATIC_STORED_TAB ----------------------------------------------------—.
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.
static T & instance()
Instance from the current thread.
void add_stored_object(pstatic_stored_object_key k, pstatic_stored_object o, permanence perm)
Add an object with two optional dependencies.
A simple singleton implementation.
bool del_dependency(pstatic_stored_object o1, pstatic_stored_object o2)
remove a dependency.
Table of stored objects.
void add_dependency(pstatic_stored_object o1, pstatic_stored_object o2)
Add a dependency, object o1 will depend on object o2.
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.
Pointer to an object with the dependencies.
bool exists_stored_object(pstatic_stored_object o)
Test if an object is stored.
size_t nb_stored_objects(void)
Return the number of stored objects (for debugging purpose).