react-content-loader icon indicating copy to clipboard operation
react-content-loader copied to clipboard

High CPU usage

Open vylan opened this issue 6 years ago • 17 comments

image As shown in the above image the home page's cpu usage is always more than 40% and also more 20% in my app. I think this is abnormal, please confirm whether it is a bug or the normal phenomenon?

vylan avatar Dec 26 '18 15:12 vylan

That's interesting. How did you benchmark that?

AjayPoshak avatar Dec 28 '18 05:12 AjayPoshak

You can simply open the home page of this library (http://danilowoz.com/create-content-loader), then check the chrome's Task Manager., you'll see the cpu usage monitor.

Now I am pretty sure it's caused by the svg animation ( if I set {animate: false} , the cpu usage will stay at almost 0. )

vylan avatar Dec 28 '18 09:12 vylan

Thanks, I got your point. I can see that animations are taking significant CPU time (34-38%) at my system. I think that this is the issue with animations in general, as this chromium bug. However, we'll look into it and try to figure out a way to reduce CPU usage.

AjayPoshak avatar Dec 29 '18 03:12 AjayPoshak

Thanks, it's not a big problem cause the content loader won't last for a long time, but fix it will be perfect.

vylan avatar Dec 29 '18 10:12 vylan

I've tried some alternatives approaches and I reached these results, but I'm not sure if I should forward in one of these or wait for a chrome fix:

  1. Current: ~40%
  2. With one <animate />: ~53%
        <linearGradient id={idGradient} x1="-100%">
          <stop
            offset="0%"
            stopColor={primaryColor}
            stopOpacity={primaryOpacity}
          />

          <stop
            offset="50%"
            stopColor={secondaryColor}
            stopOpacity={secondaryOpacity}
          />

          <stop
            offset="100%"
            stopColor={primaryColor}
            stopOpacity={primaryOpacity}
          />

          <animate
            attributeName="x1"
            from="-100%"
            to="100%"
            dur={`${speed}s`}
            repeatCount="indefinite"
          />
        </linearGradient>
  1. With backfaceVisibility: 'hidden', willChange: 'auto',; in the <svg />: >40%

danilowoz avatar Jan 24 '19 09:01 danilowoz

Is there a way to push SVG animations to the GPU?

josh-stevens avatar May 29 '19 15:05 josh-stevens

We're seeing similarly high CPU usage when animate=true for React Native as well.

dmkmedina avatar Oct 17 '19 08:10 dmkmedina

I was using react-content-loader as a placeholder while during development and I couldn't figure out why my computer was soooo slow all the time. Then I checked the task manager and finally blamed it on the animation. Without animation everything is fine.

image

Cellule avatar Mar 05 '20 20:03 Cellule

I'm seeing similar results regarding my CPU usage as well. I'm using React (for the web) on development mode and for comparison, those are the CPU usage without and with animate={false} on my page:

With animate={false} Screenshot 2020-05-24 at 03 02 43

Without animate={false} Screenshot 2020-05-24 at 03 02 54

FIY: I'm using react-content-loader version 5.0.4 in here.

pedrommenezes avatar May 24 '20 02:05 pedrommenezes

I actually have a huge CPU usage on this page https://danilowoz.com/create-content-loader/ but it's still close to 0 on this codesandbox https://codesandbox.io/s/6x2414oqln.

bertho-zero avatar Jul 07 '20 16:07 bertho-zero

See the following proposal @danilowoz. The essence is to use SVG mask instead of clippath. Fill the rectangle in white and mask the content placeholder shapes black. That way, the SVG's element background becomes visible where the mask is black. Now you can use CSS linear-gradient for the background which is animated by changing the background position.

Tested in latest firefox, low CPU usage. Didn't check for compatibility with other browsers.

SVG:

<svg width="100%" viewBox="0 0 800 350" className='loader-animated-bgr'>
    <rect x="0" y="0" width="100%" height="100%" fill='white' mask="url(#mymask)">
    </rect>
    <defs>
        <mask id="mymask">
            <rect id="bg" x="0" y="0" width="100%" height="100%" fill="white" />
            <!-- TODO: insert any shapes filled black -->
        </mask>
    </defs>
</svg>

CSS:

$col-bgr: #ecebeb;
$col-accent: #e0e0e0;

.loader-animated-bgr {
    background: linear-gradient(90deg, $col-bgr, $col-bgr 25%, $col-accent 45%, $col-accent 55%, $col-bgr 75%, $col-bgr);
    background-size: 400% 100%;
    animation: loader-animation 3s ease infinite;
}

@keyframes loader-animation {
    0% { background-position: 100% 0% }
    100% { background-position: 0% 0% }
}

Have a nice day!

This reporting in Chromium might help: https://bugs.chromium.org/p/chromium/issues/detail?id=1141881

danilowoz avatar Nov 02 '20 11:11 danilowoz

Also most likely related to this - when using Detox (React Native) to test, tests just hang whenever the content loader is present. Might be something to do with how Animate lib is interacted with, maybe some unresolved promise.

If I set animate={false} it works well.

dasaco avatar Feb 14 '21 13:02 dasaco

I did`t research much this topic, but can add when I trying to run tests - every time snapshot are updated, without any changes in spec file, and every time updates below property of <RNSVGRect /> ( symbols in **). Test passes very long time, and seems like an infinity loop, one time I even got error with full memory.

clipPath=" **zrpmk0p** -animated-diff"

AND-GORNIY avatar Feb 19 '21 14:02 AND-GORNIY

@AND-GORNIY regarding the id issue, I'd recommend the following issue https://github.com/danilowoz/react-content-loader/issues/78, it introduces the prop uniqueId in order to manage this kind of situation. Unfortunately, it needs somehow a unique value, and in case the user doesn't provide any one, the library needs to generate a random one.

Make sense?

danilowoz avatar Feb 19 '21 15:02 danilowoz

Found an interesting sort of solution to this problem:

"As with the hero of any story, however, there must be a fall from grace. For animated SVGs, this fall occurs in CPU usage. The inclusion of just a few on a webpage can cause the CPU usage of a browser to jump by several tens of percentage points. Viewing such a page on even modern laptops will cause the machine to whirr like it’s trying to take flight and heat up like a bacon griddle.

Fortunately, redemption for our hero comes easily and quickly in the form of CSS hardware acceleration.

If you’re unfamiliar with the concept, the idea is to give a troublesome element the style transform: translateZ(0);. This gives the element its own render layer, and lets the GPU (who’s better at this kind of work anyway) take the hard number crunching away from the overloaded CPU."

Worked well for me, reduced the max workload experienced from 40-50% to an average of 20-30% (still a lot, but an improvement).

MadsFrost avatar Oct 27 '21 08:10 MadsFrost

I fixed this by re-implementing the loader to clip a div instead of a rect. I also had to rely on animating opacity instead of backgroundColor/fill.

meronogbai avatar Dec 03 '22 00:12 meronogbai