merge from dev
This commit is contained in:
154
src/options.c
154
src/options.c
@@ -51,25 +51,22 @@ static mi_option_desc_t options[_mi_option_last] =
|
||||
{ 0, UNINIT, MI_OPTION(show_stats) },
|
||||
{ 0, UNINIT, MI_OPTION(verbose) },
|
||||
|
||||
#if MI_SECURE
|
||||
{ MI_SECURE, INITIALIZED, MI_OPTION(secure) }, // in a secure build the environment setting is ignored
|
||||
#else
|
||||
{ 0, UNINIT, MI_OPTION(secure) },
|
||||
#endif
|
||||
|
||||
// the following options are experimental and not all combinations make sense.
|
||||
{ 1, UNINIT, MI_OPTION(eager_commit) }, // note: needs to be on when eager_region_commit is enabled
|
||||
#ifdef _WIN32 // and BSD?
|
||||
{ 1, UNINIT, MI_OPTION(lazy_commit) },
|
||||
{ 0, UNINIT, MI_OPTION(eager_region_commit) }, // don't commit too eagerly on windows (just for looks...)
|
||||
#else
|
||||
{ 0, UNINIT, MI_OPTION(lazy_commit) },
|
||||
{ 1, UNINIT, MI_OPTION(eager_region_commit) },
|
||||
#endif
|
||||
{ 0, UNINIT, MI_OPTION(decommit) },
|
||||
{ 0, UNINIT, MI_OPTION(large_os_pages) }, // use large OS pages, use only with eager commit to prevent fragmentation of VMA's
|
||||
{ 0, UNINIT, MI_OPTION(reserve_huge_os_pages) },
|
||||
{ 0, UNINIT, MI_OPTION(segment_cache) }, // cache N segments per thread
|
||||
{ 0, UNINIT, MI_OPTION(page_reset) },
|
||||
{ 0, UNINIT, MI_OPTION(cache_reset) },
|
||||
{ 0, UNINIT, MI_OPTION(reset_decommits) } // note: cannot enable this if secure is on
|
||||
{ 0, UNINIT, MI_OPTION(reset_decommits) }, // note: cannot enable this if secure is on
|
||||
{ 0, UNINIT, MI_OPTION(eager_commit_delay) }, // the first N segments per thread are not eagerly committed
|
||||
{ 0, UNINIT, MI_OPTION(segment_reset) }, // reset segment memory on free
|
||||
{ 100, UNINIT, MI_OPTION(os_tag) } // only apple specific for now but might serve more or less related purpose
|
||||
};
|
||||
|
||||
static void mi_option_init(mi_option_desc_t* desc);
|
||||
@@ -77,7 +74,12 @@ static void mi_option_init(mi_option_desc_t* desc);
|
||||
void _mi_options_init(void) {
|
||||
// called on process load
|
||||
for(int i = 0; i < _mi_option_last; i++ ) {
|
||||
mi_option_get((mi_option_t)i); // initialize
|
||||
mi_option_t option = (mi_option_t)i;
|
||||
mi_option_get(option); // initialize
|
||||
if (option != mi_option_verbose) {
|
||||
mi_option_desc_t* desc = &options[option];
|
||||
_mi_verbose_message("option '%s': %ld\n", desc->name, desc->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,10 +88,7 @@ long mi_option_get(mi_option_t option) {
|
||||
mi_option_desc_t* desc = &options[option];
|
||||
mi_assert(desc->option == option); // index should match the option
|
||||
if (mi_unlikely(desc->init == UNINIT)) {
|
||||
mi_option_init(desc);
|
||||
if (option != mi_option_verbose) {
|
||||
_mi_verbose_message("option '%s': %ld\n", desc->name, desc->value);
|
||||
}
|
||||
mi_option_init(desc);
|
||||
}
|
||||
return desc->value;
|
||||
}
|
||||
@@ -131,8 +130,80 @@ void mi_option_disable(mi_option_t option) {
|
||||
}
|
||||
|
||||
|
||||
static void mi_out_stderr(const char* msg) {
|
||||
#ifdef _WIN32
|
||||
// on windows with redirection, the C runtime cannot handle locale dependent output
|
||||
// after the main thread closes so we use direct console output.
|
||||
_cputs(msg);
|
||||
#else
|
||||
fputs(msg, stderr);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Since an output function can be registered earliest in the `main`
|
||||
// function we also buffer output that happens earlier. When
|
||||
// an output function is registered it is called immediately with
|
||||
// the output up to that point.
|
||||
#ifndef MI_MAX_DELAY_OUTPUT
|
||||
#define MI_MAX_DELAY_OUTPUT (32*1024)
|
||||
#endif
|
||||
static char out_buf[MI_MAX_DELAY_OUTPUT+1];
|
||||
static _Atomic(uintptr_t) out_len;
|
||||
|
||||
static void mi_out_buf(const char* msg) {
|
||||
if (msg==NULL) return;
|
||||
if (mi_atomic_read_relaxed(&out_len)>=MI_MAX_DELAY_OUTPUT) return;
|
||||
size_t n = strlen(msg);
|
||||
if (n==0) return;
|
||||
// claim space
|
||||
uintptr_t start = mi_atomic_addu(&out_len, n);
|
||||
if (start >= MI_MAX_DELAY_OUTPUT) return;
|
||||
// check bound
|
||||
if (start+n >= MI_MAX_DELAY_OUTPUT) {
|
||||
n = MI_MAX_DELAY_OUTPUT-start-1;
|
||||
}
|
||||
memcpy(&out_buf[start], msg, n);
|
||||
}
|
||||
|
||||
static void mi_out_buf_flush(mi_output_fun* out) {
|
||||
if (out==NULL) return;
|
||||
// claim all (no more output will be added after this point)
|
||||
size_t count = mi_atomic_addu(&out_len, MI_MAX_DELAY_OUTPUT);
|
||||
// and output the current contents
|
||||
if (count>MI_MAX_DELAY_OUTPUT) count = MI_MAX_DELAY_OUTPUT;
|
||||
out_buf[count] = 0;
|
||||
out(out_buf);
|
||||
}
|
||||
|
||||
// The initial default output, outputs to stderr and the delayed output buffer.
|
||||
static void mi_out_buf_stderr(const char* msg) {
|
||||
mi_out_stderr(msg);
|
||||
mi_out_buf(msg);
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------
|
||||
// Messages
|
||||
// Default output handler
|
||||
// --------------------------------------------------------
|
||||
|
||||
// Should be atomic but gives errors on many platforms as generally we cannot cast a function pointer to a uintptr_t.
|
||||
// For now, don't register output from multiple threads.
|
||||
#pragma warning(suppress:4180)
|
||||
static mi_output_fun* volatile mi_out_default; // = NULL
|
||||
|
||||
static mi_output_fun* mi_out_get_default(void) {
|
||||
mi_output_fun* out = mi_out_default;
|
||||
return (out == NULL ? &mi_out_buf_stderr : out);
|
||||
}
|
||||
|
||||
void mi_register_output(mi_output_fun* out) mi_attr_noexcept {
|
||||
mi_out_default = (out == NULL ? &mi_out_stderr : out); // stop using the delayed output buffer
|
||||
if (out!=NULL) mi_out_buf_flush(out); // output the delayed output now
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------
|
||||
// Messages, all end up calling `_mi_fputs`.
|
||||
// --------------------------------------------------------
|
||||
#define MAX_ERROR_COUNT (10)
|
||||
static volatile _Atomic(uintptr_t) error_count; // = 0; // when MAX_ERROR_COUNT stop emitting errors and warnings
|
||||
@@ -141,33 +212,30 @@ static volatile _Atomic(uintptr_t) error_count; // = 0; // when MAX_ERROR_COUNT
|
||||
// inside the C runtime causes another message.
|
||||
static mi_decl_thread bool recurse = false;
|
||||
|
||||
// Define our own limited `fprintf` that avoids memory allocation.
|
||||
// We do this using `snprintf` with a limited buffer.
|
||||
static void mi_vfprintf( FILE* out, const char* prefix, const char* fmt, va_list args ) {
|
||||
char buf[256];
|
||||
if (fmt==NULL) return;
|
||||
void _mi_fputs(mi_output_fun* out, const char* prefix, const char* message) {
|
||||
if (_mi_preloading() || recurse) return;
|
||||
if (out==NULL || (FILE*)out==stdout || (FILE*)out==stderr) out = mi_out_get_default();
|
||||
recurse = true;
|
||||
if (out==NULL) out = stdout;
|
||||
vsnprintf(buf,sizeof(buf)-1,fmt,args);
|
||||
#ifdef _WIN32
|
||||
// on windows with redirection, the C runtime cannot handle locale dependent output
|
||||
// after the main thread closes so use direct console output.
|
||||
if (out==stderr) {
|
||||
if (prefix != NULL) _cputs(prefix);
|
||||
_cputs(buf);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (prefix != NULL) fputs(prefix,out);
|
||||
fputs(buf,out);
|
||||
}
|
||||
if (prefix != NULL) out(prefix);
|
||||
out(message);
|
||||
recurse = false;
|
||||
return;
|
||||
}
|
||||
|
||||
void _mi_fprintf( FILE* out, const char* fmt, ... ) {
|
||||
// Define our own limited `fprintf` that avoids memory allocation.
|
||||
// We do this using `snprintf` with a limited buffer.
|
||||
static void mi_vfprintf( mi_output_fun* out, const char* prefix, const char* fmt, va_list args ) {
|
||||
char buf[512];
|
||||
if (fmt==NULL) return;
|
||||
if (_mi_preloading() || recurse) return;
|
||||
recurse = true;
|
||||
vsnprintf(buf,sizeof(buf)-1,fmt,args);
|
||||
recurse = false;
|
||||
_mi_fputs(out,prefix,buf);
|
||||
}
|
||||
|
||||
|
||||
void _mi_fprintf( mi_output_fun* out, const char* fmt, ... ) {
|
||||
va_list args;
|
||||
va_start(args,fmt);
|
||||
mi_vfprintf(out,NULL,fmt,args);
|
||||
@@ -178,7 +246,7 @@ void _mi_trace_message(const char* fmt, ...) {
|
||||
if (mi_option_get(mi_option_verbose) <= 1) return; // only with verbose level 2 or higher
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
mi_vfprintf(stderr, "mimalloc: ", fmt, args);
|
||||
mi_vfprintf(NULL, "mimalloc: ", fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
@@ -186,7 +254,7 @@ void _mi_verbose_message(const char* fmt, ...) {
|
||||
if (!mi_option_is_enabled(mi_option_verbose)) return;
|
||||
va_list args;
|
||||
va_start(args,fmt);
|
||||
mi_vfprintf(stderr, "mimalloc: ", fmt, args);
|
||||
mi_vfprintf(NULL, "mimalloc: ", fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
@@ -195,7 +263,7 @@ void _mi_error_message(const char* fmt, ...) {
|
||||
if (mi_atomic_increment(&error_count) > MAX_ERROR_COUNT) return;
|
||||
va_list args;
|
||||
va_start(args,fmt);
|
||||
mi_vfprintf(stderr, "mimalloc: error: ", fmt, args);
|
||||
mi_vfprintf(NULL, "mimalloc: error: ", fmt, args);
|
||||
va_end(args);
|
||||
mi_assert(false);
|
||||
}
|
||||
@@ -205,14 +273,14 @@ void _mi_warning_message(const char* fmt, ...) {
|
||||
if (mi_atomic_increment(&error_count) > MAX_ERROR_COUNT) return;
|
||||
va_list args;
|
||||
va_start(args,fmt);
|
||||
mi_vfprintf(stderr, "mimalloc: warning: ", fmt, args);
|
||||
mi_vfprintf(NULL, "mimalloc: warning: ", fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
#if MI_DEBUG
|
||||
void _mi_assert_fail(const char* assertion, const char* fname, unsigned line, const char* func ) {
|
||||
_mi_fprintf(stderr,"mimalloc: assertion failed: at \"%s\":%u, %s\n assertion: \"%s\"\n", fname, line, (func==NULL?"":func), assertion);
|
||||
_mi_fprintf(NULL,"mimalloc: assertion failed: at \"%s\":%u, %s\n assertion: \"%s\"\n", fname, line, (func==NULL?"":func), assertion);
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
@@ -278,7 +346,7 @@ static void mi_option_init(mi_option_desc_t* desc) {
|
||||
size_t len = strlen(s);
|
||||
if (len >= sizeof(buf)) len = sizeof(buf) - 1;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
buf[i] = toupper(s[i]);
|
||||
buf[i] = (char)toupper(s[i]);
|
||||
}
|
||||
buf[len] = 0;
|
||||
if (buf[0]==0 || strstr("1;TRUE;YES;ON", buf) != NULL) {
|
||||
|
||||
Reference in New Issue
Block a user