Add an option to allocate cache, dataset and VMs all at once

+ Support for 1GB memory pages
This commit is contained in:
tevador
2019-12-05 23:05:13 +01:00
parent 30969c0e25
commit caa016434c
20 changed files with 553 additions and 84 deletions
+1
View File
@@ -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
+17 -1
View File
@@ -57,4 +57,20 @@ namespace randomx {
freePagedMemory(ptr, count);
};
}
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);
};
}
+10 -1
View File
@@ -43,4 +43,13 @@ namespace randomx {
static void freeMemory(void*, size_t);
};
}
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);
};
}
+164
View File
@@ -0,0 +1,164 @@
/*
Copyright (c) 2019, tevador <tevador@gmail.com>
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 <new>
#include <memory>
#include <cstdint>
#include <cassert>
#include <limits>
#include <iostream>
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<class T>
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<class T>
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<Container>(size);
addAlign<randomx_container_data>(size);
if (flags & RANDOMX_FLAG_FULL_MEM) {
addAlign<randomx_cache>(size);
if (flags & RANDOMX_FLAG_JIT) {
addAlign<randomx::JitCompiler>(size);
}
}
if ((flags & RANDOMX_FLAG_LARGE_PAGES) && !(flags & RANDOMX_FLAG_MONSTER_PAGES)) {
align = 2 * 1024 * 1024;
}
addAlign<randomx_dataset>(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<randomx::CompiledVmContainerHardAesSecure>(size);
}
else {
addAlign<randomx::CompiledVmContainerHardAes>(size);
}
}
else {
if (flags & RANDOMX_FLAG_SECURE) {
addAlign<randomx::CompiledVmContainerSecure>(size);
}
else {
addAlign<randomx::CompiledVmContainer>(size);
}
}
}
else {
if (flags & RANDOMX_FLAG_HARD_AES) {
addAlign<randomx::InterpretedVmContainerHardAes>(size);
}
else {
addAlign<randomx::InterpretedVmContainer>(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<class Allocator>
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<size_t>::max()) {
throw std::bad_alloc();
}
size_t bufferCapacity = bufferSize;
void* buffer = Allocator::allocMemory(bufferSize);
void* bufferHead = buffer;
auto* container = constructStatic<Container>(bufferHead, bufferCapacity);
auto* data = constructStatic<randomx_container_data>(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<MonsterPageAllocator>(randomx_flags flags, size_t vmCount);
template Container* Container::create<LargePageAllocator>(randomx_flags flags, size_t vmCount);
template Container* Container::create<DefaultAllocator>(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);
}
}
+70
View File
@@ -0,0 +1,70 @@
/*
Copyright (c) 2019, tevador <tevador@gmail.com>
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 <type_traits>
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<class Allocator>
static Container* create(randomx_flags flags, size_t vmCount);
void* alloc(size_t bytes, size_t align = sizeof(uintptr_t));
template<typename T>
void* alloc() {
return alloc(sizeof(T), alignof(T));
}
template<class T>
T* construct() {
return new(alloc<T>()) T();
}
template<class T>
T* construct(size_t numElements) {
return new(alloc(numElements * sizeof(T), alignof(T))) T[numElements];
}
void dealloc();
};
static_assert(std::is_standard_layout<Container>(), "Container must be a standard-layout struct");
}
+6
View File
@@ -68,6 +68,12 @@ namespace randomx {
template void deallocCache<DefaultAllocator>(randomx_cache* cache);
template void deallocCache<LargePageAllocator>(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;
+2
View File
@@ -86,6 +86,8 @@ namespace randomx {
template<class Allocator>
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);
+127 -38
View File
@@ -1,5 +1,6 @@
/*
Copyright (c) 2018-2019, tevador <tevador@gmail.com>
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 <cassert>
#include <limits>
@@ -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<randomx::DefaultAllocator>;
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<randomx::DefaultAllocator>;
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<randomx::LargePageAllocator>;
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<randomx::LargePageAllocator>;
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<randomx::LargePageAllocator>;
cache->memory = (uint8_t*)randomx::LargePageAllocator::allocMemory(randomx::CacheSize);
}
else {
cache->dealloc = &randomx::deallocCache<randomx::DefaultAllocator>;
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<randomx::MonsterPageAllocator>;
dataset->memory = (uint8_t*)randomx::MonsterPageAllocator::allocMemory(randomx::DatasetSize);
}
else if (flags & RANDOMX_FLAG_LARGE_PAGES) {
dataset->dealloc = &randomx::deallocDataset<randomx::LargePageAllocator>;
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<randomx::MonsterPageAllocator>(flags, vmCount);
}
else if (flags & RANDOMX_FLAG_LARGE_PAGES) {
align = 2 * 1024 * 1024;
container = randomx::Container::create<randomx::LargePageAllocator>(flags, vmCount);
}
else {
container = randomx::Container::create<randomx::DefaultAllocator>(flags, vmCount);
}
}
catch (std::exception& ex) {
return nullptr;
}
if (flags & RANDOMX_FLAG_FULL_MEM) {
auto cache = container->cache = container->construct<randomx_cache>();
if (flags & RANDOMX_FLAG_JIT) {
cache->jit = container->construct<randomx::JitCompiler>();
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<randomx_dataset>();
dataset->dealloc = &randomx::deallocDataset<randomx::NullAllocator>;
container->vmCount = vmCount;
container->vms = container->construct<randomx_vm*>(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<randomx::CompiledVmContainerHardAesSecure>();
}
else {
vm = container->construct<randomx::CompiledVmContainerHardAes>();
}
}
else {
if (flags & RANDOMX_FLAG_SECURE) {
vm = container->construct<randomx::CompiledVmContainerSecure>();
}
else {
vm = container->construct<randomx::CompiledVmContainer>();
}
}
}
else {
if (flags & RANDOMX_FLAG_HARD_AES) {
vm = container->construct<randomx::InterpretedVmContainerHardAes>();
}
else {
vm = container->construct<randomx::InterpretedVmContainer>();
}
}
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<randomx::Container*>(container);
cont->dealloc();
}
constexpr unsigned long DatasetItemCount = randomx::DatasetSize / RANDOMX_DATASET_ITEM_SIZE;
unsigned long randomx_dataset_item_count() {
+49 -6
View File
@@ -1,5 +1,6 @@
/*
Copyright (c) 2018-2019, tevador <tevador@gmail.com>
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)
}
+59 -19
View File
@@ -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<uint32_t>& 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<uint32_t>& 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<randomx_vm*> vms;
std::vector<std::thread> 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)
+2
View File
@@ -140,4 +140,6 @@ namespace randomx {
template class VmBase<AlignedAllocator<CacheLineSize>, true>;
template class VmBase<LargePageAllocator, false>;
template class VmBase<LargePageAllocator, true>;
template class VmBase<NullAllocator, false>;
template class VmBase<NullAllocator, true>;
}
+3
View File
@@ -50,6 +50,9 @@ public:
const void* getScratchpad() {
return scratchpad;
}
void setScratchpad(void* memory) {
scratchpad = (uint8_t*)memory;
}
const randomx::Program& getProgram()
{
return program;
+16
View File
@@ -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);
+3 -1
View File
@@ -29,8 +29,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include <cstddef>
#include <cstdint>
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);
+5
View File
@@ -77,4 +77,9 @@ namespace randomx {
template class CompiledVm<AlignedAllocator<CacheLineSize>, true, true>;
template class CompiledVm<LargePageAllocator, false, true>;
template class CompiledVm<LargePageAllocator, true, true>;
template class CompiledVm<NullAllocator, false, false>;
template class CompiledVm<NullAllocator, true, false>;
template class CompiledVm<NullAllocator, false, true>;
template class CompiledVm<NullAllocator, true, true>;
}
+5 -9
View File
@@ -40,15 +40,6 @@ namespace randomx {
template<class Allocator, bool softAes, bool secureJit>
class CompiledVm : public VmBase<Allocator, softAes> {
public:
void* operator new(size_t size) {
void* ptr = AlignedAllocator<CacheLineSize>::allocMemory(size);
if (ptr == nullptr)
throw std::bad_alloc();
return ptr;
}
void operator delete(void* ptr) {
AlignedAllocator<CacheLineSize>::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<AlignedAllocator<CacheLineSize>, false, true>;
using CompiledVmLargePageSecure = CompiledVm<LargePageAllocator, true, true>;
using CompiledVmLargePageHardAesSecure = CompiledVm<LargePageAllocator, false, true>;
using CompiledVmContainer = CompiledVm<NullAllocator, true, false>;
using CompiledVmContainerHardAes = CompiledVm<NullAllocator, false, false>;
using CompiledVmContainerSecure = CompiledVm<NullAllocator, true, true>;
using CompiledVmContainerHardAesSecure = CompiledVm<NullAllocator, false, true>;
}
+2
View File
@@ -128,4 +128,6 @@ namespace randomx {
template class InterpretedVm<AlignedAllocator<CacheLineSize>, true>;
template class InterpretedVm<LargePageAllocator, false>;
template class InterpretedVm<LargePageAllocator, true>;
template class InterpretedVm<NullAllocator, false>;
template class InterpretedVm<NullAllocator, true>;
}
+4 -9
View File
@@ -48,15 +48,7 @@ namespace randomx {
using VmBase<Allocator, softAes>::reg;
using VmBase<Allocator, softAes>::datasetPtr;
using VmBase<Allocator, softAes>::datasetOffset;
void* operator new(size_t size) {
void* ptr = AlignedAllocator<CacheLineSize>::allocMemory(size);
if (ptr == nullptr)
throw std::bad_alloc();
return ptr;
}
void operator delete(void* ptr) {
AlignedAllocator<CacheLineSize>::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<AlignedAllocator<CacheLineSize>, false>;
using InterpretedVmLargePage = InterpretedVm<LargePageAllocator, true>;
using InterpretedVmLargePageHardAes = InterpretedVm<LargePageAllocator, false>;
using InterpretedVmContainer = InterpretedVm<NullAllocator, true>;
using InterpretedVmContainerHardAes = InterpretedVm<NullAllocator, false>;
}
+2
View File
@@ -141,6 +141,7 @@ SET ERRORLEVEL = 0</Command>
<ClCompile Include="..\src\blake2_generator.cpp" />
<ClCompile Include="..\src\blake2\blake2b.c" />
<ClCompile Include="..\src\bytecode_machine.cpp" />
<ClCompile Include="..\src\container.cpp" />
<ClCompile Include="..\src\cpu.cpp" />
<ClCompile Include="..\src\vm_compiled_light.cpp" />
<ClCompile Include="..\src\vm_compiled.cpp" />
@@ -175,6 +176,7 @@ SET ERRORLEVEL = 0</Command>
<ClInclude Include="..\src\blake2_generator.hpp" />
<ClInclude Include="..\src\bytecode_machine.hpp" />
<ClInclude Include="..\src\common.hpp" />
<ClInclude Include="..\src\container.hpp" />
<ClInclude Include="..\src\cpu.hpp" />
<ClInclude Include="..\src\jit_compiler.hpp" />
<ClInclude Include="..\src\jit_compiler_a64.hpp" />
+6
View File
@@ -90,6 +90,9 @@
<ClCompile Include="..\src\cpu.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\container.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\src\argon2.h">
@@ -203,6 +206,9 @@
<ClInclude Include="..\src\cpu.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\container.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<MASM Include="..\src\jit_compiler_x86_static.asm">