Home | History | Annotate | Line # | Download | only in unit
      1      1.1  christos #include "test/jemalloc_test.h"
      2      1.1  christos 
      3      1.1  christos #include "jemalloc/internal/fxp.h"
      4      1.1  christos 
      5      1.1  christos static double
      6      1.1  christos fxp2double(fxp_t a) {
      7      1.1  christos 	double intpart = (double)(a >> 16);
      8      1.1  christos 	double fracpart = (double)(a & ((1U << 16) - 1)) / (1U << 16);
      9      1.1  christos 	return intpart + fracpart;
     10      1.1  christos }
     11      1.1  christos 
     12      1.1  christos /* Is a close to b? */
     13      1.1  christos static bool
     14      1.1  christos double_close(double a, double b) {
     15      1.1  christos 	/*
     16      1.1  christos 	 * Our implementation doesn't try for precision.  Correspondingly, don't
     17      1.1  christos 	 * enforce it too strenuously here; accept values that are close in
     18      1.1  christos 	 * either relative or absolute terms.
     19      1.1  christos 	 */
     20      1.1  christos 	return fabs(a - b) < 0.01 || fabs(a - b) / a < 0.01;
     21      1.1  christos }
     22      1.1  christos 
     23      1.1  christos static bool
     24      1.1  christos fxp_close(fxp_t a, fxp_t b) {
     25      1.1  christos 	return double_close(fxp2double(a), fxp2double(b));
     26      1.1  christos }
     27      1.1  christos 
     28      1.1  christos static fxp_t
     29      1.1  christos xparse_fxp(const char *str) {
     30      1.1  christos 	fxp_t result;
     31  1.1.1.2  christos 	bool  err = fxp_parse(&result, str, NULL);
     32      1.1  christos 	assert_false(err, "Invalid fxp string: %s", str);
     33      1.1  christos 	return result;
     34      1.1  christos }
     35      1.1  christos 
     36      1.1  christos static void
     37      1.1  christos expect_parse_accurate(const char *str, const char *parse_str) {
     38      1.1  christos 	double true_val = strtod(str, NULL);
     39  1.1.1.2  christos 	fxp_t  fxp_val;
     40  1.1.1.2  christos 	char  *end;
     41  1.1.1.2  christos 	bool   err = fxp_parse(&fxp_val, parse_str, &end);
     42      1.1  christos 	expect_false(err, "Unexpected parse failure");
     43  1.1.1.2  christos 	expect_ptr_eq(
     44  1.1.1.2  christos 	    parse_str + strlen(str), end, "Didn't parse whole string");
     45  1.1.1.2  christos 	expect_true(
     46  1.1.1.2  christos 	    double_close(fxp2double(fxp_val), true_val), "Misparsed %s", str);
     47      1.1  christos }
     48      1.1  christos 
     49      1.1  christos static void
     50      1.1  christos parse_valid_trial(const char *str) {
     51      1.1  christos 	/* The value it parses should be correct. */
     52      1.1  christos 	expect_parse_accurate(str, str);
     53      1.1  christos 	char buf[100];
     54      1.1  christos 	snprintf(buf, sizeof(buf), "%swith_some_trailing_text", str);
     55      1.1  christos 	expect_parse_accurate(str, buf);
     56      1.1  christos 	snprintf(buf, sizeof(buf), "%s with a space", str);
     57      1.1  christos 	expect_parse_accurate(str, buf);
     58      1.1  christos 	snprintf(buf, sizeof(buf), "%s,in_a_malloc_conf_string:1", str);
     59      1.1  christos 	expect_parse_accurate(str, buf);
     60      1.1  christos }
     61      1.1  christos 
     62      1.1  christos TEST_BEGIN(test_parse_valid) {
     63      1.1  christos 	parse_valid_trial("0");
     64      1.1  christos 	parse_valid_trial("1");
     65      1.1  christos 	parse_valid_trial("2");
     66      1.1  christos 	parse_valid_trial("100");
     67      1.1  christos 	parse_valid_trial("345");
     68      1.1  christos 	parse_valid_trial("00000000123");
     69      1.1  christos 	parse_valid_trial("00000000987");
     70      1.1  christos 
     71      1.1  christos 	parse_valid_trial("0.0");
     72      1.1  christos 	parse_valid_trial("0.00000000000456456456");
     73      1.1  christos 	parse_valid_trial("100.00000000000456456456");
     74      1.1  christos 
     75      1.1  christos 	parse_valid_trial("123.1");
     76      1.1  christos 	parse_valid_trial("123.01");
     77      1.1  christos 	parse_valid_trial("123.001");
     78      1.1  christos 	parse_valid_trial("123.0001");
     79      1.1  christos 	parse_valid_trial("123.00001");
     80      1.1  christos 	parse_valid_trial("123.000001");
     81      1.1  christos 	parse_valid_trial("123.0000001");
     82      1.1  christos 
     83      1.1  christos 	parse_valid_trial(".0");
     84      1.1  christos 	parse_valid_trial(".1");
     85      1.1  christos 	parse_valid_trial(".01");
     86      1.1  christos 	parse_valid_trial(".001");
     87      1.1  christos 	parse_valid_trial(".0001");
     88      1.1  christos 	parse_valid_trial(".00001");
     89      1.1  christos 	parse_valid_trial(".000001");
     90      1.1  christos 
     91      1.1  christos 	parse_valid_trial(".1");
     92      1.1  christos 	parse_valid_trial(".10");
     93      1.1  christos 	parse_valid_trial(".100");
     94      1.1  christos 	parse_valid_trial(".1000");
     95      1.1  christos 	parse_valid_trial(".100000");
     96      1.1  christos }
     97      1.1  christos TEST_END
     98      1.1  christos 
     99      1.1  christos static void
    100      1.1  christos expect_parse_failure(const char *str) {
    101      1.1  christos 	fxp_t result = FXP_INIT_INT(333);
    102      1.1  christos 	char *end = (void *)0x123;
    103  1.1.1.2  christos 	bool  err = fxp_parse(&result, str, &end);
    104      1.1  christos 	expect_true(err, "Expected a parse error on: %s", str);
    105  1.1.1.2  christos 	expect_ptr_eq(
    106  1.1.1.2  christos 	    (void *)0x123, end, "Parse error shouldn't change results");
    107  1.1.1.2  christos 	expect_u32_eq(
    108  1.1.1.2  christos 	    result, FXP_INIT_INT(333), "Parse error shouldn't change results");
    109      1.1  christos }
    110      1.1  christos 
    111      1.1  christos TEST_BEGIN(test_parse_invalid) {
    112      1.1  christos 	expect_parse_failure("123.");
    113      1.1  christos 	expect_parse_failure("3.a");
    114      1.1  christos 	expect_parse_failure(".a");
    115      1.1  christos 	expect_parse_failure("a.1");
    116      1.1  christos 	expect_parse_failure("a");
    117      1.1  christos 	/* A valid string, but one that overflows. */
    118      1.1  christos 	expect_parse_failure("123456789");
    119      1.1  christos 	expect_parse_failure("0000000123456789");
    120      1.1  christos 	expect_parse_failure("1000000");
    121      1.1  christos }
    122      1.1  christos TEST_END
    123      1.1  christos 
    124      1.1  christos static void
    125      1.1  christos expect_init_percent(unsigned percent, const char *str) {
    126      1.1  christos 	fxp_t result_init = FXP_INIT_PERCENT(percent);
    127      1.1  christos 	fxp_t result_parse = xparse_fxp(str);
    128      1.1  christos 	expect_u32_eq(result_init, result_parse,
    129      1.1  christos 	    "Expect representations of FXP_INIT_PERCENT(%u) and "
    130      1.1  christos 	    "fxp_parse(\"%s\") to be equal; got %x and %x",
    131      1.1  christos 	    percent, str, result_init, result_parse);
    132      1.1  christos }
    133      1.1  christos 
    134      1.1  christos /*
    135      1.1  christos  * Every other test uses either parsing or FXP_INIT_INT; it gets tested in those
    136      1.1  christos  * ways.  We need a one-off for the percent-based initialization, though.
    137      1.1  christos  */
    138      1.1  christos TEST_BEGIN(test_init_percent) {
    139      1.1  christos 	expect_init_percent(100, "1");
    140      1.1  christos 	expect_init_percent(75, ".75");
    141      1.1  christos 	expect_init_percent(1, ".01");
    142      1.1  christos 	expect_init_percent(50, ".5");
    143      1.1  christos }
    144      1.1  christos TEST_END
    145      1.1  christos 
    146      1.1  christos static void
    147  1.1.1.2  christos expect_add(const char *astr, const char *bstr, const char *resultstr) {
    148      1.1  christos 	fxp_t a = xparse_fxp(astr);
    149      1.1  christos 	fxp_t b = xparse_fxp(bstr);
    150      1.1  christos 	fxp_t result = xparse_fxp(resultstr);
    151  1.1.1.2  christos 	expect_true(fxp_close(fxp_add(a, b), result), "Expected %s + %s == %s",
    152  1.1.1.2  christos 	    astr, bstr, resultstr);
    153      1.1  christos }
    154      1.1  christos 
    155      1.1  christos TEST_BEGIN(test_add_simple) {
    156      1.1  christos 	expect_add("0", "0", "0");
    157      1.1  christos 	expect_add("0", "1", "1");
    158      1.1  christos 	expect_add("1", "1", "2");
    159      1.1  christos 	expect_add("1.5", "1.5", "3");
    160      1.1  christos 	expect_add("0.1", "0.1", "0.2");
    161      1.1  christos 	expect_add("123", "456", "579");
    162      1.1  christos }
    163      1.1  christos TEST_END
    164      1.1  christos 
    165      1.1  christos static void
    166  1.1.1.2  christos expect_sub(const char *astr, const char *bstr, const char *resultstr) {
    167      1.1  christos 	fxp_t a = xparse_fxp(astr);
    168      1.1  christos 	fxp_t b = xparse_fxp(bstr);
    169      1.1  christos 	fxp_t result = xparse_fxp(resultstr);
    170  1.1.1.2  christos 	expect_true(fxp_close(fxp_sub(a, b), result), "Expected %s - %s == %s",
    171  1.1.1.2  christos 	    astr, bstr, resultstr);
    172      1.1  christos }
    173      1.1  christos 
    174      1.1  christos TEST_BEGIN(test_sub_simple) {
    175      1.1  christos 	expect_sub("0", "0", "0");
    176      1.1  christos 	expect_sub("1", "0", "1");
    177      1.1  christos 	expect_sub("1", "1", "0");
    178      1.1  christos 	expect_sub("3.5", "1.5", "2");
    179      1.1  christos 	expect_sub("0.3", "0.1", "0.2");
    180      1.1  christos 	expect_sub("456", "123", "333");
    181      1.1  christos }
    182      1.1  christos TEST_END
    183      1.1  christos 
    184      1.1  christos static void
    185  1.1.1.2  christos expect_mul(const char *astr, const char *bstr, const char *resultstr) {
    186      1.1  christos 	fxp_t a = xparse_fxp(astr);
    187      1.1  christos 	fxp_t b = xparse_fxp(bstr);
    188      1.1  christos 	fxp_t result = xparse_fxp(resultstr);
    189  1.1.1.2  christos 	expect_true(fxp_close(fxp_mul(a, b), result), "Expected %s * %s == %s",
    190  1.1.1.2  christos 	    astr, bstr, resultstr);
    191      1.1  christos }
    192      1.1  christos 
    193      1.1  christos TEST_BEGIN(test_mul_simple) {
    194      1.1  christos 	expect_mul("0", "0", "0");
    195      1.1  christos 	expect_mul("1", "0", "0");
    196      1.1  christos 	expect_mul("1", "1", "1");
    197      1.1  christos 	expect_mul("1.5", "1.5", "2.25");
    198      1.1  christos 	expect_mul("100.0", "10", "1000");
    199      1.1  christos 	expect_mul(".1", "10", "1");
    200      1.1  christos }
    201      1.1  christos TEST_END
    202      1.1  christos 
    203      1.1  christos static void
    204  1.1.1.2  christos expect_div(const char *astr, const char *bstr, const char *resultstr) {
    205      1.1  christos 	fxp_t a = xparse_fxp(astr);
    206      1.1  christos 	fxp_t b = xparse_fxp(bstr);
    207      1.1  christos 	fxp_t result = xparse_fxp(resultstr);
    208  1.1.1.2  christos 	expect_true(fxp_close(fxp_div(a, b), result), "Expected %s / %s == %s",
    209  1.1.1.2  christos 	    astr, bstr, resultstr);
    210      1.1  christos }
    211      1.1  christos 
    212      1.1  christos TEST_BEGIN(test_div_simple) {
    213      1.1  christos 	expect_div("1", "1", "1");
    214      1.1  christos 	expect_div("0", "1", "0");
    215      1.1  christos 	expect_div("2", "1", "2");
    216      1.1  christos 	expect_div("3", "2", "1.5");
    217      1.1  christos 	expect_div("3", "1.5", "2");
    218      1.1  christos 	expect_div("10", ".1", "100");
    219      1.1  christos 	expect_div("123", "456", ".2697368421");
    220      1.1  christos }
    221      1.1  christos TEST_END
    222      1.1  christos 
    223      1.1  christos static void
    224      1.1  christos expect_round(const char *str, uint32_t rounded_down, uint32_t rounded_nearest) {
    225  1.1.1.2  christos 	fxp_t    fxp = xparse_fxp(str);
    226      1.1  christos 	uint32_t fxp_rounded_down = fxp_round_down(fxp);
    227      1.1  christos 	uint32_t fxp_rounded_nearest = fxp_round_nearest(fxp);
    228  1.1.1.2  christos 	expect_u32_eq(
    229  1.1.1.2  christos 	    rounded_down, fxp_rounded_down, "Mistake rounding %s down", str);
    230      1.1  christos 	expect_u32_eq(rounded_nearest, fxp_rounded_nearest,
    231      1.1  christos 	    "Mistake rounding %s to nearest", str);
    232      1.1  christos }
    233      1.1  christos 
    234      1.1  christos TEST_BEGIN(test_round_simple) {
    235      1.1  christos 	expect_round("1.5", 1, 2);
    236      1.1  christos 	expect_round("0", 0, 0);
    237      1.1  christos 	expect_round("0.1", 0, 0);
    238      1.1  christos 	expect_round("0.4", 0, 0);
    239      1.1  christos 	expect_round("0.40000", 0, 0);
    240      1.1  christos 	expect_round("0.5", 0, 1);
    241      1.1  christos 	expect_round("0.6", 0, 1);
    242      1.1  christos 	expect_round("123", 123, 123);
    243      1.1  christos 	expect_round("123.4", 123, 123);
    244      1.1  christos 	expect_round("123.5", 123, 124);
    245      1.1  christos }
    246      1.1  christos TEST_END
    247      1.1  christos 
    248      1.1  christos static void
    249      1.1  christos expect_mul_frac(size_t a, const char *fracstr, size_t expected) {
    250  1.1.1.2  christos 	fxp_t  frac = xparse_fxp(fracstr);
    251      1.1  christos 	size_t result = fxp_mul_frac(a, frac);
    252      1.1  christos 	expect_true(double_close(expected, result),
    253  1.1.1.2  christos 	    "Expected %zu * %s == %zu (fracmul); got %zu", a, fracstr, expected,
    254  1.1.1.2  christos 	    result);
    255      1.1  christos }
    256      1.1  christos 
    257      1.1  christos TEST_BEGIN(test_mul_frac_simple) {
    258      1.1  christos 	expect_mul_frac(SIZE_MAX, "1.0", SIZE_MAX);
    259      1.1  christos 	expect_mul_frac(SIZE_MAX, ".75", SIZE_MAX / 4 * 3);
    260      1.1  christos 	expect_mul_frac(SIZE_MAX, ".5", SIZE_MAX / 2);
    261      1.1  christos 	expect_mul_frac(SIZE_MAX, ".25", SIZE_MAX / 4);
    262      1.1  christos 	expect_mul_frac(1U << 16, "1.0", 1U << 16);
    263      1.1  christos 	expect_mul_frac(1U << 30, "0.5", 1U << 29);
    264      1.1  christos 	expect_mul_frac(1U << 30, "0.25", 1U << 28);
    265      1.1  christos 	expect_mul_frac(1U << 30, "0.125", 1U << 27);
    266      1.1  christos 	expect_mul_frac((1U << 30) + 1, "0.125", 1U << 27);
    267      1.1  christos 	expect_mul_frac(100, "0.25", 25);
    268      1.1  christos 	expect_mul_frac(1000 * 1000, "0.001", 1000);
    269      1.1  christos }
    270      1.1  christos TEST_END
    271      1.1  christos 
    272      1.1  christos static void
    273      1.1  christos expect_print(const char *str) {
    274      1.1  christos 	fxp_t fxp = xparse_fxp(str);
    275  1.1.1.2  christos 	char  buf[FXP_BUF_SIZE];
    276      1.1  christos 	fxp_print(fxp, buf);
    277      1.1  christos 	expect_d_eq(0, strcmp(str, buf), "Couldn't round-trip print %s", str);
    278      1.1  christos }
    279      1.1  christos 
    280      1.1  christos TEST_BEGIN(test_print_simple) {
    281      1.1  christos 	expect_print("0.0");
    282      1.1  christos 	expect_print("1.0");
    283      1.1  christos 	expect_print("2.0");
    284      1.1  christos 	expect_print("123.0");
    285      1.1  christos 	/*
    286      1.1  christos 	 * We hit the possibility of roundoff errors whenever the fractional
    287      1.1  christos 	 * component isn't a round binary number; only check these here (we
    288      1.1  christos 	 * round-trip properly in the stress test).
    289      1.1  christos 	 */
    290      1.1  christos 	expect_print("1.5");
    291      1.1  christos 	expect_print("3.375");
    292      1.1  christos 	expect_print("0.25");
    293      1.1  christos 	expect_print("0.125");
    294      1.1  christos 	/* 1 / 2**14 */
    295      1.1  christos 	expect_print("0.00006103515625");
    296      1.1  christos }
    297      1.1  christos TEST_END
    298      1.1  christos 
    299      1.1  christos TEST_BEGIN(test_stress) {
    300  1.1.1.2  christos 	const char *numbers[] = {"0.0", "0.1", "0.2", "0.3", "0.4", "0.5",
    301  1.1.1.2  christos 	    "0.6", "0.7", "0.8", "0.9",
    302      1.1  christos 
    303  1.1.1.2  christos 	    "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8",
    304  1.1.1.2  christos 	    "1.9",
    305      1.1  christos 
    306  1.1.1.2  christos 	    "2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8",
    307  1.1.1.2  christos 	    "2.9",
    308      1.1  christos 
    309  1.1.1.2  christos 	    "17.0", "17.1", "17.2", "17.3", "17.4", "17.5", "17.6", "17.7",
    310  1.1.1.2  christos 	    "17.8", "17.9",
    311      1.1  christos 
    312  1.1.1.2  christos 	    "18.0", "18.1", "18.2", "18.3", "18.4", "18.5", "18.6", "18.7",
    313  1.1.1.2  christos 	    "18.8", "18.9",
    314      1.1  christos 
    315  1.1.1.2  christos 	    "123.0", "123.1", "123.2", "123.3", "123.4", "123.5", "123.6",
    316  1.1.1.2  christos 	    "123.7", "123.8", "123.9",
    317      1.1  christos 
    318  1.1.1.2  christos 	    "124.0", "124.1", "124.2", "124.3", "124.4", "124.5", "124.6",
    319  1.1.1.2  christos 	    "124.7", "124.8", "124.9",
    320      1.1  christos 
    321  1.1.1.2  christos 	    "125.0", "125.1", "125.2", "125.3", "125.4", "125.5", "125.6",
    322  1.1.1.2  christos 	    "125.7", "125.8", "125.9"};
    323  1.1.1.2  christos 	size_t      numbers_len = sizeof(numbers) / sizeof(numbers[0]);
    324      1.1  christos 	for (size_t i = 0; i < numbers_len; i++) {
    325  1.1.1.2  christos 		fxp_t  fxp_a = xparse_fxp(numbers[i]);
    326      1.1  christos 		double double_a = strtod(numbers[i], NULL);
    327      1.1  christos 
    328      1.1  christos 		uint32_t fxp_rounded_down = fxp_round_down(fxp_a);
    329      1.1  christos 		uint32_t fxp_rounded_nearest = fxp_round_nearest(fxp_a);
    330      1.1  christos 		uint32_t double_rounded_down = (uint32_t)double_a;
    331      1.1  christos 		uint32_t double_rounded_nearest = (uint32_t)round(double_a);
    332      1.1  christos 
    333      1.1  christos 		expect_u32_eq(double_rounded_down, fxp_rounded_down,
    334      1.1  christos 		    "Incorrectly rounded down %s", numbers[i]);
    335      1.1  christos 		expect_u32_eq(double_rounded_nearest, fxp_rounded_nearest,
    336      1.1  christos 		    "Incorrectly rounded-to-nearest %s", numbers[i]);
    337      1.1  christos 
    338      1.1  christos 		for (size_t j = 0; j < numbers_len; j++) {
    339  1.1.1.2  christos 			fxp_t  fxp_b = xparse_fxp(numbers[j]);
    340      1.1  christos 			double double_b = strtod(numbers[j], NULL);
    341      1.1  christos 
    342  1.1.1.2  christos 			fxp_t  fxp_sum = fxp_add(fxp_a, fxp_b);
    343      1.1  christos 			double double_sum = double_a + double_b;
    344      1.1  christos 			expect_true(
    345      1.1  christos 			    double_close(fxp2double(fxp_sum), double_sum),
    346      1.1  christos 			    "Miscomputed %s + %s", numbers[i], numbers[j]);
    347      1.1  christos 
    348      1.1  christos 			if (double_a > double_b) {
    349  1.1.1.2  christos 				fxp_t  fxp_diff = fxp_sub(fxp_a, fxp_b);
    350      1.1  christos 				double double_diff = double_a - double_b;
    351  1.1.1.2  christos 				expect_true(double_close(fxp2double(fxp_diff),
    352  1.1.1.2  christos 				                double_diff),
    353      1.1  christos 				    "Miscomputed %s - %s", numbers[i],
    354      1.1  christos 				    numbers[j]);
    355      1.1  christos 			}
    356      1.1  christos 
    357  1.1.1.2  christos 			fxp_t  fxp_prod = fxp_mul(fxp_a, fxp_b);
    358      1.1  christos 			double double_prod = double_a * double_b;
    359      1.1  christos 			expect_true(
    360      1.1  christos 			    double_close(fxp2double(fxp_prod), double_prod),
    361      1.1  christos 			    "Miscomputed %s * %s", numbers[i], numbers[j]);
    362      1.1  christos 
    363      1.1  christos 			if (double_b != 0.0) {
    364  1.1.1.2  christos 				fxp_t  fxp_quot = fxp_div(fxp_a, fxp_b);
    365      1.1  christos 				double double_quot = double_a / double_b;
    366  1.1.1.2  christos 				expect_true(double_close(fxp2double(fxp_quot),
    367  1.1.1.2  christos 				                double_quot),
    368      1.1  christos 				    "Miscomputed %s / %s", numbers[i],
    369      1.1  christos 				    numbers[j]);
    370      1.1  christos 			}
    371      1.1  christos 		}
    372      1.1  christos 	}
    373      1.1  christos }
    374      1.1  christos TEST_END
    375      1.1  christos 
    376      1.1  christos int
    377      1.1  christos main(void) {
    378  1.1.1.2  christos 	return test_no_reentrancy(test_parse_valid, test_parse_invalid,
    379  1.1.1.2  christos 	    test_init_percent, test_add_simple, test_sub_simple,
    380  1.1.1.2  christos 	    test_mul_simple, test_div_simple, test_round_simple,
    381  1.1.1.2  christos 	    test_mul_frac_simple, test_print_simple, test_stress);
    382      1.1  christos }
    383