Skip to content
This repository has been archived by the owner on Jun 23, 2022. It is now read-only.

feat: supporting release all tcmalloc reserved but not used memory #864

Merged
merged 3 commits into from
Jul 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 30 additions & 7 deletions src/replica/replica_stub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,11 @@ replica_stub::replica_stub(replica_state_subscriber subscriber /*= nullptr*/,
_is_running(false)
{
#ifdef DSN_ENABLE_GPERF
_is_releasing_memory = false;
_release_tcmalloc_memory_command = nullptr;
_get_tcmalloc_status_command = nullptr;
_max_reserved_memory_percentage_command = nullptr;
_release_all_reserved_memory_command = nullptr;
#endif
_replica_state_subscriber = subscriber;
_is_long_subscriber = is_long_subscriber;
Expand Down Expand Up @@ -832,7 +834,7 @@ void replica_stub::initialize_start()
_mem_release_timer_task =
tasking::enqueue_timer(LPC_MEM_RELEASE,
&_tracker,
std::bind(&replica_stub::gc_tcmalloc_memory, this),
std::bind(&replica_stub::gc_tcmalloc_memory, this, false),
std::chrono::milliseconds(_options.mem_release_check_interval_ms),
0,
std::chrono::milliseconds(_options.mem_release_check_interval_ms));
Expand Down Expand Up @@ -2311,8 +2313,8 @@ void replica_stub::register_ctrl_command()

_get_tcmalloc_status_command = ::dsn::command_manager::instance().register_command(
{"replica.get-tcmalloc-status"},
"replica.get-tcmalloc-status",
"replica.get-tcmalloc-status - get status of tcmalloc",
"get status of tcmalloc",
[](const std::vector<std::string> &args) {
char buf[4096];
MallocExtension::instance()->GetStats(buf, 4096);
Expand Down Expand Up @@ -2345,6 +2347,15 @@ void replica_stub::register_ctrl_command()
}
return result;
});

_release_all_reserved_memory_command = ::dsn::command_manager::instance().register_command(
{"replica.release-all-reserved-memory"},
"replica.release-all-reserved-memory - release tcmalloc all reserved-not-used memory",
"release tcmalloc all reserverd not-used memory back to operating system",
[this](const std::vector<std::string> &args) {
auto release_bytes = gc_tcmalloc_memory(true);
return "OK, release_bytes=" + std::to_string(release_bytes);
});
#endif
_max_concurrent_bulk_load_downloading_count_command =
dsn::command_manager::instance().register_command(
Expand Down Expand Up @@ -2506,6 +2517,7 @@ void replica_stub::close()
UNREGISTER_VALID_HANDLER(_release_tcmalloc_memory_command);
UNREGISTER_VALID_HANDLER(_get_tcmalloc_status_command);
UNREGISTER_VALID_HANDLER(_max_reserved_memory_percentage_command);
UNREGISTER_VALID_HANDLER(_release_all_reserved_memory_command);
#endif
UNREGISTER_VALID_HANDLER(_max_concurrent_bulk_load_downloading_count_command);

Expand All @@ -2520,6 +2532,7 @@ void replica_stub::close()
_release_tcmalloc_memory_command = nullptr;
_get_tcmalloc_status_command = nullptr;
_max_reserved_memory_percentage_command = nullptr;
_release_all_reserved_memory_command = nullptr;
#endif
_max_concurrent_bulk_load_downloading_count_command = nullptr;

Expand Down Expand Up @@ -2648,23 +2661,31 @@ static int64_t get_tcmalloc_numeric_property(const char *prop)
return value;
}

void replica_stub::gc_tcmalloc_memory()
uint64_t replica_stub::gc_tcmalloc_memory(bool release_all)
{
int64_t tcmalloc_released_bytes = 0;
auto tcmalloc_released_bytes = 0;
if (!_release_tcmalloc_memory) {
_is_releasing_memory.store(false);
_counter_tcmalloc_release_memory_size->set(tcmalloc_released_bytes);
return;
return tcmalloc_released_bytes;
}

if (_is_releasing_memory.load()) {
dwarn_f("This node is releasing memory...");
return tcmalloc_released_bytes;
}

_is_releasing_memory.store(true);
int64_t total_allocated_bytes =
get_tcmalloc_numeric_property("generic.current_allocated_bytes");
int64_t reserved_bytes = get_tcmalloc_numeric_property("tcmalloc.pageheap_free_bytes");
if (total_allocated_bytes == -1 || reserved_bytes == -1) {
return;
return tcmalloc_released_bytes;
}

int64_t max_reserved_bytes =
total_allocated_bytes * _mem_release_max_reserved_mem_percentage / 100.0;
release_all ? 0
: (total_allocated_bytes * _mem_release_max_reserved_mem_percentage / 100.0);
if (reserved_bytes > max_reserved_bytes) {
int64_t release_bytes = reserved_bytes - max_reserved_bytes;
tcmalloc_released_bytes = release_bytes;
Expand All @@ -2677,6 +2698,8 @@ void replica_stub::gc_tcmalloc_memory()
}
}
_counter_tcmalloc_release_memory_size->set(tcmalloc_released_bytes);
_is_releasing_memory.store(false);
return tcmalloc_released_bytes;
}
#endif

Expand Down
8 changes: 7 additions & 1 deletion src/replica/replica_stub.h
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,8 @@ class replica_stub : public serverlet<replica_stub>, public ref_counter

#ifdef DSN_ENABLE_GPERF
// Try to release tcmalloc memory back to operating system
void gc_tcmalloc_memory();
// If release_all = true, it will release all reserved-not-used memory
uint64_t gc_tcmalloc_memory(bool release_all);
#endif

private:
Expand Down Expand Up @@ -370,6 +371,7 @@ class replica_stub : public serverlet<replica_stub>, public ref_counter
dsn_handle_t _release_tcmalloc_memory_command;
dsn_handle_t _get_tcmalloc_status_command;
dsn_handle_t _max_reserved_memory_percentage_command;
dsn_handle_t _release_all_reserved_memory_command;
#endif
dsn_handle_t _max_concurrent_bulk_load_downloading_count_command;

Expand Down Expand Up @@ -402,6 +404,10 @@ class replica_stub : public serverlet<replica_stub>, public ref_counter

bool _is_running;

#ifdef DSN_ENABLE_GPERF
std::atomic_bool _is_releasing_memory{false};
#endif

// performance counters
perf_counter_wrapper _counter_replicas_count;
perf_counter_wrapper _counter_replicas_opening_count;
Expand Down