-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmemprof_stat.cpp
166 lines (138 loc) · 4.1 KB
/
memprof_stat.cpp
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
//
// Copyright Aliaksei Levin ([email protected]), Arseny Smirnov ([email protected]) 2014-2023
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include "memprof/memprof_stat.h"
#include "td/utils/port/platform.h"
#if (TD_DARWIN || TD_LINUX)
#include <algorithm>
#include <atomic>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <new>
#include <utility>
#include <vector>
#include <dlfcn.h>
#include <execinfo.h>
bool is_memprof_on() {
return true;
}
#define my_assert(f) \
if (!(f)) { \
std::abort(); \
}
struct malloc_info {
std::int32_t magic;
std::int32_t size;
};
static std::atomic<std::size_t> total_memory_used;
void register_xalloc(malloc_info *info, std::int32_t diff) {
my_assert(info->size >= 0);
// TODO: this is very slow in case of several threads.
// Currently this statistics is intended only for memory benchmarks.
total_memory_used.fetch_add(diff * info->size, std::memory_order_relaxed);
}
std::size_t get_used_memory_size() {
return total_memory_used.load();
}
extern "C" {
static constexpr std::size_t RESERVED_SIZE = 16;
static constexpr std::int32_t MALLOC_INFO_MAGIC = 0x27138373;
static void *do_malloc(std::size_t size) {
static_assert(RESERVED_SIZE % alignof(std::max_align_t) == 0, "fail");
static_assert(RESERVED_SIZE >= sizeof(malloc_info), "fail");
#if TD_DARWIN
static void *malloc_void = dlsym(RTLD_NEXT, "malloc");
static auto malloc_old = *reinterpret_cast<decltype(malloc) **>(&malloc_void);
#else
extern decltype(malloc) __libc_malloc;
static auto malloc_old = __libc_malloc;
#endif
auto *info = static_cast<malloc_info *>(malloc_old(size + RESERVED_SIZE));
auto *buf = reinterpret_cast<char *>(info);
info->magic = MALLOC_INFO_MAGIC;
info->size = static_cast<std::int32_t>(size);
register_xalloc(info, +1);
void *data = buf + RESERVED_SIZE;
return data;
}
static malloc_info *get_info(void *data_void) {
auto *data = static_cast<char *>(data_void);
auto *buf = data - RESERVED_SIZE;
auto *info = reinterpret_cast<malloc_info *>(buf);
my_assert(info->magic == MALLOC_INFO_MAGIC);
return info;
}
void *malloc(std::size_t size) {
return do_malloc(size);
}
void free(void *data_void) {
if (data_void == nullptr) {
return;
}
auto *info = get_info(data_void);
register_xalloc(info, -1);
#if TD_DARWIN
static void *free_void = dlsym(RTLD_NEXT, "free");
static auto free_old = *reinterpret_cast<decltype(free) **>(&free_void);
#else
extern decltype(free) __libc_free;
static auto free_old = __libc_free;
#endif
return free_old(info);
}
void *calloc(std::size_t size_a, std::size_t size_b) {
auto size = size_a * size_b;
void *res = do_malloc(size);
std::memset(res, 0, size);
return res;
}
void *realloc(void *ptr, std::size_t size) {
if (ptr == nullptr) {
return do_malloc(size);
}
auto *info = get_info(ptr);
auto *new_ptr = do_malloc(size);
auto to_copy = std::min(static_cast<std::int32_t>(size), info->size);
std::memcpy(new_ptr, ptr, to_copy);
free(ptr);
return new_ptr;
}
void *memalign(std::size_t alignment, std::size_t size) {
auto res = malloc(size);
my_assert(reinterpret_cast<std::uintptr_t>(res) % alignment == 0);
return res;
}
int posix_memalign(void **memptr, size_t alignment, size_t size) {
auto res = malloc(size);
my_assert(reinterpret_cast<std::uintptr_t>(res) % alignment == 0);
*memptr = res;
return 0;
}
}
// c++14 guarantees that it is enough to override these two operators.
void *operator new(std::size_t count) {
return do_malloc(count);
}
void operator delete(void *ptr) noexcept(true) {
free(ptr);
}
// because of gcc warning: the program should also define 'void operator delete(void*, std::size_t)'
void operator delete(void *ptr, std::size_t) noexcept(true) {
free(ptr);
}
// c++17
// void *operator new(std::size_t count, std::align_val_t al);
// void operator delete(void *ptr, std::align_val_t al);
#else
bool is_memprof_on() {
return false;
}
std::size_t get_used_memory_size() {
return 0;
}
#endif