diff --git a/CMakeLists.txt b/CMakeLists.txt index de0f818a..6c4f2809 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ src/argon2_ref.c src/argon2_ssse3.c src/argon2_avx2.c src/bytecode_machine.cpp +src/container.cpp src/cpu.cpp src/dataset.cpp src/soft_aes.cpp diff --git a/src/allocator.cpp b/src/allocator.cpp index 4c6d86e0..7adf0f05 100644 --- a/src/allocator.cpp +++ b/src/allocator.cpp @@ -57,4 +57,20 @@ namespace randomx { freePagedMemory(ptr, count); }; -} \ No newline at end of file + void* NullAllocator::allocMemory(size_t count) { + return nullptr; + } + + void NullAllocator::freeMemory(void* ptr, size_t count) { + + }; + + void* MonsterPageAllocator::allocMemory(size_t count) { + return allocMonsterPagesMemory(count); + } + + void MonsterPageAllocator::freeMemory(void* ptr, size_t count) { + freePagedMemory(ptr, count); + }; + +} diff --git a/src/allocator.hpp b/src/allocator.hpp index d7aa3f95..32fca53e 100644 --- a/src/allocator.hpp +++ b/src/allocator.hpp @@ -43,4 +43,13 @@ namespace randomx { static void freeMemory(void*, size_t); }; -} \ No newline at end of file + struct NullAllocator { + static void* allocMemory(size_t); + static void freeMemory(void*, size_t); + }; + + struct MonsterPageAllocator { + static void* allocMemory(size_t); + static void freeMemory(void*, size_t); + }; +} diff --git a/src/container.cpp b/src/container.cpp new file mode 100644 index 00000000..b71b0908 --- /dev/null +++ b/src/container.cpp @@ -0,0 +1,164 @@ +/* +Copyright (c) 2019, tevador + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "container.hpp" +#include "allocator.hpp" +#include "virtual_machine.hpp" +#include "virtual_memory.hpp" +#include "dataset.hpp" +#include "vm_interpreted.hpp" +#include "vm_compiled.hpp" +#include +#include +#include +#include +#include +#include + +namespace randomx { + + static void* allocStatic(size_t bytes, size_t align, void*& bufferHead, size_t& bufferCapacity) { + auto ptr = std::align(align, bytes, bufferHead, bufferCapacity); + assert(ptr != nullptr); + void* memory = bufferHead; + bufferHead = (uint8_t*)bufferHead + bytes; + bufferCapacity -= bytes; + //std::cout << "Container alloc: " << bytes << ", remaining: " << bufferCapacity << std::endl; + return memory; + } + + template + static T* constructStatic(void*& bufferHead, size_t& bufferCapacity) { + return new(allocStatic(sizeof(T), alignof(T), bufferHead, bufferCapacity)) T(); + } + + static void addAlign(uint64_t& size, size_t add, size_t align) { + size = alignSize(size, align); + size += add; + } + + template + static void addAlign(uint64_t& size) { + addAlign(size, sizeof(T), alignof(T)); + } + + static uint64_t calculateSize(randomx_flags flags, size_t vmCount) { + uint64_t size = 0; + uint64_t align = randomx::CacheLineSize; + addAlign(size); + addAlign(size); + if (flags & RANDOMX_FLAG_FULL_MEM) { + addAlign(size); + if (flags & RANDOMX_FLAG_JIT) { + addAlign(size); + } + } + if ((flags & RANDOMX_FLAG_LARGE_PAGES) && !(flags & RANDOMX_FLAG_MONSTER_PAGES)) { + align = 2 * 1024 * 1024; + } + addAlign(size); + addAlign(size, sizeof(uintptr_t) * vmCount, alignof(uintptr_t)); + for (size_t i = 0; i < vmCount; ++i) { + randomx_vm* vm; + if (flags & RANDOMX_FLAG_JIT) { + if (flags & RANDOMX_FLAG_HARD_AES) { + if (flags & RANDOMX_FLAG_SECURE) { + addAlign(size); + } + else { + addAlign(size); + } + } + else { + if (flags & RANDOMX_FLAG_SECURE) { + addAlign(size); + } + else { + addAlign(size); + } + } + } + else { + if (flags & RANDOMX_FLAG_HARD_AES) { + addAlign(size); + } + else { + addAlign(size); + } + } + } + for (size_t i = 0; i < vmCount; ++i) { + addAlign(size, randomx::ScratchpadSize, align); + } + if (flags & RANDOMX_FLAG_FULL_MEM) { + addAlign(size, randomx::CacheSize, align); + } + addAlign(size, randomx::DatasetSize, align); + return size; + } + + template + Container* Container::create(randomx_flags flags, size_t vmCount) { + uint64_t bufferSize = calculateSize(flags, vmCount); + //std::cout << "Container size: " << bufferSize << std::endl; + if (bufferSize > std::numeric_limits::max()) { + throw std::bad_alloc(); + } + size_t bufferCapacity = bufferSize; + void* buffer = Allocator::allocMemory(bufferSize); + void* bufferHead = buffer; + auto* container = constructStatic(bufferHead, bufferCapacity); + auto* data = constructStatic(bufferHead, bufferCapacity); + data->buffer = buffer; + data->bufferSize = bufferSize; + data->bufferHead = bufferHead; + data->bufferCapacity = bufferCapacity; + data->dealloc = &Allocator::freeMemory; + container->data = data; + return container; + } + + template Container* Container::create(randomx_flags flags, size_t vmCount); + template Container* Container::create(randomx_flags flags, size_t vmCount); + template Container* Container::create(randomx_flags flags, size_t vmCount); + + void* Container::alloc(size_t bytes, size_t align) { + return allocStatic(bytes, align, data->bufferHead, data->bufferCapacity); + } + + void Container::dealloc() { + if (cache != nullptr) { + cache->dealloc(cache); + } + for (size_t i = 0; i < vmCount; ++i) { + vms[i]->~randomx_vm(); + } + data->dealloc(data->buffer, data->bufferSize); + } + +} diff --git a/src/container.hpp b/src/container.hpp new file mode 100644 index 00000000..608a0be1 --- /dev/null +++ b/src/container.hpp @@ -0,0 +1,70 @@ +/* +Copyright (c) 2019, tevador + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#pragma once + +#include "randomx.h" +#include + +namespace randomx { + + typedef void(DeallocFunc)(void*, size_t); + +} + +struct randomx_container_data { + void* buffer; + void* bufferHead; + size_t bufferSize; + size_t bufferCapacity; + randomx::DeallocFunc* dealloc; +}; + +namespace randomx { + + struct Container : public randomx_container { + template + static Container* create(randomx_flags flags, size_t vmCount); + void* alloc(size_t bytes, size_t align = sizeof(uintptr_t)); + template + void* alloc() { + return alloc(sizeof(T), alignof(T)); + } + template + T* construct() { + return new(alloc()) T(); + } + template + T* construct(size_t numElements) { + return new(alloc(numElements * sizeof(T), alignof(T))) T[numElements]; + } + void dealloc(); + }; + + static_assert(std::is_standard_layout(), "Container must be a standard-layout struct"); +} diff --git a/src/dataset.cpp b/src/dataset.cpp index 675c5abc..7ab957f5 100644 --- a/src/dataset.cpp +++ b/src/dataset.cpp @@ -68,6 +68,12 @@ namespace randomx { template void deallocCache(randomx_cache* cache); template void deallocCache(randomx_cache* cache); + void deallocCacheContainer(randomx_cache* cache) { + if (cache->jit != nullptr) { + cache->jit->~JitCompiler(); + } + } + void initCache(randomx_cache* cache, const void* key, size_t keySize) { uint32_t memory_blocks, segment_length; argon2_instance_t instance; diff --git a/src/dataset.hpp b/src/dataset.hpp index d01911f9..74e7f713 100644 --- a/src/dataset.hpp +++ b/src/dataset.hpp @@ -86,6 +86,8 @@ namespace randomx { template void deallocCache(randomx_cache* cache); + void deallocCacheContainer(randomx_cache* cache); + void initCache(randomx_cache*, const void*, size_t); void initCacheCompile(randomx_cache*, const void*, size_t); void initDatasetItem(randomx_cache* cache, uint8_t* out, uint64_t blockNumber); diff --git a/src/randomx.cpp b/src/randomx.cpp index 898425c3..846c5575 100644 --- a/src/randomx.cpp +++ b/src/randomx.cpp @@ -1,5 +1,6 @@ /* Copyright (c) 2018-2019, tevador +Copyright (c) 2019, The Monero Project All rights reserved. @@ -34,6 +35,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "vm_compiled_light.hpp" #include "blake2/blake2.h" #include "cpu.hpp" +#include "container.hpp" #include #include @@ -60,50 +62,33 @@ extern "C" { } randomx_cache *randomx_alloc_cache(randomx_flags flags) { - randomx_cache *cache = nullptr; auto impl = randomx::selectArgonImpl(flags); if (impl == nullptr) { - return cache; + return nullptr; } + randomx_cache* cache; + try { cache = new randomx_cache(); cache->argonImpl = impl; - switch ((int)(flags & (RANDOMX_FLAG_JIT | RANDOMX_FLAG_LARGE_PAGES))) { - case RANDOMX_FLAG_DEFAULT: - cache->dealloc = &randomx::deallocCache; - cache->jit = nullptr; - cache->initialize = &randomx::initCache; - cache->datasetInit = &randomx::initDataset; - cache->memory = (uint8_t*)randomx::DefaultAllocator::allocMemory(randomx::CacheSize); - break; - - case RANDOMX_FLAG_JIT: - cache->dealloc = &randomx::deallocCache; - cache->jit = new randomx::JitCompiler(); - cache->initialize = &randomx::initCacheCompile; - cache->datasetInit = cache->jit->getDatasetInitFunc(); - cache->memory = (uint8_t*)randomx::DefaultAllocator::allocMemory(randomx::CacheSize); - break; - - case RANDOMX_FLAG_LARGE_PAGES: - cache->dealloc = &randomx::deallocCache; - cache->jit = nullptr; - cache->initialize = &randomx::initCache; - cache->datasetInit = &randomx::initDataset; - cache->memory = (uint8_t*)randomx::LargePageAllocator::allocMemory(randomx::CacheSize); - break; - - case RANDOMX_FLAG_JIT | RANDOMX_FLAG_LARGE_PAGES: - cache->dealloc = &randomx::deallocCache; - cache->jit = new randomx::JitCompiler(); - cache->initialize = &randomx::initCacheCompile; - cache->datasetInit = cache->jit->getDatasetInitFunc(); - cache->memory = (uint8_t*)randomx::LargePageAllocator::allocMemory(randomx::CacheSize); - break; - - default: - UNREACHABLE; + if (flags & RANDOMX_FLAG_JIT) { + cache->jit = new randomx::JitCompiler(); + cache->initialize = &randomx::initCacheCompile; + cache->datasetInit = cache->jit->getDatasetInitFunc(); + } + else { + cache->jit = nullptr; + cache->initialize = &randomx::initCache; + cache->datasetInit = &randomx::initDataset; + } + if (flags & RANDOMX_FLAG_LARGE_PAGES) { + cache->dealloc = &randomx::deallocCache; + cache->memory = (uint8_t*)randomx::LargePageAllocator::allocMemory(randomx::CacheSize); + } + else { + cache->dealloc = &randomx::deallocCache; + cache->memory = (uint8_t*)randomx::DefaultAllocator::allocMemory(randomx::CacheSize); } } catch (std::exception &ex) { @@ -146,7 +131,11 @@ extern "C" { try { dataset = new randomx_dataset(); - if (flags & RANDOMX_FLAG_LARGE_PAGES) { + if (flags & RANDOMX_FLAG_MONSTER_PAGES) { + dataset->dealloc = &randomx::deallocDataset; + dataset->memory = (uint8_t*)randomx::MonsterPageAllocator::allocMemory(randomx::DatasetSize); + } + else if (flags & RANDOMX_FLAG_LARGE_PAGES) { dataset->dealloc = &randomx::deallocDataset; dataset->memory = (uint8_t*)randomx::LargePageAllocator::allocMemory(randomx::DatasetSize); } @@ -165,6 +154,106 @@ extern "C" { return dataset; } + randomx_container* randomx_alloc_container(randomx_flags flags, size_t vmCount) { + assert(vmCount > 0); + size_t align = randomx::CacheLineSize; + randomx_argon2_impl* impl; + if (flags & RANDOMX_FLAG_FULL_MEM) { + impl = randomx::selectArgonImpl(flags); + if (impl == nullptr) { + return nullptr; + } + } + if ((flags & RANDOMX_FLAG_JIT) && !RANDOMX_HAVE_COMPILER) { + return nullptr; + } + randomx::Container* container; + try { + if (flags & RANDOMX_FLAG_MONSTER_PAGES) { + container = randomx::Container::create(flags, vmCount); + } + else if (flags & RANDOMX_FLAG_LARGE_PAGES) { + align = 2 * 1024 * 1024; + container = randomx::Container::create(flags, vmCount); + } + else { + container = randomx::Container::create(flags, vmCount); + } + } + catch (std::exception& ex) { + return nullptr; + } + if (flags & RANDOMX_FLAG_FULL_MEM) { + auto cache = container->cache = container->construct(); + if (flags & RANDOMX_FLAG_JIT) { + cache->jit = container->construct(); + cache->initialize = &randomx::initCacheCompile; + cache->datasetInit = cache->jit->getDatasetInitFunc(); + } + else { + cache->jit = nullptr; + cache->initialize = &randomx::initCache; + cache->datasetInit = &randomx::initDataset; + } + cache->dealloc = &randomx::deallocCacheContainer; + cache->argonImpl = impl; + } + else { + container->cache = nullptr; + } + auto dataset = container->dataset = container->construct(); + dataset->dealloc = &randomx::deallocDataset; + container->vmCount = vmCount; + container->vms = container->construct(vmCount); + for (size_t i = 0; i < vmCount; ++i) { + randomx_vm* vm; + if (flags & RANDOMX_FLAG_JIT) { + if (flags & RANDOMX_FLAG_HARD_AES) { + if (flags & RANDOMX_FLAG_SECURE) { + vm = container->construct(); + } + else { + vm = container->construct(); + } + } + else { + if (flags & RANDOMX_FLAG_SECURE) { + vm = container->construct(); + } + else { + vm = container->construct(); + } + } + } + else { + if (flags & RANDOMX_FLAG_HARD_AES) { + vm = container->construct(); + } + else { + vm = container->construct(); + } + } + container->vms[i] = vm; + } + for (size_t i = 0; i < vmCount; ++i) { + container->vms[i]->setScratchpad(container->alloc(randomx::ScratchpadSize, align)); + } + if (container->cache != nullptr) { + container->cache->memory = (uint8_t*)container->alloc(randomx::CacheSize, align); + } + container->dataset->memory = (uint8_t*)container->alloc(randomx::DatasetSize, align); + for (size_t i = 0; i < vmCount; ++i) { + container->vms[i]->setDataset(dataset); + } + return container; + } + + void randomx_release_container(randomx_container* container) { + assert(container != nullptr); + randomx::Container* cont = reinterpret_cast(container); + cont->dealloc(); + } + constexpr unsigned long DatasetItemCount = randomx::DatasetSize / RANDOMX_DATASET_ITEM_SIZE; unsigned long randomx_dataset_item_count() { diff --git a/src/randomx.h b/src/randomx.h index d582cf0f..30c2faa0 100644 --- a/src/randomx.h +++ b/src/randomx.h @@ -1,5 +1,6 @@ /* Copyright (c) 2018-2019, tevador +Copyright (c) 2019, The Monero Project All rights reserved. @@ -48,13 +49,22 @@ typedef enum { RANDOMX_FLAG_SECURE = 16, RANDOMX_FLAG_ARGON2_SSSE3 = 32, RANDOMX_FLAG_ARGON2_AVX2 = 64, - RANDOMX_FLAG_ARGON2 = 96 + RANDOMX_FLAG_ARGON2 = 96, + RANDOMX_FLAG_MONSTER_PAGES = 128 } randomx_flags; typedef struct randomx_dataset randomx_dataset; typedef struct randomx_cache randomx_cache; typedef struct randomx_vm randomx_vm; +typedef struct randomx_container_data randomx_container_data; +typedef struct randomx_container { + randomx_cache* cache; + randomx_dataset* dataset; + randomx_vm** vms; + size_t vmCount; + randomx_container_data* data; /* private */ +} randomx_container; #if defined(__cplusplus) @@ -105,7 +115,7 @@ RANDOMX_EXPORT randomx_flags randomx_get_flags(void); * Returns NULL if: * (1) memory allocation fails * (2) the RANDOMX_FLAG_JIT is set and JIT compilation is not supported on the current platform - * (3) an invalid or unsupported RANDOMX_FLAG_ARGON2 value is set + * (3) an unsupported RANDOMX_FLAG_ARGON2 value is set */ RANDOMX_EXPORT randomx_cache *randomx_alloc_cache(randomx_flags flags); @@ -124,13 +134,14 @@ RANDOMX_EXPORT void randomx_init_cache(randomx_cache *cache, const void *key, si * * @param cache is a pointer to a previously allocated randomx_cache structure. */ -RANDOMX_EXPORT void randomx_release_cache(randomx_cache* cache); +RANDOMX_EXPORT void randomx_release_cache(randomx_cache *cache); /** * Creates a randomx_dataset structure and allocates memory for RandomX Dataset. * - * @param flags is the initialization flags. Only one flag is supported (can be set or not set): + * @param flags is the initialization flags. Two flags are supported (can be set or not set): * RANDOMX_FLAG_LARGE_PAGES - allocate memory in large pages + * RANDOMX_FLAG_MONSTER_PAGES - allocate memory using 1GB memory pages * * @return Pointer to an allocated randomx_dataset structure. * NULL is returned if memory allocation fails. @@ -228,6 +239,38 @@ RANDOMX_EXPORT void randomx_vm_set_dataset(randomx_vm *machine, randomx_dataset */ RANDOMX_EXPORT void randomx_destroy_vm(randomx_vm *machine); +/** + * Allocates a container that includes a randomx_dataset structure, one or more randomx_vm + * structures and optionally a randomx_cache structure. All memory is allocated in + * a single contiguous memory buffer. + * + * @param flags is a combination of flags used to create structures inside the container. + * The following flags set the properties of the container itself: + * RANDOMX_FLAG_FULL_MEM - if set, the container will include a randomx_cache structure + * RANDOMX_FLAG_LARGE_PAGES - the container will be allocated using large pages + * RANDOMX_FLAG_MONSTER_PAGES - the container will be allocated using 1GB memory pages + * + * The remaining flags have the same meaning as the flags parameter of randomx_alloc_cache, + * randomx_alloc_dataset and randomx_create_vm functions. Virtual machines in the container + * always use the full dataset. + * + * @param vmCount is the number of virtual machines to create inside the container. + * + * @return Pointer to an allocated randomx_container structure. + * Returns NULL if: + * (1) memory allocation fails + * (2) the RANDOMX_FLAG_JIT is set and JIT compilation is not supported on the current platform + * (3) the RANDOMX_FLAG_FULL_MEM is set and an unsupported RANDOMX_FLAG_ARGON2 value is set +*/ +RANDOMX_EXPORT randomx_container* randomx_alloc_container(randomx_flags flags, size_t vmCount); + +/** + * Releases all memory occupied by the randomx_container structure. + * + * @param machine is a pointer to a randomx_container structure returned from randomx_alloc_container. +*/ +RANDOMX_EXPORT void randomx_release_container(randomx_container *container); + /** * Calculates a RandomX hash value. * @@ -252,8 +295,8 @@ RANDOMX_EXPORT void randomx_calculate_hash(randomx_vm *machine, const void *inpu * @param output is a pointer to memory where the hash will be stored. Must not * be NULL and at least RANDOMX_HASH_SIZE bytes must be available for writing. */ -RANDOMX_EXPORT void randomx_calculate_hash_first(randomx_vm* machine, const void* input, size_t inputSize); -RANDOMX_EXPORT void randomx_calculate_hash_next(randomx_vm* machine, const void* nextInput, size_t nextInputSize, void* output); +RANDOMX_EXPORT void randomx_calculate_hash_first(randomx_vm *machine, const void *input, size_t inputSize); +RANDOMX_EXPORT void randomx_calculate_hash_next(randomx_vm *machine, const void *nextInput, size_t nextInputSize, void *output); #if defined(__cplusplus) } diff --git a/src/tests/benchmark.cpp b/src/tests/benchmark.cpp index 47cd0264..341546ef 100644 --- a/src/tests/benchmark.cpp +++ b/src/tests/benchmark.cpp @@ -94,6 +94,7 @@ void printUsage(const char* executable) { std::cout << " --ssse3 use optimized Argon2 for SSSE3 CPUs" << std::endl; std::cout << " --avx2 use optimized Argon2 for AVX2 CPUs" << std::endl; std::cout << " --auto select the best options for the current CPU" << std::endl; + std::cout << " --container allocate all memory at once" << std::endl; } struct MemoryException : public std::exception { @@ -108,6 +109,11 @@ struct DatasetAllocException : public MemoryException { return "Dataset allocation failed"; } }; +struct ContainerAllocException : public MemoryException { + const char* what() const throw () { + return "Container allocation failed"; + } +}; void mine(randomx_vm* vm, std::atomic& atomicNonce, AtomicHash& result, uint32_t noncesCount, int thread, int cpuid=-1) { if (cpuid >= 0) { @@ -134,7 +140,7 @@ void mine(randomx_vm* vm, std::atomic& atomicNonce, AtomicHash& result } int main(int argc, char** argv) { - bool softAes, miningMode, verificationMode, help, largePages, jit, secure, ssse3, avx2, autoFlags; + bool softAes, miningMode, verificationMode, help, largePages, jit, secure, ssse3, avx2, autoFlags, useContainer, monsterPages; int noncesCount, threadCount, initThreadCount; uint64_t threadAffinity; int32_t seedValue; @@ -158,10 +164,12 @@ int main(int argc, char** argv) { readOption("--ssse3", argc, argv, ssse3); readOption("--avx2", argc, argv, avx2); readOption("--auto", argc, argv, autoFlags); + readOption("--container", argc, argv, useContainer); + readOption("--monsterPages", argc, argv, monsterPages); store32(&seed, seedValue); - std::cout << "RandomX benchmark v1.1.7" << std::endl; + std::cout << "RandomX benchmark v1.2.0" << std::endl; if (help) { printUsage(argv[0]); @@ -178,9 +186,10 @@ int main(int argc, char** argv) { AtomicHash result; std::vector vms; std::vector threads; - randomx_dataset* dataset; - randomx_cache* cache; + randomx_dataset* dataset = nullptr; + randomx_cache* cache = nullptr; randomx_flags flags; + randomx_container* container = nullptr; if (autoFlags) { initThreadCount = std::thread::hardware_concurrency(); @@ -208,6 +217,9 @@ int main(int argc, char** argv) { if (largePages) { flags |= RANDOMX_FLAG_LARGE_PAGES; } + if (monsterPages) { + flags |= RANDOMX_FLAG_MONSTER_PAGES; + } if (miningMode) { flags |= RANDOMX_FLAG_FULL_MEM; } @@ -252,7 +264,10 @@ int main(int argc, char** argv) { std::cout << " - software AES mode" << std::endl; } - if (flags & RANDOMX_FLAG_LARGE_PAGES) { + if (miningMode && (flags & RANDOMX_FLAG_MONSTER_PAGES)) { + std::cout << " - monster pages mode" << std::endl; + } + else if (flags & RANDOMX_FLAG_LARGE_PAGES) { std::cout << " - large pages mode" << std::endl; } else { @@ -280,15 +295,27 @@ int main(int argc, char** argv) { } Stopwatch sw(true); - cache = randomx_alloc_cache(flags); - if (cache == nullptr) { - throw CacheAllocException(); + if (miningMode && useContainer) { + container = randomx_alloc_container(flags, threadCount); + if (container == nullptr) { + throw ContainerAllocException(); + } + cache = container->cache; + dataset = container->dataset; + } + else { + cache = randomx_alloc_cache(flags); + if (cache == nullptr) { + throw CacheAllocException(); + } } randomx_init_cache(cache, &seed, sizeof(seed)); if (miningMode) { - dataset = randomx_alloc_dataset(flags); if (dataset == nullptr) { - throw DatasetAllocException(); + dataset = randomx_alloc_dataset(flags); + if (dataset == nullptr) { + throw DatasetAllocException(); + } } uint32_t datasetItemCount = randomx_dataset_item_count(); if (initThreadCount > 1) { @@ -307,14 +334,22 @@ int main(int argc, char** argv) { else { randomx_init_dataset(dataset, cache, 0, datasetItemCount); } - randomx_release_cache(cache); - cache = nullptr; + if (container == nullptr) { + randomx_release_cache(cache); + cache = nullptr; + } threads.clear(); } std::cout << "Memory initialized in " << sw.getElapsed() << " s" << std::endl; std::cout << "Initializing " << threadCount << " virtual machine(s) ..." << std::endl; for (int i = 0; i < threadCount; ++i) { - randomx_vm *vm = randomx_create_vm(flags, cache, dataset); + randomx_vm* vm; + if (container != nullptr) { + vm = container->vms[i]; + } + else { + vm = randomx_create_vm(flags, cache, dataset); + } if (vm == nullptr) { if ((flags & RANDOMX_FLAG_HARD_AES)) { throw std::runtime_error("Cannot create VM with the selected options. Try using --softAes"); @@ -344,12 +379,17 @@ int main(int argc, char** argv) { } double elapsed = sw.getElapsed(); - for (unsigned i = 0; i < vms.size(); ++i) - randomx_destroy_vm(vms[i]); - if (miningMode) - randomx_release_dataset(dataset); - else - randomx_release_cache(cache); + if (container != nullptr) { + randomx_release_container(container); + } + else { + for (unsigned i = 0; i < vms.size(); ++i) + randomx_destroy_vm(vms[i]); + if (miningMode) + randomx_release_dataset(dataset); + else + randomx_release_cache(cache); + } std::cout << "Calculated result: "; result.print(std::cout); if (noncesCount == 1000 && seedValue == 0) diff --git a/src/virtual_machine.cpp b/src/virtual_machine.cpp index 2d5d2bea..6a2b2ffb 100644 --- a/src/virtual_machine.cpp +++ b/src/virtual_machine.cpp @@ -140,4 +140,6 @@ namespace randomx { template class VmBase, true>; template class VmBase; template class VmBase; + template class VmBase; + template class VmBase; } \ No newline at end of file diff --git a/src/virtual_machine.hpp b/src/virtual_machine.hpp index d72a9181..164c8ee1 100644 --- a/src/virtual_machine.hpp +++ b/src/virtual_machine.hpp @@ -50,6 +50,9 @@ class randomx_vm { const void* getScratchpad() { return scratchpad; } + void setScratchpad(void* memory) { + scratchpad = (uint8_t*)memory; + } const randomx::Program& getProgram() { return program; diff --git a/src/virtual_memory.cpp b/src/virtual_memory.cpp index fc46ae9b..c634bab2 100644 --- a/src/virtual_memory.cpp +++ b/src/virtual_memory.cpp @@ -152,6 +152,22 @@ void* allocLargePagesMemory(std::size_t bytes) { return mem; } +#if !defined(MAP_HUGE_1GB) && defined(MAP_HUGE_SHIFT) +#define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT) +#endif + +void* allocMonsterPagesMemory(std::size_t bytes) { + void* mem; +#ifdef MAP_HUGE_1GB + mem = mmap(nullptr, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE | MAP_HUGE_1GB, -1, 0); + if (mem == MAP_FAILED) + throw std::runtime_error("allocMonsterPagesMemory - mmap failed"); +#else + throw std::runtime_error("allocMonsterPagesMemory - Monster pages are not supported"); +#endif + return mem; +} + void freePagedMemory(void* ptr, std::size_t bytes) { #if defined(_WIN32) || defined(__CYGWIN__) VirtualFree(ptr, 0, MEM_RELEASE); diff --git a/src/virtual_memory.hpp b/src/virtual_memory.hpp index 9e8bc29a..98af4dbb 100644 --- a/src/virtual_memory.hpp +++ b/src/virtual_memory.hpp @@ -29,8 +29,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include +#include -constexpr std::size_t alignSize(std::size_t pos, std::size_t align) { +constexpr uint64_t alignSize(uint64_t pos, uint64_t align) { return ((pos - 1) / align + 1) * align; } @@ -39,4 +40,5 @@ void setPagesRW(void*, std::size_t); void setPagesRX(void*, std::size_t); void setPagesRWX(void*, std::size_t); void* allocLargePagesMemory(std::size_t); +void* allocMonsterPagesMemory(std::size_t); void freePagedMemory(void*, std::size_t); diff --git a/src/vm_compiled.cpp b/src/vm_compiled.cpp index 060abec3..183cd763 100644 --- a/src/vm_compiled.cpp +++ b/src/vm_compiled.cpp @@ -77,4 +77,9 @@ namespace randomx { template class CompiledVm, true, true>; template class CompiledVm; template class CompiledVm; + + template class CompiledVm; + template class CompiledVm; + template class CompiledVm; + template class CompiledVm; } \ No newline at end of file diff --git a/src/vm_compiled.hpp b/src/vm_compiled.hpp index f7ceb0a6..3178a17f 100644 --- a/src/vm_compiled.hpp +++ b/src/vm_compiled.hpp @@ -40,15 +40,6 @@ namespace randomx { template class CompiledVm : public VmBase { public: - void* operator new(size_t size) { - void* ptr = AlignedAllocator::allocMemory(size); - if (ptr == nullptr) - throw std::bad_alloc(); - return ptr; - } - void operator delete(void* ptr) { - AlignedAllocator::freeMemory(ptr, sizeof(CompiledVm)); - } CompiledVm(); void setDataset(randomx_dataset* dataset) override; void run(void* seed) override; @@ -74,4 +65,9 @@ namespace randomx { using CompiledVmHardAesSecure = CompiledVm, false, true>; using CompiledVmLargePageSecure = CompiledVm; using CompiledVmLargePageHardAesSecure = CompiledVm; + + using CompiledVmContainer = CompiledVm; + using CompiledVmContainerHardAes = CompiledVm; + using CompiledVmContainerSecure = CompiledVm; + using CompiledVmContainerHardAesSecure = CompiledVm; } diff --git a/src/vm_interpreted.cpp b/src/vm_interpreted.cpp index 64243c3e..cd85bd33 100644 --- a/src/vm_interpreted.cpp +++ b/src/vm_interpreted.cpp @@ -128,4 +128,6 @@ namespace randomx { template class InterpretedVm, true>; template class InterpretedVm; template class InterpretedVm; + template class InterpretedVm; + template class InterpretedVm; } \ No newline at end of file diff --git a/src/vm_interpreted.hpp b/src/vm_interpreted.hpp index 2fac2edd..699b3ef5 100644 --- a/src/vm_interpreted.hpp +++ b/src/vm_interpreted.hpp @@ -48,15 +48,7 @@ namespace randomx { using VmBase::reg; using VmBase::datasetPtr; using VmBase::datasetOffset; - void* operator new(size_t size) { - void* ptr = AlignedAllocator::allocMemory(size); - if (ptr == nullptr) - throw std::bad_alloc(); - return ptr; - } - void operator delete(void* ptr) { - AlignedAllocator::freeMemory(ptr, sizeof(InterpretedVm)); - } + void run(void* seed) override; void setDataset(randomx_dataset* dataset) override; protected: @@ -72,4 +64,7 @@ namespace randomx { using InterpretedVmHardAes = InterpretedVm, false>; using InterpretedVmLargePage = InterpretedVm; using InterpretedVmLargePageHardAes = InterpretedVm; + + using InterpretedVmContainer = InterpretedVm; + using InterpretedVmContainerHardAes = InterpretedVm; } \ No newline at end of file diff --git a/vcxproj/randomx.vcxproj b/vcxproj/randomx.vcxproj index bfde9f7d..ff92993d 100644 --- a/vcxproj/randomx.vcxproj +++ b/vcxproj/randomx.vcxproj @@ -141,6 +141,7 @@ SET ERRORLEVEL = 0 + @@ -175,6 +176,7 @@ SET ERRORLEVEL = 0 + diff --git a/vcxproj/randomx.vcxproj.filters b/vcxproj/randomx.vcxproj.filters index eb4462a5..07827cc5 100644 --- a/vcxproj/randomx.vcxproj.filters +++ b/vcxproj/randomx.vcxproj.filters @@ -90,6 +90,9 @@ Source Files + + Source Files + @@ -203,6 +206,9 @@ Header Files + + Header Files +