GoogleChromeLabs / react-adaptive-hooks

Deliver experiences best suited to a user's device and network constraints
Apache License 2.0
5.11k stars 114 forks source link

Alternative to Core count #9

Open andrewgreenh opened 5 years ago

andrewgreenh commented 5 years ago

The basic idea behind the useHardwareConcurrency hook is great, but I fear that it is not sufficient to identify slow devices. Even the moto G of the first generation (with a Snapdragon 400 CPU) has 4 cores. On the other hand, older iPhones only have 2 cores while the single cores are much faster and are able to run expensive animations more easily compared to low end android devices with more cores.

Could we maybe implement a "mini benchmark" to identify the JS execution speed of the device? Maybe something along the lines of this:

function measure() {
  let start = Date.now();
  let index = 0;
  while (start + 8 >= Date.now()) index++;
  return index;
}

This would however block the mainthread for 8ms (duration could be changed obviously).

Get your score here: https://ogb5i.csb.app/

My Laptop (i7 8565U) manages something around 30.000 while my s10 (Exynos variant) only gets 3.000 - 10.000, the s7 of a friend manages ~1000 and the iPhone 6s of a friend gets 8.000

One would need to source the scores for different devices and implement categories.

Another added benefit would be, that the JS execution speed of the browser is factored in. That would mean, that IE gets fewer heavy animations because it is slower.

addyosmani commented 5 years ago

I'm glad you started this discussion :)

In my talk at Chrome Dev Summit, we briefly discussed that CPU reporting is not well exposed in the Web Platform at present, in large-part due to concerns about exposing another fingerprinting vector. There's a great doc about this here. An alternative is to extrapolate the device model ID from the UA string, map the device back to pre-computed CPU benchmark data from Geekbench and use that to define low-end/high-end classifications. Loosely:

CDS19-D1-5_Adaptive Loading - Improving the user-experience for billions on low-end devices (2)

We implemented a demo of this idea over in https://github.com/GoogleChromeLabs/adaptive-loading/tree/master/cra-device-class-aware-code-splitting where you can see us using the Device Atlas API for model detection and static Geekbench data for the mapping.

For the local benchmarking idea, I think it would be interesting to think through the caveats a little. e.g I imagine you are limited to changing the loading strategy after initial page load (as the benchmark needs JS to execute), how much time does the benchmark itself take to execute (would it have to run after the page is idle to not content with other main-thread activity) etc.

andrewgreenh commented 5 years ago

I really like the idea of benchmarking in a requestIdleCallback. The goal of such a feature would be to check if a device can handle a non-critical feature performance wise. That means, we could maybe live with delaying this feature until the device has time to run the mini-benchmark. We could also rerun the benchmark every x minutes in order to update the score depending on the other work the device has to perform at a given moment.

TimvanScherpenzeel commented 5 years ago

An alternative is to extrapolate the device model ID from the UA string, map the device back to pre-computed CPU benchmark data from Geekbench and use that to define low-end/high-end classifications.

I've done something similar for detecting GPU's in the past: https://github.com/TimvanScherpenzeel/detect-gpu (mapping reported GPU to a scraped benchmarking list). I've mostly used it for highly interactive WebGL websites where based on the GPU tier it picks a default quality setting (which is still overridable by the user).