~ubuntu-branches/ubuntu/precise/insighttoolkit/precise

« back to all changes in this revision

Viewing changes to Code/Common/itkSmapsFileParser.cxx

  • Committer: Bazaar Package Importer
  • Author(s): Steve M. Robbins
  • Date: 2008-12-19 20:16:49 UTC
  • mfrom: (1.2.1 upstream) (4.1.1 sid)
  • Revision ID: james.westby@ubuntu.com-20081219201649-drt97guwl2ryt0cn

* New upstream version.
  - patches/nifti-versioning.patch: Remove.  Applied upstream.
  - control:
  - rules: Update version numbers, package names.

* control: Build-depend on uuid-dev (gdcm uses it).

* copyright: Update download URL.

* rules: Adhere to parallel=N in DEB_BUILD_OPTIONS by setting MAKEFLAGS.

* compat: Set to 7.
* control: Update build-dep on debhelper to version >= 7.

* CMakeCache.txt.debian: Set CMAKE_BUILD_TYPE to "RELEASE" so that we
  build with -O3 (not -O2), necessary to optimize the templated code.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*=========================================================================
 
2
 
 
3
  Program:   Insight Segmentation & Registration Toolkit
 
4
  Module:    $RCSfile: itkSmapsFileParser.cxx,v $
 
5
  Language:  C++
 
6
  Date:      $Date: 2008-10-24 18:11:22 $
 
7
  Version:   $Revision: 1.1 $
 
8
 
 
9
  Copyright (c) Insight Software Consortium. All rights reserved.
 
10
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
 
11
 
 
12
     This software is distributed WITHOUT ANY WARRANTY; without even 
 
13
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
 
14
     PURPOSE.  See the above copyright notices for more information.
 
15
 
 
16
=========================================================================*/
 
17
 
 
18
#include "itkSmapsFileParser.h"
 
19
 
 
20
namespace itk
 
