Coverage Report

Created: 2025-07-04 06:49

/src/cpython/Objects/mimalloc/stats.c
Line
Count
Source (jump to first uncovered line)
1
/* ----------------------------------------------------------------------------
2
Copyright (c) 2018-2021, Microsoft Research, Daan Leijen
3
This is free software; you can redistribute it and/or modify it under the
4
terms of the MIT license. A copy of the license can be found in the file
5
"LICENSE" at the root of this distribution.
6
-----------------------------------------------------------------------------*/
7
#include "mimalloc.h"
8
#include "mimalloc/internal.h"
9
#include "mimalloc/atomic.h"
10
#include "mimalloc/prim.h"
11
12
#include <stdio.h>  // snprintf
13
#include <string.h> // memset
14
15
#if defined(_MSC_VER) && (_MSC_VER < 1920)
16
#pragma warning(disable:4204)  // non-constant aggregate initializer
17
#endif
18
19
/* -----------------------------------------------------------
20
  Statistics operations
21
----------------------------------------------------------- */
22
23
0
static bool mi_is_in_main(void* stat) {
24
0
  return ((uint8_t*)stat >= (uint8_t*)&_mi_stats_main
25
0
         && (uint8_t*)stat < ((uint8_t*)&_mi_stats_main + sizeof(mi_stats_t)));
26
0
}
27
28
0
static void mi_stat_update(mi_stat_count_t* stat, int64_t amount) {
29
0
  if (amount == 0) return;
30
0
  if (mi_is_in_main(stat))
31
0
  {
32
    // add atomically (for abandoned pages)
33
0
    int64_t current = mi_atomic_addi64_relaxed(&stat->current, amount);
34
0
    mi_atomic_maxi64_relaxed(&stat->peak, current + amount);
35
0
    if (amount > 0) {
36
0
      mi_atomic_addi64_relaxed(&stat->allocated,amount);
37
0
    }
38
0
    else {
39
0
      mi_atomic_addi64_relaxed(&stat->freed, -amount);
40
0
    }
41
0
  }
42
0
  else {
43
    // add thread local
44
0
    stat->current += amount;
45
0
    if (stat->current > stat->peak) stat->peak = stat->current;
46
0
    if (amount > 0) {
47
0
      stat->allocated += amount;
48
0
    }
49
0
    else {
50
0
      stat->freed += -amount;
51
0
    }
52
0
  }
53
0
}
54
55
0
void _mi_stat_counter_increase(mi_stat_counter_t* stat, size_t amount) {
56
0
  if (mi_is_in_main(stat)) {
57
0
    mi_atomic_addi64_relaxed( &stat->count, 1 );
58
0
    mi_atomic_addi64_relaxed( &stat->total, (int64_t)amount );
59
0
  }
60
0
  else {
61
0
    stat->count++;
62
0
    stat->total += amount;
63
0
  }
64
0
}
65
66
0
void _mi_stat_increase(mi_stat_count_t* stat, size_t amount) {
67
0
  mi_stat_update(stat, (int64_t)amount);
68
0
}
69
70
0
void _mi_stat_decrease(mi_stat_count_t* stat, size_t amount) {
71
0
  mi_stat_update(stat, -((int64_t)amount));
72
0
}
73
74
// must be thread safe as it is called from stats_merge
75
0
static void mi_stat_add(mi_stat_count_t* stat, const mi_stat_count_t* src, int64_t unit) {
76
0
  if (stat==src) return;
77
0
  if (src->allocated==0 && src->freed==0) return;
78
0
  mi_atomic_addi64_relaxed( &stat->allocated, src->allocated * unit);
79
0
  mi_atomic_addi64_relaxed( &stat->current, src->current * unit);
80
0
  mi_atomic_addi64_relaxed( &stat->freed, src->freed * unit);
81
  // peak scores do not work across threads..
82
0
  mi_atomic_addi64_relaxed( &stat->peak, src->peak * unit);
83
0
}
84
85
0
static void mi_stat_counter_add(mi_stat_counter_t* stat, const mi_stat_counter_t* src, int64_t unit) {
86
0
  if (stat==src) return;
87
0
  mi_atomic_addi64_relaxed( &stat->total, src->total * unit);
88
0
  mi_atomic_addi64_relaxed( &stat->count, src->count * unit);
89
0
}
90
91
// must be thread safe as it is called from stats_merge
92
0
static void mi_stats_add(mi_stats_t* stats, const mi_stats_t* src) {
93
0
  if (stats==src) return;
94
0
  mi_stat_add(&stats->segments, &src->segments,1);
95
0
  mi_stat_add(&stats->pages, &src->pages,1);
96
0
  mi_stat_add(&stats->reserved, &src->reserved, 1);
97
0
  mi_stat_add(&stats->committed, &src->committed, 1);
98
0
  mi_stat_add(&stats->reset, &src->reset, 1);
99
0
  mi_stat_add(&stats->purged, &src->purged, 1);
100
0
  mi_stat_add(&stats->page_committed, &src->page_committed, 1);
101
102
0
  mi_stat_add(&stats->pages_abandoned, &src->pages_abandoned, 1);
103
0
  mi_stat_add(&stats->segments_abandoned, &src->segments_abandoned, 1);
104
0
  mi_stat_add(&stats->threads, &src->threads, 1);
105
106
0
  mi_stat_add(&stats->malloc, &src->malloc, 1);
107
0
  mi_stat_add(&stats->segments_cache, &src->segments_cache, 1);
108
0
  mi_stat_add(&stats->normal, &src->normal, 1);
109
0
  mi_stat_add(&stats->huge, &src->huge, 1);
110
0
  mi_stat_add(&stats->large, &src->large, 1);
111
112
0
  mi_stat_counter_add(&stats->pages_extended, &src->pages_extended, 1);
113
0
  mi_stat_counter_add(&stats->mmap_calls, &src->mmap_calls, 1);
114
0
  mi_stat_counter_add(&stats->commit_calls, &src->commit_calls, 1);
115
0
  mi_stat_counter_add(&stats->reset_calls, &src->reset_calls, 1);
116
0
  mi_stat_counter_add(&stats->purge_calls, &src->purge_calls, 1);
117
118
0
  mi_stat_counter_add(&stats->page_no_retire, &src->page_no_retire, 1);
119
0
  mi_stat_counter_add(&stats->searches, &src->searches, 1);
120
0
  mi_stat_counter_add(&stats->normal_count, &src->normal_count, 1);
121
0
  mi_stat_counter_add(&stats->huge_count, &src->huge_count, 1);
122
0
  mi_stat_counter_add(&stats->large_count, &src->large_count, 1);
123
#if MI_STAT>1
124
  for (size_t i = 0; i <= MI_BIN_HUGE; i++) {
125
    if (src->normal_bins[i].allocated > 0 || src->normal_bins[i].freed > 0) {
126
      mi_stat_add(&stats->normal_bins[i], &src->normal_bins[i], 1);
127
    }
128
  }
129
#endif
130
0
}
131
132
/* -----------------------------------------------------------
133
  Display statistics
134
----------------------------------------------------------- */
135
136
// unit > 0 : size in binary bytes
137
// unit == 0: count as decimal
138
// unit < 0 : count in binary
139
0
static void mi_printf_amount(int64_t n, int64_t unit, mi_output_fun* out, void* arg, const char* fmt) {
140
0
  char buf[32]; buf[0] = 0;
141
0
  int  len = 32;
142
0
  const char* suffix = (unit <= 0 ? " " : "B");
143
0
  const int64_t base = (unit == 0 ? 1000 : 1024);
144
0
  if (unit>0) n *= unit;
145
146
0
  const int64_t pos = (n < 0 ? -n : n);
147
0
  if (pos < base) {
148
0
    if (n!=1 || suffix[0] != 'B') {  // skip printing 1 B for the unit column
149
0
      snprintf(buf, len, "%d   %-3s", (int)n, (n==0 ? "" : suffix));
150
0
    }
151
0
  }
152
0
  else {
153
0
    int64_t divider = base;
154
0
    const char* magnitude = "K";
155
0
    if (pos >= divider*base) { divider *= base; magnitude = "M"; }
156
0
    if (pos >= divider*base) { divider *= base; magnitude = "G"; }
157
0
    const int64_t tens = (n / (divider/10));
158
0
    const long whole = (long)(tens/10);
159
0
    const long frac1 = (long)(tens%10);
160
0
    char unitdesc[8];
161
0
    snprintf(unitdesc, 8, "%s%s%s", magnitude, (base==1024 ? "i" : ""), suffix);
162
0
    snprintf(buf, len, "%ld.%ld %-3s", whole, (frac1 < 0 ? -frac1 : frac1), unitdesc);
163
0
  }
164
0
  _mi_fprintf(out, arg, (fmt==NULL ? "%12s" : fmt), buf);
165
0
}
166
167
168
0
static void mi_print_amount(int64_t n, int64_t unit, mi_output_fun* out, void* arg) {
169
0
  mi_printf_amount(n,unit,out,arg,NULL);
170
0
}
171
172
0
static void mi_print_count(int64_t n, int64_t unit, mi_output_fun* out, void* arg) {
173
0
  if (unit==1) _mi_fprintf(out, arg, "%12s"," ");
174
0
          else mi_print_amount(n,0,out,arg);
175
0
}
176
177
0
static void mi_stat_print_ex(const mi_stat_count_t* stat, const char* msg, int64_t unit, mi_output_fun* out, void* arg, const char* notok ) {
178
0
  _mi_fprintf(out, arg,"%10s:", msg);
179
0
  if (unit > 0) {
180
0
    mi_print_amount(stat->peak, unit, out, arg);
181
0
    mi_print_amount(stat->allocated, unit, out, arg);
182
0
    mi_print_amount(stat->freed, unit, out, arg);
183
0
    mi_print_amount(stat->current, unit, out, arg);
184
0
    mi_print_amount(unit, 1, out, arg);
185
0
    mi_print_count(stat->allocated, unit, out, arg);
186
0
    if (stat->allocated > stat->freed) {
187
0
      _mi_fprintf(out, arg, "  ");
188
0
      _mi_fprintf(out, arg, (notok == NULL ? "not all freed" : notok));
189
0
      _mi_fprintf(out, arg, "\n");
190
0
    }
191
0
    else {
192
0
      _mi_fprintf(out, arg, "  ok\n");
193
0
    }
194
0
  }
195
0
  else if (unit<0) {
196
0
    mi_print_amount(stat->peak, -1, out, arg);
197
0
    mi_print_amount(stat->allocated, -1, out, arg);
198
0
    mi_print_amount(stat->freed, -1, out, arg);
199
0
    mi_print_amount(stat->current, -1, out, arg);
200
0
    if (unit==-1) {
201
0
      _mi_fprintf(out, arg, "%24s", "");
202
0
    }
203
0
    else {
204
0
      mi_print_amount(-unit, 1, out, arg);
205
0
      mi_print_count((stat->allocated / -unit), 0, out, arg);
206
0
    }
207
0
    if (stat->allocated > stat->freed)
208
0
      _mi_fprintf(out, arg, "  not all freed!\n");
209
0
    else
210
0
      _mi_fprintf(out, arg, "  ok\n");
211
0
  }
212
0
  else {
213
0
    mi_print_amount(stat->peak, 1, out, arg);
214
0
    mi_print_amount(stat->allocated, 1, out, arg);
215
0
    _mi_fprintf(out, arg, "%11s", " ");  // no freed
216
0
    mi_print_amount(stat->current, 1, out, arg);
217
0
    _mi_fprintf(out, arg, "\n");
218
0
  }
219
0
}
220
221
0
static void mi_stat_print(const mi_stat_count_t* stat, const char* msg, int64_t unit, mi_output_fun* out, void* arg) {
222
0
  mi_stat_print_ex(stat, msg, unit, out, arg, NULL);
223
0
}
224
225
0
static void mi_stat_peak_print(const mi_stat_count_t* stat, const char* msg, int64_t unit, mi_output_fun* out, void* arg) {
226
0
  _mi_fprintf(out, arg, "%10s:", msg);
227
0
  mi_print_amount(stat->peak, unit, out, arg);
228
0
  _mi_fprintf(out, arg, "\n");
229
0
}
230
231
0
static void mi_stat_counter_print(const mi_stat_counter_t* stat, const char* msg, mi_output_fun* out, void* arg ) {
232
0
  _mi_fprintf(out, arg, "%10s:", msg);
233
0
  mi_print_amount(stat->total, -1, out, arg);
234
0
  _mi_fprintf(out, arg, "\n");
235
0
}
236
237
238
0
static void mi_stat_counter_print_avg(const mi_stat_counter_t* stat, const char* msg, mi_output_fun* out, void* arg) {
239
0
  const int64_t avg_tens = (stat->count == 0 ? 0 : (stat->total*10 / stat->count));
240
0
  const long avg_whole = (long)(avg_tens/10);
241
0
  const long avg_frac1 = (long)(avg_tens%10);
242
0
  _mi_fprintf(out, arg, "%10s: %5ld.%ld avg\n", msg, avg_whole, avg_frac1);
243
0
}
244
245
246
0
static void mi_print_header(mi_output_fun* out, void* arg ) {
247
0
  _mi_fprintf(out, arg, "%10s: %11s %11s %11s %11s %11s %11s\n", "heap stats", "peak   ", "total   ", "freed   ", "current   ", "unit   ", "count   ");
248
0
}
249
250
#if MI_STAT>1
251
static void mi_stats_print_bins(const mi_stat_count_t* bins, size_t max, const char* fmt, mi_output_fun* out, void* arg) {
252
  bool found = false;
253
  char buf[64];
254
  for (size_t i = 0; i <= max; i++) {
255
    if (bins[i].allocated > 0) {
256
      found = true;
257
      int64_t unit = _mi_bin_size((uint8_t)i);
258
      snprintf(buf, 64, "%s %3lu", fmt, (long)i);
259
      mi_stat_print(&bins[i], buf, unit, out, arg);
260
    }
261
  }
262
  if (found) {
263
    _mi_fprintf(out, arg, "\n");
264
    mi_print_header(out, arg);
265
  }
266
}
267
#endif
268
269
270
271
//------------------------------------------------------------
272
// Use an output wrapper for line-buffered output
273
// (which is nice when using loggers etc.)
274
//------------------------------------------------------------
275
typedef struct buffered_s {
276
  mi_output_fun* out;   // original output function
277
  void*          arg;   // and state
278
  char*          buf;   // local buffer of at least size `count+1`
279
  size_t         used;  // currently used chars `used <= count`
280
  size_t         count; // total chars available for output
281
} buffered_t;
282
283
0
static void mi_buffered_flush(buffered_t* buf) {
284
0
  buf->buf[buf->used] = 0;
285
0
  _mi_fputs(buf->out, buf->arg, NULL, buf->buf);
286
0
  buf->used = 0;
287
0
}
288
289
0
static void mi_cdecl mi_buffered_out(const char* msg, void* arg) {
290
0
  buffered_t* buf = (buffered_t*)arg;
291
0
  if (msg==NULL || buf==NULL) return;
292
0
  for (const char* src = msg; *src != 0; src++) {
293
0
    char c = *src;
294
0
    if (buf->used >= buf->count) mi_buffered_flush(buf);
295
0
    mi_assert_internal(buf->used < buf->count);
296
0
    buf->buf[buf->used++] = c;
297
0
    if (c == '\n') mi_buffered_flush(buf);
298
0
  }
299
0
}
300
301
//------------------------------------------------------------
302
// Print statistics
303
//------------------------------------------------------------
304
305
0
static void _mi_stats_print(mi_stats_t* stats, mi_output_fun* out0, void* arg0) mi_attr_noexcept {
306
  // wrap the output function to be line buffered
307
0
  char buf[256];
308
0
  buffered_t buffer = { out0, arg0, NULL, 0, 255 };
309
0
  buffer.buf = buf;
310
0
  mi_output_fun* out = &mi_buffered_out;
311
0
  void* arg = &buffer;
312
313
  // and print using that
314
0
  mi_print_header(out,arg);
315
  #if MI_STAT>1
316
  mi_stats_print_bins(stats->normal_bins, MI_BIN_HUGE, "normal",out,arg);
317
  #endif
318
  #if MI_STAT
319
  mi_stat_print(&stats->normal, "normal", (stats->normal_count.count == 0 ? 1 : -(stats->normal.allocated / stats->normal_count.count)), out, arg);
320
  mi_stat_print(&stats->large, "large", (stats->large_count.count == 0 ? 1 : -(stats->large.allocated / stats->large_count.count)), out, arg);
321
  mi_stat_print(&stats->huge, "huge", (stats->huge_count.count == 0 ? 1 : -(stats->huge.allocated / stats->huge_count.count)), out, arg);
322
  mi_stat_count_t total = { 0,0,0,0 };
323
  mi_stat_add(&total, &stats->normal, 1);
324
  mi_stat_add(&total, &stats->large, 1);
325
  mi_stat_add(&total, &stats->huge, 1);
326
  mi_stat_print(&total, "total", 1, out, arg);
327
  #endif
328
  #if MI_STAT>1
329
  mi_stat_print(&stats->malloc, "malloc req", 1, out, arg);
330
  _mi_fprintf(out, arg, "\n");
331
  #endif
332
0
  mi_stat_print_ex(&stats->reserved, "reserved", 1, out, arg, "");
333
0
  mi_stat_print_ex(&stats->committed, "committed", 1, out, arg, "");
334
0
  mi_stat_peak_print(&stats->reset, "reset", 1, out, arg );
335
0
  mi_stat_peak_print(&stats->purged, "purged", 1, out, arg );
336
0
  mi_stat_print(&stats->page_committed, "touched", 1, out, arg);
337
0
  mi_stat_print(&stats->segments, "segments", -1, out, arg);
338
0
  mi_stat_print(&stats->segments_abandoned, "-abandoned", -1, out, arg);
339
0
  mi_stat_print(&stats->segments_cache, "-cached", -1, out, arg);
340
0
  mi_stat_print(&stats->pages, "pages", -1, out, arg);
341
0
  mi_stat_print(&stats->pages_abandoned, "-abandoned", -1, out, arg);
342
0
  mi_stat_counter_print(&stats->pages_extended, "-extended", out, arg);
343
0
  mi_stat_counter_print(&stats->page_no_retire, "-noretire", out, arg);
344
0
  mi_stat_counter_print(&stats->mmap_calls, "mmaps", out, arg);
345
0
  mi_stat_counter_print(&stats->commit_calls, "commits", out, arg);
346
0
  mi_stat_counter_print(&stats->reset_calls, "resets", out, arg);
347
0
  mi_stat_counter_print(&stats->purge_calls, "purges", out, arg);
348
0
  mi_stat_print(&stats->threads, "threads", -1, out, arg);
349
0
  mi_stat_counter_print_avg(&stats->searches, "searches", out, arg);
350
0
  _mi_fprintf(out, arg, "%10s: %5zu\n", "numa nodes", _mi_os_numa_node_count());
351
352
0
  size_t elapsed;
353
0
  size_t user_time;
354
0
  size_t sys_time;
355
0
  size_t current_rss;
356
0
  size_t peak_rss;
357
0
  size_t current_commit;
358
0
  size_t peak_commit;
359
0
  size_t page_faults;
360
0
  mi_process_info(&elapsed, &user_time, &sys_time, &current_rss, &peak_rss, &current_commit, &peak_commit, &page_faults);
361
0
  _mi_fprintf(out, arg, "%10s: %5ld.%03ld s\n", "elapsed", elapsed/1000, elapsed%1000);
362
0
  _mi_fprintf(out, arg, "%10s: user: %ld.%03ld s, system: %ld.%03ld s, faults: %lu, rss: ", "process",
363
0
              user_time/1000, user_time%1000, sys_time/1000, sys_time%1000, (unsigned long)page_faults );
364
0
  mi_printf_amount((int64_t)peak_rss, 1, out, arg, "%s");
365
0
  if (peak_commit > 0) {
366
0
    _mi_fprintf(out, arg, ", commit: ");
367
0
    mi_printf_amount((int64_t)peak_commit, 1, out, arg, "%s");
368
0
  }
369
0
  _mi_fprintf(out, arg, "\n");
370
0
}
371
372
static mi_msecs_t mi_process_start; // = 0
373
374
16
static mi_stats_t* mi_stats_get_default(void) {
375
16
  mi_heap_t* heap = mi_heap_get_default();
376
16
  return &heap->tld->stats;
377
16
}
378
379
0
static void mi_stats_merge_from(mi_stats_t* stats) {
380
0
  if (stats != &_mi_stats_main) {
381
0
    mi_stats_add(&_mi_stats_main, stats);
382
0
    memset(stats, 0, sizeof(mi_stats_t));
383
0
  }
384
0
}
385
386
16
void mi_stats_reset(void) mi_attr_noexcept {
387
16
  mi_stats_t* stats = mi_stats_get_default();
388
16
  if (stats != &_mi_stats_main) { memset(stats, 0, sizeof(mi_stats_t)); }
389
16
  memset(&_mi_stats_main, 0, sizeof(mi_stats_t));
390
16
  if (mi_process_start == 0) { mi_process_start = _mi_clock_start(); };
391
16
}
392
393
0
void mi_stats_merge(void) mi_attr_noexcept {
394
0
  mi_stats_merge_from( mi_stats_get_default() );
395
0
}
396
397
0
void _mi_stats_done(mi_stats_t* stats) {  // called from `mi_thread_done`
398
0
  mi_stats_merge_from(stats);
399
0
}
400
401
0
void mi_stats_print_out(mi_output_fun* out, void* arg) mi_attr_noexcept {
402
0
  mi_stats_merge_from(mi_stats_get_default());
403
0
  _mi_stats_print(&_mi_stats_main, out, arg);
404
0
}
405
406
0
void mi_stats_print(void* out) mi_attr_noexcept {
407
  // for compatibility there is an `out` parameter (which can be `stdout` or `stderr`)
408
0
  mi_stats_print_out((mi_output_fun*)out, NULL);
409
0
}
410
411
0
void mi_thread_stats_print_out(mi_output_fun* out, void* arg) mi_attr_noexcept {
412
0
  _mi_stats_print(mi_stats_get_default(), out, arg);
413
0
}
414
415
416
// ----------------------------------------------------------------
417
// Basic timer for convenience; use milli-seconds to avoid doubles
418
// ----------------------------------------------------------------
419
420
static mi_msecs_t mi_clock_diff;
421
422
48
mi_msecs_t _mi_clock_now(void) {
423
48
  return _mi_prim_clock_now();
424
48
}
425
426
16
mi_msecs_t _mi_clock_start(void) {
427
16
  if (mi_clock_diff == 0.0) {
428
16
    mi_msecs_t t0 = _mi_clock_now();
429
16
    mi_clock_diff = _mi_clock_now() - t0;
430
16
  }
431
16
  return _mi_clock_now();
432
16
}
433
434
0
mi_msecs_t _mi_clock_end(mi_msecs_t start) {
435
0
  mi_msecs_t end = _mi_clock_now();
436
0
  return (end - start - mi_clock_diff);
437
0
}
438
439
440
// --------------------------------------------------------
441
// Basic process statistics
442
// --------------------------------------------------------
443
444
mi_decl_export void mi_process_info(size_t* elapsed_msecs, size_t* user_msecs, size_t* system_msecs, size_t* current_rss, size_t* peak_rss, size_t* current_commit, size_t* peak_commit, size_t* page_faults) mi_attr_noexcept
445
0
{
446
0
  mi_process_info_t pinfo;
447
0
  _mi_memzero_var(pinfo);
448
0
  pinfo.elapsed        = _mi_clock_end(mi_process_start);
449
0
  pinfo.current_commit = (size_t)(mi_atomic_loadi64_relaxed((_Atomic(int64_t)*)&_mi_stats_main.committed.current));
450
0
  pinfo.peak_commit    = (size_t)(mi_atomic_loadi64_relaxed((_Atomic(int64_t)*)&_mi_stats_main.committed.peak));
451
0
  pinfo.current_rss    = pinfo.current_commit;
452
0
  pinfo.peak_rss       = pinfo.peak_commit;
453
0
  pinfo.utime          = 0;
454
0
  pinfo.stime          = 0;
455
0
  pinfo.page_faults    = 0;
456
457
0
  _mi_prim_process_info(&pinfo);
458
459
0
  if (elapsed_msecs!=NULL)  *elapsed_msecs  = (pinfo.elapsed < 0 ? 0 : (pinfo.elapsed < (mi_msecs_t)PTRDIFF_MAX ? (size_t)pinfo.elapsed : PTRDIFF_MAX));
460
0
  if (user_msecs!=NULL)     *user_msecs     = (pinfo.utime < 0 ? 0 : (pinfo.utime < (mi_msecs_t)PTRDIFF_MAX ? (size_t)pinfo.utime : PTRDIFF_MAX));
461
0
  if (system_msecs!=NULL)   *system_msecs   = (pinfo.stime < 0 ? 0 : (pinfo.stime < (mi_msecs_t)PTRDIFF_MAX ? (size_t)pinfo.stime : PTRDIFF_MAX));
462
0
  if (current_rss!=NULL)    *current_rss    = pinfo.current_rss;
463
0
  if (peak_rss!=NULL)       *peak_rss       = pinfo.peak_rss;
464
0
  if (current_commit!=NULL) *current_commit = pinfo.current_commit;
465
0
  if (peak_commit!=NULL)    *peak_commit    = pinfo.peak_commit;
466
0
  if (page_faults!=NULL)    *page_faults    = pinfo.page_faults;
467
0
}