Skip to content

Commit 5c13d45

Browse files
committed
chore: wip
1 parent c2377f4 commit 5c13d45

File tree

8 files changed

+1116
-12
lines changed

8 files changed

+1116
-12
lines changed
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
# File Detection Performance Comparison
2+
3+
This benchmark compares the performance of different approaches for detecting project configuration files in directory trees, specifically comparing the current shell-based implementation with custom Bun/TypeScript alternatives.
4+
5+
## 🎯 Key Findings
6+
7+
The Bun-based approaches are **dramatically faster** than the current shell implementation:
8+
9+
- **Bun Direct (sync)**: **99.2% faster** on average
10+
- **Bun Glob (async)**: **98.9% faster** on average
11+
12+
## 📊 Detailed Results
13+
14+
| Test Scenario | Bun Direct | Bun Glob | Shell (Current) | Speed Improvement |
15+
|---------------|------------|----------|-----------------|-------------------|
16+
| Shallow (3 levels) | 0.12ms | 0.27ms | 24.85ms | **99.5% faster** |
17+
| Medium (7 levels) | 0.31ms | 0.74ms | 49.96ms | **99.4% faster** |
18+
| Deep (15 levels) | 0.72ms | 0.94ms | 89.68ms | **99.2% faster** |
19+
| Very Deep (25 levels) | 1.39ms | 1.53ms | 143.67ms | **99.0% faster** |
20+
21+
## 🔍 Analysis
22+
23+
### Current Shell Approach
24+
```bash
25+
files=$(ls -1a "$dir" 2>/dev/null | grep -E '^(dependencies|deps|pkgx|launchpad)\.(yaml|yml)$|^package\.json$|...' | head -1)
26+
```
27+
28+
**Pros:**
29+
- ✅ Works in any environment (no runtime dependencies)
30+
- ✅ Leverages optimized shell commands (`ls`, `grep`)
31+
- ✅ Consistent performance regardless of directory depth
32+
33+
**Cons:**
34+
-**Significant process overhead** (spawning shell, pipes, regex)
35+
-**Poor scalability** - gets slower with deeper directory trees
36+
-**25-140ms per lookup** depending on depth
37+
38+
### Bun Direct Approach (Recommended)
39+
```typescript
40+
for (const file of PROJECT_FILES) {
41+
const filePath = join(currentDir, file)
42+
if (existsSync(filePath)) {
43+
return currentDir
44+
}
45+
}
46+
```
47+
48+
**Pros:**
49+
-**Fastest performance** (0.12-1.39ms)
50+
-**No async overhead**
51+
-**Simple, readable implementation**
52+
-**Excellent scalability**
53+
-**Direct file system calls**
54+
55+
**Cons:**
56+
- ❌ Requires Node.js/Bun runtime
57+
- ❌ Multiple `existsSync` calls (though still faster)
58+
59+
### Bun Glob Approach
60+
```typescript
61+
const glob = new Glob(`{${PROJECT_FILES.join(',')}}`)
62+
for await (const file of glob.scan({ cwd: currentDir, onlyFiles: true })) {
63+
return currentDir // Found a match
64+
}
65+
```
66+
67+
**Pros:**
68+
-**Very fast performance** (0.27-1.53ms)
69+
-**Flexible pattern matching**
70+
-**Single glob operation per directory**
71+
72+
**Cons:**
73+
-**Async overhead** (slightly slower than direct approach)
74+
- ❌ Requires Node.js/Bun runtime
75+
- ❌ More complex implementation
76+
77+
## 🚀 Performance Characteristics
78+
79+
### Scaling with Directory Depth
80+
81+
| Depth | Shell Time | Bun Direct | Bun Glob | Shell Overhead |
82+
|-------|------------|------------|----------|----------------|
83+
| 3 levels | 24.85ms | 0.12ms | 0.27ms | **207x slower** |
84+
| 7 levels | 49.96ms | 0.31ms | 0.74ms | **161x slower** |
85+
| 15 levels | 89.68ms | 0.72ms | 0.94ms | **124x slower** |
86+
| 25 levels | 143.67ms | 1.39ms | 1.53ms | **103x slower** |
87+
88+
**Key Observations:**
89+
- Shell approach has **linear degradation** with depth
90+
- Bun approaches scale much better
91+
- The deeper the directory tree, the more pronounced the performance difference
92+
93+
## 💡 Recommendations
94+
95+
### 1. **Primary Recommendation: Hybrid Approach**
96+
97+
Implement a hybrid solution that uses Bun when available, falls back to shell:
98+
99+
```typescript
100+
function findProjectRoot(startDir: string): string | null {
101+
// Try Bun approach first (when in Node.js/Bun environment)
102+
if (typeof process !== 'undefined') {
103+
return findProjectRootBunSync(startDir)
104+
}
105+
106+
// Fallback to shell approach
107+
return findProjectRootShell(startDir)
108+
}
109+
```
110+
111+
### 2. **For Pure Performance: Bun Direct**
112+
113+
If you can guarantee a Node.js/Bun runtime, use the direct file system approach:
114+
- **99.2% faster** than current implementation
115+
- Simple, maintainable code
116+
- Excellent scalability
117+
118+
### 3. **For Flexibility: Bun Glob**
119+
120+
If you need more complex pattern matching or plan to extend file detection:
121+
- **98.9% faster** than current implementation
122+
- More flexible for future enhancements
123+
- Slightly more overhead due to async nature
124+
125+
## 🔧 Implementation Impact
126+
127+
### Current Usage Patterns
128+
The file detection is used in:
129+
- Shell integration (`__lp_find_deps_dir`)
130+
- Project root discovery
131+
- Development environment setup
132+
133+
### Migration Considerations
134+
1. **Backward Compatibility**: Keep shell version for environments without Node.js
135+
2. **Runtime Detection**: Detect available runtime and choose appropriate method
136+
3. **Caching**: Both approaches benefit from the existing caching mechanism
137+
4. **Error Handling**: Ensure graceful fallback between approaches
138+
139+
## 🧪 Running the Benchmark
140+
141+
```bash
142+
cd packages/launchpad/benchmark
143+
bun install
144+
bun run file-detection-comparison.ts
145+
```
146+
147+
The benchmark creates temporary directory structures at various depths and measures the time to find project files, providing comprehensive performance data across different scenarios.
148+
149+
## 📈 Conclusion
150+
151+
The performance difference is **dramatic and consistent**:
152+
- Bun approaches are **~100x faster** than the shell approach
153+
- The performance gap **increases** with directory depth
154+
- Implementation complexity is **minimal** for the Bun direct approach
155+
156+
**Recommendation**: Implement the hybrid approach with Bun Direct as primary and shell as fallback for maximum performance while maintaining compatibility.

packages/launchpad/benchmark/bun.lock

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"lockfileVersion": 1,
3+
"workspaces": {
4+
"": {
5+
"name": "@launchpad/benchmark",
6+
"dependencies": {
7+
"bun-types": "latest",
8+
},
9+
},
10+
},
11+
"packages": {
12+
"@types/node": ["@types/[email protected]", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow=="],
13+
14+
"@types/react": ["@types/[email protected]", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg=="],
15+
16+
"bun-types": ["[email protected]", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-pxTnQYOrKvdOwyiyd/7sMt9yFOenN004Y6O4lCcCUoKVej48FS5cvTw9geRaEcB9TsDZaJKAxPTVvi8tFsVuXA=="],
17+
18+
"csstype": ["[email protected]", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
19+
20+
"undici-types": ["[email protected]", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="],
21+
}
22+
}

0 commit comments

Comments
 (0)