Home | History | Annotate | Line # | Download | only in unit
      1      1.1  christos #include "test/jemalloc_test.h"
      2      1.1  christos 
      3  1.1.1.2  christos #include "jemalloc/internal/prof_data.h"
      4  1.1.1.2  christos #include "jemalloc/internal/prof_sys.h"
      5  1.1.1.2  christos 
      6      1.1  christos static int
      7  1.1.1.2  christos prof_dump_open_file_intercept(const char *filename, int mode) {
      8      1.1  christos 	int fd;
      9      1.1  christos 
     10      1.1  christos 	fd = open("/dev/null", O_WRONLY);
     11      1.1  christos 	assert_d_ne(fd, -1, "Unexpected open() failure");
     12      1.1  christos 
     13      1.1  christos 	return fd;
     14      1.1  christos }
     15      1.1  christos 
     16      1.1  christos static void
     17      1.1  christos set_prof_active(bool active) {
     18  1.1.1.2  christos 	expect_d_eq(mallctl("prof.active", NULL, NULL, (void *)&active,
     19      1.1  christos 	    sizeof(active)), 0, "Unexpected mallctl failure");
     20      1.1  christos }
     21      1.1  christos 
     22      1.1  christos static size_t
     23      1.1  christos get_lg_prof_sample(void) {
     24  1.1.1.2  christos 	size_t ret;
     25      1.1  christos 	size_t sz = sizeof(size_t);
     26      1.1  christos 
     27  1.1.1.2  christos 	expect_d_eq(mallctl("prof.lg_sample", (void *)&ret, &sz, NULL, 0), 0,
     28      1.1  christos 	    "Unexpected mallctl failure while reading profiling sample rate");
     29  1.1.1.2  christos 	return ret;
     30      1.1  christos }
     31      1.1  christos 
     32      1.1  christos static void
     33  1.1.1.2  christos do_prof_reset(size_t lg_prof_sample_input) {
     34  1.1.1.2  christos 	expect_d_eq(mallctl("prof.reset", NULL, NULL,
     35  1.1.1.2  christos 	    (void *)&lg_prof_sample_input, sizeof(size_t)), 0,
     36      1.1  christos 	    "Unexpected mallctl failure while resetting profile data");
     37  1.1.1.2  christos 	expect_zu_eq(lg_prof_sample_input, get_lg_prof_sample(),
     38      1.1  christos 	    "Expected profile sample rate change");
     39      1.1  christos }
     40      1.1  christos 
     41      1.1  christos TEST_BEGIN(test_prof_reset_basic) {
     42  1.1.1.2  christos 	size_t lg_prof_sample_orig, lg_prof_sample_cur, lg_prof_sample_next;
     43      1.1  christos 	size_t sz;
     44      1.1  christos 	unsigned i;
     45      1.1  christos 
     46      1.1  christos 	test_skip_if(!config_prof);
     47      1.1  christos 
     48      1.1  christos 	sz = sizeof(size_t);
     49  1.1.1.2  christos 	expect_d_eq(mallctl("opt.lg_prof_sample", (void *)&lg_prof_sample_orig,
     50      1.1  christos 	    &sz, NULL, 0), 0,
     51      1.1  christos 	    "Unexpected mallctl failure while reading profiling sample rate");
     52  1.1.1.2  christos 	expect_zu_eq(lg_prof_sample_orig, 0,
     53      1.1  christos 	    "Unexpected profiling sample rate");
     54  1.1.1.2  christos 	lg_prof_sample_cur = get_lg_prof_sample();
     55  1.1.1.2  christos 	expect_zu_eq(lg_prof_sample_orig, lg_prof_sample_cur,
     56      1.1  christos 	    "Unexpected disagreement between \"opt.lg_prof_sample\" and "
     57      1.1  christos 	    "\"prof.lg_sample\"");
     58      1.1  christos 
     59      1.1  christos 	/* Test simple resets. */
     60      1.1  christos 	for (i = 0; i < 2; i++) {
     61  1.1.1.2  christos 		expect_d_eq(mallctl("prof.reset", NULL, NULL, NULL, 0), 0,
     62      1.1  christos 		    "Unexpected mallctl failure while resetting profile data");
     63  1.1.1.2  christos 		lg_prof_sample_cur = get_lg_prof_sample();
     64  1.1.1.2  christos 		expect_zu_eq(lg_prof_sample_orig, lg_prof_sample_cur,
     65      1.1  christos 		    "Unexpected profile sample rate change");
     66      1.1  christos 	}
     67      1.1  christos 
     68      1.1  christos 	/* Test resets with prof.lg_sample changes. */
     69      1.1  christos 	lg_prof_sample_next = 1;
     70      1.1  christos 	for (i = 0; i < 2; i++) {
     71      1.1  christos 		do_prof_reset(lg_prof_sample_next);
     72  1.1.1.2  christos 		lg_prof_sample_cur = get_lg_prof_sample();
     73  1.1.1.2  christos 		expect_zu_eq(lg_prof_sample_cur, lg_prof_sample_next,
     74      1.1  christos 		    "Expected profile sample rate change");
     75      1.1  christos 		lg_prof_sample_next = lg_prof_sample_orig;
     76      1.1  christos 	}
     77      1.1  christos 
     78      1.1  christos 	/* Make sure the test code restored prof.lg_sample. */
     79  1.1.1.2  christos 	lg_prof_sample_cur = get_lg_prof_sample();
     80  1.1.1.2  christos 	expect_zu_eq(lg_prof_sample_orig, lg_prof_sample_cur,
     81      1.1  christos 	    "Unexpected disagreement between \"opt.lg_prof_sample\" and "
     82      1.1  christos 	    "\"prof.lg_sample\"");
     83      1.1  christos }
     84      1.1  christos TEST_END
     85      1.1  christos 
     86      1.1  christos TEST_BEGIN(test_prof_reset_cleanup) {
     87      1.1  christos 	test_skip_if(!config_prof);
     88      1.1  christos 
     89      1.1  christos 	set_prof_active(true);
     90      1.1  christos 
     91  1.1.1.2  christos 	expect_zu_eq(prof_bt_count(), 0, "Expected 0 backtraces");
     92  1.1.1.2  christos 	void *p = mallocx(1, 0);
     93  1.1.1.2  christos 	expect_ptr_not_null(p, "Unexpected mallocx() failure");
     94  1.1.1.2  christos 	expect_zu_eq(prof_bt_count(), 1, "Expected 1 backtrace");
     95  1.1.1.2  christos 
     96  1.1.1.2  christos 	prof_cnt_t cnt_all;
     97  1.1.1.2  christos 	prof_cnt_all(&cnt_all);
     98  1.1.1.2  christos 	expect_u64_eq(cnt_all.curobjs, 1, "Expected 1 allocation");
     99      1.1  christos 
    100  1.1.1.2  christos 	expect_d_eq(mallctl("prof.reset", NULL, NULL, NULL, 0), 0,
    101      1.1  christos 	    "Unexpected error while resetting heap profile data");
    102  1.1.1.2  christos 	prof_cnt_all(&cnt_all);
    103  1.1.1.2  christos 	expect_u64_eq(cnt_all.curobjs, 0, "Expected 0 allocations");
    104  1.1.1.2  christos 	expect_zu_eq(prof_bt_count(), 1, "Expected 1 backtrace");
    105      1.1  christos 
    106      1.1  christos 	dallocx(p, 0);
    107  1.1.1.2  christos 	expect_zu_eq(prof_bt_count(), 0, "Expected 0 backtraces");
    108      1.1  christos 
    109      1.1  christos 	set_prof_active(false);
    110      1.1  christos }
    111      1.1  christos TEST_END
    112      1.1  christos 
    113      1.1  christos #define NTHREADS		4
    114      1.1  christos #define NALLOCS_PER_THREAD	(1U << 13)
    115      1.1  christos #define OBJ_RING_BUF_COUNT	1531
    116      1.1  christos #define RESET_INTERVAL		(1U << 10)
    117      1.1  christos #define DUMP_INTERVAL		3677
    118      1.1  christos static void *
    119      1.1  christos thd_start(void *varg) {
    120      1.1  christos 	unsigned thd_ind = *(unsigned *)varg;
    121      1.1  christos 	unsigned i;
    122      1.1  christos 	void *objs[OBJ_RING_BUF_COUNT];
    123      1.1  christos 
    124      1.1  christos 	memset(objs, 0, sizeof(objs));
    125      1.1  christos 
    126      1.1  christos 	for (i = 0; i < NALLOCS_PER_THREAD; i++) {
    127      1.1  christos 		if (i % RESET_INTERVAL == 0) {
    128  1.1.1.2  christos 			expect_d_eq(mallctl("prof.reset", NULL, NULL, NULL, 0),
    129      1.1  christos 			    0, "Unexpected error while resetting heap profile "
    130      1.1  christos 			    "data");
    131      1.1  christos 		}
    132      1.1  christos 
    133      1.1  christos 		if (i % DUMP_INTERVAL == 0) {
    134  1.1.1.2  christos 			expect_d_eq(mallctl("prof.dump", NULL, NULL, NULL, 0),
    135      1.1  christos 			    0, "Unexpected error while dumping heap profile");
    136      1.1  christos 		}
    137      1.1  christos 
    138      1.1  christos 		{
    139      1.1  christos 			void **pp = &objs[i % OBJ_RING_BUF_COUNT];
    140      1.1  christos 			if (*pp != NULL) {
    141      1.1  christos 				dallocx(*pp, 0);
    142      1.1  christos 				*pp = NULL;
    143      1.1  christos 			}
    144      1.1  christos 			*pp = btalloc(1, thd_ind*NALLOCS_PER_THREAD + i);
    145  1.1.1.2  christos 			expect_ptr_not_null(*pp,
    146      1.1  christos 			    "Unexpected btalloc() failure");
    147      1.1  christos 		}
    148      1.1  christos 	}
    149      1.1  christos 
    150      1.1  christos 	/* Clean up any remaining objects. */
    151      1.1  christos 	for (i = 0; i < OBJ_RING_BUF_COUNT; i++) {
    152      1.1  christos 		void **pp = &objs[i % OBJ_RING_BUF_COUNT];
    153      1.1  christos 		if (*pp != NULL) {
    154      1.1  christos 			dallocx(*pp, 0);
    155      1.1  christos 			*pp = NULL;
    156      1.1  christos 		}
    157      1.1  christos 	}
    158      1.1  christos 
    159      1.1  christos 	return NULL;
    160      1.1  christos }
    161      1.1  christos 
    162      1.1  christos TEST_BEGIN(test_prof_reset) {
    163      1.1  christos 	size_t lg_prof_sample_orig;
    164      1.1  christos 	thd_t thds[NTHREADS];
    165      1.1  christos 	unsigned thd_args[NTHREADS];
    166      1.1  christos 	unsigned i;
    167      1.1  christos 	size_t bt_count, tdata_count;
    168      1.1  christos 
    169      1.1  christos 	test_skip_if(!config_prof);
    170      1.1  christos 
    171      1.1  christos 	bt_count = prof_bt_count();
    172  1.1.1.2  christos 	expect_zu_eq(bt_count, 0,
    173      1.1  christos 	    "Unexpected pre-existing tdata structures");
    174      1.1  christos 	tdata_count = prof_tdata_count();
    175      1.1  christos 
    176      1.1  christos 	lg_prof_sample_orig = get_lg_prof_sample();
    177      1.1  christos 	do_prof_reset(5);
    178      1.1  christos 
    179      1.1  christos 	set_prof_active(true);
    180      1.1  christos 
    181      1.1  christos 	for (i = 0; i < NTHREADS; i++) {
    182      1.1  christos 		thd_args[i] = i;
    183      1.1  christos 		thd_create(&thds[i], thd_start, (void *)&thd_args[i]);
    184      1.1  christos 	}
    185      1.1  christos 	for (i = 0; i < NTHREADS; i++) {
    186      1.1  christos 		thd_join(thds[i], NULL);
    187      1.1  christos 	}
    188      1.1  christos 
    189  1.1.1.2  christos 	expect_zu_eq(prof_bt_count(), bt_count,
    190      1.1  christos 	    "Unexpected bactrace count change");
    191  1.1.1.2  christos 	expect_zu_eq(prof_tdata_count(), tdata_count,
    192      1.1  christos 	    "Unexpected remaining tdata structures");
    193      1.1  christos 
    194      1.1  christos 	set_prof_active(false);
    195      1.1  christos 
    196      1.1  christos 	do_prof_reset(lg_prof_sample_orig);
    197      1.1  christos }
    198      1.1  christos TEST_END
    199      1.1  christos #undef NTHREADS
    200      1.1  christos #undef NALLOCS_PER_THREAD
    201      1.1  christos #undef OBJ_RING_BUF_COUNT
    202      1.1  christos #undef RESET_INTERVAL
    203      1.1  christos #undef DUMP_INTERVAL
    204      1.1  christos 
    205      1.1  christos /* Test sampling at the same allocation site across resets. */
    206      1.1  christos #define NITER 10
    207      1.1  christos TEST_BEGIN(test_xallocx) {
    208      1.1  christos 	size_t lg_prof_sample_orig;
    209      1.1  christos 	unsigned i;
    210      1.1  christos 	void *ptrs[NITER];
    211      1.1  christos 
    212      1.1  christos 	test_skip_if(!config_prof);
    213      1.1  christos 
    214      1.1  christos 	lg_prof_sample_orig = get_lg_prof_sample();
    215      1.1  christos 	set_prof_active(true);
    216      1.1  christos 
    217      1.1  christos 	/* Reset profiling. */
    218      1.1  christos 	do_prof_reset(0);
    219      1.1  christos 
    220      1.1  christos 	for (i = 0; i < NITER; i++) {
    221      1.1  christos 		void *p;
    222      1.1  christos 		size_t sz, nsz;
    223      1.1  christos 
    224      1.1  christos 		/* Reset profiling. */
    225      1.1  christos 		do_prof_reset(0);
    226      1.1  christos 
    227      1.1  christos 		/* Allocate small object (which will be promoted). */
    228      1.1  christos 		p = ptrs[i] = mallocx(1, 0);
    229  1.1.1.2  christos 		expect_ptr_not_null(p, "Unexpected mallocx() failure");
    230      1.1  christos 
    231      1.1  christos 		/* Reset profiling. */
    232      1.1  christos 		do_prof_reset(0);
    233      1.1  christos 
    234      1.1  christos 		/* Perform successful xallocx(). */
    235      1.1  christos 		sz = sallocx(p, 0);
    236  1.1.1.2  christos 		expect_zu_eq(xallocx(p, sz, 0, 0), sz,
    237      1.1  christos 		    "Unexpected xallocx() failure");
    238      1.1  christos 
    239      1.1  christos 		/* Perform unsuccessful xallocx(). */
    240      1.1  christos 		nsz = nallocx(sz+1, 0);
    241  1.1.1.2  christos 		expect_zu_eq(xallocx(p, nsz, 0, 0), sz,
    242      1.1  christos 		    "Unexpected xallocx() success");
    243      1.1  christos 	}
    244      1.1  christos 
    245      1.1  christos 	for (i = 0; i < NITER; i++) {
    246      1.1  christos 		/* dallocx. */
    247      1.1  christos 		dallocx(ptrs[i], 0);
    248      1.1  christos 	}
    249      1.1  christos 
    250      1.1  christos 	set_prof_active(false);
    251      1.1  christos 	do_prof_reset(lg_prof_sample_orig);
    252      1.1  christos }
    253      1.1  christos TEST_END
    254      1.1  christos #undef NITER
    255      1.1  christos 
    256      1.1  christos int
    257      1.1  christos main(void) {
    258      1.1  christos 	/* Intercept dumping prior to running any tests. */
    259  1.1.1.2  christos 	prof_dump_open_file = prof_dump_open_file_intercept;
    260      1.1  christos 
    261      1.1  christos 	return test_no_reentrancy(
    262      1.1  christos 	    test_prof_reset_basic,
    263      1.1  christos 	    test_prof_reset_cleanup,
    264      1.1  christos 	    test_prof_reset,
    265      1.1  christos 	    test_xallocx);
    266      1.1  christos }
    267