Skip to content

Commit

Permalink
Benchmark for React Native (Hermes) target (#47)
Browse files Browse the repository at this point in the history
Size of the bytecode outputs:

- `graphemer`: 140 KB
- `unicode-segmenter/grapheme`: 48 KB

Perf benchmark result on a MacBook Pro M1 laptop:

```
graphemer (small input)
samples: 1000
duration (avg): 0.326

graphemer (medium input)
samples: 1000
duration (avg): 1.611

unicode-segmenter/grapheme (small input)
samples: 1000
duration (avg): 0.14

unicode-segmenter/grapheme (medium input)
samples: 1000
medium input (avg): 0.674
```
  • Loading branch information
cometkim authored Jun 29, 2024
1 parent 6d02503 commit a943e9f
Show file tree
Hide file tree
Showing 7 changed files with 2,818 additions and 47 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ lcov.info

/.parcel-cache/
/dist/

*.hermes.js
*.hermes.hbc
27 changes: 27 additions & 0 deletions benchmark/hermes/graphemer/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import Graphemer from 'graphemer';

import { inputs, simpleBench } from '../suite.js';

let graphemer = new (Graphemer.default || Graphemer)();

{
let result = simpleBench(1000, () => {
void [...graphemer.iterateGraphemes(inputs.small)];
});

print(`graphemer (small input)`);
print(`samples: ${result.samples}`);
print(`duration (avg): ${result.avgDuration}`);
}


{
let result = simpleBench(1000, () => {
void [...graphemer.iterateGraphemes(inputs.medium)];
});

print();
print(`graphemer (medium input)`);
print(`samples: ${result.samples}`);
print(`duration (avg): ${result.avgDuration}`);
}
67 changes: 67 additions & 0 deletions benchmark/hermes/run.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import * as path from 'node:path';
import * as fs from 'node:fs/promises';
import Metro from 'metro';
import { $ } from 'zx';

let baseDir = import.meta.dirname;

$.cwd = baseDir;

let config = await Metro.loadConfig(undefined, {
transformer: {
enableBabelRCLookup: false,
babelTransformerPath: '@react-native/metro-babel-transformer',
},
reporter: {
update: () => {},
},
});

let libs = [
'graphemer',
'unicode-segmenter',
];

let benches = [];

console.group('Preparing bundles...');

for (let lib of libs) {
let libDir = path.join(baseDir, lib);

let files = await fs.readdir(libDir);
files = files.filter(file => file.endsWith('.js') && !file.includes('hermes'));

for (let file of files) {
let source = path.join(libDir, file);
let hermesEntry = path.join(libDir, file.replace(/\.js$/, '.hermes.js'));
let hermesBin = path.join(libDir, file.replace(/\.js$/, '.hermes.hbc'));

await Metro.runBuild(config, {
entry: path.join(libDir, file),
out: hermesEntry,
dev: false,
});

console.log(`Compiling bundle to ${hermesBin}`);
await $`hermes -emit-binary -out ${hermesBin} ${hermesEntry}`;

console.log();

benches.push({
lib,
source,
hermesBin,
hermesEntry,
});
}
}

console.groupEnd();

console.log('\nExecuting Hermes bytecodes...\n');

for (let bench of benches) {
await $({ stdio: 'inherit' })`hermes ${bench.hermesBin}`;
console.log();
}
32 changes: 32 additions & 0 deletions benchmark/hermes/suite.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
export let inputs = {
small: `🚀 새로운 유니코드 분할기 라이브러리 \'unicode-segmenter\'를 소개합니다! 🔍 각종 언어의 문자를 정확하게 구분해주는 강력한 도구입니다. Check it out! 👉 [https://github.com/cometkim/unicode-segmenter] #Unicode #Programming 🌐`,

medium: `The quick brown 🦊 fox jumps over 13 lazy 🐶 dogs. हिंदी भाषा में स्वागत है. 中文环境的介绍。日本語での説明。АБВГД ЕЁЖЗ ИЙКЛМН ОПРСТ УФХЦЧ ШЩЪЫЬ ЭЮЯ. السَّلَامُ عَلَيْكُمْ. 1234567890!@# $%^&*()_+[];'./,\<>?:"{}|= abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 🌍 🚀 ✨. 𐍈𐍉𐌽𐌴𐍄𐌹𐌲𐍉𐌸𐌰𐍃𐌰𐍂𐌺𐍃 𐌲𐌴𐍂𐌰𐌼𐌰𐌽𐌹𐍃𐌺𐌰𐌹𐍃𐌰𐍂𐌰𐌶𐌳𐌰. 🧙‍♂️⚔️🏰👸🐉🏹🛡️🌌. ¡Hola! ¿Cómo estás? 🎉🎊🎈. Dans un village de La Mancha, dont je ne veux pas me souvenir du nom, vivait pas si longtemps, un hidalgo des lances reposées, ancien bouclier, cheval maigre et lévrier rapide. O Romeo, Romeo! wherefore art thou Romeo? Deny thy father and refuse thy name; Or, if thou wilt not, be but sworn my love, And I'll no longer be a Capulet. 세계의 모든 인간은 자유롭고 평등하게 태어났다. 人人生而自由,在尊严和权利上一律平等。Είναι ελεύθεροι και ίσοι στην αξιοπρέπεια και τα δικαιώματα. כָּל אָדָם נוֹלָד חוֹפְשִׁי וּשְׁוֵה בַּכָּבוֹד וּבַזְּכוּיוֹת.`,
};

/**
* @param {number} nums
* @param {() => void} callback
*/
export function simpleBench(nums, callback) {
// warmup
for (let i = 0; i < 100; i++) {
void callback();
}

let startAt = Date.now();
for (let i = 0; i < nums; i++) {
void callback();
}
let endAt = Date.now();
let totalDuration = endAt - startAt;
let avgDuration = totalDuration / nums;

return {
samples: nums,
startAt,
endAt,
totalDuration,
avgDuration,
};
}
24 changes: 24 additions & 0 deletions benchmark/hermes/unicode-segmenter/grapheme.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { graphemeSegments } from '../../../src/grapheme.js';

import { inputs, simpleBench } from '../suite.js';

{
let result = simpleBench(1000, () => {
void [...graphemeSegments(inputs.small)];
});

print(`unicode-segmenter/grapheme (small input)`);
print(`samples: ${result.samples}`);
print(`duration (avg): ${result.avgDuration}`);
}

{
let result = simpleBench(1000, () => {
void [...graphemeSegments(inputs.medium)];
});

print();
print(`unicode-segmenter/grapheme (medium input)`);
print(`samples: ${result.samples}`);
print(`medium input (avg): ${result.avgDuration}`);
}
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@
"perf:emoji": "node benchmark/performance-emoji.js",
"perf:general": "node benchmark/performance-general.js",
"perf:grapheme": "node benchmark/performance-grapheme.js",
"perf:grapheme:browser": "vite benchmark/performance-grapheme"
"perf:grapheme:browser": "vite benchmark/performance-grapheme",
"perf:hermes": "node benchmark/hermes/run.js"
},
"alias": {
"process": false
Expand All @@ -111,6 +112,7 @@
"@changesets/cli": "^2.27.1",
"@formatjs/intl-segmenter": "11.5.7",
"@jazzer.js/core": "^2.1.0",
"@react-native/metro-babel-transformer": "^0.74.84",
"@types/node": "^20.12.7",
"@types/xregexp": "^4.4.0",
"emoji-regex": "10.3.0",
Expand All @@ -119,6 +121,7 @@
"fast-check": "^3.17.1",
"grapheme-splitter": "1.0.4",
"graphemer": "1.4.0",
"metro": "^0.80.9",
"mitata": "^0.1.11",
"os-browserify": "^0.3.0",
"pretty-bytes": "^6.1.1",
Expand All @@ -127,7 +130,8 @@
"typescript": "^5.4.5",
"unicode-segmentation-wasm": "portal:benchmark/unicode-segmentation-wasm",
"vite": "^5.2.11",
"xregexp": "5.1.1"
"xregexp": "5.1.1",
"zx": "^8.1.3"
},
"packageManager": "[email protected]"
}
Loading

0 comments on commit a943e9f

Please sign in to comment.