diff options
author | Björn Gustavsson <bjorn@erlang.org> | 2017-10-13 13:28:25 +0200 |
---|---|---|
committer | Björn Gustavsson <bjorn@erlang.org> | 2017-10-18 14:05:00 +0200 |
commit | 360d26b21c169b0c88d6ca43265cbcfa3ce9ef74 (patch) | |
tree | 7476c8aaed61a5f788f635c2d46807df72bab6cc | |
parent | b73c4d012e122547c896f64d92ef9af3e531433e (diff) | |
download | erlang-360d26b21c169b0c88d6ca43265cbcfa3ce9ef74.tar.gz |
Buffer writing of crash dumps
Writing of crash dumps were done using unbuffered IO. This
is slow since many small writes are done.
Use a FILE* with an allocated buffer to obtain buffered IO.
I wrote a small test program that created 50000 binaries of 200 bytes
each and then created a crash dump. The crash dumping was an order of
magnitude faster with buffered IO than without.
-rw-r--r-- | erts/emulator/beam/break.c | 49 | ||||
-rw-r--r-- | erts/include/internal/erl_printf.h | 1 | ||||
-rw-r--r-- | erts/lib_src/common/erl_printf.c | 12 |
3 files changed, 51 insertions, 11 deletions
diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c index 76a0c5c716..8182e55006 100644 --- a/erts/emulator/beam/break.c +++ b/erts/emulator/beam/break.c @@ -58,6 +58,8 @@ static void dump_attributes(fmtfn_t to, void *to_arg, byte* ptr, int size); extern char* erts_system_version[]; +#define WRITE_BUFFER_SIZE (64*1024) + static void port_info(fmtfn_t to, void *to_arg) { @@ -677,18 +679,28 @@ bin_check(void) static Sint64 crash_dump_limit = ERTS_SINT64_MAX; static Sint64 crash_dump_written = 0; -static int crash_dump_limited_writer(void* vfdp, char* buf, size_t len) +typedef struct LimitedWriterInfo_ { + fmtfn_t to; + void* to_arg; +} LimitedWriterInfo; + +static int +crash_dump_limited_writer(void* vfdp, char* buf, size_t len) { const char stop_msg[] = "\n=abort:CRASH DUMP SIZE LIMIT REACHED\n"; + LimitedWriterInfo* lwi = (LimitedWriterInfo *) vfdp; crash_dump_written += len; if (crash_dump_written <= crash_dump_limit) { - return erts_write_fd(vfdp, buf, len); + return lwi->to(lwi->to_arg, buf, len); } len -= (crash_dump_written - crash_dump_limit); - erts_write_fd(vfdp, buf, len); - erts_write_fd(vfdp, (char*)stop_msg, sizeof(stop_msg)-1); + lwi->to(lwi->to_arg, buf, len); + lwi->to(lwi->to_arg, (char*)stop_msg, sizeof(stop_msg)-1); + if (lwi->to == &erts_write_fp) { + fclose((FILE *) lwi->to_arg); + } /* We assume that crash dump was called from erts_exit_vv() */ erts_exit_epilogue(); @@ -713,6 +725,9 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args) int i; fmtfn_t to = &erts_write_fd; void* to_arg; + FILE* fp = 0; + LimitedWriterInfo lwi; + static char* write_buffer; /* 'static' to avoid a leak warning in valgrind */ if (ERTS_SOMEONE_IS_CRASH_DUMPING) return; @@ -820,7 +835,28 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args) fd = open(dumpname,O_WRONLY | O_CREAT | O_TRUNC,0640); if (fd < 0) return; /* Can't create the crash dump, skip it */ - to_arg = (void*)&fd; + + /* + * Wrap into a FILE* so that we can use buffered output. Set an + * explicit buffer to make sure the first write does not fail because + * of a failure to allocate a buffer. + */ + write_buffer = (char *) erts_alloc_fnf(ERTS_ALC_T_TMP, WRITE_BUFFER_SIZE); + if (write_buffer && (fp = fdopen(fd, "w")) != NULL) { + setvbuf(fp, write_buffer, _IOFBF, WRITE_BUFFER_SIZE); + lwi.to = &erts_write_fp; + lwi.to_arg = (void*)fp; + } else { + lwi.to = &erts_write_fd; + lwi.to_arg = (void*)&fd; + } + if (to == &crash_dump_limited_writer) { + to_arg = (void *) &lwi; + } else { + to = lwi.to; + to_arg = lwi.to_arg; + } + time(&now); erts_cbprintf(to, to_arg, "=erl_crash_dump:0.3\n%s", ctime(&now)); @@ -932,6 +968,9 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args) } erts_cbprintf(to, to_arg, "=end\n"); + if (fp) { + fclose(fp); + } close(fd); erts_fprintf(stderr,"done\n"); } diff --git a/erts/include/internal/erl_printf.h b/erts/include/internal/erl_printf.h index f180a53f18..7e9807f6a8 100644 --- a/erts/include/internal/erl_printf.h +++ b/erts/include/internal/erl_printf.h @@ -44,6 +44,7 @@ struct erts_dsprintf_buf_t_ { typedef int (*fmtfn_t)(void*, char*, size_t); int erts_write_fd(void *vfdp, char* buf, size_t len); +int erts_write_fp(void *vfdp, char* buf, size_t len); int erts_write_ds(void *vdsbufp, char* buf, size_t len); int erts_printf(const char *, ...); diff --git a/erts/lib_src/common/erl_printf.c b/erts/lib_src/common/erl_printf.c index 7781fc2196..3b073bcd1b 100644 --- a/erts/lib_src/common/erl_printf.c +++ b/erts/lib_src/common/erl_printf.c @@ -147,8 +147,8 @@ write_f_add_cr(void *vfp, char* buf, size_t len) return len; } -static int -write_f(void *vfp, char* buf, size_t len) +int +erts_write_fp(void *vfp, char* buf, size_t len) { ASSERT(vfp); #ifdef PUTC_ON_SMALL_WRITES @@ -257,7 +257,7 @@ erts_printf(const char *format, ...) FLOCKFILE(stdout); res = erts_printf_format(erts_printf_add_cr_to_stdout ? write_f_add_cr - : write_f, + : erts_write_fp, (void *) stdout, (char *) format, arglist); @@ -285,7 +285,7 @@ erts_fprintf(FILE *filep, const char *format, ...) else if (erts_printf_add_cr_to_stderr && filep == stderr) fmt_f = write_f_add_cr; else - fmt_f = write_f; + fmt_f = erts_write_fp; FLOCKFILE(filep); res = erts_printf_format(fmt_f,(void *)filep,(char *)format,arglist); FUNLOCKFILE(filep); @@ -390,7 +390,7 @@ erts_vprintf(const char *format, va_list arglist) errno = 0; res = erts_printf_format(erts_printf_add_cr_to_stdout ? write_f_add_cr - : write_f, + : erts_write_fp, (void *) stdout, (char *) format, arglist); @@ -414,7 +414,7 @@ erts_vfprintf(FILE *filep, const char *format, va_list arglist) else if (erts_printf_add_cr_to_stderr && filep == stderr) fmt_f = write_f_add_cr; else - fmt_f = write_f; + fmt_f = erts_write_fp; res = erts_printf_format(fmt_f,(void *)filep,(char *)format,arglist); } return res; |