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.
163 lines
4.3 KiB
C++
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();
|
|
}
|
|
}
|