内存优化
This commit is contained in:
@@ -65,6 +65,8 @@ Global::Global() : Config() {
|
||||
SSR::mode_s_logger = new BaseLogger("@/logs/mode_s", MB * size_MB * 10, piece_num);
|
||||
dsp_logger = new BaseLogger("@/logs/dsp", MB * size_MB, piece_num);
|
||||
server_logger = new BaseLogger("@/logs/server", MB * size_MB, piece_num);
|
||||
SSR::parse_pos_call_back = nullptr;
|
||||
SSR::parse_ok_json = nullptr;
|
||||
asio_socket::socket_logger->set_redirect([](const BaseLogger::Log_Info& log_info) {
|
||||
auto msg = "[" + std::string("func") + "~" + log_info.func_pattern + "] " + log_info.log_type.to_string() +
|
||||
log_info.content;
|
||||
@@ -77,9 +79,7 @@ Global::Global() : Config() {
|
||||
});
|
||||
from_base_json(&j);
|
||||
#ifdef Cache_Some_Mode_S
|
||||
auto old_parse_ok_json = SSR::parse_ok_json;
|
||||
SSR::parse_ok_json = [old_parse_ok_json](Aircraft_Info* aircraft_info, SSR::P_S mode_s_msg, Psc::JSON json) {
|
||||
old_parse_ok_json(aircraft_info, mode_s_msg, json);
|
||||
SSR::parse_ok_json = [](Aircraft_Info* aircraft_info, SSR::P_S mode_s_msg, Psc::JSON) {
|
||||
auto f = static_cast<Aircraft*>(aircraft_info);
|
||||
f->add_msg_limit(mode_s_msg);
|
||||
};
|
||||
@@ -88,7 +88,10 @@ Global::Global() : Config() {
|
||||
auto src = std::dynamic_pointer_cast<Data_Source>(msg->source);
|
||||
Mode_S_Statistic_Data* ss = &src->mode_s_statistic;
|
||||
ss->add_cpr_error(t, err_type);
|
||||
SSR::mode_s_logger->debug("CPR/" + to_string(t) + "/" + to_string(err_type), {}, log);
|
||||
if (err_type == SSR::CPR_Ret_Type::Speed_Error || err_type == SSR::CPR_Ret_Type::Inter_Error ||
|
||||
err_type == SSR::CPR_Ret_Type::Time_Space_Too_Long ||
|
||||
err_type == SSR::CPR_Ret_Type::Out_of_Maximum_Detection_Range)
|
||||
SSR::mode_s_logger->debug("CPR/" + to_string(t) + "/" + to_string(err_type), {}, log);
|
||||
};
|
||||
// 处理错误
|
||||
SSR::parse_call_back = [this](SSR::Parse_Call_Back_Type type, SSR::Aircraft_Info* info, std::string_view field_name,
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
#include "Memory_Monitor.h"
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <mimalloc.h>
|
||||
#include <sstream>
|
||||
#include "Memory_Resource.h"
|
||||
namespace {
|
||||
constexpr std::uint64_t kibibyte = 1024;
|
||||
constexpr std::uint64_t mebibyte = 1024 * kibibyte;
|
||||
constexpr std::size_t history_capacity = 600;
|
||||
constexpr std::size_t response_history_capacity = 120;
|
||||
constexpr std::uint64_t growth_warmup_ms = 10 * 60 * 1000;
|
||||
constexpr std::uint64_t growth_window_ms = 15 * 60 * 1000;
|
||||
constexpr std::uint64_t recent_growth_window_ms = 5 * 60 * 1000;
|
||||
constexpr std::uint64_t minimum_growth_window_ms = 10 * 60 * 1000;
|
||||
constexpr std::uint64_t minimum_recent_growth_window_ms = 4 * 60 * 1000;
|
||||
std::uint64_t now_milliseconds() {
|
||||
return static_cast<std::uint64_t>(std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch()).count());
|
||||
}
|
||||
std::uint64_t parse_kibibytes(std::string_view line) {
|
||||
const auto separator = line.find(':');
|
||||
if (separator == std::string_view::npos)
|
||||
return 0;
|
||||
std::uint64_t value{};
|
||||
std::istringstream stream(std::string(line.substr(separator + 1)));
|
||||
stream >> value;
|
||||
return value * kibibyte;
|
||||
}
|
||||
#if defined(ECAP_TARGET_LINUX)
|
||||
void read_linux_process_memory(Process_Memory_Snapshot& result) {
|
||||
std::ifstream stream("/proc/self/status");
|
||||
std::string line;
|
||||
while (std::getline(stream, line)) {
|
||||
if (line.starts_with("VmRSS:"))
|
||||
result.rss_bytes = parse_kibibytes(line);
|
||||
else if (line.starts_with("VmHWM:"))
|
||||
result.peak_rss_bytes = parse_kibibytes(line);
|
||||
else if (line.starts_with("RssAnon:"))
|
||||
result.anonymous_rss_bytes = parse_kibibytes(line);
|
||||
else if (line.starts_with("RssFile:"))
|
||||
result.file_rss_bytes = parse_kibibytes(line);
|
||||
else if (line.starts_with("RssShmem:"))
|
||||
result.shared_rss_bytes = parse_kibibytes(line);
|
||||
else if (line.starts_with("VmSize:"))
|
||||
result.virtual_bytes = parse_kibibytes(line);
|
||||
else if (line.starts_with("VmSwap:"))
|
||||
result.swap_bytes = parse_kibibytes(line);
|
||||
}
|
||||
}
|
||||
void read_linux_system_memory(Process_Memory_Snapshot& result) {
|
||||
std::ifstream stream("/proc/meminfo");
|
||||
std::string line;
|
||||
while (std::getline(stream, line)) {
|
||||
if (line.starts_with("MemTotal:"))
|
||||
result.system_total_bytes = parse_kibibytes(line);
|
||||
else if (line.starts_with("MemAvailable:"))
|
||||
result.system_available_bytes = parse_kibibytes(line);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
struct Growth_Trend {
|
||||
std::int64_t bytes_per_hour{};
|
||||
std::uint64_t window_ms{};
|
||||
};
|
||||
template <typename Getter>
|
||||
Growth_Trend growth_trend(const std::pmr::deque<Process_Memory_Snapshot>& history, Getter getter,
|
||||
std::uint64_t maximum_window_ms) {
|
||||
if (history.size() < 2)
|
||||
return {};
|
||||
const auto latest_timestamp = history.back().timestamp_ms;
|
||||
const auto warmup_end = history.front().timestamp_ms + growth_warmup_ms;
|
||||
if (latest_timestamp <= warmup_end)
|
||||
return {};
|
||||
const auto tail_start = latest_timestamp > maximum_window_ms ? latest_timestamp - maximum_window_ms : 0;
|
||||
const auto analysis_start = std::max(warmup_end, tail_start);
|
||||
const auto first = std::find_if(history.begin(), history.end(), [analysis_start](const auto& sample) {
|
||||
return sample.timestamp_ms >= analysis_start;
|
||||
});
|
||||
if (first == history.end() || std::next(first) == history.end())
|
||||
return {};
|
||||
const auto origin = first->timestamp_ms;
|
||||
long double sum_x = 0;
|
||||
long double sum_y = 0;
|
||||
for (auto iter = first; iter != history.end(); ++iter) {
|
||||
const auto& sample = *iter;
|
||||
sum_x += static_cast<long double>(sample.timestamp_ms - origin) / 1000.0L;
|
||||
sum_y += static_cast<long double>(getter(sample));
|
||||
}
|
||||
const auto count = static_cast<long double>(std::distance(first, history.end()));
|
||||
const auto mean_x = sum_x / count;
|
||||
const auto mean_y = sum_y / count;
|
||||
long double numerator = 0;
|
||||
long double denominator = 0;
|
||||
for (auto iter = first; iter != history.end(); ++iter) {
|
||||
const auto& sample = *iter;
|
||||
const auto x = static_cast<long double>(sample.timestamp_ms - origin) / 1000.0L - mean_x;
|
||||
const auto y = static_cast<long double>(getter(sample)) - mean_y;
|
||||
numerator += x * y;
|
||||
denominator += x * x;
|
||||
}
|
||||
if (denominator == 0)
|
||||
return {};
|
||||
return {static_cast<std::int64_t>(numerator / denominator * 3600.0L), latest_timestamp - origin};
|
||||
}
|
||||
Psc::JSON snapshot_json(const Process_Memory_Snapshot& value) {
|
||||
Psc::JSON result = Psc::JSON::object();
|
||||
result.append({"timestamp_ms", value.timestamp_ms});
|
||||
result.append({"rss_bytes", value.rss_bytes});
|
||||
result.append({"peak_rss_bytes", value.peak_rss_bytes});
|
||||
result.append({"anonymous_rss_bytes", value.anonymous_rss_bytes});
|
||||
result.append({"file_rss_bytes", value.file_rss_bytes});
|
||||
result.append({"shared_rss_bytes", value.shared_rss_bytes});
|
||||
result.append({"virtual_bytes", value.virtual_bytes});
|
||||
result.append({"swap_bytes", value.swap_bytes});
|
||||
result.append({"commit_bytes", value.commit_bytes});
|
||||
result.append({"peak_commit_bytes", value.peak_commit_bytes});
|
||||
result.append({"system_total_bytes", value.system_total_bytes});
|
||||
result.append({"system_available_bytes", value.system_available_bytes});
|
||||
result.append({"page_faults", value.page_faults});
|
||||
result.append({"allocator_live_bytes", value.allocator_live_bytes});
|
||||
result.append({"allocator_peak_live_bytes", value.allocator_peak_live_bytes});
|
||||
result.append({"pmr_live_bytes", value.pmr_live_bytes});
|
||||
result.append({"pmr_peak_live_bytes", value.pmr_peak_live_bytes});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
Memory_Monitor::Memory_Monitor() : history_(server_memory_resource()) {
|
||||
}
|
||||
Memory_Monitor& Memory_Monitor::instance() {
|
||||
static Memory_Monitor monitor;
|
||||
return monitor;
|
||||
}
|
||||
void Memory_Monitor::sample() {
|
||||
Process_Memory_Snapshot result;
|
||||
result.timestamp_ms = now_milliseconds();
|
||||
std::size_t elapsed{};
|
||||
std::size_t user{};
|
||||
std::size_t system{};
|
||||
std::size_t rss{};
|
||||
std::size_t peak_rss{};
|
||||
std::size_t commit{};
|
||||
std::size_t peak_commit{};
|
||||
std::size_t page_faults{};
|
||||
mi_process_info(&elapsed, &user, &system, &rss, &peak_rss, &commit, &peak_commit, &page_faults);
|
||||
result.rss_bytes = rss;
|
||||
result.peak_rss_bytes = peak_rss;
|
||||
result.commit_bytes = commit;
|
||||
result.peak_commit_bytes = peak_commit;
|
||||
result.page_faults = page_faults;
|
||||
result.system_total_bytes = Psc::get_system_memory();
|
||||
#if defined(ECAP_TARGET_LINUX)
|
||||
read_linux_process_memory(result);
|
||||
read_linux_system_memory(result);
|
||||
#endif
|
||||
const auto allocator = server_allocator_snapshot();
|
||||
result.allocator_live_bytes = allocator.live_bytes;
|
||||
result.allocator_peak_live_bytes = allocator.peak_live_bytes;
|
||||
result.pmr_live_bytes = allocator.pmr_live_bytes;
|
||||
result.pmr_peak_live_bytes = allocator.pmr_peak_live_bytes;
|
||||
std::lock_guard lock(mutex_);
|
||||
history_.push_back(result);
|
||||
if (history_.size() > history_capacity)
|
||||
history_.pop_front();
|
||||
}
|
||||
Psc::JSON Memory_Monitor::state_json() const {
|
||||
std::lock_guard lock(mutex_);
|
||||
Psc::JSON result = Psc::JSON::object();
|
||||
if (history_.empty())
|
||||
return result;
|
||||
const auto& latest = history_.back();
|
||||
const auto window_ms = latest.timestamp_ms - history_.front().timestamp_ms;
|
||||
const auto rss_growth = growth_trend(history_, [](const auto& sample) { return sample.rss_bytes; }, growth_window_ms);
|
||||
const auto anonymous_growth = growth_trend(history_, [](const auto& sample) { return sample.anonymous_rss_bytes; },
|
||||
growth_window_ms);
|
||||
const auto recent_anonymous_growth = growth_trend(history_, [](const auto& sample) {
|
||||
return sample.anonymous_rss_bytes;
|
||||
}, recent_growth_window_ms);
|
||||
const auto allocator_growth = growth_trend(history_, [](const auto& sample) {
|
||||
return sample.allocator_live_bytes;
|
||||
}, growth_window_ms);
|
||||
const auto process_percent = latest.system_total_bytes == 0 ? 0.0 :
|
||||
static_cast<double>(latest.rss_bytes) * 100.0 / static_cast<double>(latest.system_total_bytes);
|
||||
const auto available_percent = latest.system_total_bytes == 0 ? 0.0 :
|
||||
static_cast<double>(latest.system_available_bytes) * 100.0 / static_cast<double>(latest.system_total_bytes);
|
||||
std::string pressure = "normal";
|
||||
if (process_percent >= 75.0 || (available_percent > 0.0 && available_percent <= 5.0))
|
||||
pressure = "critical";
|
||||
else if (process_percent >= 50.0 || (available_percent > 0.0 && available_percent <= 15.0))
|
||||
pressure = "warning";
|
||||
const bool sustained_growth = anonymous_growth.window_ms >= minimum_growth_window_ms &&
|
||||
recent_anonymous_growth.window_ms >= minimum_recent_growth_window_ms &&
|
||||
anonymous_growth.bytes_per_hour >= static_cast<std::int64_t>(16 * mebibyte) &&
|
||||
recent_anonymous_growth.bytes_per_hour >= static_cast<std::int64_t>(16 * mebibyte);
|
||||
const auto allocator = server_allocator_snapshot();
|
||||
result.append({"allocator", "mimalloc"});
|
||||
result.append({"allocator_version", allocator.allocator_version});
|
||||
result.append({"current", snapshot_json(latest)});
|
||||
result.append({"process_memory_percent", process_percent});
|
||||
result.append({"system_available_percent", available_percent});
|
||||
result.append({"pressure", pressure});
|
||||
result.append({"sample_count", history_.size()});
|
||||
result.append({"window_seconds", window_ms / 1000});
|
||||
result.append({"growth_window_seconds", anonymous_growth.window_ms / 1000});
|
||||
result.append({"rss_growth_bytes_per_hour", rss_growth.bytes_per_hour});
|
||||
result.append({"anonymous_growth_bytes_per_hour", anonymous_growth.bytes_per_hour});
|
||||
result.append({"recent_anonymous_growth_bytes_per_hour", recent_anonymous_growth.bytes_per_hour});
|
||||
result.append({"allocator_growth_bytes_per_hour", allocator_growth.bytes_per_hour});
|
||||
result.append({"sustained_growth", sustained_growth});
|
||||
result.append({"allocated_bytes_total", allocator.allocated_bytes_total});
|
||||
result.append({"allocation_count", allocator.allocation_count});
|
||||
result.append({"deallocation_count", allocator.deallocation_count});
|
||||
result.append({"pmr_allocated_bytes_total", allocator.pmr_allocated_bytes_total});
|
||||
result.append({"pmr_allocation_count", allocator.pmr_allocation_count});
|
||||
result.append({"pmr_deallocation_count", allocator.pmr_deallocation_count});
|
||||
Psc::JSON history = Psc::JSON::array();
|
||||
const auto stride = std::max<std::size_t>(1, (history_.size() + response_history_capacity - 1) / response_history_capacity);
|
||||
for (std::size_t index = 0; index < history_.size(); index += stride)
|
||||
history.append(snapshot_json(history_[index]));
|
||||
if ((history_.size() - 1) % stride != 0)
|
||||
history.append(snapshot_json(history_.back()));
|
||||
result.append({"history", history});
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <deque>
|
||||
#include <memory_resource>
|
||||
#include <mutex>
|
||||
#include "../global_include.h"
|
||||
struct Process_Memory_Snapshot {
|
||||
std::uint64_t timestamp_ms{};
|
||||
std::uint64_t rss_bytes{};
|
||||
std::uint64_t peak_rss_bytes{};
|
||||
std::uint64_t anonymous_rss_bytes{};
|
||||
std::uint64_t file_rss_bytes{};
|
||||
std::uint64_t shared_rss_bytes{};
|
||||
std::uint64_t virtual_bytes{};
|
||||
std::uint64_t swap_bytes{};
|
||||
std::uint64_t commit_bytes{};
|
||||
std::uint64_t peak_commit_bytes{};
|
||||
std::uint64_t system_total_bytes{};
|
||||
std::uint64_t system_available_bytes{};
|
||||
std::uint64_t page_faults{};
|
||||
std::uint64_t allocator_live_bytes{};
|
||||
std::uint64_t allocator_peak_live_bytes{};
|
||||
std::uint64_t pmr_live_bytes{};
|
||||
std::uint64_t pmr_peak_live_bytes{};
|
||||
};
|
||||
class Memory_Monitor {
|
||||
public:
|
||||
static Memory_Monitor& instance();
|
||||
void sample();
|
||||
Psc::JSON state_json() const;
|
||||
private:
|
||||
Memory_Monitor();
|
||||
mutable std::mutex mutex_;
|
||||
std::pmr::deque<Process_Memory_Snapshot> history_;
|
||||
};
|
||||
@@ -0,0 +1,171 @@
|
||||
#include "Memory_Resource.h"
|
||||
#include <atomic>
|
||||
#include <mimalloc.h>
|
||||
#include <new>
|
||||
namespace {
|
||||
struct Allocation_Counters {
|
||||
std::atomic<std::uint64_t> live_bytes{};
|
||||
std::atomic<std::uint64_t> peak_live_bytes{};
|
||||
std::atomic<std::uint64_t> allocated_bytes_total{};
|
||||
std::atomic<std::uint64_t> allocation_count{};
|
||||
std::atomic<std::uint64_t> deallocation_count{};
|
||||
std::atomic<std::uint64_t> pmr_live_bytes{};
|
||||
std::atomic<std::uint64_t> pmr_peak_live_bytes{};
|
||||
std::atomic<std::uint64_t> pmr_allocated_bytes_total{};
|
||||
std::atomic<std::uint64_t> pmr_allocation_count{};
|
||||
std::atomic<std::uint64_t> pmr_deallocation_count{};
|
||||
};
|
||||
constinit Allocation_Counters allocation_counters;
|
||||
void update_peak(std::atomic<std::uint64_t>& peak, std::uint64_t value) {
|
||||
auto current = peak.load(std::memory_order_relaxed);
|
||||
while (current < value && !peak.compare_exchange_weak(current, value, std::memory_order_relaxed)) {
|
||||
}
|
||||
}
|
||||
void record_allocation(void* pointer, bool pmr) {
|
||||
if (pointer == nullptr)
|
||||
return;
|
||||
const auto bytes = static_cast<std::uint64_t>(mi_usable_size(pointer));
|
||||
const auto live = allocation_counters.live_bytes.fetch_add(bytes, std::memory_order_relaxed) + bytes;
|
||||
allocation_counters.allocated_bytes_total.fetch_add(bytes, std::memory_order_relaxed);
|
||||
allocation_counters.allocation_count.fetch_add(1, std::memory_order_relaxed);
|
||||
update_peak(allocation_counters.peak_live_bytes, live);
|
||||
if (!pmr)
|
||||
return;
|
||||
const auto pmr_live = allocation_counters.pmr_live_bytes.fetch_add(bytes, std::memory_order_relaxed) + bytes;
|
||||
allocation_counters.pmr_allocated_bytes_total.fetch_add(bytes, std::memory_order_relaxed);
|
||||
allocation_counters.pmr_allocation_count.fetch_add(1, std::memory_order_relaxed);
|
||||
update_peak(allocation_counters.pmr_peak_live_bytes, pmr_live);
|
||||
}
|
||||
void record_deallocation(void* pointer, bool pmr) {
|
||||
if (pointer == nullptr)
|
||||
return;
|
||||
const auto bytes = static_cast<std::uint64_t>(mi_usable_size(pointer));
|
||||
allocation_counters.live_bytes.fetch_sub(bytes, std::memory_order_relaxed);
|
||||
allocation_counters.deallocation_count.fetch_add(1, std::memory_order_relaxed);
|
||||
if (!pmr)
|
||||
return;
|
||||
allocation_counters.pmr_live_bytes.fetch_sub(bytes, std::memory_order_relaxed);
|
||||
allocation_counters.pmr_deallocation_count.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
void free_tracked(void* pointer) noexcept {
|
||||
record_deallocation(pointer, false);
|
||||
mi_free(pointer);
|
||||
}
|
||||
class Mimalloc_Memory_Resource final : public std::pmr::memory_resource {
|
||||
protected:
|
||||
void* do_allocate(std::size_t bytes, std::size_t alignment) override {
|
||||
auto pointer = mi_new_aligned(bytes, alignment);
|
||||
record_allocation(pointer, true);
|
||||
return pointer;
|
||||
}
|
||||
void do_deallocate(void* pointer, std::size_t, std::size_t) override {
|
||||
record_deallocation(pointer, true);
|
||||
mi_free(pointer);
|
||||
}
|
||||
bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override {
|
||||
return this == &other;
|
||||
}
|
||||
};
|
||||
}
|
||||
void* operator new(std::size_t bytes) {
|
||||
auto pointer = mi_new(bytes);
|
||||
record_allocation(pointer, false);
|
||||
return pointer;
|
||||
}
|
||||
void* operator new[](std::size_t bytes) {
|
||||
auto pointer = mi_new(bytes);
|
||||
record_allocation(pointer, false);
|
||||
return pointer;
|
||||
}
|
||||
void* operator new(std::size_t bytes, const std::nothrow_t&) noexcept {
|
||||
auto pointer = mi_new_nothrow(bytes);
|
||||
record_allocation(pointer, false);
|
||||
return pointer;
|
||||
}
|
||||
void* operator new[](std::size_t bytes, const std::nothrow_t&) noexcept {
|
||||
auto pointer = mi_new_nothrow(bytes);
|
||||
record_allocation(pointer, false);
|
||||
return pointer;
|
||||
}
|
||||
void operator delete(void* pointer) noexcept {
|
||||
free_tracked(pointer);
|
||||
}
|
||||
void operator delete[](void* pointer) noexcept {
|
||||
free_tracked(pointer);
|
||||
}
|
||||
void operator delete(void* pointer, const std::nothrow_t&) noexcept {
|
||||
free_tracked(pointer);
|
||||
}
|
||||
void operator delete[](void* pointer, const std::nothrow_t&) noexcept {
|
||||
free_tracked(pointer);
|
||||
}
|
||||
void operator delete(void* pointer, std::size_t) noexcept {
|
||||
free_tracked(pointer);
|
||||
}
|
||||
void operator delete[](void* pointer, std::size_t) noexcept {
|
||||
free_tracked(pointer);
|
||||
}
|
||||
void* operator new(std::size_t bytes, std::align_val_t alignment) {
|
||||
auto pointer = mi_new_aligned(bytes, static_cast<std::size_t>(alignment));
|
||||
record_allocation(pointer, false);
|
||||
return pointer;
|
||||
}
|
||||
void* operator new[](std::size_t bytes, std::align_val_t alignment) {
|
||||
auto pointer = mi_new_aligned(bytes, static_cast<std::size_t>(alignment));
|
||||
record_allocation(pointer, false);
|
||||
return pointer;
|
||||
}
|
||||
void* operator new(std::size_t bytes, std::align_val_t alignment, const std::nothrow_t&) noexcept {
|
||||
auto pointer = mi_new_aligned_nothrow(bytes, static_cast<std::size_t>(alignment));
|
||||
record_allocation(pointer, false);
|
||||
return pointer;
|
||||
}
|
||||
void* operator new[](std::size_t bytes, std::align_val_t alignment, const std::nothrow_t&) noexcept {
|
||||
auto pointer = mi_new_aligned_nothrow(bytes, static_cast<std::size_t>(alignment));
|
||||
record_allocation(pointer, false);
|
||||
return pointer;
|
||||
}
|
||||
void operator delete(void* pointer, std::align_val_t) noexcept {
|
||||
free_tracked(pointer);
|
||||
}
|
||||
void operator delete[](void* pointer, std::align_val_t) noexcept {
|
||||
free_tracked(pointer);
|
||||
}
|
||||
void operator delete(void* pointer, std::size_t, std::align_val_t) noexcept {
|
||||
free_tracked(pointer);
|
||||
}
|
||||
void operator delete[](void* pointer, std::size_t, std::align_val_t) noexcept {
|
||||
free_tracked(pointer);
|
||||
}
|
||||
void operator delete(void* pointer, std::align_val_t, const std::nothrow_t&) noexcept {
|
||||
free_tracked(pointer);
|
||||
}
|
||||
void operator delete[](void* pointer, std::align_val_t, const std::nothrow_t&) noexcept {
|
||||
free_tracked(pointer);
|
||||
}
|
||||
std::pmr::memory_resource* server_memory_resource() {
|
||||
static Mimalloc_Memory_Resource resource;
|
||||
return &resource;
|
||||
}
|
||||
void initialize_server_memory_resource() {
|
||||
mi_process_init();
|
||||
std::pmr::set_default_resource(server_memory_resource());
|
||||
}
|
||||
Server_Allocator_Snapshot server_allocator_snapshot() {
|
||||
Server_Allocator_Snapshot result;
|
||||
result.live_bytes = allocation_counters.live_bytes.load(std::memory_order_relaxed);
|
||||
result.peak_live_bytes = allocation_counters.peak_live_bytes.load(std::memory_order_relaxed);
|
||||
result.allocated_bytes_total = allocation_counters.allocated_bytes_total.load(std::memory_order_relaxed);
|
||||
result.allocation_count = allocation_counters.allocation_count.load(std::memory_order_relaxed);
|
||||
result.deallocation_count = allocation_counters.deallocation_count.load(std::memory_order_relaxed);
|
||||
result.pmr_live_bytes = allocation_counters.pmr_live_bytes.load(std::memory_order_relaxed);
|
||||
result.pmr_peak_live_bytes = allocation_counters.pmr_peak_live_bytes.load(std::memory_order_relaxed);
|
||||
result.pmr_allocated_bytes_total = allocation_counters.pmr_allocated_bytes_total.load(std::memory_order_relaxed);
|
||||
result.pmr_allocation_count = allocation_counters.pmr_allocation_count.load(std::memory_order_relaxed);
|
||||
result.pmr_deallocation_count = allocation_counters.pmr_deallocation_count.load(std::memory_order_relaxed);
|
||||
result.allocator_version = mi_version();
|
||||
return result;
|
||||
}
|
||||
void collect_server_memory(bool force) {
|
||||
mi_collect(force);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory_resource>
|
||||
struct Server_Allocator_Snapshot {
|
||||
std::uint64_t live_bytes{};
|
||||
std::uint64_t peak_live_bytes{};
|
||||
std::uint64_t allocated_bytes_total{};
|
||||
std::uint64_t allocation_count{};
|
||||
std::uint64_t deallocation_count{};
|
||||
std::uint64_t pmr_live_bytes{};
|
||||
std::uint64_t pmr_peak_live_bytes{};
|
||||
std::uint64_t pmr_allocated_bytes_total{};
|
||||
std::uint64_t pmr_allocation_count{};
|
||||
std::uint64_t pmr_deallocation_count{};
|
||||
int allocator_version{};
|
||||
};
|
||||
void initialize_server_memory_resource();
|
||||
std::pmr::memory_resource* server_memory_resource();
|
||||
Server_Allocator_Snapshot server_allocator_snapshot();
|
||||
void collect_server_memory(bool force);
|
||||
@@ -2,6 +2,7 @@
|
||||
#define BIN_Msg_Buffer_H
|
||||
|
||||
#include "../global_include.h"
|
||||
#include <memory_resource>
|
||||
#include <stack>
|
||||
#include <string_view>
|
||||
|
||||
@@ -38,20 +39,18 @@ protected:
|
||||
};
|
||||
|
||||
struct BIN_Msg_Buffer {
|
||||
using Batch = std::pmr::vector<std::pmr::string>;
|
||||
void push(std::string_view msg);
|
||||
const std::vector<std::string *> &get_all();
|
||||
|
||||
Batch take_all();
|
||||
std::atomic<size_t> mode_s_msg_num{};
|
||||
std::atomic<size_t> mode_other_msg_num{};
|
||||
BIN_Msg_Buffer();
|
||||
|
||||
Psc::JSON state_json();
|
||||
|
||||
protected:
|
||||
std::mutex mtx;
|
||||
std::vector<std::string *> msg_list_cache;
|
||||
std::vector<std::string *> msg_list;
|
||||
Batch msg_list_cache;
|
||||
size_t cache_bytes{};
|
||||
size_t dispatch_batches{};
|
||||
size_t dispatch_bytes{};
|
||||
size_t high_water_messages{};
|
||||
size_t high_water_bytes{};
|
||||
|
||||
@@ -136,13 +136,11 @@ asio::awaitable<void> Data_Feed::loop_coro() {
|
||||
auto feed = this;
|
||||
auto co = Coro::instance();
|
||||
auto& mode_acs = Global::instance()->mode_acs;
|
||||
auto& cfg = mode_acs.data_feed_config;
|
||||
auto& pool = cfg.pool_;
|
||||
while (feed->running()) {
|
||||
if (data_feed_debug) {
|
||||
std::cout << std::format("{} feed loop begin {}\n", key, thread_id_str());
|
||||
}
|
||||
std::vector<std::string> messages;
|
||||
BIN_Msg_Buffer::Batch messages;
|
||||
{
|
||||
if (!feed->running() || !feed->registered()) {
|
||||
break;
|
||||
@@ -150,26 +148,17 @@ asio::awaitable<void> Data_Feed::loop_coro() {
|
||||
co_await feed->handle_in_loop_coro();
|
||||
auto s_num = feed->msg_buffer.mode_s_msg_num.load();
|
||||
auto other_num = feed->msg_buffer.mode_other_msg_num.load();
|
||||
const std::vector<std::string*>& all = feed->msg_buffer.get_all();
|
||||
Pool_Guard pg(&pool, all);
|
||||
messages = feed->msg_buffer.take_all();
|
||||
const auto [num, monitor_msg_live] = mode_acs.settings.read([](const auto& value) {
|
||||
return std::pair{value.report_data_feed_msg_mum, value.monitor_msg_live};
|
||||
});
|
||||
if (monitor_msg_live && num != 0 && all.size() > num && too_many_msg_limit.test()) {
|
||||
if (monitor_msg_live && num != 0 && messages.size() > num && too_many_msg_limit.test()) {
|
||||
std::ostringstream oss;
|
||||
oss << "feed_key:" << feed->key << " ";
|
||||
oss << "recv_s:" << s_num << " ";
|
||||
oss << "recv_other:" << other_num << " ";
|
||||
std::cout << oss.str() << std::endl;
|
||||
}
|
||||
messages.reserve(all.size());
|
||||
for (const auto* str : all) {
|
||||
if (!str || str->empty()) {
|
||||
std::cout << "empty feed message:" << feed->key << std::endl;
|
||||
continue;
|
||||
}
|
||||
messages.emplace_back(*str);
|
||||
}
|
||||
}
|
||||
if (messages.empty()) {
|
||||
co_await co->sleep_for(std::chrono::milliseconds(10));
|
||||
@@ -186,7 +175,7 @@ asio::awaitable<void> Data_Feed::loop_coro() {
|
||||
if (data_feed_debug) {
|
||||
std::cout << std::format("{} before send {}\n", key, thread_id_str());
|
||||
}
|
||||
co_await feed->send_coro(msg);
|
||||
co_await feed->send_coro(std::string_view(msg.data(), msg.size()));
|
||||
if (data_feed_debug) {
|
||||
std::cout << std::format("{} after send {}\n", key, thread_id_str());
|
||||
}
|
||||
@@ -292,7 +281,6 @@ asio::awaitable<void> Data_Source::loop_coro() {
|
||||
ask_sleep = false;
|
||||
}
|
||||
}
|
||||
std::cout << std::flush;
|
||||
}
|
||||
std::cout << std::format("{} source loop exit {}\n", key, thread_id_str());
|
||||
co_return;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <cctype>
|
||||
#include <string_view>
|
||||
#include "Global.h"
|
||||
#include "Memory_Monitor.h"
|
||||
#include "Performance_Monitor.h"
|
||||
namespace {
|
||||
constexpr std::size_t kMaxLogRequestBodySize = 8 * 1024;
|
||||
@@ -174,6 +175,7 @@ void Global::init_web_server() {
|
||||
add_path(R"(^/map3d)");
|
||||
add_path(R"(^/aircraftlist)");
|
||||
add_path(R"(^/topology)");
|
||||
add_path(R"(^/memory)");
|
||||
drogon::app().registerHandlerViaRegex(
|
||||
R"(^/ui(/.*)?$)",
|
||||
[return_file](const drogon::HttpRequestPtr& req, std::function<void(const drogon::HttpResponsePtr&)>&& callback) {
|
||||
@@ -185,7 +187,7 @@ void Global::init_web_server() {
|
||||
}
|
||||
auto is_spa_path = [](std::string_view value) {
|
||||
return value == "/" || value == "/map" || value == "/map3d" || value == "/settings" ||
|
||||
value == "/aircraftlist" || value == "/topology";
|
||||
value == "/aircraftlist" || value == "/topology" || value == "/memory";
|
||||
};
|
||||
if (is_spa_path(rp)) {
|
||||
path += "/index.html";
|
||||
@@ -196,12 +198,6 @@ void Global::init_web_server() {
|
||||
callback(return_file(path));
|
||||
});
|
||||
State_Report::instance();
|
||||
svr.Get(R"(/get_debug_info)", [](HTTP_Param) {
|
||||
JSON arr = JSON::array();
|
||||
auto& sp = Global::instance()->mode_acs.data_feed_config.pool_;
|
||||
arr.append(JSON::object({{"remain_size", sp.remain_size()}, {"free_size", sp.free_size()}}));
|
||||
res->setBody(arr.to_json_string("", "\n", ""));
|
||||
});
|
||||
database_server(this);
|
||||
external_resources_manager.server(this);
|
||||
mode_acs.server(this);
|
||||
@@ -389,6 +385,17 @@ void Global::init_web_server() {
|
||||
// ret.append({"基站信息", base_station.to_Json()});
|
||||
res->setBody(warp(ret).to_json_string());
|
||||
});
|
||||
svr.Post(api + "memory_status", [this](HTTP_Param) {
|
||||
auto result = Memory_Monitor::instance().state_json();
|
||||
JSON sources = JSON::object();
|
||||
for (const auto& source : mode_acs.data_source_config.map.list()) {
|
||||
if (const auto dll_source = dynamic_cast<Dll_Data_Source*>(source.get()))
|
||||
sources.append({source->key, dll_source->backlog_state_json()});
|
||||
}
|
||||
result.append({"dll_sources", sources});
|
||||
result.append({"iq_dropped_frames_total", dsp_config.iq_memory_buffer.dropped()});
|
||||
res->setBody(warp(result).to_json_string());
|
||||
});
|
||||
svr.Post(api + "version", [this](HTTP_Param) {
|
||||
auto ret = JSON::object();
|
||||
ret.append({"version", version});
|
||||
|
||||
Reference in New Issue
Block a user