Mesh Oriented datABase  (version 5.5.0)
An array-based unstructured mesh library
mbmem.cpp
Go to the documentation of this file.
1 #include "moab/Core.hpp"
2 #include "moab/Range.hpp"
3 #include "moab/CN.hpp"
4 
5 #include <iostream>
6 #include <iomanip>
7 #include <sstream>
8 #include <string>
9 #include <cstdio>
10 #include <cstdlib>
11 
12 #ifndef _WIN32
13 #include <sys/times.h>
14 #include <sys/resource.h>
15 #include <unistd.h>
16 #endif
17 
18 static void usage( const char* argv0, bool help = false )
19 {
20  std::ostream& str = help ? std::cout : std::cerr;
21  str << "Usage: " << argv0 << " [-H|-b|-k|-m] <filename> [<filename> ...]" << std::endl
22  << " " << argv0 << " [-H|-b|-k|-m] -T" << std::endl;
23  if( !help )
24  {
25  str << " " << argv0 << " -h" << std::endl;
26  std::exit( 1 );
27  }
28 
29  std::cerr << " -H : human readable units" << std::endl
30  << " -b : bytes" << std::endl
31  << " -k : kilobytes (1 kB == 1024 bytes)" << std::endl
32  << " -m : megabytes (1 MB == 1024 kB)" << std::endl
33  << " -g : gigabytes (1 GB == 1024 MB)" << std::endl
34  << " -T : test mode" << std::endl
35  << std::endl;
36  std::exit( 0 );
37 }
38 
39 enum Units
40 {
45  GIGABYTES
46 };
48 
49 // The core functionality of this example
51  bool per_type = true,
52  bool per_tag = true,
53  bool totals = true,
54  bool sysstats = true );
55 
56 // Generate a series of meshes for testing
57 static void do_test_mode();
58 
59 // main routine: read any specified files and call print_memory_stats
60 int main( int argc, char* argv[] )
61 {
62  moab::ErrorCode rval;
63  bool no_more_flags = false;
64  bool test_mode = false;
65  std::vector< int > input_file_list;
66 
67  // load each file specified on command line
68  for( int i = 1; i < argc; ++i )
69  {
70  if( !no_more_flags && argv[i][0] == '-' )
71  {
72  if( !strcmp( argv[i], "-H" ) )
73  UNITS = HUMAN;
74  else if( !strcmp( argv[i], "-b" ) )
75  UNITS = BYTES;
76  else if( !strcmp( argv[i], "-k" ) )
77  UNITS = KILOBYTES;
78  else if( !strcmp( argv[i], "-m" ) )
79  UNITS = MEGABYTES;
80  else if( !strcmp( argv[i], "-g" ) )
81  UNITS = GIGABYTES;
82  else if( !strcmp( argv[i], "-T" ) )
83  test_mode = true;
84  else if( !strcmp( argv[i], "-h" ) )
85  usage( argv[0], true );
86  else if( !strcmp( argv[i], "--" ) )
87  no_more_flags = true;
88  else
89  {
90  std::cerr << argv[0] << ": Invalid flag: \"" << argv[i] << "\"." << std::endl << std::endl;
91  usage( argv[0] );
92  }
93  }
94  else
95  {
96  input_file_list.push_back( i );
97  }
98  }
99 
100  if( test_mode )
101  {
102  do_test_mode();
103  if( input_file_list.empty() ) return 0;
104  }
105 
106  moab::Core mbcore;
107  moab::Interface& mb = mbcore;
108  for( std::vector< int >::iterator it = input_file_list.begin(); it != input_file_list.end(); ++it )
109  {
110  rval = mb.load_file( argv[*it] );
111 
112  // if file load failed, print some info and exit
113  if( moab::MB_SUCCESS != rval )
114  {
115  std::string message;
116  mb.get_last_error( message );
117  std::cerr << mb.get_error_string( rval ) << ": " << message << std::endl
118  << argv[*it] << ": Failed to read file." << std::endl;
119  return 1;
120  }
121 
122  std::cout << "Loaded file: " << argv[*it] << std::endl;
123  }
124 
125  // print summary of MOAB's memory use
127  return 0;
128 }
129 
130 // struct to store memory stats
131 struct MemStats
132 {
133  unsigned long long total_storage;
134  unsigned long long total_amortized;
135  unsigned long long entity_storage;
136  unsigned long long entity_amortized;
137  unsigned long long adjacency_storage;
138  unsigned long long adjacency_amortized;
139  unsigned long long tag_storage;
140  unsigned long long tag_amortized;
141 };
142 
143 // test if MemStats object indicates no memory
144 static bool is_zero( const MemStats& stats );
145 
146 // populdate a MemStats structg by calling
147 // moab::Interface::estimated_memory_use
148 static void get_mem_stats( moab::Interface& mb, MemStats& data, moab::EntityType type = moab::MBMAXTYPE );
149 
150 // Formatted string representation of memory size value
151 static std::string memstr( unsigned long long val );
152 
153 // Get string describing tag data type
154 static std::string tag_type_string( moab::Interface& mb, moab::Tag tag );
155 
156 // Get string representation of tag storage type
157 static std::string tag_storage_string( moab::Interface& mb, moab::Tag tag );
158 
159 // Center
160 static std::string center( const char* str, size_t width );
161 
162 void print_memory_stats( moab::Interface& mb, bool per_type, bool per_tag, bool totals, bool sysstats )
163 {
164  moab::ErrorCode rval;
165  const char ANON_TAG_NAME[] = "(anonymous)";
166  const int TYPE_WIDTH = 10;
167  const int MEM_WIDTH = 7;
168  const int MEM2_WIDTH = 2 * MEM_WIDTH + 1;
169  const int MIN_TAG_NAME_WIDTH = strlen( ANON_TAG_NAME );
170  const int DTYPE_WIDTH = 12;
171  const int STORAGE_WIDTH = 8;
172 
173  // per-entity-type table header
174  MemStats stats;
175 
176  if( per_type )
177  {
178 
179  std::cout.fill( ' ' );
180  std::cout << std::left << std::setw( TYPE_WIDTH ) << "Type" << ' ' << center( "Total", MEM2_WIDTH ) << ' '
181  << center( "Entity", MEM2_WIDTH ) << ' ' << center( "Adjacency", MEM2_WIDTH ) << ' '
182  << center( "Tag", MEM2_WIDTH ) << ' ' << std::endl
183  << std::setw( TYPE_WIDTH ) << " ";
184  for( int i = 0; i < 4; ++i )
185  std::cout << ' ' << std::left << std::setw( MEM_WIDTH ) << "Used" << ' ' << std::left
186  << std::setw( MEM_WIDTH ) << "Alloc";
187  std::cout << std::endl;
188  std::cout.fill( '-' );
189  std::cout << std::setw( TYPE_WIDTH ) << '-';
190  for( int i = 0; i < 8; ++i )
191  std::cout << ' ' << std::setw( MEM_WIDTH ) << '-';
192  std::cout.fill( ' ' );
193  std::cout << std::endl;
194 
195  // per-entity-type memory use
196  for( moab::EntityType t = moab::MBVERTEX; t != moab::MBMAXTYPE; ++t )
197  {
198  get_mem_stats( mb, stats, t );
199  if( is_zero( stats ) ) continue; // skip types with no allocated memory
200 
201  std::cout << std::left << std::setw( TYPE_WIDTH ) << moab::CN::EntityTypeName( t ) << ' ' << std::right
202  << std::setw( MEM_WIDTH ) << memstr( stats.total_storage ) << ' ' << std::right
203  << std::setw( MEM_WIDTH ) << memstr( stats.total_amortized ) << ' ' << std::right
204  << std::setw( MEM_WIDTH ) << memstr( stats.entity_storage ) << ' ' << std::right
205  << std::setw( MEM_WIDTH ) << memstr( stats.entity_amortized ) << ' ' << std::right
206  << std::setw( MEM_WIDTH ) << memstr( stats.adjacency_storage ) << ' ' << std::right
207  << std::setw( MEM_WIDTH ) << memstr( stats.adjacency_amortized ) << ' ' << std::right
208  << std::setw( MEM_WIDTH ) << memstr( stats.tag_storage ) << ' ' << std::right
209  << std::setw( MEM_WIDTH ) << memstr( stats.tag_amortized ) << std::endl;
210  }
211  } // end per_type
212 
213  if( per_tag )
214  {
215  // get list of tags
216  std::vector< moab::Tag > tags;
217  std::vector< moab::Tag >::const_iterator ti;
218  mb.tag_get_tags( tags );
219 
220  // figure out required field with to fit longest tag name
221  unsigned maxlen = MIN_TAG_NAME_WIDTH;
222  for( ti = tags.begin(); ti != tags.end(); ++ti )
223  {
224  std::string name;
225  rval = mb.tag_get_name( *ti, name );
226  if( moab::MB_SUCCESS != rval ) continue;
227  if( name.size() > maxlen ) maxlen = name.size();
228  }
229 
230  // print header for per-tag data
231  if( !tags.empty() )
232  {
233  std::cout.fill( ' ' );
234  std::cout << std::endl
235  << std::left << std::setw( maxlen ) << "Tag Name" << ' ' << std::left << std::setw( DTYPE_WIDTH )
236  << "Type" << ' ' << std::left << std::setw( STORAGE_WIDTH ) << "Storage" << ' ' << std::left
237  << std::setw( MEM_WIDTH ) << "Used" << ' ' << std::left << std::setw( MEM_WIDTH ) << "Alloc"
238  << std::endl;
239  std::cout.fill( '-' );
240  std::cout << std::setw( maxlen ) << '-' << ' ' << std::setw( DTYPE_WIDTH ) << '-' << ' '
241  << std::setw( STORAGE_WIDTH ) << '-' << ' ' << std::setw( MEM_WIDTH ) << '-' << ' '
242  << std::setw( MEM_WIDTH ) << '-' << std::endl;
243  std::cout.fill( ' ' );
244  }
245 
246  // print per-tag memory use
247  for( ti = tags.begin(); ti != tags.end(); ++ti )
248  {
249  std::string name;
250  rval = mb.tag_get_name( *ti, name );
251  if( moab::MB_SUCCESS != rval || name.empty() ) name = ANON_TAG_NAME;
252 
253  unsigned long long occupied, allocated;
254  mb.estimated_memory_use( 0, 0, 0, 0, 0, 0, 0, 0, &*ti, 1, &occupied, &allocated );
255 
256  std::cout << std::left << std::setw( maxlen ) << name << ' ' << std::right << std::setw( DTYPE_WIDTH )
257  << tag_type_string( mb, *ti ) << ' ' << std::right << std::setw( STORAGE_WIDTH )
258  << tag_storage_string( mb, *ti ) << ' ' << std::right << std::setw( MEM_WIDTH )
259  << memstr( occupied ) << ' ' << std::right << std::setw( MEM_WIDTH ) << memstr( allocated )
260  << std::endl;
261  }
262  } // end per_tag
263 
264  if( totals )
265  {
266  // print summary of overall memory use
267  get_mem_stats( mb, stats );
268  std::cout << std::endl
269  << "TOTAL: (Used/Allocated)" << std::endl
270  << "memory: " << memstr( stats.total_storage ) << "/" << memstr( stats.total_amortized )
271  << std::endl
272  << "entity: " << memstr( stats.entity_storage ) << "/" << memstr( stats.entity_amortized )
273  << std::endl
274  << "adjacency: " << memstr( stats.adjacency_storage ) << "/" << memstr( stats.adjacency_amortized )
275  << std::endl
276  << "tag: " << memstr( stats.tag_storage ) << "/" << memstr( stats.tag_amortized ) << std::endl
277  << std::endl;
278 
279  } // end totals
280 
281  if( sysstats )
282  {
283  std::FILE* filp = std::fopen( "/proc/self/stat", "r" );
284  unsigned long long vsize;
285  long rss;
286  if( filp && 2 == std::fscanf( filp,
287  "%*d " // pid
288  "%*s " // comm
289  "%*c " // state
290  "%*d " // ppid
291  "%*d " // pgrp
292  "%*d " // session
293  "%*d " // tty_nr
294  "%*d " // tpgid
295  "%*u " // flags
296  "%*u " // minflt
297  "%*u " // cminflt
298  "%*u " // majflt
299  "%*u " // cmajflt
300  "%*u " // utime
301  "%*u " // stime
302  "%*d " // cutime
303  "%*d " // cstime
304  "%*d " // priority
305  "%*d " // nice
306  "%*d " // num_threads
307  "%*d " // itrealvalue
308  "%*u " // starttime
309  "%llu " // vsize
310  "%ld", // rss
311  &vsize, &rss ) )
312  {
313 #ifndef _WIN32
314  long long tmprss = rss * getpagesize();
315 #endif
316  std::cout << std::endl
317  << "SYSTEM:" << std::endl
318  << "Virtual memory: " << memstr( vsize )
319 #ifndef _WIN32
320  << std::endl
321  << "Resident set size: " << memstr( tmprss )
322 #endif
323  << std::endl;
324  }
325  else
326  {
327 #ifndef _WIN32
328  struct rusage sysdata;
329  if( getrusage( RUSAGE_SELF, &sysdata ) )
330  {
331  std::cerr << "getrusage failed" << std::endl;
332  }
333  else
334  {
335  rss = sysdata.ru_maxrss;
336  long long tmprss = rss * getpagesize();
337  std::cerr << std::endl
338  << "SYSTEM:" << std::endl
339  << "Resident set size: " << memstr( tmprss ) << std::endl;
340  }
341 #endif
342  }
343  if( filp ) fclose( filp );
344  } // end sysstats
345 }
346 
347 bool is_zero( const MemStats& stats )
348 {
349  return stats.total_amortized == 0;
350 }
351 
352 void get_mem_stats( moab::Interface& mb, MemStats& data, moab::EntityType type )
353 {
354  if( type != moab::MBMAXTYPE )
355  {
356  moab::Range range;
357  mb.get_entities_by_type( 0, type, range );
358  mb.estimated_memory_use( range, &data.total_storage, &data.total_amortized, &data.entity_storage,
359  &data.entity_amortized, &data.adjacency_storage, &data.adjacency_amortized, 0, 0,
360  &data.tag_storage, &data.tag_amortized );
361  }
362  else
363  {
364  mb.estimated_memory_use( 0, 0, &data.total_storage, &data.total_amortized, &data.entity_storage,
365  &data.entity_amortized, &data.adjacency_storage, &data.adjacency_amortized, 0, 0,
366  &data.tag_storage, &data.tag_amortized );
367  }
368 }
369 
370 // rounded division
371 static unsigned long long rdiv( unsigned long long num, unsigned long long den )
372 {
373  return ( num + den / 2 ) / den;
374 }
375 
376 std::string memstr( unsigned long long val )
377 {
378  const unsigned long long kb = 1024;
379  const unsigned long long mb = kb * kb;
380  const unsigned long long gb = kb * mb;
381  const unsigned long long tb = kb * gb;
382 
383  std::ostringstream s;
384  if( UNITS == HUMAN )
385  {
386  if( val >= 10 * tb )
387  s << rdiv( val, tb ) << "TB";
388  else if( val >= 10 * gb )
389  s << rdiv( val, gb ) << "GB";
390  else if( val >= 10 * mb )
391  s << rdiv( val, mb ) << "MB";
392  else if( val >= 10 * kb )
393  s << rdiv( val, kb ) << "kB";
394  else if( val > 0 )
395  s << val << " B";
396  else
397  s << "0 ";
398  }
399  else
400  {
401  unsigned long long den = 1;
402  switch( UNITS )
403  {
404  case BYTES:
405  den = 1;
406  break;
407  case KILOBYTES:
408  den = kb;
409  break;
410  case MEGABYTES:
411  den = mb;
412  break;
413  case GIGABYTES:
414  den = gb;
415  break;
416  case HUMAN:
417  break; // handled above, list here to suppress warning
418  }
419 
420  s << rdiv( val, den );
421  }
422  return s.str();
423 }
424 
426 {
427  moab::ErrorCode rval;
428  std::ostringstream s;
429 
430  moab::DataType type;
431  rval = mb.tag_get_data_type( tag, type );
432  if( moab::MB_SUCCESS != rval ) return std::string();
433 
434  int typesize;
435  std::string typestr;
436  switch( type )
437  {
439  typestr = "int";
440  typesize = sizeof( int );
441  break;
443  typestr = "double";
444  typesize = sizeof( double );
445  break;
447  typestr = "handle";
448  typesize = sizeof( moab::EntityHandle );
449  break;
450  case moab::MB_TYPE_BIT:
451  typesize = 1;
452  typestr = "bits";
453  break;
455  typesize = 1;
456  typestr = "bytes";
457  break;
458  default:
459  typesize = 1;
460  typestr = "???";
461  break;
462  }
463 
464  int size;
465  rval = mb.tag_get_length( tag, size );
466  if( moab::MB_VARIABLE_DATA_LENGTH == rval )
467  s << "VAR " << typestr;
468  else if( moab::MB_SUCCESS == rval )
469  s << size / typesize << " " << typestr;
470  // else do nothing
471 
472  return s.str();
473 }
474 
476 {
477  moab::ErrorCode rval;
478  moab::TagType type;
479  rval = mb.tag_get_type( tag, type );
480  if( moab::MB_SUCCESS != rval ) return std::string();
481 
482  switch( type )
483  {
484  case moab::MB_TAG_DENSE:
485  return "dense";
486  case moab::MB_TAG_SPARSE:
487  return "sparse";
488  case moab::MB_TAG_BIT:
489  return "bit";
490  default:
491  return "(none)";
492  }
493 }
494 
495 std::string center( const char* str, size_t width )
496 {
497  std::string text( str );
498  if( text.size() >= width ) return text;
499 
500  width -= text.size();
501  if( 1u == width )
502  {
503  text += " ";
504  return text;
505  }
506 
507  std::ostringstream s;
508  s << std::setw( width / 2 ) << ' ' << text << std::setw( width / 2 + width % 2 ) << ' ';
509  return s.str();
510 }
511 
513 {
514  const char prefix[] = "****************";
515  moab::Core mbcore;
516  moab::Interface& mb = mbcore;
517  moab::ErrorCode rval;
518  moab::Range handles;
520  moab::Range::iterator jt, it;
521  const unsigned N = 1000;
522 
523  // creating some vertices
524  double coords[3] = { 1, 2, 3 };
525  for( unsigned i = 0; i < N; ++i )
526  mb.create_vertex( coords, h );
527  std::cout << std::endl << prefix << "Created " << N << " vertices" << std::endl;
528  print_memory_stats( mb, true, false, true, true );
529 
530  for( unsigned i = 0; i < N; ++i )
531  mb.create_vertex( coords, h );
532  std::cout << std::endl << prefix << "Created another " << N << " vertices" << std::endl;
533  print_memory_stats( mb, true, false, true, true );
534 
535  for( int i = 0; i < 100; ++i )
536  {
537  for( unsigned j = 0; j < N; ++j )
538  mb.create_vertex( coords, h );
539  }
540  std::cout << std::endl << prefix << "Created another " << 100 * N << " vertices" << std::endl;
541  print_memory_stats( mb, true, false, true, true );
542 
543  // create some elements
544  handles.clear();
545  mb.get_entities_by_type( 0, moab::MBVERTEX, handles );
546  it = handles.begin();
547  for( unsigned i = 0; i < N - 2; ++i, ++it )
548  {
549  jt = it;
550  moab::EntityHandle conn[3];
551  conn[0] = *jt;
552  ++jt;
553  conn[1] = *jt;
554  ++jt;
555  conn[2] = *jt;
556  ++jt;
557  mb.create_element( moab::MBTRI, conn, 3, h );
558  }
559  std::cout << std::endl << prefix << "Created " << N - 2 << " triangles" << std::endl;
560  print_memory_stats( mb, true, false, true, true );
561 
562  it = handles.begin();
563  for( unsigned i = 0; i < N - 3; ++i, ++it )
564  {
565  jt = it;
566  moab::EntityHandle conn[4];
567  conn[0] = *jt;
568  ++jt;
569  conn[1] = *jt;
570  ++jt;
571  conn[2] = *jt;
572  ++jt;
573  conn[3] = *jt;
574  ++jt;
575  mb.create_element( moab::MBQUAD, conn, 4, h );
576  }
577  std::cout << std::endl << prefix << "Created " << N - 3 << " quads" << std::endl;
578  print_memory_stats( mb, true, false, true, true );
579 
580  for( int i = 0; i < 100; ++i )
581  {
582  it = handles.begin();
583  for( unsigned j = 0; j < N - 3; ++j, ++it )
584  {
585  jt = it;
586  moab::EntityHandle conn[4];
587  conn[0] = *jt;
588  ++jt;
589  conn[1] = *jt;
590  ++jt;
591  conn[2] = *jt;
592  ++jt;
593  conn[3] = *jt;
594  ++jt;
595  mb.create_element( moab::MBQUAD, conn, 4, h );
596  }
597  }
598  std::cout << std::endl << prefix << "Created another " << 100 * ( N - 3 ) << " quads" << std::endl;
599  print_memory_stats( mb, true, false, true, true );
600 
601  // set global ID
602  moab::Tag tag;
603  rval = mb.tag_get_handle( "GLOBAL_ID", 1, moab::MB_TYPE_INTEGER, tag );
604  if( moab::MB_SUCCESS != rval )
605  {
606  std::cerr << "Failed to get GLOBAL_ID tag handle" << std::endl;
607  return;
608  }
609  handles.clear();
610  mb.get_entities_by_type( 0, moab::MBVERTEX, handles );
611  int id = 1;
612  for( it = handles.begin(); it != handles.end(); ++it )
613  {
614  mb.tag_set_data( tag, &*it, 1, &id );
615  ++id;
616  }
617  std::cout << std::endl << prefix << "Set global ID tag on " << handles.size() << " vertices" << std::endl;
618  print_memory_stats( mb, true, true, true, true );
619 
620  handles.clear();
621  mb.get_entities_by_type( 0, moab::MBQUAD, handles );
622  id = 1;
623  for( it = handles.begin(); it != handles.end(); ++it )
624  {
625  mb.tag_set_data( tag, &*it, 1, &id );
626  ++id;
627  }
628  std::cout << std::endl << prefix << "Set global ID tag on " << handles.size() << " quads" << std::endl;
629  print_memory_stats( mb, true, true, true, true );
630 
631  // create and set a sparse tag
632  mb.tag_get_handle( "mem_test_tag", 3, moab::MB_TYPE_DOUBLE, tag, moab::MB_TAG_SPARSE | moab::MB_TAG_CREAT );
633  handles.clear();
634  mb.get_entities_by_type( 0, moab::MBVERTEX, handles );
635  for( it = handles.begin(); it != handles.end(); ++it )
636  {
637  mb.get_coords( &*it, 1, coords );
638  mb.tag_set_data( tag, &*it, 1, coords );
639  }
640  std::cout << std::endl
641  << prefix << "Copied vertex coords to sparse tag for " << handles.size() << " vertices" << std::endl;
642  print_memory_stats( mb, true, true, true, true );
643 
644  // create and set bit tag
645  mb.tag_get_handle( "mem_test_bit", 1, moab::MB_TYPE_BIT, tag, moab::MB_TAG_CREAT );
646  handles.clear();
647  mb.get_entities_by_type( 0, moab::MBTRI, handles );
648  for( it = handles.begin(); it != handles.end(); ++it )
649  {
650  char byte = '\001';
651  mb.tag_set_data( tag, &*it, 1, &byte );
652  }
653  std::cout << std::endl << prefix << "Set 1-bit tag for " << handles.size() << " triangles" << std::endl;
654  print_memory_stats( mb, true, true, true, true );
655 
656  // create vertex to element adjacency data
657  handles.clear();
658  mb.get_entities_by_type( 0, moab::MBVERTEX, handles );
659  std::vector< moab::EntityHandle > adj_vec;
660  mb.get_adjacencies( &*handles.begin(), 1, 2, false, adj_vec );
661  std::cout << std::endl << prefix << "Created vertex-to-element adjacencies" << std::endl;
662  print_memory_stats( mb, true, false, true, true );
663  std::cout << std::endl;
664 }