lean4-htt/src/runtime/memory.cpp
2023-01-23 09:27:09 -08:00

150 lines
3.9 KiB
C++

/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include <new>
#include <cstdlib>
#include <iostream>
#include "runtime/exception.h"
#include "runtime/memory.h"
#include "runtime/thread.h"
#ifndef LEAN_CHECK_MEM_THRESHOLD
#define LEAN_CHECK_MEM_THRESHOLD 200
#endif
#if defined(HAS_JEMALLOC)
#include <jemalloc/jemalloc.h>
namespace lean {
size_t get_peak_rss() {
// refresh stats
uint64_t epoch;
mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch));
size_t allocated;
size_t sz = sizeof(size_t);
if (mallctl("stats.allocated", &allocated, &sz, NULL, 0) == 0) {
return allocated;
} else {
return 0;
}
}
size_t get_current_rss() {
return get_peak_rss();
}
}
#elif defined(LEAN_WINDOWS)
/* ----------------------------------------------------
Windows version for get_peak_rss and get_current_rss
--------------------------------------------------- */
#include <windows.h>
#include <psapi.h>
namespace lean {
size_t get_peak_rss() {
PROCESS_MEMORY_COUNTERS info;
GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
return static_cast<size_t>(info.PeakWorkingSetSize);
}
size_t get_current_rss() {
PROCESS_MEMORY_COUNTERS info;
GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
return static_cast<size_t>(info.WorkingSetSize);
}
}
/* ----------------------------------------------------
End of Windows version
--------------------------------------------------- */
#else
/* ----------------------------------------------------
Linux/OSX version for get_peak_rss and get_current_rss
--------------------------------------------------- */
#include <unistd.h>
#include <sys/resource.h>
#if defined(__APPLE__)
#include <mach/mach.h>
#endif
namespace lean {
size_t get_peak_rss() {
struct rusage rusage;
getrusage(RUSAGE_SELF, &rusage);
#if defined(__APPLE__)
return static_cast<size_t>(rusage.ru_maxrss);
#else
return static_cast<size_t>(rusage.ru_maxrss) * static_cast<size_t>(1024);
#endif
}
size_t get_current_rss() {
#if defined(__APPLE__)
struct mach_task_basic_info info;
mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, reinterpret_cast<task_info_t>(&info), &infoCount) != KERN_SUCCESS)
return static_cast<size_t>(0);
return static_cast<size_t>(info.resident_size);
#else
long rss = 0;
FILE * fp = nullptr;
if ((fp = fopen("/proc/self/statm", "r")) == nullptr)
return static_cast<size_t>(0L);
if (fscanf(fp, "%*s%ld", &rss ) != 1) {
fclose(fp);
return static_cast<size_t>(0);
}
fclose(fp);
return static_cast<size_t>(rss) * static_cast<size_t>(sysconf(_SC_PAGESIZE));
#endif
}
}
/* ----------------------------------------------------
End of Linux/OSX version
--------------------------------------------------- */
#endif
namespace lean {
static size_t g_max_memory = 0;
LEAN_THREAD_VALUE(size_t, g_counter, 0);
void set_max_memory(size_t max) {
g_max_memory = max;
}
void set_max_memory_megabyte(unsigned max) {
size_t m = max;
m *= 1024 * 1024;
set_max_memory(m);
}
// separate definition to allow breakpoint in debugger
void throw_memory_exception(char const * component_name) {
throw memory_exception(component_name);
}
void check_memory(char const * component_name) {
if (g_max_memory == 0) return;
g_counter++;
if (g_counter >= LEAN_CHECK_MEM_THRESHOLD) {
g_counter = 0;
// We try first get_peak_rss because it is much faster
// than get_current_rss on Linux.
size_t r = get_peak_rss();
if (r > 0 && r < g_max_memory) return;
r = get_current_rss();
if (r == 0 || r < g_max_memory) return;
throw_memory_exception(component_name);
}
}
size_t get_allocated_memory() {
return get_current_rss();
}
}