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 << _timer.getCombTime()
<< "s, +" << (_timer.getIncrease()>>10) << "Kb/"
<< (_timer.getMemorySize()>>10) << "Kb";
<< Timer::getStringMemory(Timer::getMemorySize());
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 {
size_t Timer::_baseMemorySize = (size_t)sbrk(0);
size_t Timer::_baseMemorySize = Timer::getMemorySize();
// -------------------------------------------------------------------
@ -47,7 +50,7 @@ namespace Hurricane {
Timer::Timer ( double limitInSec )
: timeLimit(limitInSec)
, _memorySize((size_t)sbrk(0))
, _memorySize(getMemorySize())
{
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
{
//CPUNormalizer cpunorm;
@ -196,15 +268,16 @@ namespace Hurricane {
}
string Timer::getStringMemory ( size_t size ) {
string s;
string Timer::getStringMemory ( size_t size )
{
ostringstream oss;
if ( size >> 30 ) s = getString(size>>30) + "Mb";
else if ( size >> 20 ) s = getString(size>>20) + "Mb";
else if ( size >> 10 ) s = getString(size>>10) + "Kb";
else s = getString(size) + " bytes";
if (size >> 30) oss << fixed << setprecision(1) << ((float)size)/powf(2.0,30.0) << "Gb";
else if (size >> 20) oss << fixed << setprecision(1) << ((float)size)/powf(2.0,20.0) << "Mb";
else if (size >> 10) oss << size << "Kb";
else oss << size << " bytes";
return s;
return oss.str();
}

View File

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

View File

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

View File

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

View File

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