├── .github └── workflows │ └── c-cpp.yml ├── .gitignore ├── Backtrace.hpp ├── GNUmakefile ├── LICENSE ├── README.md ├── cheap.h ├── cheap.mk ├── cheaper.mk ├── cheaper.py ├── common.hpp ├── docker ├── base-clang-13-stdlibcxx.dockerfile ├── base-clang-13.dockerfile └── base-gcc-10.dockerfile ├── examples ├── .gitignore ├── boostjson │ ├── Makefile │ ├── citm_catalog.json │ ├── src.hpp │ └── testboostjson.cpp ├── json │ ├── Makefile │ ├── citm_catalog.json │ ├── gsoc-2018.json │ ├── json.hpp │ └── testjson.cpp ├── rapidjson │ ├── Makefile │ ├── gsoc-2018.json │ ├── rapidjson │ │ ├── allocators.h │ │ ├── cursorstreamwrapper.h │ │ ├── document.h │ │ ├── encodedstream.h │ │ ├── encodings.h │ │ ├── error │ │ │ ├── en.h │ │ │ └── error.h │ │ ├── filereadstream.h │ │ ├── filewritestream.h │ │ ├── fwd.h │ │ ├── internal │ │ │ ├── biginteger.h │ │ │ ├── clzll.h │ │ │ ├── diyfp.h │ │ │ ├── dtoa.h │ │ │ ├── ieee754.h │ │ │ ├── itoa.h │ │ │ ├── meta.h │ │ │ ├── pow10.h │ │ │ ├── regex.h │ │ │ ├── stack.h │ │ │ ├── strfunc.h │ │ │ ├── strtod.h │ │ │ └── swap.h │ │ ├── istreamwrapper.h │ │ ├── memorybuffer.h │ │ ├── memorystream.h │ │ ├── msinttypes │ │ │ ├── inttypes.h │ │ │ └── stdint.h │ │ ├── ostreamwrapper.h │ │ ├── pointer.h │ │ ├── prettywriter.h │ │ ├── rapidjson.h │ │ ├── reader.h │ │ ├── schema.h │ │ ├── stream.h │ │ ├── stringbuffer.h │ │ └── writer.h │ └── testrapidjson.cpp └── swaptions │ ├── COPYRIGHT │ ├── CumNormalInv.cpp │ ├── HJM.cpp │ ├── HJM.h │ ├── HJM_Securities.cpp │ ├── HJM_Securities.h │ ├── HJM_SimPath_Forward_Blocking.cpp │ ├── HJM_Swaption_Blocking.cpp │ ├── HJM_type.h │ ├── Makefile │ ├── MaxFunction.cpp │ ├── README.md │ ├── RanUnif.cpp │ ├── icdf.cpp │ ├── nr_routines.c │ ├── nr_routines.h │ ├── original │ ├── HJM.cpp │ ├── HJM.h │ ├── HJM_SimPath_Forward_Blocking.cpp │ ├── HJM_Swaption_Blocking.cpp │ └── Makefile │ └── resource.h ├── experimental ├── Makefile ├── bde-config.h ├── bde-replacements │ ├── bdlma_buffermanager.cpp │ ├── bdlma_buffermanager.h │ ├── bdlma_buffermanager.t.cpp │ ├── bdlma_concurrentpool.cpp │ ├── bdlma_concurrentpool.h │ ├── bdlma_concurrentpool.t.cpp │ ├── bdlma_dllist.cpp │ ├── bdlma_dllist.h │ ├── bdlma_multipool.cpp │ ├── bdlma_multipool.h │ ├── bdlma_multipool.t.cpp │ ├── bdlma_pool.cpp │ ├── bdlma_pool.h │ ├── bdlma_pool.t.cpp │ ├── bdlma_simpool.cpp │ ├── bdlma_simpool.h │ ├── simregion.cpp │ └── simregion.h ├── bdlma │ ├── bdlma_bufferedsequentialallocator.cpp │ ├── bdlma_bufferedsequentialallocator.h │ ├── bdlma_buffermanager.cpp │ ├── bdlma_buffermanager.h │ ├── bdlma_concurrentpool.cpp │ ├── bdlma_concurrentpool.h │ ├── bdlma_multipool.cpp │ ├── bdlma_multipool.h │ ├── bdlma_pool.cpp │ └── bdlma_pool.h ├── bslma │ └── bslma_sequentialallocator.h ├── bslstl │ └── bslstl_simplepool.h ├── cxxopts.hpp ├── dllist.h ├── fragmenter.hpp ├── litterer.hpp ├── notes.txt ├── old │ ├── shim_allocator.hpp │ └── shim_buffermanager.hpp ├── page-litterer.hpp ├── shim_allocator.hpp ├── shim_buffermanager.hpp ├── shim_concurrentpool.hpp ├── shim_multipool.hpp ├── shim_pool.hpp ├── shim_simplepool.hpp ├── simpool.hpp ├── simregion.hpp ├── stlallocator.h ├── test-fragmenter.cpp ├── test-shim-allocator.cpp ├── test-shim-buffermanager.cpp ├── test-shim-simplepool.cpp ├── test-string.cpp ├── tprintf.h └── validator.py ├── heaplayers-make.mk ├── libcheap.cpp ├── libcheaper.cpp ├── nextheap.hpp ├── printf.cpp ├── printf.h ├── regionheap.h ├── requirements.txt ├── test └── regional.cpp ├── testcheapen.cpp └── testme.cpp /.github/workflows/c-cpp.yml: -------------------------------------------------------------------------------- 1 | name: Build Cheap 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | container: prsam/cheap:base-clang-13-stdlibcxx 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: build libs 18 | run: | 19 | make 20 | test -f libcheap.so 21 | test -f libcheaper.so 22 | - name: basic compile test 23 | run: make 24 | - name: example.json 25 | working-directory: examples/json/ 26 | run: | 27 | make 28 | ./testjson 29 | LD_LIBRARY_PATH=../.. ./testjson-cheapened 30 | - name: example.rapidjson 31 | working-directory: examples/rapidjson/ 32 | run: | 33 | make 34 | ./testrapidjson 35 | LD_PRELOAD=../../libcheaper.so ./testrapidjson 36 | python3 ../../cheaper.py --progname ./testrapidjson 37 | LD_LIBRARY_PATH=../.. ./testrapidjson-cheapened 38 | - name: example.swaptions 39 | working-directory: examples/swaptions/ 40 | run: | 41 | make 42 | make version=pthreads cheap=1 43 | ./swaptions-expensive -ns 2 -sm 1000000 -nt 1 44 | LD_LIBRARY_PATH=../.. ./swaptions-cheap -ns 2 -sm 1000000 -nt 1 45 | - name: example.boostjson 46 | working-directory: examples/boostjson/ 47 | run: | 48 | make 49 | ./testboostjson 50 | LD_LIBRARY_PATH=../.. ./testboostjson-cheapened 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | Heap-Layers 3 | *.so 4 | -------------------------------------------------------------------------------- /Backtrace.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CHEAP_BACKTRACE_HPP 2 | #define CHEAP_BACKTRACE_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace Backtrace { 14 | namespace { 15 | static backtrace_state* state = nullptr; 16 | } 17 | 18 | struct StackFrame { 19 | std::string function; 20 | std::string filename; 21 | int lineno; 22 | }; 23 | } 24 | 25 | extern "C" 26 | int onStackFrame(void* data, uintptr_t pc, const char* filename, int lineno, const char* function) { 27 | auto* backtrace = static_cast*>(data); 28 | 29 | Backtrace::StackFrame frame; 30 | 31 | // If we have no information, look up info using the pc. 32 | if (!function && !filename) { 33 | Dl_info info; 34 | dladdr((void *) pc, &info); 35 | int status; 36 | if (info.dli_sname) { 37 | char* demangled_function = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status); 38 | if (demangled_function) { 39 | frame.function = std::string(demangled_function); 40 | } else { 41 | frame.function = std::string(info.dli_sname); 42 | } 43 | } 44 | frame.filename = std::string(info.dli_fname); 45 | backtrace->insert(backtrace->begin(), frame); 46 | return 0; 47 | } 48 | 49 | // std::cerr << "in " << filename << " at line " << lineno << std::endl; 50 | 51 | if (!function) { 52 | frame.function = "[UNKNOWN]"; 53 | } else { 54 | int status; 55 | char* demangled_function = abi::__cxa_demangle(function, nullptr, nullptr, &status); 56 | if (!demangled_function) { 57 | Dl_info info; 58 | int status = dladdr((void *) pc, &info); 59 | if (status) { 60 | filename = info.dli_sname; 61 | } 62 | } 63 | if (status == 0) { 64 | frame.function = std::string(demangled_function); 65 | static decltype(::free)* free = (decltype(::free)*) dlsym(RTLD_DEFAULT, "free"); 66 | (*free)(demangled_function); 67 | } else { 68 | frame.function = std::string(function); 69 | } 70 | } 71 | 72 | frame.filename = (!filename) ? "[UNKNOWN]" : std::string(filename); 73 | frame.lineno = lineno; 74 | 75 | backtrace->insert(backtrace->begin(), frame); 76 | 77 | return 0; 78 | }; 79 | 80 | // Small utility file I wrote while testing libbacktrace with Intel Pin. 81 | namespace Backtrace { 82 | void initialize(char* filename) { 83 | if (state == nullptr) { 84 | const auto onError = [](void*, const char* msg, int errnum) { 85 | std::cerr << "Error #" << errnum << " while setting up backtrace. Message: " << msg << std::endl; 86 | }; 87 | 88 | state = backtrace_create_state(filename, true, onError, nullptr); 89 | } 90 | } 91 | 92 | std::vector getBacktrace(int skip) { 93 | // If we have not initialized the utility yet, we return an empty stack trace. 94 | if (state == nullptr) { 95 | return std::vector(); 96 | } 97 | 98 | const auto onError = [](void*, const char* msg, int errnum) { 99 | std::cerr << "Error #" << errnum << " while getting backtrace. Message: " << msg << std::endl; 100 | }; 101 | 102 | 103 | std::vector backtrace; 104 | backtrace_full(state, skip, onStackFrame, onError, &backtrace); 105 | return backtrace; 106 | } 107 | 108 | std::vector getBacktrace() { 109 | return getBacktrace(0); 110 | } 111 | } // namespace Backtrace 112 | 113 | #endif // CHEAP_BACKTRACE_HPP 114 | -------------------------------------------------------------------------------- /GNUmakefile: -------------------------------------------------------------------------------- 1 | SOURCES = libcheaper.cpp libcheap.cpp cheap.h 2 | 3 | .PHONY: all format test 4 | 5 | all: vendor 6 | -make -f cheap.mk 7 | -make -f cheaper.mk 8 | 9 | vendor: 10 | mkdir vendor 11 | cd vendor && git clone https://github.com/ianlancetaylor/libbacktrace.git 12 | # cd vendor/libbacktrace && ./configure CFLAGS='-arch x86_64 -fPIC' CC='clang' && make 13 | cd vendor/libbacktrace && ./configure CFLAGS='-arch x86_64 -arch arm64 -fPIC' CC='clang' && make 14 | 15 | format: $(SOURCES) 16 | clang-format -i $(SOURCES) 17 | black cheaper.py 18 | 19 | test: $(SOURCES) testme.cpp test/regional.cpp testcheapen.cpp 20 | clang++ -std=c++14 -O0 -fno-inline -g -fno-inline-functions testme.cpp -o testme 21 | clang++ -std=c++14 -O0 -fno-inline -g -fno-inline-functions test/regional.cpp -o regional 22 | clang++ -std=c++14 -O0 -DTEST -IHeap-Layers -fno-inline-functions -fno-inline -g testcheapen.cpp -o testcheapen-trace 23 | clang++ -std=c++14 -flto -O3 -g -IHeap-Layers -DNDEBUG -DCHEAPEN=1 testcheapen.cpp -o testcheapen-cheapen -lpthread -L. -lcheap 24 | clang++ -std=c++14 -fno-inline-functions -fno-inline -O0 -g -IHeap-Layers -DCHEAPEN=1 testcheapen.cpp -o testcheapen-cheapen-debug -lpthread -L. -lcheap 25 | clang++ -std=c++14 -flto -O3 -g -IHeap-Layers -DNDEBUG testcheapen.cpp -o testcheapen -lpthread 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Emery Berger 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cheap 2 | 3 | Cheap: a `malloc`/`new` optimizer 4 | 5 | by [Emery Berger](https://emeryberger.com) 6 | 7 | # About Cheap 8 | 9 | Cheap is a system that makes it easy to improve the performance of 10 | memory-intensive C/C++ applications. Cheap works by replacing memory 11 | allocation operations with a custom heap that can substantially 12 | improve performance. Unlike past approaches, Cheap requires almost no 13 | programming effort. For example, by adding _just one line of code_ 14 | (plus an `#include`), we were able to speed up the Boost JSON library 15 | by 30-40%. 16 | 17 | # How it works 18 | 19 | The Cheap library (`libcheap.so`) and its header `cheap.h` let you use 20 | a custom heap with little effort. One line of code creates a custom 21 | heap with certain characteristics and temporarily redirects _all_ 22 | memory allocation calls (`malloc`, `free`, `new`, `delete`) to that 23 | heap until the heap goes out of scope. 24 | 25 | To use Cheap, you include the file `cheap.h`, and then insert a line of code creating a custom heap. For example: 26 | 27 | cheap::cheap r; 28 | 29 | The options for the heap are passed as a series of flags, each separated by `|`. 30 | 31 | Current options for the custom heap are the following: 32 | 33 | * `cheap::NONZERO` -- no requests for 0 bytes 34 | * `cheap::ALIGNED` -- all size requests are suitably aligned 35 | * `cheap::SINGLE_THREADED` -- all allocations and frees are by the same thread 36 | * `cheap::SIZE_TAKEN` -- need to track object sizes for `realloc` or `malloc_usable_size` 37 | * `cheap::SAME_SIZE` -- all object requests are the same size; pass the size as the second argument to the constructor 38 | * `cheap::DISABLE_FREE` -- turns `free` calls into no-ops 39 | 40 | Once you place this line at the appropriate point in your program, it 41 | will redirect all subsequent allocations and frees to use the 42 | generated custom heap. _Using `cheap::DISABLE_FREE` gives you the effect of a "region-style" allocator (a.k.a. "arena", "pool", or "monotonic 43 | resource"); otherwise, you get a customized freelist implementation._ 44 | 45 | Once this object goes out of scope ([RAII-style](https://en.cppreference.com/w/cpp/language/raii), like 46 | [`std::lock_guard`](https://en.cppreference.com/w/cpp/thread/lock_guard)), the program reverts to ordinary behavior, using the 47 | system-supplied memory allocator, and the custom heap's memory is 48 | reclaimed. 49 | 50 | ## Placing a custom heap 51 | 52 | Sometimes, placing a custom heap is straightforward, but it's nice to 53 | have help. We provide a tool called `Cheaper` that finds places in 54 | your program where a custom heap could potentially improve 55 | performance, and which generates the line of code to insert. 56 | 57 | ### Collecting a trace with `libcheaper` 58 | 59 | First, run your program with the Cheaper library, as follows: 60 | 61 | LD_PRELOAD=libcheaper.so ./yourprogram 62 | 63 | or, on Mac: 64 | 65 | DYLD_INSERT_LIBRARIES=libcheaper.dylib ./yourprogram 66 | 67 | This generates a file `cheaper.out` in the current directory. That file is a JSON file that contains information used by the `cheaper.py` script. NOTE: you need to compile your program with several flags to make sure Cheaper can get enough information to work. For example: 68 | 69 | clang++ -g -fno-inline-functions -O0 yourprogram.cpp -o yourprogram 70 | 71 | ### Analyze the trace with `cheaper.py` 72 | 73 | You may need to install Rust (https://www.rust-lang.org/tools/install) the first time you 74 | run Cheaper: 75 | 76 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh 77 | 78 | Now run Cheaper as follows: 79 | 80 | python3 cheaper.py --progname ./yourprogram 81 | 82 | For a complete list of options, type `python3 cheaper.py --help`. 83 | 84 | Cheaper will produce output, in ranked order from most to least 85 | promising, corresponding to places in the code where you should insert 86 | the `cheap` declaration. It outputs the line of code, which you can 87 | then copy and paste directly into your program. 88 | 89 | -------------------------------------------------------------------------------- /cheap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //#define MIN_ALIGNMENT 8 4 | #define MIN_ALIGNMENT alignof(max_align_t) 5 | #define THREAD_SAFE 1 6 | 7 | #include 8 | 9 | #if !defined(__APPLE__) 10 | #include 11 | #endif 12 | 13 | #if defined(__cplusplus) 14 | 15 | #include "common.hpp" 16 | #include "regionheap.h" 17 | #include "nextheap.hpp" 18 | 19 | using namespace HL; 20 | 21 | #if 0 22 | class TopHeap : public SizeHeap>> {}; 23 | 24 | class CheapHeapType : 25 | public KingsleyHeap>, TopHeap> {}; 26 | #endif 27 | 28 | template 29 | class PrintMeHeap : public SuperHeap { 30 | public: 31 | inline void * malloc(size_t sz) { 32 | auto ptr = SuperHeap::malloc(sz); 33 | // tprintf::tprintf("@ malloc request (@) = @\n", name, sz, ptr); 34 | return ptr; 35 | } 36 | }; 37 | 38 | class TopHeap : public SizeHeap> {}; 39 | 40 | class CheapHeapType : 41 | public KingsleyHeap, TopHeap> {}; 42 | 43 | class CheapRegionHeap : 44 | public RegionHeap {}; 45 | 46 | class CheapFreelistHeap : 47 | public FreelistHeap> {}; 49 | 50 | namespace cheap { 51 | 52 | enum flags { 53 | ALIGNED = 0b0000'0001, // no need to align sizes 54 | NONZERO = 0b0000'0010, // no zero size requests 55 | SIZE_TAKEN = 0b0000'0100, // need support for size 56 | SINGLE_THREADED = 0b0000'1000, // all requests the same size - use freelist 57 | DISABLE_FREE = 0b0001'0000, // frees -> NOPs: use a "region" allocator 58 | SAME_SIZE = 0b0010'0000, // all requests the same size 59 | FIXED_BUFFER = 0b0100'0000, // use a specified buffer 60 | }; 61 | 62 | class cheap_base; 63 | } 64 | 65 | extern cheap::cheap_base*& current(); 66 | 67 | namespace cheap { 68 | class cheap_base { 69 | public: 70 | inline __attribute__((always_inline)) virtual void * malloc(size_t) = 0; 71 | inline __attribute__((always_inline)) virtual void free(void *) = 0; 72 | inline __attribute__((always_inline)) virtual size_t getSize(void *) = 0; 73 | // virtual void * memalign(size_t, size_t) = 0; 74 | bool in_cheap {false}; 75 | }; 76 | } 77 | 78 | namespace cheap { 79 | class cheap_header { 80 | public: 81 | cheap_header(size_t sz) : object_size(sz) {} 82 | alignas(max_align_t) size_t object_size; 83 | }; 84 | 85 | template 86 | class cheap : public cheap_base { 87 | private: 88 | 89 | static constexpr bool isAligned = Flags & flags::ALIGNED; 90 | static constexpr bool isAllNonZero = Flags & flags::NONZERO; 91 | static constexpr bool disableFrees = Flags & flags::DISABLE_FREE; 92 | static constexpr bool sizeTaken = Flags & flags::SIZE_TAKEN; 93 | static constexpr bool useFixedBuffer = Flags & flags::FIXED_BUFFER; 94 | static constexpr bool allSameSize = Flags & flags::SAME_SIZE; 95 | 96 | public: 97 | inline cheap(size_t sz = 8, 98 | char * buf = nullptr, 99 | size_t bufSz = 0) 100 | { 101 | static_assert(flags::ALIGNED ^ flags::NONZERO ^ flags::SIZE_TAKEN ^ flags::SINGLE_THREADED ^ flags::DISABLE_FREE ^ flags::SAME_SIZE ^ flags::FIXED_BUFFER == (1 << 8) - 1, 102 | "Flags must be one bit and mutually exclusive."); 103 | static_assert(disableFrees || allSameSize, "Either frees must be disabled (DISABLE_FREE), or all requests must be the same size (SAME_SIZE)."); 104 | _oneSize = sz; 105 | _buf = buf; 106 | _bufSz = bufSz; 107 | current() = this; 108 | in_cheap = true; 109 | } 110 | 111 | inline __attribute__((always_inline)) void * malloc(size_t req_sz) { 112 | assert(in_cheap); 113 | size_t sz = req_sz; 114 | if (!isAligned) { 115 | // Enforce default alignment. 116 | if (!isAllNonZero) { 117 | // Ensure zero requests are rounded up. 118 | if (sz < MIN_ALIGNMENT) { 119 | sz = MIN_ALIGNMENT; 120 | } 121 | } 122 | sz = (sz + MIN_ALIGNMENT - 1) & ~(MIN_ALIGNMENT - 1); 123 | } 124 | void * ptr; 125 | if (disableFrees) { 126 | if (!(sizeTaken || allSameSize)) { 127 | if (useFixedBuffer) { 128 | ptr = _buf; 129 | _buf += sz; 130 | } else { 131 | ptr = getRegion()->malloc(sz); 132 | } 133 | } else { 134 | if (useFixedBuffer) { 135 | ptr = _buf; 136 | _buf += sz + sizeof(cheap_header); 137 | } else { 138 | ptr = getRegion()->malloc(sz + sizeof(cheap_header)); 139 | } 140 | // Prepend an object header. 141 | new (ptr) cheap_header(sz); 142 | ptr = (cheap_header *) ptr + 1; 143 | } 144 | } else { 145 | assert(sz == req_sz); 146 | ptr = getFreelist()->malloc(sz); 147 | } 148 | return ptr; 149 | } 150 | inline void free(void * ptr) { 151 | // tprintf::tprintf("current now = @\n", current()); 152 | assert(in_cheap); 153 | if (!disableFrees) { 154 | getFreelist()->free(ptr); 155 | } 156 | } 157 | inline size_t getSize(void * ptr) { 158 | if (sizeTaken) { 159 | if (allSameSize) { 160 | return _oneSize; 161 | } else { 162 | return ((cheap_header *)ptr - 1)->object_size; 163 | } 164 | } else { 165 | assert(false); 166 | return 0; 167 | } 168 | } 169 | #if 0 170 | inline void * memalign(size_t, size_t) { 171 | } 172 | #endif 173 | inline ~cheap() { 174 | if (disableFrees) { 175 | if (!useFixedBuffer) { 176 | getRegion()->clear(); 177 | } 178 | } else { 179 | getFreelist()->clear(); 180 | } 181 | in_cheap = false; 182 | } 183 | private: 184 | 185 | static inline CheapRegionHeap * getRegion() { 186 | // return nullptr; 187 | static CheapRegionHeap region; 188 | return ®ion; 189 | } 190 | 191 | static inline CheapFreelistHeap * getFreelist() { 192 | // return nullptr; 193 | static CheapFreelistHeap freelist; 194 | return &freelist; 195 | } 196 | 197 | size_t _oneSize {0}; 198 | char * _buf; 199 | size_t _bufSz; 200 | }; 201 | 202 | 203 | } // namespace cheap 204 | 205 | 206 | class ParentHeap : public NextHeap {}; 207 | 208 | class CustomHeapType : public ParentHeap { 209 | public: 210 | void lock() {} 211 | void unlock() {} 212 | }; 213 | 214 | class spin_lock { 215 | public: 216 | void lock() { 217 | while (_lock.test_and_set(std::memory_order_acquire)) 218 | ; 219 | } 220 | void unlock() 221 | { 222 | _lock.clear(std::memory_order_release); 223 | } 224 | private: 225 | std::atomic_flag _lock = ATOMIC_FLAG_INIT; 226 | }; 227 | 228 | #endif 229 | -------------------------------------------------------------------------------- /cheap.mk: -------------------------------------------------------------------------------- 1 | PYTHON = python3 2 | SOURCES = libcheap.cpp cheap.h 3 | LIBNAME = cheap 4 | 5 | include heaplayers-make.mk 6 | 7 | .PHONY: format test 8 | 9 | format: $(SOURCES) 10 | clang-format -i $(SOURCES) 11 | black cheaper.py 12 | 13 | test: $(SOURCES) test/regional.cpp 14 | clang++ -O3 -g -fno-inline test/regional.cpp 15 | -------------------------------------------------------------------------------- /cheaper.mk: -------------------------------------------------------------------------------- 1 | PYTHON = python3 2 | SOURCES = libcheaper.cpp libcheapen.cpp printf.cpp 3 | LIBNAME = cheaper 4 | include heaplayers-make.mk 5 | 6 | .PHONY: format test 7 | 8 | format: $(SOURCES) 9 | clang-format -i $(SOURCES) 10 | black cheaper.py 11 | 12 | test: $(SOURCES) test/regional.cpp 13 | clang++ -O3 -g -fno-inline test/regional.cpp 14 | -------------------------------------------------------------------------------- /common.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef COMMON_HPP 4 | #define COMMON_HPP 5 | 6 | #define likely(x) __builtin_expect(!!(x), 1) 7 | #define unlikely(x) __builtin_expect(!!(x), 0) 8 | 9 | #define ATTRIBUTE_NEVER_INLINE __attribute__((noinline)) 10 | #define ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline)) 11 | #define ATTRIBUTE_HIDDEN __attribute__((visibility("hidden"))) 12 | #define ATTRIBUTE_EXPORT __attribute__((visibility("default"))) 13 | #define ATTRIBUTE_ALIGNED(s) __attribute__((aligned(s))) 14 | #define CACHELINE_SIZE 64 15 | #define CACHELINE_ALIGNED ATTRIBUTE_ALIGNED(CACHELINE_SIZE) 16 | #define CACHELINE_ALIGNED_FN CACHELINE_ALIGNED 17 | 18 | 19 | #define USE_COMPRESSED_PTRS 0 20 | #define USE_SIZE_CACHES 0 // 1 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /docker/base-clang-13-stdlibcxx.dockerfile: -------------------------------------------------------------------------------- 1 | FROM gcc:10 2 | 3 | RUN \ 4 | apt-get -qq update && apt-get -qq install -y lsb-release wget software-properties-common gnupg2 git make \ 5 | \ 6 | && wget -nv -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - \ 7 | && wget -nv -O - https://apt.llvm.org/llvm.sh | bash -s -- 13 \ 8 | && apt-get -qq install -y clang-format-13 clang-tidy-13 9 | 10 | RUN wget -nv -O - https://gist.githubusercontent.com/junkdog/70231d6953592cd6f27def59fe19e50d/raw/update-alternatives-clang.sh | bash -s -- 13 100 \ 11 | && update-alternatives --install /usr/bin/ld ld /usr/bin/ld.lld-13 100 \ 12 | && rm -f /usr/bin/clang++ \ 13 | && printf '#!/bin/sh\nexec "/usr/bin/clang++-13" --gcc-toolchain=/usr/local ${@}' >/usr/bin/clang++ \ 14 | && chmod +x /usr/bin/clang++ 15 | 16 | RUN wget -nv -O - 'http://downloads.sourceforge.net/project/boost/boost/1.76.0/boost_1_76_0.tar.gz' \ 17 | | tar xz \ 18 | && ( \ 19 | cd boost_1_76_0 \ 20 | && ./bootstrap.sh --prefix=/usr/local \ 21 | && ./b2 toolset=clang --with-json release install \ 22 | ) \ 23 | && rm -rf boost_1_76_0 24 | -------------------------------------------------------------------------------- /docker/base-clang-13.dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:buster 2 | 3 | RUN \ 4 | apt-get -qq update && apt-get -qq install -y lsb-release wget software-properties-common gnupg2 git make \ 5 | \ 6 | && wget -nv -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - \ 7 | && wget -nv -O - https://apt.llvm.org/llvm.sh | bash -s -- 13 \ 8 | && apt-get -qq install -y clang-format-13 clang-tidy-13 libc++-13-dev libc++abi-13-dev 9 | 10 | RUN wget -nv -O - https://gist.githubusercontent.com/junkdog/70231d6953592cd6f27def59fe19e50d/raw/update-alternatives-clang.sh | bash -s -- 13 100 \ 11 | && update-alternatives --install /usr/bin/ld ld /usr/bin/ld.lld-13 100 \ 12 | && rm -f /usr/bin/clang++ \ 13 | && printf '#!/bin/sh\nexec "/usr/bin/clang++-13" -stdlib=libc++ ${@}' >/usr/bin/clang++ \ 14 | && chmod +x /usr/bin/clang++ 15 | 16 | RUN wget -nv -O - 'http://downloads.sourceforge.net/project/boost/boost/1.76.0/boost_1_76_0.tar.gz' \ 17 | | tar xz \ 18 | && ( \ 19 | cd boost_1_76_0 \ 20 | && ./bootstrap.sh --prefix=/usr/local \ 21 | && ./b2 --with-json release install \ 22 | ) \ 23 | && rm -rf boost_1_76_0 24 | -------------------------------------------------------------------------------- /docker/base-gcc-10.dockerfile: -------------------------------------------------------------------------------- 1 | FROM gcc:10 2 | 3 | RUN \ 4 | apt-get -qq update && apt-get -qq install -y lsb-release wget software-properties-common gnupg2 git 5 | 6 | RUN wget -nv -O - 'http://downloads.sourceforge.net/project/boost/boost/1.76.0/boost_1_76_0.tar.gz' \ 7 | | tar xz \ 8 | && ( \ 9 | cd boost_1_76_0 \ 10 | && ./bootstrap.sh --prefix=/usr/local \ 11 | && ./b2 --with-json release install \ 12 | ) \ 13 | && rm -rf boost_1_76_0 14 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | -------------------------------------------------------------------------------- /examples/boostjson/Makefile: -------------------------------------------------------------------------------- 1 | INCLUDES = -I../.. -I../../Heap-Layers -I. # -I/usr/include/boost 2 | CXXFLAGS = -std=c++20 -g 3 | 4 | all: 5 | clang++ -flto $(INCLUDES) -L../.. $(CXXFLAGS) -O3 -DNDEBUG testboostjson.cpp -o testboostjson 6 | clang++ -flto -DCHEAPEN=1 $(INCLUDES) -L../.. $(CXXFLAGS) -O3 -DNDEBUG testboostjson.cpp -o testboostjson-cheapened -lcheap 7 | 8 | trace: 9 | clang++ -fno-inline-functions $(INCLUDES) -L../.. $(CXXFLAGS) -O2 -DNDEBUG testboostjson.cpp -o testboostjson-trace 10 | 11 | test: 12 | clang++ -fno-inline-functions -DCHEAPEN=1 $(INCLUDES) -L../.. $(CXXFLAGS) -O0 testboostjson.cpp -o testboostjson-test -lcheap 13 | -------------------------------------------------------------------------------- /examples/boostjson/src.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) 3 | // 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | // 7 | // Official repository: https://github.com/boostorg/json 8 | // 9 | 10 | #ifndef BOOST_JSON_SRC_HPP 11 | #define BOOST_JSON_SRC_HPP 12 | 13 | /* 14 | 15 | This file is meant to be included once, 16 | in a translation unit of the program. 17 | 18 | */ 19 | 20 | #ifndef BOOST_JSON_SOURCE 21 | #define BOOST_JSON_SOURCE 22 | #endif 23 | 24 | // We include this in case someone is using 25 | // src.hpp as their main JSON header file 26 | // https://github.com/boostorg/json/issues/223#issuecomment-689264149 27 | #include 28 | 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | 56 | #include 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /examples/boostjson/testboostjson.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #if !defined(CHEAPEN) 8 | #define CHEAPEN 0 9 | #endif 10 | 11 | #define OPTIMIZED_HEAP 0 // NB: NOT working 12 | 13 | #if CHEAPEN 14 | #include "cheap.h" 15 | #endif 16 | 17 | // #include 18 | #include "src.hpp" 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | // From https://github.com/lefticus/cpp_weekly/blob/master/PMR/json_tests.cpp 28 | 29 | struct RapidJSONPMRAlloc 30 | { 31 | std::pmr::memory_resource *upstream = std::pmr::get_default_resource(); 32 | 33 | static constexpr bool kNeedFree = true; 34 | 35 | static constexpr auto objectOffset = alignof(std::max_align_t); 36 | static constexpr auto memPadding = objectOffset * 2; 37 | 38 | void *Malloc(size_t size) 39 | { 40 | if (size != 0) { 41 | const auto allocated_size = size + memPadding; 42 | std::byte *newPtr = static_cast(upstream->allocate(allocated_size)); 43 | auto *ptrToReturn = newPtr + memPadding; 44 | // placement new a pointer to ourselves at the first memory location 45 | new (newPtr)(RapidJSONPMRAlloc *)(this); 46 | // placement new the size in the second location 47 | new (newPtr + objectOffset)(std::size_t)(size); 48 | return ptrToReturn; 49 | } else { 50 | return nullptr; 51 | } 52 | } 53 | 54 | void freePtr(void *origPtr, size_t originalSize) 55 | { 56 | if (origPtr == nullptr) { 57 | return; 58 | } 59 | upstream->deallocate(static_cast(origPtr) - memPadding, originalSize + memPadding); 60 | } 61 | 62 | void *Realloc(void *origPtr, size_t originalSize, size_t newSize) 63 | { 64 | if (newSize == 0) { 65 | freePtr(origPtr, originalSize); 66 | return nullptr; 67 | } 68 | 69 | if (newSize <= originalSize) { 70 | return origPtr; 71 | } 72 | 73 | void *newPtr = Malloc(newSize); 74 | std::memcpy(newPtr, origPtr, originalSize); 75 | freePtr(origPtr, originalSize); 76 | return newPtr; 77 | } 78 | 79 | // and Free needs to be static, which causes this whole thing 80 | // to fall apart. This means that we have to keep our own list of allocated memory 81 | // with our own pointers back to ourselves and our own list of sizes 82 | // so we can push all of this back to the upstream allocator 83 | static void Free(void *ptr) 84 | { 85 | if (ptr == nullptr ) { 86 | return; 87 | } 88 | 89 | std::byte *startOfData = static_cast(ptr) - memPadding; 90 | 91 | auto *ptrToAllocator = *reinterpret_cast(startOfData); 92 | auto origAllocatedSize = *reinterpret_cast(startOfData + objectOffset); 93 | 94 | ptrToAllocator->freePtr(ptr, origAllocatedSize); 95 | } 96 | }; 97 | 98 | 99 | void parseMe(volatile const char * s, size_t sz) 100 | { 101 | #if OPTIMIZED_HEAP 102 | std::pmr::monotonic_buffer_resource mr; 103 | std::pmr::polymorphic_allocator<> pa{ &mr }; 104 | auto &p = *pa.new_object(); 105 | p.reset(pa); 106 | #endif 107 | boost::json::error_code ec; 108 | 109 | #if 0 110 | boost::json::parser ps; 111 | ps.write(s, sz, ec); 112 | #else 113 | boost::json::stream_parser ps; 114 | ps.write((const char *) s, sz, ec); 115 | if (!ec) { 116 | ps.finish(ec); 117 | } 118 | #if !OPTIMIZED_HEAP 119 | if (!ec) { 120 | #if !CHEAPEN 121 | auto jv = ps.release(); 122 | #endif 123 | } 124 | #endif 125 | #endif 126 | } 127 | 128 | int main() 129 | { 130 | // std::ifstream i("gsoc-2018.json"); 131 | std::ifstream i("citm_catalog.json"); 132 | std::ostringstream sstr; 133 | sstr << i.rdbuf(); 134 | // mallopt(M_MMAP_THRESHOLD, 10487560 + 32); 135 | auto str = sstr.str(); 136 | auto data = str.data(); 137 | volatile auto sz = str.size(); 138 | char * buf = new char[3 * 1048576]; 139 | for (auto i = 0; i < 1000; i++) 140 | { 141 | #if CHEAPEN 142 | cheap::cheap reg(8, buf, 3 * 1048576); 143 | // cheap::cheap reg; 144 | #endif 145 | parseMe(data, sz); 146 | } 147 | return 0; 148 | } 149 | -------------------------------------------------------------------------------- /examples/json/Makefile: -------------------------------------------------------------------------------- 1 | FLAGS = -std=c++17 2 | 3 | all: 4 | clang++ $(FLAGS) -flto -I../.. -L../.. -O3 -g -DNDEBUG testjson.cpp -o testjson 5 | clang++ $(FLAGS) -flto -DCHEAPEN=1 -I../../Heap-Layers -I../.. -L../.. -O3 -g -DNDEBUG testjson.cpp -o testjson-cheapened -lcheap 6 | 7 | trace: 8 | clang++ $(FLAGS) -fno-inline-functions -I../.. -L../.. -O2 -g -DNDEBUG testjson.cpp -o testjson-trace 9 | -------------------------------------------------------------------------------- /examples/json/testjson.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #if !defined(CHEAPEN) 9 | #define CHEAPEN 0 10 | #endif 11 | 12 | #if CHEAPEN 13 | #include "cheap.h" 14 | #endif 15 | 16 | #include "json.hpp" 17 | 18 | void parseMe(std::string_view& view) 19 | { 20 | // std::ifstream i("gsoc-2018.json"); 21 | #if 0 22 | nlohmann::json j; 23 | i >> j; 24 | #else 25 | auto volatile r = nlohmann::json::parse(view.begin(), view.end()); // data, sz); 26 | #endif 27 | } 28 | 29 | void outputMe(nlohmann::json& j) 30 | { 31 | // write prettified JSON to another file 32 | std::ofstream o("pretty.json"); 33 | o << std::setw(4) << j << std::endl; 34 | } 35 | 36 | 37 | int 38 | main() 39 | { 40 | std::ifstream i("citm_catalog.json"); 41 | std::ostringstream sstr; 42 | sstr << i.rdbuf(); 43 | // mallopt(M_MMAP_THRESHOLD, 10487560 + 32); 44 | auto str = sstr.str(); 45 | char * data = str.data(); 46 | size_t sz = str.size(); 47 | auto view = std::string_view(data, sz); 48 | for (auto i = 0; i < 1000; i++) 49 | { 50 | #if CHEAPEN 51 | cheap::cheap reg; 52 | #endif 53 | parseMe(view); 54 | } 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /examples/rapidjson/Makefile: -------------------------------------------------------------------------------- 1 | INCLUDES = -I../../Heap-Layers -I../.. 2 | # CXXFLAGS = -O0 -g -lpthread 3 | CXXFLAGS = -std=c++20 -flto -O3 -g -DNDEBUG -lpthread 4 | CXXFLAGS_DEBUG = -std=c++20 -O2 -g -lpthread 5 | 6 | all: 7 | clang++ $(CXXFLAGS) $(INCLUDES) -L../.. testrapidjson.cpp -o testrapidjson 8 | clang++ -DCHEAPEN=1 $(CXXFLAGS) $(INCLUDES) -L../.. testrapidjson.cpp -o testrapidjson-cheapened -lcheap 9 | 10 | trace: 11 | clang++ -fno-inline-functions $(INCLUDES) -L../.. $(CXXFLAGS_DEBUG) testrapidjson.cpp -o testrapidjson-trace 12 | -------------------------------------------------------------------------------- /examples/rapidjson/rapidjson/cursorstreamwrapper.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_CURSORSTREAMWRAPPER_H_ 16 | #define RAPIDJSON_CURSORSTREAMWRAPPER_H_ 17 | 18 | #include "stream.h" 19 | 20 | #if defined(__GNUC__) 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(effc++) 23 | #endif 24 | 25 | #if defined(_MSC_VER) && _MSC_VER <= 1800 26 | RAPIDJSON_DIAG_PUSH 27 | RAPIDJSON_DIAG_OFF(4702) // unreachable code 28 | RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated 29 | #endif 30 | 31 | RAPIDJSON_NAMESPACE_BEGIN 32 | 33 | 34 | //! Cursor stream wrapper for counting line and column number if error exists. 35 | /*! 36 | \tparam InputStream Any stream that implements Stream Concept 37 | */ 38 | template > 39 | class CursorStreamWrapper : public GenericStreamWrapper { 40 | public: 41 | typedef typename Encoding::Ch Ch; 42 | 43 | CursorStreamWrapper(InputStream& is): 44 | GenericStreamWrapper(is), line_(1), col_(0) {} 45 | 46 | // counting line and column number 47 | Ch Take() { 48 | Ch ch = this->is_.Take(); 49 | if(ch == '\n') { 50 | line_ ++; 51 | col_ = 0; 52 | } else { 53 | col_ ++; 54 | } 55 | return ch; 56 | } 57 | 58 | //! Get the error line number, if error exists. 59 | size_t GetLine() const { return line_; } 60 | //! Get the error column number, if error exists. 61 | size_t GetColumn() const { return col_; } 62 | 63 | private: 64 | size_t line_; //!< Current Line 65 | size_t col_; //!< Current Column 66 | }; 67 | 68 | #if defined(_MSC_VER) && _MSC_VER <= 1800 69 | RAPIDJSON_DIAG_POP 70 | #endif 71 | 72 | #if defined(__GNUC__) 73 | RAPIDJSON_DIAG_POP 74 | #endif 75 | 76 | RAPIDJSON_NAMESPACE_END 77 | 78 | #endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_ 79 | -------------------------------------------------------------------------------- /examples/rapidjson/rapidjson/error/en.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_ERROR_EN_H_ 16 | #define RAPIDJSON_ERROR_EN_H_ 17 | 18 | #include "error.h" 19 | 20 | #ifdef __clang__ 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(switch-enum) 23 | RAPIDJSON_DIAG_OFF(covered-switch-default) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Maps error code of parsing into error message. 29 | /*! 30 | \ingroup RAPIDJSON_ERRORS 31 | \param parseErrorCode Error code obtained in parsing. 32 | \return the error message. 33 | \note User can make a copy of this function for localization. 34 | Using switch-case is safer for future modification of error codes. 35 | */ 36 | inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { 37 | switch (parseErrorCode) { 38 | case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); 39 | 40 | case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); 41 | case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); 42 | 43 | case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); 44 | 45 | case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); 46 | case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); 47 | case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); 48 | 49 | case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); 50 | 51 | case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); 52 | case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); 53 | case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); 54 | case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); 55 | case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); 56 | 57 | case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); 58 | case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); 59 | case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); 60 | 61 | case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); 62 | case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); 63 | 64 | default: return RAPIDJSON_ERROR_STRING("Unknown error."); 65 | } 66 | } 67 | 68 | RAPIDJSON_NAMESPACE_END 69 | 70 | #ifdef __clang__ 71 | RAPIDJSON_DIAG_POP 72 | #endif 73 | 74 | #endif // RAPIDJSON_ERROR_EN_H_ 75 | -------------------------------------------------------------------------------- /examples/rapidjson/rapidjson/error/error.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_ERROR_ERROR_H_ 16 | #define RAPIDJSON_ERROR_ERROR_H_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | #ifdef __clang__ 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(padded) 23 | #endif 24 | 25 | /*! \file error.h */ 26 | 27 | /*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */ 28 | 29 | /////////////////////////////////////////////////////////////////////////////// 30 | // RAPIDJSON_ERROR_CHARTYPE 31 | 32 | //! Character type of error messages. 33 | /*! \ingroup RAPIDJSON_ERRORS 34 | The default character type is \c char. 35 | On Windows, user can define this macro as \c TCHAR for supporting both 36 | unicode/non-unicode settings. 37 | */ 38 | #ifndef RAPIDJSON_ERROR_CHARTYPE 39 | #define RAPIDJSON_ERROR_CHARTYPE char 40 | #endif 41 | 42 | /////////////////////////////////////////////////////////////////////////////// 43 | // RAPIDJSON_ERROR_STRING 44 | 45 | //! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[]. 46 | /*! \ingroup RAPIDJSON_ERRORS 47 | By default this conversion macro does nothing. 48 | On Windows, user can define this macro as \c _T(x) for supporting both 49 | unicode/non-unicode settings. 50 | */ 51 | #ifndef RAPIDJSON_ERROR_STRING 52 | #define RAPIDJSON_ERROR_STRING(x) x 53 | #endif 54 | 55 | RAPIDJSON_NAMESPACE_BEGIN 56 | 57 | /////////////////////////////////////////////////////////////////////////////// 58 | // ParseErrorCode 59 | 60 | //! Error code of parsing. 61 | /*! \ingroup RAPIDJSON_ERRORS 62 | \see GenericReader::Parse, GenericReader::GetParseErrorCode 63 | */ 64 | enum ParseErrorCode { 65 | kParseErrorNone = 0, //!< No error. 66 | 67 | kParseErrorDocumentEmpty, //!< The document is empty. 68 | kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. 69 | 70 | kParseErrorValueInvalid, //!< Invalid value. 71 | 72 | kParseErrorObjectMissName, //!< Missing a name for object member. 73 | kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. 74 | kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. 75 | 76 | kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. 77 | 78 | kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. 79 | kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. 80 | kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. 81 | kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. 82 | kParseErrorStringInvalidEncoding, //!< Invalid encoding in string. 83 | 84 | kParseErrorNumberTooBig, //!< Number too big to be stored in double. 85 | kParseErrorNumberMissFraction, //!< Miss fraction part in number. 86 | kParseErrorNumberMissExponent, //!< Miss exponent in number. 87 | 88 | kParseErrorTermination, //!< Parsing was terminated. 89 | kParseErrorUnspecificSyntaxError //!< Unspecific syntax error. 90 | }; 91 | 92 | //! Result of parsing (wraps ParseErrorCode) 93 | /*! 94 | \ingroup RAPIDJSON_ERRORS 95 | \code 96 | Document doc; 97 | ParseResult ok = doc.Parse("[42]"); 98 | if (!ok) { 99 | fprintf(stderr, "JSON parse error: %s (%u)", 100 | GetParseError_En(ok.Code()), ok.Offset()); 101 | exit(EXIT_FAILURE); 102 | } 103 | \endcode 104 | \see GenericReader::Parse, GenericDocument::Parse 105 | */ 106 | struct ParseResult { 107 | //!! Unspecified boolean type 108 | typedef bool (ParseResult::*BooleanType)() const; 109 | public: 110 | //! Default constructor, no error. 111 | ParseResult() : code_(kParseErrorNone), offset_(0) {} 112 | //! Constructor to set an error. 113 | ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} 114 | 115 | //! Get the error code. 116 | ParseErrorCode Code() const { return code_; } 117 | //! Get the error offset, if \ref IsError(), 0 otherwise. 118 | size_t Offset() const { return offset_; } 119 | 120 | //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError(). 121 | operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; } 122 | //! Whether the result is an error. 123 | bool IsError() const { return code_ != kParseErrorNone; } 124 | 125 | bool operator==(const ParseResult& that) const { return code_ == that.code_; } 126 | bool operator==(ParseErrorCode code) const { return code_ == code; } 127 | friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } 128 | 129 | bool operator!=(const ParseResult& that) const { return !(*this == that); } 130 | bool operator!=(ParseErrorCode code) const { return !(*this == code); } 131 | friend bool operator!=(ParseErrorCode code, const ParseResult & err) { return err != code; } 132 | 133 | //! Reset error code. 134 | void Clear() { Set(kParseErrorNone); } 135 | //! Update error code and offset. 136 | void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } 137 | 138 | private: 139 | ParseErrorCode code_; 140 | size_t offset_; 141 | }; 142 | 143 | //! Function pointer type of GetParseError(). 144 | /*! \ingroup RAPIDJSON_ERRORS 145 | 146 | This is the prototype for \c GetParseError_X(), where \c X is a locale. 147 | User can dynamically change locale in runtime, e.g.: 148 | \code 149 | GetParseErrorFunc GetParseError = GetParseError_En; // or whatever 150 | const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode()); 151 | \endcode 152 | */ 153 | typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode); 154 | 155 | RAPIDJSON_NAMESPACE_END 156 | 157 | #ifdef __clang__ 158 | RAPIDJSON_DIAG_POP 159 | #endif 160 | 161 | #endif // RAPIDJSON_ERROR_ERROR_H_ 162 | -------------------------------------------------------------------------------- /examples/rapidjson/rapidjson/filereadstream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_FILEREADSTREAM_H_ 16 | #define RAPIDJSON_FILEREADSTREAM_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | 21 | #ifdef __clang__ 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(padded) 24 | RAPIDJSON_DIAG_OFF(unreachable-code) 25 | RAPIDJSON_DIAG_OFF(missing-noreturn) 26 | #endif 27 | 28 | RAPIDJSON_NAMESPACE_BEGIN 29 | 30 | //! File byte stream for input using fread(). 31 | /*! 32 | \note implements Stream concept 33 | */ 34 | class FileReadStream { 35 | public: 36 | typedef char Ch; //!< Character type (byte). 37 | 38 | //! Constructor. 39 | /*! 40 | \param fp File pointer opened for read. 41 | \param buffer user-supplied buffer. 42 | \param bufferSize size of buffer in bytes. Must >=4 bytes. 43 | */ 44 | FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { 45 | RAPIDJSON_ASSERT(fp_ != 0); 46 | RAPIDJSON_ASSERT(bufferSize >= 4); 47 | Read(); 48 | } 49 | 50 | Ch Peek() const { return *current_; } 51 | Ch Take() { Ch c = *current_; Read(); return c; } 52 | size_t Tell() const { return count_ + static_cast(current_ - buffer_); } 53 | 54 | // Not implemented 55 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 56 | void Flush() { RAPIDJSON_ASSERT(false); } 57 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 58 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 59 | 60 | // For encoding detection only. 61 | const Ch* Peek4() const { 62 | return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0; 63 | } 64 | 65 | private: 66 | void Read() { 67 | if (current_ < bufferLast_) 68 | ++current_; 69 | else if (!eof_) { 70 | count_ += readCount_; 71 | readCount_ = std::fread(buffer_, 1, bufferSize_, fp_); 72 | bufferLast_ = buffer_ + readCount_ - 1; 73 | current_ = buffer_; 74 | 75 | if (readCount_ < bufferSize_) { 76 | buffer_[readCount_] = '\0'; 77 | ++bufferLast_; 78 | eof_ = true; 79 | } 80 | } 81 | } 82 | 83 | std::FILE* fp_; 84 | Ch *buffer_; 85 | size_t bufferSize_; 86 | Ch *bufferLast_; 87 | Ch *current_; 88 | size_t readCount_; 89 | size_t count_; //!< Number of characters read 90 | bool eof_; 91 | }; 92 | 93 | RAPIDJSON_NAMESPACE_END 94 | 95 | #ifdef __clang__ 96 | RAPIDJSON_DIAG_POP 97 | #endif 98 | 99 | #endif // RAPIDJSON_FILESTREAM_H_ 100 | -------------------------------------------------------------------------------- /examples/rapidjson/rapidjson/filewritestream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_FILEWRITESTREAM_H_ 16 | #define RAPIDJSON_FILEWRITESTREAM_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | 21 | #ifdef __clang__ 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(unreachable-code) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Wrapper of C file stream for output using fwrite(). 29 | /*! 30 | \note implements Stream concept 31 | */ 32 | class FileWriteStream { 33 | public: 34 | typedef char Ch; //!< Character type. Only support char. 35 | 36 | FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { 37 | RAPIDJSON_ASSERT(fp_ != 0); 38 | } 39 | 40 | void Put(char c) { 41 | if (current_ >= bufferEnd_) 42 | Flush(); 43 | 44 | *current_++ = c; 45 | } 46 | 47 | void PutN(char c, size_t n) { 48 | size_t avail = static_cast(bufferEnd_ - current_); 49 | while (n > avail) { 50 | std::memset(current_, c, avail); 51 | current_ += avail; 52 | Flush(); 53 | n -= avail; 54 | avail = static_cast(bufferEnd_ - current_); 55 | } 56 | 57 | if (n > 0) { 58 | std::memset(current_, c, n); 59 | current_ += n; 60 | } 61 | } 62 | 63 | void Flush() { 64 | if (current_ != buffer_) { 65 | size_t result = std::fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); 66 | if (result < static_cast(current_ - buffer_)) { 67 | // failure deliberately ignored at this time 68 | // added to avoid warn_unused_result build errors 69 | } 70 | current_ = buffer_; 71 | } 72 | } 73 | 74 | // Not implemented 75 | char Peek() const { RAPIDJSON_ASSERT(false); return 0; } 76 | char Take() { RAPIDJSON_ASSERT(false); return 0; } 77 | size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } 78 | char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 79 | size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } 80 | 81 | private: 82 | // Prohibit copy constructor & assignment operator. 83 | FileWriteStream(const FileWriteStream&); 84 | FileWriteStream& operator=(const FileWriteStream&); 85 | 86 | std::FILE* fp_; 87 | char *buffer_; 88 | char *bufferEnd_; 89 | char *current_; 90 | }; 91 | 92 | //! Implement specialized version of PutN() with memset() for better performance. 93 | template<> 94 | inline void PutN(FileWriteStream& stream, char c, size_t n) { 95 | stream.PutN(c, n); 96 | } 97 | 98 | RAPIDJSON_NAMESPACE_END 99 | 100 | #ifdef __clang__ 101 | RAPIDJSON_DIAG_POP 102 | #endif 103 | 104 | #endif // RAPIDJSON_FILESTREAM_H_ 105 | -------------------------------------------------------------------------------- /examples/rapidjson/rapidjson/fwd.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_FWD_H_ 16 | #define RAPIDJSON_FWD_H_ 17 | 18 | #include "rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | 22 | // encodings.h 23 | 24 | template struct UTF8; 25 | template struct UTF16; 26 | template struct UTF16BE; 27 | template struct UTF16LE; 28 | template struct UTF32; 29 | template struct UTF32BE; 30 | template struct UTF32LE; 31 | template struct ASCII; 32 | template struct AutoUTF; 33 | 34 | template 35 | struct Transcoder; 36 | 37 | // allocators.h 38 | 39 | class CrtAllocator; 40 | 41 | template 42 | class MemoryPoolAllocator; 43 | 44 | // stream.h 45 | 46 | template 47 | struct GenericStringStream; 48 | 49 | typedef GenericStringStream > StringStream; 50 | 51 | template 52 | struct GenericInsituStringStream; 53 | 54 | typedef GenericInsituStringStream > InsituStringStream; 55 | 56 | // stringbuffer.h 57 | 58 | template 59 | class GenericStringBuffer; 60 | 61 | typedef GenericStringBuffer, CrtAllocator> StringBuffer; 62 | 63 | // filereadstream.h 64 | 65 | class FileReadStream; 66 | 67 | // filewritestream.h 68 | 69 | class FileWriteStream; 70 | 71 | // memorybuffer.h 72 | 73 | template 74 | struct GenericMemoryBuffer; 75 | 76 | typedef GenericMemoryBuffer MemoryBuffer; 77 | 78 | // memorystream.h 79 | 80 | struct MemoryStream; 81 | 82 | // reader.h 83 | 84 | template 85 | struct BaseReaderHandler; 86 | 87 | template 88 | class GenericReader; 89 | 90 | typedef GenericReader, UTF8, CrtAllocator> Reader; 91 | 92 | // writer.h 93 | 94 | template 95 | class Writer; 96 | 97 | // prettywriter.h 98 | 99 | template 100 | class PrettyWriter; 101 | 102 | // document.h 103 | 104 | template 105 | class GenericMember; 106 | 107 | template 108 | class GenericMemberIterator; 109 | 110 | template 111 | struct GenericStringRef; 112 | 113 | template 114 | class GenericValue; 115 | 116 | typedef GenericValue, MemoryPoolAllocator > Value; 117 | 118 | template 119 | class GenericDocument; 120 | 121 | typedef GenericDocument, MemoryPoolAllocator, CrtAllocator> Document; 122 | 123 | // pointer.h 124 | 125 | template 126 | class GenericPointer; 127 | 128 | typedef GenericPointer Pointer; 129 | 130 | // schema.h 131 | 132 | template 133 | class IGenericRemoteSchemaDocumentProvider; 134 | 135 | template 136 | class GenericSchemaDocument; 137 | 138 | typedef GenericSchemaDocument SchemaDocument; 139 | typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; 140 | 141 | template < 142 | typename SchemaDocumentType, 143 | typename OutputHandler, 144 | typename StateAllocator> 145 | class GenericSchemaValidator; 146 | 147 | typedef GenericSchemaValidator, void>, CrtAllocator> SchemaValidator; 148 | 149 | RAPIDJSON_NAMESPACE_END 150 | 151 | #endif // RAPIDJSON_RAPIDJSONFWD_H_ 152 | -------------------------------------------------------------------------------- /examples/rapidjson/rapidjson/internal/clzll.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_CLZLL_H_ 16 | #define RAPIDJSON_CLZLL_H_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | #if defined(_MSC_VER) && !defined(UNDER_CE) 21 | #include 22 | #if defined(_WIN64) 23 | #pragma intrinsic(_BitScanReverse64) 24 | #else 25 | #pragma intrinsic(_BitScanReverse) 26 | #endif 27 | #endif 28 | 29 | RAPIDJSON_NAMESPACE_BEGIN 30 | namespace internal { 31 | 32 | inline uint32_t clzll(uint64_t x) { 33 | // Passing 0 to __builtin_clzll is UB in GCC and results in an 34 | // infinite loop in the software implementation. 35 | RAPIDJSON_ASSERT(x != 0); 36 | 37 | #if defined(_MSC_VER) && !defined(UNDER_CE) 38 | unsigned long r = 0; 39 | #if defined(_WIN64) 40 | _BitScanReverse64(&r, x); 41 | #else 42 | // Scan the high 32 bits. 43 | if (_BitScanReverse(&r, static_cast(x >> 32))) 44 | return 63 - (r + 32); 45 | 46 | // Scan the low 32 bits. 47 | _BitScanReverse(&r, static_cast(x & 0xFFFFFFFF)); 48 | #endif // _WIN64 49 | 50 | return 63 - r; 51 | #elif (defined(__GNUC__) && __GNUC__ >= 4) || RAPIDJSON_HAS_BUILTIN(__builtin_clzll) 52 | // __builtin_clzll wrapper 53 | return static_cast(__builtin_clzll(x)); 54 | #else 55 | // naive version 56 | uint32_t r = 0; 57 | while (!(x & (static_cast(1) << 63))) { 58 | x <<= 1; 59 | ++r; 60 | } 61 | 62 | return r; 63 | #endif // _MSC_VER 64 | } 65 | 66 | #define RAPIDJSON_CLZLL RAPIDJSON_NAMESPACE::internal::clzll 67 | 68 | } // namespace internal 69 | RAPIDJSON_NAMESPACE_END 70 | 71 | #endif // RAPIDJSON_CLZLL_H_ 72 | -------------------------------------------------------------------------------- /examples/rapidjson/rapidjson/internal/ieee754.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_IEEE754_ 16 | #define RAPIDJSON_IEEE754_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | namespace internal { 22 | 23 | class Double { 24 | public: 25 | Double() {} 26 | Double(double d) : d_(d) {} 27 | Double(uint64_t u) : u_(u) {} 28 | 29 | double Value() const { return d_; } 30 | uint64_t Uint64Value() const { return u_; } 31 | 32 | double NextPositiveDouble() const { 33 | RAPIDJSON_ASSERT(!Sign()); 34 | return Double(u_ + 1).Value(); 35 | } 36 | 37 | bool Sign() const { return (u_ & kSignMask) != 0; } 38 | uint64_t Significand() const { return u_ & kSignificandMask; } 39 | int Exponent() const { return static_cast(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); } 40 | 41 | bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } 42 | bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } 43 | bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; } 44 | bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } 45 | bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } 46 | 47 | uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } 48 | int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } 49 | uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } 50 | 51 | static int EffectiveSignificandSize(int order) { 52 | if (order >= -1021) 53 | return 53; 54 | else if (order <= -1074) 55 | return 0; 56 | else 57 | return order + 1074; 58 | } 59 | 60 | private: 61 | static const int kSignificandSize = 52; 62 | static const int kExponentBias = 0x3FF; 63 | static const int kDenormalExponent = 1 - kExponentBias; 64 | static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); 65 | static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); 66 | static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); 67 | static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); 68 | 69 | union { 70 | double d_; 71 | uint64_t u_; 72 | }; 73 | }; 74 | 75 | } // namespace internal 76 | RAPIDJSON_NAMESPACE_END 77 | 78 | #endif // RAPIDJSON_IEEE754_ 79 | -------------------------------------------------------------------------------- /examples/rapidjson/rapidjson/internal/meta.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_META_H_ 16 | #define RAPIDJSON_INTERNAL_META_H_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | #ifdef __GNUC__ 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(effc++) 23 | #endif 24 | 25 | #if defined(_MSC_VER) && !defined(__clang__) 26 | RAPIDJSON_DIAG_PUSH 27 | RAPIDJSON_DIAG_OFF(6334) 28 | #endif 29 | 30 | #if RAPIDJSON_HAS_CXX11_TYPETRAITS 31 | #include 32 | #endif 33 | 34 | //@cond RAPIDJSON_INTERNAL 35 | RAPIDJSON_NAMESPACE_BEGIN 36 | namespace internal { 37 | 38 | // Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching 39 | template struct Void { typedef void Type; }; 40 | 41 | /////////////////////////////////////////////////////////////////////////////// 42 | // BoolType, TrueType, FalseType 43 | // 44 | template struct BoolType { 45 | static const bool Value = Cond; 46 | typedef BoolType Type; 47 | }; 48 | typedef BoolType TrueType; 49 | typedef BoolType FalseType; 50 | 51 | 52 | /////////////////////////////////////////////////////////////////////////////// 53 | // SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr 54 | // 55 | 56 | template struct SelectIfImpl { template struct Apply { typedef T1 Type; }; }; 57 | template <> struct SelectIfImpl { template struct Apply { typedef T2 Type; }; }; 58 | template struct SelectIfCond : SelectIfImpl::template Apply {}; 59 | template struct SelectIf : SelectIfCond {}; 60 | 61 | template struct AndExprCond : FalseType {}; 62 | template <> struct AndExprCond : TrueType {}; 63 | template struct OrExprCond : TrueType {}; 64 | template <> struct OrExprCond : FalseType {}; 65 | 66 | template struct BoolExpr : SelectIf::Type {}; 67 | template struct NotExpr : SelectIf::Type {}; 68 | template struct AndExpr : AndExprCond::Type {}; 69 | template struct OrExpr : OrExprCond::Type {}; 70 | 71 | 72 | /////////////////////////////////////////////////////////////////////////////// 73 | // AddConst, MaybeAddConst, RemoveConst 74 | template struct AddConst { typedef const T Type; }; 75 | template struct MaybeAddConst : SelectIfCond {}; 76 | template struct RemoveConst { typedef T Type; }; 77 | template struct RemoveConst { typedef T Type; }; 78 | 79 | 80 | /////////////////////////////////////////////////////////////////////////////// 81 | // IsSame, IsConst, IsMoreConst, IsPointer 82 | // 83 | template struct IsSame : FalseType {}; 84 | template struct IsSame : TrueType {}; 85 | 86 | template struct IsConst : FalseType {}; 87 | template struct IsConst : TrueType {}; 88 | 89 | template 90 | struct IsMoreConst 91 | : AndExpr::Type, typename RemoveConst::Type>, 92 | BoolType::Value >= IsConst::Value> >::Type {}; 93 | 94 | template struct IsPointer : FalseType {}; 95 | template struct IsPointer : TrueType {}; 96 | 97 | /////////////////////////////////////////////////////////////////////////////// 98 | // IsBaseOf 99 | // 100 | #if RAPIDJSON_HAS_CXX11_TYPETRAITS 101 | 102 | template struct IsBaseOf 103 | : BoolType< ::std::is_base_of::value> {}; 104 | 105 | #else // simplified version adopted from Boost 106 | 107 | template struct IsBaseOfImpl { 108 | RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0); 109 | RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0); 110 | 111 | typedef char (&Yes)[1]; 112 | typedef char (&No) [2]; 113 | 114 | template 115 | static Yes Check(const D*, T); 116 | static No Check(const B*, int); 117 | 118 | struct Host { 119 | operator const B*() const; 120 | operator const D*(); 121 | }; 122 | 123 | enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) }; 124 | }; 125 | 126 | template struct IsBaseOf 127 | : OrExpr, BoolExpr > >::Type {}; 128 | 129 | #endif // RAPIDJSON_HAS_CXX11_TYPETRAITS 130 | 131 | 132 | ////////////////////////////////////////////////////////////////////////// 133 | // EnableIf / DisableIf 134 | // 135 | template struct EnableIfCond { typedef T Type; }; 136 | template struct EnableIfCond { /* empty */ }; 137 | 138 | template struct DisableIfCond { typedef T Type; }; 139 | template struct DisableIfCond { /* empty */ }; 140 | 141 | template 142 | struct EnableIf : EnableIfCond {}; 143 | 144 | template 145 | struct DisableIf : DisableIfCond {}; 146 | 147 | // SFINAE helpers 148 | struct SfinaeTag {}; 149 | template struct RemoveSfinaeTag; 150 | template struct RemoveSfinaeTag { typedef T Type; }; 151 | 152 | #define RAPIDJSON_REMOVEFPTR_(type) \ 153 | typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \ 154 | < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type 155 | 156 | #define RAPIDJSON_ENABLEIF(cond) \ 157 | typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ 158 | ::Type * = NULL 159 | 160 | #define RAPIDJSON_DISABLEIF(cond) \ 161 | typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ 162 | ::Type * = NULL 163 | 164 | #define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ 165 | typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ 166 | ::Type 168 | 169 | #define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ 170 | typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ 171 | ::Type 173 | 174 | } // namespace internal 175 | RAPIDJSON_NAMESPACE_END 176 | //@endcond 177 | 178 | #if defined(_MSC_VER) && !defined(__clang__) 179 | RAPIDJSON_DIAG_POP 180 | #endif 181 | 182 | #ifdef __GNUC__ 183 | RAPIDJSON_DIAG_POP 184 | #endif 185 | 186 | #endif // RAPIDJSON_INTERNAL_META_H_ 187 | -------------------------------------------------------------------------------- /examples/rapidjson/rapidjson/internal/pow10.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_POW10_ 16 | #define RAPIDJSON_POW10_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | namespace internal { 22 | 23 | //! Computes integer powers of 10 in double (10.0^n). 24 | /*! This function uses lookup table for fast and accurate results. 25 | \param n non-negative exponent. Must <= 308. 26 | \return 10.0^n 27 | */ 28 | inline double Pow10(int n) { 29 | static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes 30 | 1e+0, 31 | 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, 32 | 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, 33 | 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, 34 | 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, 35 | 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, 36 | 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, 37 | 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, 38 | 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, 39 | 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, 40 | 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, 41 | 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, 42 | 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, 43 | 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, 44 | 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, 45 | 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, 46 | 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 47 | }; 48 | RAPIDJSON_ASSERT(n >= 0 && n <= 308); 49 | return e[n]; 50 | } 51 | 52 | } // namespace internal 53 | RAPIDJSON_NAMESPACE_END 54 | 55 | #endif // RAPIDJSON_POW10_ 56 | -------------------------------------------------------------------------------- /examples/rapidjson/rapidjson/internal/strfunc.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ 16 | #define RAPIDJSON_INTERNAL_STRFUNC_H_ 17 | 18 | #include "../stream.h" 19 | #include 20 | 21 | RAPIDJSON_NAMESPACE_BEGIN 22 | namespace internal { 23 | 24 | //! Custom strlen() which works on different character types. 25 | /*! \tparam Ch Character type (e.g. char, wchar_t, short) 26 | \param s Null-terminated input string. 27 | \return Number of characters in the string. 28 | \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. 29 | */ 30 | template 31 | inline SizeType StrLen(const Ch* s) { 32 | RAPIDJSON_ASSERT(s != 0); 33 | const Ch* p = s; 34 | while (*p) ++p; 35 | return SizeType(p - s); 36 | } 37 | 38 | template <> 39 | inline SizeType StrLen(const char* s) { 40 | return SizeType(std::strlen(s)); 41 | } 42 | 43 | template <> 44 | inline SizeType StrLen(const wchar_t* s) { 45 | return SizeType(std::wcslen(s)); 46 | } 47 | 48 | //! Returns number of code points in a encoded string. 49 | template 50 | bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { 51 | RAPIDJSON_ASSERT(s != 0); 52 | RAPIDJSON_ASSERT(outCount != 0); 53 | GenericStringStream is(s); 54 | const typename Encoding::Ch* end = s + length; 55 | SizeType count = 0; 56 | while (is.src_ < end) { 57 | unsigned codepoint; 58 | if (!Encoding::Decode(is, &codepoint)) 59 | return false; 60 | count++; 61 | } 62 | *outCount = count; 63 | return true; 64 | } 65 | 66 | } // namespace internal 67 | RAPIDJSON_NAMESPACE_END 68 | 69 | #endif // RAPIDJSON_INTERNAL_STRFUNC_H_ 70 | -------------------------------------------------------------------------------- /examples/rapidjson/rapidjson/internal/swap.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_SWAP_H_ 16 | #define RAPIDJSON_INTERNAL_SWAP_H_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | #if defined(__clang__) 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(c++98-compat) 23 | #endif 24 | 25 | RAPIDJSON_NAMESPACE_BEGIN 26 | namespace internal { 27 | 28 | //! Custom swap() to avoid dependency on C++ header 29 | /*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only. 30 | \note This has the same semantics as std::swap(). 31 | */ 32 | template 33 | inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { 34 | T tmp = a; 35 | a = b; 36 | b = tmp; 37 | } 38 | 39 | } // namespace internal 40 | RAPIDJSON_NAMESPACE_END 41 | 42 | #if defined(__clang__) 43 | RAPIDJSON_DIAG_POP 44 | #endif 45 | 46 | #endif // RAPIDJSON_INTERNAL_SWAP_H_ 47 | -------------------------------------------------------------------------------- /examples/rapidjson/rapidjson/istreamwrapper.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_ISTREAMWRAPPER_H_ 16 | #define RAPIDJSON_ISTREAMWRAPPER_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | #include 21 | 22 | #ifdef __clang__ 23 | RAPIDJSON_DIAG_PUSH 24 | RAPIDJSON_DIAG_OFF(padded) 25 | #elif defined(_MSC_VER) 26 | RAPIDJSON_DIAG_PUSH 27 | RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized 28 | #endif 29 | 30 | RAPIDJSON_NAMESPACE_BEGIN 31 | 32 | //! Wrapper of \c std::basic_istream into RapidJSON's Stream concept. 33 | /*! 34 | The classes can be wrapped including but not limited to: 35 | 36 | - \c std::istringstream 37 | - \c std::stringstream 38 | - \c std::wistringstream 39 | - \c std::wstringstream 40 | - \c std::ifstream 41 | - \c std::fstream 42 | - \c std::wifstream 43 | - \c std::wfstream 44 | 45 | \tparam StreamType Class derived from \c std::basic_istream. 46 | */ 47 | 48 | template 49 | class BasicIStreamWrapper { 50 | public: 51 | typedef typename StreamType::char_type Ch; 52 | 53 | //! Constructor. 54 | /*! 55 | \param stream stream opened for read. 56 | */ 57 | BasicIStreamWrapper(StreamType &stream) : stream_(stream), buffer_(peekBuffer_), bufferSize_(4), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { 58 | Read(); 59 | } 60 | 61 | //! Constructor. 62 | /*! 63 | \param stream stream opened for read. 64 | \param buffer user-supplied buffer. 65 | \param bufferSize size of buffer in bytes. Must >=4 bytes. 66 | */ 67 | BasicIStreamWrapper(StreamType &stream, char* buffer, size_t bufferSize) : stream_(stream), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { 68 | RAPIDJSON_ASSERT(bufferSize >= 4); 69 | Read(); 70 | } 71 | 72 | Ch Peek() const { return *current_; } 73 | Ch Take() { Ch c = *current_; Read(); return c; } 74 | size_t Tell() const { return count_ + static_cast(current_ - buffer_); } 75 | 76 | // Not implemented 77 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 78 | void Flush() { RAPIDJSON_ASSERT(false); } 79 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 80 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 81 | 82 | // For encoding detection only. 83 | const Ch* Peek4() const { 84 | return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0; 85 | } 86 | 87 | private: 88 | BasicIStreamWrapper(); 89 | BasicIStreamWrapper(const BasicIStreamWrapper&); 90 | BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); 91 | 92 | void Read() { 93 | if (current_ < bufferLast_) 94 | ++current_; 95 | else if (!eof_) { 96 | count_ += readCount_; 97 | readCount_ = bufferSize_; 98 | bufferLast_ = buffer_ + readCount_ - 1; 99 | current_ = buffer_; 100 | 101 | if (!stream_.read(buffer_, static_cast(bufferSize_))) { 102 | readCount_ = static_cast(stream_.gcount()); 103 | *(bufferLast_ = buffer_ + readCount_) = '\0'; 104 | eof_ = true; 105 | } 106 | } 107 | } 108 | 109 | StreamType &stream_; 110 | Ch peekBuffer_[4], *buffer_; 111 | size_t bufferSize_; 112 | Ch *bufferLast_; 113 | Ch *current_; 114 | size_t readCount_; 115 | size_t count_; //!< Number of characters read 116 | bool eof_; 117 | }; 118 | 119 | typedef BasicIStreamWrapper IStreamWrapper; 120 | typedef BasicIStreamWrapper WIStreamWrapper; 121 | 122 | #if defined(__clang__) || defined(_MSC_VER) 123 | RAPIDJSON_DIAG_POP 124 | #endif 125 | 126 | RAPIDJSON_NAMESPACE_END 127 | 128 | #endif // RAPIDJSON_ISTREAMWRAPPER_H_ 129 | -------------------------------------------------------------------------------- /examples/rapidjson/rapidjson/memorybuffer.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_MEMORYBUFFER_H_ 16 | #define RAPIDJSON_MEMORYBUFFER_H_ 17 | 18 | #include "stream.h" 19 | #include "internal/stack.h" 20 | 21 | RAPIDJSON_NAMESPACE_BEGIN 22 | 23 | //! Represents an in-memory output byte stream. 24 | /*! 25 | This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream. 26 | 27 | It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file. 28 | 29 | Differences between MemoryBuffer and StringBuffer: 30 | 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. 31 | 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator. 32 | 33 | \tparam Allocator type for allocating memory buffer. 34 | \note implements Stream concept 35 | */ 36 | template 37 | struct GenericMemoryBuffer { 38 | typedef char Ch; // byte 39 | 40 | GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} 41 | 42 | void Put(Ch c) { *stack_.template Push() = c; } 43 | void Flush() {} 44 | 45 | void Clear() { stack_.Clear(); } 46 | void ShrinkToFit() { stack_.ShrinkToFit(); } 47 | Ch* Push(size_t count) { return stack_.template Push(count); } 48 | void Pop(size_t count) { stack_.template Pop(count); } 49 | 50 | const Ch* GetBuffer() const { 51 | return stack_.template Bottom(); 52 | } 53 | 54 | size_t GetSize() const { return stack_.GetSize(); } 55 | 56 | static const size_t kDefaultCapacity = 256; 57 | mutable internal::Stack stack_; 58 | }; 59 | 60 | typedef GenericMemoryBuffer<> MemoryBuffer; 61 | 62 | //! Implement specialized version of PutN() with memset() for better performance. 63 | template<> 64 | inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) { 65 | std::memset(memoryBuffer.stack_.Push(n), c, n * sizeof(c)); 66 | } 67 | 68 | RAPIDJSON_NAMESPACE_END 69 | 70 | #endif // RAPIDJSON_MEMORYBUFFER_H_ 71 | -------------------------------------------------------------------------------- /examples/rapidjson/rapidjson/memorystream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_MEMORYSTREAM_H_ 16 | #define RAPIDJSON_MEMORYSTREAM_H_ 17 | 18 | #include "stream.h" 19 | 20 | #ifdef __clang__ 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(unreachable-code) 23 | RAPIDJSON_DIAG_OFF(missing-noreturn) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Represents an in-memory input byte stream. 29 | /*! 30 | This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream. 31 | 32 | It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file. 33 | 34 | Differences between MemoryStream and StringStream: 35 | 1. StringStream has encoding but MemoryStream is a byte stream. 36 | 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source. 37 | 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4(). 38 | \note implements Stream concept 39 | */ 40 | struct MemoryStream { 41 | typedef char Ch; // byte 42 | 43 | MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} 44 | 45 | Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; } 46 | Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; } 47 | size_t Tell() const { return static_cast(src_ - begin_); } 48 | 49 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 50 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 51 | void Flush() { RAPIDJSON_ASSERT(false); } 52 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 53 | 54 | // For encoding detection only. 55 | const Ch* Peek4() const { 56 | return Tell() + 4 <= size_ ? src_ : 0; 57 | } 58 | 59 | const Ch* src_; //!< Current read position. 60 | const Ch* begin_; //!< Original head of the string. 61 | const Ch* end_; //!< End of stream. 62 | size_t size_; //!< Size of the stream. 63 | }; 64 | 65 | RAPIDJSON_NAMESPACE_END 66 | 67 | #ifdef __clang__ 68 | RAPIDJSON_DIAG_POP 69 | #endif 70 | 71 | #endif // RAPIDJSON_MEMORYBUFFER_H_ 72 | -------------------------------------------------------------------------------- /examples/rapidjson/rapidjson/ostreamwrapper.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_OSTREAMWRAPPER_H_ 16 | #define RAPIDJSON_OSTREAMWRAPPER_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | 21 | #ifdef __clang__ 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(padded) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept. 29 | /*! 30 | The classes can be wrapped including but not limited to: 31 | 32 | - \c std::ostringstream 33 | - \c std::stringstream 34 | - \c std::wpstringstream 35 | - \c std::wstringstream 36 | - \c std::ifstream 37 | - \c std::fstream 38 | - \c std::wofstream 39 | - \c std::wfstream 40 | 41 | \tparam StreamType Class derived from \c std::basic_ostream. 42 | */ 43 | 44 | template 45 | class BasicOStreamWrapper { 46 | public: 47 | typedef typename StreamType::char_type Ch; 48 | BasicOStreamWrapper(StreamType& stream) : stream_(stream) {} 49 | 50 | void Put(Ch c) { 51 | stream_.put(c); 52 | } 53 | 54 | void Flush() { 55 | stream_.flush(); 56 | } 57 | 58 | // Not implemented 59 | char Peek() const { RAPIDJSON_ASSERT(false); return 0; } 60 | char Take() { RAPIDJSON_ASSERT(false); return 0; } 61 | size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } 62 | char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 63 | size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } 64 | 65 | private: 66 | BasicOStreamWrapper(const BasicOStreamWrapper&); 67 | BasicOStreamWrapper& operator=(const BasicOStreamWrapper&); 68 | 69 | StreamType& stream_; 70 | }; 71 | 72 | typedef BasicOStreamWrapper OStreamWrapper; 73 | typedef BasicOStreamWrapper WOStreamWrapper; 74 | 75 | #ifdef __clang__ 76 | RAPIDJSON_DIAG_POP 77 | #endif 78 | 79 | RAPIDJSON_NAMESPACE_END 80 | 81 | #endif // RAPIDJSON_OSTREAMWRAPPER_H_ 82 | -------------------------------------------------------------------------------- /examples/rapidjson/rapidjson/stringbuffer.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_STRINGBUFFER_H_ 16 | #define RAPIDJSON_STRINGBUFFER_H_ 17 | 18 | #include "stream.h" 19 | #include "internal/stack.h" 20 | 21 | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 22 | #include // std::move 23 | #endif 24 | 25 | #include "internal/stack.h" 26 | 27 | #if defined(__clang__) 28 | RAPIDJSON_DIAG_PUSH 29 | RAPIDJSON_DIAG_OFF(c++98-compat) 30 | #endif 31 | 32 | RAPIDJSON_NAMESPACE_BEGIN 33 | 34 | //! Represents an in-memory output stream. 35 | /*! 36 | \tparam Encoding Encoding of the stream. 37 | \tparam Allocator type for allocating memory buffer. 38 | \note implements Stream concept 39 | */ 40 | template 41 | class GenericStringBuffer { 42 | public: 43 | typedef typename Encoding::Ch Ch; 44 | 45 | GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} 46 | 47 | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 48 | GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {} 49 | GenericStringBuffer& operator=(GenericStringBuffer&& rhs) { 50 | if (&rhs != this) 51 | stack_ = std::move(rhs.stack_); 52 | return *this; 53 | } 54 | #endif 55 | 56 | void Put(Ch c) { *stack_.template Push() = c; } 57 | void PutUnsafe(Ch c) { *stack_.template PushUnsafe() = c; } 58 | void Flush() {} 59 | 60 | void Clear() { stack_.Clear(); } 61 | void ShrinkToFit() { 62 | // Push and pop a null terminator. This is safe. 63 | *stack_.template Push() = '\0'; 64 | stack_.ShrinkToFit(); 65 | stack_.template Pop(1); 66 | } 67 | 68 | void Reserve(size_t count) { stack_.template Reserve(count); } 69 | Ch* Push(size_t count) { return stack_.template Push(count); } 70 | Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe(count); } 71 | void Pop(size_t count) { stack_.template Pop(count); } 72 | 73 | const Ch* GetString() const { 74 | // Push and pop a null terminator. This is safe. 75 | *stack_.template Push() = '\0'; 76 | stack_.template Pop(1); 77 | 78 | return stack_.template Bottom(); 79 | } 80 | 81 | //! Get the size of string in bytes in the string buffer. 82 | size_t GetSize() const { return stack_.GetSize(); } 83 | 84 | //! Get the length of string in Ch in the string buffer. 85 | size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); } 86 | 87 | static const size_t kDefaultCapacity = 256; 88 | mutable internal::Stack stack_; 89 | 90 | private: 91 | // Prohibit copy constructor & assignment operator. 92 | GenericStringBuffer(const GenericStringBuffer&); 93 | GenericStringBuffer& operator=(const GenericStringBuffer&); 94 | }; 95 | 96 | //! String buffer with UTF8 encoding 97 | typedef GenericStringBuffer > StringBuffer; 98 | 99 | template 100 | inline void PutReserve(GenericStringBuffer& stream, size_t count) { 101 | stream.Reserve(count); 102 | } 103 | 104 | template 105 | inline void PutUnsafe(GenericStringBuffer& stream, typename Encoding::Ch c) { 106 | stream.PutUnsafe(c); 107 | } 108 | 109 | //! Implement specialized version of PutN() with memset() for better performance. 110 | template<> 111 | inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { 112 | std::memset(stream.stack_.Push(n), c, n * sizeof(c)); 113 | } 114 | 115 | RAPIDJSON_NAMESPACE_END 116 | 117 | #if defined(__clang__) 118 | RAPIDJSON_DIAG_POP 119 | #endif 120 | 121 | #endif // RAPIDJSON_STRINGBUFFER_H_ 122 | -------------------------------------------------------------------------------- /examples/rapidjson/testrapidjson.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #if !defined(CHEAPEN) 9 | #define CHEAPEN 0 10 | #endif 11 | 12 | #if CHEAPEN 13 | #include "cheap.h" 14 | #endif 15 | 16 | #include "rapidjson/document.h" 17 | #include "rapidjson/rapidjson.h" 18 | #include "rapidjson/stringbuffer.h" 19 | #include "rapidjson/writer.h" 20 | 21 | // From https://github.com/lefticus/cpp_weekly/blob/master/PMR/json_tests.cpp 22 | 23 | struct RapidJSONPMRAlloc 24 | { 25 | std::pmr::memory_resource *upstream = std::pmr::get_default_resource(); 26 | 27 | static constexpr bool kNeedFree = true; 28 | 29 | static constexpr auto objectOffset = alignof(std::max_align_t); 30 | static constexpr auto memPadding = objectOffset * 2; 31 | 32 | void *Malloc(size_t size) 33 | { 34 | if (size != 0) { 35 | const auto allocated_size = size + memPadding; 36 | std::byte *newPtr = static_cast(upstream->allocate(allocated_size)); 37 | auto *ptrToReturn = newPtr + memPadding; 38 | // placement new a pointer to ourselves at the first memory location 39 | new (newPtr)(RapidJSONPMRAlloc *)(this); 40 | // placement new the size in the second location 41 | new (newPtr + objectOffset)(std::size_t)(size); 42 | return ptrToReturn; 43 | } else { 44 | return nullptr; 45 | } 46 | } 47 | 48 | void freePtr(void *origPtr, size_t originalSize) 49 | { 50 | if (origPtr == nullptr) { 51 | return; 52 | } 53 | upstream->deallocate(static_cast(origPtr) - memPadding, originalSize + memPadding); 54 | } 55 | 56 | void *Realloc(void *origPtr, size_t originalSize, size_t newSize) 57 | { 58 | if (newSize == 0) { 59 | freePtr(origPtr, originalSize); 60 | return nullptr; 61 | } 62 | 63 | if (newSize <= originalSize) { 64 | return origPtr; 65 | } 66 | 67 | void *newPtr = Malloc(newSize); 68 | std::memcpy(newPtr, origPtr, originalSize); 69 | freePtr(origPtr, originalSize); 70 | return newPtr; 71 | } 72 | 73 | // and Free needs to be static, which causes this whole thing 74 | // to fall apart. This means that we have to keep our own list of allocated memory 75 | // with our own pointers back to ourselves and our own list of sizes 76 | // so we can push all of this back to the upstream allocator 77 | static void Free(void *ptr) 78 | { 79 | if (ptr == nullptr ) { 80 | return; 81 | } 82 | 83 | std::byte *startOfData = static_cast(ptr) - memPadding; 84 | 85 | auto *ptrToAllocator = *reinterpret_cast(startOfData); 86 | auto origAllocatedSize = *reinterpret_cast(startOfData + objectOffset); 87 | 88 | ptrToAllocator->freePtr(ptr, origAllocatedSize); 89 | } 90 | }; 91 | 92 | void parseMe(const char * s, size_t sz) 93 | { 94 | { 95 | #if CHEAPEN 96 | cheap::cheap reg; // | cheap::SIZE_TAKEN 97 | #endif 98 | using namespace rapidjson; 99 | #if 0 100 | CrtAllocator alloc; 101 | GenericDocument, CrtAllocator> d(&alloc); 102 | #else 103 | using namespace rapidjson; 104 | RapidJSONPMRAlloc alloc; 105 | GenericDocument, RapidJSONPMRAlloc> d(&alloc); 106 | //Document d; 107 | // GenericDocument> d; 108 | #endif 109 | d.Parse(s, sz); 110 | } 111 | } 112 | 113 | int main() 114 | { 115 | // std::ifstream i("gsoc-2018.json"); 116 | std::ifstream i("citm_catalog.json"); 117 | std::ostringstream sstr; 118 | sstr << i.rdbuf(); 119 | // mallopt(M_MMAP_THRESHOLD, 10487560 + 32); 120 | for (auto i = 0; i < 1000; i++) 121 | { 122 | parseMe(sstr.str().data(), sstr.str().size()); 123 | } 124 | return 0; 125 | } 126 | -------------------------------------------------------------------------------- /examples/swaptions/COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2007 Intel Corp. 2 | -------------------------------------------------------------------------------- /examples/swaptions/CumNormalInv.cpp: -------------------------------------------------------------------------------- 1 | // CumNormalInv.c 2 | // Author: Mark Broadie 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "HJM_type.h" 9 | 10 | FTYPE CumNormalInv( FTYPE u ); 11 | 12 | /**********************************************************************/ 13 | static FTYPE a[4] = { 14 | 2.50662823884, 15 | -18.61500062529, 16 | 41.39119773534, 17 | -25.44106049637 18 | }; 19 | 20 | static FTYPE b[4] = { 21 | -8.47351093090, 22 | 23.08336743743, 23 | -21.06224101826, 24 | 3.13082909833 25 | }; 26 | 27 | static FTYPE c[9] = { 28 | 0.3374754822726147, 29 | 0.9761690190917186, 30 | 0.1607979714918209, 31 | 0.0276438810333863, 32 | 0.0038405729373609, 33 | 0.0003951896511919, 34 | 0.0000321767881768, 35 | 0.0000002888167364, 36 | 0.0000003960315187 37 | }; 38 | 39 | /**********************************************************************/ 40 | FTYPE CumNormalInv( FTYPE u ) 41 | { 42 | // Returns the inverse of cumulative normal distribution function. 43 | // Reference: Moro, B., 1995, "The Full Monte," RISK (February), 57-58. 44 | 45 | FTYPE x, r; 46 | 47 | x = u - 0.5; 48 | if( fabs (x) < 0.42 ) 49 | { 50 | r = x * x; 51 | r = x * ((( a[3]*r + a[2]) * r + a[1]) * r + a[0])/ 52 | ((((b[3] * r+ b[2]) * r + b[1]) * r + b[0]) * r + 1.0); 53 | return (r); 54 | } 55 | 56 | r = u; 57 | if( x > 0.0 ) r = 1.0 - u; 58 | r = log(-log(r)); 59 | r = c[0] + r * (c[1] + r * 60 | (c[2] + r * (c[3] + r * 61 | (c[4] + r * (c[5] + r * (c[6] + r * (c[7] + r*c[8]))))))); 62 | if( x < 0.0 ) r = -r; 63 | 64 | return (r); 65 | 66 | } // end of CumNormalInv 67 | 68 | /**********************************************************************/ 69 | // end of CumNormalInv.c 70 | -------------------------------------------------------------------------------- /examples/swaptions/HJM.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "HJM_type.h" 3 | 4 | #include 5 | 6 | FTYPE RanUnif( long *s ); 7 | FTYPE CumNormalInv( FTYPE u ); 8 | void icdf_SSE(const int N, FTYPE *in, FTYPE *out); 9 | void icdf_baseline(const int N, FTYPE *in, FTYPE *out); 10 | int HJM_SimPath_Forward_SSE(FTYPE **ppdHJMPath, int iN, int iFactors, FTYPE dYears, FTYPE *pdForward, FTYPE *pdTotalDrift, 11 | FTYPE **ppdFactors, long *lRndSeed); 12 | int Discount_Factors_SSE(FTYPE *pdDiscountFactors, int iN, FTYPE dYears, FTYPE *pdRatePath); 13 | int Discount_Factors_opt(FTYPE *pdDiscountFactors, int iN, FTYPE dYears, FTYPE *pdRatePath); 14 | 15 | 16 | int HJM_SimPath_Forward_Blocking_SSE(FTYPE **ppdHJMPath, int iN, int iFactors, FTYPE dYears, FTYPE *pdForward, FTYPE *pdTotalDrift, 17 | FTYPE **ppdFactors, long *lRndSeed, int BLOCKSIZE); 18 | int HJM_SimPath_Forward_Blocking(FTYPE **ppdHJMPath, int iN, int iFactors, FTYPE dYears, FTYPE *pdForward, FTYPE *pdTotalDrift, 19 | FTYPE **ppdFactors, long *lRndSeed, int BLOCKSIZE, FTYPE **pdZ, FTYPE **randZ); 20 | 21 | 22 | int Discount_Factors_Blocking(FTYPE *pdDiscountFactors, int iN, FTYPE dYears, FTYPE *pdRatePath, int BLOCKSIZE, FTYPE *pdexpRes); 23 | int Discount_Factors_Blocking_SSE(FTYPE *pdDiscountFactors, int iN, FTYPE dYears, FTYPE *pdRatePath, int BLOCKSIZE); 24 | 25 | 26 | int HJM_Swaption_Blocking_SSE(FTYPE *pdSwaptionPrice, //Output vector that will store simulation results in the form: 27 | //Swaption Price 28 | //Swaption Standard Error 29 | //Swaption Parameters 30 | FTYPE dStrike, 31 | FTYPE dCompounding, //Compounding convention used for quoting the strike (0 => continuous, 32 | //0.5 => semi-annual, 1 => annual). 33 | FTYPE dMaturity, //Maturity of the swaption (time to expiration) 34 | FTYPE dTenor, //Tenor of the swap 35 | FTYPE dPaymentInterval, //frequency of swap payments e.g. dPaymentInterval = 0.5 implies a swap payment every half 36 | //year 37 | //HJM Framework Parameters (please refer HJM.cpp for explanation of variables and functions) 38 | int iN, 39 | int iFactors, 40 | FTYPE dYears, 41 | FTYPE *pdYield, 42 | FTYPE **ppdFactors, 43 | //Simulation Parameters 44 | long iRndSeed, 45 | long lTrials, int blocksize, int tid); 46 | 47 | int HJM_Swaption_Blocking(FTYPE *pdSwaptionPrice, //Output vector that will store simulation results in the form: 48 | //Swaption Price 49 | //Swaption Standard Error 50 | //Swaption Parameters 51 | FTYPE dStrike, 52 | FTYPE dCompounding, //Compounding convention used for quoting the strike (0 => continuous, 53 | //0.5 => semi-annual, 1 => annual). 54 | FTYPE dMaturity, //Maturity of the swaption (time to expiration) 55 | FTYPE dTenor, //Tenor of the swap 56 | FTYPE dPaymentInterval, //frequency of swap payments e.g. dPaymentInterval = 0.5 implies a swap payment every half 57 | //year 58 | //HJM Framework Parameters (please refer HJM.cpp for explanation of variables and functions) 59 | int iN, 60 | int iFactors, 61 | FTYPE dYears, 62 | FTYPE *pdYield, 63 | FTYPE **ppdFactors, 64 | //Simulation Parameters 65 | long iRndSeed, 66 | long lTrials, int blocksize, int tid); 67 | /* 68 | extern "C" FTYPE *dvector( long nl, long nh ); 69 | extern "C" FTYPE **dmatrix( long nrl, long nrh, long ncl, long nch ); 70 | extern "C" void free_dvector( FTYPE *v, long nl, long nh ); 71 | extern "C" void free_dmatrix( FTYPE **m, long nrl, long nrh, long ncl, long nch ); 72 | */ 73 | -------------------------------------------------------------------------------- /examples/swaptions/HJM_Securities.h: -------------------------------------------------------------------------------- 1 | #ifndef __HJM_SECURITIES__ 2 | #define __HJM_SECURITIES__ 3 | 4 | #include "HJM_type.h" 5 | 6 | int HJM_SimPath_Yield(FTYPE **ppdHJMPath, int iN, int iFactors, FTYPE dYears, FTYPE *pdYield, FTYPE **ppdFactors); 7 | int HJM_SimPath_Forward(FTYPE **ppdHJMPath, int iN, int iFactors, FTYPE dYears, FTYPE *pdForward, FTYPE *pdTotalDrift, 8 | FTYPE **ppdFactors, long *iSeed); 9 | int HJM_Yield_to_Forward(FTYPE *pdForward, int iN, FTYPE *pdYield); 10 | int HJM_Factors(FTYPE **ppdFactors,int iN, int iFactors, FTYPE *pdVol, FTYPE **ppdFacBreak); 11 | int HJM_Drifts(FTYPE *pdTotalDrift, FTYPE **ppdDrifts, int iN, int iFactors, FTYPE dYears, FTYPE **ppdFactors); 12 | int HJM_Correlations(FTYPE **ppdHJMCorr, int iN, int iFactors, FTYPE **ppdFactors); 13 | int HJM_Forward_to_Yield(FTYPE *pdYield, int iN, FTYPE *pdForward); 14 | int Discount_Factors(FTYPE *pdDiscountFactors, int iN, FTYPE dYears, FTYPE *pdRatePath); 15 | FTYPE dMax( FTYPE dA, FTYPE dB ); 16 | 17 | #endif //__HJM_SECURITIES__ 18 | -------------------------------------------------------------------------------- /examples/swaptions/HJM_SimPath_Forward_Blocking.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "HJM_type.h" 5 | #include "HJM.h" 6 | #include "nr_routines.h" 7 | 8 | #ifdef TBB_VERSION 9 | #include 10 | #include "tbb/task_scheduler_init.h" 11 | #include "tbb/blocked_range.h" 12 | #include "tbb/parallel_for.h" 13 | #include "tbb/cache_aligned_allocator.h" 14 | 15 | 16 | #define PARALLEL_B_GRAINSIZE 8 17 | 18 | 19 | struct ParallelB { 20 | __volatile__ int l; 21 | FTYPE **pdZ; 22 | FTYPE **randZ; 23 | int BLOCKSIZE; 24 | int iN; 25 | 26 | ParallelB(FTYPE **pdZ_, FTYPE **randZ_, int BLOCKSIZE_, int iN_)//: 27 | // pdZ(pdZ_), randZ(randZ_), BLOCKSIZE(BLOCKSIZE_), iN(iN_) 28 | { 29 | pdZ = pdZ_; 30 | randZ = randZ_; 31 | BLOCKSIZE = BLOCKSIZE_; 32 | iN = iN_; 33 | /*fprintf(stderr,"(Construction object) pdZ=0x%08x, randZ=0x%08x\n", 34 | pdZ, randZ);*/ 35 | 36 | } 37 | void set_l(int l_){l = l_;} 38 | 39 | void operator()(const tbb::blocked_range &range) const { 40 | int begin = range.begin(); 41 | int end = range.end(); 42 | int b,j; 43 | /*fprintf(stderr,"B: Thread %d from %d to %d. l=%d pdZ=0x%08x, BLOCKSIZE=%d, iN=%d\n", 44 | pthread_self(), begin, end, l,(int)pdZ,BLOCKSIZE,iN); */ 45 | 46 | for(b=begin; b!=end; b++) { 47 | for (j=1;j<=iN-1;++j){ 48 | pdZ[l][BLOCKSIZE*j + b]= CumNormalInv(randZ[l][BLOCKSIZE*j + b]); /* 18% of the total executition time */ 49 | //fprintf(stderr,"%d (%d, %d): [%d][%d]=%e\n",pthread_self(), begin, end, l,BLOCKSIZE*j+b,pdZ[l][BLOCKSIZE*j + b]); 50 | } 51 | } 52 | 53 | } 54 | 55 | }; 56 | 57 | 58 | #endif // TBB_VERSION 59 | 60 | void serialB(FTYPE **pdZ, FTYPE **randZ, int BLOCKSIZE, int iN, int iFactors) 61 | { 62 | 63 | 64 | for(int l=0;l<=iFactors-1;++l){ 65 | for(int b=0; b(0, BLOCKSIZE, PARALLEL_B_GRAINSIZE),B); 137 | } 138 | 139 | #else 140 | /* 18% of the total executition time */ 141 | serialB(pdZ, randZ, BLOCKSIZE, iN, iFactors); 142 | #endif 143 | 144 | // ===================================================== 145 | // Generation of HJM Path1 146 | for(int b=0; b 5 | #include 6 | #include 7 | #include "HJM_type.h" 8 | 9 | FTYPE dMax( FTYPE dA, FTYPE dB ); 10 | 11 | FTYPE dMax( FTYPE dA, FTYPE dB ) 12 | { 13 | return (dA>dB ? dA:dB); 14 | } // end of dMax 15 | -------------------------------------------------------------------------------- /examples/swaptions/README.md: -------------------------------------------------------------------------------- 1 | Original code for modified files is in original/. 2 | 3 | To build the multi-threaded version with the "cheap" optimizations on, compile as follows: 4 | 5 | make version=pthreads cheap=1 6 | 7 | Test with the following arguments ("native.runconf" in Parsec): 8 | 9 | ./swaptions -ns 128 -sm 1000000 -nt ${NTHREADS} 10 | 11 | e.g., `-nt 1` 12 | -------------------------------------------------------------------------------- /examples/swaptions/RanUnif.cpp: -------------------------------------------------------------------------------- 1 | // RanUnif.c 2 | // Author: Mark Broadie 3 | // Collaborator: Mikhail Smelyanskiy, Intel 4 | 5 | /* See "Random Number Generators: Good Ones Are Hard To Find", */ 6 | /* Park & Miller, CACM 31#10 October 1988 pages 1192-1201. */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include "HJM_type.h" 12 | 13 | FTYPE RanUnif( long *s ); 14 | 15 | FTYPE RanUnif( long *s ) 16 | { 17 | // uniform random number generator 18 | 19 | long ix, k1; 20 | FTYPE dRes; 21 | 22 | ix = *s; 23 | k1 = ix/127773L; 24 | ix = 16807L*( ix - k1*127773L ) - k1 * 2836L; 25 | if (ix < 0) ix = ix + 2147483647L; 26 | *s = ix; 27 | dRes = (ix * 4.656612875e-10); 28 | return (dRes); 29 | 30 | } // end of RanUnif 31 | -------------------------------------------------------------------------------- /examples/swaptions/icdf.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "HJM_type.h" 5 | 6 | 7 | 8 | 9 | void icdf_baseline(const int N, FTYPE *in, FTYPE *out){ 10 | 11 | register FTYPE z, r; 12 | 13 | const FTYPE 14 | a1 = -3.969683028665376e+01, 15 | a2 = 2.209460984245205e+02, 16 | a3 = -2.759285104469687e+02, 17 | a4 = 1.383577518672690e+02, 18 | a5 = -3.066479806614716e+01, 19 | a6 = 2.506628277459239e+00; 20 | 21 | const FTYPE 22 | b1 = -5.447609879822406e+01, 23 | b2 = 1.615858368580409e+02, 24 | b3 = -1.556989798598866e+02, 25 | b4 = 6.680131188771972e+01, 26 | b5 = -1.328068155288572e+01; 27 | 28 | const FTYPE 29 | c1 = -7.784894002430293e-03, 30 | c2 = -3.223964580411365e-01, 31 | c3 = -2.400758277161838e+00, 32 | c4 = -2.549732539343734e+00, 33 | c5 = 4.374664141464968e+00, 34 | c6 = 2.938163982698783e+00; 35 | 36 | const FTYPE 37 | //d0 = 0.0, 38 | d1 = 7.784695709041462e-03, 39 | d2 = 3.224671290700398e-01, 40 | d3 = 2.445134137142996e+00, 41 | d4 = 3.754408661907416e+00; 42 | 43 | // Limits of the approximation region. 44 | #define U_LOW 0.02425 45 | 46 | const FTYPE u_low = U_LOW, u_high = 1.0 - U_LOW; 47 | 48 | for(int i=0; i 2 | #include 3 | #include 4 | 5 | #include "nr_routines.h" 6 | #include "HJM_type.h" 7 | 8 | #define SWAP(a,b) {temp=(a);(a)=(b);(b)=temp;} 9 | 10 | 11 | 12 | void nrerror(const char *error_text) 13 | { 14 | // Numerical Recipes standard error handler 15 | fprintf( stderr,"Numerical Recipes run-time error...\n" ); 16 | fprintf( stderr,"%s\n",error_text ); 17 | fprintf( stderr,"...now exiting to system...\n" ); 18 | exit(1); 19 | 20 | } // end of nrerror 21 | 22 | /**********************************************************************/ 23 | 24 | int choldc(FTYPE **a, int n) 25 | { 26 | // modifications: float -> FTYPE 27 | // nrerror removed 28 | // routine returns int instead of void, where 29 | // 1 means success, and 0 failure 30 | // p vector removed 31 | // upper triangular part of A is zeroed out 32 | 33 | int i,j,k; 34 | FTYPE sum; 35 | 36 | for (i=1;i<=n;i++) { 37 | for (j=i;j<=n;j++) { 38 | for (sum=a[i][j],k=i-1;k>=1;k--) sum -= a[i][k]*a[j][k]; 39 | if (i == j) { 40 | if (sum <= 0.0) 41 | // matrix is not positive definite 42 | return(0); 43 | a[i][i]=sqrt(sum); 44 | } else a[j][i]=sum/a[i][i]; 45 | } 46 | } 47 | 48 | for (i=1;i<=n-1;i++) 49 | for (j=i+1;j<=n;j++) 50 | a[i][j] = 0.0; 51 | 52 | return(1); 53 | } 54 | 55 | void gaussj(FTYPE **a, int n, FTYPE **b, int m) 56 | { 57 | int *indxc,*indxr,*ipiv; 58 | int i,icol,irow,j,k,l,ll; 59 | FTYPE big,dum,pivinv,temp; 60 | 61 | indxc=ivector(1,n); 62 | indxr=ivector(1,n); 63 | ipiv=ivector(1,n); 64 | icol=-1; irow=-1; 65 | for (j=1;j<=n;j++) ipiv[j]=0; 66 | for (i=1;i<=n;i++) { 67 | big=0.0; 68 | for (j=1;j<=n;j++) 69 | if (ipiv[j] != 1) 70 | for (k=1;k<=n;k++) { 71 | if (ipiv[k] == 0) { 72 | if (fabs(a[j][k]) >= big) { 73 | big=fabs(a[j][k]); 74 | irow=j; 75 | icol=k; 76 | } 77 | } else if (ipiv[k] > 1) nrerror("gaussj: Singular Matrix-1"); 78 | } 79 | ++(ipiv[icol]); 80 | if (irow != icol) { 81 | for (l=1;l<=n;l++) SWAP(a[irow][l],a[icol][l]) 82 | for (l=1;l<=m;l++) SWAP(b[irow][l],b[icol][l]) 83 | } 84 | indxr[i]=irow; 85 | indxc[i]=icol; 86 | if (a[icol][icol] == 0.0) nrerror("gaussj: Singular Matrix-2"); 87 | pivinv=1.0/a[icol][icol]; 88 | a[icol][icol]=1.0; 89 | for (l=1;l<=n;l++) a[icol][l] *= pivinv; 90 | for (l=1;l<=m;l++) b[icol][l] *= pivinv; 91 | for (ll=1;ll<=n;ll++) 92 | if (ll != icol) { 93 | dum=a[ll][icol]; 94 | a[ll][icol]=0.0; 95 | for (l=1;l<=n;l++) a[ll][l] -= a[icol][l]*dum; 96 | for (l=1;l<=m;l++) b[ll][l] -= b[icol][l]*dum; 97 | } 98 | } 99 | for (l=n;l>=1;l--) { 100 | if (indxr[l] != indxc[l]) 101 | for (k=1;k<=n;k++) 102 | SWAP(a[k][indxr[l]],a[k][indxc[l]]); 103 | } 104 | free_ivector(ipiv,1,n); 105 | free_ivector(indxr,1,n); 106 | free_ivector(indxc,1,n); 107 | } 108 | #undef SWAP 109 | #undef NRANSI 110 | 111 | 112 | 113 | /**********************************************************************/ 114 | int *ivector(long nl, long nh) 115 | /* allocate an int vector with subscript range v[nl..nh] */ 116 | { 117 | int *v; 118 | 119 | v=(int *)malloc((size_t) ((nh-nl+2)*sizeof(int))); 120 | if (!v) nrerror("allocation failure in ivector()"); 121 | return v-nl+1; 122 | } 123 | 124 | /**********************************************************************/ 125 | void free_ivector(int *v, long nl, long nh) 126 | /* free an int vector allocated with ivector() */ 127 | { 128 | free((char *) (v+nl-1)); 129 | } 130 | 131 | /**********************************************************************/ 132 | FTYPE *dvector( long nl, long nh ) 133 | { 134 | // allocate a FTYPE vector with subscript range v[nl..nh] 135 | 136 | FTYPE *v; 137 | 138 | v=(FTYPE *)malloc((size_t) ((nh-nl+2)*sizeof(FTYPE))); 139 | if (!v) nrerror("allocation failure in dvector()"); 140 | return v-nl+1; 141 | 142 | } // end of dvector 143 | 144 | /**********************************************************************/ 145 | void free_dvector( FTYPE *v, long nl, long nh ) 146 | { 147 | // free a FTYPE vector allocated with dvector() 148 | 149 | free((char*) (v+nl-1)); 150 | 151 | } // end of free_dvector 152 | 153 | /**********************************************************************/ 154 | FTYPE **dmatrix( long nrl, long nrh, long ncl, long nch ) 155 | { 156 | // allocate a FTYPE matrix with subscript range m[nrl..nrh][ncl..nch] 157 | 158 | long i, nrow=nrh-nrl+1,ncol=nch-ncl+1; 159 | FTYPE **m; 160 | 161 | // allocate pointers to rows 162 | m=(FTYPE **) malloc((size_t)((nrow+1)*sizeof(FTYPE*))); 163 | if (!m) nrerror("allocation failure 1 in dmatrix()"); 164 | m += 1; 165 | m -= nrl; 166 | 167 | // allocate rows and set pointers to them 168 | m[nrl]=(FTYPE *) malloc((size_t)((nrow*ncol+1)*sizeof(FTYPE))); 169 | if (!m[nrl]) nrerror("allocation failure 2 in dmatrix()"); 170 | m[nrl] += 1; 171 | m[nrl] -= ncl; 172 | 173 | for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol; 174 | 175 | // return pointer to array of pointers to rows 176 | return m; 177 | 178 | } // end of dmatrix 179 | 180 | /**********************************************************************/ 181 | void free_dmatrix( FTYPE **m, long nrl, long nrh, long ncl, long nch ) 182 | { 183 | // free a FTYPE matrix allocated by dmatrix() 184 | 185 | free((char*) (m[nrl]+ncl-1)); 186 | free((char*) (m+nrl-1)); 187 | 188 | } // end of free_dmatrix 189 | 190 | // end of nr_routines.c 191 | 192 | -------------------------------------------------------------------------------- /examples/swaptions/nr_routines.h: -------------------------------------------------------------------------------- 1 | #include "HJM_type.h" 2 | 3 | void nrerror(const char *error_text); 4 | int choldc(FTYPE **a, int n); 5 | void gaussj(FTYPE **a, int n, FTYPE **b, int m); 6 | int *ivector(long nl, long nh); 7 | void free_ivector(int *v, long nl, long nh); 8 | FTYPE *dvector( long nl, long nh ); 9 | void free_dvector( FTYPE *v, long nl, long nh ); 10 | FTYPE **dmatrix( long nrl, long nrh, long ncl, long nch ); 11 | void free_dmatrix( FTYPE **m, long nrl, long nrh, long ncl, long nch ); 12 | -------------------------------------------------------------------------------- /examples/swaptions/original/HJM.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "HJM_type.h" 3 | 4 | #include 5 | 6 | FTYPE RanUnif( long *s ); 7 | FTYPE CumNormalInv( FTYPE u ); 8 | void icdf_SSE(const int N, FTYPE *in, FTYPE *out); 9 | void icdf_baseline(const int N, FTYPE *in, FTYPE *out); 10 | int HJM_SimPath_Forward_SSE(FTYPE **ppdHJMPath, int iN, int iFactors, FTYPE dYears, FTYPE *pdForward, FTYPE *pdTotalDrift, 11 | FTYPE **ppdFactors, long *lRndSeed); 12 | int Discount_Factors_SSE(FTYPE *pdDiscountFactors, int iN, FTYPE dYears, FTYPE *pdRatePath); 13 | int Discount_Factors_opt(FTYPE *pdDiscountFactors, int iN, FTYPE dYears, FTYPE *pdRatePath); 14 | 15 | 16 | int HJM_SimPath_Forward_Blocking_SSE(FTYPE **ppdHJMPath, int iN, int iFactors, FTYPE dYears, FTYPE *pdForward, FTYPE *pdTotalDrift, 17 | FTYPE **ppdFactors, long *lRndSeed, int BLOCKSIZE); 18 | int HJM_SimPath_Forward_Blocking(FTYPE **ppdHJMPath, int iN, int iFactors, FTYPE dYears, FTYPE *pdForward, FTYPE *pdTotalDrift, 19 | FTYPE **ppdFactors, long *lRndSeed, int BLOCKSIZE); 20 | 21 | 22 | int Discount_Factors_Blocking(FTYPE *pdDiscountFactors, int iN, FTYPE dYears, FTYPE *pdRatePath, int BLOCKSIZE); 23 | int Discount_Factors_Blocking_SSE(FTYPE *pdDiscountFactors, int iN, FTYPE dYears, FTYPE *pdRatePath, int BLOCKSIZE); 24 | 25 | 26 | int HJM_Swaption_Blocking_SSE(FTYPE *pdSwaptionPrice, //Output vector that will store simulation results in the form: 27 | //Swaption Price 28 | //Swaption Standard Error 29 | //Swaption Parameters 30 | FTYPE dStrike, 31 | FTYPE dCompounding, //Compounding convention used for quoting the strike (0 => continuous, 32 | //0.5 => semi-annual, 1 => annual). 33 | FTYPE dMaturity, //Maturity of the swaption (time to expiration) 34 | FTYPE dTenor, //Tenor of the swap 35 | FTYPE dPaymentInterval, //frequency of swap payments e.g. dPaymentInterval = 0.5 implies a swap payment every half 36 | //year 37 | //HJM Framework Parameters (please refer HJM.cpp for explanation of variables and functions) 38 | int iN, 39 | int iFactors, 40 | FTYPE dYears, 41 | FTYPE *pdYield, 42 | FTYPE **ppdFactors, 43 | //Simulation Parameters 44 | long iRndSeed, 45 | long lTrials, int blocksize, int tid); 46 | 47 | int HJM_Swaption_Blocking(FTYPE *pdSwaptionPrice, //Output vector that will store simulation results in the form: 48 | //Swaption Price 49 | //Swaption Standard Error 50 | //Swaption Parameters 51 | FTYPE dStrike, 52 | FTYPE dCompounding, //Compounding convention used for quoting the strike (0 => continuous, 53 | //0.5 => semi-annual, 1 => annual). 54 | FTYPE dMaturity, //Maturity of the swaption (time to expiration) 55 | FTYPE dTenor, //Tenor of the swap 56 | FTYPE dPaymentInterval, //frequency of swap payments e.g. dPaymentInterval = 0.5 implies a swap payment every half 57 | //year 58 | //HJM Framework Parameters (please refer HJM.cpp for explanation of variables and functions) 59 | int iN, 60 | int iFactors, 61 | FTYPE dYears, 62 | FTYPE *pdYield, 63 | FTYPE **ppdFactors, 64 | //Simulation Parameters 65 | long iRndSeed, 66 | long lTrials, int blocksize, int tid); 67 | /* 68 | extern "C" FTYPE *dvector( long nl, long nh ); 69 | extern "C" FTYPE **dmatrix( long nrl, long nrh, long ncl, long nch ); 70 | extern "C" void free_dvector( FTYPE *v, long nl, long nh ); 71 | extern "C" void free_dmatrix( FTYPE **m, long nrl, long nrh, long ncl, long nch ); 72 | */ 73 | -------------------------------------------------------------------------------- /examples/swaptions/original/HJM_SimPath_Forward_Blocking.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "HJM_type.h" 5 | #include "HJM.h" 6 | #include "nr_routines.h" 7 | 8 | #ifdef TBB_VERSION 9 | #include 10 | #include "tbb/task_scheduler_init.h" 11 | #include "tbb/blocked_range.h" 12 | #include "tbb/parallel_for.h" 13 | #include "tbb/cache_aligned_allocator.h" 14 | 15 | 16 | #define PARALLEL_B_GRAINSIZE 8 17 | 18 | 19 | struct ParallelB { 20 | __volatile__ int l; 21 | FTYPE **pdZ; 22 | FTYPE **randZ; 23 | int BLOCKSIZE; 24 | int iN; 25 | 26 | ParallelB(FTYPE **pdZ_, FTYPE **randZ_, int BLOCKSIZE_, int iN_)//: 27 | // pdZ(pdZ_), randZ(randZ_), BLOCKSIZE(BLOCKSIZE_), iN(iN_) 28 | { 29 | pdZ = pdZ_; 30 | randZ = randZ_; 31 | BLOCKSIZE = BLOCKSIZE_; 32 | iN = iN_; 33 | /*fprintf(stderr,"(Construction object) pdZ=0x%08x, randZ=0x%08x\n", 34 | pdZ, randZ);*/ 35 | 36 | } 37 | void set_l(int l_){l = l_;} 38 | 39 | void operator()(const tbb::blocked_range &range) const { 40 | int begin = range.begin(); 41 | int end = range.end(); 42 | int b,j; 43 | /*fprintf(stderr,"B: Thread %d from %d to %d. l=%d pdZ=0x%08x, BLOCKSIZE=%d, iN=%d\n", 44 | pthread_self(), begin, end, l,(int)pdZ,BLOCKSIZE,iN); */ 45 | 46 | for(b=begin; b!=end; b++) { 47 | for (j=1;j<=iN-1;++j){ 48 | pdZ[l][BLOCKSIZE*j + b]= CumNormalInv(randZ[l][BLOCKSIZE*j + b]); /* 18% of the total executition time */ 49 | //fprintf(stderr,"%d (%d, %d): [%d][%d]=%e\n",pthread_self(), begin, end, l,BLOCKSIZE*j+b,pdZ[l][BLOCKSIZE*j + b]); 50 | } 51 | } 52 | 53 | } 54 | 55 | }; 56 | 57 | 58 | #endif // TBB_VERSION 59 | 60 | void serialB(FTYPE **pdZ, FTYPE **randZ, int BLOCKSIZE, int iN, int iFactors) 61 | { 62 | 63 | 64 | for(int l=0;l<=iFactors-1;++l){ 65 | for(int b=0; b(0, BLOCKSIZE, PARALLEL_B_GRAINSIZE),B); 135 | } 136 | 137 | #else 138 | /* 18% of the total executition time */ 139 | serialB(pdZ, randZ, BLOCKSIZE, iN, iFactors); 140 | #endif 141 | 142 | // ===================================================== 143 | // Generation of HJM Path1 144 | for(int b=0; b 22 | 23 | /** 24 | * 25 | * @class DLList 26 | * @brief A "memory neutral" (intrusive) doubly-linked list. 27 | * @author Emery Berger 28 | */ 29 | 30 | class DLList { 31 | public: 32 | 33 | inline DLList() { 34 | clear(); 35 | } 36 | 37 | class Entry; 38 | 39 | /// Clear the list. 40 | inline void clear() { 41 | head.setPrev (&head); 42 | head.setNext (&head); 43 | } 44 | 45 | /// Is the list empty? 46 | inline bool isEmpty() const { 47 | return (head.getNext() == &head); 48 | } 49 | 50 | /// Get the head of the list. 51 | #pragma GCC diagnostic push 52 | #pragma GCC diagnostic ignored "-Wcast-qual" 53 | inline Entry * get() { 54 | const Entry * e = head.next; 55 | if (e == &head) { 56 | return nullptr; 57 | } 58 | head.next = e->next; 59 | head.next->prev = &head; 60 | return (Entry *) e; 61 | } 62 | 63 | /// Remove one item from the list. 64 | inline void remove (Entry * e) { 65 | e->remove(); 66 | } 67 | 68 | /// Insert an entry into the head of the list. 69 | inline void insert (Entry * e) { 70 | e->insert (&head, head.next); 71 | } 72 | 73 | /// An entry in the list. 74 | class Entry { 75 | public: 76 | // private: 77 | inline void setPrev (Entry * p) { assert (p != nullptr); prev = p; } 78 | inline void setNext (Entry * p) { assert (p != nullptr); next = p; } 79 | inline Entry * getPrev() const { return prev; } 80 | inline Entry * getNext() const { return next; } 81 | inline void remove() const { 82 | prev->setNext(next); 83 | next->setPrev(prev); 84 | } 85 | inline void insert (Entry * p, Entry * n) { 86 | prev = p; 87 | next = n; 88 | p->setNext (this); 89 | n->setPrev (this); 90 | } 91 | Entry * prev; 92 | Entry * next; 93 | }; 94 | 95 | 96 | private: 97 | 98 | /// The head of the list. 99 | Entry head; 100 | 101 | }; 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /experimental/bde-replacements/bdlma_multipool.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emeryberger/cheap/53dd89acdb92f9f1c84ce0993b3491aeef7d7541/experimental/bde-replacements/bdlma_multipool.cpp -------------------------------------------------------------------------------- /experimental/bde-replacements/bdlma_pool.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emeryberger/cheap/53dd89acdb92f9f1c84ce0993b3491aeef7d7541/experimental/bde-replacements/bdlma_pool.cpp -------------------------------------------------------------------------------- /experimental/bde-replacements/bdlma_simpool.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emeryberger/cheap/53dd89acdb92f9f1c84ce0993b3491aeef7d7541/experimental/bde-replacements/bdlma_simpool.cpp -------------------------------------------------------------------------------- /experimental/bde-replacements/bdlma_simpool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef SIMPOOL_HPP 4 | #define SIMPOOL_HPP 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | #if defined(__APPLE__) 14 | #include 15 | #else 16 | #include 17 | #endif 18 | 19 | class SimPool { 20 | public: 21 | 22 | static inline constexpr size_t align(size_t sz) { 23 | return (sz + alignof(std::max_align_t) - 1) & ~(alignof(std::max_align_t) - 1); 24 | } 25 | 26 | SimPool(uint64_t maxSize = 0) 27 | : _maxSize (maxSize), 28 | _size (0) 29 | { 30 | // static bool v = printInfo(); 31 | } 32 | 33 | void resetSize(uint64_t maxSize) { 34 | _maxSize = maxSize; 35 | _size = 0; 36 | } 37 | 38 | bool printInfo() { 39 | std::cout << "SimPool initialized." << std::endl; 40 | return true; 41 | } 42 | 43 | ~SimPool() 44 | { 45 | release(); 46 | } 47 | 48 | inline void * malloc(size_t sz) { 49 | if ((_maxSize) && (sz + _size > _maxSize)) { 50 | return nullptr; 51 | } 52 | // sz = align(sz); 53 | // Get an object of the requested size plus the header. 54 | auto * b = reinterpret_cast(::malloc(sz + sizeof(DLList::Entry))); 55 | if (b) { 56 | // Update current size of the pool. 57 | if (_maxSize) { 58 | _size += getSize(b); 59 | } 60 | // Add to the front of the linked list. 61 | _list.insert(b); 62 | // Return just past the header. 63 | return reinterpret_cast(b + 1); 64 | } else { 65 | return nullptr; 66 | } 67 | } 68 | 69 | inline void * allocate(size_t sz) { 70 | return malloc(sz); 71 | } 72 | 73 | inline void free(void * ptr) { 74 | // Find the actual block header. 75 | auto * b = reinterpret_cast(ptr) - 1; 76 | // Remove from the linked list. 77 | _list.remove(b); 78 | if (_maxSize) { 79 | _size -= getSize(b); 80 | } 81 | // Free the object. 82 | ::free(b); 83 | } 84 | 85 | inline void deallocate(void * ptr) { 86 | free(ptr); 87 | } 88 | 89 | bool isEmpty() { 90 | return _list.isEmpty(); 91 | } 92 | 93 | void release() { 94 | // Iterate through the list, freeing each item. 95 | auto * e = _list.get(); 96 | while (e) { 97 | ::free(e); 98 | e = _list.get(); 99 | } 100 | _size = 0; 101 | } 102 | 103 | void rewind() { 104 | release(); 105 | } 106 | 107 | private: 108 | 109 | uint64_t getSize(void * ptr) { 110 | #if defined(__APPLE__) 111 | auto sz = malloc_size(ptr); 112 | #else 113 | auto sz = malloc_usable_size(ptr); 114 | #endif 115 | return sz; 116 | } 117 | 118 | uint64_t _maxSize; 119 | uint64_t _size; 120 | DLList _list; 121 | 122 | }; 123 | 124 | 125 | #endif 126 | -------------------------------------------------------------------------------- /experimental/bde-replacements/simregion.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emeryberger/cheap/53dd89acdb92f9f1c84ce0993b3491aeef7d7541/experimental/bde-replacements/simregion.cpp -------------------------------------------------------------------------------- /experimental/bde-replacements/simregion.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef SIMREGION_HPP 4 | #define SIMREGION_HPP 5 | 6 | #include 7 | #include 8 | #ifndef __APPLE__ 9 | #include 10 | #else 11 | #include 12 | #endif 13 | 14 | #include 15 | #include 16 | 17 | class SimRegion { 18 | public: 19 | 20 | static constexpr int VECTOR_INITIAL_SIZE = 0; 21 | 22 | enum { Alignment = alignof(std::max_align_t) }; // guaranteed by malloc 23 | 24 | static inline constexpr size_t align(size_t sz) { 25 | return (sz + alignof(std::max_align_t) - 1) & ~(alignof(std::max_align_t) - 1); 26 | } 27 | 28 | SimRegion(unsigned int = 0) // ignore argument - just here for compatibility now 29 | { 30 | // static bool v = printInfo(); 31 | } 32 | 33 | bool printInfo() { 34 | std::cout << "SimRegion initialized." << std::endl; 35 | return true; 36 | } 37 | 38 | 39 | ~SimRegion() { 40 | release(); 41 | } 42 | 43 | static inline size_t getSize(void * ptr) { 44 | #ifndef __APPLE__ 45 | return ::malloc_usable_size(ptr); 46 | #else 47 | return ::malloc_size(ptr); 48 | #endif 49 | } 50 | 51 | inline void * malloc(size_t sz) { 52 | if (sz == 0) { 53 | return nullptr; 54 | } 55 | // sz = align(sz); 56 | auto ptr = ::malloc(sz); 57 | _allocated.push_back(ptr); 58 | return ptr; 59 | } 60 | 61 | inline void * memalign(size_t alignment, size_t size) { 62 | // Check for non power-of-two alignment. 63 | if ((alignment == 0) || (alignment & (alignment - 1))) 64 | { 65 | return nullptr; 66 | } 67 | 68 | if (alignment <= Alignment) { 69 | // Already aligned by default. 70 | return malloc(size); 71 | } else { 72 | // Try to just allocate an object of the requested size. 73 | // If it happens to be aligned properly, just return it. 74 | void * ptr = malloc(size); 75 | if (((size_t) ptr & ~(alignment - 1)) == (size_t) ptr) { 76 | // It is already aligned just fine; return it. 77 | return ptr; 78 | } 79 | // It was not aligned as requested: free the object and allocate a big one, 80 | // and align within. 81 | free(ptr); 82 | ptr = malloc (size + 2 * alignment); 83 | void * alignedPtr = (void *) (((size_t) ptr + alignment - 1) & ~(alignment - 1)); 84 | return alignedPtr; 85 | } 86 | } 87 | 88 | inline void * allocate(size_t sz) { 89 | return malloc(sz); 90 | } 91 | 92 | inline void deallocate(void *) 93 | { 94 | } 95 | 96 | private: 97 | 98 | inline void free(void *) { 99 | } 100 | 101 | public: 102 | 103 | inline size_t size() { 104 | return _allocated.size(); 105 | } 106 | 107 | void rewind() 108 | { 109 | std::for_each(_allocated.begin(), _allocated.end(), std::free); 110 | _allocated.clear(); 111 | } 112 | 113 | void release() 114 | { 115 | rewind(); 116 | } 117 | 118 | private: 119 | 120 | std::vector _allocated; 121 | }; 122 | 123 | #endif // SIMREGION_HPP 124 | -------------------------------------------------------------------------------- /experimental/bdlma/bdlma_bufferedsequentialallocator.cpp: -------------------------------------------------------------------------------- 1 | // bdlma_bufferedsequentialallocator.cpp -*-C++-*- 2 | #include 3 | 4 | #include 5 | BSLS_IDENT_RCSID(bdlma_bufferedsequentialallocator_cpp,"$Id$ $CSID$") 6 | 7 | namespace BloombergLP { 8 | namespace bdlma { 9 | 10 | // --------------------------------- 11 | // class BufferedSequentialAllocator 12 | // --------------------------------- 13 | 14 | // CREATORS 15 | BufferedSequentialAllocator_REAL::~BufferedSequentialAllocator_REAL() 16 | { 17 | d_pool.release(); 18 | } 19 | 20 | } // close package namespace 21 | } // close enterprise namespace 22 | 23 | // ---------------------------------------------------------------------------- 24 | // Copyright 2015 Bloomberg Finance L.P. 25 | // 26 | // Licensed under the Apache License, Version 2.0 (the "License"); 27 | // you may not use this file except in compliance with the License. 28 | // You may obtain a copy of the License at 29 | // 30 | // http://www.apache.org/licenses/LICENSE-2.0 31 | // 32 | // Unless required by applicable law or agreed to in writing, software 33 | // distributed under the License is distributed on an "AS IS" BASIS, 34 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 35 | // See the License for the specific language governing permissions and 36 | // limitations under the License. 37 | // ----------------------------- END-OF-FILE ---------------------------------- 38 | -------------------------------------------------------------------------------- /experimental/bdlma/bdlma_buffermanager.cpp: -------------------------------------------------------------------------------- 1 | // bdlma_buffermanager.cpp -*-C++-*- 2 | 3 | // ---------------------------------------------------------------------------- 4 | // NOTICE 5 | // 6 | // This component is not up to date with current BDE coding standards, and 7 | // should not be used as an example for new development. 8 | // ---------------------------------------------------------------------------- 9 | 10 | #include 11 | 12 | #include 13 | BSLS_IDENT_RCSID(bdlma_buffermanager_cpp,"$Id$ $CSID$") 14 | 15 | #include 16 | 17 | namespace BloombergLP { 18 | namespace bdlma { 19 | 20 | // ------------------- 21 | // class BufferManager_REAL 22 | // ------------------- 23 | 24 | // MANIPULATORS 25 | bsls::Types::size_type BufferManager_REAL::expand(void *address, 26 | bsls::Types::size_type size) 27 | { 28 | BSLS_ASSERT(address); 29 | BSLS_ASSERT(0 < size); 30 | BSLS_ASSERT(d_buffer_p); 31 | BSLS_ASSERT(0 <= d_cursor); 32 | BSLS_ASSERT(static_cast(d_cursor) <= d_bufferSize); 33 | 34 | if (static_cast(address) + size == d_buffer_p + d_cursor) { 35 | const bsls::Types::size_type newSize = size + d_bufferSize - d_cursor; 36 | d_cursor = d_bufferSize; 37 | 38 | return newSize; // RETURN 39 | } 40 | 41 | return size; 42 | } 43 | 44 | bsls::Types::size_type BufferManager_REAL::truncate( 45 | void *address, 46 | bsls::Types::size_type originalSize, 47 | bsls::Types::size_type newSize) 48 | { 49 | BSLS_ASSERT(address); 50 | BSLS_ASSERT(newSize <= originalSize); 51 | BSLS_ASSERT(d_buffer_p); 52 | BSLS_ASSERT(originalSize <= d_bufferSize); 53 | BSLS_ASSERT(static_cast(d_cursor) <= d_bufferSize); 54 | 55 | if (static_cast(address) + originalSize == d_buffer_p + d_cursor) { 56 | d_cursor -= originalSize - newSize; 57 | return newSize; // RETURN 58 | } 59 | 60 | return originalSize; 61 | } 62 | 63 | } // close package namespace 64 | } // close enterprise namespace 65 | 66 | // ---------------------------------------------------------------------------- 67 | // Copyright 2016 Bloomberg Finance L.P. 68 | // 69 | // Licensed under the Apache License, Version 2.0 (the "License"); 70 | // you may not use this file except in compliance with the License. 71 | // You may obtain a copy of the License at 72 | // 73 | // http://www.apache.org/licenses/LICENSE-2.0 74 | // 75 | // Unless required by applicable law or agreed to in writing, software 76 | // distributed under the License is distributed on an "AS IS" BASIS, 77 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 78 | // See the License for the specific language governing permissions and 79 | // limitations under the License. 80 | // ----------------------------- END-OF-FILE ---------------------------------- 81 | -------------------------------------------------------------------------------- /experimental/bdlma/bdlma_pool.cpp: -------------------------------------------------------------------------------- 1 | // bdlma_pool.cpp -*-C++-*- 2 | #include 3 | 4 | #include 5 | BSLS_IDENT_RCSID(bdlma_pool_cpp,"$Id$ $CSID$") 6 | 7 | #include 8 | 9 | #include 10 | 11 | namespace BloombergLP { 12 | namespace bdlma { 13 | namespace { 14 | 15 | // TYPES 16 | struct Link { 17 | // This 'struct' implements a link data structure that stores the address 18 | // of the next link, used to implement the internal linked list of free 19 | // memory blocks. Note that this type was copied from 'bdlma_pool.h' to 20 | // provide access to this type from static methods. 21 | 22 | Link *d_next_p; 23 | }; 24 | 25 | // CONSTANTS 26 | enum { 27 | k_INITIAL_CHUNK_SIZE = 1, // default number of blocks per chunk 28 | 29 | k_GROWTH_FACTOR = 2, // multiplicative factor by which to grow pool 30 | // capacity 31 | 32 | k_MAX_CHUNK_SIZE = 32 // maximum number of blocks per chunk 33 | }; 34 | 35 | // LOCAL FUNCTIONS 36 | static inline 37 | bsls::Types::size_type roundUp(bsls::Types::size_type x, 38 | bsls::Types::size_type y) 39 | // Round up the specified 'x' to the nearest whole integer multiple of the 40 | // specified 'y'. The behavior is undefined unless '1 <= y'. 41 | { 42 | BSLS_ASSERT(1 <= y); 43 | 44 | return (x + y - 1) / y * y; 45 | } 46 | 47 | } // close unnamed namespace 48 | 49 | // ---------- 50 | // class Pool_REAL 51 | // ---------- 52 | 53 | // PRIVATE MANIPULATORS 54 | void Pool_REAL::replenish() 55 | { 56 | d_begin_p = static_cast(d_blockList.allocate(d_chunkSize 57 | * d_internalBlockSize)); 58 | d_end_p = d_begin_p + d_chunkSize * d_internalBlockSize; 59 | 60 | if ( bsls::BlockGrowth::BSLS_GEOMETRIC == d_growthStrategy 61 | && d_chunkSize < d_maxBlocksPerChunk) { 62 | 63 | if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY( 64 | d_chunkSize * k_GROWTH_FACTOR <= d_maxBlocksPerChunk)) { 65 | d_chunkSize = d_chunkSize * k_GROWTH_FACTOR; 66 | } 67 | else { 68 | BSLS_PERFORMANCEHINT_UNLIKELY_HINT; 69 | d_chunkSize = d_maxBlocksPerChunk; 70 | } 71 | } 72 | } 73 | 74 | // CREATORS 75 | Pool_REAL::Pool_REAL(bsls::Types::size_type blockSize, bslma::Allocator *basicAllocator) 76 | : d_blockSize(blockSize) 77 | , d_chunkSize(k_INITIAL_CHUNK_SIZE) 78 | , d_maxBlocksPerChunk(k_MAX_CHUNK_SIZE) 79 | , d_growthStrategy(bsls::BlockGrowth::BSLS_GEOMETRIC) 80 | , d_freeList_p(0) 81 | , d_blockList(basicAllocator) 82 | , d_begin_p(0) 83 | , d_end_p(0) 84 | { 85 | BSLS_ASSERT(1 <= blockSize); 86 | 87 | d_internalBlockSize = roundUp(blockSize, 88 | bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT); 89 | } 90 | 91 | Pool_REAL::Pool_REAL(bsls::Types::size_type blockSize, 92 | bsls::BlockGrowth::Strategy growthStrategy, 93 | bslma::Allocator *basicAllocator) 94 | : d_blockSize(blockSize) 95 | , d_chunkSize(bsls::BlockGrowth::BSLS_CONSTANT == growthStrategy 96 | ? k_MAX_CHUNK_SIZE 97 | : k_INITIAL_CHUNK_SIZE) 98 | , d_maxBlocksPerChunk(k_MAX_CHUNK_SIZE) 99 | , d_growthStrategy(growthStrategy) 100 | , d_freeList_p(0) 101 | , d_blockList(basicAllocator) 102 | , d_begin_p(0) 103 | , d_end_p(0) 104 | { 105 | BSLS_ASSERT(1 <= blockSize); 106 | 107 | d_internalBlockSize = roundUp(blockSize, 108 | bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT); 109 | } 110 | 111 | Pool_REAL::Pool_REAL(bsls::Types::size_type blockSize, 112 | bsls::BlockGrowth::Strategy growthStrategy, 113 | int maxBlocksPerChunk, 114 | bslma::Allocator *basicAllocator) 115 | : d_blockSize(blockSize) 116 | , d_chunkSize(bsls::BlockGrowth::BSLS_CONSTANT == growthStrategy 117 | ? maxBlocksPerChunk 118 | : k_INITIAL_CHUNK_SIZE) 119 | , d_maxBlocksPerChunk(maxBlocksPerChunk) 120 | , d_growthStrategy(growthStrategy) 121 | , d_freeList_p(0) 122 | , d_blockList(basicAllocator) 123 | , d_begin_p(0) 124 | , d_end_p(0) 125 | { 126 | BSLS_ASSERT(1 <= blockSize); 127 | BSLS_ASSERT(1 <= maxBlocksPerChunk); 128 | 129 | d_internalBlockSize = roundUp(blockSize, 130 | bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT); 131 | } 132 | 133 | Pool_REAL::~Pool_REAL() 134 | { 135 | BSLS_ASSERT(sizeof(Link) <= d_internalBlockSize); 136 | BSLS_ASSERT(0 < d_chunkSize); 137 | } 138 | 139 | // MANIPULATORS 140 | void Pool_REAL::reserveCapacity(int numBlocks) 141 | { 142 | BSLS_ASSERT(0 <= numBlocks); 143 | 144 | Link *p = d_freeList_p; 145 | while (p && numBlocks > 0) { 146 | p = p->d_next_p; 147 | --numBlocks; 148 | } 149 | 150 | if (numBlocks > 0 && d_end_p == d_begin_p) { 151 | d_begin_p = static_cast(d_blockList.allocate(numBlocks 152 | * d_internalBlockSize)); 153 | d_end_p = d_begin_p + numBlocks * d_internalBlockSize; 154 | return; // RETURN 155 | } 156 | 157 | numBlocks -= static_cast((d_end_p - d_begin_p) / d_internalBlockSize); 158 | 159 | if (numBlocks > 0) { 160 | 161 | // Allocate memory and add its blocks to the free list. 162 | 163 | void *blocks = d_blockList.allocate(numBlocks * d_internalBlockSize); 164 | char *p = static_cast(blocks); 165 | for (int i = 1; i < numBlocks; ++i) { 166 | Link *plink = static_cast(static_cast(p)); 167 | p += d_internalBlockSize; 168 | Link *pnext = static_cast(static_cast(p)); 169 | plink->d_next_p = pnext; 170 | } 171 | 172 | Link *pend = static_cast(static_cast(p)); 173 | pend->d_next_p = d_freeList_p; 174 | d_freeList_p = static_cast(blocks); 175 | } 176 | } 177 | 178 | } // close package namespace 179 | } // close enterprise namespace 180 | 181 | // ---------------------------------------------------------------------------- 182 | // Copyright 2016 Bloomberg Finance L.P. 183 | // 184 | // Licensed under the Apache License, Version 2.0 (the "License"); 185 | // you may not use this file except in compliance with the License. 186 | // You may obtain a copy of the License at 187 | // 188 | // http://www.apache.org/licenses/LICENSE-2.0 189 | // 190 | // Unless required by applicable law or agreed to in writing, software 191 | // distributed under the License is distributed on an "AS IS" BASIS, 192 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 193 | // See the License for the specific language governing permissions and 194 | // limitations under the License. 195 | // ----------------------------- END-OF-FILE ---------------------------------- 196 | -------------------------------------------------------------------------------- /experimental/dllist.h: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | 3 | /* 4 | 5 | Heap Layers: An Extensible Memory Allocation Infrastructure 6 | 7 | Copyright (C) 2000-2020 by Emery Berger 8 | http://www.emeryberger.com 9 | emery@cs.umass.edu 10 | 11 | Heap Layers is distributed under the terms of the Apache 2.0 license. 12 | 13 | You may obtain a copy of the License at 14 | http://www.apache.org/licenses/LICENSE-2.0 15 | 16 | */ 17 | 18 | #ifndef HL_DLLIST_H 19 | #define HL_DLLIST_H 20 | 21 | #include 22 | 23 | /** 24 | * 25 | * @class DLList 26 | * @brief A "memory neutral" (intrusive) doubly-linked list. 27 | * @author Emery Berger 28 | */ 29 | 30 | namespace HL { 31 | 32 | class DLList { 33 | public: 34 | 35 | inline DLList() { 36 | clear(); 37 | } 38 | 39 | class Entry; 40 | 41 | /// Clear the list. 42 | inline void clear() { 43 | head.setPrev (&head); 44 | head.setNext (&head); 45 | } 46 | 47 | /// Is the list empty? 48 | inline bool isEmpty() const { 49 | return (head.getNext() == &head); 50 | } 51 | 52 | /// Get the head of the list. 53 | #pragma GCC diagnostic push 54 | #pragma GCC diagnostic ignored "-Wcast-qual" 55 | inline Entry * get() { 56 | const Entry * e = head.next; 57 | if (e == &head) { 58 | return nullptr; 59 | } 60 | head.next = e->next; 61 | head.next->prev = &head; 62 | return (Entry *) e; 63 | } 64 | 65 | /// Remove one item from the list. 66 | inline void remove (Entry * e) { 67 | e->remove(); 68 | } 69 | 70 | /// Insert an entry into the head of the list. 71 | inline void insert (Entry * e) { 72 | e->insert (&head, head.next); 73 | } 74 | 75 | /// An entry in the list. 76 | class Entry { 77 | public: 78 | // private: 79 | inline void setPrev (Entry * p) { assert (p != nullptr); prev = p; } 80 | inline void setNext (Entry * p) { assert (p != nullptr); next = p; } 81 | inline Entry * getPrev() const { return prev; } 82 | inline Entry * getNext() const { return next; } 83 | inline void remove() const { 84 | prev->setNext(next); 85 | next->setPrev(prev); 86 | } 87 | inline void insert (Entry * p, Entry * n) { 88 | prev = p; 89 | next = n; 90 | p->setNext (this); 91 | n->setPrev (this); 92 | } 93 | Entry * prev; 94 | Entry * next; 95 | }; 96 | 97 | 98 | private: 99 | 100 | /// The head of the list. 101 | Entry head; 102 | 103 | }; 104 | 105 | } 106 | 107 | #endif 108 | -------------------------------------------------------------------------------- /experimental/fragmenter.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef FRAGMENTER_HPP 4 | #define FRAGMENTER_HPP 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | /*** 14 | * Fragmenter 15 | * 16 | * Fragments memory by allocating memory, freeing it randomly, 17 | * and leaving some fraction allocated. 18 | * 19 | * @author Emery Berger 20 | * 21 | ***/ 22 | 23 | template 30 | class Fragmenter { 31 | private: 32 | std::mt19937 * gen { nullptr }; 33 | public: 34 | Fragmenter() 35 | { 36 | std::random_device rd; 37 | // If there is a non-zero seed set, use it; otherwise, use the 38 | // random device. 39 | size_t seed; 40 | if (Seed) { 41 | seed = Seed; 42 | } else { 43 | seed = rd(); 44 | } 45 | gen = new std::mt19937(seed); 46 | std::vector allocated (NObjects); 47 | std::uniform_int_distribution<> dist(MinSize, MaxSize); 48 | 49 | // Allocate a bunch of objects from a range of sizes. 50 | for (auto i = 0UL; i < NObjects; i++) { 51 | size_t size = dist(*gen); 52 | auto ptr = ::malloc(size); 53 | allocated[i] = ptr; 54 | } 55 | 56 | assert(allocated.size() == NObjects); 57 | 58 | if (Shuffle) { 59 | // Shuffle them. 60 | std::shuffle(allocated.begin(), allocated.end(), *gen); 61 | } 62 | 63 | // Free some fraction of them (potentially in shuffled order). 64 | for (auto i = 0UL; i < ((OccupancyDenominator - OccupancyNumerator) * NObjects) / OccupancyDenominator; i++) { 65 | auto ptr = allocated[i]; 66 | // std::cout << "freeing " << ptr << std::endl; 67 | ::free(ptr); 68 | } 69 | } 70 | 71 | ~Fragmenter() { 72 | delete gen; 73 | } 74 | }; 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /experimental/litterer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef LITTERER_HPP 4 | #define LITTERER_HPP 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | /*** 17 | * Litterer 18 | * 19 | * Shuffles the heap by allocating memory, freeing it randomly, 20 | * and leaving some fraction allocated. 21 | * 22 | * @author Emery Berger 23 | * 24 | ***/ 25 | 26 | class Litterer { 27 | private: 28 | std::mt19937 * gen { nullptr }; 29 | size_t _seed {0}; 30 | public: 31 | Litterer(size_t MinSize, 32 | size_t MaxSize, 33 | size_t NObjects, 34 | size_t OccupancyNumerator, 35 | size_t OccupancyDenominator, 36 | size_t Seed = 0) 37 | { 38 | std::random_device rd; 39 | std::cout << "Littering." << std::endl; 40 | // If there is a non-zero seed set, use it; otherwise, use the 41 | // random device. 42 | if (Seed) { 43 | _seed = Seed; 44 | } else { 45 | _seed = rd(); 46 | } 47 | gen = new std::mt19937(_seed); 48 | std::vector allocated = *(new std::vector(NObjects)); 49 | std::uniform_int_distribution<> dist(MinSize, MaxSize); 50 | 51 | intptr_t minAddress = -1; 52 | intptr_t maxAddress = -1; 53 | 54 | // Allocate a bunch of objects from a range of sizes. 55 | for (auto i = 0UL; i < NObjects; i++) { 56 | size_t size = dist(*gen); 57 | auto ptr = ::malloc(size); 58 | allocated[i] = ptr; 59 | 60 | if ((intptr_t) ptr < minAddress || minAddress == -1) { 61 | minAddress = (intptr_t) ptr; 62 | } 63 | 64 | if ((intptr_t) ptr > maxAddress || maxAddress == -1) { 65 | maxAddress = (intptr_t) ptr; 66 | } 67 | } 68 | 69 | #ifndef NODEBUG 70 | std::cout << "Allocated " << NObjects << " objects..." << std::endl; 71 | std::cout << "Min: " << minAddress << ", Max: " << maxAddress << ", Spread: " << (maxAddress - minAddress) << std::endl; 72 | #endif 73 | 74 | assert(allocated.size() == NObjects); 75 | 76 | // Shuffle them. 77 | std::shuffle(allocated.begin(), allocated.end(), *gen); 78 | // Prevent optimization. 79 | volatile auto v = allocated.end(); 80 | 81 | // Free some fraction of them (potentially in shuffled order). 82 | auto objsToBeFreed = ((OccupancyDenominator - OccupancyNumerator) * NObjects) / OccupancyDenominator; 83 | for (auto i = 0UL; i < objsToBeFreed; i++) { 84 | auto ptr = allocated[i]; 85 | ::free(ptr); 86 | } 87 | #ifndef NODEBUG 88 | std::cout << "Littering complete." << std::endl; 89 | #endif 90 | } 91 | 92 | ~Litterer() { 93 | delete gen; 94 | } 95 | 96 | size_t getSeed() const { 97 | return _seed; 98 | } 99 | }; 100 | 101 | #endif 102 | -------------------------------------------------------------------------------- /experimental/notes.txt: -------------------------------------------------------------------------------- 1 | kernel.marker for timing; failing that, terminate 2 | 3 | Results for test-shim-buffermanager: 4 | 5 | Linux ARM, Mac Mini: 6 | working set: 64000, object size: 64 7 | no shim, no shuffle: 0.07MB (mimalloc), 2.543s 8 | no shim, shuffle: 0.07MB (mimalloc), 2.554s 9 | shim, no shuffle: 6.05MB (mimalloc), 5.379s 10 | shim, shuffle (5%, 1M obj): 62.05MB (mimalloc), 24.852s 11 | 12 | 13 | OS X, MacBook Pro (x86): 14 | working set: 256000, object size: 64 15 | no shim, shuffle: (mimalloc) 15.89s {TurboBoost off}, 9.89s {TurboBoost on} 16 | shim, shuffle: (mimalloc) 159.80s {TurboBoost off}, 160.03s {TurboBoost off} 17 | -------------------------------------------------------------------------------- /experimental/page-litterer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef PAGE_LITTERER_HPP 4 | #define PAGE_LITTERER_HPP 5 | 6 | #include // std::sort 7 | #include 8 | #ifndef __APPLE__ 9 | #include // malloc_usable_size 10 | #else 11 | #include 12 | #define malloc_usable_size(x) malloc_size(x) 13 | #endif 14 | #include 15 | #include 16 | 17 | #ifndef __APPLE__ 18 | long abs(long l) { return (l < 0L) ? -l : l; } 19 | #endif 20 | 21 | /*** 22 | * The intuition behind this first version is to keep allocating until we reach PageSize bytes, forming a group of at 23 | * least that size. Repeat to obtain NPages groups of at least PageSize bytes. Then, free a single object from each. 24 | ***/ 25 | class PageLittererV1 { 26 | public: 27 | PageLittererV1(int MinSize, int MaxSize, int NPages, size_t Seed, long PageSize = sysconf(_SC_PAGESIZE)) { 28 | std::vector> allocated = *(new std::vector>(NPages)); 29 | std::default_random_engine gen(Seed); 30 | std::uniform_int_distribution dist(MinSize, MaxSize); 31 | 32 | int NAllocations = 0; 33 | int pagesFilled = 0; 34 | long currentPageFill = 0; 35 | 36 | intptr_t minAddress = -1; 37 | intptr_t maxAddress = -1; 38 | 39 | int AverageObjectSize = (MinSize + MaxSize) / 2; 40 | for (int i = 0; i < NPages; ++i) { 41 | allocated[i].reserve((PageSize / AverageObjectSize) * 1.05); 42 | } 43 | 44 | while (pagesFilled != NPages) { 45 | size_t size = dist(gen); 46 | auto ptr = ::malloc(size); 47 | allocated[pagesFilled].push_back(ptr); 48 | ++NAllocations; 49 | 50 | if (minAddress == -1 || ((intptr_t) ptr) < minAddress) { 51 | minAddress = (intptr_t) ptr; 52 | } 53 | 54 | if (maxAddress == -1 || ((intptr_t) ptr) > maxAddress) { 55 | maxAddress = (intptr_t) ptr; 56 | } 57 | 58 | currentPageFill += ::malloc_usable_size(ptr); 59 | if (currentPageFill >= PageSize) { 60 | ++pagesFilled; 61 | currentPageFill = 0; 62 | } 63 | } 64 | 65 | std::vector toBeFreed = *(new std::vector); 66 | toBeFreed.reserve(NPages); 67 | for (int i = 0; i < NPages; ++i) { 68 | std::uniform_int_distribution dist(0, allocated[i].size() - 1); 69 | int index = dist(gen); 70 | toBeFreed.push_back(allocated[i][index]); 71 | } 72 | 73 | std::shuffle(toBeFreed.begin(), toBeFreed.end(), gen); 74 | for (auto ptr : toBeFreed) { 75 | free(ptr); 76 | } 77 | 78 | #ifndef NODEBUG 79 | std::cout << "Allocated " << NAllocations << " objects..." << std::endl; 80 | std::cout << "Min: " << minAddress << ", Max: " << maxAddress << ", Spread: " << (maxAddress - minAddress) << std::endl; 81 | #endif 82 | } 83 | }; 84 | 85 | /*** 86 | * This second method allocates objects, then sorts the addresses, and proceeds to free an object at least every 87 | * PageSize bytes. Some corner cases need to be handled, mainly because it is hard to know how many objects we will 88 | * actually need to allocate to be able to partition enough pages. 89 | ***/ 90 | class PageLittererV2 { 91 | public: 92 | PageLittererV2(int MinSize, int MaxSize, int NPages, size_t Seed, long PageSize = sysconf(_SC_PAGESIZE)) { 93 | std::vector allocated = *(new std::vector); 94 | std::default_random_engine gen(Seed); 95 | std::uniform_int_distribution dist(MinSize, MaxSize); 96 | 97 | int AverageObjectSize = (MinSize + MaxSize) / 2; 98 | // We add 5% to our initial guess to make it quasi-impossible to have a second set of allocations. 99 | int NAllocations = guess(AverageObjectSize, 0, 0, NPages, PageSize) * 1.05; 100 | int PagesFilled = 0; 101 | 102 | while (PagesFilled < NPages) { 103 | allocated.reserve(NAllocations); 104 | 105 | for (int i = 0; i < NAllocations; ++i) { 106 | size_t size = dist(gen); 107 | auto ptr = ::malloc(size); 108 | allocated.push_back(ptr); 109 | } 110 | 111 | // Recount how many pages our current allocations are filling. 112 | std::sort(allocated.begin(), allocated.end()); 113 | PagesFilled = 0; 114 | intptr_t previous = (intptr_t) allocated[0]; 115 | for (int i = 1; i < allocated.size(); ++i) { 116 | if (abs((intptr_t) allocated[i] - previous) >= PageSize) { 117 | previous = (intptr_t) allocated[i]; 118 | ++PagesFilled; 119 | } 120 | } 121 | 122 | // If we fell short, allocate more. 123 | if (PagesFilled < NPages) { 124 | NAllocations = guess(AverageObjectSize, NAllocations, PagesFilled, NPages, PageSize); 125 | } 126 | } 127 | 128 | // allocated is already sorted. 129 | 130 | #ifndef NODEBUG 131 | std::cout << "Allocated " << NAllocations << " objects..." << std::endl; 132 | intptr_t minAddress = (intptr_t) allocated[0]; 133 | intptr_t maxAddress = (intptr_t) allocated[allocated.size() - 1]; 134 | std::cout << "Min: " << minAddress << ", Max: " << maxAddress << ", Spread: " << (maxAddress - minAddress) << std::endl; 135 | #endif 136 | 137 | std::vector toBeFreed = *(new std::vector); 138 | toBeFreed.reserve(PagesFilled); 139 | 140 | intptr_t previous = (intptr_t) allocated[0]; 141 | for (int i = 1; i < allocated.size(); ++i) { 142 | if (abs((intptr_t) allocated[i] - previous) >= PageSize) { 143 | toBeFreed.push_back((void*) previous); 144 | previous = (intptr_t) allocated[i]; 145 | } 146 | } 147 | 148 | std::shuffle(toBeFreed.begin(), toBeFreed.end(), gen); 149 | for (auto ptr : toBeFreed) { 150 | free(ptr); 151 | } 152 | 153 | assert(PagesFilled >= NPages); 154 | } 155 | 156 | private: 157 | // Estimate total allocations that would be needed to reach the goal. 158 | int guess(int AverageObjectSize, int AlreadyAllocated, int PagesFilled, int TargetPages, long PageSize) { 159 | return (AlreadyAllocated && PagesFilled) ? ((long long int) AlreadyAllocated) * TargetPages / PagesFilled 160 | : ((long long int) TargetPages) * PageSize / AverageObjectSize; 161 | } 162 | }; 163 | 164 | #endif 165 | -------------------------------------------------------------------------------- /experimental/simpool.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef SIMPOOL_HPP 4 | #define SIMPOOL_HPP 5 | 6 | #include "dllist.h" 7 | 8 | #include 9 | #include 10 | 11 | class SimPool { 12 | public: 13 | 14 | ~SimPool() 15 | { 16 | release(); 17 | } 18 | 19 | inline void * malloc(size_t sz) { 20 | // Get an object of the requested size plus the header. 21 | auto * b = reinterpret_cast(::malloc(sz + sizeof(HL::DLList::Entry))); 22 | // Add to the front of the linked list. 23 | _list.insert(b); 24 | // Return just past the header. 25 | return reinterpret_cast(b + 1); 26 | } 27 | 28 | inline void free(void * ptr) { 29 | // Find the actual block header. 30 | auto * b = reinterpret_cast(ptr) - 1; 31 | // Remove from the linked list. 32 | _list.remove(b); 33 | // Free the object. 34 | ::free(b); 35 | } 36 | 37 | bool isEmpty() { 38 | return _list.isEmpty(); 39 | } 40 | 41 | void release() { 42 | // Iterate through the list, freeing each item. 43 | auto * e = _list.get(); 44 | while (e) { 45 | ::free(e); 46 | e = _list.get(); 47 | } 48 | } 49 | 50 | private: 51 | 52 | HL::DLList _list; 53 | 54 | }; 55 | 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /experimental/simregion.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef SIMREGION_HPP 4 | #define SIMREGION_HPP 5 | 6 | #include 7 | #include 8 | #ifndef __APPLE__ 9 | #include 10 | #else 11 | #include 12 | #endif 13 | 14 | #include 15 | 16 | class SimRegion { 17 | public: 18 | 19 | static constexpr int VECTOR_INITIAL_SIZE = 0; 20 | 21 | enum { Alignment = alignof(std::max_align_t) }; // guaranteed by malloc 22 | 23 | static inline constexpr size_t align(size_t sz) { 24 | return (sz + alignof(std::max_align_t) - 1) & ~(alignof(std::max_align_t) - 1); 25 | } 26 | 27 | SimRegion(unsigned int = 0) // ignore argument - just here for compatibility now 28 | { 29 | } 30 | 31 | ~SimRegion() { 32 | release(); 33 | } 34 | 35 | static inline size_t getSize(void * ptr) { 36 | #ifndef __APPLE__ 37 | return ::malloc_usable_size(ptr); 38 | #else 39 | return ::malloc_size(ptr); 40 | #endif 41 | } 42 | 43 | inline void * malloc(size_t sz) { 44 | if (sz == 0) { 45 | return nullptr; 46 | } 47 | // sz = align(sz); 48 | auto ptr = ::malloc(sz); 49 | _allocated.push_back(ptr); 50 | return ptr; 51 | } 52 | 53 | inline void * memalign(size_t alignment, size_t size) { 54 | // Check for non power-of-two alignment. 55 | if ((alignment == 0) || (alignment & (alignment - 1))) 56 | { 57 | return nullptr; 58 | } 59 | 60 | if (alignment <= Alignment) { 61 | // Already aligned by default. 62 | return malloc(size); 63 | } else { 64 | // Try to just allocate an object of the requested size. 65 | // If it happens to be aligned properly, just return it. 66 | void * ptr = malloc(size); 67 | if (((size_t) ptr & ~(alignment - 1)) == (size_t) ptr) { 68 | // It is already aligned just fine; return it. 69 | return ptr; 70 | } 71 | // It was not aligned as requested: free the object and allocate a big one, 72 | // and align within. 73 | free(ptr); 74 | ptr = malloc (size + 2 * alignment); 75 | void * alignedPtr = (void *) (((size_t) ptr + alignment - 1) & ~(alignment - 1)); 76 | return alignedPtr; 77 | } 78 | } 79 | 80 | inline void free(void *) { 81 | } 82 | 83 | inline void * allocate(size_t sz) { 84 | return malloc(sz); 85 | } 86 | 87 | inline void deallocate(void *) 88 | { 89 | } 90 | 91 | inline size_t size() { 92 | return _allocated.size(); 93 | } 94 | 95 | void rewind() 96 | { 97 | std::for_each(_allocated.begin(), _allocated.end(), std::free); 98 | _allocated.clear(); 99 | } 100 | 101 | void release() 102 | { 103 | rewind(); 104 | } 105 | 106 | private: 107 | 108 | std::vector _allocated; 109 | }; 110 | 111 | #endif // SIMREGION_HPP 112 | -------------------------------------------------------------------------------- /experimental/stlallocator.h: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | 3 | /* 4 | 5 | Heap Layers: An Extensible Memory Allocation Infrastructure 6 | 7 | Copyright (C) 2000-2020 by Emery Berger 8 | http://www.emeryberger.com 9 | emery@cs.umass.edu 10 | 11 | Heap Layers is distributed under the terms of the Apache 2.0 license. 12 | 13 | You may obtain a copy of the License at 14 | http://www.apache.org/licenses/LICENSE-2.0 15 | 16 | */ 17 | 18 | #ifndef HL_STLALLOCATOR_H 19 | #define HL_STLALLOCATOR_H 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include // STL 27 | 28 | // Somewhere someone is defining a max macro (on Windows), 29 | // and this is a problem -- solved by undefining it. 30 | 31 | #if defined(max) 32 | #undef max 33 | #endif 34 | 35 | using namespace std; 36 | 37 | /** 38 | * @class STLAllocator 39 | * @brief An allocator adapter for STL. 40 | * 41 | * This mixin lets you use any Heap Layers allocator as the allocator 42 | * for an STL container. 43 | * 44 | * Example: 45 | * 46 | * typedef STLAllocator MyAllocator;
47 | * list l;
48 | *
49 | */ 50 | 51 | namespace HL { 52 | 53 | template 54 | class STLAllocator : public Super { 55 | public: 56 | 57 | typedef T value_type; 58 | typedef T * pointer; 59 | typedef const T * const_pointer; 60 | typedef T& reference; 61 | typedef const T& const_reference; 62 | typedef std::size_t size_type; 63 | typedef std::ptrdiff_t difference_type; 64 | typedef std::false_type propagate_on_container_move_assignment; 65 | typedef std::false_type is_always_equal; 66 | 67 | template 68 | struct rebind { 69 | typedef STLAllocator other; 70 | }; 71 | 72 | pointer address (reference x) const { 73 | return &x; 74 | } 75 | 76 | const_pointer address (const_reference x) const { 77 | return &x; 78 | } 79 | 80 | STLAllocator() throw() { 81 | } 82 | 83 | STLAllocator (const STLAllocator& s) throw() 84 | : Super (s) 85 | {} 86 | 87 | virtual ~STLAllocator() throw() { 88 | } 89 | 90 | /// Make the maximum size be the largest possible object. 91 | size_type max_size() const 92 | { 93 | return std::numeric_limits::max() / sizeof(T); 94 | } 95 | 96 | #if defined(_WIN32) 97 | char * _Charalloc (size_type n) { 98 | return (char *) allocate (n); 99 | } 100 | #endif 101 | 102 | #if defined(__SUNPRO_CC) 103 | inline void * allocate (size_type n, 104 | const void * = 0) { 105 | if (n) { 106 | return reinterpret_cast(Super::malloc(sizeof(T) * n)); 107 | } else { 108 | return (void *) 0; 109 | } 110 | } 111 | #else 112 | inline pointer allocate (size_type n, 113 | const void * = 0) { 114 | if (n) { 115 | return reinterpret_cast(Super::malloc(sizeof(T) * n)); 116 | } else { 117 | return 0; 118 | } 119 | } 120 | #endif 121 | 122 | inline void deallocate (void * p, size_type) { 123 | Super::free (p); 124 | } 125 | 126 | inline void deallocate (pointer p, size_type) { 127 | Super::free (p); 128 | } 129 | 130 | #if __cplusplus >= 201103L 131 | // Updated API from C++11 to work with move constructors 132 | template 133 | void construct (U* p, Args&&... args) { 134 | new((void *) p) U(std::forward(args)...); 135 | } 136 | 137 | template 138 | void destroy (U* p) { 139 | p->~U(); 140 | } 141 | 142 | #else 143 | // Legacy API for pre-C++11 144 | void construct (pointer p, const T& val) { 145 | new ((void *) p) T (val); 146 | } 147 | 148 | void destroy (pointer p) { 149 | ((T*)p)->~T(); 150 | } 151 | 152 | #endif 153 | 154 | template STLAllocator (const STLAllocator &) throw() 155 | { 156 | } 157 | 158 | }; 159 | 160 | template 161 | inline bool operator!=(const STLAllocator& a, const STLAllocator& b) { 162 | return (&a != &b); 163 | } 164 | 165 | template 166 | inline bool operator==(const STLAllocator& a, const STLAllocator& b) { 167 | return (&a == &b); 168 | } 169 | 170 | 171 | } 172 | 173 | 174 | #endif 175 | -------------------------------------------------------------------------------- /experimental/test-fragmenter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "fragmenter.hpp" 4 | 5 | int 6 | main() 7 | { 8 | Fragmenter<8, 64, 1048576, 50> fragIt; 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /experimental/test-shim-allocator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "shim_allocator.hpp" 7 | 8 | #ifndef USE_MALLOC 9 | #define USE_MALLOC 0 10 | #endif 11 | 12 | #ifndef USE_SHUFFLE 13 | #define USE_SHUFFLE 1 14 | #endif 15 | 16 | #if USE_MALLOC 17 | #define MALLOC(x) malloc(x) 18 | #define FREE(x) free(x) 19 | #else 20 | #define MALLOC(x) alloc.allocate(x) 21 | #define FREE(x) alloc.deallocate(x) 22 | #endif 23 | 24 | 25 | int main() 26 | { 27 | constexpr size_t objectSize = 64; 28 | constexpr int its = 1000000; 29 | constexpr int reps = 10000; 30 | 31 | #if USE_MALLOC 32 | std::cout << "Malloc "; 33 | #else 34 | std::cout << "Shim "; 35 | #endif 36 | std::cout << " objectSize=" << objectSize << ", reps = " << reps << ", each rep: iterations=" << its; 37 | 38 | #if USE_SHUFFLE 39 | std::cout << " [shuffled]"; 40 | #endif 41 | std::cout << std::endl; 42 | 43 | BloombergLP::bslma::ShimAllocator alloc; 44 | auto ptrs = new void *[its]; 45 | 46 | 47 | std::random_device rdev; 48 | std::mt19937 rng(rdev()); 49 | 50 | // Shuffle memory. 51 | for (auto i = 0; i < its; i++) { 52 | ptrs[i] = MALLOC(objectSize); 53 | } 54 | #if USE_SHUFFLE 55 | std::shuffle(ptrs, ptrs + its, rng); 56 | #endif 57 | for (auto i = 0; i < its; i++) { 58 | FREE(ptrs[i]); 59 | } 60 | 61 | // Now repeatedly allocate and free. 62 | volatile void * ptr = nullptr; 63 | volatile char target[objectSize]; 64 | for (auto its = 0; its < reps; its++) { 65 | for (auto i = 0; i < its; i++) { 66 | ptr = MALLOC(objectSize); 67 | ptrs[i] = (void *) ptr; 68 | memset((void *) ptr, 0, objectSize); 69 | } 70 | for (auto i = 0; i < its; i++) { 71 | memcpy((void *) &target, (void *) ptrs[i], objectSize); 72 | } 73 | #if USE_MALLOC 74 | for (auto i = 0; i < its; i++) { 75 | FREE(ptrs[i]); 76 | } 77 | #else 78 | alloc.release(); 79 | #endif 80 | } 81 | return (long) ptr; 82 | } 83 | -------------------------------------------------------------------------------- /experimental/test-string.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | //#include 11 | #include "shim_allocator.hpp" 12 | 13 | #define USE_BUFFERED 0 14 | #define USE_NEWDELETE 0 15 | #define USE_SHIM 1 16 | 17 | constexpr auto ITS = 1; // 128; 18 | 19 | #if USE_BUFFERED + USE_NEWDELETE + USE_SHIM != 1 20 | #error "Exactly one of USE_BUFFERED, USE_NEWDELETE, or NEW_SHIM must be set to 1." 21 | #endif 22 | 23 | #if USE_BUFFERED 24 | using allocatorType = BloombergLP::bdlma::BufferedSequentialAllocator; 25 | #elif USE_NEWDELETE 26 | using allocatorType = BloombergLP::bslma::NewDeleteAllocator; 27 | #elif USE_SHIM 28 | using allocatorType = ShimAllocator; 29 | #endif 30 | 31 | template 32 | class stl_alloc : public bsl::allocator { 33 | public: 34 | using value_type = T; 35 | }; 36 | 37 | #include "fragmenter.hpp" 38 | 39 | #include 40 | 41 | int main() 42 | { 43 | #define SEED 0 // 4148279034// 0 // 99371865 44 | #if 0 45 | for (auto i = 0; i < 100; i++) { 46 | volatile Fragmenter<48, 56, 104857, 99, 100, SEED> frag; 47 | } 48 | #endif 49 | 50 | using namespace std::chrono; 51 | 52 | auto start = high_resolution_clock::now(); 53 | 54 | // using allocatorType = BloombergLP::bslma::TestAllocator; // BufferedSequentialAllocator; 55 | #if USE_BUFFERED 56 | char abuf[1024*100]; 57 | allocatorType alloc(abuf, 1024*100); 58 | #elif USE_NEWDELETE 59 | allocatorType alloc; 60 | #elif USE_SHIM 61 | allocatorType alloc; 62 | #endif 63 | 64 | 65 | volatile void * buf[1000]; 66 | volatile char rdBuf[64]; 67 | 68 | 69 | for (int i = 0; i < 10000000 / ITS; i++) { 70 | #if !USE_NEWDELETE 71 | alloc.rewind(); 72 | #endif 73 | 74 | #if 0 75 | 76 | for (int j = 0; j < 1000; j++) { 77 | buf[j] = alloc.allocate(64); 78 | memset((void *) buf[j], 13, 64); 79 | memcpy((void *) rdBuf, (void *) buf[j], 64); 80 | } 81 | for (int j = 0; j < 1000; j++) { 82 | alloc.deallocate((void *) buf[j]); 83 | } 84 | 85 | #else 86 | 87 | 88 | for (int j = 0; j < ITS; j++) { 89 | volatile bsl::string bs1 ("The quick brown fox jumps over the lazy dog", &alloc); 90 | volatile bsl::string bs2 ("Portez ce vieux whisky au juge blond qui fume", &alloc); 91 | #if 0 92 | volatile bsl::string bs3 ("Portez ce vieux whisky au juge blond qui fume la pipe", &alloc); 93 | volatile bsl::string bs4 ("Lorem ipsum dolor sit amet, consectetur adipiscing elit", &alloc); 94 | volatile bsl::string bs5 ("The quick brown fox jumps over the lazy dog", &alloc); 95 | volatile bsl::string bs6 ("Portez ce vieux whisky au juge blond qui fume", &alloc); 96 | volatile bsl::string bs7 ("Portez ce vieux whisky au juge blond qui fume la pipe", &alloc); 97 | volatile bsl::string bs8 ("Lorem ipsum dolor sit amet, consectetur adipiscing elit", &alloc); 98 | #endif 99 | } 100 | #endif 101 | #if 0 102 | vector> v1; 103 | for (int j = 0; j < 100; j++) { 104 | v1.push_back(i); 105 | } 106 | for (int j = 99; j >= 0; j--) { 107 | volatile int z = v1.back(); 108 | v1.pop_back(); 109 | } 110 | #endif 111 | } 112 | // std::cout << bs << std::endl; 113 | //std::cout << alloc.numBlocksInUse() << std::endl; 114 | 115 | auto stop = high_resolution_clock::now(); 116 | 117 | std::cout << "Time elapsed: " << (duration_cast>(stop-start)).count() << std::endl; 118 | return 0; 119 | } 120 | -------------------------------------------------------------------------------- /experimental/tprintf.h: -------------------------------------------------------------------------------- 1 | #ifndef TPRINTF_H 2 | #define TPRINTF_H 3 | 4 | #pragma once 5 | 6 | // Written by Emery Berger 7 | 8 | #if !defined(_WIN32) 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | 17 | namespace tprintf { 18 | 19 | const int MAXBUF = 65536; 20 | static int FD { 1 }; // 2 21 | 22 | template 23 | inline void writeval(T v); 24 | 25 | 26 | template 27 | inline unsigned int itoa(char * buf, T v) { 28 | long n = (long) v; 29 | auto startbuf = buf; 30 | if (n < 0) { 31 | *buf++ = '-'; 32 | n = -n; 33 | } 34 | if (n == 0) { 35 | *buf++ = '0'; 36 | return static_cast(buf - startbuf); 37 | } 38 | long tens = 1L; 39 | while (n / (10 * tens)) { 40 | tens *= 10; 41 | } 42 | while (tens) { 43 | *buf++ = '0' + static_cast(n / tens); 44 | n = n - (n / tens) * tens; 45 | tens /= 10; 46 | } 47 | return (unsigned int) (buf - startbuf); 48 | } 49 | 50 | inline unsigned int ftoa(char * buf, double n, int decimalPlaces = 4) { 51 | // Extract integer part 52 | auto ipart = (long) n; 53 | 54 | // Extract floating part 55 | auto fpart = n - (double) ipart; 56 | if (fpart < 0.0) { 57 | fpart = -fpart; 58 | } 59 | 60 | // convert integer part to string 61 | auto i = itoa(buf, ipart); 62 | 63 | if (decimalPlaces > 0) { 64 | buf[i] = '.'; 65 | auto multiple = pow(10, decimalPlaces); 66 | fpart = fpart * multiple; 67 | multiple /= 10; 68 | while ((fpart < multiple) && (decimalPlaces > 0)) { 69 | buf[++i] = '0'; 70 | multiple /= 10; 71 | decimalPlaces--; 72 | } 73 | if (fpart > 0) { 74 | i = i + itoa(buf + i + 1, (long) fpart) + 1; 75 | } 76 | } 77 | return i; 78 | } 79 | 80 | inline void writeval(double n) { 81 | char buf[MAXBUF]; 82 | unsigned long len = ftoa(buf, n); 83 | auto _ __attribute__((unused)) = write(FD, buf, len); 84 | } 85 | 86 | inline void writeval(float n) { 87 | char buf[MAXBUF]; 88 | auto len = ftoa(buf, n); 89 | auto _ __attribute__((unused)) = write(FD, buf, len); 90 | } 91 | 92 | inline void writeval(const char * str) { 93 | auto _ __attribute__((unused)) = write(FD, str, strlen(str)); 94 | } 95 | 96 | inline void writeval(char * str) { 97 | auto _ __attribute__((unused)) = write(FD, str, strlen(str)); 98 | } 99 | 100 | inline void writeval(const char c) { 101 | char buf[1]; 102 | buf[0] = c; 103 | auto _ __attribute__((unused)) = write(FD, buf, 1); 104 | } 105 | 106 | inline void writeval(uint64_t n) { 107 | char buf[MAXBUF]; 108 | auto len = itoa(buf, n); 109 | auto _ __attribute__((unused)) = write(FD, buf, len); 110 | } 111 | 112 | template 113 | inline void writeval(T n) { 114 | char buf[MAXBUF]; 115 | auto len = itoa(buf, n); 116 | auto _ __attribute__((unused)) = write(FD, buf, len); 117 | } 118 | 119 | inline void tprintf(const char* format) // base function 120 | { 121 | writeval(format); 122 | } 123 | 124 | template 125 | inline void tprintf(const char * format, T value, Targs... Fargs) 126 | { 127 | for ( ; *format != '\0'; format++ ) { 128 | if ( *format == '@' ) { 129 | if ( *(format + 1) == '@') { 130 | writeval("@"); 131 | format = format+2; 132 | } else { 133 | writeval(value); 134 | tprintf(format+1, Fargs...); 135 | return; 136 | } 137 | } 138 | writeval(*format); 139 | } 140 | } 141 | 142 | } 143 | 144 | #endif // !_WIN32 145 | 146 | #endif 147 | -------------------------------------------------------------------------------- /experimental/validator.py: -------------------------------------------------------------------------------- 1 | import re 2 | import fileinput 3 | 4 | matcher = r"\d+\s+[a-z\_\.]+\s+0x[0-9a-f]+\s+([a-zA-Z\_0-9]+)" 5 | f = re.compile(matcher) 6 | 7 | test_str = "0 libhoard.dylib 0x0000000113c480af xxmalloc + 159" 8 | r = f.match(test_str) 9 | 10 | print(re.findall(f, test_str)) 11 | 12 | print("WOOT") 13 | 14 | state = 0 15 | 16 | for count, line in enumerate(fileinput.input()): 17 | results = re.findall(f, line) 18 | if not results: 19 | continue 20 | # Look for mallocs called by any Bloomberg function that isn't 21 | # just the wrapper around new/delete/malloc/free, IF they aren't 22 | # intercepted by a call to a SimPool or SimRegion. 23 | if state == 0 and results[0] == "xxmalloc": 24 | state = 1 25 | elif state == 1 and ("Bloomberg" in results[0] and "NewDeleteAllocator" in results[0] or "MallocFreeAllocator" in results[0]): 26 | # print("GOOD " + str(count)) 27 | state = 0 28 | elif state == 1 and ("SimRegion" in results[0] or "SimPool" in results[0]): 29 | state = 2 30 | elif state == 1 and ("Bloomberg" in results[0] and "NewDeleteAllocator" not in results[0] and "MallocFreeAllocator" not in results[0]): 31 | print("CRAP " + str(count)) 32 | state = 0 33 | elif state == 2 and ("Bloomberg" in results[0] and "NewDeleteAllocator" not in results[0] and "MallocFreeAllocator" not in results[0]): 34 | # print("GOOD " + str(count)) 35 | state = 0 36 | 37 | 38 | -------------------------------------------------------------------------------- /heaplayers-make.mk: -------------------------------------------------------------------------------- 1 | CPPFLAGS = -ftls-model=initial-exec -W -Wall -flto -std=c++14 -fno-builtin-malloc -fvisibility=hidden -g -arch x86_64 # -arch arm64 2 | # CPPFLAGS = -ftls-model=initial-exec -W -Wall -flto -std=c++14 -DNDEBUG -fno-builtin-malloc -fvisibility=hidden -O3 -arch x86_64 # -arch arm64 3 | CXX = clang++ 4 | 5 | INCLUDES = -Ivendor/libbacktrace -I. -I./include -IHeap-Layers -IHeap-Layers/wrappers -IHeap-Layers/utility 6 | 7 | MACOS_SRC = lib$(LIBNAME).cpp printf.cpp Heap-Layers/wrappers/macwrapper.cpp 8 | # MACOS_COMPILE = $(CXX) -ftls-model=initial-exec -ftemplate-depth=1024 -arch x86_64 -arch arm64 -pipe $(CPPFLAGS) $(INCLUDES) -D_REENTRANT=1 -compatibility_version 1 -current_version 1 -D'CUSTOM_PREFIX(x)=xx\#\#x' $(MACOS_SRC) -dynamiclib -install_name $(DESTDIR)$(PREFIX)/lib$(LIBNAME).dylib -o lib$(LIBNAME).dylib -Lvendor/libbacktrace/.libs -lbacktrace -ldl -lpthread 9 | MACOS_COMPILE = $(CXX) -ftls-model=initial-exec -ftemplate-depth=1024 -pipe $(CPPFLAGS) $(INCLUDES) -D_REENTRANT=1 -compatibility_version 1 -current_version 1 -D'CUSTOM_PREFIX(x)=xx\#\#x' $(MACOS_SRC) -dynamiclib -install_name $(DESTDIR)$(PREFIX)/lib$(LIBNAME).dylib -o lib$(LIBNAME).dylib -Lvendor/libbacktrace/.libs -lbacktrace -ldl -lpthread 10 | 11 | LINUX_SRC = lib$(LIBNAME).cpp printf.cpp # Heap-Layers/wrappers/gnuwrapper.cpp 12 | LINUX_COMPILE = $(CXX) $(CPPFLAGS) -D'CUSTOM_PREFIX(x)=xx\#\#x' -I/usr/include/nptl -pipe -fPIC $(INCLUDES) -D_REENTRANT=1 -shared $(LINUX_SRC) -Bsymbolic -o lib$(LIBNAME).so -Lvendor/libbacktrace/.libs -lbacktrace -ldl -lpthread 13 | 14 | UNAME_S := $(shell uname -s) 15 | UNAME_P := $(shell uname -p) 16 | 17 | ifeq ($(UNAME_S),Darwin) 18 | all: Heap-Layers $(MACOS_SRC) 19 | $(MACOS_COMPILE) 20 | endif 21 | 22 | ifeq ($(UNAME_S),Linux) 23 | all: Heap-Layers $(LINUX_SRC) 24 | $(LINUX_COMPILE) 25 | endif 26 | 27 | Heap-Layers: 28 | git clone https://github.com/emeryberger/Heap-Layers 29 | -------------------------------------------------------------------------------- /libcheap.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | libcheap.cpp 3 | enables easy use of regions 4 | invoke `region_begin(...)` --> all subsequent `malloc`s use the buffer, 5 | `free`s are ignored 6 | invoke `region_end()` --> back to normal `malloc`/`free` behavior 7 | 8 | see the C++ API in cheap.h 9 | 10 | */ 11 | 12 | #include 13 | 14 | #include "cheap.h" 15 | 16 | #if defined(__APPLE__) 17 | #include "macinterpose.h" 18 | #endif 19 | 20 | #if defined(__APPLE__) 21 | #define LOCAL_PREFIX(x) xx##x 22 | #else 23 | #define LOCAL_PREFIX(x) x 24 | #endif 25 | 26 | CustomHeapType &getTheCustomHeap() { 27 | static CustomHeapType thang; 28 | return thang; 29 | } 30 | 31 | class cheap_current { 32 | private: 33 | cheap_current(); 34 | public: 35 | cheap_current(const cheap_current&) = delete; 36 | cheap_current& operator=(const cheap_current&) = delete; 37 | cheap_current(cheap_current &&) = delete; 38 | cheap_current & operator=(cheap_current &&) = delete; 39 | inline static auto*& current() { 40 | #if THREAD_SAFE 41 | static __thread cheap::cheap_base * c __attribute__((tls_model ("initial-exec"))); 42 | #else 43 | static cheap::cheap_base * c; 44 | #endif 45 | return c; 46 | } 47 | }; 48 | 49 | __attribute__((visibility("default"))) cheap::cheap_base*& current() { 50 | return cheap_current::current(); 51 | } 52 | 53 | #if 1 54 | #define FLATTEN __attribute__((flatten)) 55 | #else 56 | #define FLATTEN 57 | #endif 58 | 59 | extern "C" size_t FLATTEN xxmalloc_usable_size(void *ptr) { 60 | auto ci = current(); 61 | if (likely(ci && ci->in_cheap)) { 62 | return ci->getSize(ptr); 63 | } 64 | return getTheCustomHeap().getSize(ptr); 65 | } 66 | 67 | extern "C" void * FLATTEN xxmalloc(size_t req_sz) __attribute__((alloc_size(1))) __attribute((malloc)); 68 | 69 | extern "C" void * FLATTEN xxmalloc(size_t req_sz) { 70 | size_t sz = req_sz; 71 | auto ci = current(); 72 | // tprintf::tprintf("xxmalloc(@) OH YEAH @\n", sz, ci); 73 | if (likely(ci && ci->in_cheap)) { 74 | auto ptr = ci->malloc(sz); 75 | // tprintf::tprintf("region malloc @ = @\n", sz, ptr); 76 | return ptr; 77 | } 78 | return getTheCustomHeap().malloc(sz); 79 | } 80 | 81 | extern "C" void FLATTEN xxfree(void *ptr) { 82 | auto ci = current(); 83 | if (unlikely(!ci || !ci->in_cheap)) { 84 | getTheCustomHeap().free(ptr); 85 | return; 86 | } 87 | return ci->free(ptr); 88 | } 89 | 90 | extern "C" void FLATTEN xxfree_sized(void *ptr, size_t) { 91 | xxfree(ptr); 92 | } 93 | 94 | extern "C" void * FLATTEN xxmemalign(size_t alignment, size_t sz) { 95 | auto ci = current(); 96 | if (likely(ci && ci->in_cheap)) { 97 | // Round up the region pointer to the required alignment. 98 | // auto bufptr = reinterpret_cast(ci->region.malloc(sz)); 99 | // FIXME THIS IS NOT ENOUGH 100 | // ci->region_buffer = 101 | // reinterpret_cast((bufptr + alignment - 1) & ~(alignment - 1)); 102 | return xxmalloc(sz); 103 | } 104 | return getTheCustomHeap().memalign(alignment, sz); 105 | } 106 | 107 | extern "C" void __attribute__((always_inline)) xxmalloc_lock() { getTheCustomHeap().lock(); } 108 | 109 | extern "C" void __attribute__((always_inline)) xxmalloc_unlock() { 110 | getTheCustomHeap().unlock(); 111 | } 112 | 113 | #if !defined(__APPLE__) 114 | #include "gnuwrapper.cpp" 115 | #endif 116 | -------------------------------------------------------------------------------- /libcheaper.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | const char output_filename[] = "cheaper.out"; 15 | 16 | #include "common.hpp" 17 | #include "nextheap.hpp" 18 | 19 | #include "printf.h" 20 | 21 | auto output_file = open(output_filename, O_CREAT | O_RDWR | O_TRUNC, S_IWUSR | S_IRUSR); 22 | 23 | // For use by the replacement printf routines (see 24 | // https://github.com/mpaland/printf) 25 | extern "C" void _putchar(char ch) { ::write(output_file, (void *)&ch, 1); } 26 | 27 | #include "Backtrace.hpp" 28 | 29 | #if defined(__APPLE__) 30 | #include "macinterpose.h" 31 | #endif 32 | 33 | #if defined(__APPLE__) 34 | #define LOCAL_PREFIX(x) xx##x 35 | #else 36 | #define LOCAL_PREFIX(x) x 37 | #endif 38 | 39 | #if defined(__APPLE__) 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #endif 47 | 48 | #define gettid() (pthread_self()) 49 | 50 | class ParentHeap : public NextHeap {}; 51 | 52 | class CustomHeapType : public ParentHeap { 53 | public: 54 | void lock() {} 55 | void unlock() {} 56 | }; 57 | 58 | CustomHeapType& getTheCustomHeap() { 59 | static CustomHeapType thang; 60 | return thang; 61 | } 62 | 63 | static std::atomic samples{0}; 64 | static std::atomic busy{0}; 65 | #define USE_LOCKS 0 66 | 67 | #if USE_LOCKS 68 | static std::atomic_flag entryLock = ATOMIC_FLAG_INIT; 69 | static void lockme() { 70 | while (entryLock.test_and_set()) { 71 | } 72 | } 73 | static void unlockme() { entryLock.clear(); } 74 | #else 75 | static void lockme() {} 76 | static void unlockme() {} 77 | #endif 78 | 79 | // Open the JSON file before we start recording events, close it when we are done. 80 | class Initialization { 81 | public: 82 | Initialization() { 83 | ++busy; 84 | // tprintf::FD = output_file; 85 | // tprintf::tprintf("{ \"trace\": ["); 86 | printf_("{ \"trace\": ["); 87 | 88 | Backtrace::initialize(nullptr); 89 | --busy; 90 | 91 | isReadyToSample = true; 92 | } 93 | 94 | ~Initialization() { 95 | isReadyToSample = false; 96 | 97 | lockme(); 98 | printf_("\n]}"); 99 | // tprintf::tprintf("\n]}"); 100 | fsync(output_file); 101 | unlockme(); 102 | } 103 | 104 | static std::atomic isReadyToSample; 105 | }; 106 | 107 | static Initialization _; 108 | std::atomic Initialization::isReadyToSample{false}; 109 | 110 | static void printStack() { 111 | busy++; 112 | 113 | // We don't skip any frames. 114 | // Extra stack frames will get filtered out by the utility since libbacktrace won't have access to Cheap's debug info. 115 | for (const auto& frame : Backtrace::getBacktrace()) { 116 | char buf[1024]; 117 | snprintf_(buf, 1024, "[%s] %s:%d", frame.function.c_str(), frame.filename.c_str(), frame.lineno); 118 | printf_("\"%s\", ", buf); 119 | // tprintf::tprintf("\"@\", ", buf); 120 | } 121 | 122 | // Now print a bogus stack with no commas, just to make JSON processing happy. 123 | printf_("\"CHEAPERBAD\""); // Filtered out by cheaper.py 124 | // tprintf::tprintf("\"CHEAPERBAD\""); // Filtered out by cheaper.py 125 | 126 | busy--; 127 | } 128 | 129 | static void printProlog(char action) { 130 | if (samples != 0) { 131 | printf_(","); 132 | // tprintf::tprintf(","); 133 | } 134 | 135 | printf_("\n\t{ \"action\": \"%c\", \"stack\": [", action); 136 | // tprintf::tprintf("\n\t{ \"action\": \"@\", \"stack\": [", action); 137 | } 138 | 139 | extern "C" ATTRIBUTE_EXPORT void* xxmalloc(size_t sz) { 140 | // The number of bytes that need to be processed until the next sample. 141 | // This count is per-thread. 142 | static thread_local long long int sampling_count = 0; 143 | 144 | // Prevent loop due to internal call by backtrace_symbols 145 | // and omit any records once we have "ended" to prevent 146 | // corrupting the JSON output. 147 | if (busy || !Initialization::isReadyToSample) { 148 | return getTheCustomHeap().malloc(sz); 149 | } 150 | 151 | busy++; 152 | void* ptr = getTheCustomHeap().malloc(sz); 153 | size_t real_sz = getTheCustomHeap().getSize(ptr); 154 | busy--; 155 | 156 | auto tid = gettid(); 157 | lockme(); 158 | printProlog('M'); 159 | printStack(); 160 | printf_("], \"size\": %lu, \"reqsize\": %lu, \"address\": %lu, \"tid\": %d }", real_sz, sz, ptr, tid); 161 | // tprintf::tprintf("], \"size\": @, \"reqsize\": @, \"address\": @, \"tid\": @ }", real_sz, sz, ptr, tid); 162 | unlockme(); 163 | 164 | ++samples; 165 | 166 | return ptr; 167 | } 168 | 169 | extern "C" ATTRIBUTE_EXPORT void xxfree(void* ptr) { 170 | if (busy || !Initialization::isReadyToSample) { 171 | getTheCustomHeap().free(ptr); 172 | return; 173 | } 174 | 175 | busy++; 176 | // Note: this info is redundant (it will already be in the trace) and may be 177 | // removed. 178 | size_t real_sz = getTheCustomHeap().getSize(ptr); 179 | getTheCustomHeap().free(ptr); 180 | busy--; 181 | 182 | auto tid = gettid(); 183 | lockme(); 184 | printProlog('F'); 185 | printStack(); 186 | printf_("], \"size\": %lu, \"address\": %lu, \"tid\": %d }", real_sz, ptr, tid); 187 | // tprintf::tprintf("], \"size\": @, \"address\": @, \"tid\": @ }", real_sz, ptr, tid); 188 | unlockme(); 189 | ++samples; 190 | } 191 | 192 | extern "C" ATTRIBUTE_EXPORT size_t xxmalloc_usable_size(void* ptr) { 193 | auto real_sz = getTheCustomHeap().getSize(ptr); 194 | if (busy || !Initialization::isReadyToSample) { 195 | return real_sz; 196 | } 197 | auto tid = gettid(); 198 | lockme(); 199 | printProlog('S'); 200 | printStack(); 201 | printf_("], \"size\": %lu, \"address\": %lu, \"tid\": %d }", real_sz, ptr, tid); 202 | // tprintf::tprintf("], \"size\": @, \"address\": @, \"tid\": @ }", real_sz, ptr, tid); 203 | unlockme(); 204 | ++samples; 205 | 206 | return real_sz; 207 | } 208 | 209 | extern "C" ATTRIBUTE_EXPORT void xxfree_sized(void* ptr, size_t) { xxfree(ptr); } 210 | 211 | extern "C" ATTRIBUTE_EXPORT void* xxmemalign(size_t alignment, size_t sz) { 212 | if (busy || !Initialization::isReadyToSample) { 213 | return getTheCustomHeap().memalign(alignment, sz); 214 | } 215 | busy++; 216 | void* ptr = getTheCustomHeap().memalign(alignment, sz); 217 | auto real_sz = getTheCustomHeap().getSize(ptr); 218 | busy--; 219 | auto tid = gettid(); 220 | lockme(); 221 | printProlog('A'); 222 | printStack(); 223 | printf_("], \"size\": %lu, \"address\": %lu, \"tid\": %d }", real_sz, ptr, tid); 224 | // tprintf::tprintf("], \"size\": @, \"address\": @, \"tid\": @ }", real_sz, ptr, tid); 225 | unlockme(); 226 | ++samples; 227 | 228 | return ptr; 229 | } 230 | 231 | extern "C" ATTRIBUTE_EXPORT void xxmalloc_lock() { getTheCustomHeap().lock(); } 232 | 233 | extern "C" ATTRIBUTE_EXPORT void xxmalloc_unlock() { getTheCustomHeap().unlock(); } 234 | 235 | #if !defined(__APPLE__) 236 | #include "gnuwrapper.cpp" 237 | #endif 238 | -------------------------------------------------------------------------------- /nextheap.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef NEXTHEAP_HPP 4 | #define NEXTHEAP_HPP 5 | 6 | #include 7 | 8 | #if defined(__APPLE__) 9 | 10 | class NextHeap { 11 | public: 12 | enum { Alignment = alignof(max_align_t) }; 13 | 14 | inline void * malloc(size_t sz) { 15 | return ::malloc(sz); 16 | } 17 | inline void * memalign(size_t alignment, size_t size) { 18 | void * buf; 19 | ::posix_memalign(&buf, alignment, size); 20 | return buf; 21 | } 22 | inline bool free(void * ptr) { 23 | ::free(ptr); 24 | return true; 25 | } 26 | inline size_t getSize(void * ptr) { 27 | return ::malloc_size(ptr); 28 | } 29 | }; 30 | 31 | #else 32 | 33 | extern "C" { 34 | typedef void * mallocFn(size_t); 35 | typedef void freeFn(void *); 36 | typedef size_t mallocusablesizeFn(void *); 37 | typedef void * memalignFn(size_t, size_t); 38 | } 39 | 40 | class NextHeap { 41 | private: 42 | public: 43 | enum { Alignment = alignof(max_align_t) }; 44 | NextHeap() 45 | : _inMalloc (false), 46 | _inFree (false), 47 | _inMemalign (false), 48 | _malloc (nullptr), 49 | _free (nullptr), 50 | _memalign (nullptr), 51 | _malloc_usable_size (nullptr) 52 | { 53 | } 54 | inline void * malloc(size_t sz) { 55 | if (unlikely(_inMalloc)) { 56 | // If we're in a recursive call, return null. 57 | return 0; 58 | } 59 | if (unlikely(_malloc == nullptr)) { 60 | return slowPathMalloc(sz); 61 | } 62 | _inMalloc = true; 63 | void * ptr = (*_malloc)(sz); 64 | _inMalloc = false; 65 | return ptr; 66 | } 67 | inline void * memalign(size_t alignment, size_t sz) { 68 | if (unlikely(_memalign == nullptr)) { 69 | return slowPathMemalign(alignment, sz); 70 | } 71 | return (*_memalign)(alignment, sz); 72 | } 73 | inline bool free(void * ptr) { 74 | if (unlikely(_free == nullptr)) { 75 | return slowPathFree(ptr); 76 | } 77 | (*_free)(ptr); 78 | return true; 79 | } 80 | 81 | inline size_t getSize(void * ptr) { 82 | if (unlikely(!_malloc_usable_size)) { 83 | if (_inMalloc) { 84 | // If we're in a recursive call, return 0 for the size. 85 | return 0; 86 | } 87 | _inMalloc = true; 88 | *(void **)(&_malloc_usable_size) = dlsym(RTLD_NEXT, "malloc_usable_size"); 89 | _inMalloc = false; 90 | } 91 | return (*_malloc_usable_size)(ptr); 92 | } 93 | 94 | private: 95 | 96 | bool slowPathFree(void * ptr) { 97 | if (_inFree) { 98 | return false; 99 | } 100 | _inFree = true; 101 | *(void **)(&_free) = dlsym(RTLD_NEXT, "free"); 102 | _inFree = false; 103 | (*_free)(ptr); 104 | return true; 105 | } 106 | 107 | void * slowPathMalloc(size_t sz) { 108 | _inMalloc = true; 109 | // Welcome to the hideous incantation required to use dlsym with C++... 110 | *(void **)(&_malloc) = dlsym(RTLD_NEXT, "malloc"); 111 | _inMalloc = false; 112 | return (*_malloc)(sz); 113 | } 114 | 115 | void * slowPathMemalign(size_t alignment, size_t sz) { 116 | if (_inMemalign) { 117 | // If we're in a recursive call, return null. 118 | return 0; 119 | } 120 | _inMemalign = true; 121 | // Welcome to the hideous incantation required to use dlsym with C++... 122 | *(void **)(&_memalign) = dlsym(RTLD_NEXT, "memalign"); 123 | _inMemalign = false; 124 | return (*_memalign)(alignment, sz); 125 | } 126 | 127 | bool _inMalloc; 128 | bool _inFree; 129 | bool _inMemalign; 130 | mallocFn * _malloc; 131 | freeFn * _free; 132 | memalignFn * _memalign; 133 | mallocusablesizeFn * _malloc_usable_size; 134 | }; 135 | #endif 136 | 137 | #endif 138 | -------------------------------------------------------------------------------- /printf.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // \author (c) Marco Paland (info@paland.com) 3 | // 2014-2019, PALANDesign Hannover, Germany 4 | // 5 | // \license The MIT License (MIT) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | // \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on 26 | // embedded systems with a very limited resources. 27 | // Use this instead of bloated standard/newlib printf. 28 | // These routines are thread safe and reentrant. 29 | // 30 | /////////////////////////////////////////////////////////////////////////////// 31 | 32 | #ifndef _PRINTF_H_ 33 | #define _PRINTF_H_ 34 | 35 | #include 36 | #include 37 | 38 | 39 | #ifdef __cplusplus 40 | extern "C" { 41 | #endif 42 | 43 | 44 | /** 45 | * Output a character to a custom device like UART, used by the printf() function 46 | * This function is declared here only. You have to write your custom implementation somewhere 47 | * \param character Character to output 48 | */ 49 | void _putchar(char character); 50 | 51 | 52 | /** 53 | * Tiny printf implementation 54 | * You have to implement _putchar if you use printf() 55 | * To avoid conflicts with the regular printf() API it is overridden by macro defines 56 | * and internal underscore-appended functions like printf_() are used 57 | * \param format A string that specifies the format of the output 58 | * \return The number of characters that are written into the array, not counting the terminating null character 59 | */ 60 | //#define printf printf_ 61 | int printf_(const char* format, ...); 62 | 63 | 64 | /** 65 | * Tiny sprintf implementation 66 | * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD! 67 | * \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output! 68 | * \param format A string that specifies the format of the output 69 | * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character 70 | */ 71 | #define sprintf sprintf_ 72 | int sprintf_(char* buffer, const char* format, ...); 73 | 74 | 75 | /** 76 | * Tiny snprintf/vsnprintf implementation 77 | * \param buffer A pointer to the buffer where to store the formatted string 78 | * \param count The maximum number of characters to store in the buffer, including a terminating null character 79 | * \param format A string that specifies the format of the output 80 | * \param va A value identifying a variable arguments list 81 | * \return The number of characters that COULD have been written into the buffer, not counting the terminating 82 | * null character. A value equal or larger than count indicates truncation. Only when the returned value 83 | * is non-negative and less than count, the string has been completely written. 84 | */ 85 | #define snprintf snprintf_ 86 | #define vsnprintf vsnprintf_ 87 | int snprintf_(char* buffer, size_t count, const char* format, ...); 88 | int vsnprintf_(char* buffer, size_t count, const char* format, va_list va); 89 | 90 | 91 | /** 92 | * Tiny vprintf implementation 93 | * \param format A string that specifies the format of the output 94 | * \param va A value identifying a variable arguments list 95 | * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character 96 | */ 97 | #define vprintf vprintf_ 98 | int vprintf_(const char* format, va_list va); 99 | 100 | 101 | /** 102 | * printf with output function 103 | * You may use this as dynamic alternative to printf() with its fixed _putchar() output 104 | * \param out An output function which takes one character and an argument pointer 105 | * \param arg An argument pointer for user data passed to output function 106 | * \param format A string that specifies the format of the output 107 | * \return The number of characters that are sent to the output function, not counting the terminating null character 108 | */ 109 | int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...); 110 | 111 | 112 | #ifdef __cplusplus 113 | } 114 | #endif 115 | 116 | 117 | #endif // _PRINTF_H_ 118 | -------------------------------------------------------------------------------- /regionheap.h: -------------------------------------------------------------------------------- 1 | /* -*- C++ -*- */ 2 | 3 | #pragma once 4 | 5 | #ifndef REGIONHEAP_H 6 | #define REGIONHEAP_H 7 | 8 | #include "heaplayers.h" 9 | 10 | #include 11 | 12 | template 16 | class RegionHeap : public SuperHeap { 17 | public: 18 | 19 | // enum { Alignment = SuperHeap::Alignment }; 20 | 21 | RegionHeap() 22 | : _sizeRemaining (0), 23 | _currentArena (nullptr), 24 | _pastArenas (nullptr), 25 | _lastChunkSize (ChunkSize) 26 | { 27 | static_assert(MultiplierNumerator >= MultiplierDenominator, 28 | "Numerator must be at least as large as the denominator."); 29 | static_assert(MultiplierNumerator * MultiplierDenominator > 0, 30 | "Both the numerator and denominator need to be nonzero positive integers."); 31 | } 32 | 33 | ~RegionHeap() 34 | { 35 | clear(); 36 | } 37 | 38 | inline void * __attribute__((always_inline)) malloc (size_t sz) { 39 | void * ptr; 40 | // We assume sz is suitably aligned. 41 | if (unlikely(!_currentArena || (_sizeRemaining < sz))) { 42 | refill(sz); 43 | if (!_currentArena) { 44 | return nullptr; 45 | } 46 | } 47 | // tprintf::tprintf("bump @ from @\n", sz, _sizeRemaining); 48 | // Bump the pointer and update the amount of memory remaining. 49 | _sizeRemaining -= sz; 50 | ptr = _currentPointer; // Arena->arenaSpace; 51 | _currentPointer += sz; 52 | // _currentArena->arenaSpace += sz; 53 | return ptr; 54 | } 55 | 56 | /// Free in a zone allocator is a no-op. 57 | void __attribute__((always_inline)) free (void *) {} 58 | 59 | void __attribute__((noinline)) clear() 60 | { 61 | Arena * ptr = _pastArenas; 62 | while (ptr != nullptr) { 63 | void * oldPtr = (void *) ptr; 64 | ptr = ptr->nextArena; 65 | SuperHeap::free (oldPtr); 66 | } 67 | if (_currentArena != nullptr) { 68 | SuperHeap::free ((void *) _currentArena); 69 | } 70 | _sizeRemaining = 0; 71 | _currentArena = nullptr; 72 | _pastArenas = nullptr; 73 | _lastChunkSize = ChunkSize; 74 | } 75 | 76 | private: 77 | 78 | size_t getSize(void *); 79 | 80 | RegionHeap (const RegionHeap&); 81 | RegionHeap& operator=(const RegionHeap&); 82 | 83 | void __attribute__((noinline)) refill(size_t sz) { 84 | // Get more space in our arena since there's not enough room in this one. 85 | // First, add this arena to our past arena list. 86 | if (_currentArena) { 87 | _currentArena->nextArena = _pastArenas; 88 | _pastArenas = _currentArena; 89 | } 90 | // Now get more memory. 91 | size_t allocSize = (int) _lastChunkSize; 92 | _lastChunkSize *= MultiplierNumerator; 93 | _lastChunkSize /= MultiplierDenominator; 94 | if (allocSize < sz) { 95 | allocSize += sz; 96 | } 97 | _currentArena = 98 | (Arena *) SuperHeap::malloc(allocSize); 99 | if (_currentArena) { 100 | assert(_currentArena != nullptr); 101 | // _currentArena->arenaSpace = (char *) (_currentArena + 1); 102 | _currentPointer = (char *) (_currentArena + 1); 103 | _currentArena->nextArena = nullptr; 104 | _sizeRemaining = allocSize - sizeof(Arena); 105 | } else { 106 | _sizeRemaining = 0; 107 | } 108 | } 109 | 110 | class Arena { 111 | public: 112 | Arena() { 113 | static_assert((sizeof(Arena) % HL::MallocInfo::Alignment == 0), 114 | "Alignment must match Arena size."); 115 | } 116 | 117 | // alignas(8) char * arenaSpace; 118 | Arena * nextArena { nullptr }; 119 | }; 120 | 121 | /// Space left in the current arena. 122 | size_t _sizeRemaining; 123 | 124 | /// The current arena. 125 | Arena * _currentArena; 126 | 127 | /// The current bump pointer. 128 | char * _currentPointer; 129 | 130 | /// A linked list of past arenas. 131 | Arena * _pastArenas; 132 | 133 | /// Last size (which increases geometrically). 134 | float _lastChunkSize; 135 | }; 136 | 137 | #endif 138 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | orjson>=3.4.6 2 | -------------------------------------------------------------------------------- /test/regional.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void doIt() { 4 | const int num = 2000; 5 | volatile char * volatile arr[num]; 6 | for (int i = 0; i < num / 2; i++) { 7 | arr[i] = new char[16]; 8 | } 9 | for (int i = num / 2; i < num; i++) { 10 | arr[i] = new char[16]; // i / 100 + 1]; 11 | } 12 | for (int i = 0; i < num; i++) { 13 | delete [] arr[i]; 14 | } 15 | } 16 | 17 | int 18 | main() 19 | { 20 | int v; 21 | std::cout << &v << std::endl; 22 | for (int i = 0; i < 10; i++) { 23 | doIt(); 24 | } 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /testcheapen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "cheap.h" 3 | 4 | #ifndef CHEAPEN 5 | #define CHEAPEN 0 6 | #endif 7 | 8 | #ifdef TEST 9 | const auto NUMITERATIONS = 100; 10 | const auto NUMOBJS = 1000; 11 | const int NTHREADS = 4; 12 | #else 13 | const auto NUMITERATIONS = 1000; 14 | const auto NUMOBJS = 100000; 15 | const int NTHREADS = 4; // 32; 16 | #endif 17 | 18 | const auto OBJSIZE = 16; 19 | 20 | void doWork(volatile char** mem) 21 | { 22 | for (int i = 0; i < NUMITERATIONS; i++) { 23 | for (int j = 0; j < NUMOBJS; j++) { 24 | mem[j] = new char[OBJSIZE]; 25 | volatile char ch = mem[j][0]; 26 | // delete [] mem[j]; 27 | } 28 | #if 1 29 | for (int j = 0; j < NUMOBJS; j++) { 30 | delete [] mem[j]; 31 | } 32 | #endif 33 | } 34 | } 35 | 36 | void allocWorker() 37 | { 38 | char buf[NUMOBJS * OBJSIZE]; 39 | volatile char * mem[NUMOBJS]; 40 | // for (int i = 0; i < NUMITERATIONS; i++) { 41 | #if CHEAPEN 42 | // cheap::cheap reg(24); 43 | cheap::cheap reg(24); 44 | #endif 45 | doWork(mem); 46 | // } 47 | } 48 | 49 | int main() 50 | { 51 | #if TEST 52 | allocWorker(); 53 | #else 54 | std::thread * t[NTHREADS]; 55 | for (auto i = 0; i < NTHREADS; i++) { 56 | t[i] = new std::thread(allocWorker); 57 | } 58 | for (auto i = 0; i < NTHREADS; i++) { 59 | t[i]->join(); 60 | } 61 | #endif 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /testme.cpp: -------------------------------------------------------------------------------- 1 | #if defined(__APPLE__) 2 | #else 3 | #include 4 | #endif 5 | 6 | #include 7 | 8 | void foo() { 9 | //volatile auto* a = new std::vector; 10 | volatile auto* b = malloc(16); 11 | volatile auto* c = calloc(32, 16); 12 | // volatile auto* d = realloc((void*) b, 32); 13 | 14 | // delete a; 15 | free((void*) b); 16 | free((void*) c); 17 | } 18 | 19 | void bar() { 20 | foo(); 21 | } 22 | 23 | int main() { 24 | bar(); 25 | } 26 | --------------------------------------------------------------------------------