Skip to content

Commit

Permalink
Updated documentation and test vectors
Browse files Browse the repository at this point in the history
Added AesGenerator1R test
Added benchmark hints if large pages fail
  • Loading branch information
tevador committed Jun 22, 2019
1 parent 91cd35f commit 8282413
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 23 deletions.
6 changes: 5 additions & 1 deletion doc/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,11 @@ The IADD_RS instruction utilizes the address calculation logic of CPUs and can b

Because integer division is not fully pipelined in CPUs and can be made faster in ASICs, the IMUL_RCP instruction requires only one division per program to calculate the reciprocal. This forces an ASIC to include a hardware divider without giving them a performance advantage during program execution.

#### 2.4.3 ISWAP_R
#### 2.4.3 IROR_R/IROL_R

Rotation instructions are split between rotate right and rotate left with a 4:1 ratio. Rotate right has a higher frequency because some architecures (like ARM) don't support rotate left natively (it must be emulated using rotate right).

#### 2.4.4 ISWAP_R

This instruction can be executed efficiently by CPUs that support register renaming/move elimination.

Expand Down
12 changes: 6 additions & 6 deletions doc/specs.md
Original file line number Diff line number Diff line change
Expand Up @@ -567,8 +567,8 @@ For integer instructions, the destination is always an integer register (registe
|2/256|INEG_R|R|-|-|`dst = -dst`|
|15/256|IXOR_R|R|R|`src = imm32`|`dst = dst ^ src`|
|5/256|IXOR_M|R|R|`src = 0`|`dst = dst ^ [mem]`|
|10/256|IROR_R|R|R|`src = imm32`|`dst = dst >>> src`|
|0/256|IROL_R|R|R|`src = imm32`|`dst = dst <<< src`|
|8/256|IROR_R|R|R|`src = imm32`|`dst = dst >>> src`|
|2/256|IROL_R|R|R|`src = imm32`|`dst = dst <<< src`|
|4/256|ISWAP_R|R|R|`src = dst`|`temp = src; src = dst; dst = temp`|

#### 5.2.1 IADD_RS
Expand Down Expand Up @@ -616,13 +616,13 @@ All floating point operations are rounded according to the current value of the

|frequency|instruction|dst|src|operation|
|-|-|-|-|-|
|8/256|FSWAP_R|F+E|-|`(dst0, dst1) = (dst1, dst0)`|
|20/256|FADD_R|F|A|`(dst0, dst1) = (dst0 + src0, dst1 + src1)`|
|4/256|FSWAP_R|F+E|-|`(dst0, dst1) = (dst1, dst0)`|
|16/256|FADD_R|F|A|`(dst0, dst1) = (dst0 + src0, dst1 + src1)`|
|5/256|FADD_M|F|R|`(dst0, dst1) = (dst0 + [mem][0], dst1 + [mem][1])`|
|20/256|FSUB_R|F|A|`(dst0, dst1) = (dst0 - src0, dst1 - src1)`|
|16/256|FSUB_R|F|A|`(dst0, dst1) = (dst0 - src0, dst1 - src1)`|
|5/256|FSUB_M|F|R|`(dst0, dst1) = (dst0 - [mem][0], dst1 - [mem][1])`|
|6/256|FSCAL_R|F|-|<code>(dst0, dst1) = (-2<sup>x0</sup> * dst0, -2<sup>x1</sup> * dst1)</code>|
|20/256|FMUL_R|E|A|`(dst0, dst1) = (dst0 * src0, dst1 * src1)`|
|32/256|FMUL_R|E|A|`(dst0, dst1) = (dst0 * src0, dst1 * src1)`|
|4/256|FDIV_M|E|R|`(dst0, dst1) = (dst0 / [mem][0], dst1 / [mem][1])`|
|6/256|FSQRT_R|E|-|`(dst0, dst1) = (√dst0, √dst1)`|

Expand Down
47 changes: 40 additions & 7 deletions src/tests/benchmark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "utility.hpp"
#include "../randomx.h"
#include "../blake2/endian.h"
#include "../common.hpp"
#ifdef _WIN32
#include <windows.h>
#include <VersionHelpers.h>
#endif

const uint8_t blockTemplate_[] = {
0x07, 0x07, 0xf7, 0xa4, 0xf0, 0xd6, 0x05, 0xb3, 0x03, 0x26, 0x08, 0x16, 0xba, 0x3f, 0x10, 0x90, 0x2e, 0x1a, 0x14,
Expand Down Expand Up @@ -84,6 +89,19 @@ void printUsage(const char* executable) {
std::cout << " --seed S seed for cache initialization (default: 0)" << std::endl;
}

struct MemoryException : public std::exception {
};
struct CacheAllocException : public MemoryException {
const char * what() const throw () {
return "Cache allocation failed";
}
};
struct DatasetAllocException : public MemoryException {
const char * what() const throw () {
return "Dataset allocation failed";
}
};

void mine(randomx_vm* vm, std::atomic<uint32_t>& atomicNonce, AtomicHash& result, uint32_t noncesCount, int thread) {
uint64_t hash[RANDOMX_HASH_SIZE / sizeof(uint64_t)];
uint8_t blockTemplate[sizeof(blockTemplate_)];
Expand Down Expand Up @@ -118,7 +136,7 @@ int main(int argc, char** argv) {

store32(&seed, seedValue);

std::cout << "RandomX benchmark" << std::endl;
std::cout << "RandomX benchmark v1.0.4" << std::endl;

if (help || (!miningMode && !verificationMode)) {
printUsage(argv[0]);
Expand Down Expand Up @@ -171,19 +189,20 @@ int main(int argc, char** argv) {
std::cout << " ..." << std::endl;

try {
if (jit && !RANDOMX_HAVE_COMPILER) {
throw std::runtime_error("JIT compilation is not supported on this platform");
}

Stopwatch sw(true);
cache = randomx_alloc_cache(flags);
if (cache == nullptr) {
if (jit) {
throw std::runtime_error("JIT compilation is not supported or cache allocation failed");
}
throw std::runtime_error("Cache allocation failed");
throw CacheAllocException();
}
randomx_init_cache(cache, &seed, sizeof(seed));
if (miningMode) {
dataset = randomx_alloc_dataset(flags);
if (dataset == nullptr) {
throw std::runtime_error("Dataset allocation failed");
throw DatasetAllocException();
}
uint32_t datasetItemCount = randomx_dataset_item_count();
if (initThreadCount > 1) {
Expand Down Expand Up @@ -241,14 +260,28 @@ int main(int argc, char** argv) {
std::cout << "Calculated result: ";
result.print(std::cout);
if (noncesCount == 1000 && seedValue == 0)
std::cout << "Reference result: a925d346195ef38048e714709e0b24a88fef565fa02fa97127e00fac08ee6eb8" << std::endl;
std::cout << "Reference result: 38d47ea494480bff8d621189e8e92747288bb1da6c75dc401f2ab4b6807b6010" << std::endl;
if (!miningMode) {
std::cout << "Performance: " << 1000 * elapsed / noncesCount << " ms per hash" << std::endl;
}
else {
std::cout << "Performance: " << noncesCount / elapsed << " hashes per second" << std::endl;
}
}
catch (MemoryException& e) {
std::cout << "ERROR: " << e.what() << std::endl;
if (largePages) {
#ifdef _WIN32
std::cout << "To use large pages, please enable the \"Lock Pages in Memory\" policy and reboot." << std::endl;
if (!IsWindows8OrGreater()) {
std::cout << "Additionally, you have to run the benchmark from elevated command prompt." << std::endl;
}
#else
std::cout << "To use large pages, please run: sudo sysctl -w vm.nr_hugepages=1250" << std::endl;
#endif
}
return 1;
}
catch (std::exception& e) {
std::cout << "ERROR: " << e.what() << std::endl;
return 1;
Expand Down
21 changes: 14 additions & 7 deletions src/tests/tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "../reciprocal.h"
#include "../intrin_portable.h"
#include "../jit_compiler.hpp"
#include "../aes_hash.hpp"

struct CacheKey {
void* key;
Expand Down Expand Up @@ -146,6 +147,13 @@ int main() {
assert(datasetItem[0] == 0x145a5091f7853099);
});

runTest("AesGenerator1R", true, []() {
char state[64] = { 0 };
hex2bin("6c19536eb2de31b6c0065f7f116e86f960d8af0c57210a6584c3237b9d064dc7", 64, state);
fillAes1Rx4<true>(state, sizeof(state), state);
assert(equalsHex(state, "fa89397dd6ca422513aeadba3f124b5540324c4ad4b6db434394307a17c833ab"));
});

runTest("randomx_reciprocal", true, []() {
assert(randomx_reciprocal(3) == 12297829382473034410U);
assert(randomx_reciprocal(13) == 11351842506898185609U);
Expand Down Expand Up @@ -959,35 +967,34 @@ int main() {
auto test_a = [&] {
char hash[RANDOMX_HASH_SIZE];
calcStringHash("test key 000", "This is a test", &hash);
assert(equalsHex(hash, "207d7cedf2a16590bd33d758e413ad129ce9888e05417984f46296252a7ba3d0"));
assert(equalsHex(hash, "b33f8d10a8655d6f1925e3754adeb0a6da4c2f48a81cd4c220a412f1ef016a15"));
};

auto test_b = [&] {
char hash[RANDOMX_HASH_SIZE];
calcStringHash("test key 000", "Lorem ipsum dolor sit amet", &hash);
assert(equalsHex(hash, "76dd2da840d56d38153e0beaca33e7f862c5ead91a052380d99f3a62bf84579b"));
assert(equalsHex(hash, "62ac336786ad3a7aff990beb2f643bd748d81dba585a52149d0baebdea0e9823"));
};

auto test_c = [&] {
char hash[RANDOMX_HASH_SIZE];
calcStringHash("test key 000", "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua", &hash);
assert(equalsHex(hash, "109f6a405efe09d302336dce4389127e33aa62d4c782aca7797a628e87839a61"));
assert(equalsHex(hash, "6c550ebe765f7b784d2c183552fbb6048b58f17a3f115baf2b968724eb2f7a23"));
};

auto test_d = [&] {
char hash[RANDOMX_HASH_SIZE];
calcStringHash("test key 001", "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua", &hash);
assert(equalsHex(hash, "3cbb82edf9541ab80233cdc47384cea719c8567a8bbaca8f3ff038488ce9c16c"));
assert(equalsHex(hash, "cb602b9c498b67e31e519fbdc07e288de46f949b14ad620380df6250eaffbd4e"));
};

auto test_e = [&] {
char hash[RANDOMX_HASH_SIZE];
calcHexHash("test key 001", "0b0b98bea7e805e0010a2126d287a2a0cc833d312cb786385a7c2f9de69d25537f584a9bc9977b00000000666fd8753bf61a8631f12984e3fd44f4014eca629276817b56f32e9b68bd82f416", &hash);

//std::cout << std::endl;
//outputHex(std::cout, (const char*)hash, sizeof(hash));
//std::cout << std::endl;

assert(equalsHex(hash, "e003ef128b1f96d99d4a0490e03253ef11186002a8ec018cbd4e07b8ec8c82e8"));
assert(equalsHex(hash, "f60caf300917760337e8ce51487484e6a33d4aaa15aa79c985efb4ea00390918"));
};

runTest("Hash test 1a (interpreter)", stringsEqual(RANDOMX_ARGON_SALT, "RandomX\x03"), test_a);
Expand Down
4 changes: 2 additions & 2 deletions src/tests/utility.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ char parseNibble(char hex) {
return hex;
}

void hex2bin(char *in, int length, char *out) {
void hex2bin(const char *in, int length, char *out) {
for (int i = 0; i < length; i += 2) {
char nibble1 = parseNibble(*in++);
char nibble2 = parseNibble(*in++);
Expand All @@ -67,7 +67,7 @@ constexpr bool stringsEqual(char const * a, char const * b) {
template<size_t N>
bool equalsHex(const void* hash, const char (&hex)[N]) {
char reference[N / 2];
hex2bin((char*)hex, N - 1, reference);
hex2bin(hex, N - 1, reference);
return memcmp(hash, reference, sizeof(reference)) == 0;
}

Expand Down

0 comments on commit 8282413

Please sign in to comment.