summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Evans <je@fb.com>2014-01-17 23:40:52 (GMT)
committerJason Evans <je@fb.com>2014-01-17 23:40:52 (GMT)
commit772163b4f3d8e9a12343e9215f6b070068507604 (patch)
treefca7a4cfaad0ba53a836ea57f12b5e9f1935d4a1
parenteefdd02e70ec1b9cf11920fcff585835dcbd766b (diff)
downloadjemalloc-772163b4f3d8e9a12343e9215f6b070068507604.zip
jemalloc-772163b4f3d8e9a12343e9215f6b070068507604.tar.gz
jemalloc-772163b4f3d8e9a12343e9215f6b070068507604.tar.bz2
Add heap profiling tests.
Fix a regression in prof_dump_ctx() due to an uninitized variable. This was caused by revision 4f37ef693e3d5903ce07dc0b61c0da320b35e3d9, so no releases are affected.
-rw-r--r--Makefile.in30
-rw-r--r--include/jemalloc/internal/private_symbols.txt2
-rw-r--r--include/jemalloc/internal/prof.h5
-rw-r--r--src/prof.c52
-rw-r--r--test/unit/prof_accum.c116
-rw-r--r--test/unit/prof_gdump.c56
-rw-r--r--test/unit/prof_idump.c51
7 files changed, 290 insertions, 22 deletions
diff --git a/Makefile.in b/Makefile.in
index 38ffbf4..67c4d5d 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -107,15 +107,27 @@ C_TESTLIB_SRCS := $(srcroot)test/src/math.c $(srcroot)test/src/mtx.c \
$(srcroot)test/src/SFMT.c $(srcroot)test/src/test.c \
$(srcroot)test/src/thd.c
C_UTIL_INTEGRATION_SRCS := $(srcroot)src/util.c
-TESTS_UNIT := $(srcroot)test/unit/bitmap.c $(srcroot)test/unit/ckh.c \
- $(srcroot)test/unit/hash.c $(srcroot)test/unit/junk.c \
- $(srcroot)test/unit/mallctl.c $(srcroot)test/unit/math.c \
- $(srcroot)test/unit/mq.c $(srcroot)test/unit/mtx.c \
- $(srcroot)test/unit/ql.c $(srcroot)test/unit/qr.c \
- $(srcroot)test/unit/quarantine.c $(srcroot)test/unit/rb.c \
- $(srcroot)test/unit/rtree.c $(srcroot)test/unit/SFMT.c \
- $(srcroot)test/unit/stats.c $(srcroot)test/unit/tsd.c \
- $(srcroot)test/unit/util.c $(srcroot)test/unit/zero.c
+TESTS_UNIT := $(srcroot)test/unit/bitmap.c \
+ $(srcroot)test/unit/ckh.c \
+ $(srcroot)test/unit/hash.c \
+ $(srcroot)test/unit/junk.c \
+ $(srcroot)test/unit/mallctl.c \
+ $(srcroot)test/unit/math.c \
+ $(srcroot)test/unit/mq.c \
+ $(srcroot)test/unit/mtx.c \
+ $(srcroot)test/unit/prof_accum.c \
+ $(srcroot)test/unit/prof_gdump.c \
+ $(srcroot)test/unit/prof_idump.c \
+ $(srcroot)test/unit/ql.c \
+ $(srcroot)test/unit/qr.c \
+ $(srcroot)test/unit/quarantine.c \
+ $(srcroot)test/unit/rb.c \
+ $(srcroot)test/unit/rtree.c \
+ $(srcroot)test/unit/SFMT.c \
+ $(srcroot)test/unit/stats.c \
+ $(srcroot)test/unit/tsd.c \
+ $(srcroot)test/unit/util.c \
+ $(srcroot)test/unit/zero.c
TESTS_INTEGRATION := $(srcroot)test/integration/aligned_alloc.c \
$(srcroot)test/integration/allocated.c \
$(srcroot)test/integration/mallocx.c \
diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt
index 6cc811d..1e64ed5 100644
--- a/include/jemalloc/internal/private_symbols.txt
+++ b/include/jemalloc/internal/private_symbols.txt
@@ -288,8 +288,10 @@ prof_backtrace
prof_boot0
prof_boot1
prof_boot2
+prof_bt_count
prof_ctx_get
prof_ctx_set
+prof_dump_open
prof_free
prof_gdump
prof_idump
diff --git a/include/jemalloc/internal/prof.h b/include/jemalloc/internal/prof.h
index 566739b..db056fc 100644
--- a/include/jemalloc/internal/prof.h
+++ b/include/jemalloc/internal/prof.h
@@ -225,6 +225,11 @@ extern bool prof_promote;
void bt_init(prof_bt_t *bt, void **vec);
void prof_backtrace(prof_bt_t *bt, unsigned nignore);
prof_thr_cnt_t *prof_lookup(prof_bt_t *bt);
+#ifdef JEMALLOC_JET
+size_t prof_bt_count(void);
+typedef int (prof_dump_open_t)(bool, const char *);
+extern prof_dump_open_t *prof_dump_open;
+#endif
void prof_idump(void);
bool prof_mdump(const char *filename);
void prof_gdump(void);
diff --git a/src/prof.c b/src/prof.c
index 0d65212..1d8ccbd 100644
--- a/src/prof.c
+++ b/src/prof.c
@@ -646,24 +646,49 @@ prof_lookup(prof_bt_t *bt)
return (ret.p);
}
-static bool
+#ifdef JEMALLOC_JET
+size_t
+prof_bt_count(void)
+{
+ size_t bt_count;
+ prof_tdata_t *prof_tdata;
+
+ prof_tdata = prof_tdata_get(false);
+ if ((uintptr_t)prof_tdata <= (uintptr_t)PROF_TDATA_STATE_MAX)
+ return (0);
+
+ prof_enter(prof_tdata);
+ bt_count = ckh_count(&bt2ctx);
+ prof_leave(prof_tdata);
+
+ return (bt_count);
+}
+#endif
+
+#ifdef JEMALLOC_JET
+#undef prof_dump_open
+#define prof_dump_open JEMALLOC_N(prof_dump_open_impl)
+#endif
+static int
prof_dump_open(bool propagate_err, const char *filename)
{
+ int fd;
- prof_dump_fd = creat(filename, 0644);
- if (prof_dump_fd == -1) {
- if (propagate_err == false) {
- malloc_printf(
- "<jemalloc>: creat(\"%s\"), 0644) failed\n",
- filename);
- if (opt_abort)
- abort();
- }
- return (true);
+ fd = creat(filename, 0644);
+ if (fd == -1 && propagate_err == false) {
+ malloc_printf("<jemalloc>: creat(\"%s\"), 0644) failed\n",
+ filename);
+ if (opt_abort)
+ abort();
}
- return (false);
+ return (fd);
}
+#ifdef JEMALLOC_JET
+#undef prof_dump_open
+#define prof_dump_open JEMALLOC_N(prof_dump_open)
+prof_dump_open_t *prof_dump_open = JEMALLOC_N(prof_dump_open_impl);
+#endif
static bool
prof_dump_flush(bool propagate_err)
@@ -895,6 +920,7 @@ prof_dump_ctx(bool propagate_err, prof_ctx_t *ctx, const prof_bt_t *bt,
goto label_return;
}
+ ret = false;
label_return:
prof_dump_ctx_cleanup_locked(ctx, ctx_ql);
malloc_mutex_unlock(ctx->lock);
@@ -995,7 +1021,7 @@ prof_dump(bool propagate_err, const char *filename, bool leakcheck)
prof_leave(prof_tdata);
/* Create dump file. */
- if (prof_dump_open(propagate_err, filename))
+ if ((prof_dump_fd = prof_dump_open(propagate_err, filename)) == -1)
goto label_open_close_error;
/* Dump profile header. */
diff --git a/test/unit/prof_accum.c b/test/unit/prof_accum.c
new file mode 100644
index 0000000..b5f1c8d
--- /dev/null
+++ b/test/unit/prof_accum.c
@@ -0,0 +1,116 @@
+#include "test/jemalloc_test.h"
+
+#define NTHREADS 4
+#define NALLOCS_PER_THREAD 50
+#define DUMP_INTERVAL 1
+#define BT_COUNT_CHECK_INTERVAL 5
+
+#ifdef JEMALLOC_PROF
+const char *malloc_conf =
+ "prof:true,prof_accum:true,prof_active:false,lg_prof_sample:0";
+#endif
+
+static int
+prof_dump_open_intercept(bool propagate_err, const char *filename)
+{
+ int fd;
+
+ fd = open("/dev/null", O_WRONLY);
+ assert_d_ne(fd, -1, "Unexpected open() failure");
+
+ return (fd);
+}
+
+#define alloc_n_proto(n) \
+static void *alloc_##n(unsigned bits);
+
+#define alloc_n_gen(n) \
+static void * \
+alloc_##n(unsigned bits) \
+{ \
+ \
+ if (bits == 0) { \
+ void *p = mallocx(1, 0); \
+ assert_ptr_not_null(p, "Unexpected mallocx() failure"); \
+ return (p); \
+ } \
+ \
+ switch (bits & 0x1U) { \
+ case 0: return (alloc_0(bits >> 1)); \
+ case 1: return (alloc_1(bits >> 1)); \
+ default: not_reached(); \
+ } \
+}
+alloc_n_proto(0)
+alloc_n_proto(1)
+alloc_n_gen(0)
+alloc_n_gen(1)
+
+static void *
+alloc_from_permuted_backtrace(unsigned thd_ind, unsigned iteration)
+{
+
+ return (alloc_0(thd_ind*NALLOCS_PER_THREAD + iteration));
+}
+
+static void *
+thd_start(void *varg)
+{
+ unsigned thd_ind = *(unsigned *)varg;
+ size_t bt_count_prev, bt_count;
+ unsigned i_prev, i;
+
+ i_prev = 0;
+ bt_count_prev = 0;
+ for (i = 0; i < NALLOCS_PER_THREAD; i++) {
+ void *p = alloc_from_permuted_backtrace(thd_ind, i);
+ dallocx(p, 0);
+ if (i % DUMP_INTERVAL == 0) {
+ assert_d_eq(mallctl("prof.dump", NULL, NULL, NULL, 0),
+ 0, "Unexpected error while dumping heap profile");
+ }
+
+ if (i % BT_COUNT_CHECK_INTERVAL == 0 ||
+ i+1 == NALLOCS_PER_THREAD) {
+ bt_count = prof_bt_count();
+ assert_zu_le(bt_count_prev+(i-i_prev), bt_count,
+ "Expected larger bactrace count increase");
+ i_prev = i;
+ bt_count_prev = bt_count;
+ }
+ }
+
+ return (NULL);
+}
+
+TEST_BEGIN(test_idump)
+{
+ bool active;
+ thd_t thds[NTHREADS];
+ unsigned thd_args[NTHREADS];
+ unsigned i;
+
+ test_skip_if(!config_prof);
+
+ active = true;
+ assert_d_eq(mallctl("prof.active", NULL, NULL, &active, sizeof(active)),
+ 0, "Unexpected mallctl failure while activating profiling");
+
+ prof_dump_open = prof_dump_open_intercept;
+
+ for (i = 0; i < NTHREADS; i++) {
+ thd_args[i] = i;
+ thd_create(&thds[i], thd_start, (void *)&thd_args[i]);
+ }
+ for (i = 0; i < NTHREADS; i++)
+ thd_join(thds[i], NULL);
+}
+TEST_END
+
+int
+main(void)
+{
+
+ return (test(
+ test_idump));
+}
diff --git a/test/unit/prof_gdump.c b/test/unit/prof_gdump.c
new file mode 100644
index 0000000..a00b105
--- /dev/null
+++ b/test/unit/prof_gdump.c
@@ -0,0 +1,56 @@
+#include "test/jemalloc_test.h"
+
+#ifdef JEMALLOC_PROF
+const char *malloc_conf = "prof:true,prof_active:false,prof_gdump:true";
+#endif
+
+static bool did_prof_dump_open;
+
+static int
+prof_dump_open_intercept(bool propagate_err, const char *filename)
+{
+ int fd;
+
+ did_prof_dump_open = true;
+
+ fd = open("/dev/null", O_WRONLY);
+ assert_d_ne(fd, -1, "Unexpected open() failure");
+
+ return (fd);
+}
+
+TEST_BEGIN(test_gdump)
+{
+ bool active;
+ void *p, *q;
+
+ test_skip_if(!config_prof);
+
+ active = true;
+ assert_d_eq(mallctl("prof.active", NULL, NULL, &active, sizeof(active)),
+ 0, "Unexpected mallctl failure while activating profiling");
+
+ prof_dump_open = prof_dump_open_intercept;
+
+ did_prof_dump_open = false;
+ p = mallocx(chunksize, 0);
+ assert_ptr_not_null(p, "Unexpected mallocx() failure");
+ assert_true(did_prof_dump_open, "Expected a profile dump");
+
+ did_prof_dump_open = false;
+ q = mallocx(chunksize, 0);
+ assert_ptr_not_null(q, "Unexpected mallocx() failure");
+ assert_true(did_prof_dump_open, "Expected a profile dump");
+
+ dallocx(p, 0);
+ dallocx(q, 0);
+}
+TEST_END
+
+int
+main(void)
+{
+
+ return (test(
+ test_gdump));
+}
diff --git a/test/unit/prof_idump.c b/test/unit/prof_idump.c
new file mode 100644
index 0000000..bdea53e
--- /dev/null
+++ b/test/unit/prof_idump.c
@@ -0,0 +1,51 @@
+#include "test/jemalloc_test.h"
+
+#ifdef JEMALLOC_PROF
+const char *malloc_conf =
+ "prof:true,prof_accum:true,prof_active:false,lg_prof_sample:0,"
+ "lg_prof_interval:0";
+#endif
+
+static bool did_prof_dump_open;
+
+static int
+prof_dump_open_intercept(bool propagate_err, const char *filename)
+{
+ int fd;
+
+ did_prof_dump_open = true;
+
+ fd = open("/dev/null", O_WRONLY);
+ assert_d_ne(fd, -1, "Unexpected open() failure");
+
+ return (fd);
+}
+
+TEST_BEGIN(test_idump)
+{
+ bool active;
+ void *p;
+
+ test_skip_if(!config_prof);
+
+ active = true;
+ assert_d_eq(mallctl("prof.active", NULL, NULL, &active, sizeof(active)),
+ 0, "Unexpected mallctl failure while activating profiling");
+
+ prof_dump_open = prof_dump_open_intercept;
+
+ did_prof_dump_open = false;
+ p = mallocx(1, 0);
+ assert_ptr_not_null(p, "Unexpected mallocx() failure");
+ dallocx(p, 0);
+ assert_true(did_prof_dump_open, "Expected a profile dump");
+}
+TEST_END
+
+int
+main(void)
+{
+
+ return (test(
+ test_idump));
+}