Mesh Oriented datABase  (version 5.5.0)
An array-based unstructured mesh library
IODebugTrack.cpp
Go to the documentation of this file.
1 #include "IODebugTrack.hpp"
2 #include "moab/Range.hpp"
3 #include <iostream>
4 #include <vector>
5 #include <cassert>
6 
7 #ifdef MOAB_HAVE_MPI
8 #include "moab_mpi.h"
9 #endif
10 
11 const char PFX[] = ">>> ";
12 
13 namespace moab
14 {
15 
17  const std::string& name,
18  std::ostream& output_stream,
19  unsigned long table_size )
20  : enableOutput( enabled ), tableName( name ), ostr( output_stream ), maxSize( table_size ), haveMPI( false )
21 {
22 #ifdef MOAB_HAVE_MPI
23  MPI_Comm_rank( MPI_COMM_WORLD, &mpiRank );
24 #else
25  mpiRank = 0;
26 #endif
27 }
28 
29 IODebugTrack::IODebugTrack( bool enabled, const std::string& name, unsigned long table_size )
30  : enableOutput( enabled ), tableName( name ), ostr( std::cerr ), maxSize( table_size )
31 {
32  mpiRank = 0;
33  haveMPI = false;
34 #ifdef MOAB_HAVE_MPI
35  int have_init = 0;
36  MPI_Initialized( &have_init );
37  if( have_init )
38  {
39  haveMPI = true;
40  MPI_Comm_rank( MPI_COMM_WORLD, &mpiRank );
41  }
42 #endif
43 }
44 
46 {
47  if( !enableOutput || mpiRank ) // only root prints gap summary
48  return;
49 
50  if( dataSet.empty() )
51  {
52  ostr << PFX << tableName << " : No Data Written!!!!" << std::endl;
53  return;
54  }
55 
56  std::list< DRange >::const_iterator i;
57  if( !maxSize )
58  {
59  for( i = dataSet.begin(); i != dataSet.end(); ++i )
60  if( i->end >= maxSize ) maxSize = i->end + 1;
61  }
62  Range processed;
63  Range::iterator h = processed.begin();
64  bool wrote_zero = false;
65  for( i = dataSet.begin(); i != dataSet.end(); ++i )
66  {
67  // ranges cannot contain zero
68  assert( i->begin <= i->end );
69  if( i->begin )
70  h = processed.insert( h, i->begin, i->end );
71  else
72  {
73  wrote_zero = true;
74  if( i->end ) h = processed.insert( h, i->begin + 1, i->end );
75  }
76  }
77 
78  // ranges cannot contain zero
79  Range unprocessed;
80  if( maxSize > 1 ) unprocessed.insert( 1, maxSize - 1 );
81  unprocessed = subtract( unprocessed, processed );
82  if( unprocessed.empty() ) return;
83 
85  for( j = unprocessed.const_pair_begin(); j != unprocessed.const_pair_end(); ++j )
86  {
87  unsigned long b = j->first;
88  unsigned long e = j->second;
89  if( b == 1 && !wrote_zero ) b = 0;
90 
91  ostr << PFX << tableName << " : range not read/written: [" << b << "," << e << "]" << std::endl;
92  ostr.flush();
93  }
94 }
95 
96 void IODebugTrack::record_io( unsigned long begin, unsigned long count )
97 {
98  if( enableOutput && count )
99  {
100  DRange ins = { begin, begin + count - 1, static_cast< long unsigned >( mpiRank ) };
101  record_io( ins );
102  }
103 }
104 
106 {
107  if( !enableOutput ) return;
108 
109  // only root should get non-local data
110  assert( !mpiRank || ins.rank == (unsigned)mpiRank );
111  assert( ins.begin <= ins.end );
112 
113  // test for out-of-bounds write
114  if( maxSize && ins.end >= maxSize )
115  ostr << ": Out of bounds write on rank " << mpiRank << ": [" << ins.begin << "," << ins.end
116  << "] >= " << maxSize << std::endl;
117 
118  // test for overlap with all existing ranges
119  std::list< DRange >::iterator i;
120  for( i = dataSet.begin(); i != dataSet.end(); ++i )
121  {
122  if( i->end >= ins.begin && i->begin <= ins.end )
123  { // if overlap
124  ostr << PFX << tableName;
125  if( i->rank == ins.rank )
126  {
127  if( mpiRank == (int)ins.rank ) ostr << ": Local overwrite on rank " << mpiRank;
128 
129  // otherwise should have been logged on remote proc, do nothing here
130  }
131  else
132  ostr << ": Conflicting write for ranks " << i->rank << " and " << ins.rank;
133 
134  ostr << ": [" << i->begin << "," << i->end << "] and [" << ins.begin << "," << ins.end << "]" << std::endl;
135  ostr.flush();
136  }
137  }
138 
139  dataSet.push_back( ins );
140 }
141 
143 {
144 #ifdef MOAB_HAVE_MPI
145  if( !enableOutput || !haveMPI ) return;
146 
147  int commsize;
148  MPI_Comm_size( MPI_COMM_WORLD, &commsize );
149  int count = 3 * dataSet.size();
150  std::vector< int > displs( commsize ), counts( commsize );
151  MPI_Gather( &count, 1, MPI_INT, &counts[0], 1, MPI_INT, 0, MPI_COMM_WORLD );
152  displs[0] = 0;
153  for( int i = 1; i < commsize; ++i )
154  displs[i] = displs[i - 1] + counts[i - 1];
155  int total = ( displs.back() + counts.back() ) / 3;
156  count /= 3;
157 
158  std::vector< DRange > send( dataSet.size() ), recv( total );
159  std::copy( dataSet.begin(), dataSet.end(), send.begin() );
160  MPI_Gatherv( (void*)&send[0], 3 * send.size(), MPI_UNSIGNED_LONG, (void*)&recv[0], &counts[0], &displs[0],
161  MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD );
162 
163  if( 0 == mpiRank )
164  {
165  for( int i = count; i < total; ++i )
166  record_io( recv[i] );
167  }
168  else
169  {
170  dataSet.clear();
171  }
172 #endif
173 }
174 
175 } // namespace moab