upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/randomx_pow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/randomx_pow.cpp')
-rw-r--r--src/randomx_pow.cpp117
1 files changed, 106 insertions, 11 deletions
diff --git a/src/randomx_pow.cpp b/src/randomx_pow.cpp
index 9c59364..a509543 100644
--- a/src/randomx_pow.cpp
+++ b/src/randomx_pow.cpp
@@ -24,6 +24,50 @@ static std::mutex g_csInit;
24static bool g_fInit = false; 24static bool g_fInit = false;
25static bool g_fFast = false; 25static bool g_fFast = false;
26 26
27// RandomX reads a 256 MB cache, a 2 GB dataset and a 2 MB scratchpad per VM
28// at random, so most reads miss the TLB on 4 KB pages. 2 MB pages recover
29// roughly a tenth of the hash rate.
30//
31// The pool must be reserved first (vm.nr_hugepages), and RandomX returns NULL
32// instead of falling back, so each allocation below retries without the flag.
33bool fRandomXLargePages = true; // cleared by -nolargepages
34static bool g_fLargeCache = false;
35static bool g_fLargeDataset = false;
36static bool g_fLargeAny = false;
37
38// How to reserve the large-page pool, for the hint printed when a large-page
39// allocation falls back to normal pages. The mechanism is OS-specific.
40static const char* LargePagesHint()
41{
42#ifdef _WIN32
43 return "enable the \"Lock pages in memory\" privilege and run elevated";
44#else
45 return "reserve them with: sysctl vm.nr_hugepages=1280";
46#endif
47}
48
49static randomx_flags WithLargePages(randomx_flags f)
50{
51 return (randomx_flags)(f | RANDOMX_FLAG_LARGE_PAGES);
52}
53
54// Ask for a cache in large pages, then plain pages. Sets fLargeOut to say
55// which one answered.
56static randomx_cache* AllocCache(randomx_flags flags, bool& fLargeOut)
57{
58 fLargeOut = false;
59 if (fRandomXLargePages)
60 {
61 randomx_cache* c = randomx_alloc_cache(WithLargePages(flags));
62 if (c)
63 {
64 fLargeOut = true;
65 return c;
66 }
67 }
68 return randomx_alloc_cache(flags);
69}
70
27 71
28bool RandomXInit() 72bool RandomXInit()
29{ 73{
@@ -37,28 +81,56 @@ bool RandomXInit()
37 // Detect the best flags for this CPU (JIT, hardware AES, Argon2). 81 // Detect the best flags for this CPU (JIT, hardware AES, Argon2).
38 g_flags = randomx_get_flags(); 82 g_flags = randomx_get_flags();
39 83
40 g_cache = randomx_alloc_cache(g_flags); 84 g_cache = AllocCache(g_flags, g_fLargeCache);
41 if (!g_cache) 85 if (!g_cache)
42 { 86 {
43 // Try without JIT as a fallback 87 // Try without JIT as a fallback
44 g_flags = RANDOMX_FLAG_DEFAULT; 88 g_flags = RANDOMX_FLAG_DEFAULT;
45 g_cache = randomx_alloc_cache(g_flags); 89 g_cache = AllocCache(g_flags, g_fLargeCache);
46 if (!g_cache) 90 if (!g_cache)
47 return error("RandomX: failed to allocate cache (256 MB)"); 91 return error("RandomX: failed to allocate cache (256 MB)");
48 } 92 }
49 randomx_init_cache(g_cache, RANDOMX_KEY, strlen(RANDOMX_KEY)); 93 randomx_init_cache(g_cache, RANDOMX_KEY, strlen(RANDOMX_KEY));
50 94
51 // Verification VM in light mode (cache only) 95 // Verification VM in light mode (cache only). The scratchpad is only 2 MB
52 g_vmVerify = randomx_create_vm(g_flags, g_cache, NULL); 96 // and this VM is created once, but it hashes every block the node ever
97 // validates, so it gets the same treatment.
98 bool fLargeVerify = false;
99 if (fRandomXLargePages)
100 {
101 g_vmVerify = randomx_create_vm(WithLargePages(g_flags), g_cache, NULL);
102 fLargeVerify = (g_vmVerify != NULL);
103 }
104 if (!g_vmVerify)
105 g_vmVerify = randomx_create_vm(g_flags, g_cache, NULL);
53 if (!g_vmVerify) 106 if (!g_vmVerify)
54 return error("RandomX: failed to create verification VM"); 107 return error("RandomX: failed to create verification VM");
55 108
109 g_fLargeAny = g_fLargeCache || fLargeVerify;
56 g_fInit = true; 110 g_fInit = true;
57 printf("RandomX: initialized (cache 256 MB, flags=%d)\n", (int)g_flags); 111 printf("RandomX: initialized (cache 256 MB, flags=%d, large pages: %s)\n",
112 (int)g_flags, RandomXLargePagesStatus());
113 if (fRandomXLargePages && !g_fLargeCache)
114 printf("RandomX: large pages unavailable for the cache; %s "
115 "for about 10%% more hash rate\n", LargePagesHint());
58 return true; 116 return true;
59} 117}
60 118
61 119
120const char* RandomXLargePagesStatus()
121{
122 if (!fRandomXLargePages)
123 return "off (-nolargepages)";
124 if (g_fLargeCache && g_fLargeDataset)
125 return "cache + dataset";
126 if (g_fLargeCache)
127 return "cache only";
128 if (g_fLargeDataset)
129 return "dataset only";
130 return g_fLargeAny ? "scratchpad only" : "unavailable";
131}
132
133
62// One dataset, once, no matter how many miners ask for it. 134// One dataset, once, no matter how many miners ask for it.
63// 135//
64// Every miner thread calls this at startup. The g_fFast guard below is only 136// Every miner thread calls this at startup. The g_fFast guard below is only
@@ -88,8 +160,18 @@ bool RandomXInitDataset(int nThreads)
88 if (g_fFast) 160 if (g_fFast)
89 return true; 161 return true;
90 162
91 randomx_flags fastFlags = (randomx_flags)(g_flags | RANDOMX_FLAG_FULL_MEM); 163 // Only RANDOMX_FLAG_LARGE_PAGES means anything to randomx_alloc_dataset;
92 g_dataset = randomx_alloc_dataset(fastFlags); 164 // the rest of g_flags belongs to the VMs that read it.
165 if (fRandomXLargePages)
166 {
167 g_dataset = randomx_alloc_dataset(WithLargePages(RANDOMX_FLAG_DEFAULT));
168 g_fLargeDataset = (g_dataset != NULL);
169 if (!g_dataset)
170 printf("RandomX: large pages unavailable for the 2 GB dataset; %s "
171 "for about 10%% more hash rate\n", LargePagesHint());
172 }
173 if (!g_dataset)
174 g_dataset = randomx_alloc_dataset(RANDOMX_FLAG_DEFAULT);
93 if (!g_dataset) 175 if (!g_dataset)
94 { 176 {
95 printf("RandomX: not enough memory for the 2 GB dataset, staying in light mode\n"); 177 printf("RandomX: not enough memory for the 2 GB dataset, staying in light mode\n");
@@ -158,13 +240,26 @@ void* RandomXCreateMinerVM()
158{ 240{
159 if (!g_fInit && !RandomXInit()) 241 if (!g_fInit && !RandomXInit())
160 return NULL; 242 return NULL;
243
244 randomx_flags flags = g_flags;
245 randomx_cache* cache = g_cache;
246 randomx_dataset* dataset = NULL;
161 if (g_fFast && g_dataset) 247 if (g_fFast && g_dataset)
162 { 248 {
163 randomx_flags fastFlags = (randomx_flags)(g_flags | RANDOMX_FLAG_FULL_MEM); 249 flags = (randomx_flags)(g_flags | RANDOMX_FLAG_FULL_MEM);
164 return randomx_create_vm(fastFlags, NULL, g_dataset); 250 cache = NULL;
251 dataset = g_dataset;
252 }
253
254 // Each thread gets its own 2 MB scratchpad, so the large-page pool can run
255 // dry partway through a fleet of miners. Threads that miss out still run.
256 if (fRandomXLargePages)
257 {
258 randomx_vm* vm = randomx_create_vm(WithLargePages(flags), cache, dataset);
259 if (vm)
260 return vm;
165 } 261 }
166 // Light mode: own VM sharing the cache 262 return randomx_create_vm(flags, cache, dataset);
167 return randomx_create_vm(g_flags, g_cache, NULL);
168} 263}
169 264
170 265