Commit a9951b1b authored by antirez's avatar antirez
Browse files

Jemalloc updated to 4.0.3.

parent e3ded027
#include "jemalloc/internal/jemalloc_internal.h"
#ifndef JEMALLOC_VALGRIND
# error "This source file is for Valgrind integration."
#endif
#include <valgrind/memcheck.h>
void
valgrind_make_mem_noaccess(void *ptr, size_t usize)
{
VALGRIND_MAKE_MEM_NOACCESS(ptr, usize);
}
void
valgrind_make_mem_undefined(void *ptr, size_t usize)
{
VALGRIND_MAKE_MEM_UNDEFINED(ptr, usize);
}
void
valgrind_make_mem_defined(void *ptr, size_t usize)
{
VALGRIND_MAKE_MEM_DEFINED(ptr, usize);
}
void
valgrind_freelike_block(void *ptr, size_t usize)
{
VALGRIND_FREELIKE_BLOCK(ptr, usize);
}
...@@ -176,6 +176,7 @@ register_zone(void) ...@@ -176,6 +176,7 @@ register_zone(void)
* register jemalloc's. * register jemalloc's.
*/ */
malloc_zone_t *default_zone = malloc_default_zone(); malloc_zone_t *default_zone = malloc_default_zone();
malloc_zone_t *purgeable_zone = NULL;
if (!default_zone->zone_name || if (!default_zone->zone_name ||
strcmp(default_zone->zone_name, "DefaultMallocZone") != 0) { strcmp(default_zone->zone_name, "DefaultMallocZone") != 0) {
return; return;
...@@ -237,22 +238,37 @@ register_zone(void) ...@@ -237,22 +238,37 @@ register_zone(void)
* run time. * run time.
*/ */
if (malloc_default_purgeable_zone != NULL) if (malloc_default_purgeable_zone != NULL)
malloc_default_purgeable_zone(); purgeable_zone = malloc_default_purgeable_zone();
/* Register the custom zone. At this point it won't be the default. */ /* Register the custom zone. At this point it won't be the default. */
malloc_zone_register(&zone); malloc_zone_register(&zone);
/*
* Unregister and reregister the default zone. On OSX >= 10.6,
* unregistering takes the last registered zone and places it at the
* location of the specified zone. Unregistering the default zone thus
* makes the last registered one the default. On OSX < 10.6,
* unregistering shifts all registered zones. The first registered zone
* then becomes the default.
*/
do { do {
default_zone = malloc_default_zone(); default_zone = malloc_default_zone();
/*
* Unregister and reregister the default zone. On OSX >= 10.6,
* unregistering takes the last registered zone and places it
* at the location of the specified zone. Unregistering the
* default zone thus makes the last registered one the default.
* On OSX < 10.6, unregistering shifts all registered zones.
* The first registered zone then becomes the default.
*/
malloc_zone_unregister(default_zone); malloc_zone_unregister(default_zone);
malloc_zone_register(default_zone); malloc_zone_register(default_zone);
/*
* On OSX 10.6, having the default purgeable zone appear before
* the default zone makes some things crash because it thinks it
* owns the default zone allocated pointers. We thus
* unregister/re-register it in order to ensure it's always
* after the default zone. On OSX < 10.6, there is no purgeable
* zone, so this does nothing. On OSX >= 10.6, unregistering
* replaces the purgeable zone with the last registered zone
* above, i.e. the default zone. Registering it again then puts
* it at the end, obviously after the default zone.
*/
if (purgeable_zone) {
malloc_zone_unregister(purgeable_zone);
malloc_zone_register(purgeable_zone);
}
} while (malloc_default_zone() != &zone); } while (malloc_default_zone() != &zone);
} }
#include "test/jemalloc_test.h" /* btalloc() provides a mechanism for allocating via permuted backtraces. */
void *btalloc(size_t size, unsigned bits);
#define NTHREADS 4 #define btalloc_n_proto(n) \
#define NALLOCS_PER_THREAD 50 void *btalloc_##n(size_t size, unsigned bits);
#define DUMP_INTERVAL 1 btalloc_n_proto(0)
#define BT_COUNT_CHECK_INTERVAL 5 btalloc_n_proto(1)
#define alloc_n_proto(n) \ #define btalloc_n_gen(n) \
void *alloc_##n(unsigned bits);
alloc_n_proto(0)
alloc_n_proto(1)
#define alloc_n_gen(n) \
void * \ void * \
alloc_##n(unsigned bits) \ btalloc_##n(size_t size, unsigned bits) \
{ \ { \
void *p; \ void *p; \
\ \
if (bits == 0) \ if (bits == 0) \
p = mallocx(1, 0); \ p = mallocx(size, 0); \
else { \ else { \
switch (bits & 0x1U) { \ switch (bits & 0x1U) { \
case 0: \ case 0: \
p = (alloc_0(bits >> 1)); \ p = (btalloc_0(size, bits >> 1)); \
break; \ break; \
case 1: \ case 1: \
p = (alloc_1(bits >> 1)); \ p = (btalloc_1(size, bits >> 1)); \
break; \ break; \
default: not_reached(); \ default: not_reached(); \
} \ } \
......
#include <limits.h>
#ifndef SIZE_T_MAX
# define SIZE_T_MAX SIZE_MAX
#endif
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
#include <errno.h> #include <errno.h>
#include <inttypes.h>
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
#ifdef _WIN32
# include "msvc_compat/strings.h"
#endif
#include <sys/time.h>
#ifdef _WIN32 #ifdef _WIN32
# include <windows.h> # include <windows.h>
# include "msvc_compat/windows_extra.h"
#else #else
# include <pthread.h> # include <pthread.h>
#endif #endif
...@@ -132,10 +140,12 @@ ...@@ -132,10 +140,12 @@
/* /*
* Common test utilities. * Common test utilities.
*/ */
#include "test/btalloc.h"
#include "test/math.h" #include "test/math.h"
#include "test/mtx.h" #include "test/mtx.h"
#include "test/mq.h" #include "test/mq.h"
#include "test/test.h" #include "test/test.h"
#include "test/timer.h"
#include "test/thd.h" #include "test/thd.h"
#define MEXP 19937 #define MEXP 19937
#include "test/SFMT.h" #include "test/SFMT.h"
#include "jemalloc/internal/jemalloc_internal_defs.h" #include "jemalloc/internal/jemalloc_internal_defs.h"
#include "jemalloc/internal/jemalloc_internal_decls.h"
/* For use by SFMT. */ /*
* For use by SFMT. configure.ac doesn't actually define HAVE_SSE2 because its
* dependencies are notoriously unportable in practice.
*/
#undef HAVE_SSE2 #undef HAVE_SSE2
#undef HAVE_ALTIVEC #undef HAVE_ALTIVEC
...@@ -299,7 +299,7 @@ pt_chi2(double p, double df, double ln_gamma_df_2) ...@@ -299,7 +299,7 @@ pt_chi2(double p, double df, double ln_gamma_df_2)
/* /*
* Given a value p in [0..1] and Gamma distribution shape and scale parameters, * Given a value p in [0..1] and Gamma distribution shape and scale parameters,
* compute the upper limit on the definite integeral from [0..z] that satisfies * compute the upper limit on the definite integral from [0..z] that satisfies
* p. * p.
*/ */
JEMALLOC_INLINE double JEMALLOC_INLINE double
......
void mq_nanosleep(unsigned ns);
/* /*
* Simple templated message queue implementation that relies on only mutexes for * Simple templated message queue implementation that relies on only mutexes for
* synchronization (which reduces portability issues). Given the following * synchronization (which reduces portability issues). Given the following
...@@ -75,26 +77,23 @@ a_attr a_mq_msg_type * \ ...@@ -75,26 +77,23 @@ a_attr a_mq_msg_type * \
a_prefix##get(a_mq_type *mq) \ a_prefix##get(a_mq_type *mq) \
{ \ { \
a_mq_msg_type *msg; \ a_mq_msg_type *msg; \
struct timespec timeout; \ unsigned ns; \
\ \
msg = a_prefix##tryget(mq); \ msg = a_prefix##tryget(mq); \
if (msg != NULL) \ if (msg != NULL) \
return (msg); \ return (msg); \
\ \
timeout.tv_sec = 0; \ ns = 1; \
timeout.tv_nsec = 1; \
while (true) { \ while (true) { \
nanosleep(&timeout, NULL); \ mq_nanosleep(ns); \
msg = a_prefix##tryget(mq); \ msg = a_prefix##tryget(mq); \
if (msg != NULL) \ if (msg != NULL) \
return (msg); \ return (msg); \
if (timeout.tv_sec == 0) { \ if (ns < 1000*1000*1000) { \
/* Double sleep time, up to max 1 second. */ \ /* Double sleep time, up to max 1 second. */ \
timeout.tv_nsec <<= 1; \ ns <<= 1; \
if (timeout.tv_nsec >= 1000*1000*1000) { \ if (ns > 1000*1000*1000) \
timeout.tv_sec = 1; \ ns = 1000*1000*1000; \
timeout.tv_nsec = 0; \
} \
} \ } \
} \ } \
} \ } \
......
#define ASSERT_BUFSIZE 256 #define ASSERT_BUFSIZE 256
#define assert_cmp(t, a, b, cmp, neg_cmp, pri, fmt...) do { \ #define assert_cmp(t, a, b, cmp, neg_cmp, pri, ...) do { \
t a_ = (a); \ t a_ = (a); \
t b_ = (b); \ t b_ = (b); \
if (!(a_ cmp b_)) { \ if (!(a_ cmp b_)) { \
...@@ -12,205 +12,205 @@ ...@@ -12,205 +12,205 @@
"%"pri" "#neg_cmp" %"pri": ", \ "%"pri" "#neg_cmp" %"pri": ", \
__func__, __FILE__, __LINE__, \ __func__, __FILE__, __LINE__, \
#a, #b, a_, b_); \ #a, #b, a_, b_); \
malloc_snprintf(message, sizeof(message), fmt); \ malloc_snprintf(message, sizeof(message), __VA_ARGS__); \
p_test_fail(prefix, message); \ p_test_fail(prefix, message); \
} \ } \
} while (0) } while (0)
#define assert_ptr_eq(a, b, fmt...) assert_cmp(void *, a, b, ==, \ #define assert_ptr_eq(a, b, ...) assert_cmp(void *, a, b, ==, \
!=, "p", fmt) !=, "p", __VA_ARGS__)
#define assert_ptr_ne(a, b, fmt...) assert_cmp(void *, a, b, !=, \ #define assert_ptr_ne(a, b, ...) assert_cmp(void *, a, b, !=, \
==, "p", fmt) ==, "p", __VA_ARGS__)
#define assert_ptr_null(a, fmt...) assert_cmp(void *, a, NULL, ==, \ #define assert_ptr_null(a, ...) assert_cmp(void *, a, NULL, ==, \
!=, "p", fmt) !=, "p", __VA_ARGS__)
#define assert_ptr_not_null(a, fmt...) assert_cmp(void *, a, NULL, !=, \ #define assert_ptr_not_null(a, ...) assert_cmp(void *, a, NULL, !=, \
==, "p", fmt) ==, "p", __VA_ARGS__)
#define assert_c_eq(a, b, fmt...) assert_cmp(char, a, b, ==, !=, "c", fmt) #define assert_c_eq(a, b, ...) assert_cmp(char, a, b, ==, !=, "c", __VA_ARGS__)
#define assert_c_ne(a, b, fmt...) assert_cmp(char, a, b, !=, ==, "c", fmt) #define assert_c_ne(a, b, ...) assert_cmp(char, a, b, !=, ==, "c", __VA_ARGS__)
#define assert_c_lt(a, b, fmt...) assert_cmp(char, a, b, <, >=, "c", fmt) #define assert_c_lt(a, b, ...) assert_cmp(char, a, b, <, >=, "c", __VA_ARGS__)
#define assert_c_le(a, b, fmt...) assert_cmp(char, a, b, <=, >, "c", fmt) #define assert_c_le(a, b, ...) assert_cmp(char, a, b, <=, >, "c", __VA_ARGS__)
#define assert_c_ge(a, b, fmt...) assert_cmp(char, a, b, >=, <, "c", fmt) #define assert_c_ge(a, b, ...) assert_cmp(char, a, b, >=, <, "c", __VA_ARGS__)
#define assert_c_gt(a, b, fmt...) assert_cmp(char, a, b, >, <=, "c", fmt) #define assert_c_gt(a, b, ...) assert_cmp(char, a, b, >, <=, "c", __VA_ARGS__)
#define assert_x_eq(a, b, fmt...) assert_cmp(int, a, b, ==, !=, "#x", fmt) #define assert_x_eq(a, b, ...) assert_cmp(int, a, b, ==, !=, "#x", __VA_ARGS__)
#define assert_x_ne(a, b, fmt...) assert_cmp(int, a, b, !=, ==, "#x", fmt) #define assert_x_ne(a, b, ...) assert_cmp(int, a, b, !=, ==, "#x", __VA_ARGS__)
#define assert_x_lt(a, b, fmt...) assert_cmp(int, a, b, <, >=, "#x", fmt) #define assert_x_lt(a, b, ...) assert_cmp(int, a, b, <, >=, "#x", __VA_ARGS__)
#define assert_x_le(a, b, fmt...) assert_cmp(int, a, b, <=, >, "#x", fmt) #define assert_x_le(a, b, ...) assert_cmp(int, a, b, <=, >, "#x", __VA_ARGS__)
#define assert_x_ge(a, b, fmt...) assert_cmp(int, a, b, >=, <, "#x", fmt) #define assert_x_ge(a, b, ...) assert_cmp(int, a, b, >=, <, "#x", __VA_ARGS__)
#define assert_x_gt(a, b, fmt...) assert_cmp(int, a, b, >, <=, "#x", fmt) #define assert_x_gt(a, b, ...) assert_cmp(int, a, b, >, <=, "#x", __VA_ARGS__)
#define assert_d_eq(a, b, fmt...) assert_cmp(int, a, b, ==, !=, "d", fmt) #define assert_d_eq(a, b, ...) assert_cmp(int, a, b, ==, !=, "d", __VA_ARGS__)
#define assert_d_ne(a, b, fmt...) assert_cmp(int, a, b, !=, ==, "d", fmt) #define assert_d_ne(a, b, ...) assert_cmp(int, a, b, !=, ==, "d", __VA_ARGS__)
#define assert_d_lt(a, b, fmt...) assert_cmp(int, a, b, <, >=, "d", fmt) #define assert_d_lt(a, b, ...) assert_cmp(int, a, b, <, >=, "d", __VA_ARGS__)
#define assert_d_le(a, b, fmt...) assert_cmp(int, a, b, <=, >, "d", fmt) #define assert_d_le(a, b, ...) assert_cmp(int, a, b, <=, >, "d", __VA_ARGS__)
#define assert_d_ge(a, b, fmt...) assert_cmp(int, a, b, >=, <, "d", fmt) #define assert_d_ge(a, b, ...) assert_cmp(int, a, b, >=, <, "d", __VA_ARGS__)
#define assert_d_gt(a, b, fmt...) assert_cmp(int, a, b, >, <=, "d", fmt) #define assert_d_gt(a, b, ...) assert_cmp(int, a, b, >, <=, "d", __VA_ARGS__)
#define assert_u_eq(a, b, fmt...) assert_cmp(int, a, b, ==, !=, "u", fmt) #define assert_u_eq(a, b, ...) assert_cmp(int, a, b, ==, !=, "u", __VA_ARGS__)
#define assert_u_ne(a, b, fmt...) assert_cmp(int, a, b, !=, ==, "u", fmt) #define assert_u_ne(a, b, ...) assert_cmp(int, a, b, !=, ==, "u", __VA_ARGS__)
#define assert_u_lt(a, b, fmt...) assert_cmp(int, a, b, <, >=, "u", fmt) #define assert_u_lt(a, b, ...) assert_cmp(int, a, b, <, >=, "u", __VA_ARGS__)
#define assert_u_le(a, b, fmt...) assert_cmp(int, a, b, <=, >, "u", fmt) #define assert_u_le(a, b, ...) assert_cmp(int, a, b, <=, >, "u", __VA_ARGS__)
#define assert_u_ge(a, b, fmt...) assert_cmp(int, a, b, >=, <, "u", fmt) #define assert_u_ge(a, b, ...) assert_cmp(int, a, b, >=, <, "u", __VA_ARGS__)
#define assert_u_gt(a, b, fmt...) assert_cmp(int, a, b, >, <=, "u", fmt) #define assert_u_gt(a, b, ...) assert_cmp(int, a, b, >, <=, "u", __VA_ARGS__)
#define assert_ld_eq(a, b, fmt...) assert_cmp(long, a, b, ==, \ #define assert_ld_eq(a, b, ...) assert_cmp(long, a, b, ==, \
!=, "ld", fmt) !=, "ld", __VA_ARGS__)
#define assert_ld_ne(a, b, fmt...) assert_cmp(long, a, b, !=, \ #define assert_ld_ne(a, b, ...) assert_cmp(long, a, b, !=, \
==, "ld", fmt) ==, "ld", __VA_ARGS__)
#define assert_ld_lt(a, b, fmt...) assert_cmp(long, a, b, <, \ #define assert_ld_lt(a, b, ...) assert_cmp(long, a, b, <, \
>=, "ld", fmt) >=, "ld", __VA_ARGS__)
#define assert_ld_le(a, b, fmt...) assert_cmp(long, a, b, <=, \ #define assert_ld_le(a, b, ...) assert_cmp(long, a, b, <=, \
>, "ld", fmt) >, "ld", __VA_ARGS__)
#define assert_ld_ge(a, b, fmt...) assert_cmp(long, a, b, >=, \ #define assert_ld_ge(a, b, ...) assert_cmp(long, a, b, >=, \
<, "ld", fmt) <, "ld", __VA_ARGS__)
#define assert_ld_gt(a, b, fmt...) assert_cmp(long, a, b, >, \ #define assert_ld_gt(a, b, ...) assert_cmp(long, a, b, >, \
<=, "ld", fmt) <=, "ld", __VA_ARGS__)
#define assert_lu_eq(a, b, fmt...) assert_cmp(unsigned long, \ #define assert_lu_eq(a, b, ...) assert_cmp(unsigned long, \
a, b, ==, !=, "lu", fmt) a, b, ==, !=, "lu", __VA_ARGS__)
#define assert_lu_ne(a, b, fmt...) assert_cmp(unsigned long, \ #define assert_lu_ne(a, b, ...) assert_cmp(unsigned long, \
a, b, !=, ==, "lu", fmt) a, b, !=, ==, "lu", __VA_ARGS__)
#define assert_lu_lt(a, b, fmt...) assert_cmp(unsigned long, \ #define assert_lu_lt(a, b, ...) assert_cmp(unsigned long, \
a, b, <, >=, "lu", fmt) a, b, <, >=, "lu", __VA_ARGS__)
#define assert_lu_le(a, b, fmt...) assert_cmp(unsigned long, \ #define assert_lu_le(a, b, ...) assert_cmp(unsigned long, \
a, b, <=, >, "lu", fmt) a, b, <=, >, "lu", __VA_ARGS__)
#define assert_lu_ge(a, b, fmt...) assert_cmp(unsigned long, \ #define assert_lu_ge(a, b, ...) assert_cmp(unsigned long, \
a, b, >=, <, "lu", fmt) a, b, >=, <, "lu", __VA_ARGS__)
#define assert_lu_gt(a, b, fmt...) assert_cmp(unsigned long, \ #define assert_lu_gt(a, b, ...) assert_cmp(unsigned long, \
a, b, >, <=, "lu", fmt) a, b, >, <=, "lu", __VA_ARGS__)
#define assert_qd_eq(a, b, fmt...) assert_cmp(long long, a, b, ==, \ #define assert_qd_eq(a, b, ...) assert_cmp(long long, a, b, ==, \
!=, "qd", fmt) !=, "qd", __VA_ARGS__)
#define assert_qd_ne(a, b, fmt...) assert_cmp(long long, a, b, !=, \ #define assert_qd_ne(a, b, ...) assert_cmp(long long, a, b, !=, \
==, "qd", fmt) ==, "qd", __VA_ARGS__)
#define assert_qd_lt(a, b, fmt...) assert_cmp(long long, a, b, <, \ #define assert_qd_lt(a, b, ...) assert_cmp(long long, a, b, <, \
>=, "qd", fmt) >=, "qd", __VA_ARGS__)
#define assert_qd_le(a, b, fmt...) assert_cmp(long long, a, b, <=, \ #define assert_qd_le(a, b, ...) assert_cmp(long long, a, b, <=, \
>, "qd", fmt) >, "qd", __VA_ARGS__)
#define assert_qd_ge(a, b, fmt...) assert_cmp(long long, a, b, >=, \ #define assert_qd_ge(a, b, ...) assert_cmp(long long, a, b, >=, \
<, "qd", fmt) <, "qd", __VA_ARGS__)
#define assert_qd_gt(a, b, fmt...) assert_cmp(long long, a, b, >, \ #define assert_qd_gt(a, b, ...) assert_cmp(long long, a, b, >, \
<=, "qd", fmt) <=, "qd", __VA_ARGS__)
#define assert_qu_eq(a, b, fmt...) assert_cmp(unsigned long long, \ #define assert_qu_eq(a, b, ...) assert_cmp(unsigned long long, \
a, b, ==, !=, "qu", fmt) a, b, ==, !=, "qu", __VA_ARGS__)
#define assert_qu_ne(a, b, fmt...) assert_cmp(unsigned long long, \ #define assert_qu_ne(a, b, ...) assert_cmp(unsigned long long, \
a, b, !=, ==, "qu", fmt) a, b, !=, ==, "qu", __VA_ARGS__)
#define assert_qu_lt(a, b, fmt...) assert_cmp(unsigned long long, \ #define assert_qu_lt(a, b, ...) assert_cmp(unsigned long long, \
a, b, <, >=, "qu", fmt) a, b, <, >=, "qu", __VA_ARGS__)
#define assert_qu_le(a, b, fmt...) assert_cmp(unsigned long long, \ #define assert_qu_le(a, b, ...) assert_cmp(unsigned long long, \
a, b, <=, >, "qu", fmt) a, b, <=, >, "qu", __VA_ARGS__)
#define assert_qu_ge(a, b, fmt...) assert_cmp(unsigned long long, \ #define assert_qu_ge(a, b, ...) assert_cmp(unsigned long long, \
a, b, >=, <, "qu", fmt) a, b, >=, <, "qu", __VA_ARGS__)
#define assert_qu_gt(a, b, fmt...) assert_cmp(unsigned long long, \ #define assert_qu_gt(a, b, ...) assert_cmp(unsigned long long, \
a, b, >, <=, "qu", fmt) a, b, >, <=, "qu", __VA_ARGS__)
#define assert_jd_eq(a, b, fmt...) assert_cmp(intmax_t, a, b, ==, \ #define assert_jd_eq(a, b, ...) assert_cmp(intmax_t, a, b, ==, \
!=, "jd", fmt) !=, "jd", __VA_ARGS__)
#define assert_jd_ne(a, b, fmt...) assert_cmp(intmax_t, a, b, !=, \ #define assert_jd_ne(a, b, ...) assert_cmp(intmax_t, a, b, !=, \
==, "jd", fmt) ==, "jd", __VA_ARGS__)
#define assert_jd_lt(a, b, fmt...) assert_cmp(intmax_t, a, b, <, \ #define assert_jd_lt(a, b, ...) assert_cmp(intmax_t, a, b, <, \
>=, "jd", fmt) >=, "jd", __VA_ARGS__)
#define assert_jd_le(a, b, fmt...) assert_cmp(intmax_t, a, b, <=, \ #define assert_jd_le(a, b, ...) assert_cmp(intmax_t, a, b, <=, \
>, "jd", fmt) >, "jd", __VA_ARGS__)
#define assert_jd_ge(a, b, fmt...) assert_cmp(intmax_t, a, b, >=, \ #define assert_jd_ge(a, b, ...) assert_cmp(intmax_t, a, b, >=, \
<, "jd", fmt) <, "jd", __VA_ARGS__)
#define assert_jd_gt(a, b, fmt...) assert_cmp(intmax_t, a, b, >, \ #define assert_jd_gt(a, b, ...) assert_cmp(intmax_t, a, b, >, \
<=, "jd", fmt) <=, "jd", __VA_ARGS__)
#define assert_ju_eq(a, b, fmt...) assert_cmp(uintmax_t, a, b, ==, \ #define assert_ju_eq(a, b, ...) assert_cmp(uintmax_t, a, b, ==, \
!=, "ju", fmt) !=, "ju", __VA_ARGS__)
#define assert_ju_ne(a, b, fmt...) assert_cmp(uintmax_t, a, b, !=, \ #define assert_ju_ne(a, b, ...) assert_cmp(uintmax_t, a, b, !=, \
==, "ju", fmt) ==, "ju", __VA_ARGS__)
#define assert_ju_lt(a, b, fmt...) assert_cmp(uintmax_t, a, b, <, \ #define assert_ju_lt(a, b, ...) assert_cmp(uintmax_t, a, b, <, \
>=, "ju", fmt) >=, "ju", __VA_ARGS__)
#define assert_ju_le(a, b, fmt...) assert_cmp(uintmax_t, a, b, <=, \ #define assert_ju_le(a, b, ...) assert_cmp(uintmax_t, a, b, <=, \
>, "ju", fmt) >, "ju", __VA_ARGS__)
#define assert_ju_ge(a, b, fmt...) assert_cmp(uintmax_t, a, b, >=, \ #define assert_ju_ge(a, b, ...) assert_cmp(uintmax_t, a, b, >=, \
<, "ju", fmt) <, "ju", __VA_ARGS__)
#define assert_ju_gt(a, b, fmt...) assert_cmp(uintmax_t, a, b, >, \ #define assert_ju_gt(a, b, ...) assert_cmp(uintmax_t, a, b, >, \
<=, "ju", fmt) <=, "ju", __VA_ARGS__)
#define assert_zd_eq(a, b, fmt...) assert_cmp(ssize_t, a, b, ==, \ #define assert_zd_eq(a, b, ...) assert_cmp(ssize_t, a, b, ==, \
!=, "zd", fmt) !=, "zd", __VA_ARGS__)
#define assert_zd_ne(a, b, fmt...) assert_cmp(ssize_t, a, b, !=, \ #define assert_zd_ne(a, b, ...) assert_cmp(ssize_t, a, b, !=, \
==, "zd", fmt) ==, "zd", __VA_ARGS__)
#define assert_zd_lt(a, b, fmt...) assert_cmp(ssize_t, a, b, <, \ #define assert_zd_lt(a, b, ...) assert_cmp(ssize_t, a, b, <, \
>=, "zd", fmt) >=, "zd", __VA_ARGS__)
#define assert_zd_le(a, b, fmt...) assert_cmp(ssize_t, a, b, <=, \ #define assert_zd_le(a, b, ...) assert_cmp(ssize_t, a, b, <=, \
>, "zd", fmt) >, "zd", __VA_ARGS__)
#define assert_zd_ge(a, b, fmt...) assert_cmp(ssize_t, a, b, >=, \ #define assert_zd_ge(a, b, ...) assert_cmp(ssize_t, a, b, >=, \
<, "zd", fmt) <, "zd", __VA_ARGS__)
#define assert_zd_gt(a, b, fmt...) assert_cmp(ssize_t, a, b, >, \ #define assert_zd_gt(a, b, ...) assert_cmp(ssize_t, a, b, >, \
<=, "zd", fmt) <=, "zd", __VA_ARGS__)
#define assert_zu_eq(a, b, fmt...) assert_cmp(size_t, a, b, ==, \ #define assert_zu_eq(a, b, ...) assert_cmp(size_t, a, b, ==, \
!=, "zu", fmt) !=, "zu", __VA_ARGS__)
#define assert_zu_ne(a, b, fmt...) assert_cmp(size_t, a, b, !=, \ #define assert_zu_ne(a, b, ...) assert_cmp(size_t, a, b, !=, \
==, "zu", fmt) ==, "zu", __VA_ARGS__)
#define assert_zu_lt(a, b, fmt...) assert_cmp(size_t, a, b, <, \ #define assert_zu_lt(a, b, ...) assert_cmp(size_t, a, b, <, \
>=, "zu", fmt) >=, "zu", __VA_ARGS__)
#define assert_zu_le(a, b, fmt...) assert_cmp(size_t, a, b, <=, \ #define assert_zu_le(a, b, ...) assert_cmp(size_t, a, b, <=, \
>, "zu", fmt) >, "zu", __VA_ARGS__)
#define assert_zu_ge(a, b, fmt...) assert_cmp(size_t, a, b, >=, \ #define assert_zu_ge(a, b, ...) assert_cmp(size_t, a, b, >=, \
<, "zu", fmt) <, "zu", __VA_ARGS__)
#define assert_zu_gt(a, b, fmt...) assert_cmp(size_t, a, b, >, \ #define assert_zu_gt(a, b, ...) assert_cmp(size_t, a, b, >, \
<=, "zu", fmt) <=, "zu", __VA_ARGS__)
#define assert_d32_eq(a, b, fmt...) assert_cmp(int32_t, a, b, ==, \ #define assert_d32_eq(a, b, ...) assert_cmp(int32_t, a, b, ==, \
!=, PRId32, fmt) !=, FMTd32, __VA_ARGS__)
#define assert_d32_ne(a, b, fmt...) assert_cmp(int32_t, a, b, !=, \ #define assert_d32_ne(a, b, ...) assert_cmp(int32_t, a, b, !=, \
==, PRId32, fmt) ==, FMTd32, __VA_ARGS__)
#define assert_d32_lt(a, b, fmt...) assert_cmp(int32_t, a, b, <, \ #define assert_d32_lt(a, b, ...) assert_cmp(int32_t, a, b, <, \
>=, PRId32, fmt) >=, FMTd32, __VA_ARGS__)
#define assert_d32_le(a, b, fmt...) assert_cmp(int32_t, a, b, <=, \ #define assert_d32_le(a, b, ...) assert_cmp(int32_t, a, b, <=, \
>, PRId32, fmt) >, FMTd32, __VA_ARGS__)
#define assert_d32_ge(a, b, fmt...) assert_cmp(int32_t, a, b, >=, \ #define assert_d32_ge(a, b, ...) assert_cmp(int32_t, a, b, >=, \
<, PRId32, fmt) <, FMTd32, __VA_ARGS__)
#define assert_d32_gt(a, b, fmt...) assert_cmp(int32_t, a, b, >, \ #define assert_d32_gt(a, b, ...) assert_cmp(int32_t, a, b, >, \
<=, PRId32, fmt) <=, FMTd32, __VA_ARGS__)
#define assert_u32_eq(a, b, fmt...) assert_cmp(uint32_t, a, b, ==, \ #define assert_u32_eq(a, b, ...) assert_cmp(uint32_t, a, b, ==, \
!=, PRIu32, fmt) !=, FMTu32, __VA_ARGS__)
#define assert_u32_ne(a, b, fmt...) assert_cmp(uint32_t, a, b, !=, \ #define assert_u32_ne(a, b, ...) assert_cmp(uint32_t, a, b, !=, \
==, PRIu32, fmt) ==, FMTu32, __VA_ARGS__)
#define assert_u32_lt(a, b, fmt...) assert_cmp(uint32_t, a, b, <, \ #define assert_u32_lt(a, b, ...) assert_cmp(uint32_t, a, b, <, \
>=, PRIu32, fmt) >=, FMTu32, __VA_ARGS__)
#define assert_u32_le(a, b, fmt...) assert_cmp(uint32_t, a, b, <=, \ #define assert_u32_le(a, b, ...) assert_cmp(uint32_t, a, b, <=, \
>, PRIu32, fmt) >, FMTu32, __VA_ARGS__)
#define assert_u32_ge(a, b, fmt...) assert_cmp(uint32_t, a, b, >=, \ #define assert_u32_ge(a, b, ...) assert_cmp(uint32_t, a, b, >=, \
<, PRIu32, fmt) <, FMTu32, __VA_ARGS__)
#define assert_u32_gt(a, b, fmt...) assert_cmp(uint32_t, a, b, >, \ #define assert_u32_gt(a, b, ...) assert_cmp(uint32_t, a, b, >, \
<=, PRIu32, fmt) <=, FMTu32, __VA_ARGS__)
#define assert_d64_eq(a, b, fmt...) assert_cmp(int64_t, a, b, ==, \ #define assert_d64_eq(a, b, ...) assert_cmp(int64_t, a, b, ==, \
!=, PRId64, fmt) !=, FMTd64, __VA_ARGS__)
#define assert_d64_ne(a, b, fmt...) assert_cmp(int64_t, a, b, !=, \ #define assert_d64_ne(a, b, ...) assert_cmp(int64_t, a, b, !=, \
==, PRId64, fmt) ==, FMTd64, __VA_ARGS__)
#define assert_d64_lt(a, b, fmt...) assert_cmp(int64_t, a, b, <, \ #define assert_d64_lt(a, b, ...) assert_cmp(int64_t, a, b, <, \
>=, PRId64, fmt) >=, FMTd64, __VA_ARGS__)
#define assert_d64_le(a, b, fmt...) assert_cmp(int64_t, a, b, <=, \ #define assert_d64_le(a, b, ...) assert_cmp(int64_t, a, b, <=, \
>, PRId64, fmt) >, FMTd64, __VA_ARGS__)
#define assert_d64_ge(a, b, fmt...) assert_cmp(int64_t, a, b, >=, \ #define assert_d64_ge(a, b, ...) assert_cmp(int64_t, a, b, >=, \
<, PRId64, fmt) <, FMTd64, __VA_ARGS__)
#define assert_d64_gt(a, b, fmt...) assert_cmp(int64_t, a, b, >, \ #define assert_d64_gt(a, b, ...) assert_cmp(int64_t, a, b, >, \
<=, PRId64, fmt) <=, FMTd64, __VA_ARGS__)
#define assert_u64_eq(a, b, fmt...) assert_cmp(uint64_t, a, b, ==, \ #define assert_u64_eq(a, b, ...) assert_cmp(uint64_t, a, b, ==, \
!=, PRIu64, fmt) !=, FMTu64, __VA_ARGS__)
#define assert_u64_ne(a, b, fmt...) assert_cmp(uint64_t, a, b, !=, \ #define assert_u64_ne(a, b, ...) assert_cmp(uint64_t, a, b, !=, \
==, PRIu64, fmt) ==, FMTu64, __VA_ARGS__)
#define assert_u64_lt(a, b, fmt...) assert_cmp(uint64_t, a, b, <, \ #define assert_u64_lt(a, b, ...) assert_cmp(uint64_t, a, b, <, \
>=, PRIu64, fmt) >=, FMTu64, __VA_ARGS__)
#define assert_u64_le(a, b, fmt...) assert_cmp(uint64_t, a, b, <=, \ #define assert_u64_le(a, b, ...) assert_cmp(uint64_t, a, b, <=, \
>, PRIu64, fmt) >, FMTu64, __VA_ARGS__)
#define assert_u64_ge(a, b, fmt...) assert_cmp(uint64_t, a, b, >=, \ #define assert_u64_ge(a, b, ...) assert_cmp(uint64_t, a, b, >=, \
<, PRIu64, fmt) <, FMTu64, __VA_ARGS__)
#define assert_u64_gt(a, b, fmt...) assert_cmp(uint64_t, a, b, >, \ #define assert_u64_gt(a, b, ...) assert_cmp(uint64_t, a, b, >, \
<=, PRIu64, fmt) <=, FMTu64, __VA_ARGS__)
#define assert_b_eq(a, b, fmt...) do { \ #define assert_b_eq(a, b, ...) do { \
bool a_ = (a); \ bool a_ = (a); \
bool b_ = (b); \ bool b_ = (b); \
if (!(a_ == b_)) { \ if (!(a_ == b_)) { \
...@@ -222,11 +222,11 @@ ...@@ -222,11 +222,11 @@
__func__, __FILE__, __LINE__, \ __func__, __FILE__, __LINE__, \
#a, #b, a_ ? "true" : "false", \ #a, #b, a_ ? "true" : "false", \
b_ ? "true" : "false"); \ b_ ? "true" : "false"); \
malloc_snprintf(message, sizeof(message), fmt); \ malloc_snprintf(message, sizeof(message), __VA_ARGS__); \
p_test_fail(prefix, message); \ p_test_fail(prefix, message); \
} \ } \
} while (0) } while (0)
#define assert_b_ne(a, b, fmt...) do { \ #define assert_b_ne(a, b, ...) do { \
bool a_ = (a); \ bool a_ = (a); \
bool b_ = (b); \ bool b_ = (b); \
if (!(a_ != b_)) { \ if (!(a_ != b_)) { \
...@@ -238,14 +238,14 @@ ...@@ -238,14 +238,14 @@
__func__, __FILE__, __LINE__, \ __func__, __FILE__, __LINE__, \
#a, #b, a_ ? "true" : "false", \ #a, #b, a_ ? "true" : "false", \
b_ ? "true" : "false"); \ b_ ? "true" : "false"); \
malloc_snprintf(message, sizeof(message), fmt); \ malloc_snprintf(message, sizeof(message), __VA_ARGS__); \
p_test_fail(prefix, message); \ p_test_fail(prefix, message); \
} \ } \
} while (0) } while (0)
#define assert_true(a, fmt...) assert_b_eq(a, true, fmt) #define assert_true(a, ...) assert_b_eq(a, true, __VA_ARGS__)
#define assert_false(a, fmt...) assert_b_eq(a, false, fmt) #define assert_false(a, ...) assert_b_eq(a, false, __VA_ARGS__)
#define assert_str_eq(a, b, fmt...) do { \ #define assert_str_eq(a, b, ...) do { \
if (strcmp((a), (b))) { \ if (strcmp((a), (b))) { \
char prefix[ASSERT_BUFSIZE]; \ char prefix[ASSERT_BUFSIZE]; \
char message[ASSERT_BUFSIZE]; \ char message[ASSERT_BUFSIZE]; \
...@@ -254,11 +254,11 @@ ...@@ -254,11 +254,11 @@
"(%s) same as (%s) --> " \ "(%s) same as (%s) --> " \
"\"%s\" differs from \"%s\": ", \ "\"%s\" differs from \"%s\": ", \
__func__, __FILE__, __LINE__, #a, #b, a, b); \ __func__, __FILE__, __LINE__, #a, #b, a, b); \
malloc_snprintf(message, sizeof(message), fmt); \ malloc_snprintf(message, sizeof(message), __VA_ARGS__); \
p_test_fail(prefix, message); \ p_test_fail(prefix, message); \
} \ } \
} while (0) } while (0)
#define assert_str_ne(a, b, fmt...) do { \ #define assert_str_ne(a, b, ...) do { \
if (!strcmp((a), (b))) { \ if (!strcmp((a), (b))) { \
char prefix[ASSERT_BUFSIZE]; \ char prefix[ASSERT_BUFSIZE]; \
char message[ASSERT_BUFSIZE]; \ char message[ASSERT_BUFSIZE]; \
...@@ -267,18 +267,18 @@ ...@@ -267,18 +267,18 @@
"(%s) differs from (%s) --> " \ "(%s) differs from (%s) --> " \
"\"%s\" same as \"%s\": ", \ "\"%s\" same as \"%s\": ", \
__func__, __FILE__, __LINE__, #a, #b, a, b); \ __func__, __FILE__, __LINE__, #a, #b, a, b); \
malloc_snprintf(message, sizeof(message), fmt); \ malloc_snprintf(message, sizeof(message), __VA_ARGS__); \
p_test_fail(prefix, message); \ p_test_fail(prefix, message); \
} \ } \
} while (0) } while (0)
#define assert_not_reached(fmt...) do { \ #define assert_not_reached(...) do { \
char prefix[ASSERT_BUFSIZE]; \ char prefix[ASSERT_BUFSIZE]; \
char message[ASSERT_BUFSIZE]; \ char message[ASSERT_BUFSIZE]; \
malloc_snprintf(prefix, sizeof(prefix), \ malloc_snprintf(prefix, sizeof(prefix), \
"%s:%s:%d: Unreachable code reached: ", \ "%s:%s:%d: Unreachable code reached: ", \
__func__, __FILE__, __LINE__); \ __func__, __FILE__, __LINE__); \
malloc_snprintf(message, sizeof(message), fmt); \ malloc_snprintf(message, sizeof(message), __VA_ARGS__); \
p_test_fail(prefix, message); \ p_test_fail(prefix, message); \
} while (0) } while (0)
...@@ -308,8 +308,8 @@ label_test_end: \ ...@@ -308,8 +308,8 @@ label_test_end: \
p_test_fini(); \ p_test_fini(); \
} }
#define test(tests...) \ #define test(...) \
p_test(tests, NULL) p_test(__VA_ARGS__, NULL)
#define test_skip_if(e) do { \ #define test_skip_if(e) do { \
if (e) { \ if (e) { \
...@@ -319,11 +319,11 @@ label_test_end: \ ...@@ -319,11 +319,11 @@ label_test_end: \
} \ } \
} while (0) } while (0)
void test_skip(const char *format, ...) JEMALLOC_ATTR(format(printf, 1, 2)); void test_skip(const char *format, ...) JEMALLOC_FORMAT_PRINTF(1, 2);
void test_fail(const char *format, ...) JEMALLOC_ATTR(format(printf, 1, 2)); void test_fail(const char *format, ...) JEMALLOC_FORMAT_PRINTF(1, 2);
/* For private use by macros. */ /* For private use by macros. */
test_status_t p_test(test_t* t, ...); test_status_t p_test(test_t *t, ...);
void p_test_init(const char *name); void p_test_init(const char *name);
void p_test_fini(void); void p_test_fini(void);
void p_test_fail(const char *prefix, const char *message); void p_test_fail(const char *prefix, const char *message);
/* Abstraction layer for threading in tests */ /* Abstraction layer for threading in tests. */
#ifdef _WIN32 #ifdef _WIN32
typedef HANDLE thd_t; typedef HANDLE thd_t;
#else #else
......
/* Simple timer, for use in benchmark reporting. */
#include <unistd.h>
#include <sys/time.h>
#define JEMALLOC_CLOCK_GETTIME defined(_POSIX_MONOTONIC_CLOCK) \
&& _POSIX_MONOTONIC_CLOCK >= 0
typedef struct {
#ifdef _WIN32
FILETIME ft0;
FILETIME ft1;
#elif JEMALLOC_CLOCK_GETTIME
struct timespec ts0;
struct timespec ts1;
int clock_id;
#else
struct timeval tv0;
struct timeval tv1;
#endif
} timedelta_t;
void timer_start(timedelta_t *timer);
void timer_stop(timedelta_t *timer);
uint64_t timer_usec(const timedelta_t *timer);
void timer_ratio(timedelta_t *a, timedelta_t *b, char *buf, size_t buflen);
...@@ -2,6 +2,14 @@ ...@@ -2,6 +2,14 @@
#define NTHREADS 10 #define NTHREADS 10
static bool have_dss =
#ifdef JEMALLOC_DSS
true
#else
false
#endif
;
void * void *
thd_start(void *arg) thd_start(void *arg)
{ {
...@@ -18,13 +26,16 @@ thd_start(void *arg) ...@@ -18,13 +26,16 @@ thd_start(void *arg)
size_t mib[3]; size_t mib[3];
size_t miblen = sizeof(mib) / sizeof(size_t); size_t miblen = sizeof(mib) / sizeof(size_t);
const char *dss_precs[] = {"disabled", "primary", "secondary"}; const char *dss_precs[] = {"disabled", "primary", "secondary"};
const char *dss = dss_precs[thread_ind % unsigned prec_ind = thread_ind %
(sizeof(dss_precs)/sizeof(char*))]; (sizeof(dss_precs)/sizeof(char*));
const char *dss = dss_precs[prec_ind];
int expected_err = (have_dss || prec_ind == 0) ? 0 : EFAULT;
assert_d_eq(mallctlnametomib("arena.0.dss", mib, &miblen), 0, assert_d_eq(mallctlnametomib("arena.0.dss", mib, &miblen), 0,
"Error in mallctlnametomib()"); "Error in mallctlnametomib()");
mib[1] = arena_ind; mib[1] = arena_ind;
assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, (void *)&dss, assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, (void *)&dss,
sizeof(const char *)), 0, "Error in mallctlbymib()"); sizeof(const char *)), expected_err,
"Error in mallctlbymib()");
} }
p = mallocx(1, MALLOCX_ARENA(arena_ind)); p = mallocx(1, MALLOCX_ARENA(arena_ind));
...@@ -34,7 +45,7 @@ thd_start(void *arg) ...@@ -34,7 +45,7 @@ thd_start(void *arg)
return (NULL); return (NULL);
} }
TEST_BEGIN(test_ALLOCM_ARENA) TEST_BEGIN(test_MALLOCX_ARENA)
{ {
thd_t thds[NTHREADS]; thd_t thds[NTHREADS];
unsigned i; unsigned i;
...@@ -54,5 +65,5 @@ main(void) ...@@ -54,5 +65,5 @@ main(void)
{ {
return (test( return (test(
test_ALLOCM_ARENA)); test_MALLOCX_ARENA));
} }
#include "test/jemalloc_test.h"
#define CHUNK 0x400000
#define MAXALIGN (((size_t)1) << 25)
#define NITER 4
TEST_BEGIN(test_basic)
{
size_t nsz, rsz, sz;
void *p;
sz = 42;
nsz = 0;
assert_d_eq(nallocm(&nsz, sz, 0), ALLOCM_SUCCESS,
"Unexpected nallocm() error");
rsz = 0;
assert_d_eq(allocm(&p, &rsz, sz, 0), ALLOCM_SUCCESS,
"Unexpected allocm() error");
assert_zu_ge(rsz, sz, "Real size smaller than expected");
assert_zu_eq(nsz, rsz, "nallocm()/allocm() rsize mismatch");
assert_d_eq(dallocm(p, 0), ALLOCM_SUCCESS,
"Unexpected dallocm() error");
assert_d_eq(allocm(&p, NULL, sz, 0), ALLOCM_SUCCESS,
"Unexpected allocm() error");
assert_d_eq(dallocm(p, 0), ALLOCM_SUCCESS,
"Unexpected dallocm() error");
nsz = 0;
assert_d_eq(nallocm(&nsz, sz, ALLOCM_ZERO), ALLOCM_SUCCESS,
"Unexpected nallocm() error");
rsz = 0;
assert_d_eq(allocm(&p, &rsz, sz, ALLOCM_ZERO), ALLOCM_SUCCESS,
"Unexpected allocm() error");
assert_zu_eq(nsz, rsz, "nallocm()/allocm() rsize mismatch");
assert_d_eq(dallocm(p, 0), ALLOCM_SUCCESS,
"Unexpected dallocm() error");
}
TEST_END
TEST_BEGIN(test_alignment_and_size)
{
int r;
size_t nsz, rsz, sz, alignment, total;
unsigned i;
void *ps[NITER];
for (i = 0; i < NITER; i++)
ps[i] = NULL;
for (alignment = 8;
alignment <= MAXALIGN;
alignment <<= 1) {
total = 0;
for (sz = 1;
sz < 3 * alignment && sz < (1U << 31);
sz += (alignment >> (LG_SIZEOF_PTR-1)) - 1) {
for (i = 0; i < NITER; i++) {
nsz = 0;
r = nallocm(&nsz, sz, ALLOCM_ALIGN(alignment) |
ALLOCM_ZERO);
assert_d_eq(r, ALLOCM_SUCCESS,
"nallocm() error for alignment=%zu, "
"size=%zu (%#zx): %d",
alignment, sz, sz, r);
rsz = 0;
r = allocm(&ps[i], &rsz, sz,
ALLOCM_ALIGN(alignment) | ALLOCM_ZERO);
assert_d_eq(r, ALLOCM_SUCCESS,
"allocm() error for alignment=%zu, "
"size=%zu (%#zx): %d",
alignment, sz, sz, r);
assert_zu_ge(rsz, sz,
"Real size smaller than expected for "
"alignment=%zu, size=%zu", alignment, sz);
assert_zu_eq(nsz, rsz,
"nallocm()/allocm() rsize mismatch for "
"alignment=%zu, size=%zu", alignment, sz);
assert_ptr_null(
(void *)((uintptr_t)ps[i] & (alignment-1)),
"%p inadequately aligned for"
" alignment=%zu, size=%zu", ps[i],
alignment, sz);
sallocm(ps[i], &rsz, 0);
total += rsz;
if (total >= (MAXALIGN << 1))
break;
}
for (i = 0; i < NITER; i++) {
if (ps[i] != NULL) {
dallocm(ps[i], 0);
ps[i] = NULL;
}
}
}
}
}
TEST_END
int
main(void)
{
return (test(
test_basic,
test_alignment_and_size));
}
#include "test/jemalloc_test.h"
#ifdef JEMALLOC_FILL
const char *malloc_conf = "junk:false";
#endif
static chunk_hooks_t orig_hooks;
static chunk_hooks_t old_hooks;
static bool do_dalloc = true;
static bool do_decommit;
static bool did_alloc;
static bool did_dalloc;
static bool did_commit;
static bool did_decommit;
static bool did_purge;
static bool did_split;
static bool did_merge;
#if 0
# define TRACE_HOOK(fmt, ...) malloc_printf(fmt, __VA_ARGS__)
#else
# define TRACE_HOOK(fmt, ...)
#endif
void *
chunk_alloc(void *new_addr, size_t size, size_t alignment, bool *zero,
bool *commit, unsigned arena_ind)
{
TRACE_HOOK("%s(new_addr=%p, size=%zu, alignment=%zu, *zero=%s, "
"*commit=%s, arena_ind=%u)\n", __func__, new_addr, size, alignment,
*zero ? "true" : "false", *commit ? "true" : "false", arena_ind);
did_alloc = true;
return (old_hooks.alloc(new_addr, size, alignment, zero, commit,
arena_ind));
}
bool
chunk_dalloc(void *chunk, size_t size, bool committed, unsigned arena_ind)
{
TRACE_HOOK("%s(chunk=%p, size=%zu, committed=%s, arena_ind=%u)\n",
__func__, chunk, size, committed ? "true" : "false", arena_ind);
did_dalloc = true;
if (!do_dalloc)
return (true);
return (old_hooks.dalloc(chunk, size, committed, arena_ind));
}
bool
chunk_commit(void *chunk, size_t size, size_t offset, size_t length,
unsigned arena_ind)
{
bool err;
TRACE_HOOK("%s(chunk=%p, size=%zu, offset=%zu, length=%zu, "
"arena_ind=%u)\n", __func__, chunk, size, offset, length,
arena_ind);
err = old_hooks.commit(chunk, size, offset, length, arena_ind);
did_commit = !err;
return (err);
}
bool
chunk_decommit(void *chunk, size_t size, size_t offset, size_t length,
unsigned arena_ind)
{
bool err;
TRACE_HOOK("%s(chunk=%p, size=%zu, offset=%zu, length=%zu, "
"arena_ind=%u)\n", __func__, chunk, size, offset, length,
arena_ind);
if (!do_decommit)
return (true);
err = old_hooks.decommit(chunk, size, offset, length, arena_ind);
did_decommit = !err;
return (err);
}
bool
chunk_purge(void *chunk, size_t size, size_t offset, size_t length,
unsigned arena_ind)
{
TRACE_HOOK("%s(chunk=%p, size=%zu, offset=%zu, length=%zu "
"arena_ind=%u)\n", __func__, chunk, size, offset, length,
arena_ind);
did_purge = true;
return (old_hooks.purge(chunk, size, offset, length, arena_ind));
}
bool
chunk_split(void *chunk, size_t size, size_t size_a, size_t size_b,
bool committed, unsigned arena_ind)
{
TRACE_HOOK("%s(chunk=%p, size=%zu, size_a=%zu, size_b=%zu, "
"committed=%s, arena_ind=%u)\n", __func__, chunk, size, size_a,
size_b, committed ? "true" : "false", arena_ind);
did_split = true;
return (old_hooks.split(chunk, size, size_a, size_b, committed,
arena_ind));
}
bool
chunk_merge(void *chunk_a, size_t size_a, void *chunk_b, size_t size_b,
bool committed, unsigned arena_ind)
{
TRACE_HOOK("%s(chunk_a=%p, size_a=%zu, chunk_b=%p size_b=%zu, "
"committed=%s, arena_ind=%u)\n", __func__, chunk_a, size_a, chunk_b,
size_b, committed ? "true" : "false", arena_ind);
did_merge = true;
return (old_hooks.merge(chunk_a, size_a, chunk_b, size_b,
committed, arena_ind));
}
TEST_BEGIN(test_chunk)
{
void *p;
size_t old_size, new_size, large0, large1, huge0, huge1, huge2, sz;
chunk_hooks_t new_hooks = {
chunk_alloc,
chunk_dalloc,
chunk_commit,
chunk_decommit,
chunk_purge,
chunk_split,
chunk_merge
};
bool xallocx_success_a, xallocx_success_b, xallocx_success_c;
/* Install custom chunk hooks. */
old_size = sizeof(chunk_hooks_t);
new_size = sizeof(chunk_hooks_t);
assert_d_eq(mallctl("arena.0.chunk_hooks", &old_hooks, &old_size,
&new_hooks, new_size), 0, "Unexpected chunk_hooks error");
orig_hooks = old_hooks;
assert_ptr_ne(old_hooks.alloc, chunk_alloc, "Unexpected alloc error");
assert_ptr_ne(old_hooks.dalloc, chunk_dalloc,
"Unexpected dalloc error");
assert_ptr_ne(old_hooks.commit, chunk_commit,
"Unexpected commit error");
assert_ptr_ne(old_hooks.decommit, chunk_decommit,
"Unexpected decommit error");
assert_ptr_ne(old_hooks.purge, chunk_purge, "Unexpected purge error");
assert_ptr_ne(old_hooks.split, chunk_split, "Unexpected split error");
assert_ptr_ne(old_hooks.merge, chunk_merge, "Unexpected merge error");
/* Get large size classes. */
sz = sizeof(size_t);
assert_d_eq(mallctl("arenas.lrun.0.size", &large0, &sz, NULL, 0), 0,
"Unexpected arenas.lrun.0.size failure");
assert_d_eq(mallctl("arenas.lrun.1.size", &large1, &sz, NULL, 0), 0,
"Unexpected arenas.lrun.1.size failure");
/* Get huge size classes. */
assert_d_eq(mallctl("arenas.hchunk.0.size", &huge0, &sz, NULL, 0), 0,
"Unexpected arenas.hchunk.0.size failure");
assert_d_eq(mallctl("arenas.hchunk.1.size", &huge1, &sz, NULL, 0), 0,
"Unexpected arenas.hchunk.1.size failure");
assert_d_eq(mallctl("arenas.hchunk.2.size", &huge2, &sz, NULL, 0), 0,
"Unexpected arenas.hchunk.2.size failure");
/* Test dalloc/decommit/purge cascade. */
do_dalloc = false;
do_decommit = false;
p = mallocx(huge0 * 2, 0);
assert_ptr_not_null(p, "Unexpected mallocx() error");
did_dalloc = false;
did_decommit = false;
did_purge = false;
did_split = false;
xallocx_success_a = (xallocx(p, huge0, 0, 0) == huge0);
assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0,
"Unexpected arena.0.purge error");
if (xallocx_success_a) {
assert_true(did_dalloc, "Expected dalloc");
assert_false(did_decommit, "Unexpected decommit");
assert_true(did_purge, "Expected purge");
}
assert_true(did_split, "Expected split");
dallocx(p, 0);
do_dalloc = true;
/* Test decommit/commit and observe split/merge. */
do_dalloc = false;
do_decommit = true;
p = mallocx(huge0 * 2, 0);
assert_ptr_not_null(p, "Unexpected mallocx() error");
did_decommit = false;
did_commit = false;
did_split = false;
did_merge = false;
xallocx_success_b = (xallocx(p, huge0, 0, 0) == huge0);
assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0,
"Unexpected arena.0.purge error");
if (xallocx_success_b)
assert_true(did_split, "Expected split");
xallocx_success_c = (xallocx(p, huge0 * 2, 0, 0) == huge0 * 2);
assert_b_eq(did_decommit, did_commit, "Expected decommit/commit match");
if (xallocx_success_b && xallocx_success_c)
assert_true(did_merge, "Expected merge");
dallocx(p, 0);
do_dalloc = true;
do_decommit = false;
/* Test purge for partial-chunk huge allocations. */
if (huge0 * 2 > huge2) {
/*
* There are at least four size classes per doubling, so a
* successful xallocx() from size=huge2 to size=huge1 is
* guaranteed to leave trailing purgeable memory.
*/
p = mallocx(huge2, 0);
assert_ptr_not_null(p, "Unexpected mallocx() error");
did_purge = false;
assert_zu_eq(xallocx(p, huge1, 0, 0), huge1,
"Unexpected xallocx() failure");
assert_true(did_purge, "Expected purge");
dallocx(p, 0);
}
/* Test decommit for large allocations. */
do_decommit = true;
p = mallocx(large1, 0);
assert_ptr_not_null(p, "Unexpected mallocx() error");
assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0,
"Unexpected arena.0.purge error");
did_decommit = false;
assert_zu_eq(xallocx(p, large0, 0, 0), large0,
"Unexpected xallocx() failure");
assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0,
"Unexpected arena.0.purge error");
did_commit = false;
assert_zu_eq(xallocx(p, large1, 0, 0), large1,
"Unexpected xallocx() failure");
assert_b_eq(did_decommit, did_commit, "Expected decommit/commit match");
dallocx(p, 0);
do_decommit = false;
/* Make sure non-huge allocation succeeds. */
p = mallocx(42, 0);
assert_ptr_not_null(p, "Unexpected mallocx() error");
dallocx(p, 0);
/* Restore chunk hooks. */
assert_d_eq(mallctl("arena.0.chunk_hooks", NULL, NULL, &old_hooks,
new_size), 0, "Unexpected chunk_hooks error");
assert_d_eq(mallctl("arena.0.chunk_hooks", &old_hooks, &old_size,
NULL, 0), 0, "Unexpected chunk_hooks error");
assert_ptr_eq(old_hooks.alloc, orig_hooks.alloc,
"Unexpected alloc error");
assert_ptr_eq(old_hooks.dalloc, orig_hooks.dalloc,
"Unexpected dalloc error");
assert_ptr_eq(old_hooks.commit, orig_hooks.commit,
"Unexpected commit error");
assert_ptr_eq(old_hooks.decommit, orig_hooks.decommit,
"Unexpected decommit error");
assert_ptr_eq(old_hooks.purge, orig_hooks.purge,
"Unexpected purge error");
assert_ptr_eq(old_hooks.split, orig_hooks.split,
"Unexpected split error");
assert_ptr_eq(old_hooks.merge, orig_hooks.merge,
"Unexpected merge error");
}
TEST_END
int
main(void)
{
return (test(test_chunk));
}
#include "test/jemalloc_test.h" #include "test/jemalloc_test.h"
#define CHUNK 0x400000 static unsigned
#define MAXALIGN (((size_t)1) << 25) get_nsizes_impl(const char *cmd)
#define NITER 4 {
unsigned ret;
size_t z;
z = sizeof(unsigned);
assert_d_eq(mallctl(cmd, &ret, &z, NULL, 0), 0,
"Unexpected mallctl(\"%s\", ...) failure", cmd);
return (ret);
}
static unsigned
get_nhuge(void)
{
return (get_nsizes_impl("arenas.nhchunks"));
}
static size_t
get_size_impl(const char *cmd, size_t ind)
{
size_t ret;
size_t z;
size_t mib[4];
size_t miblen = 4;
z = sizeof(size_t);
assert_d_eq(mallctlnametomib(cmd, mib, &miblen),
0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd);
mib[2] = ind;
z = sizeof(size_t);
assert_d_eq(mallctlbymib(mib, miblen, &ret, &z, NULL, 0),
0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind);
return (ret);
}
static size_t
get_huge_size(size_t ind)
{
return (get_size_impl("arenas.hchunk.0.size", ind));
}
TEST_BEGIN(test_oom)
{
size_t hugemax, size, alignment;
hugemax = get_huge_size(get_nhuge()-1);
/*
* It should be impossible to allocate two objects that each consume
* more than half the virtual address space.
*/
{
void *p;
p = mallocx(hugemax, 0);
if (p != NULL) {
assert_ptr_null(mallocx(hugemax, 0),
"Expected OOM for mallocx(size=%#zx, 0)", hugemax);
dallocx(p, 0);
}
}
#if LG_SIZEOF_PTR == 3
size = ZU(0x8000000000000000);
alignment = ZU(0x8000000000000000);
#else
size = ZU(0x80000000);
alignment = ZU(0x80000000);
#endif
assert_ptr_null(mallocx(size, MALLOCX_ALIGN(alignment)),
"Expected OOM for mallocx(size=%#zx, MALLOCX_ALIGN(%#zx)", size,
alignment);
}
TEST_END
TEST_BEGIN(test_basic) TEST_BEGIN(test_basic)
{ {
size_t nsz, rsz, sz; #define MAXSZ (((size_t)1) << 26)
void *p; size_t sz;
sz = 42; for (sz = 1; sz < MAXSZ; sz = nallocx(sz, 0) + 1) {
nsz = nallocx(sz, 0); size_t nsz, rsz;
assert_zu_ne(nsz, 0, "Unexpected nallocx() error"); void *p;
p = mallocx(sz, 0); nsz = nallocx(sz, 0);
assert_ptr_not_null(p, "Unexpected mallocx() error"); assert_zu_ne(nsz, 0, "Unexpected nallocx() error");
rsz = sallocx(p, 0); p = mallocx(sz, 0);
assert_zu_ge(rsz, sz, "Real size smaller than expected"); assert_ptr_not_null(p, "Unexpected mallocx() error");
assert_zu_eq(nsz, rsz, "nallocx()/sallocx() size mismatch"); rsz = sallocx(p, 0);
dallocx(p, 0); assert_zu_ge(rsz, sz, "Real size smaller than expected");
assert_zu_eq(nsz, rsz, "nallocx()/sallocx() size mismatch");
p = mallocx(sz, 0); dallocx(p, 0);
assert_ptr_not_null(p, "Unexpected mallocx() error");
dallocx(p, 0); p = mallocx(sz, 0);
assert_ptr_not_null(p, "Unexpected mallocx() error");
nsz = nallocx(sz, MALLOCX_ZERO); dallocx(p, 0);
assert_zu_ne(nsz, 0, "Unexpected nallocx() error");
p = mallocx(sz, MALLOCX_ZERO); nsz = nallocx(sz, MALLOCX_ZERO);
assert_ptr_not_null(p, "Unexpected mallocx() error"); assert_zu_ne(nsz, 0, "Unexpected nallocx() error");
rsz = sallocx(p, 0); p = mallocx(sz, MALLOCX_ZERO);
assert_zu_eq(nsz, rsz, "nallocx()/sallocx() rsize mismatch"); assert_ptr_not_null(p, "Unexpected mallocx() error");
dallocx(p, 0); rsz = sallocx(p, 0);
assert_zu_eq(nsz, rsz, "nallocx()/sallocx() rsize mismatch");
dallocx(p, 0);
}
#undef MAXSZ
} }
TEST_END TEST_END
TEST_BEGIN(test_alignment_and_size) TEST_BEGIN(test_alignment_and_size)
{ {
#define MAXALIGN (((size_t)1) << 25)
#define NITER 4
size_t nsz, rsz, sz, alignment, total; size_t nsz, rsz, sz, alignment, total;
unsigned i; unsigned i;
void *ps[NITER]; void *ps[NITER];
...@@ -84,6 +166,8 @@ TEST_BEGIN(test_alignment_and_size) ...@@ -84,6 +166,8 @@ TEST_BEGIN(test_alignment_and_size)
} }
} }
} }
#undef MAXALIGN
#undef NITER
} }
TEST_END TEST_END
...@@ -92,6 +176,7 @@ main(void) ...@@ -92,6 +176,7 @@ main(void)
{ {
return (test( return (test(
test_oom,
test_basic, test_basic,
test_alignment_and_size)); test_alignment_and_size));
} }
#include "test/jemalloc_test.h"
TEST_BEGIN(test_mremap)
{
int err;
size_t sz, lg_chunk, chunksize, i;
char *p, *q;
sz = sizeof(lg_chunk);
err = mallctl("opt.lg_chunk", &lg_chunk, &sz, NULL, 0);
assert_d_eq(err, 0, "Error in mallctl(): %s", strerror(err));
chunksize = ((size_t)1U) << lg_chunk;
p = (char *)malloc(chunksize);
assert_ptr_not_null(p, "malloc(%zu) --> %p", chunksize, p);
memset(p, 'a', chunksize);
q = (char *)realloc(p, chunksize * 2);
assert_ptr_not_null(q, "realloc(%p, %zu) --> %p", p, chunksize * 2,
q);
for (i = 0; i < chunksize; i++) {
assert_c_eq(q[i], 'a',
"realloc() should preserve existing bytes across copies");
}
p = q;
q = (char *)realloc(p, chunksize);
assert_ptr_not_null(q, "realloc(%p, %zu) --> %p", p, chunksize, q);
for (i = 0; i < chunksize; i++) {
assert_c_eq(q[i], 'a',
"realloc() should preserve existing bytes across copies");
}
free(q);
}
TEST_END
int
main(void)
{
return (test(
test_mremap));
}
#include "test/jemalloc_test.h"
TEST_BEGIN(test_overflow)
{
unsigned nhchunks;
size_t mib[4];
size_t sz, miblen, max_size_class;
void *p;
sz = sizeof(unsigned);
assert_d_eq(mallctl("arenas.nhchunks", &nhchunks, &sz, NULL, 0), 0,
"Unexpected mallctl() error");
miblen = sizeof(mib) / sizeof(size_t);
assert_d_eq(mallctlnametomib("arenas.hchunk.0.size", mib, &miblen), 0,
"Unexpected mallctlnametomib() error");
mib[2] = nhchunks - 1;
sz = sizeof(size_t);
assert_d_eq(mallctlbymib(mib, miblen, &max_size_class, &sz, NULL, 0), 0,
"Unexpected mallctlbymib() error");
assert_ptr_null(malloc(max_size_class + 1),
"Expected OOM due to over-sized allocation request");
assert_ptr_null(malloc(SIZE_T_MAX),
"Expected OOM due to over-sized allocation request");
assert_ptr_null(calloc(1, max_size_class + 1),
"Expected OOM due to over-sized allocation request");
assert_ptr_null(calloc(1, SIZE_T_MAX),
"Expected OOM due to over-sized allocation request");
p = malloc(1);
assert_ptr_not_null(p, "Unexpected malloc() OOM");
assert_ptr_null(realloc(p, max_size_class + 1),
"Expected OOM due to over-sized allocation request");
assert_ptr_null(realloc(p, SIZE_T_MAX),
"Expected OOM due to over-sized allocation request");
free(p);
}
TEST_END
int
main(void)
{
return (test(
test_overflow));
}
#include "test/jemalloc_test.h"
TEST_BEGIN(test_same_size)
{
void *p, *q;
size_t sz, tsz;
assert_d_eq(allocm(&p, &sz, 42, 0), ALLOCM_SUCCESS,
"Unexpected allocm() error");
q = p;
assert_d_eq(rallocm(&q, &tsz, sz, 0, ALLOCM_NO_MOVE), ALLOCM_SUCCESS,
"Unexpected rallocm() error");
assert_ptr_eq(q, p, "Unexpected object move");
assert_zu_eq(tsz, sz, "Unexpected size change: %zu --> %zu", sz, tsz);
assert_d_eq(dallocm(p, 0), ALLOCM_SUCCESS,
"Unexpected dallocm() error");
}
TEST_END
TEST_BEGIN(test_extra_no_move)
{
void *p, *q;
size_t sz, tsz;
assert_d_eq(allocm(&p, &sz, 42, 0), ALLOCM_SUCCESS,
"Unexpected allocm() error");
q = p;
assert_d_eq(rallocm(&q, &tsz, sz, sz-42, ALLOCM_NO_MOVE),
ALLOCM_SUCCESS, "Unexpected rallocm() error");
assert_ptr_eq(q, p, "Unexpected object move");
assert_zu_eq(tsz, sz, "Unexpected size change: %zu --> %zu", sz, tsz);
assert_d_eq(dallocm(p, 0), ALLOCM_SUCCESS,
"Unexpected dallocm() error");
}
TEST_END
TEST_BEGIN(test_no_move_fail)
{
void *p, *q;
size_t sz, tsz;
assert_d_eq(allocm(&p, &sz, 42, 0), ALLOCM_SUCCESS,
"Unexpected allocm() error");
q = p;
assert_d_eq(rallocm(&q, &tsz, sz + 5, 0, ALLOCM_NO_MOVE),
ALLOCM_ERR_NOT_MOVED, "Unexpected rallocm() result");
assert_ptr_eq(q, p, "Unexpected object move");
assert_zu_eq(tsz, sz, "Unexpected size change: %zu --> %zu", sz, tsz);
assert_d_eq(dallocm(p, 0), ALLOCM_SUCCESS,
"Unexpected dallocm() error");
}
TEST_END
TEST_BEGIN(test_grow_and_shrink)
{
void *p, *q;
size_t tsz;
#define NCYCLES 3
unsigned i, j;
#define NSZS 2500
size_t szs[NSZS];
#define MAXSZ ZU(12 * 1024 * 1024)
assert_d_eq(allocm(&p, &szs[0], 1, 0), ALLOCM_SUCCESS,
"Unexpected allocm() error");
for (i = 0; i < NCYCLES; i++) {
for (j = 1; j < NSZS && szs[j-1] < MAXSZ; j++) {
q = p;
assert_d_eq(rallocm(&q, &szs[j], szs[j-1]+1, 0, 0),
ALLOCM_SUCCESS,
"Unexpected rallocm() error for size=%zu-->%zu",
szs[j-1], szs[j-1]+1);
assert_zu_ne(szs[j], szs[j-1]+1,
"Expected size to at least: %zu", szs[j-1]+1);
p = q;
}
for (j--; j > 0; j--) {
q = p;
assert_d_eq(rallocm(&q, &tsz, szs[j-1], 0, 0),
ALLOCM_SUCCESS,
"Unexpected rallocm() error for size=%zu-->%zu",
szs[j], szs[j-1]);
assert_zu_eq(tsz, szs[j-1],
"Expected size=%zu, got size=%zu", szs[j-1], tsz);
p = q;
}
}
assert_d_eq(dallocm(p, 0), ALLOCM_SUCCESS,
"Unexpected dallocm() error");
}
TEST_END
int
main(void)
{
return (test(
test_same_size,
test_extra_no_move,
test_no_move_fail,
test_grow_and_shrink));
}
...@@ -22,7 +22,7 @@ TEST_BEGIN(test_grow_and_shrink) ...@@ -22,7 +22,7 @@ TEST_BEGIN(test_grow_and_shrink)
szs[j-1], szs[j-1]+1); szs[j-1], szs[j-1]+1);
szs[j] = sallocx(q, 0); szs[j] = sallocx(q, 0);
assert_zu_ne(szs[j], szs[j-1]+1, assert_zu_ne(szs[j], szs[j-1]+1,
"Expected size to at least: %zu", szs[j-1]+1); "Expected size to be at least: %zu", szs[j-1]+1);
p = q; p = q;
} }
...@@ -55,8 +55,9 @@ validate_fill(const void *p, uint8_t c, size_t offset, size_t len) ...@@ -55,8 +55,9 @@ validate_fill(const void *p, uint8_t c, size_t offset, size_t len)
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
uint8_t b = buf[offset+i]; uint8_t b = buf[offset+i];
if (b != c) { if (b != c) {
test_fail("Allocation at %p contains %#x rather than " test_fail("Allocation at %p (len=%zu) contains %#x "
"%#x at offset %zu", p, b, c, offset+i); "rather than %#x at offset %zu", p, len, b, c,
offset+i);
ret = true; ret = true;
} }
} }
...@@ -95,7 +96,8 @@ TEST_BEGIN(test_zero) ...@@ -95,7 +96,8 @@ TEST_BEGIN(test_zero)
"Expected zeroed memory"); "Expected zeroed memory");
} }
if (psz != qsz) { if (psz != qsz) {
memset(q+psz, FILL_BYTE, qsz-psz); memset((void *)((uintptr_t)q+psz), FILL_BYTE,
qsz-psz);
psz = qsz; psz = qsz;
} }
p = q; p = q;
...@@ -159,8 +161,9 @@ TEST_BEGIN(test_lg_align_and_zero) ...@@ -159,8 +161,9 @@ TEST_BEGIN(test_lg_align_and_zero)
} else { } else {
assert_false(validate_fill(q, 0, 0, MAX_VALIDATE), assert_false(validate_fill(q, 0, 0, MAX_VALIDATE),
"Expected zeroed memory"); "Expected zeroed memory");
assert_false(validate_fill(q+sz-MAX_VALIDATE, 0, 0, assert_false(validate_fill(
MAX_VALIDATE), "Expected zeroed memory"); (void *)((uintptr_t)q+sz-MAX_VALIDATE),
0, 0, MAX_VALIDATE), "Expected zeroed memory");
} }
p = q; p = q;
} }
......
#include "test/jemalloc_test.h"
#define MAXALIGN (((size_t)1) << 25)
#define NITER 4
TEST_BEGIN(test_basic)
{
void *ptr = mallocx(64, 0);
sdallocx(ptr, 64, 0);
}
TEST_END
TEST_BEGIN(test_alignment_and_size)
{
size_t nsz, sz, alignment, total;
unsigned i;
void *ps[NITER];
for (i = 0; i < NITER; i++)
ps[i] = NULL;
for (alignment = 8;
alignment <= MAXALIGN;
alignment <<= 1) {
total = 0;
for (sz = 1;
sz < 3 * alignment && sz < (1U << 31);
sz += (alignment >> (LG_SIZEOF_PTR-1)) - 1) {
for (i = 0; i < NITER; i++) {
nsz = nallocx(sz, MALLOCX_ALIGN(alignment) |
MALLOCX_ZERO);
ps[i] = mallocx(sz, MALLOCX_ALIGN(alignment) |
MALLOCX_ZERO);
total += nsz;
if (total >= (MAXALIGN << 1))
break;
}
for (i = 0; i < NITER; i++) {
if (ps[i] != NULL) {
sdallocx(ps[i], sz,
MALLOCX_ALIGN(alignment));
ps[i] = NULL;
}
}
}
}
}
TEST_END
int
main(void)
{
return (test(
test_basic,
test_alignment_and_size));
}
...@@ -48,6 +48,411 @@ TEST_BEGIN(test_no_move_fail) ...@@ -48,6 +48,411 @@ TEST_BEGIN(test_no_move_fail)
} }
TEST_END TEST_END
static unsigned
get_nsizes_impl(const char *cmd)
{
unsigned ret;
size_t z;
z = sizeof(unsigned);
assert_d_eq(mallctl(cmd, &ret, &z, NULL, 0), 0,
"Unexpected mallctl(\"%s\", ...) failure", cmd);
return (ret);
}
static unsigned
get_nsmall(void)
{
return (get_nsizes_impl("arenas.nbins"));
}
static unsigned
get_nlarge(void)
{
return (get_nsizes_impl("arenas.nlruns"));
}
static unsigned
get_nhuge(void)
{
return (get_nsizes_impl("arenas.nhchunks"));
}
static size_t
get_size_impl(const char *cmd, size_t ind)
{
size_t ret;
size_t z;
size_t mib[4];
size_t miblen = 4;
z = sizeof(size_t);
assert_d_eq(mallctlnametomib(cmd, mib, &miblen),
0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd);
mib[2] = ind;
z = sizeof(size_t);
assert_d_eq(mallctlbymib(mib, miblen, &ret, &z, NULL, 0),
0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind);
return (ret);
}
static size_t
get_small_size(size_t ind)
{
return (get_size_impl("arenas.bin.0.size", ind));
}
static size_t
get_large_size(size_t ind)
{
return (get_size_impl("arenas.lrun.0.size", ind));
}
static size_t
get_huge_size(size_t ind)
{
return (get_size_impl("arenas.hchunk.0.size", ind));
}
TEST_BEGIN(test_size)
{
size_t small0, hugemax;
void *p;
/* Get size classes. */
small0 = get_small_size(0);
hugemax = get_huge_size(get_nhuge()-1);
p = mallocx(small0, 0);
assert_ptr_not_null(p, "Unexpected mallocx() error");
/* Test smallest supported size. */
assert_zu_eq(xallocx(p, 1, 0, 0), small0,
"Unexpected xallocx() behavior");
/* Test largest supported size. */
assert_zu_le(xallocx(p, hugemax, 0, 0), hugemax,
"Unexpected xallocx() behavior");
/* Test size overflow. */
assert_zu_le(xallocx(p, hugemax+1, 0, 0), hugemax,
"Unexpected xallocx() behavior");
assert_zu_le(xallocx(p, SIZE_T_MAX, 0, 0), hugemax,
"Unexpected xallocx() behavior");
dallocx(p, 0);
}
TEST_END
TEST_BEGIN(test_size_extra_overflow)
{
size_t small0, hugemax;
void *p;
/* Get size classes. */
small0 = get_small_size(0);
hugemax = get_huge_size(get_nhuge()-1);
p = mallocx(small0, 0);
assert_ptr_not_null(p, "Unexpected mallocx() error");
/* Test overflows that can be resolved by clamping extra. */
assert_zu_le(xallocx(p, hugemax-1, 2, 0), hugemax,
"Unexpected xallocx() behavior");
assert_zu_le(xallocx(p, hugemax, 1, 0), hugemax,
"Unexpected xallocx() behavior");
/* Test overflow such that hugemax-size underflows. */
assert_zu_le(xallocx(p, hugemax+1, 2, 0), hugemax,
"Unexpected xallocx() behavior");
assert_zu_le(xallocx(p, hugemax+2, 3, 0), hugemax,
"Unexpected xallocx() behavior");
assert_zu_le(xallocx(p, SIZE_T_MAX-2, 2, 0), hugemax,
"Unexpected xallocx() behavior");
assert_zu_le(xallocx(p, SIZE_T_MAX-1, 1, 0), hugemax,
"Unexpected xallocx() behavior");
dallocx(p, 0);
}
TEST_END
TEST_BEGIN(test_extra_small)
{
size_t small0, small1, hugemax;
void *p;
/* Get size classes. */
small0 = get_small_size(0);
small1 = get_small_size(1);
hugemax = get_huge_size(get_nhuge()-1);
p = mallocx(small0, 0);
assert_ptr_not_null(p, "Unexpected mallocx() error");
assert_zu_eq(xallocx(p, small1, 0, 0), small0,
"Unexpected xallocx() behavior");
assert_zu_eq(xallocx(p, small1, 0, 0), small0,
"Unexpected xallocx() behavior");
assert_zu_eq(xallocx(p, small0, small1 - small0, 0), small0,
"Unexpected xallocx() behavior");
/* Test size+extra overflow. */
assert_zu_eq(xallocx(p, small0, hugemax - small0 + 1, 0), small0,
"Unexpected xallocx() behavior");
assert_zu_eq(xallocx(p, small0, SIZE_T_MAX - small0, 0), small0,
"Unexpected xallocx() behavior");
dallocx(p, 0);
}
TEST_END
TEST_BEGIN(test_extra_large)
{
size_t smallmax, large0, large1, large2, huge0, hugemax;
void *p;
/* Get size classes. */
smallmax = get_small_size(get_nsmall()-1);
large0 = get_large_size(0);
large1 = get_large_size(1);
large2 = get_large_size(2);
huge0 = get_huge_size(0);
hugemax = get_huge_size(get_nhuge()-1);
p = mallocx(large2, 0);
assert_ptr_not_null(p, "Unexpected mallocx() error");
assert_zu_eq(xallocx(p, large2, 0, 0), large2,
"Unexpected xallocx() behavior");
/* Test size decrease with zero extra. */
assert_zu_eq(xallocx(p, large0, 0, 0), large0,
"Unexpected xallocx() behavior");
assert_zu_eq(xallocx(p, smallmax, 0, 0), large0,
"Unexpected xallocx() behavior");
assert_zu_eq(xallocx(p, large2, 0, 0), large2,
"Unexpected xallocx() behavior");
/* Test size decrease with non-zero extra. */
assert_zu_eq(xallocx(p, large0, large2 - large0, 0), large2,
"Unexpected xallocx() behavior");
assert_zu_eq(xallocx(p, large1, large2 - large1, 0), large2,
"Unexpected xallocx() behavior");
assert_zu_eq(xallocx(p, large0, large1 - large0, 0), large1,
"Unexpected xallocx() behavior");
assert_zu_eq(xallocx(p, smallmax, large0 - smallmax, 0), large0,
"Unexpected xallocx() behavior");
assert_zu_eq(xallocx(p, large0, 0, 0), large0,
"Unexpected xallocx() behavior");
/* Test size increase with zero extra. */
assert_zu_eq(xallocx(p, large2, 0, 0), large2,
"Unexpected xallocx() behavior");
assert_zu_eq(xallocx(p, huge0, 0, 0), large2,
"Unexpected xallocx() behavior");
assert_zu_eq(xallocx(p, large0, 0, 0), large0,
"Unexpected xallocx() behavior");
/* Test size increase with non-zero extra. */
assert_zu_lt(xallocx(p, large0, huge0 - large0, 0), huge0,
"Unexpected xallocx() behavior");
assert_zu_eq(xallocx(p, large0, 0, 0), large0,
"Unexpected xallocx() behavior");
/* Test size increase with non-zero extra. */
assert_zu_eq(xallocx(p, large0, large2 - large0, 0), large2,
"Unexpected xallocx() behavior");
assert_zu_eq(xallocx(p, large2, 0, 0), large2,
"Unexpected xallocx() behavior");
/* Test size+extra overflow. */
assert_zu_lt(xallocx(p, large2, hugemax - large2 + 1, 0), huge0,
"Unexpected xallocx() behavior");
dallocx(p, 0);
}
TEST_END
TEST_BEGIN(test_extra_huge)
{
size_t largemax, huge0, huge1, huge2, hugemax;
void *p;
/* Get size classes. */
largemax = get_large_size(get_nlarge()-1);
huge0 = get_huge_size(0);
huge1 = get_huge_size(1);
huge2 = get_huge_size(2);
hugemax = get_huge_size(get_nhuge()-1);
p = mallocx(huge2, 0);
assert_ptr_not_null(p, "Unexpected mallocx() error");
assert_zu_eq(xallocx(p, huge2, 0, 0), huge2,
"Unexpected xallocx() behavior");
/* Test size decrease with zero extra. */
assert_zu_ge(xallocx(p, huge0, 0, 0), huge0,
"Unexpected xallocx() behavior");
assert_zu_ge(xallocx(p, largemax, 0, 0), huge0,
"Unexpected xallocx() behavior");
assert_zu_eq(xallocx(p, huge2, 0, 0), huge2,
"Unexpected xallocx() behavior");
/* Test size decrease with non-zero extra. */
assert_zu_eq(xallocx(p, huge0, huge2 - huge0, 0), huge2,
"Unexpected xallocx() behavior");
assert_zu_eq(xallocx(p, huge1, huge2 - huge1, 0), huge2,
"Unexpected xallocx() behavior");
assert_zu_eq(xallocx(p, huge0, huge1 - huge0, 0), huge1,
"Unexpected xallocx() behavior");
assert_zu_ge(xallocx(p, largemax, huge0 - largemax, 0), huge0,
"Unexpected xallocx() behavior");
assert_zu_ge(xallocx(p, huge0, 0, 0), huge0,
"Unexpected xallocx() behavior");
/* Test size increase with zero extra. */
assert_zu_le(xallocx(p, huge2, 0, 0), huge2,
"Unexpected xallocx() behavior");
assert_zu_le(xallocx(p, hugemax+1, 0, 0), huge2,
"Unexpected xallocx() behavior");
assert_zu_ge(xallocx(p, huge0, 0, 0), huge0,
"Unexpected xallocx() behavior");
/* Test size increase with non-zero extra. */
assert_zu_le(xallocx(p, huge0, SIZE_T_MAX - huge0, 0), hugemax,
"Unexpected xallocx() behavior");
assert_zu_ge(xallocx(p, huge0, 0, 0), huge0,
"Unexpected xallocx() behavior");
/* Test size increase with non-zero extra. */
assert_zu_le(xallocx(p, huge0, huge2 - huge0, 0), huge2,
"Unexpected xallocx() behavior");
assert_zu_eq(xallocx(p, huge2, 0, 0), huge2,
"Unexpected xallocx() behavior");
/* Test size+extra overflow. */
assert_zu_le(xallocx(p, huge2, hugemax - huge2 + 1, 0), hugemax,
"Unexpected xallocx() behavior");
dallocx(p, 0);
}
TEST_END
static void
print_filled_extents(const void *p, uint8_t c, size_t len)
{
const uint8_t *pc = (const uint8_t *)p;
size_t i, range0;
uint8_t c0;
malloc_printf(" p=%p, c=%#x, len=%zu:", p, c, len);
range0 = 0;
c0 = pc[0];
for (i = 0; i < len; i++) {
if (pc[i] != c0) {
malloc_printf(" %#x[%zu..%zu)", c0, range0, i);
range0 = i;
c0 = pc[i];
}
}
malloc_printf(" %#x[%zu..%zu)\n", c0, range0, i);
}
static bool
validate_fill(const void *p, uint8_t c, size_t offset, size_t len)
{
const uint8_t *pc = (const uint8_t *)p;
bool err;
size_t i;
for (i = offset, err = false; i < offset+len; i++) {
if (pc[i] != c)
err = true;
}
if (err)
print_filled_extents(p, c, offset + len);
return (err);
}
static void
test_zero(size_t szmin, size_t szmax)
{
size_t sz, nsz;
void *p;
#define FILL_BYTE 0x7aU
sz = szmax;
p = mallocx(sz, MALLOCX_ZERO);
assert_ptr_not_null(p, "Unexpected mallocx() error");
assert_false(validate_fill(p, 0x00, 0, sz), "Memory not filled: sz=%zu",
sz);
/*
* Fill with non-zero so that non-debug builds are more likely to detect
* errors.
*/
memset(p, FILL_BYTE, sz);
assert_false(validate_fill(p, FILL_BYTE, 0, sz),
"Memory not filled: sz=%zu", sz);
/* Shrink in place so that we can expect growing in place to succeed. */
sz = szmin;
assert_zu_eq(xallocx(p, sz, 0, MALLOCX_ZERO), sz,
"Unexpected xallocx() error");
assert_false(validate_fill(p, FILL_BYTE, 0, sz),
"Memory not filled: sz=%zu", sz);
for (sz = szmin; sz < szmax; sz = nsz) {
nsz = nallocx(sz+1, MALLOCX_ZERO);
assert_zu_eq(xallocx(p, sz+1, 0, MALLOCX_ZERO), nsz,
"Unexpected xallocx() failure");
assert_false(validate_fill(p, FILL_BYTE, 0, sz),
"Memory not filled: sz=%zu", sz);
assert_false(validate_fill(p, 0x00, sz, nsz-sz),
"Memory not filled: sz=%zu, nsz-sz=%zu", sz, nsz-sz);
memset((void *)((uintptr_t)p + sz), FILL_BYTE, nsz-sz);
assert_false(validate_fill(p, FILL_BYTE, 0, nsz),
"Memory not filled: nsz=%zu", nsz);
}
dallocx(p, 0);
}
TEST_BEGIN(test_zero_large)
{
size_t large0, largemax;
/* Get size classes. */
large0 = get_large_size(0);
largemax = get_large_size(get_nlarge()-1);
test_zero(large0, largemax);
}
TEST_END
TEST_BEGIN(test_zero_huge)
{
size_t huge0, huge1;
/* Get size classes. */
huge0 = get_huge_size(0);
huge1 = get_huge_size(1);
test_zero(huge1, huge0 * 2);
}
TEST_END
int int
main(void) main(void)
{ {
...@@ -55,5 +460,12 @@ main(void) ...@@ -55,5 +460,12 @@ main(void)
return (test( return (test(
test_same_size, test_same_size,
test_extra_no_move, test_extra_no_move,
test_no_move_fail)); test_no_move_fail,
test_size,
test_size_extra_overflow,
test_extra_small,
test_extra_large,
test_extra_huge,
test_zero_large,
test_zero_huge));
} }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment