Accurate measuring of memory usage under Linux.

* Change: In Hurricane::Timer, measuring memory usage through the increase
    of sbrk() gives erroneous results. Under Linux, now read the
    /proc/[pid]/statm which gives the real size of the virtual memory
    of the process. There is also code for reading /proc/[pid]/mmap
    but it gives only the resident size of the process (i.e. swapped
    pages are *not* accounteds).
* Change: In Katabatic, Anabatic, Kite & Katana now reports the total
    memory size of the program.
This commit is contained in:
Jean-Paul Chaput 2017-02-25 18:21:55 +01:00
parent 086e40ec7d
commit 44a2f574bc
6 changed files with 128 additions and 37 deletions

View File

@ -977,8 +977,12 @@ namespace Anabatic {
result.str(""); result.str("");
result << _timer.getCombTime() result << _timer.getCombTime()
<< "s, +" << (_timer.getIncrease()>>10) << "Kb/" << "s, +" << (_timer.getIncrease()>>10) << "Kb/"
<< (_timer.getMemorySize()>>10) << "Kb"; << Timer::getStringMemory(Timer::getMemorySize());
cmess2 << Dots::asString( " - Raw measurements", result.str() ) << endl; cmess2 << Dots::asString( " - Raw measurements", result.str() ) << endl;
// result.str("");
// result << Timer::getStringMemory(Timer::getMemorySize());
// cmess1 << Dots::asString( " - Total memory", result.str() ) << endl;
} }

View File

