1
/*=========================================================================
3
Program: Insight Segmentation & Registration Toolkit
4
Module: $RCSfile: itkSmapsFileParser.cxx,v $
6
Date: $Date: 2008-10-24 18:11:22 $
7
Version: $Revision: 1.1 $
9
Copyright (c) Insight Software Consortium. All rights reserved.
10
See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
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.
16
=========================================================================*/
18
#include "itkSmapsFileParser.h"
23
bool ITKCommon_EXPORT ci_equal(char a, char b)
25
return tolower(static_cast<int>(a)) == tolower(static_cast<int>(b));
28
MapRecord::~MapRecord()
32
void MapRecord::Reset(void)
38
/* SmapsRecord implementation */
40
ITKCommon_EXPORT std::istream& operator>>(std::istream &in, SmapsRecord &record)
47
std::string headerline;
48
std::getline( in, headerline);
50
if (headerline.empty())
56
std::istringstream stream(headerline);
57
std::string address, perms, offset, device;
59
// the header is defined with the following expression: "address permissions offset device inode [name]"
61
if (!stream.good()) itkGenericExceptionMacro( << "bad address: " << address );
63
if (!stream.good()) itkGenericExceptionMacro( << "bad perms: " << perms );
65
if (!stream.good()) itkGenericExceptionMacro( << "bad offset: " << offset );
67
if (!stream.good()) itkGenericExceptionMacro( << "bad device: " << device );
72
std::getline(stream, record.m_RecordName);
76
int lastPos = in.tellg();
77
// a token is defined with the following expression: "token: N kB"
78
while ( std::getline(in,token,':').good() )
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 )
83
in.seekg (lastPos, std::ios::beg);
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] );
93
catch (ExceptionObject excp)
96
// propagate the exception
97
itkGenericExceptionMacro( << "The smaps header is corrupted" );
103
ITKCommon_EXPORT std::istream& operator>>(std::istream &in, VMMapSummaryRecord &record)
109
// the record name can have spaces.
110
in >> record.m_RecordName;
112
if (in.eof() && record.m_RecordName.empty())
119
itkGenericExceptionMacro( << "Bad record name: " << record.m_RecordName );
124
while ( (in>>bracket).good() && bracket.find("[",0) == std::string::npos )
126
record.m_RecordName += std::string(" ") + bracket;
129
if (!in.good() || bracket.find("[",0) == std::string::npos )
131
itkGenericExceptionMacro( << "For record: " << record.m_RecordName
132
<< ", bad left bracket: " << bracket );
135
in >> record.m_Tokens["Size"];
139
itkGenericExceptionMacro( << "For record: " << record.m_RecordName
140
<< ", bad size: " << record.m_Tokens["Size"] );
147
itkGenericExceptionMacro( << "For record: " << record.m_RecordName
148
<< ", bad right bracket: " << bracket );
151
catch (ExceptionObject excp)
154
// propagate the exception
155
itkGenericExceptionMacro( << "The smaps header is corrupted" );
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
177
ITKCommon_EXPORT std::istream& operator>>(std::istream &in, VMMapRecord &record)
180
bool submapFound = false;
181
bool recordHasNoName = false;
188
// the record name can have spaces.
189
in >> record.m_RecordName;
190
if( in.eof() || record.m_RecordName.empty() )
197
itkGenericExceptionMacro( << "Bad record name: " << record.m_RecordName );
200
//skip Submap entries
201
if ( record.m_RecordName == "Submap" )
203
in.getline(line,256);
207
// all the records have been parsed, this is a new section
208
else if ( record.m_RecordName == "====" )
215
// the name is folowed by an address
220
itkGenericExceptionMacro( << "For record: " << record.m_RecordName
221
<< ", bad address: " << address );
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 )
227
in.getline(line,256);
228
recordHasNoName = true;
232
recordHasNoName = false;
236
} while(submapFound || recordHasNoName);
240
while ( (in>>bracket).good() && bracket.find("[",0) == std::string::npos )
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;
247
if (!in.good() || bracket.find("[",0) == std::string::npos )
249
itkGenericExceptionMacro( << "For record: " << record.m_RecordName
250
<< ", bad left bracket: " << bracket );
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());
258
in>>record.m_Tokens["Size"];
262
itkGenericExceptionMacro( << "For record: " << record.m_RecordName
263
<< ", bad size: " << record.m_Tokens["Size"] );
265
in.getline(line,256);
268
itkGenericExceptionMacro( << "For record: " << record.m_RecordName
269
<< ", bad end of line: " << line );
272
catch (ExceptionObject excp)
275
// propagate the exception
276
itkGenericExceptionMacro( << "The smaps header is corrupted" );
282
//bool ITKCommon_EXPORT ci_equal(char a, char b); // located in itkSmapsFileParser.cxx
284
/** Binary functor to accumulate memory usage in kB
286
template<class TFirstType>
287
struct MapRecordPlusor{
288
MapRecordPlusor<TFirstType>(const char * token = "Size")
293
TFirstType operator()(TFirstType first, const MapRecord* const & second)
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);
298
const char * m_Token;
301
/** Binary functor to accumulate memory usage in kB
302
* The record must match (insensitively) the filter in order to be taken into account
304
template<class TFirstType>
305
struct MapRecordConditionalPlusor{
306
MapRecordConditionalPlusor<TFirstType>(const char * filter, const char * token = "Size")
307
:m_Filter(filter), m_Token(token)
310
TFirstType operator()(TFirstType first, const MapRecord* const &second)
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())
315
return MapRecordPlusor<TFirstType>(m_Token)(first,second);
319
std::string m_Filter;
320
const char * m_Token;
323
/** --- MapData --- **/
325
/** MadData destructor */
331
MapData::MemoryLoadType
332
MapData::GetTotalMemoryUsage( )
334
return std::accumulate(this->m_Records.begin(), this->m_Records.end(), 0, MapRecordPlusor<MemoryLoadType>());
337
MapData::MemoryLoadType
338
MapData::GetMemoryUsage( const char * filter , const char * token)
340
return std::accumulate(this->m_Records.begin(), this->m_Records.end(), 0, MapRecordConditionalPlusor<MemoryLoadType>(filter,token));
343
/** is the data empty ? */
344
bool MapData::Empty()
346
return m_Records.empty();
349
void DeleteMapRecord(MapRecord* const &record)
354
void MapData::Reset()
356
std::for_each(m_Records.begin(),m_Records.end(),DeleteMapRecord);
360
/** --- SmapsData --- **/
362
SmapsData_2_6::~SmapsData_2_6()
366
ITK_EXPORT std::istream& operator>>( std::istream & smapsStream, SmapsData_2_6 & data)
368
SmapsRecord* record = NULL;
369
// reset the records from a previous parsing
373
record = new SmapsRecord;
374
// parse each line of the Smaps file and fill the record vector.
375
while( smapsStream >> *record )
377
data.m_Records.push_back( record );
378
record = new SmapsRecord;
381
catch( ExceptionObject excp )
383
// in case of error, erase the records.
385
// propagate the exception
386
itkGenericExceptionMacro( << "The Smaps stream contains errors, can't read the memory records." );
392
SmapsData_2_6::MemoryLoadType
393
SmapsData_2_6::GetHeapUsage()
395
MemoryLoadType heapUsage = this->GetMemoryUsage("heap","Size");
396
// in some machines, there is no [heap] record;
397
if ( heapUsage == 0 )
399
//use the unnamed segments instead
400
heapUsage = this->GetMemoryUsage("","Size");
405
SmapsData_2_6::MemoryLoadType
406
SmapsData_2_6::GetStackUsage()
408
return this->GetMemoryUsage("stack","Size");
411
/** --- VMMapData --- **/
415
:m_UsingSummary(false)
425
ITK_EXPORT std::istream& operator>>( std::istream & stream, VMMapData_10_2 & data)
427
MapRecord* record = NULL;
428
// reset the records from a previous parsing
433
std::streampos startPos = stream.tellg();
434
// get to the Summary subsection
435
while( std::getline(stream,line).good() )
437
if ( line.find("==== Summary for process",0) != std::string::npos )
440
// get to the first record
441
while( std::getline(stream,line).good() )
443
if ( line.find("REGION TYPE",0) != std::string::npos )
446
// burn the line "=========== [ =======]"
447
if ( !std::getline(stream,line).good() )
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
453
stream.seekg(0,std::ios_base::beg);
454
// get to the Summary subsection
455
while( std::getline(stream,line).good() )
457
if ( line.find("==== Writable regions for process",0) != std::string::npos )
462
itkGenericExceptionMacro( << "Can't find the \"Writable regions\" section, can't read the memory records." );
464
data.m_UsingSummary = false;
468
data.m_UsingSummary = true;
470
if( data.m_UsingSummary )
472
record = new VMMapSummaryRecord;
473
// parse each line of the Smaps file and fill the record vector.
474
while( stream >> *dynamic_cast<VMMapSummaryRecord *>(record) )
476
if( record->m_RecordName.empty() )
480
data.m_Records.push_back( record );
481
record = new VMMapSummaryRecord;
486
record = new VMMapRecord;
487
// parse each line of the Smaps file and fill the record vector.
488
while( stream >> *dynamic_cast<VMMapRecord* >(record) )
490
if( record->m_RecordName.empty() )
494
data.m_Records.push_back( record );
495
record = new VMMapRecord;
499
catch( ExceptionObject excp )
501
// in case of error, erase the records.
503
// propagate the exception
504
itkGenericExceptionMacro( << "The VMMap stream contains errors, can't read the memory records." );
506
//last record failed, it hasn't be added into data, delete it.
511
VMMapData_10_2::MemoryLoadType
512
VMMapData_10_2::GetHeapUsage()
514
return this->GetMemoryUsage("malloc","Size");
517
VMMapData_10_2::MemoryLoadType
518
VMMapData_10_2::GetStackUsage()
520
return this->GetMemoryUsage("stack","Size");
524
} // end namespace itk