From 44a2f574bc817a21b063e8ec6af84a2915bf4dea Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Sat, 25 Feb 2017 18:21:55 +0100 Subject: [PATCH] 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. --- anabatic/src/AnabaticEngine.cpp | 6 +- hurricane/src/hurricane/Timer.cpp | 93 ++++++++++++++++++++--- hurricane/src/hurricane/hurricane/Timer.h | 45 +++++------ katabatic/src/KatabaticEngine.cpp | 2 +- katana/src/KatanaEngine.cpp | 5 ++ knik/src/KnikEngine.cpp | 14 +++- 6 files changed, 128 insertions(+), 37 deletions(-) diff --git a/anabatic/src/AnabaticEngine.cpp b/anabatic/src/AnabaticEngine.cpp index fefe4437..23b55d33 100644 --- a/anabatic/src/AnabaticEngine.cpp +++ b/anabatic/src/AnabaticEngine.cpp @@ -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; } diff --git a/hurricane/src/hurricane/Timer.cpp b/hurricane/src/hurricane/Timer.cpp index e833543f..3507b219 100644 --- a/hurricane/src/hurricane/Timer.cpp +++ b/hurricane/src/hurricane/Timer.cpp @@ -32,13 +32,16 @@ ***************************************************************************/ -#include "hurricane/Timer.h" +#include +#include +#include +#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(); } diff --git a/hurricane/src/hurricane/hurricane/Timer.h b/hurricane/src/hurricane/hurricane/Timer.h index e16eaab9..52d81ff1 100644 --- a/hurricane/src/hurricane/hurricane/Timer.h +++ b/hurricane/src/hurricane/hurricane/Timer.h @@ -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 #include @@ -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 diff --git a/katabatic/src/KatabaticEngine.cpp b/katabatic/src/KatabaticEngine.cpp index c60117aa..1eedbcef 100644 --- a/katabatic/src/KatabaticEngine.cpp +++ b/katabatic/src/KatabaticEngine.cpp @@ -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()) { diff --git a/katana/src/KatanaEngine.cpp b/katana/src/KatanaEngine.cpp index db76e0af..1898b15f 100644 --- a/katana/src/KatanaEngine.cpp +++ b/katana/src/KatanaEngine.cpp @@ -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(); diff --git a/knik/src/KnikEngine.cpp b/knik/src/KnikEngine.cpp index d5ee1691..b0ad2758 100644 --- a/knik/src/KnikEngine.cpp +++ b/knik/src/KnikEngine.cpp @@ -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& 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 ( getCell(), "knikT", _timer.getCombTime () ); addMeasure ( getCell(), "knikS", (_timer.getMemorySize() >> 20) );