Coverage Report

Created: 2026-04-10 04:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/runtime/memory/jemalloc_control.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#pragma once
19
20
#include <condition_variable>
21
#include <string>
22
23
#include "common/logging.h"
24
25
#ifdef USE_JEMALLOC
26
#include "jemalloc/jemalloc.h"
27
#endif
28
#if !defined(__SANITIZE_ADDRESS__) && !defined(ADDRESS_SANITIZER) && !defined(LEAK_SANITIZER) && \
29
        !defined(THREAD_SANITIZER) && !defined(USE_JEMALLOC)
30
#include <gperftools/malloc_extension.h>
31
#endif
32
33
namespace doris {
34
35
class JemallocControl {
36
public:
37
0
    static inline int64_t get_tc_metrics(const std::string& name) {
38
0
#if !defined(__SANITIZE_ADDRESS__) && !defined(ADDRESS_SANITIZER) && !defined(LEAK_SANITIZER) && \
39
0
        !defined(THREAD_SANITIZER) && !defined(USE_JEMALLOC)
40
0
        size_t value = 0;
41
0
        MallocExtension::instance()->GetNumericProperty(name.c_str(), &value);
42
0
        return value;
43
0
#endif
44
0
        return 0;
45
0
    }
46
47
    template <typename T>
48
    static inline T get_jemallctl_value(const std::string& name) {
49
#ifdef USE_JEMALLOC
50
        T value;
51
        size_t value_size = sizeof(T);
52
        if (jemallctl(name.c_str(), &value, &value_size, nullptr, 0) != 0) {
53
            LOG(WARNING) << fmt::format("Failed, jemallctl get {}", name);
54
        }
55
        return value;
56
#endif
57
        return 0;
58
    }
59
60
    template <typename T>
61
    static inline void set_jemallctl_value(const std::string& name, T value) {
62
#ifdef USE_JEMALLOC
63
        T old_value;
64
        size_t old_value_size = sizeof(T);
65
        try {
66
            int err = jemallctl(name.c_str(), &old_value, &old_value_size,
67
                                reinterpret_cast<void*>(&value), sizeof(T));
68
            if (err) {
69
                LOG(WARNING) << fmt::format("Failed, jemallctl value for {} set to {} (old {})",
70
                                            name, value, old_value);
71
            }
72
        } catch (...) {
73
            LOG(WARNING) << fmt::format("Exception, jemallctl value for {} set to {} (old {})",
74
                                        name, value, old_value);
75
        }
76
#endif
77
    }
78
79
    static void action_jemallctl(const std::string& name);
80
    static int64_t get_je_all_arena_metrics(const std::string& name);
81
    static int64_t get_je_all_arena_extents_metrics(int64_t page_size_index,
82
                                                    const std::string& extent_type);
83
    static void je_purge_all_arena_dirty_pages();
84
    static void je_reset_all_arena_dirty_decay_ms(ssize_t dirty_decay_ms);
85
    static void je_decay_all_arena_dirty_pages();
86
    // the limit of `tcache` is the number of pages, not the total number of page bytes.
87
    // `tcache` has two cleaning opportunities: 1. the number of memory alloc and releases reaches a certain number,
88
    // recycle pages that has not been used for a long time; 2. recycle all `tcache` when the thread exits.
89
    // here add a total size limit.
90
    // only free the thread cache of the current thread, which will be fast.
91
    static void je_thread_tcache_flush();
92
93
    // Tcmalloc property `generic.total_physical_bytes` records the total length of the virtual memory
94
    // obtained by the process malloc, not the physical memory actually used by the process in the OS.
95
    static void refresh_allocator_mem();
96
97
95.1k
    static inline size_t je_cache_bytes() {
98
95.1k
        return je_cache_bytes_.load(std::memory_order_relaxed);
99
95.1k
    }
100
0
    static inline size_t je_tcache_mem() { return je_tcache_mem_.load(std::memory_order_relaxed); }
101
95.1k
    static inline size_t je_metadata_mem() {
102
95.1k
        return je_metadata_mem_.load(std::memory_order_relaxed);
103
95.1k
    }
104
94.3k
    static inline int64_t je_dirty_pages_mem() {
105
94.3k
        return je_dirty_pages_mem_.load(std::memory_order_relaxed);
106
94.3k
    }
107
94.3k
    static inline size_t je_virtual_memory_used() {
108
94.3k
        return je_virtual_memory_used_.load(std::memory_order_relaxed);
109
94.3k
    }
110
111
    static std::mutex je_purge_dirty_pages_lock;
112
    static std::atomic<bool> je_purge_dirty_pages_notify;
113
400
    static void notify_je_purge_dirty_pages() {
114
400
        je_purge_dirty_pages_notify.store(true, std::memory_order_relaxed);
115
400
    }
116
117
    static std::mutex je_reset_dirty_decay_lock;
118
    static std::atomic<bool> je_enable_dirty_page;
119
    static std::condition_variable je_reset_dirty_decay_cv;
120
    static std::atomic<bool> je_reset_dirty_decay_notify;
121
0
    static void notify_je_reset_dirty_decay() {
122
0
        je_reset_dirty_decay_notify.store(true, std::memory_order_relaxed);
123
0
        je_reset_dirty_decay_cv.notify_all();
124
0
    }
125
126
private:
127
    static std::atomic<int64_t> je_cache_bytes_;
128
    static std::atomic<int64_t> je_tcache_mem_;
129
    static std::atomic<int64_t> je_metadata_mem_;
130
    static std::atomic<int64_t> je_dirty_pages_mem_;
131
    static std::atomic<int64_t> je_virtual_memory_used_;
132
};
133
134
} // namespace doris