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.cpp106
1 files changed, 95 insertions, 11 deletions
diff --git a/src/randomx_pow.cpp b/src/randomx_pow.cpp
index 1d058d4..5872090 100644
--- a/src/randomx_pow.cpp
+++ b/src/randomx_pow.cpp
@@ -23,6 +23,39 @@ 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
37static randomx_flags WithLargePages(randomx_flags f)
38{
39 return (randomx_flags)(f | RANDOMX_FLAG_LARGE_PAGES);
40}
41
42// Ask for a cache in large pages, then plain pages. Sets fLargeOut to say
43// which one answered.
44static randomx_cache* AllocCache(randomx_flags flags, bool& fLargeOut)
45{
46 fLargeOut = false;
47 if (fRandomXLargePages)
48 {
49 randomx_cache* c = randomx_alloc_cache(WithLargePages(flags));
50 if (c)
51 {
52 fLargeOut = true;
53 return c;
54 }
55 }
56 return randomx_alloc_cache(flags);
57}
58
26 59
27bool RandomXInit() 60bool RandomXInit()
28{ 61{
@@ -36,28 +69,56 @@ bool RandomXInit()
36 // Detect the best flags for this CPU (JIT, hardware AES, Argon2). 69 // Detect the best flags for this CPU (JIT, hardware AES, Argon2).
37 g_flags = randomx_get_flags(); 70 g_flags = randomx_get_flags();
38 71
39 g_cache = randomx_alloc_cache(g_flags); 72 g_cache = AllocCache(g_flags, g_fLargeCache);
40 if (!g_cache) 73 if (!g_cache)
41 { 74 {
42 // Try without JIT as a fallback 75 // Try without JIT as a fallback
43 g_flags = RANDOMX_FLAG_DEFAULT; 76 g_flags = RANDOMX_FLAG_DEFAULT;
44 g_cache = randomx_alloc_cache(g_flags); 77 g_cache = AllocCache(g_flags, g_fLargeCache);
45 if (!g_cache) 78 if (!g_cache)
46 return error("RandomX: failed to allocate cache (256 MB)"); 79 return error("RandomX: failed to allocate cache (256 MB)");
47 } 80 }
48 randomx_init_cache(g_cache, RANDOMX_KEY, strlen(RANDOMX_KEY)); 81 randomx_init_cache(g_cache, RANDOMX_KEY, strlen(RANDOMX_KEY));
49 82
50 // Verification VM in light mode (cache only) 83 // Verification VM in light mode (cache only). The scratchpad is only 2 MB
51 g_vmVerify = randomx_create_vm(g_flags, g_cache, NULL); 84 // and this VM is created once, but it hashes every block the node ever
85 // validates, so it gets the same treatment.
86 bool fLargeVerify = false;
87 if (fRandomXLargePages)
88 {
89 g_vmVerify = randomx_create_vm(WithLargePages(g_flags), g_cache, NULL);
90 fLargeVerify = (g_vmVerify != NULL);
91 }
92 if (!g_vmVerify)
93 g_vmVerify = randomx_create_vm(g_flags, g_cache, NULL);
52 if (!g_vmVerify) 94 if (!g_vmVerify)
53 return error("RandomX: failed to create verification VM"); 95 return error("RandomX: failed to create verification VM");
54 96
97 g_fLargeAny = g_fLargeCache || fLargeVerify;
55 g_fInit = true; 98 g_fInit = true;
56 printf("RandomX: initialized (cache 256 MB, flags=%d)\n", (int)g_flags); 99 printf("RandomX: initialized (cache 256 MB, flags=%d, large pages: %s)\n",
100 (int)g_flags, RandomXLargePagesStatus());
101 if (fRandomXLargePages && !g_fLargeCache)
102 printf("RandomX: large pages unavailable for the cache; "
103 "reserve them with sysctl vm.nr_hugepages=1280 for about 10%% more hash rate\n");
57 return true; 104 return true;
58} 105}
59 106
60 107
108const char* RandomXLargePagesStatus()
109{
110 if (!fRandomXLargePages)
111 return "off (-nolargepages)";
112 if (g_fLargeCache && g_fLargeDataset)
113 return "cache + dataset";
114 if (g_fLargeCache)
115 return "cache only";
116 if (g_fLargeDataset)
117 return "dataset only";
118 return g_fLargeAny ? "scratchpad only" : "unavailable";
119}
120
121
61// One dataset, once, no matter how many miners ask for it. 122// One dataset, once, no matter how many miners ask for it.
62// 123//
63// Every miner thread calls this at startup. The g_fFast guard below is only 124// Every miner thread calls this at startup. The g_fFast guard below is only
@@ -87,8 +148,18 @@ bool RandomXInitDataset(int nThreads)
87 if (g_fFast) 148 if (g_fFast)
88 return true; 149 return true;
89 150
90 randomx_flags fastFlags = (randomx_flags)(g_flags | RANDOMX_FLAG_FULL_MEM); 151 // Only RANDOMX_FLAG_LARGE_PAGES means anything to randomx_alloc_dataset;
91 g_dataset = randomx_alloc_dataset(fastFlags); 152 // the rest of g_flags belongs to the VMs that read it.
153 if (fRandomXLargePages)
154 {
155 g_dataset = randomx_alloc_dataset(WithLargePages(RANDOMX_FLAG_DEFAULT));
156 g_fLargeDataset = (g_dataset != NULL);
157 if (!g_dataset)
158 printf("RandomX: large pages unavailable for the 2 GB dataset; "
159 "reserve 1280 with sysctl vm.nr_hugepages for about 10%% more hash rate\n");
160 }
161 if (!g_dataset)
162 g_dataset = randomx_alloc_dataset(RANDOMX_FLAG_DEFAULT);
92 if (!g_dataset) 163 if (!g_dataset)
93 { 164 {
94 printf("RandomX: not enough memory for the 2 GB dataset, staying in light mode\n"); 165 printf("RandomX: not enough memory for the 2 GB dataset, staying in light mode\n");
@@ -142,13 +213,26 @@ void* RandomXCreateMinerVM()
142{ 213{
143 if (!g_fInit && !RandomXInit()) 214 if (!g_fInit && !RandomXInit())
144 return NULL; 215 return NULL;
216
217 randomx_flags flags = g_flags;
218 randomx_cache* cache = g_cache;
219 randomx_dataset* dataset = NULL;
145 if (g_fFast && g_dataset) 220 if (g_fFast && g_dataset)
146 { 221 {
147 randomx_flags fastFlags = (randomx_flags)(g_flags | RANDOMX_FLAG_FULL_MEM); 222 flags = (randomx_flags)(g_flags | RANDOMX_FLAG_FULL_MEM);
148 return randomx_create_vm(fastFlags, NULL, g_dataset); 223 cache = NULL;
224 dataset = g_dataset;
225 }
226
227 // Each thread gets its own 2 MB scratchpad, so the large-page pool can run
228 // dry partway through a fleet of miners. Threads that miss out still run.
229 if (fRandomXLargePages)
230 {
231 randomx_vm* vm = randomx_create_vm(WithLargePages(flags), cache, dataset);
232 if (vm)
233 return vm;
149 } 234 }
150 // Light mode: own VM sharing the cache 235 return randomx_create_vm(flags, cache, dataset);
151 return randomx_create_vm(g_flags, g_cache, NULL);
152} 236}
153 237
154 238