21
{
 
22
 
 
23
bool ITKCommon_EXPORT ci_equal(char a, char b)
 
24
{
 
25
  return tolower(static_cast<int>(a)) == tolower(static_cast<int>(b));
 
26
}
 
27
 
 
28
MapRecord::~MapRecord()
 
29
{
 
30
}
 
31
 
 
32
void MapRecord::Reset(void)
 
33
{
 
34
  m_Tokens.clear();
 
35
  m_RecordName = "";
 
36
}
 
37
 
 
38
/* SmapsRecord implementation */
 
39
 
 
40
ITKCommon_EXPORT std::istream&  operator>>(std::istream &in, SmapsRecord &record)
 
41
{
 
42
  record.Reset();
 
43
 
 
44
  try 
 
45
    {
 
46
    // Get Header line
 
47
    std::string headerline;
 
48
    std::getline( in, headerline);
 
49
 
 
50
    if (headerline.empty())
 
51
      {
 
52
      return in;
 
53
      }
 
54
 
 
55
    // Get name
 
56
    std::istringstream stream(headerline);
 
57
    std::string address, perms, offset, device;  
 
58
    int inode=-1;
 
59
    // the header is defined with the following expression: "address permissions offset device inode [name]"
 
60
    stream>>address;
 
61
    if (!stream.good()) itkGenericExceptionMacro( << "bad address: " << address );
 
62
    stream>>perms;
 
63
    if (!stream.good()) itkGenericExceptionMacro( << "bad perms: " << perms );
 
64
    stream>>offset;
 
65
    if (!stream.good()) itkGenericExceptionMacro( << "bad offset: " << offset );
 
66
    stream>>device;
 
67
    if (!stream.good()) itkGenericExceptionMacro( << "bad device: " << device );
 
68
    stream>>inode;
 
69
    // name can be empty
 
70
    if (!stream.eof())
 
71
      {
 
72
      std::getline(stream, record.m_RecordName);
 
73
      }
 
74
    
 
75
    std::string token;
 
76
    int lastPos = in.tellg();
 
77
    // a token is defined with the following expression: "token: N kB" 
 
78
    while ( std::getline(in,token,':').good() )
 
79
      {
 
80
      //make sure it is a token and not a new record. A token doesn't contains space character
 
81
      if ( token.find(' ') != std::string::npos )
 
82
        {
 
83
        in.seekg (lastPos, std::ios::beg);
 
84
        break;
 
85
        }
 
86
      //fill the token with the memory usage N in kB
 
87
      in>>record.m_Tokens[token];
 
88
      std::getline(in,token);
 
89
      if ( token != " kB" || !in.good()) itkGenericExceptionMacro( << "bad size: " << record.m_Tokens[token] );
 
90
      lastPos = in.tellg();
 
91
      }
 
92
    }
 
93
  catch (ExceptionObject excp)
 
94
    {
 
95
    record.Reset();
 
96
    // propagate the exception
 
97
    itkGenericExceptionMacro( << "The smaps header is corrupted" );
 
98
    }
 
99
  return in;
 
100
}
 
101
 
 
102
 
 
103
ITKCommon_EXPORT std::istream& operator>>(std::istream &in, VMMapSummaryRecord &record)
 
104
{
 
105
  record.Reset();
 
106
 
 
107
  try 
 
108
    {
 
109
    // the record name can have spaces.
 
110
    in >> record.m_RecordName;
 
111
 
 
112
    if (in.eof() && record.m_RecordName.empty())
 
113
      {
 
114
      return in;
 
115
      }
 
116
 
 
117
    if (!in.good()) 
 
118
      {
 
119
      itkGenericExceptionMacro( << "Bad record name: " << record.m_RecordName );
 
120
      }
 
121
 
 
122
    std::string bracket;
 
123
 
 
124
    while ( (in>>bracket).good() && bracket.find("[",0) == std::string::npos )
 
125
      {
 
126
      record.m_RecordName += std::string(" ") + bracket;  
 
127
      }
 
128
 
 
129
    if (!in.good() || bracket.find("[",0) == std::string::npos ) 
 
130
      {
 
131
      itkGenericExceptionMacro( << "For record: " << record.m_RecordName
 
132
                               << ", bad left bracket: " << bracket );
 
133
      }
 
134
 
 
135
    in >> record.m_Tokens["Size"];
 
136
 
 
137
    if( !in.good() ) 
 
138
      {
 
139
      itkGenericExceptionMacro( << "For record: " << record.m_RecordName
 
140
                               << ", bad size: " << record.m_Tokens["Size"] );
 
141
      }
 
142
 
 
143
    in >> bracket;
 
144
 
 
145
    if( !in.good() ) 
 
146
      {
 
147
      itkGenericExceptionMacro( << "For record: " << record.m_RecordName
 
148
                               << ", bad right bracket: " << bracket );
 
149
      }
 
150
    }
 
151
  catch (ExceptionObject excp)
 
152
    {
 
153
    record.Reset();
 
154
    // propagate the exception
 
155
    itkGenericExceptionMacro( << "The smaps header is corrupted" );
 
156
    }
 
157
  return in;
 
158
}
 
159
 
 
160
/* typical output:
 
161
 *  __DATA                             c000 [   4K] rw-/rwx SM=ZER ...l/bin/cronwake
 
162
 *  VALLOC_USED(DefaultMallocZone_    25000 [   4K] rw-/rwx SM=COW
 
163
 *  MALLOC_USED(DefaultMallocZone_    26000 [  44K] rw-/rwx SM=ZER
 
164
 *                                   31000 [   4K] rw-/rwx SM=COW 34300000 00000...
 
165
 *                                   32000 [  76K] rw-/rwx SM=COW 00001eaa 01001...
 
166
 *                                   45000 [   4K] rw-/rwx SM=COW 34300000 00000...
 
167
 *                                   46000 [ 344K] rw-/rwx SM=COW 00000000 00000...
 
168
 *  Memory tag=7                     100000 [1044K] rw-/rwx SM=COW
 
169
 *  MALLOC_USED(DefaultMallocZone_   300000 [   4K] rw-/rwx SM=PRV
 
170
 *  Submap                90000000-9fffffff         r--/r-- machine-wide submap
 
171
 *  __DATA                         a0000000 [   4K] rw-/rw- SM=COW ...System.B.dylib
 
172
 *  __DATA                         a0001000 [   4K] rw-/rw- SM=ZER ...System.B.dylib
 
173
 *  __DATA                         a0002000 [   4K] rw-/rw- SM=COW ...System.B.dylib
 
174
 *  __DATA                         a0003000 [  20K] rw-/rw- SM=COW ...System.B.dylib
 
175
*/
 
176
 
 
177
ITKCommon_EXPORT std::istream& operator>>(std::istream &in, VMMapRecord &record)
 
178
{
 
179
  record.Reset();
 
180
  bool submapFound = false;
 
181
  bool recordHasNoName = false;
 
182
  char line[256];
 
183
  try 
 
184
    {
 
185
    std::string address;
 
186
    do
 
187
      {
 
188
      // the record name can have spaces.
 
189
      in >> record.m_RecordName;
 
190
      if( in.eof() || record.m_RecordName.empty() )
 
191
        {
 
192
        return in;
 
193
        }
 
194
 
 
195
      if (!in.good())
 
196
        {
 
197
        itkGenericExceptionMacro( << "Bad record name: " << record.m_RecordName );
 
198
        }
 
199
 
 
200
      //skip Submap entries
 
201
      if ( record.m_RecordName == "Submap" )
 
202
        {
 
203
        in.getline(line,256);
 
204
        submapFound = true;
 
205
        }
 
206
 
 
207
      // all the records have been parsed, this is a new section
 
208
      else if ( record.m_RecordName == "====" )
 
209
        {
 
210
        record.Reset();
 
211
        return in;
 
212
        }
 
213
      else
 
214
        {
 
215
        // the name is folowed by an address
 
216
        in >> address;
 
217
 
 
218
        if( !in.good() )
 
219
          {
 
220
          itkGenericExceptionMacro( << "For record: " << record.m_RecordName
 
221
                                    << ", bad address: " << address );
 
222
          }
 
223
        // If address is "[" then recordName was the address and there is name for 
 
224
        // the record, skip it.
 
225
        if ( address.find("[",0) != std::string::npos )
 
226
          {
 
227
          in.getline(line,256);
 
228
          recordHasNoName = true;
 
229
          }
 
230
        else
 
231
          {
 
232
          recordHasNoName = false;
 
233
          }
 
234
        submapFound = false;
 
235
        }
 
236
      } while(submapFound || recordHasNoName);
 
237
 
 
238
    std::string bracket;
 
239
 
 
240
    while ( (in>>bracket).good() && bracket.find("[",0) == std::string::npos )
 
241
      {
 
242
      // the string is not a bracket yet, but probably the address. So the previous
 
243
      // address was just the name 
 
244
      record.m_RecordName += std::string(" ") + address;
 
245
      address = bracket;
 
246
      }
 
247
    if (!in.good() || bracket.find("[",0) == std::string::npos ) 
 
248
      {
 
249
      itkGenericExceptionMacro( << "For record: " << record.m_RecordName
 
250
                               << ", bad left bracket: " << bracket );
 
251
      }
 
252
    if ( bracket.length() > 1 )
 
253
      {//bracket contains the size, ie "[1024K]"
 
254
      record.m_Tokens["Size"] = atoi(bracket.substr(1,bracket.length()-3).c_str());
 
255
      }
 
256
    else
 
257
      {
 
258
      in>>record.m_Tokens["Size"];
 
259
      }
 
260
    if (!in.good()) 
 
261
      {
 
262
      itkGenericExceptionMacro( << "For record: " << record.m_RecordName
 
263
                               << ", bad size: " << record.m_Tokens["Size"] );
 
264
      }
 
265
    in.getline(line,256);
 
266
    if (!in.good()) 
 
267
      {
 
268
      itkGenericExceptionMacro( << "For record: " << record.m_RecordName
 
269
                               << ", bad end of line: " << line );
 
270
      }
 
271
    }
 
272
  catch (ExceptionObject excp)
 
273
    {
 
274
    record.Reset();
 
275
    // propagate the exception
 
276
    itkGenericExceptionMacro( << "The smaps header is corrupted" );
 
277
    }
 
278
  return in;
 
279
}
 
280
 
 
281
 
 
282
//bool ITKCommon_EXPORT ci_equal(char a, char b); // located in itkSmapsFileParser.cxx
 
283
 
 
284
/** Binary functor to accumulate memory usage in kB
 
285
*/
 
286
template<class TFirstType>
 
287
struct MapRecordPlusor{
 
288
  MapRecordPlusor<TFirstType>(const char * token = "Size")
 
289
    :m_Token(token)
 
290
    {
 
291
    }
 
292
 
 
293
  TFirstType operator()(TFirstType first, const MapRecord* const & second)
 
294
    { 
 
295
    std::map<std::string,unsigned int>::const_iterator it = second->m_Tokens.find(m_Token);
 
296
    return first + ((it!=second->m_Tokens.end())?it->second:0); 
 
297
    }
 
298
  const char * m_Token;
 
299
};
 
300
 
 
301
/** Binary functor to accumulate memory usage in kB
 
302
 *  The record must match (insensitively) the filter in order to be taken into account
 
303
 */
 
304
template<class TFirstType>
 
305
struct MapRecordConditionalPlusor{  
 
306
  MapRecordConditionalPlusor<TFirstType>(const char * filter, const char * token = "Size")
 
307
    :m_Filter(filter), m_Token(token)
 
308
  {
 
309
  }
 
310
  TFirstType operator()(TFirstType first, const MapRecord* const &second)
 
311
    {
 
312
      if ( std::search(second->m_RecordName.begin(),second->m_RecordName.end(),
 
313
        m_Filter.begin(),m_Filter.end(),ci_equal) != second->m_RecordName.end())
 
314
      {
 
315
      return MapRecordPlusor<TFirstType>(m_Token)(first,second);
 
316
      }
 
317
    return first;
 
318
    }
 
319
  std::string m_Filter;
 
320
  const char * m_Token;
 
321
};
 
322
 
 
323
/**              ---             MapData               ---              **/
 
324
 
 
325
/** MadData destructor */
 
326
MapData::~MapData()
 
327
{
 
328
  this->Reset();
 
329
}
 
330
 
 
331
MapData::MemoryLoadType 
 
332
MapData::GetTotalMemoryUsage( )
 
333
{
 
334
  return std::accumulate(this->m_Records.begin(), this->m_Records.end(), 0, MapRecordPlusor<MemoryLoadType>());
 
335
}
 
336
 
 
337
MapData::MemoryLoadType 
 
338
MapData::GetMemoryUsage( const char * filter , const char * token)
 
339
{
 
340
  return std::accumulate(this->m_Records.begin(), this->m_Records.end(), 0, MapRecordConditionalPlusor<MemoryLoadType>(filter,token));
 
341
}
 
342
 
 
343
/** is the data empty ? */
 
344
bool MapData::Empty()
 
345
{
 
346
  return m_Records.empty();
 
347
}
 
348
 
 
349
void DeleteMapRecord(MapRecord* const &record)
 
350
{
 
351
  delete record;
 
352
}
 
353
 
 
354
void MapData::Reset()
 
355
{
 
356
  std::for_each(m_Records.begin(),m_Records.end(),DeleteMapRecord);
 
357
  m_Records.clear();
 
358
}
 
359
 
 
360
/**              ---            SmapsData               ---              **/
 
361
 
 
362
SmapsData_2_6::~SmapsData_2_6()
 
363
{
 
364
}
 
365
 
 
366
ITK_EXPORT std::istream& operator>>( std::istream & smapsStream, SmapsData_2_6 & data)
 
367
{
 
368
  SmapsRecord* record = NULL;
 
369
  // reset the records from a previous parsing
 
370
  data.Reset();
 
371
  try
 
372
    {
 
373
    record = new SmapsRecord;
 
374
    // parse each line of the Smaps file and fill the record vector.
 
375
    while( smapsStream >> *record )
 
376
      {
 
377
      data.m_Records.push_back( record );
 
378
      record = new SmapsRecord;
 
379
      }
 
380
    }
 
381
  catch( ExceptionObject excp )
 
382
    {
 
383
    // in case of error, erase the records.
 
384
    data.Reset();
 
385
    // propagate the exception
 
386
    itkGenericExceptionMacro( << "The Smaps stream contains errors, can't read the memory records." );
 
387
    }
 
388
  delete record;
 
389
  return smapsStream;
 
390
}
 
391
 
 
392
SmapsData_2_6::MemoryLoadType 
 
393
SmapsData_2_6::GetHeapUsage()
 
394
{
 
395
  MemoryLoadType heapUsage = this->GetMemoryUsage("heap","Size");
 
396
  // in some machines, there is no [heap] record; 
 
397
  if ( heapUsage == 0 )
 
398
    {
 
399
    //use the unnamed segments instead
 
400
    heapUsage = this->GetMemoryUsage("","Size");
 
401
    }
 
402
  return heapUsage;
 
403
}
 
404
 
 
405
SmapsData_2_6::MemoryLoadType 
 
406
SmapsData_2_6::GetStackUsage()
 
407
{
 
408
  return this->GetMemoryUsage("stack","Size");
 
409
}
 
410
 
 
411
/**              ---            VMMapData               ---              **/
 
412
 
 
413
VMMapData_10_2
 
414
::VMMapData_10_2()
 
415
  :m_UsingSummary(false)
 
416
{
 
417
}
 
418
 
 
419
VMMapData_10_2
 
420
::~VMMapData_10_2()
 
421
{
 
422
}
 
423
 
 
424
 
 
425
ITK_EXPORT std::istream& operator>>( std::istream & stream, VMMapData_10_2 & data)
 
426
{
 
427
  MapRecord* record = NULL;
 
428
  // reset the records from a previous parsing
 
429
  data.Reset();
 
430
  try
 
431
    {
 
432
    std::string line;
 
433
    std::streampos startPos = stream.tellg();
 
434
    // get to the Summary subsection
 
435
    while( std::getline(stream,line).good() )
 
436
      {
 
437
      if ( line.find("==== Summary for process",0) != std::string::npos )
 
438
        break;
 
439
      }
 
440
    // get to the first record
 
441
    while( std::getline(stream,line).good() )
 
442
      {
 
443
      if ( line.find("REGION TYPE",0) != std::string::npos )
 
444
        break;
 
445
      }
 
446
    // burn the line "===========             [ =======]"
 
447
    if ( !std::getline(stream,line).good() )
 
448
      {
 
449
      //sometimes, vmmap doesn't have any Region Type summary sections, 
 
450
      //parse "Writable regions" instead
 
451
      //go back to the beginning of the file
 
452
      stream.clear();
 
453
      stream.seekg(0,std::ios_base::beg);
 
454
      // get to the Summary subsection
 
455
      while( std::getline(stream,line).good() )
 
456
        {
 
457
        if ( line.find("==== Writable regions for process",0) != std::string::npos )
 
458
          break;
 
459
        }
 
460
      if ( stream.fail() )
 
461
        {
 
462
        itkGenericExceptionMacro( << "Can't find the \"Writable regions\" section, can't read the memory records." );
 
463
        }
 
464
      data.m_UsingSummary = false;
 
465
      }
 
466
    else
 
467
      {
 
468
      data.m_UsingSummary = true;
 
469
      }
 
470
    if( data.m_UsingSummary )
 
471
      {
 
472
      record = new VMMapSummaryRecord;
 
473
      // parse each line of the Smaps file and fill the record vector.
 
474
      while( stream >> *dynamic_cast<VMMapSummaryRecord *>(record) )
 
475
        {
 
476
        if( record->m_RecordName.empty() )
 
477
          {
 
478
          break;
 
479
          }
 
480
        data.m_Records.push_back( record );
 
481
        record = new VMMapSummaryRecord;
 
482
        }
 
483
      }
 
484
    else
 
485
      {
 
486
      record = new VMMapRecord;
 
487
      // parse each line of the Smaps file and fill the record vector.
 
488
      while( stream >> *dynamic_cast<VMMapRecord* >(record) )
 
489
        {
 
490
        if( record->m_RecordName.empty() )
 
491
          {
 
492
          break;
 
493
          }
 
494
        data.m_Records.push_back( record );
 
495
        record = new VMMapRecord;
 
496
        }
 
497
      }
 
498
    }
 
499
  catch( ExceptionObject excp )
 
500
    {
 
501
    // in case of error, erase the records.
 
502
    data.Reset();
 
503
    // propagate the exception
 
504
    itkGenericExceptionMacro( << "The VMMap stream contains errors, can't read the memory records." );
 
505
    }
 
506
  //last record failed, it hasn't be added into data, delete it.
 
507
  delete record;
 
508
  return stream;
 
509
}
 
510
 
 
511
VMMapData_10_2::MemoryLoadType 
 
512
VMMapData_10_2::GetHeapUsage()
 
513
{
 
514
  return this->GetMemoryUsage("malloc","Size");
 
515
}
 
516
 
 
517
VMMapData_10_2::MemoryLoadType 
 
518
VMMapData_10_2::GetStackUsage()
 
519
{
 
520
  return this->GetMemoryUsage("stack","Size");
 
521
}
 
522
 
 
523
 
 
524
} // end namespace itk