mirror of
https://github.com/wownero/RandomX.git
synced 2026-10-19 16:28:47 +02:00
Add an option to allocate cache, dataset and VMs all at once
+ Support for 1GB memory pages
This commit is contained in:
@@ -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
@@ -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
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
@@ -50,6 +50,9 @@ public:
|
||||
const void* getScratchpad() {
|
||||
return scratchpad;
|
||||
}
|
||||
void setScratchpad(void* memory) {
|
||||
scratchpad = (uint8_t*)memory;
|
||||
}
|
||||
const randomx::Program& getProgram()
|
||||
{
|
||||
return program;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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>;
|
||||
}
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
@@ -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>;
|
||||
}
|
||||
@@ -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" />
|
||||
|
||||
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user