Add two-step measurement method, Gantt diagrams, and update README with accurate results

This commit is contained in:
Ein Anderssono
2026-04-24 01:50:49 +02:00
parent 2c9369c869
commit 9a28dc5f80
17 changed files with 1401 additions and 155 deletions
+77 -99
View File
@@ -53,150 +53,128 @@ Detailed performance reports are available for each decimal precision level:
- **[1000 Decimals](reports/1000_decimals.md)** - Very high precision
- **[2000 Decimals](reports/2000_decimals.md)** - Extreme precision
## Summary Results (100 Decimals)
## Summary Results (100 Decimals - No Measurement Overhead)
**Important:** These results use a two-step measurement method to eliminate the ~10ms overhead from measurement tools. This gives accurate timing for fast programs.
### All Languages Performance
| Rank | Language | Time (ms) | Memory (bytes) | Type |
|------|-----------|-----------|----------------|------|
| 1 | Odin | 19 | 1,725,781 | Compiled |
| 2 | Assembly | 20 | 1,409,024 | Compiled |
| 3 | Nim | 20 | 1,572,864 | Compiled |
| 4 | Rust | 20 | 1,682,096 | Compiled |
| 5 | Lua | 20 | 2,086,229 | Interpreted |
| 6 | Objective-C | 20 | 6,045,696 | Compiled |
| 7 | Swift | 20 | 5,947,392 | Compiled |
| 8 | Zig | 22 | 2,981,888 | Compiled |
| 9 | C++ | 23 | 1,490,944 | Compiled |
| 10 | Go | 24 | 3,932,160 | Compiled |
| 11 | C | 25 | 1,671,168 | Compiled |
| 12 | D | 30 | 2,457,600 | Compiled |
| 13 | Bash | 30 | 2,058,922 | Interpreted |
| 14 | Fortran | 31 | 1,802,240 | Compiled |
| 15 | Crystal | 32 | 3,244,032 | Compiled |
| 16 | Dart | 34 | 14,488,917 | JIT |
| 17 | Haskell | 40 | 11,894,784 | Compiled |
| 18 | Java | 46 | 43,078,997 | JIT |
| 19 | Python | 47 | 9,693,866 | Interpreted |
| 20 | Perl | 47 | 12,528,298 | Interpreted |
| 21 | Brainfuck | 50 | 9,267,882 | Interpreted |
| 22 | Kotlin | 60 | 45,247,146 | JIT |
| 23 | C# | 66 | 41,473,365 | JIT |
| 24 | PHP | 68 | 26,487,466 | Interpreted |
| 25 | Ruby | 79 | 28,824,917 | Interpreted |
| 26 | JavaScript | 89 | 44,848,469 | JIT |
| 27 | Julia | 157 | 235,885,909 | JIT |
| 28 | R | 163 | 90,947,584 | Interpreted |
| 29 | Erlang | 176 | 77,359,786 | Interpreted |
| 30 | Scala | 344 | 55,470,762 | JIT |
| 31 | Elixir | 401 | 89,205,418 | Interpreted |
| 32 | TypeScript | 931 | 218,868,394 | JIT |
| Rank | Language | Time (ms) | Type |
|------|-----------|-----------|------|
| 1 | C | 4 | Compiled |
| 2 | C++ | 4 | Compiled |
| 3 | Go | 4 | Compiled |
| 4 | Nim | 4 | Compiled |
| 5 | Odin | 4 | Compiled |
| 6 | Rust | 4 | Compiled |
| 7 | Crystal | 5 | Compiled |
| 8 | Fortran | 5 | Compiled |
| 9 | Objective-C | 5 | Compiled |
| 10 | Assembly | 6 | Compiled |
| 11 | Swift | 6 | Compiled |
| 12 | D | 8 | Compiled |
| 13 | Lua | 9 | Interpreted |
| 14 | Zig | 9 | Compiled |
| 15 | Bash | 12 | Interpreted |
| 16 | Dart | 17 | JIT |
| 17 | Haskell | 19 | Compiled |
| 18 | Brainfuck | 28 | Interpreted |
| 19 | Perl | 31 | Interpreted |
| 20 | Python | 33 | Interpreted |
| 21 | Java | 34 | JIT |
| 22 | C# | 37 | JIT |
| 23 | Kotlin | 41 | JIT |
| 24 | PHP | 53 | Interpreted |
| 25 | Ruby | 59 | Interpreted |
| 26 | JavaScript | 68 | JIT |
| 27 | Erlang | 114 | Interpreted |
| 28 | Julia | 124 | JIT |
| 29 | R | 206 | Interpreted |
| 30 | Elixir | 310 | Interpreted |
| 31 | Scala | 378 | JIT |
| 32 | TypeScript | 970 | JIT |
### Language Categories
**Compiled Languages (Native Code):**
- Fastest execution (9-35 ms)
- Minimal memory usage (0-966,656 bytes)
- Fastest execution (4-9 ms)
- Minimal memory usage
- Consistent performance across decimal levels
**JIT-Compiled Languages:**
- Moderate execution time (31-290 ms)
- Higher memory usage (~2 MB)
- Moderate execution time (17-970 ms)
- Higher memory usage
- Good performance after warmup
**Interpreted Languages:**
- Variable execution time (29-898 ms)
- Moderate memory usage (~2 MB)
- Variable execution time (9-310 ms)
- Moderate memory usage
- Performance varies widely
## Key Findings
1. **Compiled languages dominate**: Assembly, Rust, Nim, Odin, C, C++ all execute in 19-25 ms
2. **Memory efficiency varies**:
- Compiled languages: 1.4-6.0 MB (Assembly lowest at 1.4 MB)
- Go with runtime: 3.9 MB
- JVM languages: 41-55 MB
- Interpreted languages: 9-29 MB
- Julia: 236 MB (JIT + scientific libraries)
1. **Compiled languages dominate**: C, C++, Go, Nim, Odin, Rust all execute in 4-6 ms
2. **No measurement overhead**: Using two-step method eliminates ~10ms overhead from measurement tools
3. **Performance scaling**: Compiled languages maintain consistent performance across all decimal levels
4. **JIT overhead**: Java, Kotlin, Scala show startup overhead but good performance after warmup
5. **Interpreted languages**: Python, Perl, PHP, Ruby show moderate performance (47-79 ms)
6. **Memory fix applied**: All languages now show correct memory values using `/usr/bin/time -l` on macOS
5. **Interpreted languages**: Python, Perl, PHP, Ruby show moderate performance (31-59 ms)
6. **Two-step method**:
- Step 1: Fast test (no overhead) for accurate timing
- Step 2: Detailed trace for execution phases (Gantt diagrams)
## Performance Analysis by Language Type
### Compiled Languages (Native Code)
- **Fastest execution**: 19-32 ms
- **Minimal memory**: 1.4-6.0 MB
- **Best performers**: Assembly, Rust, Nim, Odin, C, C++
- **Fastest execution**: 4-9 ms
- **Minimal memory**: Low overhead
- **Best performers**: C, C++, Go, Nim, Odin, Rust (all 4-6 ms)
- **Why fast**: Direct machine code, no runtime overhead, no garbage collection
### JIT-Compiled Languages
- **Moderate execution**: 34-931 ms
- **Higher memory**: 14-236 MB
- **Best performers**: Java (46 ms), Kotlin (60 ms), Dart (34 ms)
- **Moderate execution**: 17-970 ms
- **Higher memory**: Runtime overhead
- **Best performers**: Dart (17 ms), Java (34 ms), Kotlin (41 ms)
- **Why moderate**: JIT compilation overhead, runtime initialization
### Interpreted Languages
- **Variable execution**: 20-401 ms
- **Moderate memory**: 2-29 MB
- **Best performers**: Lua (20 ms), Python (47 ms), Perl (47 ms)
- **Variable execution**: 9-310 ms
- **Moderate memory**: Runtime overhead
- **Best performers**: Lua (9 ms), Bash (12 ms), Python (33 ms)
- **Why variable**: Interpretation overhead, dynamic typing
### Functional Languages
- **Mixed performance**: 40-401 ms
- **Higher memory**: 12-90 MB
- **Best performers**: Haskell (40 ms), Erlang (176 ms)
- **Mixed performance**: 19-310 ms
- **Higher memory**: Runtime overhead
- **Best performers**: Haskell (19 ms), Erlang (114 ms)
- **Why mixed**: Functional paradigms, immutability, pattern matching
## Detailed Language Analysis
### Top Performers (Rank 1-10)
#### 1. Odin (19 ms, 1.7 MB) - Fastest
#### 1-6. C, C++, Go, Nim, Odin, Rust (4 ms) - Fastest
**Why fastest:**
- **Modern systems language** - Designed for performance
- **No GC** - Manual memory management
- **Direct compilation** - No intermediate representations
- **Minimal runtime** - Small standard library
- **Optimized for speed** - Built for game development
- **Direct compilation** - All compile to native machine code
- **No runtime overhead** - Minimal or no garbage collection
- **Optimized BigInt** - Efficient arbitrary precision arithmetic
- **Low-level control** - Direct memory management
- **Mature compilers** - Years of optimization work
**Implementation:**
- Uses Machin's formula with custom BigInt
- All use Machin's formula with efficient BigInt
- Direct compilation to machine code
- Very low overhead (1.7 MB)
- No interpreter or VM overhead
#### 2. Assembly (20 ms, 1.4 MB) - Most Efficient
**Why efficient:**
- **Direct machine code** - No compiler overhead, optimal instructions
- **No runtime** - Only necessary code, no overhead
- **Optimal memory** - Minimal allocations, precise control
- **No abstractions** - Direct hardware access
- **Manual optimization** - Every instruction optimized by hand
#### 7-9. Crystal, Fortran, Objective-C (5 ms) - Very Fast
**Why very fast:**
- **Crystal**: Ruby-like syntax, compiles to native code
- **Fortran**: Optimized for numerical computation
- **Objective-C**: C with Smalltalk-style OOP
**Implementation:**
- Uses Machin's formula with manual BigInt operations
- Direct register manipulation for arithmetic
- No function call overhead
- Minimal memory footprint (1.4 MB)
#### 3. Nim (20 ms, 1.5 MB) - Fast
#### 10-11. Assembly, Swift (6 ms) - Fast
**Why fast:**
- **Compiles to C** - Leverages C compiler optimizations
- **Minimal runtime** - Small standard library overhead
- **Efficient GC** - Optional garbage collector, can be disabled
- **Direct compilation** - No intermediate bytecode
- **Optimized for speed** - Designed for performance
**Implementation:**
- Compiles Nim code to C, then to machine code
- Uses Machin's formula with efficient BigInt
- Minimal runtime overhead (1.5 MB)
#### 4. Rust (20 ms, 1.6 MB) - Fast
**Why fast:**
- **Optimized BigInt library** - `num-bigint` crate with years of optimization
- **Mature compiler** - LLVM backend with aggressive optimizations
- **Assembly**: Hand-optimized machine code
- **Swift**: LLVM compiler with optimizations
- **Zero-cost abstractions** - High-level code compiles to efficient machine code
- **No garbage collection** - Manual memory management with safety guarantees
- **Optimized allocator** - Efficient memory allocation