Skip to content

Commit 8f78d05

Browse files
committed
test: add performance tests
1 parent eb8853a commit 8f78d05

File tree

5 files changed

+216
-22
lines changed

5 files changed

+216
-22
lines changed

packages/machine-id/README.md

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ Or use it directly in the CLI
1414
npx @mongodb-js/machine-id
1515
```
1616

17-
1817
## Usage
1918

2019
### As a module
@@ -29,45 +28,42 @@ const id = getMachineID({ raw: true });
2928
console.log('Original Machine ID:', id);
3029
```
3130

32-
### As a CLI
31+
## Comparison with `node-machine-id`
3332

34-
After installing globally, run:
33+
This module provides similar functionality to [node-machine-id](https://www.npmjs.com/package/node-machine-id), but **using native access to system APIs without the need for child processes**, making it much faster and reliable.
34+
35+
Here's a table of performance comparisons between the two libraries, based on the average runtime from 1000 iterations of the `getMachineId` and `machineIdSync` functions:
36+
37+
| Test | node-machine-id | @mongodb-js/machine-id | Improvement |
38+
| --- | --- | --- | ---- |
39+
| Mac - Raw ID | 5.68ms | 0.0065ms | 819x |
40+
| Mac - Hashed ID | 5.55ms | 0.01ms | 527x |
3541

36-
```
37-
machine-id
38-
```
3942

40-
This will print the machine ID to the console.
4143

42-
## Comparison with `node-machine-id`
43-
This module provides similar functionality to [node-machine-id](https://www.npmjs.com/package/node-machine-id), but **using native access to system APIs without the need for child processes**.
4444

4545
If you were previously using `node-machine-id`, you can use the following mapping to get a result that uses the same hashing transformation. This helps create more consistent results as before but it is not guaranteed to be the same for all cases.
46+
4647
```ts
4748
import { createHash } from 'crypto';
4849
import { getMachineId } from '@mongodb-js/machine-id';
4950

5051
function machineIdSync(original: boolean): string | undefined {
51-
const rawMachineId = getMachineId({ raw: true }).toLowerCase();
52+
const rawMachineId = getMachineId({ raw: true }).toLowerCase();
5253

53-
if (original) {
54-
return rawMachineId;
55-
}
54+
if (original) {
55+
return rawMachineId;
56+
}
5657

57-
return createHash("sha256")
58-
.update(rawMachineId)
59-
.digest("hex");
58+
return createHash('sha256').update(rawMachineId).digest('hex');
6059
}
61-
6260
```
6361

6462
## Supported Platforms
6563

6664
- **macOS**: Uses the `IOPlatformUUID` from the `IOKit` framework (Supported on macOS 12.0 and later).
6765
- **Linux**: Uses the `/etc/machine-id` file to retrieve the machine ID. If this file does not exist, it falls back to `/var/lib/dbus/machine-id`.
68-
- **Windows**: Uses the `MachineGuid` from the `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography` registry.
69-
70-
66+
- **Windows**: Uses the `MachineGuid` from the `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography` registry.
7167

7268
## License
7369

packages/machine-id/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
"test-ci": "npm run test",
1313
"lint": "eslint . && prettier --check .",
1414
"check": "npm run lint && npm run test",
15-
"prepublishOnly": "npm run compile"
15+
"prepublishOnly": "npm run compile",
16+
"benchmark": "ts-node scripts/benchmark.ts"
1617
},
1718
"author": "Compass Team <[email protected]>",
1819
"gypfile": true,
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#!/usr/bin/env node
2+
/* eslint-disable no-console */
3+
/**
4+
* Performance comparison script for machine-id vs node-machine-id
5+
*
6+
* This script measures and compares the performance of @mongodb-js/machine-id
7+
* against the node-machine-id package.
8+
*/
9+
10+
import { getMachineId } from '../dist/index.js';
11+
import { machineIdSync } from 'node-machine-id';
12+
13+
// Configuration
14+
const ITERATIONS = 100;
15+
const WARMUP_ITERATIONS = 10;
16+
17+
// Utility to format time
18+
function formatTime(ms: number): string {
19+
if (ms < 1) {
20+
return `${(ms * 1000).toFixed(2)}µs`;
21+
}
22+
return `${ms.toFixed(2)}ms`;
23+
}
24+
25+
// Utility to format comparison
26+
function formatComparison(time1: number, time2: number): string {
27+
if (time1 < time2) {
28+
return `${(time2 / time1).toFixed(2)}x faster`;
29+
} else {
30+
return `${(time1 / time2).toFixed(2)}x slower`;
31+
}
32+
}
33+
34+
function runBenchmark() {
35+
console.log('========================================');
36+
console.log('Machine ID Performance Benchmark');
37+
console.log('========================================');
38+
console.log(`Platform: ${process.platform}`);
39+
console.log(`Node.js version: ${process.version}`);
40+
console.log(`Test iterations: ${ITERATIONS}`);
41+
console.log('----------------------------------------');
42+
43+
// Warm-up
44+
console.log('Warming up...');
45+
for (let i = 0; i < WARMUP_ITERATIONS; i++) {
46+
getMachineId({ raw: true });
47+
machineIdSync(true);
48+
}
49+
50+
// Test raw mode (no hashing)
51+
console.log('\nRaw machine ID retrieval:');
52+
53+
const startOursRaw = process.hrtime.bigint();
54+
for (let i = 0; i < ITERATIONS; i++) {
55+
getMachineId({ raw: true });
56+
}
57+
const endOursRaw = process.hrtime.bigint();
58+
const ourTimeRaw = Number(endOursRaw - startOursRaw) / 1_000_000; // ms
59+
60+
// node-machine-id
61+
const startOtherRaw = process.hrtime.bigint();
62+
for (let i = 0; i < ITERATIONS; i++) {
63+
machineIdSync(true);
64+
}
65+
const endOtherRaw = process.hrtime.bigint();
66+
const otherTimeRaw = Number(endOtherRaw - startOtherRaw) / 1_000_000; // ms
67+
68+
console.log(
69+
`@mongodb-js/machine-id: ${formatTime(ourTimeRaw)} total, ${formatTime(ourTimeRaw / ITERATIONS)} per call`,
70+
);
71+
console.log(
72+
`node-machine-id: ${formatTime(otherTimeRaw)} total, ${formatTime(otherTimeRaw / ITERATIONS)} per call`,
73+
);
74+
console.log(
75+
`Comparison: @mongodb-js/machine-id is ${formatComparison(ourTimeRaw, otherTimeRaw)}`,
76+
);
77+
78+
// Test hashed mode
79+
console.log('\nHashed machine ID:');
80+
81+
// @mongodb-js/machine-id
82+
const startOursHashed = process.hrtime.bigint();
83+
for (let i = 0; i < ITERATIONS; i++) {
84+
getMachineId();
85+
}
86+
const endOursHashed = process.hrtime.bigint();
87+
const ourTimeHashed = Number(endOursHashed - startOursHashed) / 1_000_000; // ms
88+
89+
// node-machine-id
90+
const startOtherHashed = process.hrtime.bigint();
91+
for (let i = 0; i < ITERATIONS; i++) {
92+
machineIdSync();
93+
}
94+
const endOtherHashed = process.hrtime.bigint();
95+
const otherTimeHashed = Number(endOtherHashed - startOtherHashed) / 1_000_000; // ms
96+
97+
console.log(
98+
`@mongodb-js/machine-id: ${formatTime(ourTimeHashed)} total, ${formatTime(ourTimeHashed / ITERATIONS)} per call`,
99+
);
100+
console.log(
101+
`node-machine-id: ${formatTime(otherTimeHashed)} total, ${formatTime(otherTimeHashed / ITERATIONS)} per call`,
102+
);
103+
console.log(
104+
`Comparison: @mongodb-js/machine-id is ${formatComparison(ourTimeHashed, otherTimeHashed)}`,
105+
);
106+
107+
console.log('\n========================================');
108+
}
109+
110+
// Run the benchmark
111+
runBenchmark();

packages/machine-id/src/index.spec.ts

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable no-console */
12
import { getMachineId } from '.';
23
import { machineIdSync as otherMachineId } from 'node-machine-id';
34
import { expect } from 'chai';
@@ -54,4 +55,89 @@ describe('machine-id', function () {
5455
expect(hashRegex.test(id));
5556
});
5657
});
58+
59+
describe('performance comparison', function () {
60+
// Increase timeout for performance tests
61+
this.timeout(20_000);
62+
63+
it('performs faster than node-machine-id (raw)', function () {
64+
const iterations = 1000;
65+
66+
// Warm-up run to account for initial load time
67+
getMachineId({ raw: true });
68+
otherMachineId(true);
69+
70+
// Test implementation
71+
const startOurs = process.hrtime.bigint();
72+
for (let i = 0; i < iterations; i++) {
73+
getMachineId({ raw: true });
74+
}
75+
const endOurs = process.hrtime.bigint();
76+
const ourTime = Number(endOurs - startOurs) / 1_000_000; // Convert to ms
77+
78+
// Test node-machine-id
79+
const startOther = process.hrtime.bigint();
80+
for (let i = 0; i < iterations; i++) {
81+
otherMachineId(true);
82+
}
83+
const endOther = process.hrtime.bigint();
84+
const otherTime = Number(endOther - startOther) / 1_000_000; // Convert to ms
85+
86+
console.log(
87+
`Performance comparison (raw mode, ${iterations} iterations):`,
88+
);
89+
console.log(
90+
`- Our implementation: ${ourTime.toFixed(4)}ms (${(ourTime / iterations).toFixed(4)}ms per call)`,
91+
);
92+
console.log(
93+
`- node-machine-id: ${otherTime.toFixed(4)}ms (${(otherTime / iterations).toFixed(4)}ms per call)`,
94+
);
95+
console.log(
96+
`- Difference: ${ourTime < otherTime ? 'Ours is ' + (otherTime / ourTime).toFixed(2) + 'x faster' : 'node-machine-id is ' + (ourTime / otherTime).toFixed(2) + 'x faster'}`,
97+
);
98+
99+
// We expect our native implementation to be faster
100+
// but don't fail the test if it's not, just report the measurements
101+
});
102+
103+
it('performs faster than node-machine-id (hashed)', function () {
104+
const iterations = 1000;
105+
106+
// Warm-up run
107+
getMachineId();
108+
otherMachineId();
109+
110+
// Test our implementation
111+
const startOurs = process.hrtime.bigint();
112+
for (let i = 0; i < iterations; i++) {
113+
getMachineId();
114+
}
115+
const endOurs = process.hrtime.bigint();
116+
const ourTime = Number(endOurs - startOurs) / 1_000_000; // Convert to ms
117+
118+
// Test node-machine-id
119+
const startOther = process.hrtime.bigint();
120+
for (let i = 0; i < iterations; i++) {
121+
otherMachineId();
122+
}
123+
const endOther = process.hrtime.bigint();
124+
const otherTime = Number(endOther - startOther) / 1_000_000; // Convert to ms
125+
126+
console.log(
127+
`Performance comparison (hashed mode, ${iterations} iterations):`,
128+
);
129+
console.log(
130+
`- Our implementation: ${ourTime.toFixed(4)}ms (${(ourTime / iterations).toFixed(4)}ms per call)`,
131+
);
132+
console.log(
133+
`- node-machine-id: ${otherTime.toFixed(4)}ms (${(otherTime / iterations).toFixed(4)}ms per call)`,
134+
);
135+
console.log(
136+
`- Difference: ${ourTime < otherTime ? 'Ours is ' + (otherTime / ourTime).toFixed(2) + 'x faster' : 'node-machine-id is ' + (ourTime / otherTime).toFixed(2) + 'x faster'}`,
137+
);
138+
139+
// We expect our native implementation to be faster
140+
// but don't fail the test if it's not, just report the measurements
141+
});
142+
});
57143
});

packages/machine-id/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
"outDir": "dist"
55
},
66
"include": ["src/**/*"],
7-
"exclude": ["./src/**/*.spec.*"]
7+
"exclude": ["./src/**/*.spec.*", "scripts/benchmark.ts"]
88
}

0 commit comments

Comments
 (0)