1
/*============================================================================
2
* Base memory usage information (System and Library dependent)
3
*============================================================================*/
6
This file is part of Code_Saturne, a general-purpose CFD tool.
8
Copyright (C) 1998-2011 EDF S.A.
10
This program is free software; you can redistribute it and/or modify it under
11
the terms of the GNU General Public License as published by the Free Software
12
Foundation; either version 2 of the License, or (at your option) any later
15
This program is distributed in the hope that it will be useful, but WITHOUT
16
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
20
You should have received a copy of the GNU General Public License along with
21
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
22
Street, Fifth Floor, Boston, MA 02110-1301, USA.
25
/*----------------------------------------------------------------------------*/
27
#include "cs_config.h"
32
#if defined(__linux__) || defined(__linux) || defined(linux)
35
#elif defined(__sun__) || defined(__sun) || defined(sun)
36
#define ECS_OS_Solaris
38
#elif defined(__uxpv__) || defined(__uxpv) || defined(uxpv)
39
#define ECS_OS_UNIX_System_V
41
#elif defined(__osf__)
46
/* On Solaris, procfs may not be compiled in a largefile environment,
47
* so we redefine macros before including any system header file. */
49
#if defined(ECS_OS_Solaris) && defined(HAVE_UNISTD_H) \
50
&& defined(HAVE_SYS_PROCFS_H) && !defined(__cplusplus)
51
#define _STRUCTURED_PROC 1
52
#undef _FILE_OFFSET_BITS
53
#define _FILE_OFFSET_BITS 32
57
* Standard C library headers
64
#if defined (ECS_OS_Linux) && defined(HAVE_SYS_STAT_H) \
65
&& defined(HAVE_SYS_TYPES_H) && defined(HAVE_UNISTD_H) \
67
#include <sys/types.h>
72
#elif defined(ECS_OS_OSF1) && defined(_OSF_SOURCE) && defined(HAVE_UNISTD_H)
74
#include <sys/types.h>
75
#include <sys/signal.h>
76
#include <sys/fault.h>
77
#include <sys/syscall.h>
78
#include <sys/procfs.h>
81
#elif defined(ECS_OS_Solaris) && defined(HAVE_UNISTD_H) \
82
&& defined(HAVE_SYS_PROCFS_H) && !defined(__cplusplus)
83
#include <sys/types.h>
84
#include <sys/procfs.h>
87
#elif (defined(ECS_OS_IRIX64) || defined(ECS_OS_UNIX_System_V))
88
#if defined(HAVE_UNISTD_H) && defined(HAVE_SYS_TYPES_H) \
89
&& defined(HAVE_SYS_STAT_H)
91
#include <sys/types.h>
95
#elif defined (ECS_OS_AIX) && defined(HAVE_GETRUSAGE)
96
#include <sys/times.h>
97
#include <sys/resource.h>
99
#elif defined(HAVE_GETRUSAGE)
100
#include <sys/time.h>
101
#include <sys/resource.h>
105
#if defined(HAVE_UNISTD_H) && defined(HAVE_SBRK)
106
#if defined(__blrts__) || defined(__bgp_)
108
#elif defined (ECS_OS_Linux)
114
#if defined(HAVE_STDDEF_H)
119
* Optional library and ECS headers
122
#include "ecs_mem_usage.h"
124
/*-----------------------------------------------------------------------------*/
129
} /* Fake brace to force Emacs auto-indentation back to column 0 */
131
#endif /* __cplusplus */
133
/*-------------------------------------------------------------------------------
134
* Local type definitions
135
*-----------------------------------------------------------------------------*/
137
/*-----------------------------------------------------------------------------
138
* Local static variable definitions
139
*-----------------------------------------------------------------------------*/
141
static int _ecs_mem_usage_global_initialized = 0;
143
static size_t _ecs_mem_usage_global_max_pr = 0;
145
#if defined(USE_SBRK)
146
static void *_ecs_mem_usage_global_init_sbrk = NULL;
149
#if defined (ECS_OS_Linux) && defined(HAVE_SYS_STAT_H) \
150
&& defined(HAVE_SYS_TYPES_H)
151
static int _ecs_mem_usage_proc_file_init = 0;
154
/*-----------------------------------------------------------------------------
155
* Local function definitions
156
*-----------------------------------------------------------------------------*/
158
#if defined (ECS_OS_Linux) && defined(HAVE_SYS_STAT_H) \
159
&& defined(HAVE_SYS_TYPES_H)
162
* \brief Initialize current process memory use count depending on system.
166
_ecs_mem_usage_pr_size_init(void)
168
char buf[512]; /* should be large enough for "/proc/%lu/status"
169
then beginning of file content */
172
_Bool status_has_peak = false;
173
const pid_t pid = getpid();
176
Under Linux with procfs, one line of the pseudo-file "/proc/pid/status"
177
(where pid is the process number) is of the following form:
179
This line may be the 12th to 13th for a 2.6.x kernel.
180
On more recent 2.6.x kernels, another line (the 12th) is of the form:
184
if (_ecs_mem_usage_proc_file_init != 0)
187
sprintf(buf, "/proc/%lu/status", (unsigned long) pid);
189
fd = open(buf, O_RDONLY);
193
r_size = read(fd, buf, 512);
195
if (r_size > 32) { /* Leave a margin for "VmPeak" or "VmSize:" line */
197
for (i = 0; i < r_size; i++) {
198
if (buf[i] == 'V' && strncmp(buf+i, "VmPeak:", 7) == 0) {
199
status_has_peak = true;
203
for (i = 0; i < r_size; i++) {
204
if (buf[i] == 'V' && strncmp(buf+i, "VmSize:", 7) == 0)
207
/* If VmSize was found, proc file may be used */
209
if (status_has_peak == true)
210
_ecs_mem_usage_proc_file_init = 1;
217
/* If initialization failed for some reason (proc file unavailable or does
218
or does not contain the required fields), mark method as unusable */
219
if (_ecs_mem_usage_proc_file_init == 0)
220
_ecs_mem_usage_proc_file_init = -1;
224
* \brief Finalize current process memory use count depending on system.
228
_ecs_mem_usage_pr_size_end(void)
230
if (_ecs_mem_usage_proc_file_init != 1)
234
#else /* defined (ECS_OS_Linux) && ... */
236
#define _ecs_mem_usage_pr_size_init()
237
#define _ecs_mem_usage_pr_size_end()
239
#endif /* defined (ECS_OS_Linux) && ... */
241
/*============================================================================
242
* Public function definitions
243
*============================================================================*/
246
* \brief Initialize memory usage count depending on system.
248
* This functions checks if it has already been called, so
249
* it is safe to call more than once (though it is not
250
* thread-safe). Only the first call is effective.
254
ecs_mem_usage_init(void)
256
if (_ecs_mem_usage_global_initialized != 0)
259
#if defined(USE_SBRK)
262
We use sbrk() to know the size of the heap. This is not of any use
263
to guess at allocated memory when some part of the memory may
264
be allocated with mmap(), such as with glibc on Linux.
267
_ecs_mem_usage_global_init_sbrk = (void *) sbrk(0);
269
#endif /* (USE_SBRK) */
271
_ecs_mem_usage_global_initialized = 1;
275
* \brief End memory usage count depending on system.
279
ecs_mem_usage_end(void)
281
_ecs_mem_usage_pr_size_end();
285
* \brief Indicates if ecs_mem_usage_...() functions are initialized.
287
* \returns 1 if ecs_mem_usage_init has been called, 0 otherwise.
291
ecs_mem_usage_initialized(void)
293
return _ecs_mem_usage_global_initialized;
297
* \brief Return current process memory use (in kB) depending on system.
299
* If the information is not available (depending on availability of
300
* non-portable function calls), 0 is returned.
303
#if defined (ECS_OS_Linux) && defined(HAVE_SYS_STAT_H) \
304
&& defined(HAVE_SYS_TYPES_H)
307
ecs_mem_usage_pr_size(void)
309
size_t sys_mem_usage = 0;
312
Under Linux with procfs, one line of the pseudo-file "/proc/pid/status"
313
(where pid is the process number) is of the following form:
315
With more recent kernels, we also have a line of the form:
320
if (_ecs_mem_usage_proc_file_init == 0)
321
_ecs_mem_usage_pr_size_init();
323
if (_ecs_mem_usage_proc_file_init == 1) {
325
char buf[81]; /* should be large enough for "/proc/%lu/status" */
326
const pid_t pid = getpid();
332
sprintf(buf, "/proc/%lu/status", (unsigned long) pid);
333
fp = fopen(buf, "r");
339
while (fields_read < 2) {
340
s = fgets(buf, 80, fp);
343
if (strncmp(s, "VmSize:", 7) == 0) {
344
sscanf (s + 7, "%lu", &val);
345
sys_mem_usage = (size_t) val;
348
else if (strncmp(s, "VmPeak:", 7) == 0) {
349
sscanf (s + 7, "%lu", &val);
350
if ((size_t) val > _ecs_mem_usage_global_max_pr)
351
_ecs_mem_usage_global_max_pr = (size_t) val;
361
_ecs_mem_usage_pr_size_end();
364
if (sys_mem_usage > _ecs_mem_usage_global_max_pr)
365
_ecs_mem_usage_global_max_pr = sys_mem_usage;
367
return sys_mem_usage;
370
#elif defined (ECS_OS_OSF1) && defined(_OSF_SOURCE) && defined(HAVE_UNISTD_H)
373
ecs_mem_usage_pr_size(void)
375
size_t sys_mem_usage = 0;
377
/* On Compaq Tru64 Unix */
379
char buf[81]; /* should be large enough for "/proc/%lu/status" */
383
const pid_t pid = getpid();
385
sprintf (buf, "/proc/%05lu", (unsigned long) pid);
387
procfile = open(buf, O_RDONLY);
389
if (procfile != -1) {
391
if (ioctl(procfile, PIOCPSINFO, &p) != -1)
392
sys_mem_usage = (p.pr_size * getpagesize()) / 1024;
400
if (sys_mem_usage > _ecs_mem_usage_global_max_pr)
401
_ecs_mem_usage_global_max_pr = sys_mem_usage;
403
return sys_mem_usage;
406
#elif defined(ECS_OS_Solaris) && defined(HAVE_UNISTD_H) \
407
&& defined(HAVE_SYS_PROCFS_H) && !defined(__cplusplus)
410
ecs_mem_usage_pr_size(void)
412
size_t sys_mem_usage = 0;
415
/* We have binary pseudo-files /proc/pid/status and /proc/pid/psinfo */
417
char buf[81]; /* should be large enough for "/proc/%lu/status" */
418
const unsigned long pid = getpid ();
426
sprintf (buf, "/proc/%lu/psinfo", pid);
428
fp = fopen (buf, "r");
430
ret = fread(&pid_info, sizeof(pid_info), 1, fp);
432
sys_mem_usage = pid_info.pr_size;
438
if (sys_mem_usage > _ecs_mem_usage_global_max_pr)
439
_ecs_mem_usage_global_max_pr = sys_mem_usage;
441
return sys_mem_usage;
444
#elif (defined(ECS_OS_IRIX64) || defined(ECS_OS_UNIX_System_V))
447
ecs_mem_usage_pr_size(void)
449
size_t sys_mem_usage = 0;
451
#if defined(HAVE_UNISTD_H) && defined(HAVE_SYS_TYPES_H) \
452
&& defined(HAVE_SYS_STAT_H)
453
/* On SGI IRIX and Fujitsu VPP 5000, what follows should work */
456
char buf[81]; /* should be large enough for "/proc/%lu/status" */
457
const pid_t pid = getpid ();
459
struct stat file_stat;
461
sprintf (buf, "/proc/%05lu", (unsigned long) pid);
463
if (stat (buf, &file_stat) != -1)
464
sys_mem_usage = file_stat.st_size / 1024;
467
#endif /* HAVE_UNISTD_H and SYS_TYPES_H and SYS_STAT_H */
469
if (sys_mem_usage > _ecs_mem_usage_global_max_pr)
470
_ecs_mem_usage_global_max_pr = sys_mem_usage;
472
return sys_mem_usage;
475
#elif defined(USE_SBRK)
478
ecs_mem_usage_pr_size(void)
480
size_t alloc_size = 0;
482
if (_ecs_mem_usage_global_initialized) {
485
end_addr = (void *) sbrk(0);
487
#if defined(HAVE_PTRDIFF_T)
488
alloc_size = (size_t)( (ptrdiff_t)end_addr
489
- (ptrdiff_t)_ecs_mem_usage_global_init_sbrk) / 1024;
491
alloc_size = (end_addr - _ecs_mem_usage_global_init_sbrk) / 1024;
496
if (alloc_size > _ecs_mem_usage_global_max_pr)
497
_ecs_mem_usage_global_max_pr = alloc_size;
502
#elif defined(HAVE_GETRUSAGE)
505
ecs_mem_usage_pr_size(void)
507
size_t sys_mem_usage = 0;
510
getrusage(RUSAGE_SELF, &usage);
512
sys_mem_usage = usage.ru_maxrss / 1024;
514
return sys_mem_usage;
517
#else /* Default case */
520
ecs_mem_usage_pr_size(void)
525
#endif /* ECS_OS_Linux, ECS_OS_OSF1, ... */
528
* \brief Return maximum process memory use (in kB) depending on OS.
530
* The returned value is the maximum returned by ecs_mem_usage_pr_size()
531
* during the program's lifetime. With memory allocations which return
532
* memory to the system (such as the GNU glibc on Linux systems),
533
* this value will be correct only if allocation is tracked. This should
534
* be the case if malloc hooks are used with the glibc allocation
535
* functions (ECS library's default configuration/installation option),
536
* but may give results lower than the true maximum in other cases.
540
ecs_mem_usage_max_pr_size(void)
542
(void) ecs_mem_usage_pr_size();
544
return _ecs_mem_usage_global_max_pr;
547
/*----------------------------------------------------------------------------*/
551
#endif /* __cplusplus */