upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/util.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/util.h')
-rw-r--r--src/util.h128
1 files changed, 122 insertions, 6 deletions
diff --git a/src/util.h b/src/util.h
index d95d3ae..dfe7511 100644
--- a/src/util.h
+++ b/src/util.h
@@ -8,6 +8,13 @@
8#include <cxxabi.h> 8#include <cxxabi.h>
9#endif 9#endif
10 10
11// For AvailableCoreCount() below: sched_getaffinity on Linux, and
12// hardware_concurrency as the fallback everywhere else.
13#include <thread>
14#ifdef __linux__
15#include <sched.h>
16#endif
17
11#if defined(_MSC_VER) || defined(__BORLANDC__) 18#if defined(_MSC_VER) || defined(__BORLANDC__)
12typedef __int64 int64; 19typedef __int64 int64;
13typedef unsigned __int64 uint64; 20typedef unsigned __int64 uint64;
@@ -80,6 +87,15 @@ inline T& REF(const T& val)
80 87
81extern bool fDebug; 88extern bool fDebug;
82 89
90// /debugrelay: the per-message firehose ("relay" and "nostrdiscovery"
91// categories) that even -debug keeps off. See LogAcceptsCategory().
92extern bool fDebugRelay;
93
94// debug.log is rolled to debug.log.old once it grows past this many bytes
95// (set from -maxdebugfilesize, in MB; 0 disables the check). See the roll
96// site in OutputDebugStringF() below.
97extern int64 nMaxDebugFileSize;
98
83// --------------------------------------------------------------------------- 99// ---------------------------------------------------------------------------
84// Categorized, burst-collapsing logging 100// Categorized, burst-collapsing logging
85// 101//
@@ -99,15 +115,29 @@ extern bool fDebug;
99// 2. Burst collapse: repeated LogPrint() calls from the *same source line* 115// 2. Burst collapse: repeated LogPrint() calls from the *same source line*
100// only emit one line per DEDUP_WINDOW_SECS; if more calls land inside 116// only emit one line per DEDUP_WINDOW_SECS; if more calls land inside
101// that window they're counted instead of reprinted, and the count is 117// that window they're counted instead of reprinted, and the count is
102// flushed as a single "(xN similar in Ws)" line the moment the window 118// flushed as a single "(xN similar in Ws)" line once the window expires
103// rolls over. A loop discovering 500 peers by address now produces a 119// -- whether or not that call site ever fires again. A loop discovering
104// small, bounded number of lines instead of 500 -- log growth is capped 120// 500 peers by address now produces a small, bounded number of lines
105// by elapsed time, not by how many similar events happen to fire. 121// instead of 500 -- log growth is capped by elapsed time, not by how
122// many similar events happen to fire.
123//
124// Use LogPrintAlways() instead for anything that reports an irreversible
125// change to money: an obligation voided, a payment sent, a payment that
126// failed. One line standing in for an unknown number of identical events is
127// a tidy report of peer chatter and a false report of a ledger. A reorg
128// voiding 100 entries hits one source line 100 times inside one window;
129// under LogPrint() that read as a single block losing a single 49.49 BTF
130// payment, while 4,950 BTF of obligations were actually destroyed, and the
131// discrepancy was only found by counting entries in pending_payouts.json
132// (issue #3). Bounded log growth is not worth that ambiguity here.
106// --------------------------------------------------------------------------- 133// ---------------------------------------------------------------------------
107bool LogAcceptsCategory(const char* category); 134bool LogAcceptsCategory(const char* category);
108void LogPrintDedup(const char* category, const char* file, int line, const std::string& msg); 135void LogPrintDedup(const char* category, const char* file, int line, const std::string& msg);
136void LogPrintNoCollapse(const char* category, const std::string& msg);
109#define LogPrint(category, ...) \ 137#define LogPrint(category, ...) \
110 do { if (LogAcceptsCategory(category)) LogPrintDedup((category), __FILE__, __LINE__, strprintf(__VA_ARGS__)); } while (0) 138 do { if (LogAcceptsCategory(category)) LogPrintDedup((category), __FILE__, __LINE__, strprintf(__VA_ARGS__)); } while (0)
139#define LogPrintAlways(category, ...) \
140 do { if (LogAcceptsCategory(category)) LogPrintNoCollapse((category), strprintf(__VA_ARGS__)); } while (0)
111 141
112// Every format string in this project goes through one of the four functions 142// Every format string in this project goes through one of the four functions
113// below -- `printf` itself is remapped to OutputDebugStringF just above, and 143// below -- `printf` itself is remapped to OutputDebugStringF just above, and
@@ -138,12 +168,40 @@ void ParseString(const string& str, char c, vector<string>& v);
138string FormatMoney(int64 n, bool fPlus=false); 168string FormatMoney(int64 n, bool fPlus=false);
139bool ParseMoney(const char* pszIn, int64& nRet); 169bool ParseMoney(const char* pszIn, int64& nRet);
140bool FileExists(const char* psz); 170bool FileExists(const char* psz);
141int GetFilesize(FILE* file); 171int64 GetFilesize(FILE* file);
142uint64 GetRand(uint64 nMax); 172uint64 GetRand(uint64 nMax);
143int64 GetTime(); 173int64 GetTime();
144int64 GetAdjustedTime(); 174int64 GetAdjustedTime();
145void AddTimeData(unsigned int ip, int64 nTime); 175void AddTimeData(unsigned int ip, int64 nTime);
146 176
177// Cores this process is actually allowed to run on.
178//
179// std::thread::hardware_concurrency() reports the MACHINE's core count, which
180// is not the same number inside a container. With --cpuset-cpus 0-5 on a
181// 12-core host it still answers 12, so every caller that sized a thread pool
182// from it oversubscribed by 2x and then wondered why the box was thrashing:
183// the pool node started 11 miner threads on 6 permitted CPUs, and a burst
184// miner asked for 2 cores filled the ~2 GB RandomX dataset with 12 threads.
185//
186// sched_getaffinity reports what the cpuset permits, which is the number every
187// one of those callers meant. Falls back to hardware_concurrency where the
188// call is unavailable, and never returns 0 -- callers divide by this.
189inline unsigned int AvailableCoreCount()
190{
191#ifdef __linux__
192 cpu_set_t cpuset;
193 CPU_ZERO(&cpuset);
194 if (sched_getaffinity(0, sizeof(cpuset), &cpuset) == 0)
195 {
196 int nAllowed = CPU_COUNT(&cpuset);
197 if (nAllowed > 0)
198 return (unsigned int)nAllowed;
199 }
200#endif
201 unsigned int nCores = std::thread::hardware_concurrency();
202 return nCores > 0 ? nCores : 1;
203}
204
147 205
148 206
149 207
@@ -164,7 +222,7 @@ protected:
164public: 222public:
165 char* pszFile; 223 char* pszFile;
166 int nLine; 224 int nLine;
167 explicit CCriticalSection() { InitializeCriticalSection(&cs); } 225 explicit CCriticalSection() : pszFile(NULL), nLine(0) { InitializeCriticalSection(&cs); }
168 ~CCriticalSection() { DeleteCriticalSection(&cs); } 226 ~CCriticalSection() { DeleteCriticalSection(&cs); }
169 void Enter() { EnterCriticalSection(&cs); } 227 void Enter() { EnterCriticalSection(&cs); }
170 void Leave() { LeaveCriticalSection(&cs); } 228 void Leave() { LeaveCriticalSection(&cs); }
@@ -355,7 +413,65 @@ inline int OutputDebugStringF(const char* pszFormat, ...)
355 else 413 else
356 strDebugFile = "debug.log"; 414 strDebugFile = "debug.log";
357 } 415 }
416 // Latched by a failed rename in the roll below, which cannot be
417 // retried usefully and must not be retried endlessly.
418 static bool fRollDisabled = false;
358 FILE* fileout = fopen(strDebugFile.c_str(), "a"); 419 FILE* fileout = fopen(strDebugFile.c_str(), "a");
420 if (fileout && nMaxDebugFileSize > 0 && !fRollDisabled)
421 {
422 // Roll an overgrown debug.log before adding to it. Nothing in the
423 // tree shrinks this file once the process is running (there is no
424 // ShrinkDebugFile, and even Bitcoin's only ran at startup), so a
425 // node that stays up for months grows the log without bound --
426 // production hit ~2 GiB. The file is opened and closed per line,
427 // so a rename is safe here: the next line simply reopens the
428 // path. One generation is kept as debug.log.old; logrotate
429 // (contrib/logrotate/) handles anything longer-term.
430 int64 nSize = GetFilesize(fileout);
431 if (nSize >= 0 && nSize > nMaxDebugFileSize)
432 {
433 fclose(fileout);
434 string strOldFile = strDebugFile + ".old";
435 remove(strOldFile.c_str()); // rename() won't clobber on Windows
436 bool fRolled = (rename(strDebugFile.c_str(), strOldFile.c_str()) == 0);
437 int nRenameErrno = errno; // before fopen() can overwrite it
438 fileout = fopen(strDebugFile.c_str(), "a");
439 if (fRolled)
440 {
441 if (fileout)
442 fprintf(fileout,
443 "debug.log grew past %lld MB; previous contents moved to debug.log.old (-maxdebugfilesize)\n",
444 (long long)(nMaxDebugFileSize / 1024 / 1024));
445 }
446 else if (nRenameErrno == ENOENT)
447 {
448 // The file went away between the size check and the
449 // rename, so an external rotator (logrotate) got there
450 // first. Nothing left to roll and nothing wrong: the
451 // fopen above has already recreated it. Latching on this
452 // would let a benign race with logrotate switch the cap
453 // off for the rest of the run.
454 }
455 else
456 {
457 // The file is still over the cap, so this branch would be
458 // reached again on the next line and every line after it.
459 // Unlatched, the complaint about failing to roll becomes
460 // the runaway growth the roll exists to prevent. Say it
461 // once and stop trying -- on stderr too, because whatever
462 // blocked the rename (read-only mount, permissions, EXDEV
463 // across a bind mount) may equally block the log write.
464 fRollDisabled = true;
465 fprintf(stderr,
466 "cannot roll %s (rename to .old failed: %s); -maxdebugfilesize disabled for this run\n",
467 strDebugFile.c_str(), strerror(nRenameErrno));
468 if (fileout)
469 fprintf(fileout,
470 "cannot roll debug.log (rename to .old failed: %s); -maxdebugfilesize disabled for this run\n",
471 strerror(nRenameErrno));
472 }
473 }
474 }
359 if (fileout) 475 if (fileout)
360 { 476 {
361 va_list arg_ptr; 477 va_list arg_ptr;