|
| 1 | +--- |
| 2 | +title: TypeScript Benchmarking |
| 3 | +weight: 6 |
| 4 | + |
| 5 | +### FIXED, DO NOT MODIFY |
| 6 | +layout: learningpathall |
| 7 | +--- |
| 8 | + |
| 9 | + |
| 10 | +## JMH-style Custom Benchmarking |
| 11 | + |
| 12 | +This section demonstrates how to **benchmark TypeScript functions** using a JMH-style approach with Node.js `perf_hooks`. Unlike simple `console.time` timing, this method performs **repeated iterations**, calculates the **average execution time**, and provides more **reliable and stable performance measurements** on your Arm64 SUSE VM. |
| 13 | + |
| 14 | +### Create the Benchmark Script |
| 15 | +Create a file named `benchmark_jmh.ts` in your project folder: |
| 16 | + |
| 17 | +```typescript |
| 18 | +import { performance } from 'perf_hooks'; |
| 19 | + |
| 20 | +// Function to benchmark |
| 21 | +const sumArray = (n: number) => { |
| 22 | + let sum = 0; |
| 23 | + for (let i = 0; i < n; i++) sum += i; |
| 24 | + return sum; |
| 25 | +}; |
| 26 | + |
| 27 | +// Benchmark parameters |
| 28 | +const iterations = 10; // Number of repeated runs |
| 29 | +const arraySize = 1_000_000; // Size of array |
| 30 | +let totalTime = 0; |
| 31 | + |
| 32 | +// JMH-style repeated runs |
| 33 | +for (let i = 0; i < iterations; i++) { |
| 34 | + const start = performance.now(); |
| 35 | + sumArray(arraySize); |
| 36 | + const end = performance.now(); |
| 37 | + const timeTaken = end - start; |
| 38 | + totalTime += timeTaken; |
| 39 | + console.log(`Iteration ${i + 1}: ${timeTaken.toFixed(3)} ms`); |
| 40 | +} |
| 41 | + |
| 42 | +// Compute average execution time |
| 43 | +const averageTime = totalTime / iterations; |
| 44 | +console.log(`\nAverage execution time over ${iterations} iterations: ${averageTime.toFixed(3)} ms`); |
| 45 | +``` |
| 46 | + |
| 47 | +- **`performance.now()`** → Provides a high-resolution timestamp in milliseconds for precise timing measurements. |
| 48 | +- **`sumArray`** → A sample CPU-bound function that sums numbers from 0 to `n`. |
| 49 | +- **`iterations`** → Defines how many times the benchmark should run to stabilize results and minimize random variations. |
| 50 | +- **`for` loop** → Executes the target function multiple times and records the duration of each run. |
| 51 | +- **`totalTime / iterations`** → Calculates the **average execution time** across all runs, similar to how **JMH (Java Microbenchmark Harness)** operates in Java. |
| 52 | + |
| 53 | +This JMH-style benchmarking approach provides **more accurate and repeatable performance metrics** than a single execution, making it ideal for performance testing on Arm-based systems. |
| 54 | + |
| 55 | +### Compile the TypeScript Benchmark |
| 56 | +Compile the TypeScript benchmark file into JavaScript: |
| 57 | + |
| 58 | +```console |
| 59 | +tsc benchmark_jmh.ts |
| 60 | +``` |
| 61 | +This generates a `benchmark_jmh.js` file that can be executed by Node.js. |
| 62 | + |
| 63 | +### Run the Benchmark |
| 64 | +Execute the compiled JavaScript file: |
| 65 | + |
| 66 | +```console |
| 67 | +node benchmark_jmh.js |
| 68 | +``` |
| 69 | +You should see an output similar to: |
| 70 | + |
| 71 | +```output |
| 72 | +Iteration 1: 2.286 ms |
| 73 | +Iteration 2: 0.749 ms |
| 74 | +Iteration 3: 1.145 ms |
| 75 | +Iteration 4: 0.674 ms |
| 76 | +Iteration 5: 0.671 ms |
| 77 | +Iteration 6: 0.671 ms |
| 78 | +Iteration 7: 0.672 ms |
| 79 | +Iteration 8: 0.667 ms |
| 80 | +Iteration 9: 0.667 ms |
| 81 | +Iteration 10: 0.673 ms |
| 82 | +
|
| 83 | +Average execution time over 10 iterations: 0.888 ms |
| 84 | +``` |
| 85 | + |
| 86 | +### Benchmark Metrics Explained |
| 87 | + |
| 88 | +- **Iteration times** → Each iteration shows the **time taken for a single execution** of the function being benchmarked. |
| 89 | +- **Average execution time** → Calculated as the sum of all iteration times divided by the number of iterations. This provides a **stable measure of typical performance**. |
| 90 | +- **Why multiple iterations?** |
| 91 | + - Single-run timing can be inconsistent due to factors such as CPU scheduling, memory allocation, or caching. |
| 92 | + - Repeating the benchmark multiple times and averaging reduces variability and gives **more reliable performance results**, similar to Java’s JMH benchmarking approach. |
| 93 | +**Interpretation:** |
| 94 | +- The average execution time reflects how efficient the function is under normal conditions. |
| 95 | +- Initial iterations may take longer due to **initialization overhead**, which is common in Node.js performance tests. |
| 96 | + |
| 97 | +### Benchmark summary on x86_64 |
| 98 | +To compare the benchmark results, the following results were collected by running the same benchmark on a `x86 - c4-standard-4` (4 vCPUs, 15 GB Memory) x86_64 VM in GCP, running SUSE: |
| 99 | + |
| 100 | +| Iteration | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Average | |
| 101 | +|-----------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|---------| |
| 102 | +| Time (ms) | 3.217 | 0.631 | 0.632 | 0.611 | 0.612 | 0.614 | 0.614 | 0.611 | 0.606 | 0.532 | 0.868 | |
| 103 | + |
| 104 | +### Benchmark summary on Arm64 |
| 105 | +Results from the earlier run on the `c4a-standard-4` (4 vCPU, 16 GB memory) Arm64 VM in GCP (SUSE): |
| 106 | + |
| 107 | +| Iteration | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Average | |
| 108 | +|-----------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|---------| |
| 109 | +| Time (ms) | 2.286 | 0.749 | 1.145 | 0.674 | 0.671 | 0.671 | 0.672 | 0.667 | 0.667 | 0.673 | 0.888 | |
| 110 | + |
| 111 | +### TypeScript performance benchmarking comparison on Arm64 and x86_64 |
| 112 | + |
| 113 | +When you compare the benchmarking results, you will notice that on the Google Axion C4A Arm-based instances: |
| 114 | + |
| 115 | +- The average execution time on Arm64 (~0.888 ms) shows that CPU-bound TypeScript operations run efficiently on Arm-based VMs. |
| 116 | +- Initial iterations may show slightly higher times due to runtime warm-up and optimization overhead, which is common across architectures. |
| 117 | +- Arm64 demonstrates stable iteration times after the first run, indicating consistent performance for repeated workloads. |
| 118 | +- Compared to typical x86_64 VMs, Arm64 performance is comparable for lightweight TypeScript computations, with potential advantages in power efficiency and cost for cloud deployments. |
0 commit comments