localeCompare extremely slow sometimes
- Dominant language
- JavaScript
- Stars
- 11.3k
- Forks
- 859
- Avg merge
- 1h 30m
- Merged PRs (30d)
- 3
Description
## Bug Description
- [x] I have run `gradle clean` and confirmed this bug does not occur with JSC
Hermes version: (whatever's in RN 0.70.6)
React Native version (if any): 0.70.6 (the current latest)
OS version (if any): Android 13
Platform (most likely one of arm64-v8a, armeabi-v7a, x86, x86_64): arm64-v8a
## Steps To Reproduce
1. Clone https://github.com/gnprice/hermes-localecompare-repro .
2. Run it with `npx react-native run-android`.
3. Observe the log lines showing calls to `String.prototype.localeCompare` taking multiple seconds each. For example:
```
LOG sorting...
LOG slow localeCompare: 8836ms for 'vihmdxim' vs 'vlqkdtzn'
LOG slow localeCompare: 2078ms for 'ezkvpvbg' vs 'ivkpfinh'
LOG slow localeCompare: 6568ms for 'ctanfzkj' vs 'ctjhzdyi'
LOG slow localeCompare: 7639ms for 'hgyzpilj' vs 'hhpnlwqf'
LOG slow localeCompare: 7337ms for 'jzninmrt' vs 'orbuzdcq'
LOG slow localeCompare: 6872ms for 'rnarhxnr' vs 'rnauqlwl'
LOG slow localeCompare: 3648ms for 'nfdeptde' vs 'nfgpjekx'
LOG ...done, took 56938ms
```
Those extremely slow calls are rare relative to the total number of calls. But because they're so extremely slow, they account for most of the total time — about 75% of the whole sort in this example.
### code example
The repro repo above just consists of a fresh React Native app on the latest version (from `npx react-native init`), with the following code added at the top of the render function:
```js
const randInt = (end, start = 0) =>
Math.floor(Math.random() * (end - start) + start);
const alphabet = 'abcdefghijklmnopqrstuvwxyz';
const names = Array.from({length: 30000}, () =>
Array.from({length: 8}, () => alphabet[randInt(alphabet.length)]).join(''),
);
console.log('sorting...');
const s = Date.now();
names.sort(localeCompare);
console.log(`...done, took ${Date.now() - s}ms`);
function localeCompare(a, b) {
const s = Date.now();
const result = a.localeCompare(b);
const e = Date.now();
if (e - s > 100) {
console.log(`slow localeCompare: ${e - s}ms for '${a}' vs '${b}'`);
}
return result;
}
```
That is, it makes up a long list of boring short alphabetic strings, and sorts them. The comparator just calls `String.prototype.localeCompare`, and times the call.
## The Expected Behavior
Calling `localeCompare` on a string should be fast — certainly far less than a second, for any non-gigantic strings.
## Other notes
I do *not* reproduce the issue when running in an emulated Android device, on x86_64. So it may be architecture-dependent.
Contributor guide
Assessment
This issue has not been assessed yet.