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