Coverage Report

Created: 2026-03-31 07:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/duckdb/extension/jemalloc/jemalloc_extension.cpp
Line
Count
Source
1
#include "jemalloc_extension.hpp"
2
3
#include "duckdb/common/allocator.hpp"
4
#include "jemalloc/jemalloc.h"
5
#include "malloc_ncpus.h"
6
7
#include <thread>
8
9
namespace duckdb {
10
11
8.91k
static void LoadInternal(ExtensionLoader &) {
12
  // NOP: This extension can only be loaded statically
13
8.91k
}
14
8.91k
void JemallocExtension::Load(ExtensionLoader &loader) {
15
8.91k
  LoadInternal(loader);
16
8.91k
}
17
18
8.91k
std::string JemallocExtension::Name() {
19
8.91k
  return "jemalloc";
20
8.91k
}
21
22
0
data_ptr_t JemallocExtension::Allocate(PrivateAllocatorData *private_data, idx_t size) {
23
0
  return data_ptr_cast(duckdb_je_malloc(size));
24
0
}
25
26
0
void JemallocExtension::Free(PrivateAllocatorData *private_data, data_ptr_t pointer, idx_t size) {
27
0
  duckdb_je_free(pointer);
28
0
}
29
30
data_ptr_t JemallocExtension::Reallocate(PrivateAllocatorData *private_data, data_ptr_t pointer, idx_t old_size,
31
0
                                         idx_t size) {
32
0
  return data_ptr_cast(duckdb_je_realloc(pointer, size));
33
0
}
34
35
0
static void JemallocCTL(const char *name, void *old_ptr, size_t *old_len, void *new_ptr, size_t new_len) {
36
0
  if (duckdb_je_mallctl(name, old_ptr, old_len, new_ptr, new_len) != 0) {
37
#ifdef DEBUG
38
    // We only want to throw an exception here when debugging
39
    throw InternalException("je_mallctl failed for setting \"%s\"", name);
40
#endif
41
0
  }
42
0
}
43
44
template <class T>
45
0
static void SetJemallocCTL(const char *name, T &val) {
46
0
  JemallocCTL(name, nullptr, nullptr, &val, sizeof(T));
47
0
}
48
49
0
static void SetJemallocCTL(const char *name) {
50
0
  JemallocCTL(name, nullptr, nullptr, nullptr, 0);
51
0
}
52
53
template <class T>
54
0
static T GetJemallocCTL(const char *name) {
55
0
  T result;
56
0
  size_t len = sizeof(T);
57
0
  JemallocCTL(name, &result, &len, nullptr, 0);
58
0
  return result;
59
0
}
Unexecuted instantiation: jemalloc_extension.cpp:unsigned long duckdb::GetJemallocCTL<unsigned long>(char const*)
Unexecuted instantiation: jemalloc_extension.cpp:unsigned int duckdb::GetJemallocCTL<unsigned int>(char const*)
60
61
0
static inline string PurgeArenaString(idx_t arena_idx) {
62
0
  return StringUtil::Format("arena.%llu.purge", arena_idx);
63
0
}
64
65
0
int64_t JemallocExtension::DecayDelay() {
66
0
  return DUCKDB_JEMALLOC_DECAY;
67
0
}
68
69
0
void JemallocExtension::ThreadFlush(idx_t threshold) {
70
  // We flush after exceeding the threshold
71
0
  if (GetJemallocCTL<uint64_t>("thread.peak.read") > threshold) {
72
0
    return;
73
0
  }
74
75
  // Flush thread-local cache
76
0
  SetJemallocCTL("thread.tcache.flush");
77
78
  // Flush this thread's arena
79
0
  const auto purge_arena = PurgeArenaString(idx_t(GetJemallocCTL<unsigned>("thread.arena")));
80
0
  SetJemallocCTL(purge_arena.c_str());
81
82
  // Reset the peak after resetting
83
0
  SetJemallocCTL("thread.peak.reset");
84
0
}
85
86
0
void JemallocExtension::ThreadIdle() {
87
  // Indicate that this thread is idle
88
0
  SetJemallocCTL("thread.idle");
89
90
  // Reset the peak after resetting
91
0
  SetJemallocCTL("thread.peak.reset");
92
0
}
93
94
0
void JemallocExtension::FlushAll() {
95
  // Flush thread-local cache
96
0
  SetJemallocCTL("thread.tcache.flush");
97
98
  // Flush all arenas
99
0
  const auto purge_arena = PurgeArenaString(MALLCTL_ARENAS_ALL);
100
0
  SetJemallocCTL(purge_arena.c_str());
101
102
  // Reset the peak after resetting
103
0
  SetJemallocCTL("thread.peak.reset");
104
0
}
105
106
0
void JemallocExtension::SetBackgroundThreads(bool enable) {
107
0
#ifndef __APPLE__
108
0
  SetJemallocCTL("background_thread", enable);
109
0
#endif
110
0
}
111
112
8.91k
std::string JemallocExtension::Version() const {
113
8.91k
#ifdef EXT_VERSION_JEMALLOC
114
8.91k
  return EXT_VERSION_JEMALLOC;
115
#else
116
  return "";
117
#endif
118
8.91k
}
119
120
} // namespace duckdb
121
122
extern "C" {
123
124
0
unsigned duckdb_malloc_ncpus() {
125
#ifdef DUCKDB_NO_THREADS
126
  return 1
127
#else
128
0
  unsigned concurrency = duckdb::NumericCast<unsigned>(std::thread::hardware_concurrency());
129
0
  return std::max(concurrency, 1u);
130
0
#endif
131
0
}
132
133
0
DUCKDB_CPP_EXTENSION_ENTRY(jemalloc, loader) {
134
0
  duckdb::LoadInternal(loader);
135
0
}
136
}