1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
#include <iostream>
#include <dlfcn.h>
#include "HLTrigger/Timer/interface/memory_usage.h"
// see <jemalloc/jemalloc.h>
extern "C" {
typedef int (*mallctl_t)(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
typedef int (*mallctlnametomib_t)(const char *name, size_t *mibp, size_t *miblenp);
typedef int (*mallctlbymib_t)(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
}
namespace {
bool initialise();
bool initialise_peak();
const uint64_t *initialise_thread_allocated_p();
const uint64_t *initialise_thread_deallocated_p();
const uint64_t zero = 0UL;
size_t mib_peak_read[3]; // management information base for "thread.peak.read"
size_t mib_peak_reset[3]; // management information base for "thread.peak.reset"
thread_local const uint64_t *thread_allocated_p = initialise_thread_allocated_p();
thread_local const uint64_t *thread_deallocated_p = initialise_thread_deallocated_p();
mallctl_t mallctl = nullptr;
mallctlnametomib_t mallctlnametomib = nullptr;
mallctlbymib_t mallctlbymib = nullptr;
const bool have_jemalloc_and_stats = initialise();
const bool have_jemalloc_and_peak = have_jemalloc_and_stats and initialise_peak();
bool initialise() {
// check if mallctl and friends are available, if we are using jemalloc
mallctl = (mallctl_t)::dlsym(RTLD_DEFAULT, "mallctl");
if (mallctl == nullptr)
return false;
mallctlnametomib = (mallctlnametomib_t)::dlsym(RTLD_DEFAULT, "mallctlnametomib");
if (mallctlnametomib == nullptr)
return false;
mallctlbymib = (mallctlbymib_t)::dlsym(RTLD_DEFAULT, "mallctlbymib");
if (mallctlbymib == nullptr)
return false;
// check if the statistics are available, if --enable-stats was specified at build time
bool enable_stats = false;
size_t bool_s = sizeof(bool);
mallctl("config.stats", &enable_stats, &bool_s, nullptr, 0);
return enable_stats;
}
bool initialise_peak() {
// check if thread.peak.read and thread.peak.reset are available
size_t miblen = 3;
if (mallctlnametomib("thread.peak.read", mib_peak_read, &miblen) != 0)
return false;
if (mallctlnametomib("thread.peak.reset", mib_peak_reset, &miblen) != 0)
return false;
return true;
}
const uint64_t *initialise_thread_allocated_p() {
const uint64_t *stats = &zero;
size_t ptr_s = sizeof(uint64_t *);
if (have_jemalloc_and_stats)
// get a pointer to the thread-specific allocation statistics
mallctl("thread.allocatedp", &stats, &ptr_s, nullptr, 0);
return stats;
}
const uint64_t *initialise_thread_deallocated_p() {
const uint64_t *stats = &zero;
size_t ptr_s = sizeof(uint64_t *);
if (have_jemalloc_and_stats)
// get a pointer to the thread-specific allocation statistics
mallctl("thread.deallocatedp", &stats, &ptr_s, nullptr, 0);
return stats;
}
} // namespace
bool memory_usage::is_available() { return have_jemalloc_and_stats; }
uint64_t memory_usage::allocated() { return *thread_allocated_p; }
uint64_t memory_usage::deallocated() { return *thread_deallocated_p; }
uint64_t memory_usage::peak() {
uint64_t peak = 0;
size_t size = sizeof(uint64_t);
if (have_jemalloc_and_peak)
mallctlbymib(mib_peak_read, 3, &peak, &size, nullptr, 0);
return peak;
}
void memory_usage::reset_peak() {
if (have_jemalloc_and_peak)
mallctlbymib(mib_peak_reset, 3, nullptr, nullptr, nullptr, 0);
}
|