فهرست منبع

Updated documentation and test vectors
Added AesGenerator1R test
Added benchmark hints if large pages fail

tevador 7 سال پیش
والد
کامیت
8282413154
5فایلهای تغییر یافته به همراه67 افزوده شده و 23 حذف شده
  1. 5 1
      doc/design.md
  2. 6 6
      doc/specs.md
  3. 40 7
      src/tests/benchmark.cpp
  4. 14 7
      src/tests/tests.cpp
  5. 2 2
      src/tests/utility.hpp

+ 5 - 1
doc/design.md

@@ -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.
 

+ 6 - 6
doc/specs.md

@@ -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
@@ -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)`|
 

+ 40 - 7
src/tests/benchmark.cpp

@@ -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,
@@ -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_)];
@@ -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]);
@@ -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) {
@@ -241,7 +260,7 @@ 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;
 		}
@@ -249,6 +268,20 @@ int main(int argc, char** argv) {
 			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;

+ 14 - 7
src/tests/tests.cpp

@@ -14,6 +14,7 @@
 #include "../reciprocal.h"
 #include "../intrin_portable.h"
 #include "../jit_compiler.hpp"
+#include "../aes_hash.hpp"
 
 struct CacheKey {
 	void* key;
@@ -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);
@@ -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);

+ 2 - 2
src/tests/utility.hpp

@@ -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++);
@@ -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;
 }