├── .gitattributes ├── .github └── workflows │ └── all.yml ├── .gitignore ├── LICENSE ├── README.md ├── bench.sh ├── bench ├── CMakeLists.txt ├── README.md ├── alloc-test │ ├── README.md │ ├── allocator_tester.cpp │ ├── allocator_tester.h │ ├── new_delete_allocator.h │ ├── selector.h │ ├── test_common.cpp │ ├── test_common.h │ └── void_allocator.h ├── barnes │ ├── README.barnes │ ├── README.md │ ├── code.c │ ├── code.h │ ├── code_io.c │ ├── defs.h │ ├── getparam.c │ ├── grav.c │ ├── input │ ├── load.c │ ├── stdinc.h │ ├── util.c │ └── vectmath.h ├── cache-scratch │ ├── README.md │ └── cache-scratch.cpp ├── cache-thrash │ ├── README.md │ └── cache-thrash.cpp ├── cfrac │ ├── README.md │ ├── asm16bit.h │ ├── atop.c │ ├── cfrac.c │ ├── errorp.c │ ├── getopt.c │ ├── getopt.h │ ├── itop.c │ ├── ltop.c │ ├── pabs.c │ ├── padd.c │ ├── pcfrac.c │ ├── pcmp.c │ ├── pconst.c │ ├── pcvt.h │ ├── pdefs.h │ ├── pdivmod.c │ ├── pfactor.c │ ├── pfactor.h │ ├── pfloat.c │ ├── pgcd.c │ ├── phalf.c │ ├── picmp.c │ ├── pidiv.c │ ├── pimod.c │ ├── pio.c │ ├── pmul.c │ ├── pneg.c │ ├── podd.c │ ├── pops.c │ ├── ppowmod.c │ ├── precision.h │ ├── primes.c │ ├── primes.h │ ├── psqrt.c │ ├── psub.c │ ├── ptoa.c │ ├── ptob.c │ ├── ptou.c │ ├── seive.h │ └── utop.c ├── espresso │ ├── README.md │ ├── ansi.h │ ├── cofactor.c │ ├── cols.c │ ├── compl.c │ ├── contain.c │ ├── copyright.h │ ├── cubestr.c │ ├── cvrin.c │ ├── cvrm.c │ ├── cvrmisc.c │ ├── cvrout.c │ ├── dominate.c │ ├── equiv.c │ ├── espresso.c │ ├── espresso.h │ ├── essen.c │ ├── exact.c │ ├── expand.c │ ├── gasp.c │ ├── getopt.c │ ├── gimpel.c │ ├── globals.c │ ├── hack.c │ ├── indep.c │ ├── irred.c │ ├── largest.espresso │ ├── main.c │ ├── main.h │ ├── map.c │ ├── matrix.c │ ├── mincov.c │ ├── mincov.h │ ├── mincov_int.h │ ├── opo.c │ ├── pair.c │ ├── part.c │ ├── port.h │ ├── primes.c │ ├── reduce.c │ ├── regex.h │ ├── rows.c │ ├── set.c │ ├── setc.c │ ├── sharp.c │ ├── sminterf.c │ ├── solution.c │ ├── sparse.c │ ├── sparse.h │ ├── sparse_int.h │ ├── stdlib.h │ ├── unate.c │ ├── utility.c │ ├── utility.h │ └── verify.c ├── glibc-bench │ ├── README.md │ ├── bench-malloc-simple.c │ └── bench-malloc-thread.c ├── larson │ ├── README.md │ └── larson.cpp ├── malloc-large │ ├── README.md │ ├── malloc-large-old.cpp │ └── malloc-large.cpp ├── mleak │ ├── README.md │ └── mleak.c ├── mstress │ ├── README.md │ └── mstress.c ├── rbstress │ ├── README.md │ └── stress_mem.rb ├── rptest │ ├── README.md │ ├── atomic.h │ ├── benchmark.h │ ├── rptest.c │ ├── thread.c │ ├── thread.h │ ├── timer.c │ └── timer.h ├── security │ ├── 32_byte_memcpy_overflow.c │ ├── 32_byte_memcpy_underflow.c │ ├── 32_byte_overflow.c │ ├── 32_byte_underflow.c │ ├── CMakeLists.txt │ ├── README.md │ ├── common.h │ ├── delete_type_size_mismatch.cc │ ├── double_free.c │ ├── double_free_delayed.c │ ├── double_free_interleaved.c │ ├── double_free_reuse.c │ ├── double_free_single_reuse.c │ ├── executable_heap.c │ ├── impossibly_large_malloc.c │ ├── invalid_array_delete_char.cc │ ├── invalid_array_delete_string.cc │ ├── invalid_delete_array_char.cc │ ├── invalid_delete_array_string.cc │ ├── invalid_free.c │ ├── invalid_free_alloca.c │ ├── invalid_free_close.c │ ├── invalid_free_far.c │ ├── invalid_free_stack.c │ ├── invalid_free_unaligned.c │ ├── invalid_free_unaligned_multiple.c │ ├── malloc_reuse.c │ ├── malloc_reuse_downsize.c │ ├── one_byte_memcpy_overflow.c │ ├── one_byte_memcpy_underflow.c │ ├── one_byte_overflow.c │ ├── one_byte_underflow.c │ ├── one_mbyte_memcpy_overflow.c │ ├── one_mbyte_memcpy_underflow.c │ ├── one_mbyte_overflow.c │ ├── one_mbyte_underflow.c │ ├── read_zero_size.c │ ├── read_zero_size_free.c │ ├── realloc_reuse.c │ ├── write_after_free.c │ ├── write_after_free_reuse.c │ ├── write_zero_size.c │ ├── write_zero_size_free.c │ ├── zero_after_free.c │ └── zero_on_malloc.c ├── shbench │ ├── readme.md │ ├── sh6bench.patch │ └── sh8bench.patch ├── xmalloc-test │ ├── README.md │ ├── random.h │ └── xmalloc-test.c └── z3 │ └── test1.smt2 ├── build-bench-env.sh ├── doc ├── bench-z4-1.svg ├── bench-z4-2.svg ├── bench-z4-rss-1.svg ├── bench-z4-rss-2.svg └── mimalloc-logo.png ├── graph_many.py └── graphs.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # default behavior is to always use unix style line endings 2 | * text eol=lf 3 | *.png binary 4 | *.pdn binary 5 | *.sln binary 6 | *.suo binary 7 | *.vcproj binary 8 | *.patch binary 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | extern/ 2 | out/ 3 | bench/doc/ 4 | bench/malloc-test/ 5 | bench/shbench/sh6bench.c 6 | bench/shbench/sh6bench-new.c 7 | bench/shbench/SH8BENCH.C 8 | bench/shbench/sh8bench-new.c 9 | *.zip 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Microsoft Corporation, Daan Leijen. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bench/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | project(mimalloc-bench CXX C) 3 | set(CMAKE_CXX_STANDARD 17) 4 | 5 | if (NOT CMAKE_BUILD_TYPE) 6 | message(STATUS "No build type selected, default to *** Release ***") 7 | set(CMAKE_BUILD_TYPE "Release") 8 | endif() 9 | 10 | FUNCTION(PREPEND var prefix) 11 | SET(listVar "") 12 | FOREACH(f ${ARGN}) 13 | LIST(APPEND listVar "${prefix}/${f}") 14 | ENDFOREACH(f) 15 | SET(${var} "${listVar}" PARENT_SCOPE) 16 | ENDFUNCTION(PREPEND) 17 | 18 | set(cfrac_sources 19 | cfrac.c 20 | pops.c pconst.c pio.c 21 | pabs.c pneg.c pcmp.c podd.c phalf.c 22 | padd.c psub.c pmul.c pdivmod.c psqrt.c ppowmod.c 23 | atop.c ptoa.c itop.c utop.c ptou.c errorp.c 24 | pfloat.c pidiv.c pimod.c picmp.c 25 | primes.c pcfrac.c pgcd.c) 26 | PREPEND(cfrac_sources cfrac/ ${cfrac_sources}) 27 | 28 | set(espresso_sources 29 | cofactor.c cols.c compl.c contain.c cubestr.c cvrin.c cvrm.c cvrmisc.c cvrout.c 30 | dominate.c equiv.c espresso.c essen.c exact.c expand.c gasp.c getopt.c gimpel.c 31 | globals.c hack.c indep.c irred.c main.c map.c matrix.c mincov.c opo.c pair.c part.c 32 | primes.c reduce.c rows.c set.c setc.c sharp.c sminterf.c solution.c sparse.c unate.c 33 | utility.c verify.c) 34 | PREPEND(espresso_sources espresso/ ${espresso_sources}) 35 | 36 | set(barnes_sources 37 | code.c code_io.c load.c grav.c getparam.c util.c) 38 | PREPEND(barnes_sources barnes/ ${barnes_sources}) 39 | 40 | # turn off warnings.. 41 | message(STATUS "${CMAKE_C_COMPILER_ID}") 42 | if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU") 43 | set(FLAGS " -w -Wno-implicit-function-declaration -Wno-implicit-int -Wno-int-conversion -Wno-return-mismatch -Wno-incompatible-pointer-types") 44 | string(APPEND CMAKE_C_FLAGS ${FLAGS}) 45 | string(APPEND CMAKE_CXX_FLAGS ${FLAGS}) 46 | endif() 47 | 48 | add_executable(cfrac ${cfrac_sources}) 49 | target_compile_options(cfrac PRIVATE $<$:-std=gnu89>) 50 | target_compile_definitions(cfrac PRIVATE NOMEMOPT=1) 51 | target_link_libraries(cfrac m) 52 | 53 | add_executable(espresso ${espresso_sources}) 54 | target_compile_options(espresso PRIVATE $<$:-std=gnu89>) 55 | target_link_libraries(espresso m) 56 | 57 | add_executable(barnes ${barnes_sources}) 58 | target_link_libraries(barnes m) 59 | 60 | add_executable(larson larson/larson.cpp) 61 | target_compile_options(larson PRIVATE -Wno-unused-result) 62 | target_compile_definitions(larson PRIVATE CPP=1) 63 | target_link_libraries(larson pthread) 64 | 65 | add_executable(larson-sized larson/larson.cpp) 66 | target_compile_options(larson-sized PRIVATE -Wno-unused-result -fsized-deallocation) 67 | target_compile_definitions(larson-sized PRIVATE CPP=1 SIZED=1) 68 | target_link_libraries(larson-sized pthread) 69 | 70 | add_executable(alloc-test alloc-test/test_common.cpp alloc-test/allocator_tester.cpp) 71 | target_compile_definitions(alloc-test PRIVATE BENCH=4) 72 | target_link_libraries(alloc-test pthread) 73 | 74 | if(NOT APPLE) 75 | add_executable(sh6bench shbench/sh6bench-new.c) 76 | target_compile_definitions(sh6bench PRIVATE BENCH=1 SYS_MULTI_THREAD=1) 77 | target_link_libraries(sh6bench pthread) 78 | 79 | add_executable(sh8bench shbench/sh8bench-new.c) 80 | target_compile_definitions(sh8bench PRIVATE BENCH=1 SYS_MULTI_THREAD=1) 81 | target_link_libraries(sh8bench pthread) 82 | endif() 83 | 84 | add_executable(cache-scratch cache-scratch/cache-scratch.cpp) 85 | target_link_libraries(cache-scratch pthread) 86 | 87 | add_executable(cache-thrash cache-thrash/cache-thrash.cpp) 88 | target_link_libraries(cache-thrash pthread) 89 | 90 | add_executable(xmalloc-test xmalloc-test/xmalloc-test.c) 91 | target_link_libraries(xmalloc-test pthread) 92 | 93 | add_executable(malloc-large-old malloc-large/malloc-large-old.cpp) 94 | target_link_libraries(malloc-large-old pthread) 95 | 96 | add_executable(malloc-large malloc-large/malloc-large.cpp) 97 | target_link_libraries(malloc-large pthread) 98 | 99 | add_executable(mstress mstress/mstress.c) 100 | target_link_libraries(mstress pthread) 101 | 102 | add_executable(mleak mleak/mleak.c) 103 | target_link_libraries(mleak pthread) 104 | 105 | add_executable(rptest rptest/rptest.c rptest/thread.c rptest/timer.c) 106 | target_compile_options(rptest PRIVATE -fpermissive) 107 | target_include_directories(rptest PRIVATE rptest) 108 | target_link_libraries(rptest pthread m) 109 | 110 | add_executable(glibc-simple glibc-bench/bench-malloc-simple.c) 111 | target_link_libraries(glibc-simple pthread) 112 | 113 | add_executable(glibc-thread glibc-bench/bench-malloc-thread.c) 114 | target_link_libraries(glibc-thread pthread) 115 | 116 | add_subdirectory(security) 117 | -------------------------------------------------------------------------------- /bench/README.md: -------------------------------------------------------------------------------- 1 | Note that all the code in the `bench` directory is not part of 2 | _mimalloc-bench_ as such, and all programs here are 3 | governed under their own specific licenses and copyrights as detailed in 4 | their `README.md` (or `license.txt`) files. 5 | They are just included here for convenience. 6 | -------------------------------------------------------------------------------- /bench/alloc-test/README.md: -------------------------------------------------------------------------------- 1 | Made by OLogN Technologies and described on their 2 | [blog](http://ithare.com/testing-memory-allocators-ptmalloc2-tcmalloc-hoard-jemalloc-while-trying-to-simulate-real-world-loads). Original repository at . 3 | 4 | ``` 5 | Copyright (c) 2018, OLogN Technologies AG 6 | All rights reserved. 7 | 8 | * 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | * Neither the name of the nor the 17 | names of its contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | * 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | ``` 31 | -------------------------------------------------------------------------------- /bench/alloc-test/new_delete_allocator.h: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------------------------------------------- 2 | * Copyright (c) 2018, OLogN Technologies AG 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * ------------------------------------------------------------------------------- 27 | * 28 | * Memory allocator tester -- new-delete allocator 29 | * 30 | * v.1.00 Jun-22-2018 Initial release 31 | * 32 | * -------------------------------------------------------------------------------*/ 33 | 34 | 35 | #ifndef NEW_DELETE_ALLOCATOR_H 36 | #define NEW_DELETE_ALLOCATOR_H 37 | 38 | #include "test_common.h" 39 | 40 | 41 | class NewDeleteAllocatorForTest 42 | { 43 | ThreadTestRes* testRes; 44 | 45 | public: 46 | NewDeleteAllocatorForTest( ThreadTestRes* testRes_ ) { testRes = testRes_; } 47 | static constexpr bool isFake() { return false; } 48 | 49 | static constexpr const char* name() { return "new-delete allocator"; } 50 | 51 | void init() {} 52 | void* allocate( size_t sz ) { return new uint8_t[ sz ]; } 53 | void deallocate( void* ptr ) { delete [] reinterpret_cast(ptr); } 54 | void deinit() {} 55 | 56 | // next calls are to get additional stats of the allocator, etc, if desired 57 | void doWhateverAfterSetupPhase() {} 58 | void doWhateverAfterMainLoopPhase() {} 59 | void doWhateverAfterCleanupPhase() {} 60 | 61 | ThreadTestRes* getTestRes() { return testRes; } 62 | }; 63 | 64 | 65 | 66 | 67 | #endif // NEW_DELETE_ALLOCATOR_H 68 | -------------------------------------------------------------------------------- /bench/alloc-test/selector.h: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------------------------------------------- 2 | * Copyright (c) 2018, OLogN Technologies AG 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * ------------------------------------------------------------------------------- 27 | * 28 | * Memory allocator tester -- selector 29 | * 30 | * v.1.00 Jun-22-2018 Initial release 31 | * 32 | * -------------------------------------------------------------------------------*/ 33 | 34 | 35 | #ifndef SELECTOR_H 36 | #define SELECTOR_H 37 | 38 | // TODO: 39 | // (1) #include "my_allocator.h" 40 | // (2) define MyAllocatorT properly 41 | // (3) make sure other inclusions and/or definitions are removed or commented out :) 42 | 43 | #include "new_delete_allocator.h" 44 | typedef NewDeleteAllocatorForTest MyAllocatorT; 45 | 46 | #endif // SELECTOR_H 47 | -------------------------------------------------------------------------------- /bench/alloc-test/test_common.cpp: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------------------------------------------- 2 | * Copyright (c) 2018, OLogN Technologies AG 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * ------------------------------------------------------------------------------- 27 | * 28 | * Memory allocator tester -- common 29 | * 30 | * v.1.00 Jun-22-2018 Initial release 31 | * 32 | * -------------------------------------------------------------------------------*/ 33 | 34 | 35 | #include "test_common.h" 36 | 37 | #include 38 | #include 39 | 40 | #ifdef _MSC_VER 41 | #include 42 | #else 43 | #include 44 | #endif 45 | 46 | 47 | int64_t GetMicrosecondCount() 48 | { 49 | int64_t now = 0; 50 | #ifdef _MSC_VER 51 | static int64_t frec = 0; 52 | if (frec == 0) 53 | { 54 | LARGE_INTEGER val; 55 | BOOL ok = QueryPerformanceFrequency(&val); 56 | assert(ok); 57 | frec = val.QuadPart; 58 | } 59 | LARGE_INTEGER val; 60 | BOOL ok = QueryPerformanceCounter(&val); 61 | assert(ok); 62 | now = (val.QuadPart * 1000000) / frec; 63 | #endif 64 | return now; 65 | } 66 | 67 | 68 | 69 | NOINLINE 70 | size_t GetMillisecondCount() 71 | { 72 | size_t now; 73 | #ifdef _MSC_VER 74 | static uint64_t frec = 0; 75 | if (frec == 0) 76 | { 77 | LARGE_INTEGER val; 78 | BOOL ok = QueryPerformanceFrequency(&val); 79 | assert(ok); 80 | frec = val.QuadPart / 1000; 81 | } 82 | LARGE_INTEGER val; 83 | BOOL ok = QueryPerformanceCounter(&val); 84 | assert(ok); 85 | now = val.QuadPart / frec; 86 | 87 | #else 88 | #if 1 89 | struct timespec ts; 90 | timespec_get(&ts, TIME_UTC);//clock get time monotonic 91 | now = (uint64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000; // mks 92 | #else 93 | struct timeval now_; 94 | gettimeofday(&now_, NULL); 95 | now = now_.tv_sec; 96 | now *= 1000; 97 | now += now_.tv_usec / 1000000; 98 | #endif 99 | #endif 100 | return now; 101 | } 102 | 103 | #ifdef _MSC_VER 104 | #include 105 | size_t getRss() 106 | { 107 | HANDLE hProcess; 108 | PROCESS_MEMORY_COUNTERS pmc; 109 | hProcess = GetCurrentProcess(); 110 | BOOL ok = GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc)); 111 | CloseHandle( hProcess ); 112 | if ( ok ) 113 | return pmc.PagefileUsage >> 12; // note: we may also be interested in 'PeakPagefileUsage' 114 | else 115 | return 0; 116 | } 117 | #elif defined(__APPLE__) 118 | #include 119 | size_t getRss() { 120 | struct rusage rusage; 121 | getrusage(RUSAGE_SELF, &rusage); 122 | return rusage.ru_maxrss; 123 | } 124 | #else 125 | size_t getRss() 126 | { 127 | // see http://man7.org/linux/man-pages/man5/proc.5.html for details 128 | FILE* fstats = fopen( "/proc/self/statm", "rb" ); 129 | constexpr size_t buffsz = 0x1000; 130 | char buff[buffsz]; 131 | buff[buffsz-1] = 0; 132 | fread( buff, 1, buffsz-1, fstats); 133 | fclose( fstats); 134 | const char* pos = buff; 135 | while ( *pos && *pos == ' ' ) ++pos; 136 | while ( *pos && *pos != ' ' ) ++pos; 137 | return atol( pos ); 138 | } 139 | #endif 140 | 141 | -------------------------------------------------------------------------------- /bench/alloc-test/void_allocator.h: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------------------------------------------- 2 | * Copyright (c) 2018, OLogN Technologies AG 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * ------------------------------------------------------------------------------- 27 | * 28 | * Memory allocator tester -- void allocator (used for estimating cost of test itself) 29 | * 30 | * v.1.00 Jun-22-2018 Initial release 31 | * 32 | * -------------------------------------------------------------------------------*/ 33 | 34 | 35 | #ifndef VOID_ALLOCATOR_H 36 | #define VOID_ALLOCATOR_H 37 | 38 | #include "test_common.h" 39 | 40 | template 41 | class VoidAllocatorForTest 42 | { 43 | ThreadTestRes* testRes; 44 | ThreadTestRes discardedTestRes; 45 | ActualAllocator alloc; 46 | uint8_t* fakeBuffer = nullptr; 47 | static constexpr size_t fakeBufferSize = 0x1000000; 48 | 49 | public: 50 | VoidAllocatorForTest( ThreadTestRes* testRes_ ) : alloc( &discardedTestRes ) { testRes = testRes_; } 51 | static constexpr bool isFake() { return true; } // thus indicating that certain checks over allocated memory should be ommited 52 | 53 | static constexpr const char* name() { return "void allocator"; } 54 | 55 | void init() 56 | { 57 | alloc.init(); 58 | fakeBuffer = reinterpret_cast( alloc.allocate( fakeBufferSize ) ); 59 | } 60 | void* allocateSlots( size_t sz ) { static_assert( isFake()); assert( sz <= fakeBufferSize ); return alloc.allocate( sz ); } 61 | void* allocate( size_t sz ) { assert( sz <= fakeBufferSize ); return fakeBuffer; } 62 | void deallocate( void* ptr ) {} 63 | void deallocateSlots( void* ptr ) {alloc.deallocate( ptr );} 64 | void deinit() { if ( fakeBuffer ) alloc.deallocate( fakeBuffer ); fakeBuffer = nullptr; } 65 | 66 | // next calls are to get additional stats of the allocator, etc, if desired 67 | void doWhateverAfterSetupPhase() {} 68 | void doWhateverAfterMainLoopPhase() {} 69 | void doWhateverAfterCleanupPhase() {} 70 | 71 | ThreadTestRes* getTestRes() { return testRes; } 72 | }; 73 | 74 | 75 | 76 | 77 | #endif // VOID_ALLOCATOR_H -------------------------------------------------------------------------------- /bench/barnes/README.barnes: -------------------------------------------------------------------------------- 1 | GENERAL INFORMATION: 2 | 3 | The BARNES application implements the Barnes-Hut method to simulate the 4 | interaction of a system of bodies (N-body problem). A general description 5 | of the Barnes-Hut method can be found in: 6 | 7 | Singh, J. P. Parallel Hierarchical N-body Methods and Their Implications 8 | for Multiprocessors. PhD Thesis, Stanford University, February 1993. 9 | 10 | The SPLASH-2 implementation allows for multiple particles to be stored in 11 | each leaf cell of the space partition. A description of this feature 12 | can be found in: 13 | 14 | Holt, C. and Singh, J. P. Hierarchical N-Body Methods on Shared Address 15 | Space Multiprocessors. SIAM Conference on Parallel Processing 16 | for Scientific Computing, Feb 1995, to appear. 17 | 18 | RUNNING THE PROGRAM: 19 | 20 | For a default run, use "BARNES < input". 21 | 22 | To see how to run the program, please see the comment at the top of the 23 | file code.C, or run the application with the "-h" command line option. 24 | The input parameters should be placed in a file and redirected to standard 25 | input. Of the twelve input parameters, the ones which would normally be 26 | varied are the number of particles and the number of processors. If other 27 | parameters are changed, these changes should be reported in any results 28 | that are presented. 29 | 30 | The only compile time option, -DQUADPOLE, controls the use of quadpole 31 | interactions during the force computation. For the input parameters 32 | provided, the -DQUADPOLE option should not be defined. The constant 33 | MAX_BODIES_PER_LEAF defines the maximum number of particles per leaf 34 | cell in the tree. This constant also affects the parameter "fleaves" in 35 | the input file, which controls how many leaf cells space is allocated for. 36 | The higher the value of MAX_BODIES_PER_LEAF, the lower fleaves should be. 37 | Both these parameters should be kept at their default values for base 38 | SPLASH-2 runs. If changes are made, they should be reported in any results 39 | that are presented. 40 | 41 | BASE PROBLEM SIZE: 42 | 43 | The base problem size for an upto-64 processor machine is 16384 particles. 44 | For this many particles, you can use the input file provided (and change 45 | only the number of processors). 46 | 47 | DATA DISTRIBUTION: 48 | 49 | Our "POSSIBLE ENHANCEMENT" comments in the source code tell where one 50 | might want to distribute data and how. Data distribution, however, does 51 | not make much difference to performance on the Stanford DASH 52 | multiprocessor. 53 | -------------------------------------------------------------------------------- /bench/barnes/README.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 1994 Stanford University 2 | 3 | ``` 4 | All rights reserved. 5 | 6 | Permission is given to use, copy, and modify this software for any 7 | non-commercial purpose as long as this copyright notice is not 8 | removed. All other uses, including redistribution in whole or in 9 | part, are forbidden without prior written permission. 10 | 11 | This software is provided with absolutely no warranty and no 12 | support. 13 | ``` 14 | -------------------------------------------------------------------------------- /bench/barnes/getparam.c: -------------------------------------------------------------------------------- 1 | #line 95 "./null_macros/c.m4.null" 2 | 3 | #line 1 "getparam.C" 4 | /*************************************************************************/ 5 | /* */ 6 | /* Copyright (c) 1994 Stanford University */ 7 | /* */ 8 | /* All rights reserved. */ 9 | /* */ 10 | /* Permission is given to use, copy, and modify this software for any */ 11 | /* non-commercial purpose as long as this copyright notice is not */ 12 | /* removed. All other uses, including redistribution in whole or in */ 13 | /* part, are forbidden without prior written permission. */ 14 | /* */ 15 | /* This software is provided with absolutely no warranty and no */ 16 | /* support. */ 17 | /* */ 18 | /*************************************************************************/ 19 | 20 | /* 21 | * GETPARAM.C: 22 | */ 23 | 24 | 25 | #include "stdinc.h" 26 | 27 | local string *defaults = NULL; /* vector of "name=value" strings */ 28 | 29 | /* 30 | * INITPARAM: ignore arg vector, remember defaults. 31 | */ 32 | 33 | initparam(argv, defv) 34 | string *argv, *defv; 35 | { 36 | defaults = defv; 37 | } 38 | 39 | /* 40 | * GETPARAM: export version prompts user for value. 41 | */ 42 | 43 | string getparam(name) 44 | string name; /* name of parameter */ 45 | { 46 | int scanbind(), i, strlen(), leng; 47 | string extrvalue(), def; 48 | char buf[128], *strcpy(); 49 | char* temp; 50 | 51 | if (defaults == NULL) 52 | error("getparam: called before initparam\n"); 53 | i = scanbind(defaults, name); 54 | if (i < 0) 55 | error("getparam: %s unknown\n", name); 56 | def = extrvalue(defaults[i]); 57 | gets(buf); 58 | leng = strlen(buf) + 1; 59 | if (leng > 1) { 60 | return (strcpy(malloc(leng), buf)); 61 | } 62 | else { 63 | return (def); 64 | } 65 | } 66 | 67 | /* 68 | * GETIPARAM, ..., GETDPARAM: get int, long, bool, or double parameters. 69 | */ 70 | 71 | int getiparam(name) 72 | string name; /* name of parameter */ 73 | { 74 | string getparam(), val; 75 | int atoi(); 76 | 77 | for (val = ""; *val == NULL;) { 78 | val = getparam(name); 79 | } 80 | return (atoi(val)); 81 | } 82 | 83 | long getlparam(name) 84 | string name; /* name of parameter */ 85 | { 86 | string getparam(), val; 87 | long atol(); 88 | 89 | for (val = ""; *val == NULL; ) 90 | val = getparam(name); 91 | return (atol(val)); 92 | } 93 | 94 | bool getbparam(name) 95 | string name; /* name of parameter */ 96 | { 97 | string getparam(), val; 98 | 99 | for (val = ""; *val == NULL; ) 100 | val = getparam(name); 101 | if (strchr("tTyY1", *val) != NULL) { 102 | return (TRUE); 103 | } 104 | if (strchr("fFnN0", *val) != NULL) { 105 | return (FALSE); 106 | } 107 | error("getbparam: %s=%s not bool\n", name, val); 108 | } 109 | 110 | double getdparam(name) 111 | string name; /* name of parameter */ 112 | { 113 | string getparam(), val; 114 | double atof(); 115 | 116 | for (val = ""; *val == NULL; ) { 117 | val = getparam(name); 118 | } 119 | return (atof(val)); 120 | } 121 | 122 | 123 | 124 | /* 125 | * SCANBIND: scan binding vector for name, return index. 126 | */ 127 | 128 | int scanbind(bvec, name) 129 | string bvec[]; 130 | string name; 131 | { 132 | int i; 133 | bool matchname(); 134 | 135 | for (i = 0; bvec[i] != NULL; i++) 136 | if (matchname(bvec[i], name)) 137 | return (i); 138 | return (-1); 139 | } 140 | 141 | /* 142 | * MATCHNAME: determine if "name=value" matches "name". 143 | */ 144 | 145 | bool matchname(bind, name) 146 | string bind, name; 147 | { 148 | char *bp, *np; 149 | 150 | bp = bind; 151 | np = name; 152 | while (*bp == *np) { 153 | bp++; 154 | np++; 155 | } 156 | return (*bp == '=' && *np == NULL); 157 | } 158 | 159 | /* 160 | * EXTRVALUE: extract value from name=value string. 161 | */ 162 | 163 | string extrvalue(arg) 164 | string arg; /* string of the form "name=value" */ 165 | { 166 | char *ap; 167 | 168 | ap = (char *) arg; 169 | while (*ap != NULL) 170 | if (*ap++ == '=') 171 | return ((string) ap); 172 | return (NULL); 173 | } 174 | 175 | -------------------------------------------------------------------------------- /bench/barnes/input: -------------------------------------------------------------------------------- 1 | 2 | 163840 3 | 123 4 | 5 | 0.025 6 | 0.05 7 | 1.0 8 | 2.0 9 | 5.0 10 | 0.075 11 | 0.25 12 | 1 13 | -------------------------------------------------------------------------------- /bench/barnes/stdinc.h: -------------------------------------------------------------------------------- 1 | #line 95 "./null_macros/c.m4.null" 2 | 3 | #line 1 "stdinc.H" 4 | /*************************************************************************/ 5 | /* */ 6 | /* Copyright (c) 1994 Stanford University */ 7 | /* */ 8 | /* All rights reserved. */ 9 | /* */ 10 | /* Permission is given to use, copy, and modify this software for any */ 11 | /* non-commercial purpose as long as this copyright notice is not */ 12 | /* removed. All other uses, including redistribution in whole or in */ 13 | /* part, are forbidden without prior written permission. */ 14 | /* */ 15 | /* This software is provided with absolutely no warranty and no */ 16 | /* support. */ 17 | /* */ 18 | /*************************************************************************/ 19 | 20 | /* 21 | * STDINC.H: standard include file for C programs. 22 | */ 23 | 24 | #ifndef _STDINC_H_ 25 | #define _STDINC_H_ 26 | 27 | /* 28 | * If not already loaded, include stdio.h. 29 | */ 30 | 31 | #include 32 | 33 | /* 34 | * STREAM: a replacement for FILE *. 35 | */ 36 | 37 | typedef FILE *stream; 38 | 39 | /* 40 | * NULL: denotes a pointer to no object. 41 | */ 42 | 43 | #ifndef NULL 44 | #define NULL 0 45 | #endif 46 | 47 | /* 48 | * BOOL, TRUE and FALSE: standard names for logical values. 49 | */ 50 | 51 | typedef int bool; 52 | 53 | #ifndef TRUE 54 | 55 | #define FALSE 0 56 | #define TRUE 1 57 | 58 | #endif 59 | 60 | /* 61 | * BYTE: a short name for a handy chunk of bits. 62 | */ 63 | 64 | typedef unsigned char byte; 65 | 66 | /* 67 | * STRING: for null-terminated strings which are not taken apart. 68 | */ 69 | 70 | typedef char *string; 71 | 72 | /* 73 | * REAL: default type is double; 74 | */ 75 | 76 | typedef double real, *realptr; 77 | 78 | /* 79 | * PROC, IPROC, RPROC: pointers to procedures, integer functions, and 80 | * real-valued functions, respectively. 81 | */ 82 | 83 | typedef void (*proced)(); 84 | typedef int (*iproc)(); 85 | typedef real (*rproc)(); 86 | 87 | /* 88 | * LOCAL: declare something to be local to a file. 89 | * PERMANENT: declare something to be permanent data within a function. 90 | */ 91 | 92 | #define local static 93 | #define permanent static 94 | 95 | /* 96 | * STREQ: handy string-equality macro. 97 | */ 98 | 99 | #define streq(x,y) (strcmp((x), (y)) == 0) 100 | 101 | /* 102 | * PI, etc. -- mathematical constants 103 | */ 104 | 105 | #define PI 3.14159265358979323846 106 | #define TWO_PI 6.28318530717958647693 107 | #define FOUR_PI 12.56637061435917295385 108 | #define HALF_PI 1.57079632679489661923 109 | #define FRTHRD_PI 4.18879020478639098462 110 | 111 | /* 112 | * ABS: returns the absolute value of its argument 113 | * MAX: returns the argument with the highest value 114 | * MIN: returns the argument with the lowest value 115 | */ 116 | 117 | #define ABS(x) (((x) < 0) ? -(x) : (x)) 118 | 119 | #endif 120 | -------------------------------------------------------------------------------- /bench/barnes/util.c: -------------------------------------------------------------------------------- 1 | #line 95 "./null_macros/c.m4.null" 2 | 3 | #line 1 "util.C" 4 | /*************************************************************************/ 5 | /* */ 6 | /* Copyright (c) 1994 Stanford University */ 7 | /* */ 8 | /* All rights reserved. */ 9 | /* */ 10 | /* Permission is given to use, copy, and modify this software for any */ 11 | /* non-commercial purpose as long as this copyright notice is not */ 12 | /* removed. All other uses, including redistribution in whole or in */ 13 | /* part, are forbidden without prior written permission. */ 14 | /* */ 15 | /* This software is provided with absolutely no warranty and no */ 16 | /* support. */ 17 | /* */ 18 | /*************************************************************************/ 19 | 20 | #include 21 | #include 22 | #include "stdinc.h" 23 | 24 | #define HZ 60.0 25 | #define MULT 1103515245 26 | #define ADD 12345 27 | #define MASK (0x7FFFFFFF) 28 | #define TWOTO31 2147483648.0 29 | 30 | local int A = 1; 31 | local int B = 0; 32 | local int randx = 1; 33 | local int lastrand; /* the last random number */ 34 | 35 | /* 36 | * XRAND: generate floating-point random number. 37 | */ 38 | 39 | double prand(); 40 | 41 | double xrand(xl, xh) 42 | double xl, xh; /* lower, upper bounds on number */ 43 | { 44 | long random (); 45 | double x; 46 | 47 | return (xl + (xh - xl) * prand()); 48 | } 49 | 50 | void pranset(int seed) 51 | { 52 | int proc; 53 | 54 | A = 1; 55 | B = 0; 56 | randx = (A*seed+B) & MASK; 57 | A = (MULT * A) & MASK; 58 | B = (MULT*B + ADD) & MASK; 59 | } 60 | 61 | double 62 | prand() 63 | /* 64 | Return a random double in [0, 1.0) 65 | */ 66 | { 67 | lastrand = randx; 68 | randx = (A*randx+B) & MASK; 69 | return((double)lastrand/TWOTO31); 70 | } 71 | 72 | /* 73 | * CPUTIME: compute CPU time in min. 74 | */ 75 | 76 | #include 77 | #include 78 | 79 | 80 | double cputime() 81 | { 82 | struct tms buffer; 83 | 84 | if (times(&buffer) == -1) 85 | error("times() call failed\n"); 86 | return (buffer.tms_utime / (60.0 * HZ)); 87 | } 88 | 89 | /* 90 | * ERROR: scream and die quickly. 91 | */ 92 | 93 | error(msg, a1, a2, a3, a4) 94 | char *msg, *a1, *a2, *a3, *a4; 95 | { 96 | extern int errno; 97 | 98 | fprintf(stderr, msg, a1, a2, a3, a4); 99 | if (errno != 0) 100 | perror("Error"); 101 | exit(0); 102 | } 103 | 104 | -------------------------------------------------------------------------------- /bench/cache-scratch/README.md: -------------------------------------------------------------------------------- 1 | By Emery Berger as part of [Hoard](https://github.com/emeryberger/Hoard) 2 | to test for passive-false sharing of cache lines. 3 | 4 | ``` 5 | Hoard: A Fast, Scalable, and Memory-Efficient Allocator 6 | for Shared-Memory Multiprocessors 7 | Contact author: Emery Berger, http://www.cs.umass.edu/~emery 8 | 9 | This library is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU Library General Public License as 11 | published by the Free Software Foundation, http://www.fsf.org. 12 | 13 | This library is distributed in the hope that it will be useful, but 14 | WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | Library General Public License for more details. 17 | ``` 18 | -------------------------------------------------------------------------------- /bench/cache-scratch/cache-scratch.cpp: -------------------------------------------------------------------------------- 1 | ///-*-C++-*-////////////////////////////////////////////////////////////////// 2 | // 3 | // Hoard: A Fast, Scalable, and Memory-Efficient Allocator 4 | // for Shared-Memory Multiprocessors 5 | // Contact author: Emery Berger, http://www.cs.umass.edu/~emery 6 | // 7 | // This library is free software; you can redistribute it and/or modify 8 | // it under the terms of the GNU Library General Public License as 9 | // published by the Free Software Foundation, http://www.fsf.org. 10 | // 11 | // This library is distributed in the hope that it will be useful, but 12 | // WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | // Library General Public License for more details. 15 | // 16 | ////////////////////////////////////////////////////////////////////////////// 17 | 18 | /** 19 | * @file cache-scratch.cpp 20 | * 21 | * cache-scratch is a benchmark that exercises a heap's cache locality. 22 | * An allocator that allows multiple threads to re-use the same small 23 | * object (possibly all in one cache-line) will scale poorly, while 24 | * an allocator like Hoard will exhibit near-linear scaling. 25 | * 26 | * Try the following (on a P-processor machine): 27 | * 28 | * cache-scratch 1 1000 1 1000000 P 29 | * cache-scratch P 1000 1 1000000 P 30 | * 31 | * cache-scratch-hoard 1 1000 1 1000000 P 32 | * cache-scratch-hoard P 1000 1 1000000 P 33 | * 34 | * The ideal is a P-fold speedup. 35 | */ 36 | 37 | #include 38 | #include 39 | #include 40 | using namespace std; 41 | 42 | 43 | // This class just holds arguments to each thread. 44 | class workerArg { 45 | public: 46 | 47 | workerArg() {} 48 | 49 | workerArg (char * obj, int objSize, int repetitions, int iterations) 50 | : _object (obj), 51 | _objSize (objSize), 52 | _iterations (iterations), 53 | _repetitions (repetitions) 54 | {} 55 | 56 | char * _object; 57 | int _objSize; 58 | int _iterations; 59 | int _repetitions; 60 | }; 61 | 62 | 63 | #if defined(_WIN32) 64 | extern "C" void worker (void * arg) 65 | #else 66 | extern "C" void * worker (void * arg) 67 | #endif 68 | { 69 | // free the object we were given. 70 | // Then, repeatedly do the following: 71 | // malloc a given-sized object, 72 | // repeatedly write on it, 73 | // then free it. 74 | workerArg * w = (workerArg *) arg; 75 | delete w->_object; 76 | workerArg w1 = *w; 77 | for (int i = 0; i < w1._iterations; i++) { 78 | // Allocate the object. 79 | char * obj = new char[w1._objSize]; 80 | // Write into it a bunch of times. 81 | for (int j = 0; j < w1._repetitions; j++) { 82 | for (int k = 0; k < w1._objSize; k++) { 83 | obj[k] = (char) k; 84 | volatile char ch = obj[k]; 85 | ch++; 86 | } 87 | } 88 | // Free the object. 89 | delete [] obj; 90 | } 91 | 92 | #if !defined(_WIN32) 93 | return NULL; 94 | #endif 95 | } 96 | 97 | 98 | int main (int argc, char * argv[]) 99 | { 100 | int nthreads; 101 | int iterations; 102 | int objSize; 103 | int repetitions; 104 | int concurrency; 105 | 106 | if (argc > 5) { 107 | nthreads = atoi(argv[1]); 108 | iterations = atoi(argv[2]); 109 | objSize = atoi(argv[3]); 110 | repetitions = atoi(argv[4]); 111 | concurrency = atoi(argv[5]); 112 | } else { 113 | cout << "Usage: " << argv[0] << " nthreads iterations objSize repetitions concurrency" << endl; 114 | exit(1); 115 | } 116 | 117 | pthread_t* threads = (pthread_t*)calloc(nthreads,sizeof(pthread_t)); 118 | pthread_setconcurrency(concurrency); 119 | workerArg * w = new workerArg[nthreads]; 120 | 121 | int i; 122 | 123 | // Allocate nthreads objects and distribute them among the threads. 124 | char ** objs = new char * [nthreads]; 125 | for (i = 0; i < nthreads; i++) { 126 | objs[i] = new char[objSize]; 127 | } 128 | 129 | 130 | for (i = 0; i < nthreads; i++) { 131 | w[i] = workerArg (objs[i], objSize, repetitions / nthreads, iterations); 132 | pthread_create(&threads[i], NULL, &worker, (void *)&w[i]); 133 | } 134 | for (i = 0; i < nthreads; i++) { 135 | pthread_join(threads[i], NULL); 136 | } 137 | 138 | free(threads); 139 | delete [] objs; 140 | delete [] w; 141 | 142 | return 0; 143 | } 144 | -------------------------------------------------------------------------------- /bench/cache-thrash/README.md: -------------------------------------------------------------------------------- 1 | By Emery Berger as part of [Hoard](https://github.com/emeryberger/Hoard) 2 | to test for heap cache locality. 3 | 4 | ``` 5 | Hoard: A Fast, Scalable, and Memory-Efficient Allocator 6 | for Shared-Memory Multiprocessors 7 | 8 | Contact author: Emery Berger, http://www.cs.umass.edu/~emery 9 | 10 | This library is free software; you can redistribute it and/or modify 11 | it under the terms of the GNU Library General Public License as 12 | published by the Free Software Foundation, http://www.fsf.org. 13 | 14 | This library is distributed in the hope that it will be useful, but 15 | WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | Library General Public License for more details. 18 | ``` 19 | -------------------------------------------------------------------------------- /bench/cache-thrash/cache-thrash.cpp: -------------------------------------------------------------------------------- 1 | ///-*-C++-*-////////////////////////////////////////////////////////////////// 2 | // 3 | // Hoard: A Fast, Scalable, and Memory-Efficient Allocator 4 | // for Shared-Memory Multiprocessors 5 | // Contact author: Emery Berger, http://www.cs.umass.edu/~emery 6 | // 7 | // Copyright (c) 1998-2003, The University of Texas at Austin. 8 | // 9 | // This library is free software; you can redistribute it and/or modify 10 | // it under the terms of the GNU Library General Public License as 11 | // published by the Free Software Foundation, http://www.fsf.org. 12 | // 13 | // This library is distributed in the hope that it will be useful, but 14 | // WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | // Library General Public License for more details. 17 | // 18 | ////////////////////////////////////////////////////////////////////////////// 19 | 20 | /** 21 | * @file cache-thrash.cpp 22 | * @brief cache-thrash is a benchmark that exercises a heap's cache-locality. 23 | * 24 | * Try the following (on a P-processor machine): 25 | * 26 | * cache-thrash 1 1000 1 1000000 P 27 | * cache-thrash P 1000 1 1000000 P 28 | * 29 | * cache-thrash-hoard 1 1000 1 1000000 P 30 | * cache-thrash-hoard P 1000 1 1000000 P 31 | * 32 | * The ideal is a P-fold speedup. 33 | */ 34 | 35 | 36 | #include 37 | #include 38 | #include 39 | using namespace std; 40 | 41 | 42 | // This class just holds arguments to each thread. 43 | class workerArg { 44 | public: 45 | workerArg() {} 46 | workerArg (int objSize, int repetitions, int iterations) 47 | : _objSize (objSize), 48 | _iterations (iterations), 49 | _repetitions (repetitions) 50 | {} 51 | 52 | int _objSize; 53 | int _iterations; 54 | int _repetitions; 55 | }; 56 | 57 | 58 | extern "C" void * worker (void * arg) 59 | { 60 | // Repeatedly do the following: 61 | // malloc a given-sized object, 62 | // repeatedly write on it, 63 | // then free it. 64 | workerArg * w = (workerArg *) arg; 65 | workerArg w1 = *w; 66 | for (int i = 0; i < w1._iterations; i++) { 67 | // Allocate the object. 68 | char * obj = new char[w1._objSize]; 69 | // printf ("obj = %p\n", obj); 70 | // Write into it a bunch of times. 71 | for (int j = 0; j < w1._repetitions; j++) { 72 | for (int k = 0; k < w1._objSize; k++) { 73 | #if 0 74 | volatile double d = 1.0; 75 | d = d * d + d * d; 76 | #else 77 | obj[k] = (char) k; 78 | volatile char ch = obj[k]; 79 | ch++; 80 | #endif 81 | } 82 | } 83 | // Free the object. 84 | delete [] obj; 85 | } 86 | #if !defined(_WIN32) 87 | return NULL; 88 | #endif 89 | } 90 | 91 | 92 | int main (int argc, char * argv[]) 93 | { 94 | int nthreads; 95 | int iterations; 96 | int objSize; 97 | int repetitions; 98 | int concurrency; 99 | 100 | if (argc > 5) { 101 | nthreads = atoi(argv[1]); 102 | iterations = atoi(argv[2]); 103 | objSize = atoi(argv[3]); 104 | repetitions = atoi(argv[4]); 105 | concurrency = atoi(argv[5]); 106 | } else { 107 | cerr << "Usage: " << argv[0] << " nthreads iterations objSize repetitions concurrency" << endl; 108 | exit(1); 109 | } 110 | 111 | pthread_t* threads = (pthread_t*)calloc(nthreads,sizeof(pthread_t)); 112 | pthread_setconcurrency(concurrency); 113 | 114 | int i; 115 | 116 | workerArg * w = new workerArg[nthreads]; 117 | 118 | for (i = 0; i < nthreads; i++) { 119 | w[i] = workerArg (objSize, repetitions / nthreads, iterations); 120 | pthread_create(&threads[i], NULL, &worker, (void *)&w[i]); 121 | } 122 | for (i = 0; i < nthreads; i++) { 123 | pthread_join(threads[i], NULL); 124 | } 125 | 126 | free(threads); 127 | delete [] w; 128 | 129 | } 130 | -------------------------------------------------------------------------------- /bench/cfrac/README.md: -------------------------------------------------------------------------------- 1 | pcfrac: Implementation of the continued fraction factoring algoritm 2 | 3 | Every two digits additional appears to double the factoring time 4 | 5 | Written by Dave Barrett (barrett%asgard@boulder.Colorado.EDU) 6 | -------------------------------------------------------------------------------- /bench/cfrac/asm16bit.h: -------------------------------------------------------------------------------- 1 | /* 2 | * HP-UX C compiler conventions 3 | * 4 | * Args pushed right-to-left; caller pops args on return 5 | * Function result returned in d0 or d0(msb) d1(lsb) pair 6 | * Called function must preserve all registers except d0,d1,a0,a1 7 | * C Registers are allocated from top-to-bottem in text from d7-d2, a5-a2 8 | */ 9 | #ifdef __STDC__ 10 | extern digit memaddw(digitPtr, digitPtr, digitPtr, posit); 11 | extern digit memsubw(digitPtr, digitPtr, digitPtr, posit); 12 | 13 | extern digit memincw(digitPtr, accumulator); 14 | extern digit memdecw(digitPtr, accumulator); 15 | 16 | extern digit memmulw(digitPtr, digitPtr, posit, digitPtr, posit); 17 | 18 | extern digit memdivw(digitPtr, digitPtr, posit, digitPtr); 19 | extern digit memdivw1(digitPtr, digitPtr, posit, digit); 20 | extern digit memmulw1(digitPtr, digitPtr, posit, digit); 21 | extern digit memmodw1(digitPtr, posit, digit); 22 | 23 | extern void memlsrw(digitPtr, posit); 24 | #else 25 | extern digit memaddw(); 26 | extern digit memsubw(); 27 | 28 | extern digit memincw(); 29 | extern digit memdecw(); 30 | 31 | extern digit memmulw(); 32 | 33 | extern digit memdivw(); 34 | extern digit memdivw1(); 35 | extern digit memmulw1(); 36 | extern digit memmodw1(); 37 | 38 | extern void memlsrw(); 39 | #endif 40 | -------------------------------------------------------------------------------- /bench/cfrac/atop.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "pdefs.h" 3 | #include "pcvt.h" 4 | #include "precision.h" 5 | 6 | /* 7 | * ascii to precision (modeled after atoi) 8 | * leading whitespace skipped 9 | * an optional leading '-' or '+' followed by digits '0'..'9' 10 | * leading 0's Ok 11 | * stops at first unrecognized character 12 | * 13 | * Returns: pUndef if an invalid argument (pUndef or nondigit as 1st digit) 14 | */ 15 | precision atop(chp) 16 | register char *chp; 17 | { 18 | precision res = pUndef; 19 | precision clump = pUndef; 20 | int sign = 0; 21 | register int ch; 22 | register accumulator temp; 23 | accumulator x; 24 | register int i; 25 | 26 | if (chp != (char *) 0) { 27 | while (isspace(*chp)) chp++; /* skip whitespace */ 28 | if (*chp == '-') { 29 | sign = 1; 30 | ++chp; 31 | } else if (*chp == '+') { 32 | ++chp; 33 | } 34 | if (isdigit(ch = * (unsigned char *) chp)) { 35 | pset(&res, pzero); 36 | pset(&clump, utop(aDigit)); 37 | do { 38 | i = aDigitLog-1; 39 | temp = ch - '0'; 40 | do { 41 | if (!isdigit(ch = * (unsigned char *) ++chp)) goto atoplast; 42 | temp = temp * aBase + (ch - '0'); 43 | } while (--i > 0); 44 | pset(&res, padd(pmul(res, clump), utop(temp))); 45 | } while (isdigit(ch = * (unsigned char *) ++chp)); 46 | goto atopdone; 47 | atoplast: 48 | x = aBase; 49 | while (i++ < aDigitLog-1) { 50 | x *= aBase; 51 | } 52 | pset(&res, padd(pmul(res, utop(x)), utop(temp))); 53 | atopdone: 54 | if (sign) { 55 | pset(&res, pneg(res)); 56 | } 57 | } 58 | } 59 | pdestroy(clump); 60 | return presult(res); 61 | } 62 | -------------------------------------------------------------------------------- /bench/cfrac/errorp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "precision.h" 3 | 4 | /* 5 | * Fatal error (user substitutable) 6 | * 7 | * PNOMEM - out of memory (pcreate) 8 | * PREFCOUNT - refcount negative (pdestroy) 9 | * PUNDEFINED - undefined value referenced (all) 10 | * PDOMAIN - domain error 11 | * pdivmod: divide by zero 12 | * psqrt: negative argument 13 | * POVERFLOW - overflow 14 | * itop: too big 15 | */ 16 | precision errorp(errnum, routine, message) 17 | int errnum; 18 | char *routine; 19 | char *message; 20 | { 21 | fputs(routine, stderr); 22 | fputs(": ", stderr); 23 | fputs(message, stderr); 24 | fputs("\n", stderr); 25 | abort(); /* remove this line if you want */ 26 | return pUndef; 27 | } 28 | -------------------------------------------------------------------------------- /bench/cfrac/itop.c: -------------------------------------------------------------------------------- 1 | #include "pdefs.h" 2 | #include "pcvt.h" 3 | #include "precision.h" 4 | 5 | /* 6 | * Integer to Precision 7 | */ 8 | precision itop(i) 9 | register int i; 10 | { 11 | register digitPtr uPtr; 12 | register precision u = palloc(INTSIZE); 13 | 14 | if (u == pUndef) return u; 15 | 16 | if (u->sign = (i < 0)) i = -i; 17 | uPtr = u->value; 18 | do { 19 | *uPtr++ = modBase(i); 20 | i = divBase(i); 21 | } while (i != 0); 22 | 23 | u->size = (uPtr - u->value); /* normalize */ 24 | return presult(u); 25 | } 26 | -------------------------------------------------------------------------------- /bench/cfrac/ltop.c: -------------------------------------------------------------------------------- 1 | #include "pdefs.h" 2 | #include "pcvt.h" 3 | #include "precision.h" 4 | 5 | /* 6 | * Long to Precision 7 | */ 8 | precision ltop(l) 9 | register long l; 10 | { 11 | register digitPtr uPtr; 12 | register precision u = palloc(LONGSIZE); 13 | 14 | if (u == pUndef) return u; 15 | 16 | if (u->sign = (l < 0L)) l = -l; 17 | uPtr = u->value; 18 | do { 19 | *uPtr++ = modBase(l); 20 | l = divBase(l); 21 | } while (l != 0); 22 | 23 | u->size = (uPtr - u->value); /* normalize */ 24 | return presult(u); 25 | } 26 | -------------------------------------------------------------------------------- /bench/cfrac/pabs.c: -------------------------------------------------------------------------------- 1 | #include "pdefs.h" /* private include file */ 2 | #include "precision.h" /* public include file for forward refs */ 3 | #include 4 | 5 | /* 6 | * absolute value 7 | */ 8 | precision pabs(u) 9 | register precision u; 10 | { 11 | register precision w; 12 | 13 | (void) pparm(u); 14 | w = palloc(u->size); 15 | if (w == pUndef) return w; 16 | 17 | w->sign = false; 18 | (void) memcpy(w->value, u->value, u->size * sizeof(digit)); 19 | 20 | pdestroy(u); 21 | return presult(w); 22 | } 23 | -------------------------------------------------------------------------------- /bench/cfrac/padd.c: -------------------------------------------------------------------------------- 1 | #include "pdefs.h" 2 | #include "precision.h" 3 | #include 4 | 5 | #ifdef ASM_16BIT 6 | #include "asm16bit.h" 7 | #endif 8 | 9 | /* 10 | * Add 11 | * 12 | * This will work correctly if -0 is passed as input 13 | */ 14 | precision padd(u, v) 15 | register precision v; 16 | #ifndef ASM_16BIT 17 | precision u; 18 | { 19 | register digitPtr wPtr, uPtr, vPtr; 20 | #else 21 | register precision u; 22 | { 23 | register digitPtr wPtr; 24 | digitPtr uPtr; 25 | #endif 26 | precision w; /* function result */ 27 | register accumulator temp; /* 0 <= temp < 2*base */ 28 | register digit carry; /* 0 <= carry <= 1 */ 29 | #ifdef ASM_16BIT 30 | register int size; 31 | #endif 32 | 33 | (void) pparm(u); 34 | (void) pparm(v); 35 | if (u->sign != v->sign) { /* Are we are actually subtracting? */ 36 | w = pUndef; 37 | if (v->sign) { 38 | v->sign = !v->sign; /* can't generate -0 */ 39 | pset(&w, psub(u, v)); 40 | v->sign = !v->sign; 41 | } else { 42 | u->sign = !u->sign; /* can't generate -0 */ 43 | pset(&w, psub(v, u)); 44 | u->sign = !u->sign; 45 | } 46 | } else { 47 | if (u->size < v->size) { /* u is always biggest number */ 48 | w = u; u = v; v = w; 49 | } 50 | 51 | w = palloc(u->size+1); /* there is at most one added digit */ 52 | if (w == pUndef) return w; /* arguments not destroyed */ 53 | 54 | w->sign = u->sign; 55 | 56 | uPtr = u->value; 57 | wPtr = w->value; 58 | #ifndef ASM_16BIT 59 | vPtr = v->value; 60 | carry = 0; 61 | do { /* Add digits in both args */ 62 | temp = *uPtr++ + *vPtr++; /* 0 <= temp < 2*base-1 */ 63 | temp += carry; /* 0 <= temp < 2*base */ 64 | carry = divBase(temp); /* 0 <= carry <= 1 */ 65 | *wPtr++ = modBase(temp); /* mod has positive args */ 66 | } while (vPtr < v->value + v->size); 67 | 68 | while (uPtr < u->value + u->size) { /* propogate carry */ 69 | temp = *uPtr++ + carry; 70 | carry = divBase(temp); 71 | *wPtr++ = modBase(temp); 72 | } 73 | *wPtr = carry; 74 | #else 75 | size = v->size; 76 | temp = u->size - size; 77 | carry = memaddw(wPtr, uPtr, v->value, size); 78 | if (temp > 0) { 79 | memcpy(wPtr + size, uPtr + size, temp * sizeof(digit)); 80 | if (carry) { 81 | carry = memincw(wPtr + size, temp); 82 | } 83 | } 84 | wPtr[u->size] = carry; /* yes, I do mean u->size */ 85 | #endif 86 | if (carry == 0) { 87 | --(w->size); 88 | } 89 | } 90 | 91 | pdestroy(u); 92 | pdestroy(v); 93 | return presult(w); 94 | } 95 | -------------------------------------------------------------------------------- /bench/cfrac/pcmp.c: -------------------------------------------------------------------------------- 1 | #include "pdefs.h" 2 | #include "precision.h" 3 | 4 | /* 5 | * Compare to zero (normalization not assumed) 6 | * 7 | * Returns same as pcmp(u, 0); 8 | */ 9 | int pcmpz(u) 10 | register precision u; 11 | { 12 | register digitPtr uPtr; 13 | register int i; 14 | 15 | (void) pparm(u); 16 | i = 0; 17 | uPtr = u->value; 18 | do { 19 | if (*uPtr++ != 0) { 20 | if (u->sign) i = -1; else i = 1; 21 | break; 22 | } 23 | } while (uPtr < u->value + u->size); 24 | 25 | pdestroy(u); 26 | return i; 27 | } 28 | 29 | /* 30 | * Compare u to v. 31 | * 32 | * Return: < 0 if u < v 33 | * = 0 if u = v 34 | * > 0 if u > v 35 | * 36 | * This routine is the one that assumes results are normalized! 37 | * - no leading 0's 38 | * - no negative 0 39 | */ 40 | int pcmp(u, v) 41 | precision u, v; 42 | { 43 | register digitPtr uPtr, vPtr; 44 | register int i; /* should be bigger than posit */ 45 | 46 | (void) pparm(u); 47 | (void) pparm(v); 48 | if (u->sign != v->sign) { 49 | if (u->sign) i = -1; else i = 1; 50 | } else { 51 | i = u->size - v->size; 52 | if (i == 0) { 53 | uPtr = u->value + u->size; 54 | vPtr = v->value + v->size; 55 | do { 56 | if (*--uPtr != *--vPtr) break; 57 | } while (vPtr > v->value); 58 | if (*uPtr > *vPtr) i = 1; 59 | else if (*uPtr < *vPtr) i = -1; 60 | } 61 | 62 | if (u->sign) i = -i; 63 | } 64 | 65 | pdestroy(u); 66 | pdestroy(v); 67 | return i; 68 | } 69 | -------------------------------------------------------------------------------- /bench/cfrac/pconst.c: -------------------------------------------------------------------------------- 1 | #include "pdefs.h" 2 | 3 | static precisionType pzeroConst = { 4 | #ifndef BWGC 5 | (short) 1, /* refcount (read/write!) */ 6 | #endif 7 | (posit) 1, /* size */ 8 | (posit) 1, /* digitcount */ 9 | (boolean) 0, /* sign */ 10 | { (digit) 0 } /* value */ 11 | }; 12 | 13 | static precisionType poneConst = { 14 | #ifndef BWGC 15 | (short) 1, /* refcount (read/write!) */ 16 | #endif 17 | (posit) 1, /* size */ 18 | (posit) 1, /* digitcount */ 19 | (boolean) 0, /* sign */ 20 | { (digit) 1 } /* value */ 21 | }; 22 | 23 | static precisionType ptwoConst = { 24 | #ifndef BWGC 25 | (short) 1, /* refcount (read/write!) */ 26 | #endif 27 | (posit) 1, /* size */ 28 | (posit) 1, /* digitcount */ 29 | (boolean) 0, /* sign */ 30 | { (digit) 2 } /* value */ 31 | }; 32 | 33 | static precisionType p_oneConst = { 34 | #ifndef BWGC 35 | (short) 1, /* refcount (read/write!) */ 36 | #endif 37 | (posit) 1, /* size */ 38 | (posit) 1, /* digitcount */ 39 | (boolean) 1, /* sign */ 40 | { (digit) 1 } /* value */ 41 | }; 42 | 43 | precision pzero = &pzeroConst; /* zero */ 44 | precision pone = &poneConst; /* one */ 45 | precision ptwo = &ptwoConst; /* two */ 46 | precision p_one = &p_oneConst; /* negative one */ 47 | -------------------------------------------------------------------------------- /bench/cfrac/pcvt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Machine dependent file used for conversion routines 3 | * (e.g. atop, ptoa, itop, ptoi, etc) 4 | */ 5 | 6 | /* 7 | * For pXtop: (X = {i,u,l,ul,d}) 8 | */ 9 | #define INTSIZE 2 /* floor(log[Base](2*(MAXINT+1))) */ 10 | #define LONGSIZE 2 /* floor(log[Base](2*(MAXLONG+1))) */ 11 | #define DOUBLESIZE 129 /* double precision size = log[base](HUGE) */ 12 | 13 | /* 14 | * For ptoX 15 | */ 16 | #define MAXINT (int) ((unsigned int) ~0 >> 1) 17 | #define MAXLONG (long) ((unsigned long) ~0 >> 1) 18 | #define MAXUNSIGNED (~ (unsigned int) 0) 19 | #define MAXUNSIGNEDLONG (~ (unsigned long) 0L) 20 | 21 | #define MAXACC (~ (accumulator) 0) 22 | 23 | /* 24 | * aBase - Ascii base (ptoa) 25 | * There are aDigits Ascii digits per precision digit, pDigits. 26 | * At least one of { aDigits, pDigits } <= (MAXINT / the maximum posit value). 27 | */ 28 | #define aDigits 525 /* aDigits/pDigits >~= log[aBase](Base) */ 29 | #define pDigits 109 /* 525/109=4.8165>log[10](65536)=4.816479931 */ 30 | #define aBase 10 /* string conversion base */ 31 | #define aDigit 1000000000 /* must be power of aBase < MAXINT */ 32 | #define aDigitLog 9 /* log[aBase] of aDigit */ 33 | -------------------------------------------------------------------------------- /bench/cfrac/pdefs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * +------------------------------------------------------------------+ 3 | * | Private Math Library Definitions | 4 | * +------------------------------------------------------------------+ 5 | */ 6 | /* 7 | * Optional assembly language 8 | */ 9 | #ifdef ASM 10 | #include "machineop.h" /* 16-bit integer machine operations */ 11 | #define uModDiv(n, d, qp) umoddiv16(n, d, qp) /* slight help */ 12 | #else 13 | #define uModDiv(n, d, qp) (*(qp) = (n) / (d), (n) % (d)) 14 | #endif 15 | #define uMul(u, v) ((u) * (v)) /* fast enough */ 16 | 17 | /* 18 | * Optional alternate memory allocator 19 | */ 20 | 21 | #ifndef MYALLOC 22 | 23 | # if defined(BWGC) 24 | extern char *gc_malloc_atomic(); 25 | #define allocate(size) (char *) gc_malloc_atomic(size) 26 | # elif defined(CUSTOM_MALLOC) 27 | #define allocate(size) CUSTOM_MALLOC(size) 28 | # else 29 | /* extern char *malloc(); */ 30 | #define allocate(size) (char *) malloc(size) 31 | # endif 32 | 33 | #ifdef IGNOREFREE 34 | #define deallocate(p) {}; 35 | # elif defined(CUSTOM_FREE) 36 | #define deallocate(p) CUSTOM_FREE(p) 37 | #else 38 | /* 39 | extern int free(); 40 | */ 41 | #define deallocate(p) free(p) 42 | #endif 43 | 44 | #else 45 | extern char *allocate(); 46 | extern void deallocate(); 47 | #endif 48 | 49 | /* 50 | * These next four types are used only used in this include file 51 | */ 52 | #include 53 | typedef unsigned char u8; /* 8 bits */ 54 | typedef uint16_t u16; /* 16 bits */ 55 | typedef uint32_t u32; /* 32 bits */ 56 | typedef u8 boolean; /* 1 bit */ 57 | 58 | #define BASE 65536 /* Base * (Base-1) <= MAXINT */ 59 | 60 | /* 61 | * Operations on Base (unsigned math) 62 | */ 63 | #define modBase(u) ((u) & 0xffff) /* remainder on Base */ 64 | #define divBase(u) ((u) >> 16) /* divide by Base */ 65 | #define mulBase(u) ((u) << 16) /* multiply by Base */ 66 | 67 | /* 68 | * The type of a variable used to store intermediate results. 69 | * This should be the most efficient unsigned int on your machine. 70 | */ 71 | typedef u32 accumulator; /* 0..(Base * Base) - 1 */ 72 | 73 | /* 74 | * The type of a single digit 75 | */ 76 | typedef u16 digit; /* 0..Base-1 */ 77 | 78 | /* 79 | * The type of a digit index (the largest number of digits - 1) 80 | * Determines the maximum representable precision (not usually changed) 81 | */ 82 | typedef u16 posit; /* 0..size */ 83 | 84 | typedef unsigned short prefc; /* in precision.h also */ 85 | /* 86 | * End of area which needs to be modified 87 | */ 88 | 89 | #define false 0 90 | #define true 1 91 | 92 | typedef digit digitString[1]; /* dummy array type */ 93 | typedef digit *digitPtr; 94 | 95 | /* 96 | * A normalized integer has the following attributes: 97 | * -0 cannot occur 98 | * all digits >= size assumed to be 0. (no leading zero's) 99 | * size > 0 100 | */ 101 | typedef struct { 102 | #ifndef BWGC 103 | prefc refcount; /* reference count (must be 1st [for pref]) */ 104 | #endif 105 | posit alloc; /* allocated size */ 106 | posit size; /* number of digits */ 107 | boolean sign; /* sign: TRUE negative */ 108 | digitString value; 109 | } precisionType; 110 | 111 | typedef precisionType *precision; 112 | 113 | /* 114 | * Overlay for cache of precisions 115 | */ 116 | typedef struct { 117 | precision next; /* next item in list */ 118 | short count; /* number of items in this sublist */ 119 | } cacheType; 120 | 121 | typedef cacheType *cachePtr; 122 | /* 123 | * Maximum total memory consumed by cache = 124 | * LIMIT * (1 + SIZE * (PrecisionSize + sizeof(digit) * (SIZE-1) / 2)) 125 | */ 126 | #ifndef CACHESIZE 127 | #define CACHESIZE 32 /* size of allocation cache */ 128 | #endif 129 | #define CACHELIMIT 128 /* Determines max mem used by cache */ 130 | 131 | #define PrecisionSize (sizeof(precisionType) - sizeof(digitString)) 132 | 133 | /* 134 | * Function definitions are all in the global include file "mathdefs.h". 135 | */ 136 | extern precision palloc(); /* semi-private */ 137 | extern int pfree(); /* semi-private */ 138 | extern void pnorm(); /* semi-private */ 139 | -------------------------------------------------------------------------------- /bench/cfrac/pfactor.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "precision.h" 3 | #include "pfactor.h" 4 | 5 | void showfactors(); 6 | 7 | 8 | int main(argc, argv) 9 | int argc; 10 | char *argv[]; 11 | { 12 | precision n = pUndef; 13 | 14 | --argc; 15 | if (argc != 0) { 16 | do { 17 | pset(&n, atop(*++argv)); 18 | showfactors(n); 19 | } while (--argc > 0); 20 | } else { 21 | do { 22 | pset(&n, fgetp(stdin)); 23 | if (n == pUndef) break; 24 | showfactors(n); 25 | } while (1); 26 | } 27 | pdestroy(n); 28 | return 0; 29 | } 30 | 31 | void showfactors(n) 32 | precision n; 33 | { 34 | precision r = pUndef; 35 | FactorList factors = (FactorList) 0; 36 | 37 | (void) pparm(n); 38 | pset(&r, ptrial(n, (unsigned *) 0, &factors)); 39 | fputp(stdout, n); 40 | fputs(" = ", stdout); 41 | pputfactors(stdout, factors); 42 | if pne(r, pone) { 43 | if pne(r, n) putc('*', stdout); 44 | if (!pprime(r, 16)) { 45 | fputc('(', stdout); fputp(stdout, r); fputc(')', stdout); 46 | } else { 47 | fputp(stdout, r); 48 | } 49 | } 50 | putc('\n', stdout); 51 | 52 | pfreefactors(&factors); 53 | pdestroy(r); 54 | pdestroy(n); 55 | } 56 | -------------------------------------------------------------------------------- /bench/cfrac/pfactor.h: -------------------------------------------------------------------------------- 1 | typedef struct Pfs { 2 | struct Pfs *next; 3 | precision factor; 4 | unsigned count; 5 | } Pfactor; 6 | 7 | typedef Pfactor *FactorPtr; 8 | typedef FactorPtr FactorList; 9 | typedef precision (*pfunc)(); /* pointer to func returning precision */ 10 | 11 | #ifndef __STDC__ 12 | 13 | extern int pprime(); /* test whether a number is prime */ 14 | extern precision pnextprime(); /* next prime >= it's argument */ 15 | 16 | extern precision pgcd(); /* greatest common divisor */ 17 | extern precision plcm(); /* least common multiple */ 18 | extern precision peuclid(); /* extended euclid's algorithm */ 19 | 20 | extern precision prho(); /* find factor using rho method */ 21 | extern precision pfermat(); /* find factor using Fermat's method */ 22 | extern precision pcfrac(); /* factor w/continued fractions */ 23 | 24 | extern int prhoInit(); /* alter parameters for rho method */ 25 | extern int pcfracInit(); /* alter paramteres for cfrac method */ 26 | 27 | extern precision ptrial(); /* find factors using trial division */ 28 | extern precision prfactor(); /* recursively factor a number */ 29 | 30 | extern void paddfactor(); /* add a factor to a factorlist */ 31 | extern void pputfactors(); /* print a factorlist */ 32 | extern void pfreefactors(); /* return a factorlist to memory */ 33 | 34 | #else 35 | 36 | extern int pprime(precision, unsigned trialCount); 37 | extern precision pnextprime(precision, unsigned trialCount); 38 | 39 | extern precision pgcd(precision, precision); 40 | extern precision plcm(precision, precision); 41 | extern precision peuclid(precision, precision, precision *, precision *); 42 | 43 | extern precision prho(precision n, unsigned *maxCount); 44 | extern precision pfermat(precision n, unsigned *maxCount); 45 | extern precision pcfrac(precision n, unsigned *maxCount); 46 | 47 | extern int prhoInit(precision c, unsigned batchSize); 48 | extern int pcfracInit(unsigned m, unsigned k, unsigned aborts); 49 | 50 | extern precision ptrial(precision n, unsigned *maxCount, FactorList *); 51 | extern precision prfactor(precision, unsigned *maxCount, pfunc, FactorList *); 52 | 53 | extern void paddfactor(FactorList *, precision); 54 | extern void pfreefactors(FactorList *); 55 | 56 | #ifndef BUFSIZE 57 | #include 58 | #endif 59 | 60 | extern void pputfactors(FILE *, FactorList); 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /bench/cfrac/pfloat.c: -------------------------------------------------------------------------------- 1 | /* 2 | * High Precision Math Library Supplement for floating point routines 3 | */ 4 | #include 5 | #include 6 | #include "pdefs.h" 7 | #include "pcvt.h" 8 | #include "precision.h" 9 | 10 | extern precision palloc(); 11 | 12 | /* 13 | * double to precision 14 | */ 15 | precision dtop(f) 16 | register double f; 17 | { 18 | register digitPtr uPtr; 19 | register precision u; 20 | 21 | u = palloc(DOUBLESIZE); /* pretty big */ 22 | if (u == pUndef) return u; 23 | 24 | if (f < 0.0) { 25 | f = -f; 26 | u->sign = true; 27 | } else { 28 | u->sign = false; 29 | } 30 | uPtr = u->value; 31 | do { 32 | *uPtr++ = fmod(f, (double) BASE); 33 | f = floor(f / (double) BASE); 34 | } while (f != 0.0); 35 | 36 | u->size = (uPtr - u->value); 37 | 38 | return presult(u); 39 | } 40 | 41 | /* 42 | * precision to double (no overflow check) 43 | */ 44 | double ptod(u) 45 | precision u; 46 | { 47 | register digitPtr uPtr; 48 | register double f; 49 | 50 | (void) pparm(u); 51 | uPtr = u->value + u->size; 52 | f = 0.0; 53 | do { 54 | f = f * (double) BASE + (double) *--uPtr; 55 | } while (uPtr > u->value); 56 | 57 | if (u->sign) f = -f; 58 | 59 | pdestroy(u); 60 | return f; 61 | } 62 | -------------------------------------------------------------------------------- /bench/cfrac/pgcd.c: -------------------------------------------------------------------------------- 1 | #include "precision.h" 2 | 3 | /* 4 | * Euclid's Algorithm 5 | * 6 | * Given u and v, calculated and return their greatest common divisor. 7 | */ 8 | precision pgcd(u, v) 9 | precision u, v; 10 | { 11 | precision u3 = pnew(pabs(pparm(u))), v3 = pnew(pabs(pparm(v))); 12 | precision q = pUndef, r = pUndef; 13 | 14 | while (pnez(v3)) { 15 | pdivmod(u3, v3, &q, &r); 16 | pset(&u3, v3); 17 | pset(&v3, r); 18 | } 19 | 20 | pdestroy(v3); 21 | pdestroy(q); pdestroy(r); 22 | pdestroy(u); pdestroy(v); 23 | return presult(u3); /* result always positive */ 24 | } 25 | -------------------------------------------------------------------------------- /bench/cfrac/phalf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "pdefs.h" 3 | #include "precision.h" 4 | 5 | #ifdef ASM_16BIT 6 | #include "asm16bit.h" 7 | #endif 8 | 9 | /* 10 | * Divide a precision by 2 11 | */ 12 | precision phalf(u) 13 | register precision u; 14 | { 15 | #ifdef ASM_16BIT 16 | register precision w; 17 | register posit usize; 18 | 19 | pparm(u); 20 | usize = u->size; 21 | w = palloc(usize); 22 | if (w == pUndef) return w; 23 | 24 | w->sign = u->sign; 25 | (void) memcpy(w->value, u->value, usize * sizeof(digit)); 26 | 27 | memlsrw(w->value, usize); /* 68000 assembly language routine */ 28 | if (usize > 1 && w->value[usize-1] == (digit) 0) { /* normalize */ 29 | --(w->size); 30 | } 31 | pdestroy(u); 32 | return presult(w); 33 | #else 34 | return pdiv(u, ptwo); 35 | #endif 36 | } 37 | -------------------------------------------------------------------------------- /bench/cfrac/picmp.c: -------------------------------------------------------------------------------- 1 | #include "pdefs.h" 2 | #include "precision.h" 3 | 4 | static char cmpError[] = "Second arg not single digit"; 5 | 6 | /* 7 | * Single-digit compare 8 | */ 9 | int picmp(u, v) 10 | register precision u; 11 | register int v; 12 | { 13 | register int i; 14 | 15 | (void) pparm(u); 16 | 17 | if (u->sign) { 18 | i = -1; 19 | if (v < 0) { 20 | if (-v >= BASE) { 21 | errorp(PDOMAIN, "picmp", cmpError); 22 | } 23 | if (u->size == 1) { 24 | i = - (int) *(u->value) - v; 25 | } 26 | } 27 | } else { 28 | i = 1; 29 | if (v >= 0) { 30 | if (v >= BASE) { 31 | errorp(PDOMAIN, "picmp", cmpError); 32 | } 33 | if (u->size == 1) { 34 | i = (int) *(u->value) - v; 35 | } 36 | } 37 | } 38 | 39 | pdestroy(u); 40 | return i; 41 | } 42 | -------------------------------------------------------------------------------- /bench/cfrac/pidiv.c: -------------------------------------------------------------------------------- 1 | #include "pdefs.h" 2 | #include "precision.h" 3 | #ifdef ASM_16BIT 4 | #include "asm16bit.h" 5 | #endif 6 | 7 | /* 8 | * Single-digit divide 9 | */ 10 | precision pidiv(u, v) 11 | register precision u; 12 | int v; 13 | { 14 | #ifndef ASM_16BIT 15 | register digitPtr uPtr, qPtr; 16 | register accumulator temp; /* 0 <= temp < base^2 */ 17 | #endif 18 | register digit r, d; /* 0 <= r,d < base */ 19 | register posit m; 20 | register precision q; 21 | 22 | (void) pparm(u); 23 | 24 | if (v < 0) d = (digit) -v; else d = (digit) v; 25 | if (d >= BASE) { 26 | q = pnew(errorp(PDOMAIN, "pidiv", "divisor too big for single digit")); 27 | goto done; 28 | } 29 | if (d == 0) { 30 | q = pnew(errorp(PDOMAIN, "pidiv", "divide by zero")); 31 | goto done; 32 | } 33 | m = u->size; 34 | q = palloc(m); 35 | if (q == pUndef) goto done; 36 | 37 | #ifndef ASM_16BIT 38 | qPtr = q->value + m; 39 | uPtr = u->value + m; 40 | r = 0; /* r is current remainder */ 41 | do { 42 | temp = mulBase(r); /* 0 <= temp <= (base-1)^2 */ 43 | temp += *--uPtr; /* 0 <= temp <= base(base-1) */ 44 | r = uModDiv(temp, d, --qPtr); /* 0 <= r < base */ 45 | } while (uPtr > u->value); 46 | #else 47 | r = memdivw1(q->value, u->value, m, d); 48 | #endif 49 | /* 50 | * normalize q 51 | */ 52 | if (m > 1 && q->value[m-1] == 0) { 53 | --(q->size); 54 | } 55 | q->sign = (u->sign != (v < 0)); 56 | if (q->size == 1 && *(q->value) == 0) q->sign = false; 57 | done: 58 | pdestroy(u); 59 | return presult(q); 60 | } 61 | -------------------------------------------------------------------------------- /bench/cfrac/pimod.c: -------------------------------------------------------------------------------- 1 | #include "pdefs.h" 2 | #include "precision.h" 3 | #ifdef ASM_16BIT 4 | #include "asm16bit.h" 5 | #endif 6 | 7 | /* 8 | * Single-digit remainder 9 | */ 10 | int pimod(u, v) 11 | register precision u; 12 | int v; 13 | { 14 | #ifndef ASM_16BIT 15 | register digitPtr uPtr; 16 | register accumulator temp; /* 0 <= temp < base^2 */ 17 | #endif 18 | register digit r = 0, d; /* 0 <= r,d < base */ 19 | register int res = 0; 20 | 21 | (void) pparm(u); 22 | if (v < 0) d = (digit) -v; else d = (digit) v; 23 | if (d >= BASE) { 24 | errorp(PDOMAIN, "pimod", "divisor too big for single digit"); 25 | goto done; 26 | } 27 | if (d == 0) { 28 | errorp(PDOMAIN, "pimod", "divide by zero"); 29 | goto done; 30 | } 31 | #ifndef ASM_16BIT 32 | uPtr = u->value + u->size; 33 | r = 0; /* r is current remainder */ 34 | do { 35 | temp = mulBase(r); /* 0 <= temp <= (base-1)^2 */ 36 | temp += *--uPtr; /* 0 <= temp <= base(base-1) */ 37 | r = temp % d; /* 0 <= r < base */ 38 | } while (uPtr > u->value); 39 | #else 40 | r = memmodw1(u->value, u->size, d); 41 | #endif 42 | 43 | res = (int) r; 44 | if (u->sign) res = -res; 45 | done: 46 | pdestroy(u); 47 | return res; 48 | } 49 | -------------------------------------------------------------------------------- /bench/cfrac/pio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "pdefs.h" 5 | #include "pcvt.h" 6 | #include "precision.h" 7 | 8 | /* 9 | * Output a string to a file. 10 | * 11 | * Returns: 12 | * the number of characters written 13 | * or EOF if error 14 | */ 15 | static int fouts(stream, chp) 16 | FILE *stream; 17 | register char *chp; 18 | { 19 | register int count = 0, res = 0; 20 | 21 | if (chp != (char *) 0 && *chp != '\0') do { 22 | count++; 23 | res = putc(*chp, stream); 24 | } while (*++chp != '\0' && res != EOF); 25 | 26 | if (res != EOF) res = count; 27 | return res; 28 | } 29 | 30 | /* 31 | * output the value of a precision to a file (no cr or whitespace) 32 | * 33 | * Returns: 34 | * The number of characters output or EOF if error 35 | */ 36 | int fputp(stream, p) 37 | FILE *stream; 38 | precision p; 39 | { 40 | int res; 41 | char *chp = ptoa(pparm(p)); 42 | 43 | res = fouts(stream, chp); 44 | deallocate(chp); 45 | pdestroy(p); 46 | return res; 47 | } 48 | 49 | /* 50 | * Output a precision to stdout with a newline (useful from debugger) 51 | */ 52 | int putp(p) 53 | precision p; 54 | { 55 | int res; 56 | char *chp = ptoa(pparm(p)); 57 | 58 | res = fouts(stdout, chp); 59 | res = putc('\n', stdout); 60 | deallocate(chp); 61 | pdestroy(p); 62 | return res; 63 | 64 | } 65 | 66 | /* 67 | * Output a justified precision 68 | * 69 | * Returns: The number of characters in the precision, or EOF if error 70 | */ 71 | int fprintp(stream, p, minWidth) 72 | FILE *stream; 73 | precision p; 74 | register int minWidth; 75 | { 76 | int res; 77 | char *chp = ptoa(pparm(p)); 78 | int len; 79 | 80 | len = strlen(chp); 81 | if (minWidth < 0) { /* left-justified */ 82 | res = fouts(stream, chp); 83 | while (minWidth++ < -len) { 84 | putc(' ', stream); 85 | } 86 | } else { 87 | while (minWidth-- > len) { /* right-justified */ 88 | putc(' ', stream); 89 | } 90 | res = fouts(stream, chp); 91 | } 92 | 93 | deallocate(chp); 94 | pdestroy(p); 95 | return res; 96 | } 97 | 98 | 99 | /* 100 | * Read in a precision type - same as atop but with io 101 | * 102 | * leading whitespace skipped 103 | * an optional leading '-' or '+' followed by digits '0'..'9' 104 | * leading 0's Ok 105 | * stops at first unrecognized character 106 | * 107 | * Returns: pUndef if EOF or invalid argument (NULL or nondigit as 1st digit) 108 | */ 109 | precision fgetp(stream) 110 | FILE *stream; 111 | { 112 | precision res = pUndef; 113 | precision clump = pUndef; 114 | int sign = 0; 115 | register int ch; 116 | register accumulator temp, x; 117 | register int j; 118 | 119 | ch = getc(stream); 120 | if (ch != EOF) { 121 | while (isspace(ch)) ch = getc(stream); /* skip whitespace */ 122 | if (ch == '-') { 123 | sign = 1; 124 | ch = getc(stream); 125 | } else if (ch == '+') { 126 | ch = getc(stream); 127 | } 128 | if (isdigit(ch)) { 129 | pset(&res, pzero); 130 | pset(&clump, utop(aDigit)); 131 | do { 132 | j = aDigitLog-1; 133 | temp = ch - '0'; 134 | do { 135 | if (!isdigit(ch = getc(stream))) goto atoplast; 136 | temp = temp * aBase + (ch - '0'); 137 | } while (--j > 0); 138 | pset(&res, padd(pmul(res, clump), utop(temp))); 139 | } while (isdigit(ch = getc(stream))); 140 | goto atopdone; 141 | atoplast: 142 | x = aBase; 143 | while (j++ < aDigitLog-1) { 144 | x *= aBase; 145 | } 146 | pset(&res, padd(pmul(res, utop(x)), utop(temp))); 147 | atopdone: 148 | if (ch != EOF) ungetc(ch, stream); 149 | if (sign) { 150 | pset(&res, pneg(res)); 151 | } 152 | } else { 153 | if (ch == EOF) { 154 | res = pUndef; 155 | } else { 156 | ungetc(ch, stream); 157 | } 158 | } 159 | } else { 160 | res = pUndef; 161 | } 162 | pdestroy(clump); 163 | if (res == pUndef) return res; 164 | return presult(res); 165 | } 166 | -------------------------------------------------------------------------------- /bench/cfrac/pmul.c: -------------------------------------------------------------------------------- 1 | #include "pdefs.h" 2 | #include "precision.h" 3 | #include 4 | 5 | #ifdef ASM_16BIT 6 | #include "asm16bit.h" 7 | #endif 8 | 9 | /* 10 | * Multiply u by v (assumes normalized) 11 | */ 12 | precision pmul(u, v) 13 | register precision v; /* register a5 on 68000 */ 14 | #ifdef ASM_16BIT 15 | register precision u; /* register a4 */ 16 | { 17 | #else 18 | precision u; 19 | { 20 | digitPtr vPtr; 21 | register digitPtr uPtr, wPtr, HiDigit; 22 | register accumulator temp; /* 0 <= temp < base * base */ /* d7 */ 23 | register digit vdigit; /* d6 */ 24 | #endif 25 | register digit hi; /* 0 <= hi < base */ /* d5 */ 26 | precision w; 27 | 28 | (void) pparm(u); 29 | (void) pparm(v); 30 | /* 31 | * Check for multiply by zero. Helps prevent wasted storage and -0 32 | */ 33 | if (peqz(u) || peqz(v)) { 34 | w = palloc(1); 35 | if (w == pUndef) return w; 36 | 37 | w->sign = false; 38 | w->value[0] = 0; 39 | } else { 40 | if (u->size < v->size) { /* u is biggest number (for inner loop speed) */ 41 | w = u; u = v; v = w; 42 | } 43 | 44 | w = palloc(u->size + v->size); 45 | if (w == pUndef) return w; 46 | 47 | w->sign = (u->sign != v->sign); 48 | 49 | #ifndef ASM_16BIT 50 | uPtr = u->value; 51 | vPtr = v->value; 52 | wPtr = w->value + u->size; /* this is correct! */ 53 | do { 54 | *--wPtr = 0; 55 | } while (wPtr > w->value); 56 | 57 | vPtr = v->value; 58 | HiDigit = u->value + u->size; 59 | do { 60 | uPtr = u->value; 61 | wPtr = w->value + (vPtr - v->value); 62 | hi = 0; 63 | vdigit = *vPtr; 64 | do { 65 | temp = uMul(vdigit, *uPtr++); /* 0 <= temp <= (base-1)^2 */ 66 | temp += *wPtr; /* 0 <= temp <= base(base-1) */ 67 | temp += hi; /* 0 <= temp < base * base */ 68 | hi = divBase(temp); /* 0 <= hi < base */ 69 | *wPtr++ = modBase(temp); 70 | } while (uPtr < HiDigit); 71 | *wPtr++ = hi; 72 | } while (++vPtr < v->value + v->size); 73 | #else 74 | hi = memmulw(w->value, u->value, u->size, v->value, v->size); 75 | #endif 76 | if (hi == 0) { 77 | --(w->size); /* normalize */ 78 | } 79 | } 80 | 81 | pdestroy(u); 82 | pdestroy(v); 83 | return presult(w); 84 | } 85 | -------------------------------------------------------------------------------- /bench/cfrac/pneg.c: -------------------------------------------------------------------------------- 1 | #include "pdefs.h" /* private include file */ 2 | #include "precision.h" /* public include file for forward refs */ 3 | #include 4 | 5 | /* 6 | * negation 7 | */ 8 | precision pneg(u) 9 | register precision u; 10 | { 11 | precision w; 12 | 13 | (void) pparm(u); 14 | w = palloc(u->size); 15 | if (w == pUndef) return w; 16 | 17 | w->sign = u->sign; 18 | if (pnez(u)) { /* don't create a negative 0 */ 19 | w->sign = !w->sign; 20 | } 21 | (void) memcpy(w->value, u->value, u->size * sizeof(digit)); 22 | 23 | pdestroy(u); 24 | return presult(w); 25 | } 26 | -------------------------------------------------------------------------------- /bench/cfrac/podd.c: -------------------------------------------------------------------------------- 1 | #include "pdefs.h" 2 | #include "precision.h" 3 | 4 | /* 5 | * Returns non-zero if u is odd 6 | */ 7 | int podd(u) 8 | precision u; 9 | { 10 | register int res; 11 | 12 | (void) pparm(u); 13 | res = (*(u->value) & 1); 14 | pdestroy(u); 15 | return res; 16 | } 17 | -------------------------------------------------------------------------------- /bench/cfrac/ppowmod.c: -------------------------------------------------------------------------------- 1 | #include "precision.h" 2 | 3 | /* 4 | * Raise to precision power mod m 5 | */ 6 | precision ppowmod(u, v, m) 7 | precision u, v, m; 8 | { 9 | precision j = pUndef, i = pUndef, n = pUndef; 10 | 11 | (void) pparm(m); 12 | pset(&i, pparm(u)); 13 | pset(&n, pparm(v)); 14 | pset(&j, pone); 15 | 16 | do { 17 | if (podd(n)) { 18 | pset(&j, pmod(pmul(i, j), m)); 19 | } 20 | pset(&n, phalf(n)); 21 | if (peqz(n)) break; 22 | pset(&i, pmod(pmul(i, i), m)); 23 | } while (1); 24 | 25 | pdestroy(i); pdestroy(n); 26 | pdestroy(u); pdestroy(v); pdestroy(m); 27 | return presult(j); 28 | } 29 | -------------------------------------------------------------------------------- /bench/cfrac/primes.h: -------------------------------------------------------------------------------- 1 | extern unsigned int primesize; 2 | extern unsigned short primes[]; 3 | -------------------------------------------------------------------------------- /bench/cfrac/psqrt.c: -------------------------------------------------------------------------------- 1 | #include "precision.h" 2 | 3 | /* 4 | * Square root 5 | */ 6 | precision psqrt(y) 7 | precision y; 8 | { 9 | int i; 10 | precision x = pUndef, lastx = pUndef; 11 | 12 | i = pcmpz(pparm(y)); 13 | if (i == 0) { /* if y == 0 */ 14 | pset(&lastx, pzero); 15 | } else if (i < 0) { /* if y negative */ 16 | pset(&x, errorp(PDOMAIN, "psqrt", "negative argument")); 17 | } else { 18 | pset(&x, y); 19 | do { 20 | pset(&lastx, x); 21 | pset(&x, phalf(padd(x, pdiv(y, x)))); 22 | } while (plt(x, lastx)); 23 | } 24 | 25 | pdestroy(x); 26 | 27 | pdestroy(y); 28 | return presult(lastx); 29 | } 30 | -------------------------------------------------------------------------------- /bench/cfrac/psub.c: -------------------------------------------------------------------------------- 1 | #include "pdefs.h" 2 | #include "precision.h" 3 | #include 4 | 5 | #ifdef ASM_16BIT 6 | #include "asm16bit.h" 7 | #endif 8 | 9 | /* 10 | * Subtract u from v (assumes normalized) 11 | */ 12 | precision psub(u, v) 13 | #ifndef ASM_16BIT 14 | precision u, v; 15 | { 16 | register digitPtr HiDigit, wPtr, uPtr; 17 | register digitPtr vPtr; 18 | #else 19 | register precision u, v; 20 | { 21 | register digitPtr wPtr, uPtr; 22 | #endif 23 | precision w; 24 | register accumulator temp; 25 | #ifndef ASM_16BIT 26 | register digit noborrow; 27 | #endif 28 | register int i; 29 | 30 | (void) pparm(u); 31 | (void) pparm(v); 32 | if (u->sign != v->sign) { /* Are we actually adding? */ 33 | w = pUndef; 34 | v->sign = !v->sign; /* may generate -0 */ 35 | pset(&w, padd(u, v)); 36 | v->sign = !v->sign; 37 | } else { 38 | i = pcmp(u, v); 39 | if (u->sign) i = -i; /* compare magnitudes only */ 40 | 41 | if (i < 0) { 42 | w = u; u = v; v = w; /* make u the largest */ 43 | } 44 | 45 | w = palloc(u->size); /* may produce much wasted storage */ 46 | if (w == pUndef) return w; 47 | 48 | if (i < 0) w->sign = !u->sign; else w->sign = u->sign; 49 | 50 | uPtr = u->value; 51 | wPtr = w->value; 52 | #ifndef ASM_16BIT 53 | vPtr = v->value; 54 | noborrow = 1; 55 | 56 | HiDigit = v->value + v->size; /* digits in both args */ 57 | do { 58 | temp = (BASE-1) - *vPtr++; /* 0 <= temp < base */ 59 | temp += *uPtr++; /* 0 <= temp < 2*base-1 */ 60 | temp += noborrow; /* 0 <= temp < 2*base */ 61 | noborrow = divBase(temp); /* 0 <= noborrow <= 1 */ 62 | *wPtr++ = modBase(temp); 63 | } while (vPtr < HiDigit); 64 | 65 | HiDigit = u->value + u->size; /* propagate borrow */ 66 | while (uPtr < HiDigit) { 67 | temp = (BASE-1) + *uPtr++; 68 | temp += noborrow; /* 0 <= temp < 2 * base */ 69 | noborrow = divBase(temp); /* 0 <= noborrow <= 1 */ 70 | *wPtr++ = modBase(temp); 71 | } /* noborrow = 1 */ 72 | #else 73 | i = v->size; 74 | temp = u->size - i; 75 | if (temp > 0) { 76 | memcpy(wPtr + i, uPtr + i, temp * sizeof(digit)); 77 | } 78 | if (memsubw(wPtr, uPtr, v->value, i)) { /* trashes uPtr */ 79 | memdecw(wPtr + i, temp); 80 | } 81 | wPtr += w->size; 82 | #endif 83 | do { /* normalize */ 84 | if (*--wPtr != 0) break; 85 | } while (wPtr > w->value); 86 | w->size = (wPtr - w->value) + 1; 87 | } 88 | 89 | pdestroy(u); 90 | pdestroy(v); 91 | return presult(w); 92 | } 93 | -------------------------------------------------------------------------------- /bench/cfrac/ptoa.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "pdefs.h" 3 | #include "pcvt.h" 4 | #include "precision.h" 5 | 6 | /* 7 | * Return the character string decimal value of a Precision 8 | */ 9 | #if (BASE > 10) 10 | #define CONDIGIT(d) ((d) < 10 ? (d) + '0' : (d) + 'a'-10) 11 | #else 12 | #define CONDIGIT(d) ((d) + '0') 13 | #endif 14 | 15 | char *ptoa(u) 16 | precision u; 17 | { 18 | register accumulator temp; 19 | register char *dPtr; 20 | char *d; 21 | int i = 0; 22 | unsigned int consize; 23 | precision r, v, pbase; 24 | register int j; 25 | 26 | (void) pparm(u); 27 | r = pUndef; 28 | v = pUndef; 29 | pbase = pUndef; 30 | 31 | consize = (unsigned int) u->size; 32 | if (consize > MAXINT / aDigits) { 33 | consize = (consize / pDigits) * aDigits; 34 | } else { 35 | consize = (consize * aDigits) / pDigits; 36 | } 37 | 38 | consize += aDigitLog + 2; /* leading 0's, sign, & '\0' */ 39 | d = (char *) allocate((unsigned int) consize); 40 | if (d == (char *) 0) return d; 41 | 42 | pset(&v, pabs(u)); 43 | pset(&pbase, utop(aDigit)); 44 | 45 | dPtr = d + consize; 46 | *--dPtr = '\0'; /* null terminate string */ 47 | i = u->sign; /* save sign */ 48 | do { 49 | pdivmod(v, pbase, &v, &r); 50 | temp = ptou(r); /* Assumes unsigned and accumulator same! */ 51 | j = aDigitLog; 52 | do { 53 | *--dPtr = CONDIGIT(temp % aBase); /* remainder */ 54 | temp = temp / aBase; 55 | } while (--j > 0); 56 | } while (pnez(v)); 57 | 58 | while (*dPtr == '0') dPtr++; /* toss leading zero's */ 59 | if (*dPtr == '\0') --dPtr; /* but don't waste zero! */ 60 | if (i) *--dPtr = '-'; 61 | if (dPtr > d) { /* ASSUME copied from lower to higher! */ 62 | (void) memmove(d, dPtr, consize - (dPtr - d)); 63 | } 64 | 65 | pdestroy(pbase); 66 | pdestroy(v); 67 | pdestroy(r); 68 | 69 | pdestroy(u); 70 | return d; 71 | } 72 | -------------------------------------------------------------------------------- /bench/cfrac/ptob.c: -------------------------------------------------------------------------------- 1 | #include "pdefs.h" 2 | #include "precision.h" 3 | 4 | /* 5 | * Convert a precision to a given base (the sign is ignored) 6 | * 7 | * Input: 8 | * u - the number to convert 9 | * dest - Where to put the ASCII representation radix 10 | * WARNING! Not '\0' terminated, this is an exact image 11 | * size - the number of digits of dest. 12 | * (alphabet[0] padded on left) 13 | * if size is too small, truncation occurs on left 14 | * alphabet - A mapping from each radix digit to it's character digit 15 | * (note: '\0' is perfectly OK as a digit) 16 | * radix - The size of the alphabet, and the conversion radix 17 | * 2 <= radix < 256. 18 | * 19 | * Returns: 20 | * -1 if invalid radix 21 | * 0 if successful 22 | * >0 the number didn't fit 23 | */ 24 | int ptob(u, dest, size, alphabet, radix) 25 | precision u; /* the number to convert */ 26 | char *dest; /* where to place the converted ascii */ 27 | unsigned int size; /* the size of the result in characters */ 28 | char *alphabet; /* the character set forming the radix */ 29 | register unsigned int radix; /* the size of the character set */ 30 | { 31 | register accumulator temp; 32 | register unsigned int i; 33 | register char *chp; 34 | unsigned int lgclump; 35 | int res = 0; 36 | 37 | precision r = pUndef, v = pUndef, pbase = pUndef; 38 | 39 | if (radix > 256 || radix < 2) return -1; 40 | if (size == 0) return 1; 41 | 42 | (void) pparm(u); 43 | temp = radix; 44 | i = 1; 45 | while (temp * radix > temp) { 46 | temp *= radix; 47 | i++; 48 | } 49 | lgclump = i; 50 | 51 | pset(&v, pabs(u)); 52 | pset(&pbase, utop(temp)); /* assumes accumulator and int are the same! */ 53 | 54 | chp = dest + size; 55 | do { 56 | pdivmod(v, pbase, &v, &r); 57 | temp = ptou(r); /* assumes accumulator and int are the same! */ 58 | i = lgclump; 59 | do { 60 | *--chp = alphabet[temp % radix]; /* remainder */ 61 | temp = temp / radix; 62 | if (chp == dest) goto bail; 63 | } while (--i > 0); 64 | } while pnez(v); 65 | 66 | if (chp > dest) do { 67 | *--chp = *alphabet; 68 | } while (chp > dest); 69 | 70 | bail: 71 | if (pnez(v) || temp != 0) { /* check for overflow */ 72 | res = 1; 73 | } 74 | 75 | pdestroy(pbase); 76 | pdestroy(v); 77 | pdestroy(r); 78 | 79 | pdestroy(u); 80 | return res; 81 | } 82 | -------------------------------------------------------------------------------- /bench/cfrac/ptou.c: -------------------------------------------------------------------------------- 1 | #include "pdefs.h" 2 | #include "pcvt.h" 3 | #include "precision.h" 4 | 5 | /* 6 | * Precision to unsigned 7 | */ 8 | unsigned int ptou(u) 9 | precision u; 10 | { 11 | register digitPtr uPtr; 12 | register accumulator temp; 13 | 14 | (void) pparm(u); 15 | if (u->sign) { 16 | temp = (unsigned long) errorp(PDOMAIN, "ptou", "negative argument"); 17 | } else { 18 | uPtr = u->value + u->size; 19 | temp = 0; 20 | do { 21 | if (temp > divBase(MAXUNSIGNED - *--uPtr)) { 22 | temp = (unsigned long) errorp(POVERFLOW, "ptou", "overflow"); 23 | break; 24 | } 25 | temp = mulBase(temp); 26 | temp += *uPtr; 27 | } while (uPtr > u->value); 28 | } 29 | pdestroy(u); 30 | return (unsigned int) temp; 31 | } 32 | -------------------------------------------------------------------------------- /bench/cfrac/seive.h: -------------------------------------------------------------------------------- 1 | extern unsigned long seivesize; 2 | 3 | extern unsigned char seive[]; 4 | -------------------------------------------------------------------------------- /bench/cfrac/utop.c: -------------------------------------------------------------------------------- 1 | #include "pdefs.h" 2 | #include "pcvt.h" 3 | #include "precision.h" 4 | 5 | /* 6 | * Unsigned to Precision 7 | */ 8 | precision utop(i) 9 | register unsigned int i; 10 | { 11 | register digitPtr uPtr; 12 | register precision u = palloc(INTSIZE); 13 | 14 | if (u == pUndef) return pUndef; 15 | 16 | u->sign = false; 17 | uPtr = u->value; 18 | do { 19 | *uPtr++ = modBase(i); 20 | i = divBase(i); 21 | } while (i != 0); 22 | 23 | u->size = (uPtr - u->value); 24 | return presult(u); 25 | } 26 | -------------------------------------------------------------------------------- /bench/espresso/README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | Oct Tools Distribution 4.0 3 | 4 | Copyright (c) 1988, 1989, 1990, Regents of the University of California. 5 | All rights reserved. 6 | 7 | Use and copying of this software and preparation of derivative works 8 | based upon this software are permitted. However, any distribution of 9 | this software or derivative works must include the above copyright 10 | notice. 11 | 12 | This software is made available AS IS, and neither the Electronics 13 | Research Laboratory or the University of California make any 14 | warranty about the software, its performance or its conformity to 15 | any specification. 16 | 17 | Suggestions, comments, or improvements are welcome and should be 18 | addressed to: 19 | 20 | octtools@eros.berkeley.edu 21 | ..!ucbvax!eros!octtools 22 | ``` 23 | -------------------------------------------------------------------------------- /bench/espresso/ansi.h: -------------------------------------------------------------------------------- 1 | #ifndef ANSI_H 2 | #define ANSI_H 3 | 4 | /* 5 | * ANSI Compiler Support 6 | * 7 | * David Harrison 8 | * University of California, Berkeley 9 | * 1988 10 | * 11 | * ANSI compatible compilers are supposed to define the preprocessor 12 | * directive __STDC__. Based on this directive, this file defines 13 | * certain ANSI specific macros. 14 | * 15 | * ARGS: 16 | * Used in function prototypes. Example: 17 | * extern int foo 18 | * ARGS((char *blah, double threshold)); 19 | */ 20 | 21 | /* Function prototypes */ 22 | #if defined(__STDC__) || defined(__cplusplus) 23 | #define ARGS(args) args 24 | #else 25 | #define ARGS(args) () 26 | #endif 27 | 28 | #if defined(__cplusplus) 29 | #define NULLARGS (void) 30 | #else 31 | #define NULLARGS () 32 | #endif 33 | 34 | #ifdef __cplusplus 35 | #define EXTERN extern "C" 36 | #else 37 | #define EXTERN extern 38 | #endif 39 | 40 | #if defined(__cplusplus) || defined(__STDC__) 41 | #define HAS_STDARG 42 | #endif 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /bench/espresso/copyright.h: -------------------------------------------------------------------------------- 1 | #ifndef OCTTOOLS_COPYRIGHT_H 2 | #define OCTTOOLS_COPYRIGHT_H 3 | /* 4 | * Oct Tools Distribution 4.0 5 | * 6 | * Copyright (c) 1988, 1989, 1990, Regents of the University of California. 7 | * All rights reserved. 8 | * 9 | * Use and copying of this software and preparation of derivative works 10 | * based upon this software are permitted. However, any distribution of 11 | * this software or derivative works must include the above copyright 12 | * notice. 13 | * 14 | * This software is made available AS IS, and neither the Electronics 15 | * Research Laboratory or the University of California make any 16 | * warranty about the software, its performance or its conformity to 17 | * any specification. 18 | * 19 | * Suggestions, comments, or improvements are welcome and should be 20 | * addressed to: 21 | * 22 | * octtools@eros.berkeley.edu 23 | * ..!ucbvax!eros!octtools 24 | */ 25 | 26 | #if !defined(lint) && !defined(SABER) 27 | static char octtools_copyright[] = "Copyright (c) 1988, 1989, Regents of the University of California. All rights reserved."; 28 | #endif 29 | #endif 30 | -------------------------------------------------------------------------------- /bench/espresso/cvrmisc.c: -------------------------------------------------------------------------------- 1 | #include "espresso.h" 2 | 3 | 4 | /* cost -- compute the cost of a cover */ 5 | void cover_cost(F, cost) 6 | IN pcover F; 7 | INOUT pcost cost; 8 | { 9 | register pcube p, last; 10 | pcube *T; 11 | int var; 12 | 13 | /* use the routine used by cofactor to decide splitting variables */ 14 | massive_count(T = cube1list(F)); 15 | free_cubelist(T); 16 | 17 | cost->cubes = F->count; 18 | cost->total = cost->in = cost->out = cost->mv = cost->primes = 0; 19 | 20 | /* Count transistors (zeros) for each binary variable (inputs) */ 21 | for(var = 0; var < cube.num_binary_vars; var++) 22 | cost->in += cdata.var_zeros[var]; 23 | 24 | /* Count transistors for each mv variable based on sparse/dense */ 25 | for(var = cube.num_binary_vars; var < cube.num_vars - 1; var++) 26 | if (cube.sparse[var]) 27 | cost->mv += F->count * cube.part_size[var] - cdata.var_zeros[var]; 28 | else 29 | cost->mv += cdata.var_zeros[var]; 30 | 31 | /* Count the transistors (ones) for the output variable */ 32 | if (cube.num_binary_vars != cube.num_vars) { 33 | var = cube.num_vars - 1; 34 | cost->out = F->count * cube.part_size[var] - cdata.var_zeros[var]; 35 | } 36 | 37 | /* Count the number of nonprime cubes */ 38 | /* 39 | THIS IS A BUG! p is never set! EDB... 40 | 41 | foreach_set(F, last, p) 42 | cost->primes += TESTP(p, PRIME) != 0; 43 | */ 44 | 45 | /* Count the total number of literals */ 46 | cost->total = cost->in + cost->out + cost->mv; 47 | } 48 | 49 | 50 | /* fmt_cost -- return a string which reports the "cost" of a cover */ 51 | char *fmt_cost(cost) 52 | IN pcost cost; 53 | { 54 | static char s[200]; 55 | 56 | if (cube.num_binary_vars == cube.num_vars - 1) { 57 | int v1 = cost->primes + 1; 58 | sprintf (s, "%d", v1); 59 | (void) sprintf(s, "c=%d(%d) in=%d out=%d tot=%d", 60 | cost->cubes, cost->cubes - cost->primes, cost->in, 61 | cost->out, cost->total); 62 | } else { 63 | (void) sprintf(s, "c=%d(%d) in=%d mv=%d out=%d", 64 | cost->cubes, cost->cubes - cost->primes, cost->in, 65 | cost->mv, cost->out); 66 | } 67 | return s; 68 | } 69 | 70 | 71 | char *print_cost(F) 72 | IN pcover F; 73 | { 74 | cost_t cost; 75 | cover_cost(F, &cost); 76 | return fmt_cost(&cost); 77 | } 78 | 79 | 80 | /* copy_cost -- copy a cost function from s to d */ 81 | void copy_cost(s, d) 82 | pcost s, d; 83 | { 84 | d->cubes = s->cubes; 85 | d->in = s->in; 86 | d->out = s->out; 87 | d->mv = s->mv; 88 | d->total = s->total; 89 | d->primes = s->primes; 90 | } 91 | 92 | 93 | /* size_stamp -- print single line giving the size of a cover */ 94 | void size_stamp(T, name) 95 | IN pcover T; 96 | IN char *name; 97 | { 98 | printf("# %s\tCost is %s\n", name, print_cost(T)); 99 | (void) fflush(stdout); 100 | } 101 | 102 | 103 | /* print_trace -- print a line reporting size and time after a function */ 104 | void print_trace(T, name, time) 105 | pcover T; 106 | char *name; 107 | long time; 108 | { 109 | printf("# %s\tTime was %s, cost is %s\n", 110 | name, print_time(time), print_cost(T)); 111 | (void) fflush(stdout); 112 | } 113 | 114 | 115 | /* totals -- add time spent in the function into the totals */ 116 | void totals(time, i, T, cost) 117 | long time; 118 | int i; 119 | pcover T; 120 | pcost cost; 121 | { 122 | time = ptime() - time; 123 | total_time[i] += time; 124 | total_calls[i]++; 125 | cover_cost(T, cost); 126 | if (trace) { 127 | printf("# %s\tTime was %s, cost is %s\n", 128 | total_name[i], print_time(time), fmt_cost(cost)); 129 | (void) fflush(stdout); 130 | } 131 | } 132 | 133 | 134 | /* fatal -- report fatal error message and take a dive */ 135 | void fatal(s) 136 | char *s; 137 | { 138 | fprintf(stderr, "espresso: %s\n", s); 139 | exit(1); 140 | } 141 | -------------------------------------------------------------------------------- /bench/espresso/dominate.c: -------------------------------------------------------------------------------- 1 | #include "espresso.h" 2 | #include "mincov_int.h" 3 | 4 | 5 | int 6 | sm_row_dominance(A) 7 | sm_matrix *A; 8 | { 9 | register sm_row *prow, *prow1; 10 | register sm_col *pcol, *least_col; 11 | register sm_element *p, *pnext; 12 | int rowcnt; 13 | 14 | rowcnt = A->nrows; 15 | 16 | /* Check each row against all other rows */ 17 | for(prow = A->first_row; prow != 0; prow = prow->next_row) { 18 | 19 | /* Among all columns with a 1 in this row, choose smallest */ 20 | least_col = sm_get_col(A, prow->first_col->col_num); 21 | for(p = prow->first_col->next_col; p != 0; p = p->next_col) { 22 | pcol = sm_get_col(A, p->col_num); 23 | if (pcol->length < least_col->length) { 24 | least_col = pcol; 25 | } 26 | } 27 | 28 | /* Only check for containment against rows in this column */ 29 | for(p = least_col->first_row; p != 0; p = pnext) { 30 | pnext = p->next_row; 31 | 32 | prow1 = sm_get_row(A, p->row_num); 33 | if ((prow1->length > prow->length) || 34 | (prow1->length == prow->length && 35 | prow1->row_num > prow->row_num)) { 36 | if (sm_row_contains(prow, prow1)) { 37 | sm_delrow(A, prow1->row_num); 38 | } 39 | } 40 | } 41 | } 42 | 43 | return rowcnt - A->nrows; 44 | } 45 | 46 | int 47 | sm_col_dominance(A, weight) 48 | sm_matrix *A; 49 | int *weight; 50 | { 51 | register sm_row *prow; 52 | register sm_col *pcol, *pcol1; 53 | register sm_element *p; 54 | sm_row *least_row; 55 | sm_col *next_col; 56 | int colcnt; 57 | 58 | colcnt = A->ncols; 59 | 60 | /* Check each column against all other columns */ 61 | for(pcol = A->first_col; pcol != 0; pcol = next_col) { 62 | next_col = pcol->next_col; 63 | 64 | /* Check all rows to find the one with fewest elements */ 65 | least_row = sm_get_row(A, pcol->first_row->row_num); 66 | for(p = pcol->first_row->next_row; p != 0; p = p->next_row) { 67 | prow = sm_get_row(A, p->row_num); 68 | if (prow->length < least_row->length) { 69 | least_row = prow; 70 | } 71 | } 72 | 73 | /* Only check for containment against columns in this row */ 74 | for(p = least_row->first_col; p != 0; p = p->next_col) { 75 | pcol1 = sm_get_col(A, p->col_num); 76 | if (weight != 0 && weight[pcol1->col_num] > weight[pcol->col_num]) 77 | continue; 78 | if ((pcol1->length > pcol->length) || 79 | (pcol1->length == pcol->length && 80 | pcol1->col_num > pcol->col_num)) { 81 | if (sm_col_contains(pcol, pcol1)) { 82 | sm_delcol(A, pcol->col_num); 83 | break; 84 | } 85 | } 86 | } 87 | } 88 | 89 | return colcnt - A->ncols; 90 | } 91 | -------------------------------------------------------------------------------- /bench/espresso/equiv.c: -------------------------------------------------------------------------------- 1 | #include "espresso.h" 2 | 3 | 4 | find_equiv_outputs(PLA) 5 | pPLA PLA; 6 | { 7 | int i, j, ipart, jpart, some_equiv; 8 | pcover *R, *F; 9 | 10 | some_equiv = FALSE; 11 | 12 | makeup_labels(PLA); 13 | 14 | F = ALLOC(pcover, cube.part_size[cube.output]); 15 | R = ALLOC(pcover, cube.part_size[cube.output]); 16 | 17 | for(i = 0; i < cube.part_size[cube.output]; i++) { 18 | ipart = cube.first_part[cube.output] + i; 19 | R[i] = cof_output(PLA->R, ipart); 20 | F[i] = complement(cube1list(R[i])); 21 | } 22 | 23 | for(i = 0; i < cube.part_size[cube.output]-1; i++) { 24 | for(j = i+1; j < cube.part_size[cube.output]; j++) { 25 | ipart = cube.first_part[cube.output] + i; 26 | jpart = cube.first_part[cube.output] + j; 27 | 28 | if (check_equiv(F[i], F[j])) { 29 | printf("# Outputs %d and %d (%s and %s) are equivalent\n", 30 | i, j, PLA->label[ipart], PLA->label[jpart]); 31 | some_equiv = TRUE; 32 | } else if (check_equiv(F[i], R[j])) { 33 | printf("# Outputs %d and NOT %d (%s and %s) are equivalent\n", 34 | i, j, PLA->label[ipart], PLA->label[jpart]); 35 | some_equiv = TRUE; 36 | } else if (check_equiv(R[i], F[j])) { 37 | printf("# Outputs NOT %d and %d (%s and %s) are equivalent\n", 38 | i, j, PLA->label[ipart], PLA->label[jpart]); 39 | some_equiv = TRUE; 40 | } else if (check_equiv(R[i], R[j])) { 41 | printf("# Outputs NOT %d and NOT %d (%s and %s) are equivalent\n", 42 | i, j, PLA->label[ipart], PLA->label[jpart]); 43 | some_equiv = TRUE; 44 | } 45 | } 46 | } 47 | 48 | if (! some_equiv) { 49 | printf("# No outputs are equivalent\n"); 50 | } 51 | 52 | for(i = 0; i < cube.part_size[cube.output]; i++) { 53 | free_cover(F[i]); 54 | free_cover(R[i]); 55 | } 56 | FREE(F); 57 | FREE(R); 58 | } 59 | 60 | 61 | 62 | int check_equiv(f1, f2) 63 | pcover f1, f2; 64 | { 65 | register pcube *f1list, *f2list; 66 | register pcube p, last; 67 | 68 | f1list = cube1list(f1); 69 | foreach_set(f2, last, p) { 70 | if (! cube_is_covered(f1list, p)) { 71 | return FALSE; 72 | } 73 | } 74 | free_cubelist(f1list); 75 | 76 | f2list = cube1list(f2); 77 | foreach_set(f1, last, p) { 78 | if (! cube_is_covered(f2list, p)) { 79 | return FALSE; 80 | } 81 | } 82 | free_cubelist(f2list); 83 | 84 | return TRUE; 85 | } 86 | -------------------------------------------------------------------------------- /bench/espresso/espresso.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Module: espresso.c 3 | * Purpose: The main espresso algorithm 4 | * 5 | * Returns a minimized version of the ON-set of a function 6 | * 7 | * The following global variables affect the operation of Espresso: 8 | * 9 | * MISCELLANEOUS: 10 | * trace 11 | * print trace information as the minimization progresses 12 | * 13 | * remove_essential 14 | * remove essential primes 15 | * 16 | * single_expand 17 | * if true, stop after first expand/irredundant 18 | * 19 | * LAST_GASP or SUPER_GASP strategy: 20 | * use_super_gasp 21 | * uses the super_gasp strategy rather than last_gasp 22 | * 23 | * SETUP strategy: 24 | * recompute_onset 25 | * recompute onset using the complement before starting 26 | * 27 | * unwrap_onset 28 | * unwrap the function output part before first expand 29 | * 30 | * MAKE_SPARSE strategy: 31 | * force_irredundant 32 | * iterates make_sparse to force a minimal solution (used 33 | * indirectly by make_sparse) 34 | * 35 | * skip_make_sparse 36 | * skip the make_sparse step (used by opo only) 37 | */ 38 | 39 | #include "espresso.h" 40 | 41 | pcover espresso(F, D1, R) 42 | pcover F, D1, R; 43 | { 44 | pcover E, D, Fsave; 45 | pset last, p; 46 | cost_t cost, best_cost; 47 | 48 | begin: 49 | Fsave = sf_save(F); /* save original function */ 50 | D = sf_save(D1); /* make a scratch copy of D */ 51 | 52 | /* Setup has always been a problem */ 53 | if (recompute_onset) { 54 | EXEC(E = simplify(cube1list(F)), "SIMPLIFY ", E); 55 | free_cover(F); 56 | F = E; 57 | } 58 | cover_cost(F, &cost); 59 | if (unwrap_onset && (cube.part_size[cube.num_vars - 1] > 1) 60 | && (cost.out != cost.cubes*cube.part_size[cube.num_vars-1]) 61 | && (cost.out < 5000)) 62 | EXEC(F = sf_contain(unravel(F, cube.num_vars - 1)), "SETUP ", F); 63 | 64 | /* Initial expand and irredundant */ 65 | foreach_set(F, last, p) { 66 | RESET(p, PRIME); 67 | } 68 | EXECUTE(F = expand(F, R, FALSE), EXPAND_TIME, F, cost); 69 | EXECUTE(F = irredundant(F, D), IRRED_TIME, F, cost); 70 | 71 | if (! single_expand) { 72 | if (remove_essential) { 73 | EXECUTE(E = essential(&F, &D), ESSEN_TIME, E, cost); 74 | } else { 75 | E = new_cover(0); 76 | } 77 | 78 | cover_cost(F, &cost); 79 | do { 80 | 81 | /* Repeat inner loop until solution becomes "stable" */ 82 | do { 83 | copy_cost(&cost, &best_cost); 84 | EXECUTE(F = reduce(F, D), REDUCE_TIME, F, cost); 85 | EXECUTE(F = expand(F, R, FALSE), EXPAND_TIME, F, cost); 86 | EXECUTE(F = irredundant(F, D), IRRED_TIME, F, cost); 87 | } while (cost.cubes < best_cost.cubes); 88 | 89 | /* Perturb solution to see if we can continue to iterate */ 90 | copy_cost(&cost, &best_cost); 91 | if (use_super_gasp) { 92 | F = super_gasp(F, D, R, &cost); 93 | if (cost.cubes >= best_cost.cubes) 94 | break; 95 | } else { 96 | F = last_gasp(F, D, R, &cost); 97 | } 98 | 99 | } while (cost.cubes < best_cost.cubes || 100 | (cost.cubes == best_cost.cubes && cost.total < best_cost.total)); 101 | 102 | /* Append the essential cubes to F */ 103 | F = sf_append(F, E); /* disposes of E */ 104 | if (trace) size_stamp(F, "ADJUST "); 105 | } 106 | 107 | /* Free the D which we used */ 108 | free_cover(D); 109 | 110 | /* Attempt to make the PLA matrix sparse */ 111 | if (! skip_make_sparse) { 112 | F = make_sparse(F, D1, R); 113 | } 114 | 115 | /* 116 | * Check to make sure function is actually smaller !! 117 | * This can only happen because of the initial unravel. If we fail, 118 | * then run the whole thing again without the unravel. 119 | */ 120 | if (Fsave->count < F->count) { 121 | free_cover(F); 122 | F = Fsave; 123 | unwrap_onset = FALSE; 124 | goto begin; 125 | } else { 126 | free_cover(Fsave); 127 | } 128 | 129 | return F; 130 | } 131 | -------------------------------------------------------------------------------- /bench/espresso/exact.c: -------------------------------------------------------------------------------- 1 | #include "espresso.h" 2 | #include 3 | 4 | static void dump_irredundant(); 5 | static pcover do_minimize(); 6 | 7 | 8 | /* 9 | * minimize_exact -- main entry point for exact minimization 10 | * 11 | * Global flags which affect this routine are: 12 | * 13 | * debug 14 | * skip_make_sparse 15 | */ 16 | 17 | pcover 18 | minimize_exact(F, D, R, exact_cover) 19 | pcover F, D, R; 20 | int exact_cover; 21 | { 22 | return do_minimize(F, D, R, exact_cover, /*weighted*/ 0); 23 | } 24 | 25 | 26 | pcover 27 | minimize_exact_literals(F, D, R, exact_cover) 28 | pcover F, D, R; 29 | int exact_cover; 30 | { 31 | return do_minimize(F, D, R, exact_cover, /*weighted*/ 1); 32 | } 33 | 34 | 35 | 36 | static pcover 37 | do_minimize(F, D, R, exact_cover, weighted) 38 | pcover F, D, R; 39 | int exact_cover; 40 | int weighted; 41 | { 42 | pcover newF, E, Rt, Rp; 43 | pset p, last; 44 | int heur, level, *weights; 45 | sm_matrix *table; 46 | sm_row *cover; 47 | sm_element *pe; 48 | int debug_save = debug; 49 | 50 | if (debug & EXACT) { 51 | debug |= (IRRED | MINCOV); 52 | } 53 | #if defined(sun) || defined(bsd4_2) /* hack ... */ 54 | if (debug & MINCOV) { 55 | // setlinebuf(stdout); 56 | } 57 | #endif 58 | level = (debug & MINCOV) ? 4 : 0; 59 | heur = ! exact_cover; 60 | 61 | /* Generate all prime implicants */ 62 | EXEC(F = primes_consensus(cube2list(F, D)), "PRIMES ", F); 63 | 64 | /* Setup the prime implicant table */ 65 | EXEC(irred_split_cover(F, D, &E, &Rt, &Rp), "ESSENTIALS ", E); 66 | EXEC(table = irred_derive_table(D, E, Rp), "PI-TABLE ", Rp); 67 | 68 | /* Solve either a weighted or nonweighted covering problem */ 69 | if (weighted) { 70 | /* correct only for all 2-valued variables */ 71 | weights = ALLOC(int, F->count); 72 | foreach_set(Rp, last, p) { 73 | weights[SIZE(p)] = cube.size - set_ord(p); 74 | } 75 | } else { 76 | weights = NIL(int); 77 | } 78 | EXEC(cover=sm_minimum_cover(table,weights,heur,level), "MINCOV ", F); 79 | if (weights != 0) { 80 | FREE(weights); 81 | } 82 | 83 | if (debug & EXACT) { 84 | dump_irredundant(E, Rt, Rp, table); 85 | } 86 | 87 | /* Form the result cover */ 88 | newF = new_cover(100); 89 | foreach_set(E, last, p) { 90 | newF = sf_addset(newF, p); 91 | } 92 | sm_foreach_row_element(cover, pe) { 93 | newF = sf_addset(newF, GETSET(F, pe->col_num)); 94 | } 95 | 96 | free_cover(E); 97 | free_cover(Rt); 98 | free_cover(Rp); 99 | sm_free(table); 100 | sm_row_free(cover); 101 | free_cover(F); 102 | 103 | /* Attempt to make the results more sparse */ 104 | debug &= ~ (IRRED | SHARP | MINCOV); 105 | if (! skip_make_sparse && R != 0) { 106 | newF = make_sparse(newF, D, R); 107 | } 108 | 109 | debug = debug_save; 110 | return newF; 111 | } 112 | 113 | static void 114 | dump_irredundant(E, Rt, Rp, table) 115 | pcover E, Rt, Rp; 116 | sm_matrix *table; 117 | { 118 | FILE *fp_pi_table, *fp_primes; 119 | pPLA PLA; 120 | pset last, p; 121 | char *file; 122 | 123 | if (filename == 0 || strcmp(filename, "(stdin)") == 0) { 124 | fp_pi_table = fp_primes = stdout; 125 | } else { 126 | file = ALLOC(char, strlen(filename)+20); 127 | (void) sprintf(file, "%s.primes", filename); 128 | if ((fp_primes = fopen(file, "w")) == NULL) { 129 | fprintf(stderr, "espresso: Unable to open %s\n", file); 130 | fp_primes = stdout; 131 | } 132 | (void) sprintf(file, "%s.pi", filename); 133 | if ((fp_pi_table = fopen(file, "w")) == NULL) { 134 | fprintf(stderr, "espresso: Unable to open %s\n", file); 135 | fp_pi_table = stdout; 136 | } 137 | FREE(file); 138 | } 139 | 140 | PLA = new_PLA(); 141 | PLA_labels(PLA); 142 | 143 | fpr_header(fp_primes, PLA, F_type); 144 | free_PLA(PLA); 145 | 146 | (void) fprintf(fp_primes, "# Essential primes are\n"); 147 | foreach_set(E, last, p) { 148 | (void) fprintf(fp_primes, "%s\n", pc1(p)); 149 | } 150 | fprintf(fp_primes, "# Totally redundant primes are\n"); 151 | foreach_set(Rt, last, p) { 152 | (void) fprintf(fp_primes, "%s\n", pc1(p)); 153 | } 154 | fprintf(fp_primes, "# Partially redundant primes are\n"); 155 | foreach_set(Rp, last, p) { 156 | (void) fprintf(fp_primes, "%s\n", pc1(p)); 157 | } 158 | if (fp_primes != stdout) { 159 | (void) fclose(fp_primes); 160 | } 161 | 162 | sm_write(fp_pi_table, table); 163 | if (fp_pi_table != stdout) { 164 | (void) fclose(fp_pi_table); 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /bench/espresso/getopt.c: -------------------------------------------------------------------------------- 1 | #include "espresso.h" 2 | #include "port.h" 3 | /* File : getopt.c 4 | Author : Henry Spencer, University of Toronto 5 | Updated: 28 April 1984 6 | Purpose: get option letter from argv. 7 | */ 8 | #define NullS ((char *) 0) 9 | 10 | char *optarg; /* Global argument pointer. */ 11 | int optind = 0; /* Global argv index. */ 12 | 13 | int getopt(int argc, char * const * argv, const char * optstring) 14 | { 15 | register int c; 16 | register char *place; 17 | static char *scan = NullS; /* Private scan pointer. */ 18 | 19 | optarg = NullS; 20 | 21 | if (scan == NullS || *scan == '\0') { 22 | if (optind == 0) optind++; 23 | if (optind >= argc) return EOF; 24 | place = argv[optind]; 25 | if (place[0] != '-' || place[1] == '\0') return EOF; 26 | optind++; 27 | if (place[1] == '-' && place[2] == '\0') return EOF; 28 | scan = place+1; 29 | } 30 | 31 | c = *scan++; 32 | place = strchr(optstring, c); 33 | if (place == NullS || c == ':') { 34 | fprintf(stderr, "%s: unknown option %c\n", argv[0], c); 35 | return '?'; 36 | } 37 | if (*++place == ':') { 38 | if (*scan != '\0') { 39 | optarg = scan, scan = NullS; 40 | } else { 41 | optarg = argv[optind], optind++; 42 | } 43 | } 44 | return c; 45 | } 46 | -------------------------------------------------------------------------------- /bench/espresso/gimpel.c: -------------------------------------------------------------------------------- 1 | #include "espresso.h" 2 | #include "mincov_int.h" 3 | 4 | 5 | /* 6 | * check for: 7 | * 8 | * c1 c2 rest 9 | * -- -- --- 10 | * 1 1 0 0 0 0 <-- primary row 11 | * 1 0 S1 <-- secondary row 12 | * 0 1 T1 13 | * 0 1 T2 14 | * 0 1 Tn 15 | * 0 0 R 16 | */ 17 | 18 | int 19 | gimpel_reduce(A, select, weight, lb, bound, depth, stats, best) 20 | sm_matrix *A; 21 | solution_t *select; 22 | int *weight; 23 | int lb; 24 | int bound; 25 | int depth; 26 | stats_t *stats; 27 | solution_t **best; 28 | { 29 | register sm_row *prow, *save_sec; 30 | register sm_col *c1, *c2; 31 | register sm_element *p, *p1; 32 | int c1_col_num, c2_col_num, primary_row_num, secondary_row_num; 33 | int reduce_it; 34 | 35 | reduce_it = 0; 36 | for(prow = A->first_row; prow != 0; prow = prow->next_row) { 37 | if (prow->length == 2) { 38 | c1 = sm_get_col(A, prow->first_col->col_num); 39 | c2 = sm_get_col(A, prow->last_col->col_num); 40 | if (c1->length == 2) { 41 | reduce_it = 1; 42 | } else if (c2->length == 2) { 43 | c1 = sm_get_col(A, prow->last_col->col_num); 44 | c2 = sm_get_col(A, prow->first_col->col_num); 45 | reduce_it = 1; 46 | } 47 | if (reduce_it) { 48 | primary_row_num = prow->row_num; 49 | secondary_row_num = c1->first_row->row_num; 50 | if (secondary_row_num == primary_row_num) { 51 | secondary_row_num = c1->last_row->row_num; 52 | } 53 | break; 54 | } 55 | } 56 | } 57 | 58 | if (reduce_it) { 59 | c1_col_num = c1->col_num; 60 | c2_col_num = c2->col_num; 61 | save_sec = sm_row_dup(sm_get_row(A, secondary_row_num)); 62 | sm_row_remove(save_sec, c1_col_num); 63 | 64 | for(p = c2->first_row; p != 0; p = p->next_row) { 65 | if (p->row_num != primary_row_num) { 66 | /* merge rows S1 and T */ 67 | for(p1 = save_sec->first_col; p1 != 0; p1 = p1->next_col) { 68 | (void) sm_insert(A, p->row_num, p1->col_num); 69 | } 70 | } 71 | } 72 | 73 | sm_delcol(A, c1_col_num); 74 | sm_delcol(A, c2_col_num); 75 | sm_delrow(A, primary_row_num); 76 | sm_delrow(A, secondary_row_num); 77 | 78 | stats->gimpel_count++; 79 | stats->gimpel++; 80 | *best = sm_mincov(A, select, weight, lb-1, bound-1, depth, stats); 81 | stats->gimpel--; 82 | 83 | if (*best != NIL(solution_t)) { 84 | /* is secondary row covered ? */ 85 | if (sm_row_intersects(save_sec, (*best)->row)) { 86 | /* yes, actually select c2 */ 87 | solution_add(*best, weight, c2_col_num); 88 | } else { 89 | solution_add(*best, weight, c1_col_num); 90 | } 91 | } 92 | 93 | sm_row_free(save_sec); 94 | return 1; 95 | } else { 96 | return 0; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /bench/espresso/globals.c: -------------------------------------------------------------------------------- 1 | #include "espresso.h" 2 | 3 | /* 4 | * Global Variable Declarations 5 | */ 6 | 7 | unsigned int debug; /* debug parameter */ 8 | bool verbose_debug; /* -v: whether to print a lot */ 9 | char *total_name[TIME_COUNT]; /* basic function names */ 10 | long total_time[TIME_COUNT]; /* time spent in basic fcts */ 11 | int total_calls[TIME_COUNT]; /* # calls to each fct */ 12 | 13 | bool echo_comments; /* turned off by -eat option */ 14 | bool echo_unknown_commands; /* always true ?? */ 15 | bool force_irredundant; /* -nirr command line option */ 16 | bool skip_make_sparse; 17 | bool kiss; /* -kiss command line option */ 18 | bool pos; /* -pos command line option */ 19 | bool print_solution; /* -x command line option */ 20 | bool recompute_onset; /* -onset command line option */ 21 | bool remove_essential; /* -ness command line option */ 22 | bool single_expand; /* -fast command line option */ 23 | bool summary; /* -s command line option */ 24 | bool trace; /* -t command line option */ 25 | bool unwrap_onset; /* -nunwrap command line option */ 26 | bool use_random_order; /* -random command line option */ 27 | bool use_super_gasp; /* -strong command line option */ 28 | char *filename; /* filename PLA was read from */ 29 | 30 | struct pla_types_struct pla_types[] = { 31 | "-f", F_type, 32 | "-r", R_type, 33 | "-d", D_type, 34 | "-fd", FD_type, 35 | "-fr", FR_type, 36 | "-dr", DR_type, 37 | "-fdr", FDR_type, 38 | "-fc", F_type | CONSTRAINTS_type, 39 | "-rc", R_type | CONSTRAINTS_type, 40 | "-dc", D_type | CONSTRAINTS_type, 41 | "-fdc", FD_type | CONSTRAINTS_type, 42 | "-frc", FR_type | CONSTRAINTS_type, 43 | "-drc", DR_type | CONSTRAINTS_type, 44 | "-fdrc", FDR_type | CONSTRAINTS_type, 45 | "-pleasure", PLEASURE_type, 46 | "-eqn", EQNTOTT_type, 47 | "-eqntott", EQNTOTT_type, 48 | "-kiss", KISS_type, 49 | "-cons", CONSTRAINTS_type, 50 | "-scons", SYMBOLIC_CONSTRAINTS_type, 51 | 0, 0 52 | }; 53 | 54 | 55 | struct cube_struct cube, temp_cube_save; 56 | struct cdata_struct cdata, temp_cdata_save; 57 | 58 | int bit_count[256] = { 59 | 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, 60 | 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 61 | 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 62 | 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 63 | 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 64 | 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 65 | 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 66 | 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8 67 | }; 68 | -------------------------------------------------------------------------------- /bench/espresso/indep.c: -------------------------------------------------------------------------------- 1 | #include "espresso.h" 2 | #include "mincov_int.h" 3 | 4 | static sm_matrix *build_intersection_matrix(); 5 | 6 | 7 | #if 0 8 | /* 9 | * verify that all rows in 'indep' are actually independent ! 10 | */ 11 | static int 12 | verify_indep_set(A, indep) 13 | sm_matrix *A; 14 | sm_row *indep; 15 | { 16 | register sm_row *prow, *prow1; 17 | register sm_element *p, *p1; 18 | 19 | for(p = indep->first_col; p != 0; p = p->next_col) { 20 | prow = sm_get_row(A, p->col_num); 21 | for(p1 = p->next_col; p1 != 0; p1 = p1->next_col) { 22 | prow1 = sm_get_row(A, p1->col_num); 23 | if (sm_row_intersects(prow, prow1)) { 24 | return 0; 25 | } 26 | } 27 | } 28 | return 1; 29 | } 30 | #endif 31 | 32 | solution_t * 33 | sm_maximal_independent_set(A, weight) 34 | sm_matrix *A; 35 | int *weight; 36 | { 37 | register sm_row *best_row, *prow; 38 | register sm_element *p; 39 | int least_weight; 40 | sm_row *save; 41 | sm_matrix *B; 42 | solution_t *indep; 43 | 44 | indep = solution_alloc(); 45 | B = build_intersection_matrix(A); 46 | 47 | while (B->nrows > 0) { 48 | /* Find the row which is disjoint from a maximum number of rows */ 49 | best_row = B->first_row; 50 | for(prow = B->first_row->next_row; prow != 0; prow = prow->next_row) { 51 | if (prow->length < best_row->length) { 52 | best_row = prow; 53 | } 54 | } 55 | 56 | /* Find which element in this row has least weight */ 57 | if (weight == NIL(int)) { 58 | least_weight = 1; 59 | } else { 60 | prow = sm_get_row(A, best_row->row_num); 61 | least_weight = weight[prow->first_col->col_num]; 62 | for(p = prow->first_col->next_col; p != 0; p = p->next_col) { 63 | if (weight[p->col_num] < least_weight) { 64 | least_weight = weight[p->col_num]; 65 | } 66 | } 67 | } 68 | indep->cost += least_weight; 69 | (void) sm_row_insert(indep->row, best_row->row_num); 70 | 71 | /* Discard the rows which intersect this row */ 72 | save = sm_row_dup(best_row); 73 | for(p = save->first_col; p != 0; p = p->next_col) { 74 | sm_delrow(B, p->col_num); 75 | sm_delcol(B, p->col_num); 76 | } 77 | sm_row_free(save); 78 | } 79 | 80 | sm_free(B); 81 | 82 | /* 83 | if (! verify_indep_set(A, indep->row)) { 84 | fail("sm_maximal_independent_set: row set is not independent"); 85 | } 86 | */ 87 | return indep; 88 | } 89 | 90 | static sm_matrix * 91 | build_intersection_matrix(A) 92 | sm_matrix *A; 93 | { 94 | register sm_row *prow, *prow1; 95 | register sm_element *p, *p1; 96 | register sm_col *pcol; 97 | sm_matrix *B; 98 | 99 | /* Build row-intersection matrix */ 100 | B = sm_alloc(); 101 | for(prow = A->first_row; prow != 0; prow = prow->next_row) { 102 | 103 | /* Clear flags on all rows we can reach from row 'prow' */ 104 | for(p = prow->first_col; p != 0; p = p->next_col) { 105 | pcol = sm_get_col(A, p->col_num); 106 | for(p1 = pcol->first_row; p1 != 0; p1 = p1->next_row) { 107 | prow1 = sm_get_row(A, p1->row_num); 108 | prow1->flag = 0; 109 | } 110 | } 111 | 112 | /* Now record which rows can be reached */ 113 | for(p = prow->first_col; p != 0; p = p->next_col) { 114 | pcol = sm_get_col(A, p->col_num); 115 | for(p1 = pcol->first_row; p1 != 0; p1 = p1->next_row) { 116 | prow1 = sm_get_row(A, p1->row_num); 117 | if (! prow1->flag) { 118 | prow1->flag = 1; 119 | (void) sm_insert(B, prow->row_num, prow1->row_num); 120 | } 121 | } 122 | } 123 | } 124 | 125 | return B; 126 | } 127 | -------------------------------------------------------------------------------- /bench/espresso/main.h: -------------------------------------------------------------------------------- 1 | enum keys { 2 | KEY_ESPRESSO, KEY_PLA_verify, KEY_check, KEY_contain, KEY_d1merge, 3 | KEY_disjoint, KEY_dsharp, KEY_echo, KEY_essen, KEY_exact, KEY_expand, 4 | KEY_gasp, KEY_intersect, KEY_irred, KEY_lexsort, KEY_make_sparse, 5 | KEY_map, KEY_mapdc, KEY_minterms, KEY_opo, KEY_opoall, 6 | KEY_pair, KEY_pairall, KEY_primes, KEY_qm, KEY_reduce, KEY_sharp, 7 | KEY_simplify, KEY_so, KEY_so_both, KEY_stats, KEY_super_gasp, KEY_taut, 8 | KEY_test, KEY_equiv, KEY_union, KEY_verify, KEY_MANY_ESPRESSO, 9 | KEY_separate, KEY_xor, KEY_d1merge_in, KEY_fsm, 10 | KEY_unknown 11 | }; 12 | 13 | /* Lookup table for program options */ 14 | struct { 15 | char *name; 16 | enum keys key; 17 | int num_plas; 18 | bool needs_offset; 19 | bool needs_dcset; 20 | } option_table [] = { 21 | /* ways to minimize functions */ 22 | "ESPRESSO", KEY_ESPRESSO, 1, TRUE, TRUE, /* must be first */ 23 | "many", KEY_MANY_ESPRESSO, 1, TRUE, TRUE, 24 | "exact", KEY_exact, 1, TRUE, TRUE, 25 | "qm", KEY_qm, 1, TRUE, TRUE, 26 | "single_output", KEY_so, 1, TRUE, TRUE, 27 | "so", KEY_so, 1, TRUE, TRUE, 28 | "so_both", KEY_so_both, 1, TRUE, TRUE, 29 | "simplify", KEY_simplify, 1, FALSE, FALSE, 30 | "echo", KEY_echo, 1, FALSE, FALSE, 31 | 32 | /* output phase assignment and assignment of inputs to two-bit decoders */ 33 | "opo", KEY_opo, 1, TRUE, TRUE, 34 | "opoall", KEY_opoall, 1, TRUE, TRUE, 35 | "pair", KEY_pair, 1, TRUE, TRUE, 36 | "pairall", KEY_pairall, 1, TRUE, TRUE, 37 | 38 | /* Ways to check covers */ 39 | "check", KEY_check, 1, TRUE, TRUE, 40 | "stats", KEY_stats, 1, FALSE, FALSE, 41 | "verify", KEY_verify, 2, FALSE, TRUE, 42 | "PLAverify", KEY_PLA_verify, 2, FALSE, TRUE, 43 | 44 | /* hacks */ 45 | "equiv", KEY_equiv, 1, TRUE, TRUE, 46 | "map", KEY_map, 1, FALSE, FALSE, 47 | "mapdc", KEY_mapdc, 1, FALSE, FALSE, 48 | "fsm", KEY_fsm, 1, FALSE, TRUE, 49 | 50 | /* the basic boolean operations on covers */ 51 | "contain", KEY_contain, 1, FALSE, FALSE, 52 | "d1merge", KEY_d1merge, 1, FALSE, FALSE, 53 | "d1merge_in", KEY_d1merge_in, 1, FALSE, FALSE, 54 | "disjoint", KEY_disjoint, 1, TRUE, FALSE, 55 | "dsharp", KEY_dsharp, 2, FALSE, FALSE, 56 | "intersect", KEY_intersect, 2, FALSE, FALSE, 57 | "minterms", KEY_minterms, 1, FALSE, FALSE, 58 | "primes", KEY_primes, 1, FALSE, TRUE, 59 | "separate", KEY_separate, 1, TRUE, TRUE, 60 | "sharp", KEY_sharp, 2, FALSE, FALSE, 61 | "union", KEY_union, 2, FALSE, FALSE, 62 | "xor", KEY_xor, 2, TRUE, TRUE, 63 | 64 | /* debugging only -- call each step of the espresso algorithm */ 65 | "essen", KEY_essen, 1, FALSE, TRUE, 66 | "expand", KEY_expand, 1, TRUE, FALSE, 67 | "gasp", KEY_gasp, 1, TRUE, TRUE, 68 | "irred", KEY_irred, 1, FALSE, TRUE, 69 | "make_sparse", KEY_make_sparse, 1, TRUE, TRUE, 70 | "reduce", KEY_reduce, 1, FALSE, TRUE, 71 | "taut", KEY_taut, 1, FALSE, FALSE, 72 | "super_gasp", KEY_super_gasp, 1, TRUE, TRUE, 73 | "lexsort", KEY_lexsort, 1, FALSE, FALSE, 74 | "test", KEY_test, 1, TRUE, TRUE, 75 | 0, KEY_unknown, 0, FALSE, FALSE /* must be last */ 76 | }; 77 | 78 | 79 | struct { 80 | char *name; 81 | int value; 82 | } debug_table[] = { 83 | "", EXPAND + ESSEN + IRRED + REDUCE + SPARSE + GASP + SHARP + MINCOV, 84 | "compl", COMPL, "essen", ESSEN, 85 | "expand", EXPAND, "expand1", EXPAND1|EXPAND, 86 | "irred", IRRED, "irred1", IRRED1|IRRED, 87 | "reduce", REDUCE, "reduce1", REDUCE1|REDUCE, 88 | "mincov", MINCOV, "mincov1", MINCOV1|MINCOV, 89 | "sparse", SPARSE, "sharp", SHARP, 90 | "taut", TAUT, "gasp", GASP, 91 | "exact", EXACT, 92 | 0, 93 | }; 94 | 95 | 96 | struct { 97 | char *name; 98 | int *variable; 99 | int value; 100 | } esp_opt_table[] = { 101 | "eat", &echo_comments, FALSE, 102 | "eatdots", &echo_unknown_commands, FALSE, 103 | "fast", &single_expand, TRUE, 104 | "kiss", &kiss, TRUE, 105 | "ness", &remove_essential, FALSE, 106 | "nirr", &force_irredundant, FALSE, 107 | "nunwrap", &unwrap_onset, FALSE, 108 | "onset", &recompute_onset, TRUE, 109 | "pos", &pos, TRUE, 110 | "random", &use_random_order, TRUE, 111 | "strong", &use_super_gasp, TRUE, 112 | 0, 113 | }; 114 | -------------------------------------------------------------------------------- /bench/espresso/map.c: -------------------------------------------------------------------------------- 1 | #include "espresso.h" 2 | 3 | static pcube Gcube; 4 | static pset Gminterm; 5 | 6 | pset minterms(T) 7 | pcover T; 8 | { 9 | int size, var; 10 | register pcube last; 11 | 12 | size = 1; 13 | for(var = 0; var < cube.num_vars; var++) 14 | size *= cube.part_size[var]; 15 | Gminterm = set_new(size); 16 | 17 | foreach_set(T, last, Gcube) 18 | explode(cube.num_vars-1, 0); 19 | 20 | return Gminterm; 21 | } 22 | 23 | 24 | void explode(var, z) 25 | int var, z; 26 | { 27 | int i, last = cube.last_part[var]; 28 | for(i=cube.first_part[var], z *= cube.part_size[var]; i<=last; i++, z++) 29 | if (is_in_set(Gcube, i)) 30 | if (var == 0) 31 | set_insert(Gminterm, z); 32 | else 33 | explode(var-1, z); 34 | } 35 | 36 | 37 | static int mapindex[16][16] = { 38 | 0, 1, 3, 2, 16, 17, 19, 18, 80, 81, 83, 82, 64, 65, 67, 66, 39 | 4, 5, 7, 6, 20, 21, 23, 22, 84, 85, 87, 86, 68, 69, 71, 70, 40 | 12, 13, 15, 14, 28, 29, 31, 30, 92, 93, 95, 94, 76, 77, 79, 78, 41 | 8, 9, 11, 10, 24, 25, 27, 26, 88, 89, 91, 90, 72, 73, 75, 74, 42 | 43 | 32, 33, 35, 34, 48, 49, 51, 50, 112,113,115,114, 96, 97, 99, 98, 44 | 36, 37, 39, 38, 52, 53, 55, 54, 116,117,119,118, 100,101,103,102, 45 | 44, 45, 47, 46, 60, 61, 63, 62, 124,125,127,126, 108,109,111,110, 46 | 40, 41, 43, 42, 56, 57, 59, 58, 120,121,123,122, 104,105,107,106, 47 | 48 | 49 | 160,161,163,162, 176,177,179,178, 240,241,243,242, 224,225,227,226, 50 | 164,165,167,166, 180,181,183,182, 244,245,247,246, 228,229,231,230, 51 | 172,173,175,174, 188,189,191,190, 252,253,255,254, 236,237,239,238, 52 | 168,169,171,170, 184,185,187,186, 248,249,251,250, 232,233,235,234, 53 | 54 | 128,129,131,130, 144,145,147,146, 208,209,211,210, 192,193,195,194, 55 | 132,133,135,134, 148,149,151,150, 212,213,215,214, 196,197,199,198, 56 | 140,141,143,142, 156,157,159,158, 220,221,223,222, 204,205,207,206, 57 | 136,137,139,138, 152,153,155,154, 216,217,219,218, 200,201,203,202 58 | }; 59 | 60 | #define POWER2(n) (1 << n) 61 | void map(T) 62 | pcover T; 63 | { 64 | int j, k, l, other_input_offset, output_offset, outnum, ind; 65 | int largest_input_ind, numout; 66 | char c; 67 | pset m; 68 | bool some_output; 69 | 70 | m = minterms(T); 71 | largest_input_ind = POWER2(cube.num_binary_vars); 72 | numout = cube.part_size[cube.num_vars-1]; 73 | 74 | for(outnum = 0; outnum < numout; outnum++) { 75 | output_offset = outnum * largest_input_ind; 76 | printf("\n\nOutput space # %d\n", outnum); 77 | for(l = 0; l <= MAX(cube.num_binary_vars - 8, 0); l++) { 78 | other_input_offset = l * 256; 79 | for(k = 0; k < 16; k++) { 80 | some_output = FALSE; 81 | for(j = 0; j < 16; j++) { 82 | ind = mapindex[k][j] + other_input_offset; 83 | if (ind < largest_input_ind) { 84 | c = is_in_set(m, ind+output_offset) ? '1' : '.'; 85 | putchar(c); 86 | some_output = TRUE; 87 | } 88 | if ((j+1)%4 == 0) 89 | putchar(' '); 90 | if ((j+1)%8 == 0) 91 | printf(" "); 92 | } 93 | if (some_output) 94 | putchar('\n'); 95 | if ((k+1)%4 == 0) { 96 | if (k != 15 && mapindex[k+1][0] >= largest_input_ind) 97 | break; 98 | putchar('\n'); 99 | } 100 | if ((k+1)%8 == 0) 101 | putchar('\n'); 102 | } 103 | } 104 | } 105 | set_free(m); 106 | } 107 | -------------------------------------------------------------------------------- /bench/espresso/mincov.h: -------------------------------------------------------------------------------- 1 | /* exported */ 2 | extern sm_row *sm_minimum_cover(); 3 | -------------------------------------------------------------------------------- /bench/espresso/mincov_int.h: -------------------------------------------------------------------------------- 1 | #include "port.h" 2 | #include "utility.h" 3 | #include "sparse.h" 4 | #include "mincov.h" 5 | 6 | 7 | typedef struct stats_struct stats_t; 8 | struct stats_struct { 9 | int debug; /* 1 if debugging is enabled */ 10 | int max_print_depth; /* dump stats for levels up to this level */ 11 | int max_depth; /* deepest the recursion has gone */ 12 | int nodes; /* total nodes visited */ 13 | int component; /* currently solving a component */ 14 | int comp_count; /* number of components detected */ 15 | int gimpel_count; /* number of times Gimpel reduction applied */ 16 | int gimpel; /* currently inside Gimpel reduction */ 17 | long start_time; /* cpu time when the covering started */ 18 | int no_branching; 19 | int lower_bound; 20 | }; 21 | 22 | 23 | 24 | typedef struct solution_struct solution_t; 25 | struct solution_struct { 26 | sm_row *row; 27 | int cost; 28 | }; 29 | 30 | 31 | extern solution_t *solution_alloc(); 32 | extern void solution_free(); 33 | extern solution_t *solution_dup(); 34 | extern void solution_accept(); 35 | extern void solution_reject(); 36 | extern void solution_add(); 37 | extern solution_t *solution_choose_best(); 38 | 39 | extern solution_t *sm_maximal_independent_set(); 40 | extern solution_t *sm_mincov(); 41 | extern int gimpel_reduce(); 42 | 43 | 44 | #define WEIGHT(weight, col) (weight == NIL(int) ? 1 : weight[col]) 45 | -------------------------------------------------------------------------------- /bench/espresso/part.c: -------------------------------------------------------------------------------- 1 | #include "espresso.h" 2 | #include "mincov_int.h" 3 | 4 | static int visit_col(); 5 | 6 | static void 7 | copy_row(A, prow) 8 | register sm_matrix *A; 9 | register sm_row *prow; 10 | { 11 | register sm_element *p; 12 | 13 | for(p = prow->first_col; p != 0; p = p->next_col) { 14 | (void) sm_insert(A, p->row_num, p->col_num); 15 | } 16 | } 17 | 18 | 19 | static int 20 | visit_row(A, prow, rows_visited, cols_visited) 21 | sm_matrix *A; 22 | sm_row *prow; 23 | int *rows_visited; 24 | int *cols_visited; 25 | { 26 | sm_element *p; 27 | sm_col *pcol; 28 | 29 | if (! prow->flag) { 30 | prow->flag = 1; 31 | (*rows_visited)++; 32 | if (*rows_visited == A->nrows) { 33 | return 1; 34 | } 35 | for(p = prow->first_col; p != 0; p = p->next_col) { 36 | pcol = sm_get_col(A, p->col_num); 37 | if (! pcol->flag) { 38 | if (visit_col(A, pcol, rows_visited, cols_visited)) { 39 | return 1; 40 | } 41 | } 42 | } 43 | } 44 | return 0; 45 | } 46 | 47 | 48 | static int 49 | visit_col(A, pcol, rows_visited, cols_visited) 50 | sm_matrix *A; 51 | sm_col *pcol; 52 | int *rows_visited; 53 | int *cols_visited; 54 | { 55 | sm_element *p; 56 | sm_row *prow; 57 | 58 | if (! pcol->flag) { 59 | pcol->flag = 1; 60 | (*cols_visited)++; 61 | if (*cols_visited == A->ncols) { 62 | return 1; 63 | } 64 | for(p = pcol->first_row; p != 0; p = p->next_row) { 65 | prow = sm_get_row(A, p->row_num); 66 | if (! prow->flag) { 67 | if (visit_row(A, prow, rows_visited, cols_visited)) { 68 | return 1; 69 | } 70 | } 71 | } 72 | } 73 | return 0; 74 | } 75 | 76 | int 77 | sm_block_partition(A, L, R) 78 | sm_matrix *A; 79 | sm_matrix **L, **R; 80 | { 81 | int cols_visited, rows_visited; 82 | register sm_row *prow; 83 | register sm_col *pcol; 84 | 85 | /* Avoid the trivial case */ 86 | if (A->nrows == 0) { 87 | return 0; 88 | } 89 | 90 | /* Reset the visited flags for each row and column */ 91 | for(prow = A->first_row; prow != 0; prow = prow->next_row) { 92 | prow->flag = 0; 93 | } 94 | for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { 95 | pcol->flag = 0; 96 | } 97 | 98 | cols_visited = rows_visited = 0; 99 | if (visit_row(A, A->first_row, &rows_visited, &cols_visited)) { 100 | /* we found all of the rows */ 101 | return 0; 102 | } else { 103 | *L = sm_alloc(); 104 | *R = sm_alloc(); 105 | for(prow = A->first_row; prow != 0; prow = prow->next_row) { 106 | if (prow->flag) { 107 | copy_row(*L, prow); 108 | } else { 109 | copy_row(*R, prow); 110 | } 111 | } 112 | return 1; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /bench/espresso/primes.c: -------------------------------------------------------------------------------- 1 | #include "espresso.h" 2 | 3 | static bool primes_consensus_special_cases(); 4 | static pcover primes_consensus_merge(); 5 | static pcover and_with_cofactor(); 6 | 7 | 8 | /* primes_consensus -- generate primes using consensus */ 9 | pcover primes_consensus(T) 10 | pcube *T; /* T will be disposed of */ 11 | { 12 | register pcube cl, cr; 13 | register int best; 14 | pcover Tnew, Tl, Tr; 15 | 16 | if (primes_consensus_special_cases(T, &Tnew) == MAYBE) { 17 | cl = new_cube(); 18 | cr = new_cube(); 19 | best = binate_split_select(T, cl, cr, COMPL); 20 | 21 | Tl = primes_consensus(scofactor(T, cl, best)); 22 | Tr = primes_consensus(scofactor(T, cr, best)); 23 | Tnew = primes_consensus_merge(Tl, Tr, cl, cr); 24 | 25 | free_cube(cl); 26 | free_cube(cr); 27 | free_cubelist(T); 28 | } 29 | 30 | return Tnew; 31 | } 32 | 33 | static bool 34 | primes_consensus_special_cases(T, Tnew) 35 | pcube *T; /* will be disposed if answer is determined */ 36 | pcover *Tnew; /* returned only if answer determined */ 37 | { 38 | register pcube *T1, p, ceil, cof=T[0]; 39 | pcube last; 40 | pcover A; 41 | 42 | /* Check for no cubes in the cover */ 43 | if (T[2] == NULL) { 44 | *Tnew = new_cover(0); 45 | free_cubelist(T); 46 | return TRUE; 47 | } 48 | 49 | /* Check for only a single cube in the cover */ 50 | if (T[3] == NULL) { 51 | *Tnew = sf_addset(new_cover(1), set_or(cof, cof, T[2])); 52 | free_cubelist(T); 53 | return TRUE; 54 | } 55 | 56 | /* Check for a row of all 1's (implies function is a tautology) */ 57 | for(T1 = T+2; (p = *T1++) != NULL; ) { 58 | if (full_row(p, cof)) { 59 | *Tnew = sf_addset(new_cover(1), cube.fullset); 60 | free_cubelist(T); 61 | return TRUE; 62 | } 63 | } 64 | 65 | /* Check for a column of all 0's which can be factored out */ 66 | ceil = set_save(cof); 67 | for(T1 = T+2; (p = *T1++) != NULL; ) { 68 | INLINEset_or(ceil, ceil, p); 69 | } 70 | if (! setp_equal(ceil, cube.fullset)) { 71 | p = new_cube(); 72 | (void) set_diff(p, cube.fullset, ceil); 73 | (void) set_or(cof, cof, p); 74 | free_cube(p); 75 | 76 | A = primes_consensus(T); 77 | foreach_set(A, last, p) { 78 | INLINEset_and(p, p, ceil); 79 | } 80 | *Tnew = A; 81 | set_free(ceil); 82 | return TRUE; 83 | } 84 | set_free(ceil); 85 | 86 | /* Collect column counts, determine unate variables, etc. */ 87 | massive_count(T); 88 | 89 | /* If single active variable not factored out above, then tautology ! */ 90 | if (cdata.vars_active == 1) { 91 | *Tnew = sf_addset(new_cover(1), cube.fullset); 92 | free_cubelist(T); 93 | return TRUE; 94 | 95 | /* Check for unate cover */ 96 | } else if (cdata.vars_unate == cdata.vars_active) { 97 | A = cubeunlist(T); 98 | *Tnew = sf_contain(A); 99 | free_cubelist(T); 100 | return TRUE; 101 | 102 | /* Not much we can do about it */ 103 | } else { 104 | return MAYBE; 105 | } 106 | } 107 | 108 | static pcover 109 | primes_consensus_merge(Tl, Tr, cl, cr) 110 | pcover Tl, Tr; 111 | pcube cl, cr; 112 | { 113 | register pcube pl, pr, lastl, lastr, pt; 114 | pcover T, Tsave; 115 | 116 | Tl = and_with_cofactor(Tl, cl); 117 | Tr = and_with_cofactor(Tr, cr); 118 | 119 | T = sf_new(500, Tl->sf_size); 120 | pt = T->data; 121 | Tsave = sf_contain(sf_join(Tl, Tr)); 122 | 123 | foreach_set(Tl, lastl, pl) { 124 | foreach_set(Tr, lastr, pr) { 125 | if (cdist01(pl, pr) == 1) { 126 | consensus(pt, pl, pr); 127 | if (++T->count >= T->capacity) { 128 | Tsave = sf_union(Tsave, sf_contain(T)); 129 | T = sf_new(500, Tl->sf_size); 130 | pt = T->data; 131 | } else { 132 | pt += T->wsize; 133 | } 134 | } 135 | } 136 | } 137 | free_cover(Tl); 138 | free_cover(Tr); 139 | 140 | Tsave = sf_union(Tsave, sf_contain(T)); 141 | return Tsave; 142 | } 143 | 144 | 145 | static pcover 146 | and_with_cofactor(A, cof) 147 | pset_family A; 148 | register pset cof; 149 | { 150 | register pset last, p; 151 | 152 | foreach_set(A, last, p) { 153 | INLINEset_and(p, p, cof); 154 | if (cdist(p, cube.fullset) > 0) { 155 | RESET(p, ACTIVE); 156 | } else { 157 | SET(p, ACTIVE); 158 | } 159 | } 160 | return sf_inactive(A); 161 | } 162 | -------------------------------------------------------------------------------- /bench/espresso/sminterf.c: -------------------------------------------------------------------------------- 1 | #include "espresso.h" 2 | 3 | 4 | pset 5 | do_sm_minimum_cover(A) 6 | pset_family A; 7 | { 8 | sm_matrix *M; 9 | sm_row *sparse_cover; 10 | sm_element *pe; 11 | pset cover; 12 | register int i, base, rownum; 13 | register unsigned val; 14 | register pset last, p; 15 | 16 | M = sm_alloc(); 17 | rownum = 0; 18 | foreach_set(A, last, p) { 19 | foreach_set_element(p, i, val, base) { 20 | (void) sm_insert(M, rownum, base); 21 | } 22 | rownum++; 23 | } 24 | 25 | sparse_cover = sm_minimum_cover(M, NIL(int), 1, 0); 26 | sm_free(M); 27 | 28 | cover = set_new(A->sf_size); 29 | sm_foreach_row_element(sparse_cover, pe) { 30 | set_insert(cover, pe->col_num); 31 | } 32 | sm_row_free(sparse_cover); 33 | 34 | return cover; 35 | } 36 | -------------------------------------------------------------------------------- /bench/espresso/solution.c: -------------------------------------------------------------------------------- 1 | #include "espresso.h" 2 | #include "mincov_int.h" 3 | 4 | 5 | solution_t * 6 | solution_alloc() 7 | { 8 | solution_t *sol; 9 | 10 | sol = ALLOC(solution_t, 1); 11 | sol->cost = 0; 12 | sol->row = sm_row_alloc(); 13 | return sol; 14 | } 15 | 16 | 17 | void 18 | solution_free(sol) 19 | solution_t *sol; 20 | { 21 | sm_row_free(sol->row); 22 | FREE(sol); 23 | } 24 | 25 | 26 | solution_t * 27 | solution_dup(sol) 28 | solution_t *sol; 29 | { 30 | solution_t *new_sol; 31 | 32 | new_sol = ALLOC(solution_t, 1); 33 | new_sol->cost = sol->cost; 34 | new_sol->row = sm_row_dup(sol->row); 35 | return new_sol; 36 | } 37 | 38 | 39 | void 40 | solution_add(sol, weight, col) 41 | solution_t *sol; 42 | int *weight; 43 | int col; 44 | { 45 | (void) sm_row_insert(sol->row, col); 46 | sol->cost += WEIGHT(weight, col); 47 | } 48 | 49 | 50 | void 51 | solution_accept(sol, A, weight, col) 52 | solution_t *sol; 53 | sm_matrix *A; 54 | int *weight; 55 | int col; 56 | { 57 | register sm_element *p, *pnext; 58 | sm_col *pcol; 59 | 60 | solution_add(sol, weight, col); 61 | 62 | /* delete rows covered by this column */ 63 | pcol = sm_get_col(A, col); 64 | for(p = pcol->first_row; p != 0; p = pnext) { 65 | pnext = p->next_row; /* grab it before it disappears */ 66 | sm_delrow(A, p->row_num); 67 | } 68 | } 69 | 70 | 71 | /* ARGSUSED */ 72 | void 73 | solution_reject(sol, A, weight, col) 74 | solution_t *sol; 75 | sm_matrix *A; 76 | int *weight; 77 | int col; 78 | { 79 | sm_delcol(A, col); 80 | } 81 | 82 | 83 | solution_t * 84 | solution_choose_best(best1, best2) 85 | solution_t *best1, *best2; 86 | { 87 | if (best1 != NIL(solution_t)) { 88 | if (best2 != NIL(solution_t)) { 89 | if (best1->cost <= best2->cost) { 90 | solution_free(best2); 91 | return best1; 92 | } else { 93 | solution_free(best1); 94 | return best2; 95 | } 96 | } else { 97 | return best1; 98 | } 99 | } else { 100 | if (best2 != NIL(solution_t)) { 101 | return best2; 102 | } else { 103 | return NIL(solution_t); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /bench/espresso/sparse.c: -------------------------------------------------------------------------------- 1 | /* 2 | module: sparse.c 3 | 4 | make_sparse is a last-step cleanup to reduce the total number 5 | of literals in the cover. 6 | 7 | This is done by reducing the "sparse" variables (using a modified 8 | version of irredundant rather than reduce), followed by expanding 9 | the "dense" variables (using modified version of expand). 10 | */ 11 | 12 | #include "espresso.h" 13 | 14 | pcover make_sparse(F, D, R) 15 | pcover F, D, R; 16 | { 17 | cost_t cost, best_cost; 18 | 19 | cover_cost(F, &best_cost); 20 | 21 | do { 22 | EXECUTE(F = mv_reduce(F, D), MV_REDUCE_TIME, F, cost); 23 | if (cost.total == best_cost.total) 24 | break; 25 | copy_cost(&cost, &best_cost); 26 | 27 | EXECUTE(F = expand(F, R, TRUE), RAISE_IN_TIME, F, cost); 28 | if (cost.total == best_cost.total) 29 | break; 30 | copy_cost(&cost, &best_cost); 31 | } while (force_irredundant); 32 | 33 | return F; 34 | } 35 | 36 | /* 37 | mv_reduce -- perform an "optimal" reduction of the variables which 38 | we desire to be sparse 39 | 40 | This could be done using "reduce" and then saving just the desired 41 | part of the reduction. Instead, this version uses IRRED to find 42 | which cubes of an output are redundant. Note that this gets around 43 | the cube-ordering problem. 44 | 45 | In normal use, it is expected that the cover is irredundant and 46 | hence no cubes will be reduced to the empty cube (however, this is 47 | checked for and such cubes will be deleted) 48 | */ 49 | 50 | pcover 51 | mv_reduce(F, D) 52 | pcover F, D; 53 | { 54 | register int i, var; 55 | register pcube p, p1, last; 56 | int index; 57 | pcover F1, D1; 58 | pcube *F_cube_table; 59 | 60 | /* loop for each multiple-valued variable */ 61 | for(var = 0; var < cube.num_vars; var++) { 62 | 63 | if (cube.sparse[var]) { 64 | 65 | /* loop for each part of the variable */ 66 | for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { 67 | 68 | /* remember mapping of F1 cubes back to F cubes */ 69 | F_cube_table = ALLOC(pcube, F->count); 70 | 71 | /* 'cofactor' against part #i of variable #var */ 72 | F1 = new_cover(F->count); 73 | foreach_set(F, last, p) { 74 | if (is_in_set(p, i)) { 75 | F_cube_table[F1->count] = p; 76 | p1 = GETSET(F1, F1->count++); 77 | (void) set_diff(p1, p, cube.var_mask[var]); 78 | set_insert(p1, i); 79 | } 80 | } 81 | 82 | /* 'cofactor' against part #i of variable #var */ 83 | /* not really necessary -- just more efficient ? */ 84 | D1 = new_cover(D->count); 85 | foreach_set(D, last, p) { 86 | if (is_in_set(p, i)) { 87 | p1 = GETSET(D1, D1->count++); 88 | (void) set_diff(p1, p, cube.var_mask[var]); 89 | set_insert(p1, i); 90 | } 91 | } 92 | 93 | mark_irredundant(F1, D1); 94 | 95 | /* now remove part i from cubes which are redundant */ 96 | index = 0; 97 | foreach_set(F1, last, p1) { 98 | if (! TESTP(p1, ACTIVE)) { 99 | p = F_cube_table[index]; 100 | 101 | /* don't reduce a variable which is full 102 | * (unless it is the output variable) 103 | */ 104 | if (var == cube.num_vars-1 || 105 | ! setp_implies(cube.var_mask[var], p)) { 106 | set_remove(p, i); 107 | } 108 | RESET(p, PRIME); 109 | } 110 | index++; 111 | } 112 | 113 | free_cover(F1); 114 | free_cover(D1); 115 | FREE(F_cube_table); 116 | } 117 | } 118 | } 119 | 120 | /* Check if any cubes disappeared */ 121 | (void) sf_active(F); 122 | for(var = 0; var < cube.num_vars; var++) { 123 | if (cube.sparse[var]) { 124 | foreach_active_set(F, last, p) { 125 | if (setp_disjoint(p, cube.var_mask[var])) { 126 | RESET(p, ACTIVE); 127 | F->active_count--; 128 | } 129 | } 130 | } 131 | } 132 | 133 | if (F->count != F->active_count) { 134 | F = sf_inactive(F); 135 | } 136 | return F; 137 | } 138 | -------------------------------------------------------------------------------- /bench/espresso/sparse.h: -------------------------------------------------------------------------------- 1 | #ifndef SPARSE_H 2 | #define SPARSE_H 3 | 4 | /* 5 | * sparse.h -- sparse matrix package header file 6 | */ 7 | 8 | typedef struct sm_element_struct sm_element; 9 | typedef struct sm_row_struct sm_row; 10 | typedef struct sm_col_struct sm_col; 11 | typedef struct sm_matrix_struct sm_matrix; 12 | 13 | 14 | /* 15 | * sparse matrix element 16 | */ 17 | struct sm_element_struct { 18 | int row_num; /* row number of this element */ 19 | int col_num; /* column number of this element */ 20 | sm_element *next_row; /* next row in this column */ 21 | sm_element *prev_row; /* previous row in this column */ 22 | sm_element *next_col; /* next column in this row */ 23 | sm_element *prev_col; /* previous column in this row */ 24 | char *user_word; /* user-defined word */ 25 | }; 26 | 27 | 28 | /* 29 | * row header 30 | */ 31 | struct sm_row_struct { 32 | int row_num; /* the row number */ 33 | int length; /* number of elements in this row */ 34 | int flag; /* user-defined word */ 35 | sm_element *first_col; /* first element in this row */ 36 | sm_element *last_col; /* last element in this row */ 37 | sm_row *next_row; /* next row (in sm_matrix linked list) */ 38 | sm_row *prev_row; /* previous row (in sm_matrix linked list) */ 39 | char *user_word; /* user-defined word */ 40 | }; 41 | 42 | 43 | /* 44 | * column header 45 | */ 46 | struct sm_col_struct { 47 | int col_num; /* the column number */ 48 | int length; /* number of elements in this column */ 49 | int flag; /* user-defined word */ 50 | sm_element *first_row; /* first element in this column */ 51 | sm_element *last_row; /* last element in this column */ 52 | sm_col *next_col; /* next column (in sm_matrix linked list) */ 53 | sm_col *prev_col; /* prev column (in sm_matrix linked list) */ 54 | char *user_word; /* user-defined word */ 55 | }; 56 | 57 | 58 | /* 59 | * A sparse matrix 60 | */ 61 | struct sm_matrix_struct { 62 | sm_row **rows; /* pointer to row headers (by row #) */ 63 | int rows_size; /* alloc'ed size of above array */ 64 | sm_col **cols; /* pointer to column headers (by col #) */ 65 | int cols_size; /* alloc'ed size of above array */ 66 | sm_row *first_row; /* first row (linked list of all rows) */ 67 | sm_row *last_row; /* last row (linked list of all rows) */ 68 | int nrows; /* number of rows */ 69 | sm_col *first_col; /* first column (linked list of columns) */ 70 | sm_col *last_col; /* last column (linked list of columns) */ 71 | int ncols; /* number of columns */ 72 | char *user_word; /* user-defined word */ 73 | }; 74 | 75 | 76 | #define sm_get_col(A, colnum) \ 77 | (((colnum) >= 0 && (colnum) < (A)->cols_size) ? \ 78 | (A)->cols[colnum] : (sm_col *) 0) 79 | 80 | #define sm_get_row(A, rownum) \ 81 | (((rownum) >= 0 && (rownum) < (A)->rows_size) ? \ 82 | (A)->rows[rownum] : (sm_row *) 0) 83 | 84 | #define sm_foreach_row(A, prow) \ 85 | for(prow = A->first_row; prow != 0; prow = prow->next_row) 86 | 87 | #define sm_foreach_col(A, pcol) \ 88 | for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) 89 | 90 | #define sm_foreach_row_element(prow, p) \ 91 | for(p = prow->first_col; p != 0; p = p->next_col) 92 | 93 | #define sm_foreach_col_element(pcol, p) \ 94 | for(p = pcol->first_row; p != 0; p = p->next_row) 95 | 96 | #define sm_put(x, val) \ 97 | (x->user_word = (char *) val) 98 | 99 | #define sm_get(type, x) \ 100 | ((type) (x->user_word)) 101 | 102 | extern sm_matrix *sm_alloc(), *sm_alloc_size(), *sm_dup(); 103 | extern void sm_free(), sm_delrow(), sm_delcol(), sm_resize(); 104 | extern void sm_write(), sm_print(), sm_dump(), sm_cleanup(); 105 | extern void sm_copy_row(), sm_copy_col(); 106 | extern void sm_remove(), sm_remove_element(); 107 | extern sm_element *sm_insert(), *sm_find(); 108 | extern sm_row *sm_longest_row(); 109 | extern sm_col *sm_longest_col(); 110 | extern int sm_read(), sm_read_compressed(); 111 | 112 | extern sm_row *sm_row_alloc(), *sm_row_dup(), *sm_row_and(); 113 | extern void sm_row_free(), sm_row_remove(), sm_row_print(); 114 | extern sm_element *sm_row_insert(), *sm_row_find(); 115 | extern int sm_row_contains(), sm_row_intersects(); 116 | extern int sm_row_compare(), sm_row_hash(); 117 | 118 | extern sm_col *sm_col_alloc(), *sm_col_dup(), *sm_col_and(); 119 | extern void sm_col_free(), sm_col_remove(), sm_col_print(); 120 | extern sm_element *sm_col_insert(), *sm_col_find(); 121 | extern int sm_col_contains(), sm_col_intersects(); 122 | extern int sm_col_compare(), sm_col_hash(); 123 | 124 | extern int sm_row_dominance(), sm_col_dominance(), sm_block_partition(); 125 | 126 | #endif 127 | -------------------------------------------------------------------------------- /bench/espresso/sparse_int.h: -------------------------------------------------------------------------------- 1 | #include "port.h" 2 | #include "utility.h" 3 | #include "sparse.h" 4 | 5 | 6 | 7 | /* 8 | * sorted, double-linked list insertion 9 | * 10 | * type: object type 11 | * 12 | * first, last: fields (in header) to head and tail of the list 13 | * count: field (in header) of length of the list 14 | * 15 | * next, prev: fields (in object) to link next and previous objects 16 | * value: field (in object) which controls the order 17 | * 18 | * newval: value field for new object 19 | * e: an object to use if insertion needed (set to actual value used) 20 | */ 21 | 22 | #define sorted_insert(type, first, last, count, next, prev, value, newval, e) \ 23 | if (last == 0) { \ 24 | e->value = newval; \ 25 | first = e; \ 26 | last = e; \ 27 | e->next = 0; \ 28 | e->prev = 0; \ 29 | count++; \ 30 | } else if (last->value < newval) { \ 31 | e->value = newval; \ 32 | last->next = e; \ 33 | e->prev = last; \ 34 | last = e; \ 35 | e->next = 0; \ 36 | count++; \ 37 | } else if (first->value > newval) { \ 38 | e->value = newval; \ 39 | first->prev = e; \ 40 | e->next = first; \ 41 | first = e; \ 42 | e->prev = 0; \ 43 | count++; \ 44 | } else { \ 45 | type *p; \ 46 | for(p = first; p->value < newval; p = p->next) \ 47 | ; \ 48 | if (p->value > newval) { \ 49 | e->value = newval; \ 50 | p = p->prev; \ 51 | p->next->prev = e; \ 52 | e->next = p->next; \ 53 | p->next = e; \ 54 | e->prev = p; \ 55 | count++; \ 56 | } else { \ 57 | e = p; \ 58 | } \ 59 | } 60 | 61 | 62 | /* 63 | * double linked-list deletion 64 | */ 65 | #define dll_unlink(p, first, last, next, prev, count) { \ 66 | if (p->prev == 0) { \ 67 | first = p->next; \ 68 | } else { \ 69 | p->prev->next = p->next; \ 70 | } \ 71 | if (p->next == 0) { \ 72 | last = p->prev; \ 73 | } else { \ 74 | p->next->prev = p->prev; \ 75 | } \ 76 | count--; \ 77 | } 78 | 79 | 80 | #ifdef FAST_AND_LOOSE 81 | extern sm_element *sm_element_freelist; 82 | extern sm_row *sm_row_freelist; 83 | extern sm_col *sm_col_freelist; 84 | 85 | #define sm_element_alloc(newobj) \ 86 | if (sm_element_freelist == NIL(sm_element)) { \ 87 | newobj = ALLOC(sm_element, 1); \ 88 | } else { \ 89 | newobj = sm_element_freelist; \ 90 | sm_element_freelist = sm_element_freelist->next_col; \ 91 | } \ 92 | newobj->user_word = NIL(char); \ 93 | 94 | #define sm_element_free(e) \ 95 | (e->next_col = sm_element_freelist, sm_element_freelist = e) 96 | 97 | #else 98 | 99 | #define sm_element_alloc(newobj) \ 100 | newobj = ALLOC(sm_element, 1); \ 101 | newobj->user_word = NIL(char); 102 | #define sm_element_free(e) \ 103 | FREE(e) 104 | #endif 105 | 106 | 107 | extern void sm_row_remove_element(); 108 | extern void sm_col_remove_element(); 109 | 110 | /* LINTLIBRARY */ 111 | -------------------------------------------------------------------------------- /bench/espresso/stdlib.h: -------------------------------------------------------------------------------- 1 | /* ANSI Compatible stdlib.h stub */ 2 | 3 | #ifndef __cplusplus 4 | 5 | #include 6 | 7 | #ifndef ultrix4 8 | extern double atof(const char *); 9 | extern int atoi(const char *); 10 | extern long atol(const char *); 11 | extern void abort(void); 12 | extern void *calloc(size_t, size_t); 13 | extern void exit(int); 14 | extern void free(void *); 15 | extern void *malloc(size_t); 16 | extern void *realloc(void *, size_t); 17 | extern char *getenv(const char *); 18 | #else 19 | extern double atof(const char *); 20 | extern int atoi(char *); 21 | extern long atol(char *); 22 | extern void abort(void); 23 | extern void *calloc(size_t, size_t); 24 | extern void exit(int); 25 | extern void free(void *); 26 | extern void *malloc(size_t); 27 | extern void *realloc(void *, size_t); 28 | extern char *getenv(char *); 29 | #endif 30 | 31 | /* should be in stdio.h */ 32 | extern void perror(const char *); 33 | 34 | #ifdef LINT 35 | #undef putc 36 | #endif 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /bench/espresso/utility.c: -------------------------------------------------------------------------------- 1 | /* LINTLIBRARY */ 2 | #include "espresso.h" 3 | #include "copyright.h" 4 | #include "port.h" 5 | #include "utility.h" 6 | 7 | #ifdef IBM_WATC /* IBM Waterloo-C compiler (same as bsd 4.2) */ 8 | #ifndef BSD 9 | #define BSD 10 | #endif 11 | #ifndef void 12 | #define void int 13 | #endif 14 | #endif 15 | 16 | #ifdef ultrix 17 | #ifndef BSD 18 | #define BSD 19 | #endif 20 | #endif 21 | 22 | #ifdef hpux 23 | #ifndef UNIX50 24 | #define UNIX50 25 | #endif 26 | #endif 27 | 28 | #ifdef aiws 29 | #ifndef UNIX10 30 | #define UNIX10 31 | #endif 32 | #endif 33 | 34 | #ifdef vms /* VAX/C compiler -- times() with 100 HZ clock */ 35 | #ifndef UNIX100 36 | #define UNIX100 37 | #endif 38 | #endif 39 | 40 | /* default */ 41 | #if !defined(BSD) && !defined(UNIX10) && !defined(UNIX60) && !defined(UNIX100) && !defined(UNIX50) && !defined(_WIN32) 42 | #define UNIX10 43 | #endif 44 | 45 | #ifdef BSD 46 | #include 47 | #include 48 | #endif 49 | 50 | #ifdef UNIX10 51 | #include 52 | #endif 53 | 54 | #ifdef UNIX50 55 | #include 56 | #endif 57 | 58 | #ifdef UNIX60 59 | #include 60 | #endif 61 | 62 | #ifdef UNIX100 63 | #include 64 | #endif 65 | 66 | #ifdef _MSC_VER 67 | #include 68 | #include 69 | #endif 70 | 71 | /* 72 | * util_cpu_time -- return a long which represents the elapsed processor 73 | * time in milliseconds since some constant reference 74 | */ 75 | long 76 | util_cpu_time() 77 | { 78 | long t = 0; 79 | 80 | #ifdef _MSC_VER 81 | static uint64_t frec = 0; 82 | if (frec == 0) 83 | { 84 | LARGE_INTEGER val; 85 | BOOL ok = QueryPerformanceFrequency(&val); 86 | assert(ok); 87 | frec = val.QuadPart / 1000; 88 | } 89 | LARGE_INTEGER val; 90 | BOOL ok = QueryPerformanceCounter(&val); 91 | assert(ok); 92 | t = val.QuadPart / frec; 93 | #endif 94 | 95 | #ifdef BSD 96 | struct rusage rusage; 97 | (void) getrusage(RUSAGE_SELF, &rusage); 98 | t = (long) rusage.ru_utime.tv_sec*1000 + rusage.ru_utime.tv_usec/1000; 99 | #endif 100 | 101 | #ifdef IBMPC 102 | long ltime; 103 | (void) time(<ime); 104 | t = ltime * 1000; 105 | #endif 106 | 107 | #ifdef UNIX10 /* times() with 10 Hz resolution */ 108 | struct tms buffer; 109 | (void) times(&buffer); 110 | t = buffer.tms_utime * 100; 111 | #endif 112 | 113 | #ifdef UNIX50 /* times() with 50 Hz resolution */ 114 | struct tms buffer; 115 | times(&buffer); 116 | t = buffer.tms_utime * 20; 117 | #endif 118 | 119 | #ifdef UNIX60 /* times() with 60 Hz resolution */ 120 | struct tms buffer; 121 | times(&buffer); 122 | t = buffer.tms_utime * 16.6667; 123 | #endif 124 | 125 | #ifdef UNIX100 126 | struct tms buffer; /* times() with 100 Hz resolution */ 127 | times(&buffer); 128 | t = buffer.tms_utime * 10; 129 | #endif 130 | 131 | return t; 132 | } 133 | 134 | 135 | /* 136 | * util_print_time -- massage a long which represents a time interval in 137 | * milliseconds, into a string suitable for output 138 | * 139 | * Hack for IBM/PC -- avoids using floating point 140 | */ 141 | 142 | char * 143 | util_print_time(t) 144 | long t; 145 | { 146 | static char s[40]; 147 | 148 | //(void) sprintf(s, "%ld.%02ld sec", 0/1000, (0%1000)/10); 149 | (void) sprintf(s, "%ld.%03ld sec", t/1000, (t%1000)); 150 | return s; 151 | } 152 | 153 | 154 | /* 155 | * util_strsav -- save a copy of a string 156 | */ 157 | char * 158 | util_strsav(s) 159 | char *s; 160 | { 161 | return strcpy(ALLOC(char, strlen(s)+1), s); 162 | } 163 | -------------------------------------------------------------------------------- /bench/espresso/utility.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILITY_H 2 | #define UTILITY_H 3 | 4 | #include 5 | #include 6 | //#include 7 | 8 | /* 9 | * assumes the memory manager is libmm.a 10 | * - allows malloc(0) or realloc(obj, 0) 11 | * - catches out of memory (and calls MMout_of_memory()) 12 | * - catch free(0) and realloc(0, size) in the macros 13 | */ 14 | #define NIL(type) ((type *) 0) 15 | 16 | #ifdef BWGC 17 | #define ALLOC(type, num) \ 18 | ((type *) gc_malloc(sizeof(type) * ((num)==0?1:(num)))) 19 | #define REALLOC(type, obj, num) \ 20 | (obj) ? ((type *) gc_realloc((char *) obj, sizeof(type) * ((num)==0?1:(num)))) : \ 21 | ((type *) gc_malloc(sizeof(type) * ((num)==0?1:(num)))) 22 | #elif defined(CUSTOM_MALLOC) 23 | #define ALLOC(type, num) \ 24 | ((type *) CUSTOM_MALLOC(sizeof(type) * (num))) 25 | #define REALLOC(type, obj, num) \ 26 | (obj) ? ((type *) CUSTOM_REALLOC((char *) obj, sizeof(type) * (num))) : \ 27 | ((type *) CUSTOM_MALLOC(sizeof(type) * (num))) 28 | #else 29 | #include 30 | #define ALLOC(type, num) \ 31 | ((type *) malloc(sizeof(type) * (num))) 32 | #define REALLOC(type, obj, num) \ 33 | (obj) ? ((type *) realloc((char *) obj, sizeof(type) * (num))) : \ 34 | ((type *) malloc(sizeof(type) * (num))) 35 | #endif 36 | 37 | #ifdef IGNOREFREE 38 | #define FREE(obj) \ 39 | {}; 40 | #elif defined(CUSTOM_FREE) 41 | #define FREE(obj) \ 42 | if ((obj)) { (void) CUSTOM_FREE((char *) (obj)); (obj) = 0; } 43 | #else 44 | #define FREE(obj) \ 45 | if ((obj)) { (void) free((char *) (obj)); (obj) = 0; } 46 | #endif 47 | 48 | #include "ansi.h" 49 | 50 | EXTERN long util_cpu_time 51 | NULLARGS; 52 | EXTERN char *util_path_search 53 | ARGS((char *program)); 54 | EXTERN char *util_file_search 55 | ARGS((char *file, char *path, char *mode)); 56 | EXTERN int util_pipefork 57 | ARGS((char **argv, FILE **toCommand, FILE **fromCommand, int *pid)); 58 | EXTERN int util_csystem 59 | ARGS((char *command)); 60 | EXTERN char *util_print_time 61 | ARGS((long t)); 62 | EXTERN char *util_strsav 63 | ARGS((char *ptr)); 64 | EXTERN char *util_tilde_expand 65 | ARGS((char *filename)); 66 | EXTERN char *util_tilde_compress 67 | ARGS((char *filename)); 68 | EXTERN void util_register_user 69 | ARGS((char *user, char *directory)); 70 | 71 | #ifndef NIL_FN 72 | #define NIL_FN(type) ((type (*)()) 0) 73 | #endif /* NIL_FN */ 74 | 75 | #ifndef MAX 76 | #define MAX(a,b) ((a) > (b) ? (a) : (b)) 77 | #endif /* MAX */ 78 | #ifndef MIN 79 | #define MIN(a,b) ((a) < (b) ? (a) : (b)) 80 | #endif /* MIN */ 81 | #ifndef ABS 82 | #define ABS(a) ((a) > 0 ? (a) : -(a)) 83 | #endif /* ABS */ 84 | 85 | 86 | #ifdef lint 87 | #undef ALLOC /* allow for lint -h flag */ 88 | #undef REALLOC 89 | #define ALLOC(type, num) (((type *) 0) + (num)) 90 | #define REALLOC(type, obj, num) ((obj) + (num)) 91 | #endif /* lint */ 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /bench/glibc-bench/README.md: -------------------------------------------------------------------------------- 1 | Allocation benchmarks for the glibc library. 2 | Originals at: 3 | 4 | ``` 5 | Benchmark malloc and free functions. 6 | Copyright (C) 2013-2021 Free Software Foundation, Inc. 7 | This file is part of the GNU C Library. 8 | 9 | The GNU C Library is free software; you can redistribute it and/or 10 | modify it under the terms of the GNU Lesser General Public 11 | License as published by the Free Software Foundation; either 12 | version 2.1 of the License, or (at your option) any later version. 13 | 14 | The GNU C Library is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | Lesser General Public License for more details. 18 | 19 | You should have received a copy of the GNU Lesser General Public 20 | License along with the GNU C Library; if not, see 21 | . 22 | ``` 23 | -------------------------------------------------------------------------------- /bench/larson/README.md: -------------------------------------------------------------------------------- 1 | Test driver for memory allocators 2 | Author: Paul Larson, palarson@microsoft.com 3 | 4 | Updated to support C++14 sized deallocation with CPP. 5 | -------------------------------------------------------------------------------- /bench/malloc-large/README.md: -------------------------------------------------------------------------------- 1 | Test allocation of large blocks between 5 and 25 MiB with up to 20 live at any time. 2 | Provided by Leonid Stolyarov (@Lnd-stoL) in issue [447](https://github.com/microsoft/mimalloc/issues/447) and modified by Daan Leijen. 3 | 4 | The older benchmark (`malloc-large-old.cpp`) was supplied by Danila Kutenin (@danlark1) and modified by Daan Leijen. 5 | -------------------------------------------------------------------------------- /bench/malloc-large/malloc-large-old.cpp: -------------------------------------------------------------------------------- 1 | // Benchmark supplied by Danila Kutenin (danlark1 @github) and modified by Daan Leijen 2 | #include 3 | #include 4 | #include 5 | 6 | const size_t N = 5000; 7 | 8 | void Foo() { 9 | for (size_t i = 0; i < N; ++i) { 10 | size_t sz = 1ull << 21; 11 | std::unique_ptr a(new char[sz]); 12 | for(size_t k = 0; k < sz; k++) { a[k] = (char)k; } 13 | } 14 | } 15 | 16 | int main() { 17 | std::vector thrs; 18 | for (size_t i = 0; i < 1; ++i) { 19 | thrs.emplace_back(Foo); 20 | } 21 | for (auto&& thr : thrs) { 22 | thr.join(); 23 | } 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /bench/malloc-large/malloc-large.cpp: -------------------------------------------------------------------------------- 1 | // Test allocation large blocks between 5 and 25 MiB with up to 20 live at any time. 2 | // Provided by Leonid Stolyarov in issue #447 and modified by Daan Leijen. 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | static constexpr int kNumBuffers = 20; 10 | static constexpr size_t kMinBufferSize = 5 * 1024 * 1024; 11 | static constexpr size_t kMaxBufferSize = 25 * 1024 * 1024; 12 | std::unique_ptr buffers[kNumBuffers]; 13 | 14 | //std::random_device rd; 15 | std::mt19937 gen(42); //rd()); 16 | std::uniform_int_distribution<> size_distribution(kMinBufferSize, kMaxBufferSize); 17 | std::uniform_int_distribution<> buf_number_distribution(0, kNumBuffers - 1); 18 | 19 | static constexpr int kNumIterations = 2000; 20 | const auto start = std::chrono::steady_clock::now(); 21 | for (int i = 0; i < kNumIterations; ++i) { 22 | int buffer_idx = buf_number_distribution(gen); 23 | size_t new_size = size_distribution(gen); 24 | buffers[buffer_idx] = std::make_unique(new_size); 25 | } 26 | const auto end = std::chrono::steady_clock::now(); 27 | const auto num_ms = std::chrono::duration_cast(end - start).count(); 28 | const auto us_per_allocation = std::chrono::duration_cast(end - start).count() / kNumIterations; 29 | //std::cout << kNumIterations << " allocations Done in " << num_ms << "ms." << std::endl; 30 | //std::cout << "Avg " << us_per_allocation << " us per allocation" << std::endl; 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /bench/mleak/README.md: -------------------------------------------------------------------------------- 1 | This is a test that creates threads that allocate a small long lived 2 | object and then terminates those threads doing this N times. 3 | Some allocators can "leak" a lot of memory doing this. This 4 | is not a typical program workload -- do not use this test as a benchmark! 5 | 6 | ``` 7 | MIT License 8 | 9 | Copyright (c) 2019 Microsoft Corporation, Daan Leijen. 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in all 19 | copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | SOFTWARE. 28 | ``` 29 | -------------------------------------------------------------------------------- /bench/mleak/mleak.c: -------------------------------------------------------------------------------- 1 | /* ---------------------------------------------------------------------------- 2 | Copyright (c) 2018,2019 Microsoft Research, Daan Leijen 3 | This is free software; you can redistribute it and/or modify it under the 4 | terms of the MIT license. 5 | -----------------------------------------------------------------------------*/ 6 | 7 | /* This is a test that creates threads that allocate a smallish long lived 8 | object and then terminates those threads doing this 10*N times. 9 | Some allocators can "leak" a lot of memory doing this. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | // > mleak [ITERATIONS=1] 19 | // 20 | // argument defaults 21 | #define THREADS (10) 22 | #define BASEITER (100) 23 | static int ITER = 10; // do ITER*BASEITER iterations 24 | 25 | #define ALLOC_WORDS (16) // allocate 16*sizof(void*) objects 26 | 27 | #define custom_alloc(n) malloc(n) 28 | #define custom_calloc(n,s) calloc(n,s) 29 | #define custom_free(p) free(p) 30 | 31 | // transfer pointer between threads 32 | #define TRANSFERS (THREADS*BASEITER) 33 | static volatile void* transfer[TRANSFERS]; 34 | 35 | static void run_os_threads(size_t nthreads, void (*entry)(intptr_t tid)); 36 | static void* atomic_exchange_ptr(volatile void** p, void* newval); 37 | 38 | static void leak(intptr_t tid) { 39 | intptr_t* p = custom_calloc(ALLOC_WORDS,sizeof(void*)); 40 | intptr_t i = (rand() % TRANSFERS); 41 | void* q = atomic_exchange_ptr(&transfer[i], p); 42 | custom_free(q); 43 | } 44 | 45 | static void test_leak(void) { 46 | srand(0x1ce4e5b9); 47 | for (int n = 0; n < (ITER*BASEITER); n++) { 48 | run_os_threads(THREADS, &leak); 49 | #ifndef NDEBUG 50 | if ((n + 1) % 10 == 0) { 51 | printf("- iterations left: %3d\n", ITER - (n + 1)); 52 | } 53 | #endif 54 | } 55 | for(int i = 0; i < TRANSFERS; i++) { 56 | custom_free(transfer[i]); 57 | } 58 | } 59 | 60 | int main(int argc, char** argv) { 61 | // > mleak [ITER] 62 | if (argc >= 2) { 63 | char* end; 64 | long n = (strtol(argv[1], &end, 10)); 65 | if (n > 0) ITER = n; 66 | } 67 | printf("Using %d threads with %d*%d iterations\n", THREADS, BASEITER, ITER); 68 | test_leak(); 69 | return 0; 70 | } 71 | 72 | 73 | static void (*thread_entry_fun)(intptr_t) = &leak; 74 | 75 | #ifdef _WIN32 76 | 77 | #include 78 | 79 | static DWORD WINAPI thread_entry(LPVOID param) { 80 | thread_entry_fun((intptr_t)param); 81 | return 0; 82 | } 83 | 84 | static void run_os_threads(size_t nthreads, void (*fun)(intptr_t)) { 85 | thread_entry_fun = fun; 86 | DWORD* tids = (DWORD*)custom_calloc(nthreads,sizeof(DWORD)); 87 | HANDLE* thandles = (HANDLE*)custom_calloc(nthreads,sizeof(HANDLE)); 88 | for (uintptr_t i = 0; i < nthreads; i++) { 89 | thandles[i] = CreateThread(0, 4096, &thread_entry, (void*)(i), 0, &tids[i]); 90 | } 91 | for (size_t i = 0; i < nthreads; i++) { 92 | WaitForSingleObject(thandles[i], INFINITE); 93 | } 94 | for (size_t i = 0; i < nthreads; i++) { 95 | CloseHandle(thandles[i]); 96 | } 97 | custom_free(tids); 98 | custom_free(thandles); 99 | } 100 | 101 | static void* atomic_exchange_ptr(volatile void** p, void* newval) { 102 | #if (INTPTR_MAX == INT32_MAX) 103 | return (void*)InterlockedExchange((volatile LONG*)p, (LONG)newval); 104 | #else 105 | return (void*)InterlockedExchange64((volatile LONG64*)p, (LONG64)newval); 106 | #endif 107 | } 108 | 109 | #else 110 | 111 | #include 112 | 113 | static void* thread_entry(void* param) { 114 | thread_entry_fun((uintptr_t)param); 115 | return NULL; 116 | } 117 | 118 | static void run_os_threads(size_t nthreads, void (*fun)(intptr_t)) { 119 | thread_entry_fun = fun; 120 | pthread_t* threads = (pthread_t*)custom_calloc(nthreads,sizeof(pthread_t)); 121 | memset(threads, 0, sizeof(pthread_t) * nthreads); 122 | //pthread_setconcurrency(nthreads); 123 | for (uintptr_t i = 0; i < nthreads; i++) { 124 | pthread_create(&threads[i], NULL, &thread_entry, (void*)i); 125 | } 126 | for (size_t i = 0; i < nthreads; i++) { 127 | pthread_join(threads[i], NULL); 128 | } 129 | custom_free(threads); 130 | } 131 | 132 | #ifdef __cplusplus 133 | #include 134 | static void* atomic_exchange_ptr(volatile void** p, void* newval) { 135 | return std::atomic_exchange((volatile std::atomic*)p, newval); 136 | } 137 | #else 138 | #include 139 | static void* atomic_exchange_ptr(volatile void** p, void* newval) { 140 | return atomic_exchange((volatile _Atomic(void*)*)p, newval); 141 | } 142 | #endif 143 | 144 | #endif 145 | -------------------------------------------------------------------------------- /bench/mstress/README.md: -------------------------------------------------------------------------------- 1 | This is a stress test for allocators, using multiple threads and retaining 2 | some objects, re-allocating, and transferring objects between threads. This 3 | is not a typical program workload but uses a random size distribution -- do 4 | not use this test as a benchmark! 5 | 6 | ``` 7 | MIT License 8 | 9 | Copyright (c) 2019 Microsoft Corporation, Daan Leijen. 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in all 19 | copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | SOFTWARE. 28 | ``` 29 | -------------------------------------------------------------------------------- /bench/rbstress/README.md: -------------------------------------------------------------------------------- 1 | Original benchmark by Sam Saffron at . 2 | Modified by Daan Leijen to allocate not fully random but in X size classes. 3 | 4 | ``` 5 | Copyright (c) 2013 Sam Saffron 6 | 7 | MIT License 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining 10 | a copy of this software and associated documentation files (the 11 | "Software"), to deal in the Software without restriction, including 12 | without limitation the rights to use, copy, modify, merge, publish, 13 | distribute, sublicense, and/or sell copies of the Software, and to 14 | permit persons to whom the Software is furnished to do so, subject to 15 | the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be 18 | included in all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | ``` 28 | -------------------------------------------------------------------------------- /bench/rbstress/stress_mem.rb: -------------------------------------------------------------------------------- 1 | @retained = [] 2 | 3 | STRING_UNIT=10 4 | STRING_SIZES=5 5 | LARGE_UNIT=1000 6 | LARGE_CHUNK_SIZES = 100 7 | SEED=1 8 | RAND = Random.new(SEED) 9 | 10 | 11 | def stress(allocate_count, retain_count, chunk_size) 12 | chunk = [] 13 | while retain_count > 0 || allocate_count > 0 14 | if retain_count == 0 || (RAND.rand < 0.5 && allocate_count > 0) 15 | chunk << " " * (STRING_UNIT*RAND.rand(STRING_SIZES)) 16 | allocate_count -= 1 17 | if chunk.length > chunk_size 18 | chunk = [" " * LARGE_UNIT * LARGE_CHUNK_SIZES] 19 | end 20 | else 21 | @retained << " " * (STRING_UNIT*RAND.rand(STRING_SIZES)) 22 | retain_count -= 1 23 | end 24 | end 25 | end 26 | 27 | start = Time.now 28 | threads = ARGV[0].to_i 29 | if (threads==0) then threads = 1; end 30 | puts "run with #{threads} threads" 31 | 32 | (0...threads).map do 33 | Thread.new do 34 | stress(12_000_000/threads, 600_000/threads, 200_000/threads) 35 | end 36 | end.each(&:join) 37 | 38 | duration = (Time.now - start).to_f 39 | 40 | # _, size = `ps ax -o pid,rss | grep -E "^[[:space:]]*#{$$}"`.strip.split.map(&:to_i) 41 | # puts "#{size},#{duration}" 42 | puts "duration: #{duration}" 43 | -------------------------------------------------------------------------------- /bench/rptest/README.md: -------------------------------------------------------------------------------- 1 | From by Mattias Jannson as 2 | a benchmark for the rpmalloc allocator. 3 | 4 | Modified to touch the memory that is allocated. 5 | 6 | ``` 7 | This is free and unencumbered software released into the public domain. 8 | 9 | Anyone is free to copy, modify, publish, use, compile, sell, or 10 | distribute this software, either in source code form or as a compiled 11 | binary, for any purpose, commercial or non-commercial, and by any 12 | means. 13 | 14 | In jurisdictions that recognize copyright laws, the author or authors 15 | of this software dedicate any and all copyright interest in the 16 | software to the public domain. We make this dedication for the benefit 17 | of the public at large and to the detriment of our heirs and 18 | successors. We intend this dedication to be an overt act of 19 | relinquishment in perpetuity of all present and future rights to this 20 | software under copyright law. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 25 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 26 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 27 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 28 | OTHER DEALINGS IN THE SOFTWARE. 29 | 30 | For more information, please refer to 31 | 32 | 33 | For a commercial license including support SLA contact Rampant Pixels at 34 | corporate@rampantpixels.com 35 | 36 | Or, if you so choose, you can also use this software under the MIT license. 37 | 38 | 39 | The MIT License (MIT) 40 | 41 | Copyright (c) 2017 Rampant Pixels AB 42 | 43 | Permission is hereby granted, free of charge, to any person obtaining a copy 44 | of this software and associated documentation files (the "Software"), to deal 45 | in the Software without restriction, including without limitation the rights 46 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 47 | copies of the Software, and to permit persons to whom the Software is 48 | furnished to do so, subject to the following conditions: 49 | 50 | The above copyright notice and this permission notice shall be included in 51 | all copies or substantial portions of the Software. 52 | 53 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 54 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 55 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 56 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 57 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 58 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 59 | THE SOFTWARE. 60 | ``` 61 | -------------------------------------------------------------------------------- /bench/rptest/atomic.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #if defined( __x86_64__ ) || defined( _M_AMD64 ) || defined( _M_X64 ) || defined( _AMD64_ ) || defined( __arm64__ ) || defined( __aarch64__ ) 5 | # define ARCH_64BIT 1 6 | #else 7 | # define ARCH_64BIT 0 8 | #endif 9 | 10 | #ifdef _MSC_VER 11 | # define ALIGNED_STRUCT(name, alignment) __declspec(align(alignment)) struct name 12 | #else 13 | # define ALIGNED_STRUCT(name, alignment) struct __attribute__((__aligned__(alignment))) name 14 | #endif 15 | 16 | ALIGNED_STRUCT(atomicptr_t, 8) { 17 | void* nonatomic; 18 | }; 19 | typedef struct atomicptr_t atomicptr_t; 20 | 21 | static void* 22 | atomic_load_ptr(atomicptr_t* src) { 23 | return src->nonatomic; 24 | } 25 | 26 | static void 27 | atomic_store_ptr(atomicptr_t* dst, void* val) { 28 | dst->nonatomic = val; 29 | } 30 | 31 | ALIGNED_STRUCT(atomic32_t, 4) { 32 | int32_t nonatomic; 33 | }; 34 | typedef struct atomic32_t atomic32_t; 35 | 36 | static int32_t 37 | atomic_load32(atomic32_t* src) { 38 | return src->nonatomic; 39 | } 40 | 41 | static void 42 | atomic_store32(atomic32_t* dst, int32_t val) { 43 | dst->nonatomic = val; 44 | } 45 | 46 | static int32_t 47 | atomic_incr32(atomic32_t* val) { 48 | #ifdef _MSC_VER 49 | int32_t old = (int32_t)_InterlockedExchangeAdd((volatile long*)&val->nonatomic, 1); 50 | return (old + 1); 51 | #else 52 | return __sync_add_and_fetch(&val->nonatomic, 1); 53 | #endif 54 | } 55 | 56 | static int32_t 57 | atomic_add32(atomic32_t* val, int32_t add) { 58 | #ifdef _MSC_VER 59 | int32_t old = (int32_t)_InterlockedExchangeAdd((volatile long*)&val->nonatomic, add); 60 | return (old + add); 61 | #else 62 | return __sync_add_and_fetch(&val->nonatomic, add); 63 | #endif 64 | } 65 | 66 | static int 67 | atomic_cas_ptr(atomicptr_t* dst, void* val, void* ref) { 68 | #ifdef _MSC_VER 69 | # if ARCH_64BIT 70 | return (_InterlockedCompareExchange64((volatile long long*)&dst->nonatomic, 71 | (long long)val, (long long)ref) == (long long)ref) ? 1 : 0; 72 | # else 73 | return (_InterlockedCompareExchange((volatile long*)&dst->nonatomic, 74 | (long)val, (long)ref) == (long)ref) ? 1 : 0; 75 | # endif 76 | #else 77 | return __sync_bool_compare_and_swap(&dst->nonatomic, ref, val); 78 | #endif 79 | } 80 | 81 | #undef ARCH_64BIT 82 | #undef ALIGNED_STRUCT 83 | -------------------------------------------------------------------------------- /bench/rptest/benchmark.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #ifndef __APPLE__ 5 | # include 6 | #endif 7 | 8 | int 9 | benchmark_initialize() { 10 | return 0; 11 | } 12 | 13 | int 14 | benchmark_finalize(void) { 15 | return 0; 16 | } 17 | 18 | int 19 | benchmark_thread_initialize(void) { 20 | return 0; 21 | } 22 | 23 | int 24 | benchmark_thread_finalize(void) { 25 | return 0; 26 | } 27 | 28 | void* 29 | benchmark_malloc(size_t alignment, size_t size) { 30 | // memset/calloc to ensure all memory is touched! 31 | if (alignment != 0) { 32 | #if defined(__MACH__) 33 | void* ptr = NULL; 34 | posix_memalign(&ptr, alignment, size); 35 | #else 36 | void* ptr = memalign(alignment, size); 37 | #endif 38 | if (ptr != NULL) memset(ptr,0xCD,size); 39 | return ptr; 40 | } 41 | else { 42 | return calloc(1,size); 43 | } 44 | } 45 | 46 | extern void 47 | benchmark_free(void* ptr) { 48 | free(ptr); 49 | } 50 | 51 | const char* 52 | benchmark_name(void) { 53 | return "crt"; 54 | } 55 | 56 | void 57 | benchmark_thread_collect(void) { 58 | } 59 | -------------------------------------------------------------------------------- /bench/rptest/thread.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #ifdef _MSC_VER 5 | # define ATTRIBUTE_NORETURN 6 | #else 7 | # define ATTRIBUTE_NORETURN __attribute__((noreturn)) 8 | #endif 9 | 10 | #ifdef _WIN32 11 | # include 12 | # include 13 | 14 | static unsigned __stdcall 15 | thread_entry(void* argptr) { 16 | thread_arg* arg = argptr; 17 | arg->fn(arg->arg); 18 | return 0; 19 | } 20 | 21 | #else 22 | # include 23 | # include 24 | # include 25 | 26 | static void* 27 | thread_entry(void* argptr) { 28 | thread_arg* arg = argptr; 29 | arg->fn(arg->arg); 30 | return 0; 31 | } 32 | 33 | #endif 34 | 35 | uintptr_t 36 | thread_run(thread_arg* arg) { 37 | #ifdef _WIN32 38 | return _beginthreadex(0, 0, thread_entry, arg, 0, 0); 39 | #else 40 | pthread_t id = 0; 41 | int err = pthread_create(&id, 0, thread_entry, arg); 42 | if (err) 43 | return 0; 44 | return (uintptr_t)id; 45 | #endif 46 | } 47 | 48 | void ATTRIBUTE_NORETURN 49 | thread_exit(void* value) { 50 | #ifdef _WIN32 51 | 52 | #else 53 | pthread_exit(value); 54 | #endif 55 | } 56 | 57 | void 58 | thread_join(uintptr_t handle) { 59 | if (!handle) 60 | return; 61 | #ifdef _WIN32 62 | WaitForSingleObject((HANDLE)handle, INFINITE); 63 | CloseHandle((HANDLE)handle); 64 | #else 65 | void* result = 0; 66 | pthread_join((pthread_t)handle, &result); 67 | #endif 68 | } 69 | 70 | void 71 | thread_sleep(int milliseconds) { 72 | #ifdef _WIN32 73 | SleepEx(milliseconds, 1); 74 | #else 75 | struct timespec ts; 76 | ts.tv_sec = milliseconds / 1000; 77 | ts.tv_nsec = (long)(milliseconds % 1000) * 1000000L; 78 | nanosleep(&ts, 0); 79 | #endif 80 | } 81 | 82 | void 83 | thread_yield(void) { 84 | #ifdef _WIN32 85 | Sleep(0); 86 | _ReadWriteBarrier(); 87 | #else 88 | sched_yield(); 89 | __sync_synchronize(); 90 | #endif 91 | } 92 | 93 | void 94 | thread_fence(void) { 95 | #ifdef _WIN32 96 | _ReadWriteBarrier(); 97 | #else 98 | __sync_synchronize(); 99 | #endif 100 | } 101 | -------------------------------------------------------------------------------- /bench/rptest/thread.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | 5 | struct thread_arg { 6 | void(*fn)(void*); 7 | void* arg; 8 | }; 9 | typedef struct thread_arg thread_arg; 10 | 11 | extern uintptr_t 12 | thread_run(thread_arg* arg); 13 | 14 | extern void 15 | thread_exit(void* value); 16 | 17 | extern void 18 | thread_join(uintptr_t handle); 19 | 20 | extern void 21 | thread_sleep(int milliseconds); 22 | 23 | extern void 24 | thread_yield(void); 25 | 26 | extern void 27 | thread_fence(void); 28 | -------------------------------------------------------------------------------- /bench/rptest/timer.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #if defined(_WIN32) 5 | # include 6 | #elif defined(__APPLE__) 7 | # include 8 | static mach_timebase_info_data_t _time_info; 9 | static void 10 | absolutetime_to_nanoseconds(uint64_t mach_time, uint64_t* clock) { 11 | *clock = (uint64_t)(mach_time * _time_info.numer / _time_info.denom); 12 | } 13 | #else 14 | # include 15 | #endif 16 | 17 | static uint64_t _time_freq; 18 | 19 | int 20 | timer_initialize(void) { 21 | #if defined(_WIN32) 22 | uint64_t unused; 23 | if (!QueryPerformanceFrequency((LARGE_INTEGER*)&_time_freq) || 24 | !QueryPerformanceCounter((LARGE_INTEGER*)&unused)) 25 | return -1; 26 | #elif defined(__APPLE__) 27 | if (mach_timebase_info(&_time_info)) 28 | return -1; 29 | _time_freq = 1000000000LL; 30 | #else 31 | struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 }; 32 | if (clock_gettime(CLOCK_MONOTONIC, &ts)) 33 | return -1; 34 | _time_freq = 1000000000LL; 35 | #endif 36 | return 0; 37 | } 38 | 39 | uint64_t 40 | timer_current(void) { 41 | #if defined(_WIN32) 42 | uint64_t curclock; 43 | QueryPerformanceCounter((LARGE_INTEGER*)&curclock); 44 | return curclock; 45 | #elif defined(__APPLE__) 46 | uint64_t curclock = 0; 47 | absolutetime_to_nanoseconds(mach_absolute_time(), &curclock); 48 | return curclock; 49 | #else 50 | struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 }; 51 | clock_gettime(CLOCK_MONOTONIC, &ts); 52 | return ((uint64_t)ts.tv_sec * 1000000000LL) + (uint64_t)ts.tv_nsec; 53 | #endif 54 | } 55 | 56 | uint64_t 57 | timer_ticks_per_second(void) { 58 | return _time_freq; 59 | } 60 | 61 | double 62 | timer_ticks_to_seconds(uint64_t ticks) { 63 | uint64_t tps = timer_ticks_per_second(); 64 | return (double)ticks / (double)tps; 65 | } 66 | -------------------------------------------------------------------------------- /bench/rptest/timer.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | extern int 5 | timer_initialize(void); 6 | 7 | extern uint64_t 8 | timer_current(void); 9 | 10 | extern uint64_t 11 | timer_ticks_per_second(void); 12 | 13 | extern double 14 | timer_ticks_to_seconds(uint64_t ticks); 15 | -------------------------------------------------------------------------------- /bench/security/32_byte_memcpy_overflow.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | // This test checks for things like https://github.com/microsoft/snmalloc/blob/main/docs/security/GuardedMemcpy.md 7 | 8 | int main(void) { 9 | const char c[ALLOCATION_SIZE + 32] = {0}; 10 | char *p = malloc_noinline(ALLOCATION_SIZE); 11 | memcpy_noinline(p, c, sizeof(c)); 12 | 13 | NOT_CAUGHT(); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /bench/security/32_byte_memcpy_underflow.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | // This test checks for things like https://github.com/microsoft/snmalloc/blob/main/docs/security/GuardedMemcpy.md 7 | 8 | int main(void) { 9 | const char c[ALLOCATION_SIZE] = {0}; 10 | char *p = malloc_noinline(ALLOCATION_SIZE); 11 | memcpy_noinline(p - 32, c, sizeof(c)); 12 | 13 | NOT_CAUGHT(); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /bench/security/32_byte_overflow.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main(void) { 7 | char *p = malloc_noinline(ALLOCATION_SIZE); 8 | p[ALLOCATION_SIZE - 1 + 32] ^= 'A'; // XOR is used to avoid the test having a 1/256 chance to fail 9 | free_noinline(p); 10 | 11 | NOT_CAUGHT(); 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /bench/security/32_byte_underflow.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main(void) { 7 | char *p = malloc_noinline(ALLOCATION_SIZE); 8 | p[-32] ^= 'A'; // XOR is used to avoid the test having a 1/256 chance to fail 9 | free_noinline(p); 10 | 11 | NOT_CAUGHT(); 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /bench/security/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB MY_SECURITY_TESTS 2 | "*.c" 3 | ) 4 | 5 | macro (add_security_test test_name test_file allocation_size) 6 | add_executable(${test_name} ${test_file}) 7 | target_compile_options(${test_name} PRIVATE 8 | -Wno-free-nonheap-object 9 | -fno-inline 10 | -fno-builtin-inline 11 | -fno-inline-small-functions 12 | -DALLOCATION_SIZE=${allocation_size}) 13 | endmacro () 14 | 15 | foreach(f ${MY_SECURITY_TESTS}) 16 | get_filename_component (exe_name ${f} NAME_WE) 17 | message(STATUS "Compiling ${f} ${exe_name}") 18 | add_security_test("${exe_name}_small" ${f} 8) 19 | add_security_test("${exe_name}_medium" ${f} 4096) 20 | add_security_test("${exe_name}_large" ${f} 256*1024) 21 | endforeach() 22 | 23 | file(GLOB MY_SECURITY_TESTS_CPP 24 | "*.cc" 25 | ) 26 | foreach(f ${MY_SECURITY_TESTS_CPP}) 27 | get_filename_component (exe_name ${f} NAME_WE) 28 | message(STATUS "Compiling ${f} ${exe_name}") 29 | add_executable(${exe_name} ${f}) 30 | target_compile_options(${exe_name} PRIVATE -std=c++17 -fsized-deallocation -DALLOCATION_SIZE=4096) 31 | endforeach() 32 | -------------------------------------------------------------------------------- /bench/security/README.md: -------------------------------------------------------------------------------- 1 | # Security benchmarks 2 | 3 | This folder contains a bunch of simplistic security-related tests 4 | that can be used to validate some security properties. 5 | 6 | Having failing tests doesn't mean that a specific allocator is insecure, 7 | nor does having working one mean the opposite: 8 | 9 | - Some allocators don't want to trash performances for minor security gains. 10 | - Sometimes it's more efficient to make memory corruption harder or impossible 11 | to exploit than trying to detect them. For example, double-free detection 12 | isn't necessarily worth it when you have types isolation. 13 | - Being able to detect a dumb use-after-free doesn't mean that it's not trivial 14 | for an attacker to bypass the detection in more complex cases. 15 | 16 | In the words of the developer of a high-profile allocator: 17 | 18 | > I am very opinionated on what a secure allocator is. And anything an attacker 19 | can bypass is not worth implementing. Otherwise your allocator is slow and 20 | people will just replace it with faster less secure allocators. 21 | 22 | Testing for security properties is hard, so take those results with a grain of 23 | salt, and do make sure you understand what is being tested. 24 | -------------------------------------------------------------------------------- /bench/security/common.h: -------------------------------------------------------------------------------- 1 | #ifndef _MIMALLOC_BENCH_SECURITY_COMMON_H_ 2 | #define _MIMALLOC_BENCH_SECURITY_COMMON_H_ 3 | 4 | #ifndef ALLOCATION_SIZE 5 | #error Unspecified allocation size 6 | #endif 7 | 8 | #define NOT_CAUGHT() do { puts("NOT_CAUGHT"); fflush(stdout); } while ((0)); 9 | 10 | #if defined(_MSC_VER) 11 | #define NOINLINE __declspec(noinline) 12 | #elif defined(__INTEL_COMPILER) 13 | #define NOINLINE _Pragma("noinline") 14 | #else 15 | #define NOINLINE __attribute((noinline)) 16 | #endif 17 | 18 | NOINLINE 19 | void* memcpy_noinline(void* dest, const void* src, size_t n) { 20 | return memcpy(dest, src, n); 21 | } 22 | 23 | NOINLINE 24 | void* malloc_noinline(size_t size) { 25 | return malloc(size); 26 | } 27 | 28 | NOINLINE 29 | void free_noinline(void* ptr) { 30 | return free(ptr); 31 | } 32 | 33 | #endif //_MIMALLOC_BENCH_SECURITY_COMMON_H 34 | -------------------------------------------------------------------------------- /bench/security/delete_type_size_mismatch.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct s { 5 | size_t a, b, c, d, e, f, g, h, i; 6 | }; 7 | 8 | int main(void) { 9 | void *p = new char; 10 | struct s *q = (struct s *)p; 11 | delete q; 12 | 13 | puts("NOT_CAUGHT"); 14 | fflush(stdout); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /bench/security/double_free.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main() { 7 | void *p = malloc_noinline(ALLOCATION_SIZE); 8 | free_noinline(p); 9 | free_noinline(p); 10 | 11 | NOT_CAUGHT(); 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /bench/security/double_free_delayed.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main() { 7 | void *p = malloc_noinline(ALLOCATION_SIZE); 8 | free_noinline(p); 9 | 10 | for(int i=0; i<1024; i++) 11 | free_noinline(malloc_noinline(ALLOCATION_SIZE)); 12 | 13 | free_noinline(p); 14 | 15 | NOT_CAUGHT(); 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /bench/security/double_free_interleaved.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main() { 7 | void *p = malloc_noinline(ALLOCATION_SIZE); 8 | void *q = malloc_noinline(ALLOCATION_SIZE); 9 | free_noinline(p); 10 | free_noinline(q); 11 | free_noinline(p); 12 | 13 | NOT_CAUGHT(); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /bench/security/double_free_reuse.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main() 7 | { 8 | void *p = malloc_noinline(ALLOCATION_SIZE); 9 | printf("p = %p", p); 10 | free_noinline(p); 11 | free_noinline(p); 12 | 13 | for (size_t i = 0; i < 1024 * 256; i++) 14 | { 15 | void *q = malloc_noinline(ALLOCATION_SIZE); 16 | printf("q = %p", q); 17 | free_noinline(q); 18 | } 19 | 20 | NOT_CAUGHT(); 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /bench/security/double_free_single_reuse.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main() { 7 | void *p = malloc_noinline(ALLOCATION_SIZE); 8 | free_noinline(p); 9 | void *q = malloc_noinline(ALLOCATION_SIZE); 10 | free_noinline(p); 11 | free_noinline(q); 12 | 13 | NOT_CAUGHT(); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /bench/security/executable_heap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "common.h" 6 | 7 | const char* shellcode = "\x90\x90\x90\x90\xc3"; // nop, ..., ret on x86 8 | 9 | int main(void) { 10 | char *p = malloc_noinline(ALLOCATION_SIZE); 11 | memcpy(p, shellcode, sizeof(shellcode)); 12 | void(*fptr)(void) = (void(*)(void))p; 13 | fptr(); 14 | 15 | NOT_CAUGHT(); 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /bench/security/impossibly_large_malloc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main(void) { 7 | char *p = malloc_noinline(-2); 8 | if (p != NULL) { 9 | NOT_CAUGHT(); 10 | } 11 | free_noinline(p); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /bench/security/invalid_array_delete_char.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main(void) { 7 | char* a = new char; 8 | delete[] a; 9 | 10 | NOT_CAUGHT(); 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /bench/security/invalid_array_delete_string.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main(void) { 7 | std::string* a = new std::string; 8 | delete[] a; 9 | 10 | NOT_CAUGHT(); 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /bench/security/invalid_delete_array_char.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main(void) { 7 | char* a = new char[ALLOCATION_SIZE]; 8 | delete a; 9 | 10 | NOT_CAUGHT(); 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /bench/security/invalid_delete_array_string.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main(void) { 7 | std::string* a = new std::string[ALLOCATION_SIZE]; 8 | delete a; 9 | 10 | NOT_CAUGHT(); 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /bench/security/invalid_free.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main(void) { 7 | free_noinline((void *)1); 8 | 9 | NOT_CAUGHT(); 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /bench/security/invalid_free_alloca.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main(void) { 7 | free_noinline(alloca(ALLOCATION_SIZE)); 8 | 9 | NOT_CAUGHT(); 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /bench/security/invalid_free_close.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main(void) { 7 | char *p = malloc_noinline(ALLOCATION_SIZE); 8 | char* q = p + 4 * 1024; 9 | free_noinline(q); 10 | 11 | NOT_CAUGHT(); 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /bench/security/invalid_free_far.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main(void) { 7 | char *p = malloc_noinline(ALLOCATION_SIZE); 8 | char* q = p + 1024 * 1024 * 1024; 9 | free_noinline(q); 10 | 11 | NOT_CAUGHT(); 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /bench/security/invalid_free_stack.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main(void) { 7 | char p[ALLOCATION_SIZE]; 8 | free_noinline(p); 9 | 10 | NOT_CAUGHT(); 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /bench/security/invalid_free_unaligned.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main() { 7 | char *p = malloc_noinline(ALLOCATION_SIZE); 8 | free_noinline(p + 1); 9 | 10 | NOT_CAUGHT(); 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /bench/security/invalid_free_unaligned_multiple.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main() { 7 | char *p = malloc_noinline(ALLOCATION_SIZE); 8 | free_noinline(p + 8); 9 | 10 | NOT_CAUGHT(); 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /bench/security/malloc_reuse.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | /* This test checks that pointers aren't immediately re-used between 7 | * allocations. */ 8 | 9 | int main(void) { 10 | void *p = malloc_noinline(ALLOCATION_SIZE); 11 | void *q = p; 12 | free_noinline(p); 13 | 14 | p = malloc_noinline(ALLOCATION_SIZE); 15 | 16 | if (p == q) 17 | { 18 | NOT_CAUGHT(); 19 | } 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /bench/security/malloc_reuse_downsize.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | /* This test checks that pointers aren't immediately re-used between 7 | * an allocation and a smaller one. */ 8 | 9 | int main(void) { 10 | void *p = malloc_noinline(ALLOCATION_SIZE); 11 | void *q = p; 12 | free_noinline(p); 13 | 14 | p = malloc_noinline(ALLOCATION_SIZE / 2); 15 | 16 | if (p == q) 17 | { 18 | NOT_CAUGHT(); 19 | } 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /bench/security/one_byte_memcpy_overflow.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | // This test checks for things like https://github.com/microsoft/snmalloc/blob/main/docs/security/GuardedMemcpy.md 7 | 8 | int main(void) { 9 | const char c[ALLOCATION_SIZE + 1] = {0}; 10 | char *p = malloc_noinline(ALLOCATION_SIZE); 11 | memcpy_noinline(p, c, sizeof(c)); 12 | 13 | NOT_CAUGHT(); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /bench/security/one_byte_memcpy_underflow.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | // This test checks for things like https://github.com/microsoft/snmalloc/blob/main/docs/security/GuardedMemcpy.md 7 | 8 | int main(void) { 9 | const char c[ALLOCATION_SIZE] = {0}; 10 | char *p = malloc_noinline(ALLOCATION_SIZE); 11 | memcpy_noinline(p - 1, c, sizeof(c)); 12 | 13 | NOT_CAUGHT(); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /bench/security/one_byte_overflow.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main(void) { 7 | char *p = malloc_noinline(ALLOCATION_SIZE); 8 | p[ALLOCATION_SIZE] ^= 'A'; // XOR is used to avoid the test having a 1/256 chance to fail 9 | free_noinline(p); 10 | 11 | NOT_CAUGHT(); 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /bench/security/one_byte_underflow.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main(void) { 7 | char *p = malloc_noinline(ALLOCATION_SIZE); 8 | p[-1] ^= 'A'; // XOR is used to avoid the test having a 1/256 chance to fail 9 | free_noinline(p); 10 | 11 | NOT_CAUGHT(); 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /bench/security/one_mbyte_memcpy_overflow.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | // This test checks for things like https://github.com/microsoft/snmalloc/blob/main/docs/security/GuardedMemcpy.md 7 | 8 | int main(void) { 9 | const char c[ALLOCATION_SIZE + 1024 * 1024] = {0}; 10 | char *p = malloc_noinline(ALLOCATION_SIZE); 11 | memcpy_noinline(p, c, sizeof(c)); 12 | 13 | NOT_CAUGHT(); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /bench/security/one_mbyte_memcpy_underflow.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | // This test checks for things like https://github.com/microsoft/snmalloc/blob/main/docs/security/GuardedMemcpy.md 7 | 8 | int main(void) { 9 | const char c[ALLOCATION_SIZE] = {0}; 10 | char *p = malloc_noinline(ALLOCATION_SIZE); 11 | memcpy_noinline(p - 1024 * 1024, c, sizeof(c)); 12 | 13 | NOT_CAUGHT(); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /bench/security/one_mbyte_overflow.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main(void) { 7 | char *p = malloc_noinline(ALLOCATION_SIZE); 8 | p[ALLOCATION_SIZE - 1 + (1024 * 1024)] ^= 'A'; // XOR is used to avoid the test having a 1/256 chance to fail 9 | free_noinline(p); 10 | 11 | NOT_CAUGHT(); 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /bench/security/one_mbyte_underflow.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main(void) { 7 | char *p = malloc_noinline(ALLOCATION_SIZE); 8 | p[-(1024 * 1024)] ^= 'A'; // XOR is used to avoid the test having a 1/256 chance to fail 9 | free_noinline(p); 10 | 11 | NOT_CAUGHT(); 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /bench/security/read_zero_size.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main() { 7 | char *p = malloc_noinline(0); 8 | if (!p) { 9 | return 1; 10 | } 11 | putchar(*p); 12 | 13 | NOT_CAUGHT(); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /bench/security/read_zero_size_free.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main() { 7 | char *p = malloc_noinline(0); 8 | if (!p) { 9 | return 1; 10 | } 11 | putchar(*p); 12 | free_noinline(p); 13 | 14 | NOT_CAUGHT(); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /bench/security/realloc_reuse.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main(void) { 7 | char *p = malloc_noinline(8); 8 | char *q = p; 9 | realloc(p, 1024); 10 | 11 | if (p == q) 12 | { 13 | NOT_CAUGHT(); 14 | } 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /bench/security/write_after_free.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "common.h" 6 | 7 | int main(void) { 8 | char *p = malloc_noinline(ALLOCATION_SIZE); 9 | free_noinline(p); 10 | memset(p, 'A', ALLOCATION_SIZE); 11 | 12 | NOT_CAUGHT(); 13 | 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /bench/security/write_after_free_reuse.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "common.h" 6 | 7 | int main(void) { 8 | char *p = malloc_noinline(ALLOCATION_SIZE); 9 | free_noinline(p); 10 | memset(p, 'A', ALLOCATION_SIZE); 11 | 12 | for (size_t i=0; i< 1024 * 256; i++) 13 | free_noinline(malloc_noinline(ALLOCATION_SIZE)); 14 | 15 | NOT_CAUGHT(); 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /bench/security/write_zero_size.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main() { 7 | char *p = malloc_noinline(0); 8 | if (!p) { 9 | return 1; 10 | } 11 | *p = 'A'; 12 | 13 | NOT_CAUGHT(); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /bench/security/write_zero_size_free.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "common.h" 5 | 6 | int main() { 7 | char *p = malloc_noinline(0); 8 | if (!p) { 9 | return 1; 10 | } 11 | *p = 'A'; 12 | free_noinline(p); 13 | 14 | NOT_CAUGHT(); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /bench/security/zero_after_free.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "common.h" 6 | 7 | int main(void) { 8 | char *p = malloc_noinline(ALLOCATION_SIZE); 9 | memset(p, 'A', ALLOCATION_SIZE); 10 | free_noinline(p); 11 | 12 | for (int i=0; i< ALLOCATION_SIZE; i++) { 13 | if (p[i] != 0) { 14 | NOT_CAUGHT(); 15 | return 0; 16 | } 17 | } 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /bench/security/zero_on_malloc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "common.h" 6 | 7 | #define ITERATIONS 4096 8 | 9 | int main(void) { 10 | // Allocate many chunks, and fill them. 11 | // Do this incase the allocator randomizes new chunks 12 | char *allocations[ITERATIONS] = { 0 }; 13 | for (int i = 0; i < ITERATIONS; i++) { 14 | char *chunk = malloc_noinline(ALLOCATION_SIZE); 15 | memset(chunk, 'A', ALLOCATION_SIZE); 16 | allocations[i] = chunk; 17 | } 18 | 19 | for (int i = 0; i < ITERATIONS; i++) { 20 | free_noinline(allocations[i]); 21 | } 22 | 23 | char *p = malloc_noinline(ALLOCATION_SIZE); 24 | for (int i=0; i< ALLOCATION_SIZE; i++) { 25 | if (p[i] != 0) { 26 | NOT_CAUGHT(); 27 | return 0; 28 | } 29 | } 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /bench/shbench/readme.md: -------------------------------------------------------------------------------- 1 | The __shbench__ benchmark by [MicroQuill](http://www.microquill.com) as part of SmartHeap. 2 | 3 | Unfortunately we cannot distribute it here, so you need to download the source 4 | for [sh6bench](http://www.microquill.com/smartheap/shbench/bench.zip) (retrieved 2019-01-02) 5 | and [sh8bench](http://www.microquill.com/smartheap/SH8BENCH.zip) (retrieved 2019-01-02) 6 | and unzip them in this directory. 7 | 8 | After that, fire up your Unix prompt and patch the source to fit in our benchmark 9 | framework: 10 | ``` 11 | > dos2unix sh6bench.c 12 | > dos2unix sh6bench.patch 13 | > patch -p1 sh6bench.c sh6bench.patch 14 | ``` 15 | and 16 | ``` 17 | > dos2unix sh8bench.patch 18 | > dos2unix SH8BENCH.C 19 | > patch -p1 -o sh8bench-new.c SH8BENCH.C sh8bench.patch 20 | ``` 21 | 22 | This is done automatically by the `build-bench-env.sh` script. 23 | -------------------------------------------------------------------------------- /bench/shbench/sh6bench.patch: -------------------------------------------------------------------------------- 1 | 113c113,114 2 | < #include "smrtheap.h" 3 | --- 4 | > // #include "smrtheap.h" 5 | > 6 | 155c156 7 | < unsigned long ulCallCount = 1000; 8 | --- 9 | > unsigned long ulCallCount = 10000; 10 | 198c199,208 11 | < 12 | --- 13 | > #ifdef BENCH 14 | > fin = stdin; 15 | > fout = stdout; 16 | > unsigned int defaultThreadCount = GetNumProcessors(); 17 | > if (argc==2) { 18 | > char* end; 19 | > long l = strtol(argv[1],&end,10); 20 | > if (l > 0) defaultThreadCount = l; 21 | > } 22 | > #else 23 | 207c217 24 | < 25 | --- 26 | > #endif 27 | 223c233 28 | < unsigned uCPUs = promptAndRead("CPUs (0 for all)", 0, 'u'); 29 | --- 30 | > unsigned uCPUs = promptAndRead("CPUs (0 for all)", PROCS, 'u'); 31 | 256c266 32 | < uThreadCount = (int)promptAndRead("threads", GetNumProcessors(), 'u'); 33 | --- 34 | > uThreadCount = (int)promptAndRead("threads", defaultThreadCount, 'u'); 35 | 259a270,276 36 | > 37 | > if (uThreadCount==1) { 38 | > startCPU = clock(); 39 | > startTime = time(NULL); 40 | > doBench(NULL); 41 | > } 42 | > else { 43 | 277a295 44 | > } 45 | 301a320 46 | > exit(0); 47 | 341a361 48 | > char* p = mp[-1]; p[0] = 0; p[size-1] = 0; 49 | 389a410 50 | > #ifndef BENCH 51 | 397a419 52 | > #endif 53 | -------------------------------------------------------------------------------- /bench/shbench/sh8bench.patch: -------------------------------------------------------------------------------- 1 | 138c138 2 | < unsigned long ulIterations = 100000; 3 | --- 4 | > unsigned long ulIterations = 700000; 5 | 194c194,203 6 | < 7 | --- 8 | > #ifdef BENCH 9 | > fin = stdin; 10 | > fout = stdout; 11 | > unsigned int defaultThreadCount = GetNumProcessors(); 12 | > if (argc==2) { 13 | > char* end; 14 | > long l = strtol(argv[1],&end,10); 15 | > if (l != 0) defaultThreadCount = l; 16 | > } 17 | > #else 18 | 203c212 19 | < 20 | --- 21 | > #endif 22 | 218c227 23 | < ulThreadCount = promptAndRead("threads", ulThreadCount, 'u'); 24 | --- 25 | > ulThreadCount = promptAndRead("threads", defaultThreadCount, 'u'); 26 | 243c252 27 | < unsigned uCPUs = promptAndRead("CPUs (0 for all)", 0, 'u'); 28 | --- 29 | > unsigned uCPUs = promptAndRead("CPUs (0 for all)", GetNumProcessors(), 'u'); 30 | 542c551,552 31 | < else if (!(*mp++ = (char *)malloc(size))) 32 | --- 33 | > else { 34 | > if (!(*mp++ = (char *)malloc(size))) 35 | 546a557,558 36 | > char* p = mp[-1]; p[0] = 0; p[size-1] = 0; 37 | > } 38 | 579a592 39 | > #ifndef BENCH 40 | 587a601 41 | > #endif 42 | -------------------------------------------------------------------------------- /bench/xmalloc-test/README.md: -------------------------------------------------------------------------------- 1 | xmalloc-test.c: is also known as "malloc-test" 2 | 3 | Originally by C. Lever and D. Boreham, Christian Eder ( ederc@mathematik.uni-kl.de) for [xmalloc](https://github.com/ederc/xmalloc), 4 | and modified by Bradley C. Kuzmaul for SuperMalloc 5 | 6 | ``` 7 | * \author C. Lever and D. Boreham, Christian Eder ( ederc@mathematik.uni-kl.de ) 8 | * \date 2000 9 | * \brief Test file for xmalloc. This is a multi-threaded test system by 10 | * Lever and Boreham. It is first noted in their paper "malloc() 11 | * Performance in a Multithreaded Linux Environment", appeared at the 12 | * USENIX 2000 Annual Technical Conference: FREENIX Track. 13 | * This file is part of XMALLOC, licensed under the GNU General 14 | * Public License version 3. See COPYING for more information. 15 | ``` 16 | 17 | Random.h is based on lran2.h by Wolfram Gloger 1996 18 | -------------------------------------------------------------------------------- /bench/xmalloc-test/random.h: -------------------------------------------------------------------------------- 1 | // ======================================================= 2 | 3 | /* lran2.h 4 | * by Wolfram Gloger 1996. 5 | * 6 | * A small, portable pseudo-random number generator. 7 | */ 8 | 9 | #ifndef _LRAN2_H 10 | #define _LRAN2_H 11 | 12 | #define LRAN2_MAX 714025l /* constants for portable */ 13 | #define IA 1366l /* random number generator */ 14 | #define IC 150889l /* (see e.g. `Numerical Recipes') */ 15 | 16 | struct lran2_st { 17 | long x, y, v[97]; 18 | }; 19 | 20 | static void 21 | lran2_init(struct lran2_st* d, long seed) 22 | { 23 | long x; 24 | int j; 25 | 26 | x = (IC - seed) % LRAN2_MAX; 27 | if(x < 0) x = -x; 28 | for(j=0; j<97; j++) { 29 | x = (IA*x + IC) % LRAN2_MAX; 30 | d->v[j] = x; 31 | } 32 | d->x = (IA*x + IC) % LRAN2_MAX; 33 | d->y = d->x; 34 | } 35 | 36 | static 37 | long lran2(struct lran2_st* d) 38 | { 39 | int j = (d->y % 97); 40 | 41 | d->y = d->v[j]; 42 | d->x = (IA*d->x + IC) % LRAN2_MAX; 43 | d->v[j] = d->x; 44 | return d->y; 45 | } 46 | 47 | #undef IA 48 | #undef IC 49 | #endif 50 | -------------------------------------------------------------------------------- /bench/z3/test1.smt2: -------------------------------------------------------------------------------- 1 | 2 | (declare-fun x () (_ BitVec 16)) 3 | (declare-fun y () (_ BitVec 16)) 4 | (declare-fun z () (_ BitVec 16)) 5 | (declare-fun GCD () (_ BitVec 16)) 6 | 7 | (assert (= (bvmul ((_ zero_extend 16) x) ((_ zero_extend 16) GCD)) (_ bv300 32))) 8 | (assert (= (bvmul ((_ zero_extend 16) y) ((_ zero_extend 16) GCD)) (_ bv900 32))) 9 | (assert (= (bvmul ((_ zero_extend 16) z) ((_ zero_extend 16) GCD)) (_ bv333 32))) 10 | (maximize GCD) 11 | 12 | (check-sat) 13 | (get-model) 14 | -------------------------------------------------------------------------------- /doc/mimalloc-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daanx/mimalloc-bench/bf083fda3e12099a34876903ab6c05dccb8f1d89/doc/mimalloc-logo.png -------------------------------------------------------------------------------- /graph_many.py: -------------------------------------------------------------------------------- 1 | import re 2 | import sys 3 | import collections 4 | try: 5 | import numpy as np 6 | except ImportError: 7 | print('You need to install numpy.') 8 | sys.exit(1) 9 | try: 10 | import plotly.express as px 11 | except ImportError: 12 | print('You need to install plotly.express.') 13 | sys.exit(1) 14 | try: 15 | import kaleido 16 | except ImportError: 17 | print('You need to install kaleido.') 18 | sys.exit(1) 19 | 20 | if len(sys.argv) != 2: 21 | print('Usage: %s results.txt' % sys.argv[0]) 22 | print('Where results.txt is the output of the benchmark script. I.e.') 23 | print(' mimalloc-bench/out/bench/benchres.csv') 24 | print() 25 | print('The script is designed to visualise the results of running the main benchmark') 26 | print('script with multiple runs for each benchmark. For example running:') 27 | print(' ../../bench.sh -r=10 mi sn allt') 28 | print('from the mimalloc-bench/out/bench directory.') 29 | print() 30 | print('The script will create two graphs, one for time and one for memory.') 31 | print('The graphs will be saved as time.html, time.png and time.pdf, and') 32 | print('memory.html, memory.png and memory.pdf.') 33 | print() 34 | print('The graphs will be normalised by the mean time/memory for each benchmark.') 35 | print('The normalised time/memory uses a log scale.') 36 | sys.exit(1) 37 | 38 | parse_line = re.compile('^([^ ]+) +([^ ]+) +([0-9:.]+) +([0-9]+)') 39 | data = [] 40 | test_names = set() 41 | 42 | # read in the data 43 | with open(sys.argv[1]) as f: 44 | for l in f.readlines(): 45 | match = parse_line.search(l) 46 | if not match: 47 | continue 48 | test_name, alloc_name, time_string, memory = match.groups() 49 | time_split = time_string.split(':') 50 | time_taken = 0 51 | test_names.add(test_name) 52 | if len(time_split) == 2: 53 | time_taken = int(time_split[0]) * 60 + float(time_split[1]) 54 | else: 55 | time_taken = float(time_split[0]) 56 | data.append({"Benchmark":test_name, "Allocator":alloc_name, "Time":time_taken, "Memory":int(memory)}) 57 | 58 | # create a dictionary of means 59 | time_means = collections.defaultdict(float) 60 | memory_means = collections.defaultdict(float) 61 | for test_name in test_names: 62 | # calculate the mean 63 | time_means[test_name] = np.mean([d['Time'] for d in data if d['Benchmark'] == test_name]) 64 | memory_means[test_name] = np.mean([d['Memory'] for d in data if d['Benchmark'] == test_name]) 65 | 66 | # add normalised time and memory to each data point 67 | for d in data: 68 | d['Normalised Time'] = d['Time'] / time_means[d['Benchmark']] 69 | d['Normalised Memory'] = d['Memory'] / memory_means[d['Benchmark']] 70 | 71 | # create the graph for time 72 | fig = px.box(data, x="Benchmark", y="Normalised Time", color="Allocator", log_y=True) 73 | fig.update_xaxes(showgrid=True) 74 | fig.update_yaxes(title_text="Normalised Time (log(time/mean time))") 75 | fig.update_layout(boxgroupgap=0.6) 76 | fig.update_traces(line_width=0.5, marker_line_width=0.5, marker_size=2, marker_symbol='x-thin') 77 | fig.write_html(f"time.html") 78 | fig.write_image(f"time.png") 79 | fig.write_image(f"time.pdf") 80 | 81 | # create the graph for memory 82 | fig = px.box(data, x="Benchmark", y="Normalised Memory", color="Allocator", log_y=True) 83 | fig.update_xaxes(showgrid=True) 84 | fig.update_yaxes(title_text="Normalised Memory (log(memory/mean memory))") 85 | fig.update_layout(boxgroupgap=.6) 86 | fig.update_traces(line_width=0.5, marker_line_width=0.5, marker_size=2, marker_symbol='x-thin') 87 | fig.write_html(f"memory.html") 88 | fig.write_image(f"memory.png") 89 | fig.write_image(f"memory.pdf") -------------------------------------------------------------------------------- /graphs.py: -------------------------------------------------------------------------------- 1 | import re 2 | import sys 3 | import collections 4 | 5 | try: 6 | import pygal 7 | except ImportError: 8 | print('You need to install pygal.') 9 | sys.exit(1) 10 | 11 | if len(sys.argv) != 2: 12 | print('Usage: %s results.txt' % sys.argv[0]) 13 | sys.exit(1) 14 | 15 | parse_line = re.compile('^([^ ]+) +([^ ]+) +([0-9:.]+)') 16 | allocs = collections.defaultdict(lambda: collections.defaultdict(dict)) 17 | 18 | with open(sys.argv[1]) as f: 19 | for l in f.readlines(): 20 | match = parse_line.search(l) 21 | if not match: 22 | continue 23 | test_name, alloc_name, time_string = match.groups() 24 | time_split = time_string.split(':') 25 | time_taken = 0 26 | if len(time_split) == 2: 27 | time_taken = int(time_split[0]) * 60 + float(time_split[1]) 28 | else: 29 | time_taken = float(time_split[0]) 30 | allocs[test_name][alloc_name] = time_taken 31 | 32 | for test_name, results in allocs.items(): 33 | line_chart = pygal.Bar(logarithmic=True) 34 | line_chart.title = test_name + ' (in seconds)' 35 | for k, t in results.items(): 36 | line_chart.add(k, t) 37 | with open('out-' + test_name + '.svg', 'wb') as f: 38 | f.write(line_chart.render()) 39 | --------------------------------------------------------------------------------