fix: cap thread count before slice sizing, scale monsters to ncpu

count_sliced computed the slice size from the requested thread count and
only then clamped nt to MAX_THREADS, so the last slice ended before the
file tail: raising the cap (as pick_threads now does) silently dropped
the tail from every count. Cap nt first, then derive per.

Monsters (>=256 MiB) now get one thread per core (capped at 24) instead
of a hard 16, which measures ~1.17x on the 1B-line case and is flat on
warm files. check_sliced now sweeps the cap boundary (16, 24, 25).
This commit is contained in:
2026-08-29 18:56:48 -04:00
parent f217551448
commit af61660c42
2 changed files with 27 additions and 18 deletions
+21 -13
View File
@@ -36,6 +36,11 @@ enum
F_BYTES = 1 << 3, /* -c: bytes */
};
enum
{
MAX_THREADS = 24, /* pick_threads() and count_sliced() agree on this */
};
static int flags = 0;
typedef struct
@@ -623,18 +628,15 @@ static void count_sliced(const unsigned char *p, size_t n, int nt,
int need_lines, int need_words, long long *lines,
long long *words)
{
enum
{
MAX_THREADS = 16
};
mjob_t jobs[MAX_THREADS];
pthread_t th[MAX_THREADS];
long long tl = 0, tw = 0;
size_t per = (n + (size_t)nt - 1) / (size_t)nt;
size_t per;
int i;
if (nt > MAX_THREADS)
nt = MAX_THREADS;
nt = MAX_THREADS; /* cap first: per is derived from the real nt */
per = (n + (size_t)nt - 1) / (size_t)nt;
per = (per + 63) & ~(size_t)63;
if (per == 0)
per = 64;
@@ -678,16 +680,18 @@ static int pick_threads(size_t n)
long ncpu = sysconf(_SC_NPROCESSORS_ONLN);
int nt;
if (ncpu <= 0)
ncpu = 1;
if (n >= (size_t)256 << 20)
nt = 16;
nt = (int)ncpu; /* monsters: one thread per core, readahead wins */
else if (n >= (size_t)32 << 20)
nt = 12;
nt = (int)ncpu < 12 ? (int)ncpu : 12;
else if (n >= (size_t)8 << 20)
nt = 4;
nt = (int)ncpu < 4 ? (int)ncpu : 4;
else
nt = 1;
if (ncpu > 0 && nt > ncpu)
nt = (int)ncpu;
if (nt > MAX_THREADS)
nt = MAX_THREADS;
return nt;
}
@@ -1103,13 +1107,16 @@ static int check_sliced(void)
static unsigned char buf[9001];
int fails = 0;
size_t n, k;
static const int tcs[] = {
1, 2, 3, 4, 8, 12, 16, MAX_THREADS, MAX_THREADS + 1};
for (n = 0; n <= 9000; n += (n < 300 ? 1 : 37))
{
for (k = 0; k < n; k++)
buf[k] = (unsigned char)rng32();
for (int nt = 1; nt <= 8; nt++)
for (size_t ti = 0; ti < sizeof tcs / sizeof tcs[0]; ti++)
{
int nt = tcs[ti];
long long tl = 0, tw = 0;
long long want_l = count_newlines(buf, n);
int pw = 1;
@@ -1133,8 +1140,9 @@ static int check_sliced(void)
{
for (k = 0; k < n; k++)
buf[k] = (unsigned char)" \t\n\v\f\r\xa0x"[rng32() % 8];
for (int nt = 1; nt <= 8; nt++)
for (size_t ti = 0; ti < sizeof tcs / sizeof tcs[0]; ti++)
{
int nt = tcs[ti];
long long tl = 0, tw = 0;
long long want_l = count_newlines(buf, n);
int pw = 1;