@ -32,13 +32,16 @@
***************************************************************************/ ***************************************************************************/
#include "hurricane/Timer.h" #include <fstream>
#include <sstream>
#include <iomanip>
#include "hurricane/Timer.h"
namespace Hurricane { namespace Hurricane {
size_t Timer::_baseMemorySize = (size_t)sbrk(0); size_t Timer::_baseMemorySize = Timer::getMemorySize();
// ------------------------------------------------------------------- // -------------------------------------------------------------------
@ -47,7 +50,7 @@ namespace Hurricane {
Timer::Timer ( double limitInSec ) Timer::Timer ( double limitInSec )
: timeLimit(limitInSec) : timeLimit(limitInSec)
, _memorySize((size_t)sbrk(0)) , _memorySize(getMemorySize())
{ {
status = TimerOff; status = TimerOff;
} }
@ -142,6 +145,75 @@ namespace Hurricane {
} }
size_t Timer::getMemorySize ()
{
size_t s, m;
return getMemorySize(s,m);
}
size_t Timer::getMemorySize ( size_t& memory, size_t& shared )
{
#if !defined __linux__
return (size_t)sbrk( 0 );
#else
#if 0
string mmapFile = "/proc/" + to_string(getpid()) + "/maps" ;
ifstream mmap ( mmapFile );
char line [ 4096 ];
unsigned long long rmemory = 0;
unsigned long long rshared = 0;
while ( not mmap.eof() ) {
mmap.getline( line, 4096 );
const string sline ( line );
istringstream iss ( sline );
unsigned long long baddress = 0;
unsigned long long eaddress = 0;
string perms;
unsigned long long offset;
int major;
int minor;
unsigned long long inode;
string pathname;
char separ;
iss >> hex >> baddress >> separ >> eaddress >> dec >> perms >> offset
>> major >> separ >> minor >> inode >> pathname;
if (not pathname.empty() and pathname.compare(0,6,"[heap]") != 0)
rshared += eaddress - baddress;
else
rmemory += eaddress - baddress;
}
memory = (size_t)rmemory;
shared = (size_t)rshared;
mmap.close();
return memory;
#endif
long pagesize = sysconf( _SC_PAGESIZE );
string statmFile = "/proc/" + to_string(getpid()) + "/statm" ;
ifstream statm ( statmFile );
unsigned long long size = 0;
unsigned long long resident = 0;
unsigned long long share = 0;
unsigned long long text = 0;
unsigned long long lib = 0;
unsigned long long data = 0;
unsigned long long dt = 0;
statm >> size >> resident >> share >> text >> lib >> data >> dt;
memory = (size_t)size * pagesize;
statm.close();
return memory;
#endif
}
string Timer::_getString () const string Timer::_getString () const
{ {
//CPUNormalizer cpunorm; //CPUNormalizer cpunorm;
@ -196,15 +268,16 @@ namespace Hurricane {
} }
string Timer::getStringMemory ( size_t size ) { string Timer::getStringMemory ( size_t size )
string s; {
ostringstream oss;
if ( size >> 30 ) s = getString(size>>30) + "Mb"; if (size >> 30) oss << fixed << setprecision(1) << ((float)size)/powf(2.0,30.0) << "Gb";
else if ( size >> 20 ) s = getString(size>>20) + "Mb"; else if (size >> 20) oss << fixed << setprecision(1) << ((float)size)/powf(2.0,20.0) << "Mb";
else if ( size >> 10 ) s = getString(size>>10) + "Kb"; else if (size >> 10) oss << size << "Kb";
else s = getString(size) + " bytes"; else oss << size << " bytes";
return s; return oss.str();
} }

View File

@ -34,8 +34,8 @@
//! author="Igor Markov 06/22/97 " //! author="Igor Markov 06/22/97 "
// freely inspired from abktimer from UCLApack .... just no windows. // freely inspired from abktimer from UCLApack .... just no windows.
#ifndef __HURRICANE_TIMER__ #ifndef HURRICANE_TIMER_H
#define __HURRICANE_TIMER__ #define HURRICANE_TIMER_H
#include <sys/types.h> #include <sys/types.h>
#include <sys/time.h> #include <sys/time.h>
@ -61,11 +61,12 @@ namespace Hurricane {
// Used to record the CPU time of process // Used to record the CPU time of process
class Timer { class Timer {
public: public:
// Static Methods. // Static Methods.
static string getStringTime ( double duration ); static string getStringTime ( double duration );
static string getStringMemory ( size_t size ); static string getStringMemory ( size_t size );
static size_t getMemorySize ( size_t& memory, size_t& shared );
static size_t getMemorySize ();
// Constructors & Destructors. // Constructors & Destructors.
Timer ( double limitInSec=0.0 ); Timer ( double limitInSec=0.0 );
~Timer () { }; ~Timer () { };
@ -97,9 +98,8 @@ namespace Hurricane {
// (INT_MAX+0.0)/CLOCKS_PER_SEC) sec (can be 36 mins), // (INT_MAX+0.0)/CLOCKS_PER_SEC) sec (can be 36 mins),
// call realTimeExpired() instead // call realTimeExpired() instead
inline size_t getBaseMemorySize () const; inline size_t getBaseMemorySize () const;
inline size_t getMemorySize () const; size_t getIncrease () const;
inline size_t getIncrease () const; void resetIncrease ();
inline void resetIncrease ();
string _getString () const; string _getString () const;
protected: protected:
@ -111,18 +111,17 @@ namespace Hurricane {
private: private:
// Internal: Attributes. // Internal: Attributes.
time_t realTime1; time_t realTime1;
mutable time_t realTime2; mutable time_t realTime2;
double UserTime1; double UserTime1;
mutable double UserTime2; mutable double UserTime2;
double SysTime1; double SysTime1;
mutable double SysTime2; mutable double SysTime2;
double timeLimit; double timeLimit;
Status status; Status status;
mutable struct rusage _ru; mutable struct rusage _ru;
size_t _memorySize; size_t _memorySize;
static size_t _baseMemorySize; static size_t _baseMemorySize;
// Internal: Methods.
}; };
@ -130,9 +129,8 @@ namespace Hurricane {
// Inline Functions. // Inline Functions.
inline bool Timer::isStopped () const { return status == TimerOff; } inline bool Timer::isStopped () const { return status == TimerOff; }
inline size_t Timer::getBaseMemorySize () const { return _baseMemorySize; } inline size_t Timer::getBaseMemorySize () const { return _baseMemorySize; }
inline size_t Timer::getMemorySize () const { return _memorySize - _baseMemorySize; } inline size_t Timer::getIncrease () const { return getMemorySize() - _memorySize; }
inline size_t Timer::getIncrease () const { return (size_t)(sbrk(0)) - _memorySize; } inline void Timer::resetIncrease () { _memorySize = getMemorySize(); }
inline void Timer::resetIncrease () { _memorySize = (size_t)sbrk(0); }
inline double Timer::getRealTimeOnTheFly () const inline double Timer::getRealTimeOnTheFly () const
@ -179,11 +177,10 @@ namespace Hurricane {
} }
} // End of Hurricane namespace. } // Hurricane namespace.
GETSTRING_VALUE_SUPPORT(Hurricane::Timer); GETSTRING_VALUE_SUPPORT(Hurricane::Timer);
IOSTREAM_VALUE_SUPPORT(Hurricane::Timer); IOSTREAM_VALUE_SUPPORT(Hurricane::Timer);
#endif // HURRICANE_TIMER_H
#endif // __HURRICANE_TIMER__

View File

@ -383,7 +383,7 @@ namespace Katabatic {
result.str(""); result.str("");
result << _timer.getCombTime() result << _timer.getCombTime()
<< "s, +" << (_timer.getIncrease()>>10) << "Kb/" << "s, +" << (_timer.getIncrease()>>10) << "Kb/"
<< (_timer.getMemorySize()>>10) << "Kb"; << Timer::getStringMemory(Timer::getMemorySize());
cmess2 << Dots::asString( " - Raw measurements", result.str() ) << endl; cmess2 << Dots::asString( " - Raw measurements", result.str() ) << endl;
if (not tag.empty()) { if (not tag.empty()) {

View File

@ -25,6 +25,7 @@
#include "hurricane/Error.h" #include "hurricane/Error.h"
#include "hurricane/Warning.h" #include "hurricane/Warning.h"
#include "hurricane/Breakpoint.h" #include "hurricane/Breakpoint.h"
#include "hurricane/Timer.h"
#include "hurricane/Layer.h" #include "hurricane/Layer.h"
#include "hurricane/Net.h" #include "hurricane/Net.h"
#include "hurricane/Pad.h" #include "hurricane/Pad.h"
@ -128,6 +129,7 @@ namespace Katana {
using Hurricane::Error; using Hurricane::Error;
using Hurricane::Warning; using Hurricane::Warning;
using Hurricane::Breakpoint; using Hurricane::Breakpoint;
using Hurricane::Timer;
using Hurricane::Box; using Hurricane::Box;
using Hurricane::Torus; using Hurricane::Torus;
using Hurricane::Layer; using Hurricane::Layer;
@ -254,6 +256,9 @@ namespace Katana {
KatanaEngine* KatanaEngine::create ( Cell* cell ) KatanaEngine* KatanaEngine::create ( Cell* cell )
{ {
cmess1 << Dots::asString( " - Initial memory"
, Timer::getStringMemory(Timer::getMemorySize()) ) << endl;
KatanaEngine* katana = new KatanaEngine ( cell ); KatanaEngine* katana = new KatanaEngine ( cell );
katana->_postCreate(); katana->_postCreate();

View File

@ -363,13 +363,19 @@ Vertex* KnikEngine::getVertex ( DbU::Unit x, DbU::Unit y )
void KnikEngine::printTime() void KnikEngine::printTime()
// ************************* // *************************
{ {
ostringstream result;
cmess2 << " + Done in " << Timer::getStringTime(_timer.getCombTime()) cmess2 << " + Done in " << Timer::getStringTime(_timer.getCombTime())
<< " [+" << Timer::getStringMemory(_timer.getIncrease()) << "]." << endl; << " [+" << Timer::getStringMemory(_timer.getIncrease()) << "]." << endl;
cmess2 << " (raw measurements : " << _timer.getCombTime() cmess2 << " (raw measurements : " << _timer.getCombTime()
<< "s [+" << (_timer.getIncrease()>>10) << "Ko/" << "s [+" << (_timer.getIncrease()>>10) << "Ko/"
<< (_timer.getMemorySize()>>10) << "Ko])" << endl; << (_timer.getMemorySize()>>10) << "Ko])" << endl;
result.str("");
result << _timer.getCombTime()
<< "s, +" << (_timer.getIncrease()>>10) << "Kb/"
<< Timer::getStringMemory(Timer::getMemorySize());
cmess2 << Dots::asString( " - Raw measurements", result.str() ) << endl;
} }
// void KnikEngine::showEstimateOccupancy() // void KnikEngine::showEstimateOccupancy()
// // ************************************* // // *************************************
@ -1070,6 +1076,12 @@ void KnikEngine::run( const map<Name,Net*>& excludedNets )
cmess1 << " o Global Routing Completed." << endl; cmess1 << " o Global Routing Completed." << endl;
cmess1 << Dots::asString( " - Done in", result.str() ) << endl; cmess1 << Dots::asString( " - Done in", result.str() ) << endl;
result.str("");
result << _timer.getCombTime()
<< "s, +" << (_timer.getIncrease()>>10) << "Kb/"
<< Timer::getStringMemory(Timer::getMemorySize());
cmess2 << Dots::asString( " - Raw measurements", result.str() ) << endl;
addMeasure<double> ( getCell(), "knikT", _timer.getCombTime () ); addMeasure<double> ( getCell(), "knikT", _timer.getCombTime () );
addMeasure<size_t> ( getCell(), "knikS", (_timer.getMemorySize() >> 20) ); addMeasure<size_t> ( getCell(), "knikS", (_timer.getMemorySize() >> 20) );