Add initial testing file, test target, and readme about testing, issue #10, pr #57

This commit is contained in:
daan 2019-06-27 13:36:19 -07:00
parent 4c87643c29
commit ae47a2b13e
5 changed files with 224 additions and 14 deletions

View File

@ -106,14 +106,15 @@ else()
list(APPEND mi_libraries pthread)
endif()
# -----------------------------------------------------------------------------
# Main targets
# -----------------------------------------------------------------------------
# shared library
add_library(mimalloc SHARED ${mi_sources})
set_target_properties(mimalloc PROPERTIES VERSION ${mi_version} NO_SONAME "YES" OUTPUT_NAME ${mi_basename} )
target_compile_definitions(mimalloc PRIVATE ${mi_defines} MI_SHARED_LIB MI_SHARED_LIB_EXPORT)
if(MI_OVERRIDE MATCHES "ON")
target_compile_definitions(mimalloc PRIVATE MI_MALLOC_OVERRIDE)
endif()
target_compile_options(mimalloc PRIVATE ${mi_cflags})
target_include_directories(mimalloc PRIVATE include PUBLIC $<INSTALL_INTERFACE:${mi_install_dir}/include>)
target_link_libraries(mimalloc PUBLIC ${mi_libraries})
@ -129,10 +130,6 @@ else()
set_target_properties(mimalloc-static PROPERTIES OUTPUT_NAME ${mi_basename})
endif()
target_compile_definitions(mimalloc-static PRIVATE ${mi_defines} MI_STATIC_LIB)
if(NOT WIN32 AND MI_OVERRIDE MATCHES "ON")
# It is only possible to override malloc on Windows when building as a DLL. (src/alloc-override.c)
target_compile_definitions(mimalloc-static PRIVATE MI_MALLOC_OVERRIDE)
endif()
target_compile_options(mimalloc-static PRIVATE ${mi_cflags})
target_include_directories(mimalloc-static PRIVATE include PUBLIC $<INSTALL_INTERFACE:${mi_install_dir}/include>)
target_link_libraries(mimalloc-static PUBLIC ${mi_libraries})
@ -149,13 +146,35 @@ install(FILES "$<TARGET_FILE:mimalloc>" DESTINATION lib) # duplicate the .so in
# single object file for more predictable static overriding
add_library(mimalloc-obj OBJECT src/static.c)
target_compile_definitions(mimalloc-obj PRIVATE ${mi_defines})
if(NOT WIN32 AND MI_OVERRIDE MATCHES "ON")
# It is only possible to override malloc on Windows when building as a DLL. (src/alloc-override.c)
target_compile_definitions(mimalloc-obj PRIVATE MI_MALLOC_OVERRIDE)
endif()
target_compile_options(mimalloc-obj PRIVATE ${mi_cflags})
target_include_directories(mimalloc-obj PRIVATE include PUBLIC $<INSTALL_INTERFACE:include>)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/mimalloc-obj.dir/src/static.c${CMAKE_C_OUTPUT_EXTENSION}
DESTINATION ${mi_install_dir}
RENAME ${mi_basename}${CMAKE_C_OUTPUT_EXTENSION} )
# -----------------------------------------------------------------------------
# API surface testing
# -----------------------------------------------------------------------------
add_executable(mimalloc-test test/test-api.c)
target_compile_definitions(mimalloc-test PRIVATE ${mi_defines})
target_compile_options(mimalloc-test PRIVATE ${mi_cflags})
target_include_directories(mimalloc-test PRIVATE include)
target_link_libraries(mimalloc-test PRIVATE mimalloc-static)
enable_testing()
add_test(test_api, mimalloc-test)
# -----------------------------------------------------------------------------
# Set override properties
# -----------------------------------------------------------------------------
if (MI_OVERRIDE MATCHES "ON")
target_compile_definitions(mimalloc PRIVATE MI_MALLOC_OVERRIDE)
if(NOT WIN32)
# It is only possible to override malloc on Windows when building as a DLL. (src/alloc-override.c)
target_compile_definitions(mimalloc-static PRIVATE MI_MALLOC_OVERRIDE)
target_compile_definitions(mimalloc-obj PRIVATE MI_MALLOC_OVERRIDE)
target_compile_definitions(mimalloc-test PRIVATE MI_MALLOC_OVERRIDE)
endif()
endif()

View File

@ -145,7 +145,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\test\main.c" />
<ClCompile Include="..\..\test\test-api.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="mimalloc.vcxproj">
@ -155,4 +155,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -15,7 +15,7 @@
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\test\main.c">
<ClCompile Include="..\..\test\test-api.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>

16
test/readme.md Normal file
View File

@ -0,0 +1,16 @@
Testing allocators is difficult as bugs may only surface after particular
allocation patterns. The main approach to testing _mimalloc_ is therefore
to have extensive internal invariant checking (see `page_is_valid` in `page.c`
for example), which is enabled in debug mode with `-DMI_CHECK_FULL=ON`.
The main testing strategy is then to run [`mimalloc-bench`][bench] using full
invariant checking to catch any potential problems over a wide range of intensive
allocation benchmarks and programs.
However, this does not test well for the entire API surface and this is tested
with `test-api.c` when using `make test` (from `out/debug` etc). (This is
not complete yet, please add to it.)
The `main.c` and `main-override.c` are there to test if building and overriding
from a local install works and therefore these build a separate `test/CMakeLists.txt`.
[bench]: https://github.com/daanx/mimalloc-bench

175
test/test-api.c Normal file
View File

