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 {
41 HUMAN,
42 BYTES,
43 KILOBYTES,
44 MEGABYTES,
45 GIGABYTES
46 };
47 Units UNITS = HUMAN;
48
49
50 static void print_memory_stats( moab::Interface& mb,
51 bool per_type = true,
52 bool per_tag = true,
53 bool totals = true,
54 bool sysstats = true );
55
56
57 static void do_test_mode();
58
59
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
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
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
126 print_memory_stats( mb );
127 return 0;
128 }
129
130
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
144 static bool is_zero( const MemStats& stats );
145
146
147
148 static void get_mem_stats( moab::Interface& mb, MemStats& data, moab::EntityType type = moab::MBMAXTYPE );
149
150
151 static std::string memstr( unsigned long long val );
152
153
154 static std::string tag_type_string( moab::Interface& mb, moab::Tag tag );
155
156
157 static std::string tag_storage_string( moab::Interface& mb, moab::Tag tag );
158
159
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
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
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;
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 }
212
213 if( per_tag )
214 {
215
216 std::vector< moab::Tag > tags;
217 std::vector< moab::Tag >::const_iterator ti;
218 mb.tag_get_tags( tags );
219
220
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
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
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 }
263
264 if( totals )
265 {
266
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 }
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 "
288 "%*s "
289 "%*c "
290 "%*d "
291 "%*d "
292 "%*d "
293 "%*d "
294 "%*d "
295 "%*u "
296 "%*u "
297 "%*u "
298 "%*u "
299 "%*u "
300 "%*u "
301 "%*u "
302 "%*d "
303 "%*d "
304 "%*d "
305 "%*d "
306 "%*d "
307 "%*d "
308 "%*u "
309 "%llu "
310 "%ld",
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 }
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
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;
418 }
419
420 s << rdiv( val, den );
421 }
422 return s.str();
423 }
424
425 std::string tag_type_string( moab::Interface& mb, moab::Tag tag )
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 {
438 case moab::MB_TYPE_INTEGER:
439 typestr = "int";
440 typesize = sizeof( int );
441 break;
442 case moab::MB_TYPE_DOUBLE:
443 typestr = "double";
444 typesize = sizeof( double );
445 break;
446 case moab::MB_TYPE_HANDLE:
447 typestr = "handle";
448 typesize = sizeof( moab::EntityHandle );
449 break;
450 case moab::MB_TYPE_BIT:
451 typesize = 1;
452 typestr = "bits";
453 break;
454 case moab::MB_TYPE_OPAQUE:
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
471
472 return s.str();
473 }
474
475 std::string tag_storage_string( moab::Interface& mb, moab::Tag tag )
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
512 void do_test_mode()
513 {
514 const char prefix[] = "****************";
515 moab::Core mbcore;
516 moab::Interface& mb = mbcore;
517 moab::ErrorCode rval;
518 moab::Range handles;
519 moab::EntityHandle h;
520 moab::Range::iterator jt, it;
521 const unsigned N = 1000;
522
523
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
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
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
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
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
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 }