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

Generated at Sat Mar 8 2014 15:33:40 for Orfeo Toolbox with doxygen 1.8.3.1