lean4-htt/src/runtime/memory.cpp
Mac Malone db3fb47109
refactor: port more of shell.cpp to Lean (#10086)
This PR ports more of the post-initialization C++ shell code to Lean.

All that remains is the initialization of the profiler and task manager.
As initialization tasks rather than main shell code, they were left in
C++ (where the rest of the initialization code currently is).

The `max_memory` and `timeout` Lean options used by the the `--memory`
and `--timeout` command-line options are now properly registered. The
server defaults for max memory and max heartbeats (timeout) were removed
as they were not actually used (because the `server` option that was
checked was neither set nor exists).

This PR also makes better use of the module system in `Shell.lean` and
fixes a minor bug in a previous port where the file name check was
dependent on building the `.ilean` rather than the `.c` file (as was
originally the case).

Fixes #9879.
2025-08-26 20:02:42 +00:00

163 lines
4.3 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);
extern "C" LEAN_EXPORT lean_obj_res lean_internal_get_default_max_memory(lean_obj_arg) {
#ifdef LEAN_DEFAULT_MAX_MEMORY
return lean_box(LEAN_DEFAULT_MAX_MEMORY);
#else
return lean_box(0);
#endif
}
void set_max_memory(size_t max) {
g_max_memory = max;
}
extern "C" LEAN_EXPORT lean_obj_res lean_internal_set_max_memory(size_t max) {
set_max_memory(max);
return lean_io_result_mk_ok(lean_box(0));
}
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();
}
}