blob: 212cb757f011cff1bde4d73562869a9a7d1e8d47 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#pragma once
#include <condition_variable>
#include <string>
#include "common/logging.h"
#ifdef USE_JEMALLOC
#include "jemalloc/jemalloc.h"
#endif
#if !defined(__SANITIZE_ADDRESS__) && !defined(ADDRESS_SANITIZER) && !defined(LEAK_SANITIZER) && \
!defined(THREAD_SANITIZER) && !defined(USE_JEMALLOC)
#include <gperftools/malloc_extension.h>
#endif
namespace doris {
class JemallocControl {
public:
static inline int64_t get_tc_metrics(const std::string& name) {
#if !defined(__SANITIZE_ADDRESS__) && !defined(ADDRESS_SANITIZER) && !defined(LEAK_SANITIZER) && \
!defined(THREAD_SANITIZER) && !defined(USE_JEMALLOC)
size_t value = 0;
MallocExtension::instance()->GetNumericProperty(name.c_str(), &value);
return value;
#endif
return 0;
}
template <typename T>
static inline T get_jemallctl_value(const std::string& name) {
#ifdef USE_JEMALLOC
T value;
size_t value_size = sizeof(T);
if (jemallctl(name.c_str(), &value, &value_size, nullptr, 0) != 0) {
LOG(WARNING) << fmt::format("Failed, jemallctl get {}", name);
}
return value;
#endif
return 0;
}
template <typename T>
static inline void set_jemallctl_value(const std::string& name, T value) {
#ifdef USE_JEMALLOC
T old_value;
size_t old_value_size = sizeof(T);
try {
int err = jemallctl(name.c_str(), &old_value, &old_value_size,
reinterpret_cast<void*>(&value), sizeof(T));
if (err) {
LOG(WARNING) << fmt::format("Failed, jemallctl value for {} set to {} (old {})",
name, value, old_value);
}
} catch (...) {
LOG(WARNING) << fmt::format("Exception, jemallctl value for {} set to {} (old {})",
name, value, old_value);
}
#endif
}
static void action_jemallctl(const std::string& name);
static int64_t get_je_all_arena_metrics(const std::string& name);
static int64_t get_je_all_arena_extents_metrics(int64_t page_size_index,
const std::string& extent_type);
static void je_purge_all_arena_dirty_pages();
static void je_reset_all_arena_dirty_decay_ms(ssize_t dirty_decay_ms);
static void je_decay_all_arena_dirty_pages();
// the limit of `tcache` is the number of pages, not the total number of page bytes.
// `tcache` has two cleaning opportunities: 1. the number of memory alloc and releases reaches a certain number,
// recycle pages that has not been used for a long time; 2. recycle all `tcache` when the thread exits.
// here add a total size limit.
// only free the thread cache of the current thread, which will be fast.
static void je_thread_tcache_flush();
// Tcmalloc property `generic.total_physical_bytes` records the total length of the virtual memory
// obtained by the process malloc, not the physical memory actually used by the process in the OS.
static void refresh_allocator_mem();
static inline size_t je_cache_bytes() {
return je_cache_bytes_.load(std::memory_order_relaxed);
}
static inline size_t je_tcache_mem() { return je_tcache_mem_.load(std::memory_order_relaxed); }
static inline size_t je_metadata_mem() {
return je_metadata_mem_.load(std::memory_order_relaxed);
}
static inline int64_t je_dirty_pages_mem() {
return je_dirty_pages_mem_.load(std::memory_order_relaxed);
}
static inline size_t je_virtual_memory_used() {
return je_virtual_memory_used_.load(std::memory_order_relaxed);
}
static std::mutex je_purge_dirty_pages_lock;
static std::atomic<bool> je_purge_dirty_pages_notify;
static void notify_je_purge_dirty_pages() {
je_purge_dirty_pages_notify.store(true, std::memory_order_relaxed);
}
static std::mutex je_reset_dirty_decay_lock;
static std::atomic<bool> je_enable_dirty_page;
static std::condition_variable je_reset_dirty_decay_cv;
static std::atomic<bool> je_reset_dirty_decay_notify;
static void notify_je_reset_dirty_decay() {
je_reset_dirty_decay_notify.store(true, std::memory_order_relaxed);
je_reset_dirty_decay_cv.notify_all();
}
private:
static std::atomic<int64_t> je_cache_bytes_;
static std::atomic<int64_t> je_tcache_mem_;
static std::atomic<int64_t> je_metadata_mem_;
static std::atomic<int64_t> je_dirty_pages_mem_;
static std::atomic<int64_t> je_virtual_memory_used_;
};
} // namespace doris