make output function configurable; remove <stdio.h> from standard includes
This commit is contained in:
parent
4819d3f78f
commit
7bf12c7b5f
@ -22,7 +22,7 @@ terms of the MIT license. A copy of the license can be found in the file
|
|||||||
|
|
||||||
|
|
||||||
// "options.c"
|
// "options.c"
|
||||||
void _mi_fprintf(FILE* out, const char* fmt, ...);
|
void _mi_fprintf(mi_output_fun* out, const char* fmt, ...);
|
||||||
void _mi_error_message(const char* fmt, ...);
|
void _mi_error_message(const char* fmt, ...);
|
||||||
void _mi_warning_message(const char* fmt, ...);
|
void _mi_warning_message(const char* fmt, ...);
|
||||||
void _mi_verbose_message(const char* fmt, ...);
|
void _mi_verbose_message(const char* fmt, ...);
|
||||||
|
@ -69,8 +69,8 @@ terms of the MIT license. A copy of the license can be found in the file
|
|||||||
// Includes
|
// Includes
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
|
|
||||||
|
#include <stddef.h> // size_t
|
||||||
#include <stdbool.h> // bool
|
#include <stdbool.h> // bool
|
||||||
#include <stdio.h> // FILE
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -107,19 +107,23 @@ mi_decl_export mi_decl_allocator void* mi_reallocf(void* p, size_t newsize)
|
|||||||
mi_decl_export size_t mi_usable_size(const void* p) mi_attr_noexcept;
|
mi_decl_export size_t mi_usable_size(const void* p) mi_attr_noexcept;
|
||||||
mi_decl_export size_t mi_good_size(size_t size) mi_attr_noexcept;
|
mi_decl_export size_t mi_good_size(size_t size) mi_attr_noexcept;
|
||||||
|
|
||||||
|
typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat);
|
||||||
|
mi_decl_export void mi_register_deferred_free(mi_deferred_free_fun* deferred_free) mi_attr_noexcept;
|
||||||
|
|
||||||
|
typedef void (mi_output_fun)(const char* msg);
|
||||||
|
mi_decl_export void mi_register_output(mi_output_fun* out) mi_attr_noexcept;
|
||||||
|
|
||||||
mi_decl_export void mi_collect(bool force) mi_attr_noexcept;
|
mi_decl_export void mi_collect(bool force) mi_attr_noexcept;
|
||||||
mi_decl_export void mi_stats_print(FILE* out) mi_attr_noexcept;
|
mi_decl_export int mi_version(void) mi_attr_noexcept;
|
||||||
mi_decl_export void mi_stats_reset(void) mi_attr_noexcept;
|
mi_decl_export void mi_stats_reset(void) mi_attr_noexcept;
|
||||||
mi_decl_export void mi_stats_merge(void) mi_attr_noexcept;
|
mi_decl_export void mi_stats_merge(void) mi_attr_noexcept;
|
||||||
mi_decl_export int mi_version(void) mi_attr_noexcept;
|
mi_decl_export void mi_stats_print(mi_output_fun* out) mi_attr_noexcept;
|
||||||
|
|
||||||
mi_decl_export void mi_process_init(void) mi_attr_noexcept;
|
mi_decl_export void mi_process_init(void) mi_attr_noexcept;
|
||||||
mi_decl_export void mi_thread_init(void) mi_attr_noexcept;
|
mi_decl_export void mi_thread_init(void) mi_attr_noexcept;
|
||||||
mi_decl_export void mi_thread_done(void) mi_attr_noexcept;
|
mi_decl_export void mi_thread_done(void) mi_attr_noexcept;
|
||||||
mi_decl_export void mi_thread_stats_print(FILE* out) mi_attr_noexcept;
|
mi_decl_export void mi_thread_stats_print(mi_output_fun* out) mi_attr_noexcept;
|
||||||
|
|
||||||
typedef void (mi_deferred_free_fun)(bool force, unsigned long long heartbeat);
|
|
||||||
mi_decl_export void mi_register_deferred_free(mi_deferred_free_fun* deferred_free) mi_attr_noexcept;
|
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Aligned allocation
|
// Aligned allocation
|
||||||
|
@ -16,6 +16,7 @@ terms of the MIT license. A copy of the license can be found in the file
|
|||||||
#include <psapi.h>
|
#include <psapi.h>
|
||||||
|
|
||||||
#include <stdlib.h> // getenv
|
#include <stdlib.h> // getenv
|
||||||
|
#include <stdio.h> // _setmaxstdio
|
||||||
#include <string.h> // strstr
|
#include <string.h> // strstr
|
||||||
|
|
||||||
|
|
||||||
|
@ -134,6 +134,32 @@ 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------
|
||||||
|
// Default output handler
|
||||||
|
// --------------------------------------------------------
|
||||||
|
|
||||||
|
static volatile _Atomic(mi_output_fun*) mi_out_default; // = NULL
|
||||||
|
|
||||||
|
static mi_output_fun* mi_out_get_default(void) {
|
||||||
|
mi_output_fun* out = (mi_output_fun*)mi_atomic_read_ptr(mi_atomic_cast(void*, &mi_out_default));
|
||||||
|
return (out == NULL ? &mi_out_stderr : out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mi_register_output(mi_output_fun* out) mi_attr_noexcept {
|
||||||
|
mi_atomic_write_ptr(mi_atomic_cast(void*,&mi_out_default),out);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
// Messages
|
// Messages
|
||||||
// --------------------------------------------------------
|
// --------------------------------------------------------
|
||||||
@ -146,31 +172,20 @@ static mi_decl_thread bool recurse = false;
|
|||||||
|
|
||||||
// Define our own limited `fprintf` that avoids memory allocation.
|
// Define our own limited `fprintf` that avoids memory allocation.
|
||||||
// We do this using `snprintf` with a limited buffer.
|
// We do this using `snprintf` with a limited buffer.
|
||||||
static void mi_vfprintf( FILE* out, const char* prefix, const char* fmt, va_list args ) {
|
static void mi_vfprintf( mi_output_fun* out, const char* prefix, const char* fmt, va_list args ) {
|
||||||
char buf[256];
|
char buf[256];
|
||||||
if (fmt==NULL) return;
|
if (fmt==NULL) return;
|
||||||
if (_mi_preloading() || recurse) return;
|
if (_mi_preloading() || recurse) return;
|
||||||
recurse = true;
|
recurse = true;
|
||||||
if (out==NULL) out = stdout;
|
if (out==NULL) out = mi_out_get_default();
|
||||||
vsnprintf(buf,sizeof(buf)-1,fmt,args);
|
vsnprintf(buf,sizeof(buf)-1,fmt,args);
|
||||||
#ifdef _WIN32
|
if (prefix != NULL) out(prefix);
|
||||||
// on windows with redirection, the C runtime cannot handle locale dependent output
|
out(buf);
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
recurse = false;
|
recurse = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _mi_fprintf( FILE* out, const char* fmt, ... ) {
|
void _mi_fprintf( mi_output_fun* out, const char* fmt, ... ) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args,fmt);
|
va_start(args,fmt);
|
||||||
mi_vfprintf(out,NULL,fmt,args);
|
mi_vfprintf(out,NULL,fmt,args);
|
||||||
@ -181,7 +196,7 @@ void _mi_trace_message(const char* fmt, ...) {
|
|||||||
if (mi_option_get(mi_option_verbose) <= 1) return; // only with verbose level 2 or higher
|
if (mi_option_get(mi_option_verbose) <= 1) return; // only with verbose level 2 or higher
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
mi_vfprintf(stderr, "mimalloc: ", fmt, args);
|
mi_vfprintf(NULL, "mimalloc: ", fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +204,7 @@ void _mi_verbose_message(const char* fmt, ...) {
|
|||||||
if (!mi_option_is_enabled(mi_option_verbose)) return;
|
if (!mi_option_is_enabled(mi_option_verbose)) return;
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args,fmt);
|
va_start(args,fmt);
|
||||||
mi_vfprintf(stderr, "mimalloc: ", fmt, args);
|
mi_vfprintf(NULL, "mimalloc: ", fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,7 +213,7 @@ void _mi_error_message(const char* fmt, ...) {
|
|||||||
if (mi_atomic_increment(&error_count) > MAX_ERROR_COUNT) return;
|
if (mi_atomic_increment(&error_count) > MAX_ERROR_COUNT) return;
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args,fmt);
|
va_start(args,fmt);
|
||||||
mi_vfprintf(stderr, "mimalloc: error: ", fmt, args);
|
mi_vfprintf(NULL, "mimalloc: error: ", fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
mi_assert(false);
|
mi_assert(false);
|
||||||
}
|
}
|
||||||
@ -208,14 +223,14 @@ void _mi_warning_message(const char* fmt, ...) {
|
|||||||
if (mi_atomic_increment(&error_count) > MAX_ERROR_COUNT) return;
|
if (mi_atomic_increment(&error_count) > MAX_ERROR_COUNT) return;
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args,fmt);
|
va_start(args,fmt);
|
||||||
mi_vfprintf(stderr, "mimalloc: warning: ", fmt, args);
|
mi_vfprintf(NULL, "mimalloc: warning: ", fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if MI_DEBUG
|
#if MI_DEBUG
|
||||||
void _mi_assert_fail(const char* assertion, const char* fname, unsigned line, const char* func ) {
|
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();
|
abort();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
26
src/stats.c
26
src/stats.c
@ -8,6 +8,7 @@ terms of the MIT license. A copy of the license can be found in the file
|
|||||||
#include "mimalloc-internal.h"
|
#include "mimalloc-internal.h"
|
||||||
#include "mimalloc-atomic.h"
|
#include "mimalloc-atomic.h"
|
||||||
|
|
||||||
|
#include <stdio.h> // fputs, stderr
|
||||||
#include <string.h> // memset
|
#include <string.h> // memset
|
||||||
|
|
||||||
|
|
||||||
@ -120,7 +121,7 @@ static void mi_stats_add(mi_stats_t* stats, const mi_stats_t* src) {
|
|||||||
Display statistics
|
Display statistics
|
||||||
----------------------------------------------------------- */
|
----------------------------------------------------------- */
|
||||||
|
|
||||||
static void mi_printf_amount(int64_t n, int64_t unit, FILE* out, const char* fmt) {
|
static void mi_printf_amount(int64_t n, int64_t unit, mi_output_fun* out, const char* fmt) {
|
||||||
char buf[32];
|
char buf[32];
|
||||||
int len = 32;
|
int len = 32;
|
||||||
const char* suffix = (unit <= 0 ? " " : "b");
|
const char* suffix = (unit <= 0 ? " " : "b");
|
||||||
@ -141,16 +142,16 @@ static void mi_printf_amount(int64_t n, int64_t unit, FILE* out, const char* fmt
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void mi_print_amount(int64_t n, int64_t unit, FILE* out) {
|
static void mi_print_amount(int64_t n, int64_t unit, mi_output_fun* out) {
|
||||||
mi_printf_amount(n,unit,out,NULL);
|
mi_printf_amount(n,unit,out,NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mi_print_count(int64_t n, int64_t unit, FILE* out) {
|
static void mi_print_count(int64_t n, int64_t unit, mi_output_fun* out) {
|
||||||
if (unit==1) _mi_fprintf(out,"%11s"," ");
|
if (unit==1) _mi_fprintf(out,"%11s"," ");
|
||||||
else mi_print_amount(n,0,out);
|
else mi_print_amount(n,0,out);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mi_stat_print(const mi_stat_count_t* stat, const char* msg, int64_t unit, FILE* out ) {
|
static void mi_stat_print(const mi_stat_count_t* stat, const char* msg, int64_t unit, mi_output_fun* out ) {
|
||||||
_mi_fprintf(out,"%10s:", msg);
|
_mi_fprintf(out,"%10s:", msg);
|
||||||
if (unit>0) {
|
if (unit>0) {
|
||||||
mi_print_amount(stat->peak, unit, out);
|
mi_print_amount(stat->peak, unit, out);
|
||||||
@ -179,24 +180,24 @@ static void mi_stat_print(const mi_stat_count_t* stat, const char* msg, int64_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mi_stat_counter_print(const mi_stat_counter_t* stat, const char* msg, FILE* out ) {
|
static void mi_stat_counter_print(const mi_stat_counter_t* stat, const char* msg, mi_output_fun* out ) {
|
||||||
_mi_fprintf(out, "%10s:", msg);
|
_mi_fprintf(out, "%10s:", msg);
|
||||||
mi_print_amount(stat->total, -1, out);
|
mi_print_amount(stat->total, -1, out);
|
||||||
_mi_fprintf(out, "\n");
|
_mi_fprintf(out, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mi_stat_counter_print_avg(const mi_stat_counter_t* stat, const char* msg, FILE* out) {
|
static void mi_stat_counter_print_avg(const mi_stat_counter_t* stat, const char* msg, mi_output_fun* out) {
|
||||||
double avg = (stat->count == 0 ? 0.0 : (double)stat->total / (double)stat->count);
|
double avg = (stat->count == 0 ? 0.0 : (double)stat->total / (double)stat->count);
|
||||||
_mi_fprintf(out, "%10s: %7.1f avg\n", msg, avg);
|
_mi_fprintf(out, "%10s: %7.1f avg\n", msg, avg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void mi_print_header( FILE* out ) {
|
static void mi_print_header(mi_output_fun* out ) {
|
||||||
_mi_fprintf(out,"%10s: %10s %10s %10s %10s %10s\n", "heap stats", "peak ", "total ", "freed ", "unit ", "count ");
|
_mi_fprintf(out,"%10s: %10s %10s %10s %10s %10s\n", "heap stats", "peak ", "total ", "freed ", "unit ", "count ");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MI_STAT>1
|
#if MI_STAT>1
|
||||||
static void mi_stats_print_bins(mi_stat_count_t* all, const mi_stat_count_t* bins, size_t max, const char* fmt, FILE* out) {
|
static void mi_stats_print_bins(mi_stat_count_t* all, const mi_stat_count_t* bins, size_t max, const char* fmt, mi_output_fun* out) {
|
||||||
bool found = false;
|
bool found = false;
|
||||||
char buf[64];
|
char buf[64];
|
||||||
for (size_t i = 0; i <= max; i++) {
|
for (size_t i = 0; i <= max; i++) {
|
||||||
@ -220,8 +221,7 @@ static void mi_stats_print_bins(mi_stat_count_t* all, const mi_stat_count_t* bin
|
|||||||
|
|
||||||
static void mi_process_info(double* utime, double* stime, size_t* peak_rss, size_t* page_faults, size_t* page_reclaim, size_t* peak_commit);
|
static void mi_process_info(double* utime, double* stime, size_t* peak_rss, size_t* page_faults, size_t* page_reclaim, size_t* peak_commit);
|
||||||
|
|
||||||
static void _mi_stats_print(mi_stats_t* stats, double secs, FILE* out) mi_attr_noexcept {
|
static void _mi_stats_print(mi_stats_t* stats, double secs, mi_output_fun* out) mi_attr_noexcept {
|
||||||
if (out == NULL) out = stderr;
|
|
||||||
mi_print_header(out);
|
mi_print_header(out);
|
||||||
#if MI_STAT>1
|
#if MI_STAT>1
|
||||||
mi_stat_count_t normal = { 0,0,0,0 };
|
mi_stat_count_t normal = { 0,0,0,0 };
|
||||||
@ -304,16 +304,16 @@ void _mi_stats_done(mi_stats_t* stats) { // called from `mi_thread_done`
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void mi_stats_print_ex(mi_stats_t* stats, double secs, FILE* out) {
|
static void mi_stats_print_ex(mi_stats_t* stats, double secs, mi_output_fun* out) {
|
||||||
mi_stats_merge_from(stats);
|
mi_stats_merge_from(stats);
|
||||||
_mi_stats_print(&_mi_stats_main, secs, out);
|
_mi_stats_print(&_mi_stats_main, secs, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mi_stats_print(FILE* out) mi_attr_noexcept {
|
void mi_stats_print(mi_output_fun* out) mi_attr_noexcept {
|
||||||
mi_stats_print_ex(mi_stats_get_default(),_mi_clock_end(mi_time_start),out);
|
mi_stats_print_ex(mi_stats_get_default(),_mi_clock_end(mi_time_start),out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mi_thread_stats_print(FILE* out) mi_attr_noexcept {
|
void mi_thread_stats_print(mi_output_fun* out) mi_attr_noexcept {
|
||||||
_mi_stats_print(mi_stats_get_default(), _mi_clock_end(mi_time_start), out);
|
_mi_stats_print(mi_stats_get_default(), _mi_clock_end(mi_time_start), out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user