aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2017-10-13 13:28:25 +0200
committerBjörn Gustavsson <[email protected]>2017-10-18 14:05:00 +0200
commit360d26b21c169b0c88d6ca43265cbcfa3ce9ef74 (patch)
tree7476c8aaed61a5f788f635c2d46807df72bab6cc
parentb73c4d012e122547c896f64d92ef9af3e531433e (diff)
downloadotp-360d26b21c169b0c88d6ca43265cbcfa3ce9ef74.tar.gz
otp-360d26b21c169b0c88d6ca43265cbcfa3ce9ef74.tar.bz2
otp-360d26b21c169b0c88d6ca43265cbcfa3ce9ef74.zip
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.c49
-rw-r--r--erts/include/internal/erl_printf.h1
-rw-r--r--erts/lib_src/common/erl_printf.c12
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;