Skip to content
Snippets Groups Projects
Commit a2fe1c4e authored by Marco Clemencic's avatar Marco Clemencic
Browse files

ProcStats : Use mutex lock to make fetch() thread safe.

See merge request gaudi/Gaudi!1410
parents 13f08003 e09b8c7e
No related branches found
No related tags found
1 merge request!1410ProcStats : Use mutex lock to make fetch() thread safe.
Pipeline #5050535 passed
......@@ -48,7 +48,9 @@ void MemoryAuditor::i_printinfo( std::string_view msg, CustomEventTypeRef evt, s
/// Get the process informations.
/// fetch true if it was possible to retrieve the informations.
if ( procInfo pInfo; ProcStats::instance()->fetch( pInfo ) ) {
info() << msg << " " << caller << " " << evt << " virtual size = " << pInfo.vsize << " MB"
<< " resident set size = " << pInfo.rss << " MB" << endmsg;
if ( pInfo.vsize > 0 ) {
info() << msg << " " << caller << " " << evt << " virtual size = " << pInfo.vsize << " MB"
<< " resident set size = " << pInfo.rss << " MB" << endmsg;
}
}
}
......@@ -18,6 +18,7 @@
#endif
#include "ProcStats.h"
#include <memory>
#if defined( __linux__ ) or defined( __APPLE__ )
# include <iostream>
......@@ -29,10 +30,6 @@
# endif // __linux__
# include <cstdio>
using std::cerr;
using std::cout;
using std::endl;
/* Format of the Linux proc/stat (man 5 proc, kernel 2.6.35):
pid %d The process ID.
......@@ -201,110 +198,108 @@ using std::endl;
(divide by sysconf(_SC_CLK_TCK).
*/
struct linux_proc {
int pid;
int pid{ -1 };
char comm[400];
char state;
int ppid;
int pgrp;
int session;
int tty;
int tpgid;
unsigned long flags;
unsigned long minflt;
unsigned long cminflt;
unsigned long majflt;
unsigned long cmajflt;
unsigned long utime;
unsigned long stime;
long cutime;
long cstime;
long priority;
long nice;
long num_threads;
long itrealvalue;
unsigned long long starttime;
unsigned long vsize;
long rss;
unsigned long rlim;
unsigned long startcode;
unsigned long endcode;
unsigned long startstack;
unsigned long kstkesp;
unsigned long kstkeip;
unsigned long signal;
unsigned long blocked;
unsigned long sigignore;
unsigned long sigcatch;
unsigned long wchan;
int ppid{ -1 };
int pgrp{ -1 };
int session{ -1 };
int tty{ -1 };
int tpgid{ -1 };
unsigned long flags{ 0 };
unsigned long minflt{ 0 };
unsigned long cminflt{ 0 };
unsigned long majflt{ 0 };
unsigned long cmajflt{ 0 };
unsigned long utime{ 0 };
unsigned long stime{ 0 };
long cutime{ 0 };
long cstime{ 0 };
long priority{ 0 };
long nice{ 0 };
long num_threads{ 0 };
long itrealvalue{ 0 };
unsigned long long starttime{ 0 };
unsigned long vsize{ 0 };
long rss{ 0 };
unsigned long rlim{ 0 };
unsigned long startcode{ 0 };
unsigned long endcode{ 0 };
unsigned long startstack{ 0 };
unsigned long kstkesp{ 0 };
unsigned long kstkeip{ 0 };
unsigned long signal{ 0 };
unsigned long blocked{ 0 };
unsigned long sigignore{ 0 };
unsigned long sigcatch{ 0 };
unsigned long wchan{ 0 };
};
#endif // __linux__ or __APPLE__
ProcStats::cleanup::~cleanup() {
if ( ProcStats::inst != 0 ) {
delete ProcStats::inst;
ProcStats::inst = 0;
}
}
ProcStats* ProcStats::instance() {
static cleanup c;
if ( !inst ) inst = new ProcStats;
return inst;
static ProcStats inst{};
return &inst;
}
ProcStats* ProcStats::inst = 0;
ProcStats::ProcStats() : valid( false ) {
void ProcStats::open_ufd() {
m_valid = false;
#if defined( __linux__ ) or defined( __APPLE__ )
pg_size = sysconf( _SC_PAGESIZE ); // getpagesize();
fname = "/proc/" + std::to_string( getpid() ) + "/stat";
fd.open( fname.c_str(), O_RDONLY );
if ( !fd ) {
cerr << "Failed to open " << fname << endl;
return;
m_ufd.close();
m_pg_size = sysconf( _SC_PAGESIZE ); // getpagesize();
const auto fname = "/proc/" + std::to_string( getpid() ) + "/stat";
m_ufd.open( fname.c_str(), O_RDONLY );
if ( !m_ufd ) {
std::cerr << "ProcStats : Failed to open " << fname << std::endl;
} else {
m_valid = true;
}
#endif // __linux__ or __APPLE__
valid = true;
}
bool ProcStats::fetch( procInfo& f ) {
if ( valid == false ) return false;
#if defined( __linux__ ) or defined( __APPLE__ )
double pr_size, pr_rssize;
linux_proc pinfo;
int cnt;
if ( !m_valid ) { return false; }
fd.lseek( 0, SEEK_SET );
std::scoped_lock lock{ m_mutex };
if ( ( cnt = fd.read( buf, sizeof( buf ) ) ) < 0 ) {
cout << "LINUX Read of Proc file failed:" << endl;
return false;
}
#if defined( __linux__ ) or defined( __APPLE__ )
if ( cnt > 0 ) {
buf[std::min( static_cast<std::size_t>( cnt ), sizeof( buf ) - 1 )] = '\0';
sscanf( buf,
// 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 20 1 2 3 4 5 6 7 8 9
// 30 1 2 3 4 5
"%d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %llu %lu %ld %lu %lu %lu %lu "
"%lu %lu %lu %lu %lu %lu %lu",
&pinfo.pid, pinfo.comm, &pinfo.state, &pinfo.ppid, &pinfo.pgrp, &pinfo.session, &pinfo.tty, &pinfo.tpgid,
&pinfo.flags, &pinfo.minflt, &pinfo.cminflt, &pinfo.majflt, &pinfo.cmajflt, &pinfo.utime, &pinfo.stime,
&pinfo.cutime, &pinfo.cstime, &pinfo.priority, &pinfo.nice, &pinfo.num_threads, &pinfo.itrealvalue,
&pinfo.starttime, &pinfo.vsize, &pinfo.rss, &pinfo.rlim, &pinfo.startcode, &pinfo.endcode,
&pinfo.startstack, &pinfo.kstkesp, &pinfo.kstkeip, &pinfo.signal, &pinfo.blocked, &pinfo.sigignore,
&pinfo.sigcatch, &pinfo.wchan );
// resident set size in pages
pr_size = (double)pinfo.vsize;
pr_rssize = (double)pinfo.rss;
f.vsize = pr_size / ( 1024 * 1024 );
f.rss = pr_rssize * pg_size / ( 1024 * 1024 );
auto read_proc = [&]() {
bool ok = true;
int cnt{ 0 };
char buf[500];
linux_proc pinfo;
m_ufd.lseek( 0, SEEK_SET );
if ( ( cnt = m_ufd.read( buf, sizeof( buf ) ) ) < 0 ) { ok = false; }
if ( cnt > 0 ) {
buf[std::min( static_cast<std::size_t>( cnt ), sizeof( buf ) - 1 )] = '\0';
sscanf(
buf,
// 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 20 1 2 3 4 5 6 7 8 9
// 30 1 2 3 4 5
"%d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %llu %lu %ld %lu %lu %lu %lu "
"%lu %lu %lu %lu %lu %lu %lu",
&pinfo.pid, pinfo.comm, &pinfo.state, &pinfo.ppid, &pinfo.pgrp, &pinfo.session, &pinfo.tty, &pinfo.tpgid,
&pinfo.flags, &pinfo.minflt, &pinfo.cminflt, &pinfo.majflt, &pinfo.cmajflt, &pinfo.utime, &pinfo.stime,
&pinfo.cutime, &pinfo.cstime, &pinfo.priority, &pinfo.nice, &pinfo.num_threads, &pinfo.itrealvalue,
&pinfo.starttime, &pinfo.vsize, &pinfo.rss, &pinfo.rlim, &pinfo.startcode, &pinfo.endcode, &pinfo.startstack,
&pinfo.kstkesp, &pinfo.kstkeip, &pinfo.signal, &pinfo.blocked, &pinfo.sigignore, &pinfo.sigcatch,
&pinfo.wchan );
// resident set size in pages
const auto pr_size = static_cast<double>( pinfo.vsize );
const auto pr_rssize = static_cast<double>( pinfo.rss );
constexpr double MB = 1.0 / ( 1024 * 1024 );
f.vsize = pr_size * MB;
f.rss = pr_rssize * m_pg_size * MB;
if ( 0 == pinfo.vsize ) { ok = false; }
}
return ok;
};
// attempt to read from proc
if ( !read_proc() ) {
std::cerr << "ProcStats : -> Problems reading proc file. Will try reopening..." << std::endl;
open_ufd();
if ( !read_proc() ) { return false; }
}
#else
......@@ -312,10 +307,10 @@ bool ProcStats::fetch( procInfo& f ) {
f.rss = 0;
#endif // __linux__ or __APPLE__
bool rc = ( curr == f ) ? false : true;
const bool rc = !( m_curr == f );
curr.rss = f.rss;
curr.vsize = f.vsize;
m_curr.rss = f.rss;
m_curr.vsize = f.vsize;
return rc;
}
......@@ -8,15 +8,17 @@
* granted to it by virtue of its status as an Intergovernmental Organization *
* or submit itself to any jurisdiction. *
\***********************************************************************************/
#ifndef GAUDIAUD_PROCSTATS_H
#define GAUDIAUD_PROCSTATS_H
#pragma once
// Class: ProcStats
// Description: Keeps statistics on memory usage
// Author: Jim Kowalkowski (FNAL), modified by M. Shapiro (LBNL)
#include <mutex>
#include <string>
#include <vector>
#if defined( __linux__ ) or defined( __APPLE__ )
# include <fcntl.h>
# include <sys/stat.h>
......@@ -25,7 +27,7 @@
#endif // __linux__ or __APPLE__
struct procInfo {
procInfo() : vsize( 0 ), rss( 0 ) {}
procInfo() = default;
procInfo( double sz, double rss_sz ) : vsize( sz ), rss( rss_sz ) {}
bool operator==( const procInfo& p ) const {
......@@ -35,7 +37,7 @@ struct procInfo {
# pragma warning( disable : 1572 )
#endif
return vsize == p.vsize && rss == p.rss;
return ( vsize == p.vsize && rss == p.rss );
#ifdef __ICC
// re-enable icc remark #1572
......@@ -44,71 +46,79 @@ struct procInfo {
}
// see proc(4) man pages for units and a description
double vsize; // in MB (used to be in pages?)
double rss; // in MB (used to be in pages?)
double vsize{ 0 }; // in MB (used to be in pages?)
double rss{ 0 }; // in MB (used to be in pages?)
};
class ProcStats {
public:
static ProcStats* instance();
bool fetch( procInfo& fill_me );
double pageSize() const { return pg_size; }
public:
ProcStats() { open_ufd(); }
private:
ProcStats();
struct cleanup {
cleanup() {}
~cleanup();
};
void open_ufd();
friend struct cleanup;
public:
static ProcStats* instance();
bool fetch( procInfo& fill_me );
auto pageSize() const noexcept { return m_pg_size; }
private:
class unique_fd {
int m_fd;
private:
int m_fd{ -1 };
private:
unique_fd( const unique_fd& ) = delete;
unique_fd& operator=( const unique_fd& ) = delete;
public:
unique_fd( int fd = -1 ) : m_fd( fd ) {}
unique_fd( const int fd = -1 ) : m_fd( fd ) {}
unique_fd( unique_fd&& other ) {
m_fd = other.m_fd;
other.m_fd = -1;
}
~unique_fd() {
if ( m_fd != -1 ) ::close( m_fd );
}
~unique_fd() { close(); }
public:
explicit operator bool() const { return m_fd != -1; }
template <typename... Args>
unique_fd& open( Args&&... args ) {
m_fd = ::open( std::forward<Args>( args )... );
return *this;
}
int close() {
int r = 0;
if ( m_fd != -1 ) {
r = ::close( m_fd );
m_fd = -1;
}
return r;
}
public:
#define unique_fd_forward( fun ) \
template <typename... Args> \
auto fun( Args&&... args ) const->decltype( ::fun( m_fd, std::forward<Args>( args )... ) ) { \
auto fun( Args&&... args ) const { \
return ::fun( m_fd, std::forward<Args>( args )... ); \
}
unique_fd_forward( lseek ) unique_fd_forward( read ) unique_fd_forward( write ) unique_fd_forward( fcntl )
unique_fd_forward( fsync ) unique_fd_forward( fchown ) unique_fd_forward( stat )
// clang-format off
unique_fd_forward( lseek )
unique_fd_forward( read )
unique_fd_forward( write )
unique_fd_forward( fcntl )
unique_fd_forward( fsync )
unique_fd_forward( fchown )
unique_fd_forward( stat )
// clang-format on
#undef unique_fd_forward
int close() {
auto r = ::close( m_fd );
m_fd = -1;
return r;
}
};
unique_fd fd;
double pg_size;
procInfo curr;
std::string fname;
char buf[500];
bool valid;
static ProcStats* inst;
private:
unique_fd m_ufd;
double m_pg_size{ 0 };
procInfo m_curr;
bool m_valid{ false };
std::mutex m_mutex;
};
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment