~ubuntu-branches/ubuntu/precise/code-saturne/precise

« back to all changes in this revision

Viewing changes to preprocessor/util/ecs_mem_usage.c

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2011-11-24 00:00:08 UTC
  • mfrom: (6.1.9 sid)
  • Revision ID: package-import@ubuntu.com-20111124000008-2vo99e38267942q5
Tags: 2.1.0-3
Install a missing file

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*============================================================================
 
2
 * Base memory usage information (System and Library dependent)
 
3
 *============================================================================*/
 
4
 
 
5
/*
 
6
  This file is part of Code_Saturne, a general-purpose CFD tool.
 
7
 
 
8
  Copyright (C) 1998-2011 EDF S.A.
 
9
 
 
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
 
13
  version.
 
14
 
 
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
 
18
  details.
 
19
 
 
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.
 
23
*/
 
24
 
 
25
/*----------------------------------------------------------------------------*/
 
26
 
 
27
#include "cs_config.h"
 
28
#include "ecs_def.h"
 
29
 
 
30
/* OS type */
 
31
 
 
32
#if defined(__linux__) || defined(__linux) || defined(linux)
 
33
#define ECS_OS_Linux
 
34
 
 
35
#elif defined(__sun__) || defined(__sun) || defined(sun)
 
36
#define ECS_OS_Solaris
 
37
 
 
38
#elif defined(__uxpv__) || defined(__uxpv) || defined(uxpv)
 
39
#define ECS_OS_UNIX_System_V
 
40
 
 
41
#elif defined(__osf__)
 
42
#define ECS_OS_OSF1
 
43
 
 
44
#endif
 
45
 
 
46
/* On Solaris, procfs may not be compiled in a largefile environment,
 
47
 * so we redefine macros before including any system header file. */
 
48
 
 
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
 
54
#endif
 
55
 
 
56
/*
 
57
 * Standard C library headers
 
58
 */
 
59
 
 
60
#include <stdio.h>
 
61
#include <stdlib.h>
 
62
#include <string.h>
 
63
 
 
64
#if defined (ECS_OS_Linux) && defined(HAVE_SYS_STAT_H) \
 
65
 && defined(HAVE_SYS_TYPES_H) && defined(HAVE_UNISTD_H) \
 
66
 
 
67
#include <sys/types.h>
 
68
#include <unistd.h>
 
69
#include <sys/stat.h>
 
70
#include <fcntl.h>
 
71
 
 
72
#elif defined(ECS_OS_OSF1) && defined(_OSF_SOURCE) && defined(HAVE_UNISTD_H)
 
73
#include <fcntl.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>
 
79
#include <unistd.h>
 
80
 
 
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>
 
85
#include <unistd.h>
 
86
 
 
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)
 
90
#include <sys/stat.h>
 
91
#include <sys/types.h>
 
92
#include <unistd.h>
 
93
#endif
 
94
 
 
95
#elif defined (ECS_OS_AIX) && defined(HAVE_GETRUSAGE)
 
96
#include <sys/times.h>
 
97
#include <sys/resource.h>
 
98
 
 
99
#elif defined(HAVE_GETRUSAGE)
 
100
#include <sys/time.h>
 
101
#include <sys/resource.h>
 
102
#include <unistd.h>
 
103
#endif
 
104
 
 
105
#if defined(HAVE_UNISTD_H) && defined(HAVE_SBRK)
 
106
#if defined(__blrts__) || defined(__bgp_)
 
107
#define USE_SBRK 1
 
108
#elif defined (ECS_OS_Linux)
 
109
#define __USE_MISC 1
 
110
#endif
 
111
#include <unistd.h>
 
112
#endif
 
113
 
 
114
#if defined(HAVE_STDDEF_H)
 
115
#include <stddef.h>
 
116
#endif
 
117
 
 
118
/*
 
119
 * Optional library and ECS headers
 
120
 */
 
121
 
 
122
#include "ecs_mem_usage.h"
 
123
 
 
124
/*-----------------------------------------------------------------------------*/
 
125
 
 
126
#ifdef __cplusplus
 
127
extern "C" {
 
128
#if 0
 
129
} /* Fake brace to force Emacs auto-indentation back to column 0 */
 
130
#endif
 
131
#endif /* __cplusplus */
 
132
 
 
133
/*-------------------------------------------------------------------------------
 
134
 * Local type definitions
 
135
 *-----------------------------------------------------------------------------*/
 
136
 
 
137
/*-----------------------------------------------------------------------------
 
138
 * Local static variable definitions
 
139
 *-----------------------------------------------------------------------------*/
 
140
 
 
141
static int  _ecs_mem_usage_global_initialized = 0;
 
142
 
 
143
static size_t _ecs_mem_usage_global_max_pr = 0;
 
144
 
 
145
#if defined(USE_SBRK)
 
146
static void  *_ecs_mem_usage_global_init_sbrk = NULL;
 
147
#endif
 
148
 
 
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;
 
152
#endif
 
153
 
 
154
/*-----------------------------------------------------------------------------
 
155
 * Local function definitions
 
156
 *-----------------------------------------------------------------------------*/
 
157
 
 
158
#if defined (ECS_OS_Linux) && defined(HAVE_SYS_STAT_H) \
 
159
                             && defined(HAVE_SYS_TYPES_H)
 
160
 
 
161
/*!
 
162
 * \brief Initialize current process memory use count depending on system.
 
163
 */
 
164
 
 
165
static void
 
166
_ecs_mem_usage_pr_size_init(void)
 
167
{
 
168
  char  buf[512]; /* should be large enough for "/proc/%lu/status"
 
169
                     then beginning of file content */
 
170
  int fd;
 
171
  size_t  r_size, i;
 
172
  _Bool   status_has_peak = false;
 
173
  const pid_t  pid = getpid();
 
174
 
 
175
  /*
 
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:
 
178
    VmSize:     xxxx kB
 
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:
 
181
    VmPeak:     xxxx kB
 
182
  */
 
183
 
 
184
  if (_ecs_mem_usage_proc_file_init != 0)
 
185
    return;
 
186
 
 
187
  sprintf(buf, "/proc/%lu/status", (unsigned long) pid);
 
188
 
 
189
  fd = open(buf, O_RDONLY);
 
190
 
 
191
  if (fd != -1) {
 
192
 
 
193
    r_size = read(fd, buf, 512);
 
194
 
 
195
    if (r_size > 32) { /* Leave a margin for "VmPeak" or "VmSize:" line */
 
196
      r_size -= 32;
 
197
      for (i = 0; i < r_size; i++) {
 
198
        if (buf[i] == 'V' && strncmp(buf+i, "VmPeak:", 7) == 0) {
 
199
          status_has_peak = true;
 
200
          break;
 
201
        }
 
202
      }
 
203
      for (i = 0; i < r_size; i++) {
 
204
        if (buf[i] == 'V' && strncmp(buf+i, "VmSize:", 7) == 0)
 
205
          break;
 
206
      }
 
207
      /* If VmSize was found, proc file may be used */
 
208
      if (i < r_size) {
 
209
        if (status_has_peak == true)
 
210
          _ecs_mem_usage_proc_file_init = 1;
 
211
      }
 
212
    }
 
213
 
 
214
    (void)close(fd);
 
215
  }
 
216
 
 
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;
 
221
}
 
222
 
 
223
/*!
 
224
 * \brief Finalize current process memory use count depending on system.
 
225
 */
 
226
 
 
227
static void
 
228
_ecs_mem_usage_pr_size_end(void)
 
229
{
 
230
  if (_ecs_mem_usage_proc_file_init != 1)
 
231
    return;
 
232
}
 
233
 
 
234
#else  /* defined (ECS_OS_Linux) && ... */
 
235
 
 
236
#define _ecs_mem_usage_pr_size_init()
 
237
#define _ecs_mem_usage_pr_size_end()
 
238
 
 
239
#endif /* defined (ECS_OS_Linux) && ... */
 
240
 
 
241
/*============================================================================
 
242
 * Public function definitions
 
243
 *============================================================================*/
 
244
 
 
245
/*!
 
246
 * \brief Initialize memory usage count depending on system.
 
247
 *
 
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.
 
251
 */
 
252
 
 
253
void
 
254
ecs_mem_usage_init(void)
 
255
{
 
256
  if (_ecs_mem_usage_global_initialized != 0)
 
257
    return;
 
258
 
 
259
#if defined(USE_SBRK)
 
260
 
 
261
  /*
 
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.
 
265
  */
 
266
 
 
267
  _ecs_mem_usage_global_init_sbrk = (void *) sbrk(0);
 
268
 
 
269
#endif /* (USE_SBRK) */
 
270
 
 
271
  _ecs_mem_usage_global_initialized = 1;
 
272
}
 
273
 
 
274
/*!
 
275
 * \brief End memory usage count depending on system.
 
276
 */
 
277
 
 
278
void
 
279
ecs_mem_usage_end(void)
 
280
{
 
281
  _ecs_mem_usage_pr_size_end();
 
282
}
 
283
 
 
284
/*!
 
285
 * \brief Indicates if ecs_mem_usage_...() functions are initialized.
 
286
 *
 
287
 * \returns 1 if ecs_mem_usage_init has been called, 0 otherwise.
 
288
 */
 
289
 
 
290
int
 
291
ecs_mem_usage_initialized(void)
 
292
{
 
293
  return _ecs_mem_usage_global_initialized;
 
294
}
 
295
 
 
296
/*!
 
297
 * \brief Return current process memory use (in kB) depending on system.
 
298
 *
 
299
 * If the information is not available (depending on availability of
 
300
 * non-portable function calls), 0 is returned.
 
301
 */
 
302
 
 
303
#if defined (ECS_OS_Linux) && defined(HAVE_SYS_STAT_H) \
 
304
                           && defined(HAVE_SYS_TYPES_H)
 
305
 
 
306
size_t
 
307
ecs_mem_usage_pr_size(void)
 
308
{
 
309
  size_t sys_mem_usage = 0;
 
310
 
 
311
  /*
 
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:
 
314
    VmSize:     xxxx kB
 
315
    With more recent kernels, we also have a line of the form:
 
316
    VmPeak:     xxxx kB
 
317
  */
 
318
 
 
319
  {
 
320
    if (_ecs_mem_usage_proc_file_init == 0)
 
321
      _ecs_mem_usage_pr_size_init();
 
322
 
 
323
    if (_ecs_mem_usage_proc_file_init == 1) {
 
324
 
 
325
      char  buf[81]; /* should be large enough for "/proc/%lu/status" */
 
326
      const pid_t  pid = getpid();
 
327
 
 
328
      FILE *fp;
 
329
      unsigned long val;
 
330
      char *s;
 
331
 
 
332
      sprintf(buf, "/proc/%lu/status", (unsigned long) pid);
 
333
      fp = fopen(buf, "r");
 
334
 
 
335
      if (fp != NULL) {
 
336
 
 
337
        int fields_read = 0;
 
338
 
 
339
        while (fields_read < 2) {
 
340
          s = fgets(buf, 80, fp);
 
341
          if (s == NULL)
 
342
            break;
 
343
          if (strncmp(s, "VmSize:", 7) == 0) {
 
344
            sscanf (s + 7, "%lu", &val);
 
345
            sys_mem_usage = (size_t) val;
 
346
            fields_read += 1;
 
347
          }
 
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;
 
352
            fields_read += 1;
 
353
          }
 
354
        }
 
355
 
 
356
        fclose(fp);
 
357
 
 
358
      }
 
359
    }
 
360
 
 
361
    _ecs_mem_usage_pr_size_end();
 
362
  }
 
363
 
 
364
  if (sys_mem_usage > _ecs_mem_usage_global_max_pr)
 
365
    _ecs_mem_usage_global_max_pr = sys_mem_usage;
 
366
 
 
367
  return sys_mem_usage;
 
368
}
 
369
 
 
370
#elif defined (ECS_OS_OSF1) && defined(_OSF_SOURCE) && defined(HAVE_UNISTD_H)
 
371
 
 
372
size_t
 
373
ecs_mem_usage_pr_size(void)
 
374
{
 
375
  size_t sys_mem_usage = 0;
 
376
 
 
377
  /* On Compaq Tru64 Unix */
 
378
  {
 
379
    char        buf[81];  /* should be large enough for "/proc/%lu/status" */
 
380
    int         procfile;
 
381
    prpsinfo_t  p;
 
382
 
 
383
    const  pid_t  pid = getpid();
 
384
 
 
385
    sprintf (buf, "/proc/%05lu", (unsigned long) pid);
 
386
 
 
387
    procfile = open(buf, O_RDONLY);
 
388
 
 
389
    if (procfile != -1) {
 
390
 
 
391
      if (ioctl(procfile, PIOCPSINFO, &p) != -1)
 
392
        sys_mem_usage  = (p.pr_size * getpagesize()) / 1024;
 
393
 
 
394
      close(procfile);
 
395
 
 
396
    }
 
397
 
 
398
  }
 
399
 
 
400
  if (sys_mem_usage > _ecs_mem_usage_global_max_pr)
 
401
    _ecs_mem_usage_global_max_pr = sys_mem_usage;
 
402
 
 
403
  return sys_mem_usage;
 
404
}
 
405
 
 
406
#elif defined(ECS_OS_Solaris) && defined(HAVE_UNISTD_H) \
 
407
   && defined(HAVE_SYS_PROCFS_H) && !defined(__cplusplus)
 
408
 
 
409
size_t
 
410
ecs_mem_usage_pr_size(void)
 