@ -0,0 +1,175 @@
/* ----------------------------------------------------------------------------
Copyright (c) 2018, Microsoft Research, Daan Leijen
This is free software; you can redistribute it and/or modify it under the
terms of the MIT license. A copy of the license can be found in the file
"LICENSE" at the root of this distribution.
-----------------------------------------------------------------------------*/
/*
Testing allocators is difficult as bugs may only surface after particular
allocation patterns. The main approach to testing _mimalloc_ is therefore
to have extensive internal invariant checking (see `page_is_valid` in `page.c`
for example), which is enabled in debug mode with `-DMI_CHECK_FULL=ON`.
The main testing is then to run `mimalloc-bench` [1] using full invariant checking
to catch any potential problems over a wide range of intensive allocation bench
marks.
However, this does not test well for the entire API surface. In this test file
we therefore test the API over various inputs. Please add more tests :-)
[1] https://github.com/daanx/mimalloc-bench
*/
#include <stdio.h>
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <errno.h>
#include "mimalloc.h"
#include "mimalloc-internal.h"
// ---------------------------------------------------------------------------
// Test macros: CHECK(name,predicate) and CHECK_BODY(name,body)
// ---------------------------------------------------------------------------
static int ok = 0;
static int failed = 0;
#define CHECK_BODY(name,body) \
do { \
fprintf(stderr,"test: %s... ", name ); \
bool result = true; \
do { body } while(false); \
if (!(result)) { \
failed++; \
fprintf(stderr, \
"\n FAILED: %s:%d:\n %s\n", \
__FILE__, \
__LINE__, \
#body); \
/* exit(1); */ \
} \
else { \
ok++; \
fprintf(stderr,"ok.\n"); \
} \
} while (false)
#define CHECK(name,expr) CHECK_BODY(name,{ result = (expr); })
// ---------------------------------------------------------------------------
// Test functions
// ---------------------------------------------------------------------------
bool test_heap1();
bool test_heap2();
// ---------------------------------------------------------------------------
// Main testing
// ---------------------------------------------------------------------------
int main() {
mi_option_enable(mi_option_verbose,false);
// ---------------------------------------------------
// Malloc
// ---------------------------------------------------
CHECK_BODY("malloc-zero",{
void* p = mi_malloc(0); mi_free(p);
});
CHECK_BODY("malloc-nomem1",{
result = (mi_malloc(SIZE_MAX/2) == NULL);
});
CHECK_BODY("malloc-null",{
mi_free(NULL);
});
// ---------------------------------------------------
// Extended
// ---------------------------------------------------
#if defined(MI_MALLOC_OVERRIDE) && !defined(_WIN32)
CHECK_BODY("posix_memalign1", {
void* p = &main;
int err = posix_memalign(&p, sizeof(void*), 32);
mi_assert((err==0 && (uintptr_t)p % sizeof(void*) == 0) || p==&main);
mi_free(p);
result = (err==0);
});
CHECK_BODY("posix_memalign_no_align", {
void* p = &main;
int err = posix_memalign(&p, 3, 32);
mi_assert(p==&main);
result = (err==EINVAL);
});
CHECK_BODY("posix_memalign_zero", {
void* p = &main;
int err = posix_memalign(&p, sizeof(void*), 0);
mi_free(p);
result = (err==0);
});
CHECK_BODY("posix_memalign_nopow2", {
void* p = &main;
int err = posix_memalign(&p, 3*sizeof(void*), 32);
result = (err==EINVAL && p==&main);
});
CHECK_BODY("posix_memalign_nomem", {
void* p = &main;
int err = posix_memalign(&p, sizeof(void*), SIZE_MAX);
result = (err==ENOMEM && p==&main);
});
#endif
// ---------------------------------------------------
// Aligned API
// ---------------------------------------------------
CHECK_BODY("malloc-aligned1", {
void* p = mi_malloc_aligned(32,24); result = (p != NULL && (uintptr_t)(p) % 24 == 0); mi_free(p);
});
CHECK_BODY("malloc-aligned2", {
void* p = mi_malloc_aligned(8,24); result = (p != NULL && (uintptr_t)(p) % 24 == 0); mi_free(p);
});
CHECK_BODY("malloc-aligned-at1", {
void* p = mi_malloc_aligned_at(8,24,0); result = (p != NULL && ((uintptr_t)(p) + 0) % 24 == 0); mi_free(p);
});
CHECK_BODY("malloc-aligned-at2", {
void* p = mi_malloc_aligned_at(5,24,8); result = (p != NULL && ((uintptr_t)(p) + 8) % 24 == 0); mi_free(p);
});
// ---------------------------------------------------
// Heaps
// ---------------------------------------------------
CHECK("heap_destroy", test_heap1());
CHECK("heap_delete", test_heap2());
// ---------------------------------------------------
// Done
// ---------------------------------------------------[]
fprintf(stderr,"\n\n---------------------------------------------\n"
"succeeded: %i\n"
"failed : %i\n\n", ok, failed);
return failed;
}
// ---------------------------------------------------
// Larger test functions
// ---------------------------------------------------
bool test_heap1() {
mi_heap_t* heap = mi_heap_new();
int* p1 = mi_heap_malloc_tp(heap,int);
int* p2 = mi_heap_malloc_tp(heap,int);
*p1 = *p2 = 43;
mi_heap_destroy(heap);
return true;
}
bool test_heap2() {
mi_heap_t* heap = mi_heap_new();
int* p1 = mi_heap_malloc_tp(heap,int);
int* p2 = mi_heap_malloc_tp(heap,int);
mi_heap_delete(heap);
*p1 = 42;
mi_free(p1);
mi_free(p2);
return true;
}