Skip to content

Commit c36bfe2

Browse files
committed
wip
1 parent a0cff1c commit c36bfe2

25 files changed

+1579
-481
lines changed

bench/find-files/README.md

+215-41
Large diffs are not rendered by default.

bench/find-files/index.ts

+33-9
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,52 @@ import {bench, compact, group, run, summary} from 'mitata';
22
import * as path from 'node:path';
33
import findFilesAsync from './src/find-files.async.ts';
44
import findFilesSync from './src/find-files.sync.ts';
5+
import globbySync from './src/globby.ts';
6+
import fastGlob from './src/fast-glob.ts';
7+
import nodeGlob from './src/glob.ts';
58
import {countFiles} from "../../src/lib/file-system.ts";
6-
import {FLAT_100_TEST_DIR, DIR_3_FILE_10_NEST_8, DIR_3_FILE_10_NEST_6} from "../../src/lib/constants.ts";
9+
import {TEST_FILE_CONFIGURATIONS} from "../../src/lib/constants.ts";
710
import {runWithConfig} from "../../src/lib/utils.ts";
811

12+
const ext = '.txt';
13+
const regex = new RegExp(`${ext}$`, 'g')
14+
const globPattern = `**/*${ext}`;
915

10-
const glob = /.txt/g;
11-
12-
[FLAT_100_TEST_DIR, DIR_3_FILE_10_NEST_8, DIR_3_FILE_10_NEST_6, '.'].forEach((dir) => {
16+
TEST_FILE_CONFIGURATIONS
17+
.map(({dir}) => dir)
18+
.forEach((dir) => {
1319
const fixtureDir = path.join(process.cwd(), 'tmp', dir);
1420
const count = countFiles(fixtureDir);
1521

1622
summary(() => {
1723
compact(() => {
18-
group(`${dir}; count: ${count}; glob: ${glob}`, () => {
19-
bench('sync', () => {
20-
if (findFilesSync(fixtureDir, glob).length !== count) {
24+
group(`${dir}; count: ${count}; ext: ${ext}`, () => {
25+
bench('dir_regex_sync', () => {
26+
if (findFilesSync(regex, fixtureDir).length === 0) {
27+
throw new Error('No hits found. Bench invalid.');
28+
}
29+
}).gc('inner');
30+
31+
bench('dir_regex_async', async () => {
32+
if ((await findFilesAsync(regex, fixtureDir)).length === 0) {
33+
throw new Error('No hits found. Bench invalid.');
34+
}
35+
}).gc('inner');
36+
37+
bench('globbySync', async () => {
38+
if (globbySync(globPattern, fixtureDir).length === 0) {
39+
throw new Error('No hits found. Bench invalid.');
40+
}
41+
}).gc('inner');
42+
43+
bench('fastGlob', async () => {
44+
if ((await fastGlob(globPattern, fixtureDir)).length === 0) {
2145
throw new Error('No hits found. Bench invalid.');
2246
}
2347
}).gc('inner');
2448

25-
bench('async', async () => {
26-
if ((await findFilesAsync(fixtureDir, glob)).length !== count) {
49+
bench('nodeGlob', async () => {
50+
if ((await nodeGlob(globPattern, fixtureDir)).length === 0) {
2751
throw new Error('No hits found. Bench invalid.');
2852
}
2953
}).gc('inner');

bench/find-files/src/fast-glob.ts

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { createRequire } from 'module';
2+
const require = createRequire(import.meta.url);
3+
const fastGlob = require('fast-glob');
4+
5+
export default async function findFiles(
6+
globP: string,
7+
baseDir: string,
8+
): Promise<string[]> {
9+
return fastGlob.sync(globP, {cwd: baseDir});
10+
}

bench/find-files/src/find-files.async.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import * as fs from "node:fs/promises";
22
import * as path from "node:path";
33

44
export default async function findFiles(
5+
glob: RegExp,
56
baseDir: string,
6-
glob: RegExp
77
): Promise<string[]> {
88
const results: string[] = [];
99
const queue: string[] = [baseDir];

bench/find-files/src/find-files.sync.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import * as fs from 'fs';
22
import * as path from 'path';
33

44
export default function findFiles(
5+
glob: RegExp,
56
baseDir: string,
6-
glob: RegExp
77
): string[] {
88
const queue: string[] = [baseDir];
99
const results: string[] = [];

bench/find-files/src/glob.ts

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { createRequire } from 'module';
2+
const require = createRequire(import.meta.url);
3+
const globSync = require('glob');
4+
5+
export default async function findFiles(
6+
globP: string,
7+
baseDir: string,
8+
): Promise<string[]> {
9+
return globSync.sync(globP, {cwd: baseDir});
10+
}

bench/find-files/src/globby.ts

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
import { globbySync } from 'globby';
3+
4+
export default function findFiles(
5+
globP: string,
6+
baseDir: string,
7+
): string[] {
8+
return globbySync(globP, {cwd: baseDir});
9+
}

bench/find-in-file/index.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,25 @@ LOC_RANGES.forEach((loc) => {
1414
const targetFile = fileName(fixtureDir, loc);
1515

1616
summary(() => {
17-
// compact(() => {
17+
// compact(() => {
1818
group(`find in file; loc: ${loc}; regex: ${regex}`, () => {
1919
bench('sync', async () => {
2020
if ((await findInFileSync(targetFile, regex)).length === 0) {
21-
throw new Error('No hits found. Bench invalid.')
21+
throw new Error('No hits found. Bench invalid.');
2222
}
2323
}).gc('inner');
2424
bench('async', async () => {
2525
if ((await findInFileAsync(targetFile, regex)).length === 0) {
26-
throw new Error('No hits found. Bench invalid.')
26+
throw new Error('No hits found. Bench invalid.');
2727
}
2828
}).gc('inner');
2929
bench('stream', async () => {
3030
if ((await findInFileStream(targetFile, regex)).length === 0) {
31-
throw new Error('No hits found. Bench invalid.')
31+
throw new Error('No hits found. Bench invalid.');
3232
}
3333
}).gc('inner');
3434
})
35-
// })
35+
// })
3636
})
3737

3838
});

bench/find-in-files/README.md

+183-17
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,56 @@ export type SourceLocation = {
4949
---
5050

5151
<!-- START OVERVIEW -->
52-
The sync benchmark is the fastest.
52+
The sync generator + dir regex benchmark is the fastest.
5353

5454

55-
## find in files; count: 10930; glob: /.txt/g
55+
## dir-0-file-10000-nest-0-loc-1000-l-400; count: 10000; glob: **/file_[0-9]*.txt
5656

57-
| alias | avg (min … max) | p75 | p99 | speed |
58-
| --------------- | ----------------------------------------------------- | ---------------- | ---------------- | ------------- |
59-
| **sync** | 274001347.42 ns/iter (265857584.00 … 289608417.00) | 278807125.00 ns | 286432166.00 ns | 🔥 fastest |
60-
| async | 285903458.50 ns/iter (283222750.00 … 288366959.00) | 287662333.00 ns | 288268667.00 ns | 1.04x slower |
61-
| fastFindInFiles | 7165497163.25 ns/iter (6894166500.00 … 7383160125.00) | 7226212834.00 ns | 7371147542.00 ns | 26.15x slower |
57+
| alias | avg (min … max) | p75 | p99 | speed |
58+
| ------------------------------ | ----------------------------------------------------- | ---------------- | ---------------- | ------------ |
59+
| **sync generator + dir regex** | 2459490701.58 ns/iter (2381238083.00 … 2573007542.00) | 2463524542.00 ns | 2509002667.00 ns | 🔥 fastest |
60+
| async generator + dir regex | 2500631288.08 ns/iter (2425313875.00 … 2556074917.00) | 2512137291.00 ns | 2540765875.00 ns | 1.02x slower |
61+
| sync generator + dir globby | 2541343913.33 ns/iter (2359620917.00 … 3349688208.00) | 2513638500.00 ns | 2535446459.00 ns | 1.03x slower |
62+
63+
## dir-0-file-1000-nest-0-loc-1000-l-400; count: 1000; glob: **/file_[0-9]*.txt
64+
65+
| alias | avg (min … max) | p75 | p99 | speed |
66+
| ------------------------------ | -------------------------------------------------- | --------------- | --------------- | ------------ |
67+
| **sync generator + dir regex** | 246353395.75 ns/iter (242169083.00 … 249798417.00) | 247863625.00 ns | 248634541.00 ns | 🔥 fastest |
68+
| async generator + dir regex | 247330024.33 ns/iter (243480292.00 … 253323125.00) | 248034083.00 ns | 251851833.00 ns | 1.00x slower |
69+
| sync generator + dir globby | 250722812.42 ns/iter (237498875.00 … 280895500.00) | 251800041.00 ns | 256440250.00 ns | 1.02x slower |
70+
71+
## dir-0-file-100-nest-0-loc-1000-l-400; count: 100; glob: **/file_[0-9]*.txt
72+
73+
| alias | avg (min … max) | p75 | p99 | speed |
74+
| ------------------------------ | ----------------------------------------------- | -------------- | -------------- | ------------ |
75+
| **sync generator + dir regex** | 24735696.00 ns/iter (22698125.00 … 26135125.00) | 25185750.00 ns | 25939208.00 ns | 🔥 fastest |
76+
| sync generator + dir globby | 24898677.57 ns/iter (22948458.00 … 26883000.00) | 25538500.00 ns | 26421083.00 ns | 1.01x slower |
77+
| async generator + dir regex | 25021457.59 ns/iter (23587000.00 … 27241042.00) | 25311750.00 ns | 27109334.00 ns | 1.01x slower |
78+
79+
## dir-0-file-10-nest-0-loc-1000-l-400; count: 10; glob: **/file_[0-9]*.txt
80+
81+
| alias | avg (min … max) | p75 | p99 | speed |
82+
| ------------------------------ | -------------------------------------------- | ------------- | ------------- | ------------ |
83+
| **sync generator + dir regex** | 2516434.06 ns/iter (2271375.00 … 2912875.00) | 2599208.00 ns | 2767667.00 ns | 🔥 fastest |
84+
| async generator + dir regex | 2594183.28 ns/iter (2234875.00 … 3017417.00) | 2734958.00 ns | 2953708.00 ns | 1.03x slower |
85+
| sync generator + dir globby | 2787720.24 ns/iter (2568250.00 … 3242083.00) | 2875959.00 ns | 3082375.00 ns | 1.11x slower |
86+
87+
## dir-3-file-10-nest-3-loc-1000-l-400; count: 1180; glob: **/file_[0-9]*.txt
88+
89+
| alias | avg (min … max) | p75 | p99 | speed |
90+
| ------------------------------ | -------------------------------------------------- | --------------- | --------------- | ------------ |
91+
| **sync generator + dir regex** | 99484195.90 ns/iter (97909083.00 … 100768792.00) | 99833333.00 ns | 100416334.00 ns | 🔥 fastest |
92+
| sync generator + dir globby | 100039133.30 ns/iter (95831000.00 … 103941500.00) | 101424375.00 ns | 102131083.00 ns | 1.01x slower |
93+
| async generator + dir regex | 101394804.00 ns/iter (100386916.00 … 102983000.00) | 101338875.00 ns | 102962166.00 ns | 1.02x slower |
94+
95+
## dir-3-file-10-nest-6-loc-1000-l-400; count: 32770; glob: **/file_[0-9]*.txt
96+
97+
| alias | avg (min … max) | p75 | p99 | speed |
98+
| ------------------------------ | ----------------------------------------------------- | ---------------- | ---------------- | ------------ |
99+
| **sync generator + dir regex** | 2792778201.08 ns/iter (2744331959.00 … 2900717291.00) | 2809293208.00 ns | 2833738375.00 ns | 🔥 fastest |
100+
| async generator + dir regex | 2863397770.83 ns/iter (2823073917.00 … 2938205417.00) | 2874066458.00 ns | 2913156625.00 ns | 1.03x slower |
101+
| sync generator + dir globby | 2987521163.17 ns/iter (2686594000.00 … 5365234917.00) | 2815883833.00 ns | 2893300291.00 ns | 1.07x slower |
62102

63103
<!-- END OVERVIEW -->
64104

@@ -115,7 +155,6 @@ export default async function findInFilesAsync(
115155
for (const result of await findInFile(fullPath, pattern, bail)) {
116156
results.push(result);
117157
}
118-
119158
}
120159
});
121160

@@ -127,6 +166,74 @@ export default async function findInFilesAsync(
127166

128167
```
129168

169+
## find-in-files.fast-glob.sync.ts
170+
_[find-in-files.fast-glob.sync.ts](find-in-files/src)_
171+
```ts
172+
import {globbySync} from 'globby';
173+
import findInFile from "../../find-in-file/src/find-in-file.sync.ts";
174+
import type {SourceLocation} from "../../../src/lib/shared/types.ts";
175+
176+
177+
export default async function findInFiles(
178+
baseDir: string,
179+
globPatterns: string | string[],
180+
pattern: string,
181+
bail = false
182+
): Promise<SourceLocation[]> {
183+
// Get absolute file paths for all matched files
184+
const filePaths = globbySync(globPatterns, {cwd: baseDir, absolute: true});
185+
186+
const results: SourceLocation[] = [];
187+
188+
for (const filePath of filePaths) {
189+
190+
for (const match of await findInFile(filePath, pattern, bail)) {
191+
results.push(match);
192+
if (bail) {
193+
return results;
194+
}
195+
}
196+
}
197+
198+
return results;
199+
}
200+
201+
```
202+
203+
## find-in-files.globby.sync.ts
204+
_[find-in-files.globby.sync.ts](find-in-files/src)_
205+
```ts
206+
import {globbySync} from 'globby';
207+
import findInFile from "../../find-in-file/src/find-in-file.sync.ts";
208+
import type {SourceLocation} from "../../../src/lib/shared/types.ts";
209+
210+
211+
export default async function findInFiles(
212+
baseDir: string,
213+
globPatterns: string | string[],
214+
pattern: string,
215+
bail = false
216+
): Promise<SourceLocation[]> {
217+
// Get absolute file paths for all matched files
218+
const filePaths = globbySync(globPatterns, {cwd: baseDir, absolute: true});
219+
220+
const results: SourceLocation[] = [];
221+
222+
for (const filePath of filePaths) {
223+
224+
for (const match of await findInFile(filePath, pattern, bail)) {
225+
results.push(match);
226+
if (bail) {
227+
return results;
228+
}
229+
}
230+
}
231+
232+
return results;
233+
}
234+
235+
```
236+
130237
## find-in-files.sync.ts
131238
_[find-in-files.sync.ts](find-in-files/src)_
132239
```ts
@@ -159,9 +266,13 @@ export default async function findInFiles(
159266
const fullPath = path.join(dir, entry.name);
160267
if (entry.isDirectory()) {
161268
queue.push(fullPath);
162-
} else if (entry.isFile() && fullPath.match(glob)) {
269+
} else if (entry.isFile() && fullPath.match(glob)
270+
) {
163271
for (const result of await findInFile(fullPath, pattern, bail)) {
164272
results.push(result);
273+
if (bail) {
274+
return results;
275+
}
165276
}
166277
}
167278
}
@@ -180,22 +291,77 @@ export default async function findInFiles(
180291

181292
<!-- START DATA -->
182293
```bash
183-
clk: ~3.47 GHz
294+
clk: ~3.36 GHz
184295
cpu: Apple M2 Max
185296
runtime: node 23.9.0 (arm64-darwin)
186297

187298
benchmark avg (min … max) p75 / p99 (min … top 1%)
188299
------------------------------------------- -------------------------------
189-
• find in files; count: 10930; glob: /.txt/g
300+
• dir-0-file-10000-nest-0-loc-1000-l-400; count: 10000; glob: **/file_[0-9]*.txt
301+
------------------------------------------- -------------------------------
302+
sync generator + dir globby 2.63 s/iter 2.47 s 2.54 s ▃▁▁▆▃█▁▃▁▁▃
303+
sync generator + dir regex 2.44 s/iter 2.45 s 2.47 s ▃▁▃▁▁▁█▅▃▃▃
304+
async generator + dir regex 2.50 s/iter 2.51 s 2.52 s ▃▁▁█▃▃▃▁▃▆▃
305+
306+
summary
307+
sync generator + dir regex
308+
1.02x faster than async generator + dir regex
309+
1.08x faster than sync generator + dir globby
310+
311+
• dir-0-file-1000-nest-0-loc-1000-l-400; count: 1000; glob: **/file_[0-9]*.txt
312+
------------------------------------------- -------------------------------
313+
sync generator + dir globby 242.63 ms/iter 244.25 ms 246.80 ms ▃▁▃▃▁█▆▃▃▁▃
314+
sync generator + dir regex 242.00 ms/iter 243.43 ms 244.89 ms ▃▆▁█▃▁▁▆▁▃▃
315+
async generator + dir regex 244.29 ms/iter 244.55 ms 247.90 ms ▃▁▆▃█▃▆▁▁▁▃
316+
317+
summary
318+
sync generator + dir regex
319+
1x faster than sync generator + dir globby
320+
1.01x faster than async generator + dir regex
321+
322+
• dir-0-file-100-nest-0-loc-1000-l-400; count: 100; glob: **/file_[0-9]*.txt
323+
------------------------------------------- -------------------------------
324+
sync generator + dir globby 24.47 ms/iter 24.86 ms 25.75 ms ▂▁▂▄▅▄█▅▄▃▂
325+
sync generator + dir regex 24.55 ms/iter 25.21 ms 25.91 ms ▄▄▃▄▅█▇▄▇▄▃
326+
async generator + dir regex 25.40 ms/iter 25.87 ms 26.30 ms ▄█▄▄█▂▆▅▅▆▃
327+
328+
summary
329+
sync generator + dir globby
330+
1x faster than sync generator + dir regex
331+
1.04x faster than async generator + dir regex
332+
333+
• dir-0-file-10-nest-0-loc-1000-l-400; count: 10; glob: **/file_[0-9]*.txt
334+
------------------------------------------- -------------------------------
335+
sync generator + dir globby 2.78 ms/iter 2.86 ms 3.18 ms ▁▃▅██▇▅▃▂▂▁
336+
sync generator + dir regex 2.34 ms/iter 2.37 ms 2.65 ms ▃▅█▇▆▃▂▁▁▁▁
337+
async generator + dir regex 2.54 ms/iter 2.66 ms 2.85 ms ▃▅▄▄▆▅█▆▆▄▂
338+
339+
summary
340+
sync generator + dir regex
341+
1.09x faster than async generator + dir regex
342+
1.19x faster than sync generator + dir globby
343+
344+
• dir-3-file-10-nest-3-loc-1000-l-400; count: 1180; glob: **/file_[0-9]*.txt
345+
------------------------------------------- -------------------------------
346+
sync generator + dir globby 99.75 ms/iter 100.06 ms 100.36 ms ▅▁▁▅▅▁▅▅█▅▅
347+
sync generator + dir regex 98.01 ms/iter 99.12 ms 99.89 ms █▁▁█▁▅▁▅▅▅▅
348+
async generator + dir regex 103.67 ms/iter 104.53 ms 104.88 ms ▅█▁▅▁▁█▁▁█▅
349+
350+
summary
351+
sync generator + dir regex
352+
1.02x faster than sync generator + dir globby
353+
1.06x faster than async generator + dir regex
354+
355+
• dir-3-file-10-nest-6-loc-1000-l-400; count: 32770; glob: **/file_[0-9]*.txt
190356
------------------------------------------- -------------------------------
191-
sync 292.95 ms/iter 293.07 ms 300.01 ms ▃▆▁▆▃▃█▁▁▁
192-
async 300.86 ms/iter 304.60 ms 309.55 ms ▅▅▁██▅▅▅▅▁▅
193-
fastFindInFiles 7.24 s/iter 7.30 s 7.44 s ▃▃█▁▁█▃▁▁▃▃
357+
sync generator + dir globby 3.13 s/iter 2.79 s 4.46 s █▃▁▁▁▁▁▁▁▁▂
358+
sync generator + dir regex 2.76 s/iter 2.77 s 2.79 s ▃▁▆▃▃█▃▃▁▁▃
359+
async generator + dir regex 2.83 s/iter 2.85 s 2.88 s ▅▅▅▅▅▅▁▅█▅▅
194360

195361
summary
196-
sync
197-
1.03x faster than async
198-
24.73x faster than fastFindInFiles
362+
sync generator + dir regex
363+
1.03x faster than async generator + dir regex
364+
1.13x faster than sync generator + dir globby
199365

200366
```
201367

0 commit comments

Comments
 (0)