Coverage Report

Created: 2026-03-13 03:47

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
#include "common/compile_check_begin.h"
35
36
class JemallocControl {
37
public:
38
0
    static inline int64_t get_tc_metrics(const std::string& name) {
39
0
#if !defined(__SANITIZE_ADDRESS__) && !defined(ADDRESS_SANITIZER) && !defined(LEAK_SANITIZER) && \
40
0
        !defined(THREAD_SANITIZER) && !defined(USE_JEMALLOC)
41
0
        size_t value = 0;
42
0
        MallocExtension::instance()->GetNumericProperty(name.c_str(), &value);
43
0
        return value;
44
0
#endif
45
0
        return 0;
46
0
    }
47
48
    template <typename T>
49
    static inline T get_jemallctl_value(const std::string& name) {
50
#ifdef USE_JEMALLOC
51
        T value;
52
        size_t value_size = sizeof(T);
53
        if (jemallctl(name.c_str(), &value, &value_size, nullptr, 0) != 0) {
54
            LOG(WARNING) << fmt::format("Failed, jemallctl get {}", name);
55
        }
56
        return value;
57
#endif
58
        return 0;
59
    }
60
61
    template <typename T>
62
    static inline void set_jemallctl_value(const std::string& name, T value) {
63
#ifdef USE_JEMALLOC
64
        T old_value;
65
        size_t old_value_size = sizeof(T);
66
        try {
67
            int err = jemallctl(name.c_str(), &old_value, &old_value_size,
68
                                reinterpret_cast<void*>(&value), sizeof(T));
69
            if (err) {
70
                LOG(WARNING) << fmt::format("Failed, jemallctl value for {} set to {} (old {})",
71
                                            name, value, old_value);
72
            }
73
        } catch (...) {
74
            LOG(WARNING) << fmt::format("Exception, jemallctl value for {} set to {} (old {})",
75
                                        name, value, old_value);
76
        }
77
#endif
78
    }
79
80
    static void action_jemallctl(const std::string& name);
81
    static int64_t get_je_all_arena_metrics(const std::string& name);
82
    static int64_t get_je_all_arena_extents_metrics(int64_t page_size_index,
83
                                                    const std::string& extent_type);
84
    static void je_purge_all_arena_dirty_pages();
85
    static void je_reset_all_arena_dirty_decay_ms(ssize_t dirty_decay_ms);
86
    static void je_decay_all_arena_dirty_pages();
87
    // the limit of `tcache` is the number of pages, not the total number of page bytes.
88
    // `tcache` has two cleaning opportunities: 1. the number of memory alloc and releases reaches a certain number,
89
    // recycle pages that has not been used for a long time; 2. recycle all `tcache` when the thread exits.
90
    // here add a total size limit.
91
    // only free the thread cache of the current thread, which will be fast.
92
    static void je_thread_tcache_flush();
93
94
    // Tcmalloc property `generic.total_physical_bytes` records the total length of the virtual memory
95
    // obtained by the process malloc, not the physical memory actually used by the process in the OS.
96
    static void refresh_allocator_mem();
97
98
98.4k
    static inline size_t je_cache_bytes() {
99
98.4k
        return je_cache_bytes_.load(std::memory_order_relaxed);
100
98.4k
    }
101
0
    static inline size_t je_tcache_mem() { return je_tcache_mem_.load(std::memory_order_relaxed); }
102
98.4k
    static inline size_t je_metadata_mem() {
103
98.4k
        return je_metadata_mem_.load(std::memory_order_relaxed);
104
98.4k
    }
105
97.7k
    static inline int64_t je_dirty_pages_mem() {
106
97.7k
        return je_dirty_pages_mem_.load(std::memory_order_relaxed);
107
97.7k
    }
108
97.7k
    static inline size_t je_virtual_memory_used() {
109
97.7k
        return je_virtual_memory_used_.load(std::memory_order_relaxed);
110
97.7k
    }
111
112
    static std::mutex je_purge_dirty_pages_lock;
113
    static std::atomic<bool> je_purge_dirty_pages_notify;
114
357
    static void notify_je_purge_dirty_pages() {
115
357
        je_purge_dirty_pages_notify.store(true, std::memory_order_relaxed);
116
357
    }
117
118
    static std::mutex je_reset_dirty_decay_lock;
119
    static std::atomic<bool> je_enable_dirty_page;
120
    static std::condition_variable je_reset_dirty_decay_cv;
121
    static std::atomic<bool> je_reset_dirty_decay_notify;
122
0
    static void notify_je_reset_dirty_decay() {
123
0
        je_reset_dirty_decay_notify.store(true, std::memory_order_relaxed);
124
0
        je_reset_dirty_decay_cv.notify_all();
125
0
    }
126
127
private:
128
    static std::atomic<int64_t> je_cache_bytes_;
129
    static std::atomic<int64_t> je_tcache_mem_;
130
    static std::atomic<int64_t> je_metadata_mem_;
131
    static std::atomic<int64_t> je_dirty_pages_mem_;
132
    static std::atomic<int64_t> je_virtual_memory_used_;
133
};
134
135
#include "common/compile_check_end.h"
136
} // namespace doris