411
{
 
412
  size_t sys_mem_usage = 0;
 
413
 
 
414
  {
 
415
    /* We have binary pseudo-files /proc/pid/status and /proc/pid/psinfo */
 
416
 
 
417
    char   buf[81];     /* should be large enough for "/proc/%lu/status" */
 
418
    const  unsigned long  pid = getpid ();
 
419
 
 
420
    FILE     *fp;
 
421
    int       val;
 
422
    char     *s ;
 
423
    size_t    ret;
 
424
    psinfo_t  pid_info;
 
425
 
 
426
    sprintf (buf, "/proc/%lu/psinfo", pid);
 
427
 
 
428
    fp = fopen (buf, "r");
 
429
    if (fp != NULL) {
 
430
      ret = fread(&pid_info, sizeof(pid_info), 1, fp);
 
431
      if (ret == 1)
 
432
        sys_mem_usage = pid_info.pr_size;
 
433
      fclose (fp);
 
434
    }
 
435
 
 
436
  }
 
437
 
 
438
  if (sys_mem_usage > _ecs_mem_usage_global_max_pr)
 
439
    _ecs_mem_usage_global_max_pr = sys_mem_usage;
 
440
 
 
441
  return sys_mem_usage;
 
442
}
 
443
 
 
444
#elif (defined(ECS_OS_IRIX64) || defined(ECS_OS_UNIX_System_V))
 
445
 
 
446
size_t
 
447
ecs_mem_usage_pr_size(void)
 
448
{
 
449
  size_t sys_mem_usage = 0;
 
450
 
 
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 */
 
454
 
 
455
  {
 
456
    char   buf[81];     /* should be large enough for "/proc/%lu/status" */
 
457
    const  pid_t  pid = getpid ();
 
458
 
 
459
    struct stat file_stat;
 
460
 
 
461
    sprintf (buf, "/proc/%05lu", (unsigned long) pid);
 
462
 
 
463
    if (stat (buf, &file_stat) != -1)
 
464
      sys_mem_usage = file_stat.st_size / 1024;
 
465
 
 
466
  }
 
467
#endif /* HAVE_UNISTD_H and SYS_TYPES_H and SYS_STAT_H */
 
468
 
 
469
  if (sys_mem_usage > _ecs_mem_usage_global_max_pr)
 
470
    _ecs_mem_usage_global_max_pr = sys_mem_usage;
 
471
 
 
472
  return sys_mem_usage;
 
473
}
 
474
 
 
475
#elif defined(USE_SBRK)
 
476
 
 
477
size_t
 
478
ecs_mem_usage_pr_size(void)
 
479
{
 
480
  size_t alloc_size = 0;
 
481
 
 
482
  if (_ecs_mem_usage_global_initialized) {
 
483
    void    *end_addr;
 
484
 
 
485
    end_addr = (void *) sbrk(0);
 
486
 
 
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;
 
490
#else
 
491
    alloc_size = (end_addr - _ecs_mem_usage_global_init_sbrk) / 1024;
 
492
#endif
 
493
 
 
494
  }
 
495
 
 
496
  if (alloc_size > _ecs_mem_usage_global_max_pr)
 
497
    _ecs_mem_usage_global_max_pr = alloc_size;
 
498
 
 
499
  return alloc_size;
 
500
}
 
501
 
 
502
#elif defined(HAVE_GETRUSAGE)
 
503
 
 
504
size_t
 
505
ecs_mem_usage_pr_size(void)
 
506
{
 
507
  size_t sys_mem_usage = 0;
 
508
  struct rusage usage;
 
509
 
 
510
  getrusage(RUSAGE_SELF, &usage);
 
511
 
 
512
  sys_mem_usage = usage.ru_maxrss / 1024;
 
513
 
 
514
  return sys_mem_usage;
 
515
}
 
516
 
 
517
#else /* Default case */
 
518
 
 
519
size_t
 
520
ecs_mem_usage_pr_size(void)
 
521
{
 
522
  return 0;
 
523
}
 
524
 
 
525
#endif /* ECS_OS_Linux, ECS_OS_OSF1, ... */
 
526
 
 
527
/*
 
528
 * \brief Return maximum process memory use (in kB) depending on OS.
 
529
 *
 
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.
 
537
 */
 
538
 
 
539
size_t
 
540
ecs_mem_usage_max_pr_size(void)
 
541
{
 
542
  (void) ecs_mem_usage_pr_size();
 
543
 
 
544
  return _ecs_mem_usage_global_max_pr;
 
545
}
 
546
 
 
547
/*----------------------------------------------------------------------------*/
 
548
 
 
549
#ifdef __cplusplus
 
550
}
 
551
#endif /* __cplusplus */