Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
Johan ⚡️ Nerdmanship

CPU test like Modernizr?

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

Designing by screen size and available features is common practice, but what about hardware?

I wanna do something like this:

if (powerfulCPU) {
    // Use a crazy amount of blur
} else {
    // Skip everything fancy but still deliver a killer animation
}

Is there a way to perform a quick CPU test in the loading sequence of a website in a similar manner that Modernizr does feature testing? Or do you have any other thoughts on how to achieve something similar?

Link to comment
Share on other sites

Hello stromqvist,

 

There is nothing that will communicate with the browser the amount of RAM or CPU being used. The OS will not allow this type of information to be passed. There is no methods in JavaScript that will let you know anything about CPU usage or RAM usage. The OS has a separate abstraction layer and due to security will not allow the browser or JavaScript to know the load of the CPU and GPU. Maybe using some type of Java applet, but still every user would need that installed in the browser and still who knows if it will be accurate, plus Java Runtime Environment browser plugins are a security risk and are automatically disabled in modern browsers due to previous bugs and malware that have been exploited.

 

Keep in mind that a CSS blur and even SVG blur can cause massive repaints in the browser. With blur i don't see the benefit of blurring past a certain point.

 

What are using for the blur? .. CSS, SVG, or Canvas?

  • Like 4
Link to comment
Share on other sites

Hi, thanks for your reply!

I'll elaborate this brain fart a little bit, so please bare with me. :)

 

--

 

At first I was hoping for an implicit test of sorts, like the way that some feature detection seems to work. Instead of asking someone what languages they speak, you could say something in German and see if they get it. And then French, Italian, etc. So instead of explicitly asking the system about its RAM/CPU, you'd throw it a task and see how it responds. I don't know, like ask the browser to create and kill a thousand elements, or make a latency/fps test, or measure how fast the browser parse a specific document. Measure the result of whatever test and rank it between fast and slow.

 

Are these crazy-thoughts?

 

--

 

Another idea would be to forget about the actual hardware and focus on feature detection that relate to hardware.

 

Let's say we had an animation that could be done in a light, moderate and rich fashion. Never mind the blur, just anything resource heavy. Wouldn't it be possible to combine information that is likely to be related to performance and then make assumptions about the system from there?

 

Examples:

 

What's significant for a system likely to be above average?

Condition 1: It has a retina display, but it isn't a touch device (true for most modern laptops)

Condition 2: It has force touch, but it isn't a touch device (true for any new macbook)

Condition 3: ..?

 

What's significant for a system likely to be below average?

Condition 1: Runs <IE10

Condition 2: Any Samsung user agent and is mobile device

Condition 3: ..?

 

Anything that doesn't qualify in above or below average falls back in moderate.

if (aboveAverage) {
    initRich()
} else if (belowAverage) {
    initLight()
} else {
    initModerate()
}

Wouldn't something like this be useful? What other conditions could be added?

 

--

 

Maybe none of this is doable, desirable or usable... I don't know. My experience in hardware and computer science is very limited. But GSAP does unlock some really cool possibilities for "conventional" animators, motion graphics artists and interaction designers, and we could definitely optimise the user experience if we have some (any) knowledge about the user's system.

 

Maybe the topic should be something like: Graceful degradation and progressive enhancement for graphics and motion?

Link to comment
Share on other sites

Those are all great ideas you have listed. But each browser vendor handles devices and displays differently. And there is no one size fits all type of thing when detecting for features or specific mobile properties.

 

Basically all the things you listed would happen outside of GSAP. GSAP add its core is an animation platform, being able to animate any javascript numerical object or property. So its up to the developer to use various event handlers or feature detection to apply the animation they see fit.

 

To detect the device pixel ratio for retina you can do feature detection and check for devicePixelRatio

 

window.devicePixelRatio: https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio

 

But the browser support is limited. http://caniuse.com/#feat=devicepixelratio

 

There is a spec right now to check for device resolution with CSS media queries, but that is still being worked on in the spec.

 

The most important thing to consider is that when animating you want to stick to animating CSS properties like transforms and opacity. Which will give you the best performance. Since those CSS properties can take advantage of rendering with the help of the GPU (hardware acceleration), if you focus on that then you can make sure that the elements get animated without jank (lost frames) at 60fps. Then you don't have to worry about wanting to check for RAM or CPU since the elements will be animating at the highest possible frame rate the browser allows, regardless of RAM, CPU, or display type.

 

Articles i suggest you read:

 

https://css-tricks.com/myth-busting-css-animations-vs-javascript/

 

https://www.paulirish.com/2012/why-moving-elements-with-translate-is-better-than-posabs-topleft/

 

https://developers.google.com/web/fundamentals/performance/rendering/

 

https://www.html5rocks.com/en/tutorials/speed/rendering/

 

https://www.html5rocks.com/en/tutorials/speed/css-paint-times/

 

:)

  • Like 3
Link to comment
Share on other sites

Animating transforms are great for sure – but I can definitely not stick to it. ;)

 

I guess I'll do some experimentation and post here again when I've got something.

 

Thanks a bunch for your time and the reading tips!

Link to comment
Share on other sites

I think the only way to really do this with GSAP is to monitor the framerate. Here is how you can check the average fps over 1 second with GSAP. You could run some logic in the if statement to control what can be animated.

See the Pen 4e54ebe6273b98196de19521ab0d693d?editors=0010 by osublake (@osublake) on CodePen

 

Here's a really cool demo that limits the number of particles based on the fps. It's not using GSAP, but the concept is similar to what I described above.

See the Pen YPWwaG?editors=0010 by amwmedia (@amwmedia) on CodePen

  • Like 2
Link to comment
Share on other sites

  • 1 year later...
On 10/16/2016 at 1:15 PM, OSUblake said:

I think the only way to really do this with GSAP is to monitor the framerate. Here is how you can check the average fps over 1 second with GSAP. You could run some logic in the if statement to control what can be animated.

http://codepen.io/osublake/pen/4e54ebe6273b98196de19521ab0d693d?editors=0010

 

 

I recently implemented something like this based on that codepen.

 

I tried to lower the animation stress to try and improve the fps.

when the fps drop below 30 twice, I kill some of the animation and scenes in order to try and get a better performance for the user.

 

I tried to think of a way to do this before the animation actually starts, but wasn't able to find one. But gracefully degrading the animation seems like a good start :-)

 

Here is my take on it:

 

FPS(30 /* minimum acceptable fps */ ,
    2 /* how many framedrops is too many  */ ,
    false /* true = trigger drops-limit more than once */ ,
    true /* show fps info */ )
  .on('drops-limit', function(numberOfDrops) {
    console.log('~= Animation degradation triggered =~');
    /* stop animations and simplify things here.
       if you want to have several degradations in quality,
       turn alwaysTrigger to true and change the behaviour
       based on numberOfDrops */

    // MY EXAMPLE:
    if (ANIMATIONS.complicatedAnimation) {
      ANIMATIONS.complicatedAnimation.seek(0).kill();
      ANIMATIONS.complicatedAnimation2.seek(0).kill();
      ANIMATIONS.complicatedAnimation3.seek(0).kill();
      // destroy scrollMagic scene
      SCENES.fightScene.destroy(true);
      // go to end of animation before killing it
      ANIMATIONS.fight.seek('-=0').kill();

      // just a fix for now, instead of adding a condition in the SCENES
      // functions
      ANIMATIONS.text1 = ANIMATIONS.text2 = ANIMATIONS.text3 = {
        play: function() {}
      };
    }
  });

function FPS(framesThreshold, dropsThreshold, alwaysTrigger, showDebugBox) {
  var self = {};

  self.framesThreshold = framesThreshold || 30;
  self.dropsThreshold = dropsThreshold || 2;
  self.firstDropsTrigger = true;

  toEmitter(self);

  if (showDebugBox) {
    $('body').append([
      '<div class="hud">',
      'FPS: <span id="framerate">0</span>; ',
      'lowest FPS: <span id="lowest">null</span>; ',
      'DROPS Below ', self.framesThreshold, 'FPS: <span id="drops">0</span>',
      '</div>'
    ].join(''));
  }

  var $framerate = showDebugBox ? document.querySelector("#framerate") : {};
  var $lowest = showDebugBox ? document.querySelector("#lowest") : {};
  var $drops = showDebugBox ? document.querySelector("#drops") : {};
  var prevTime = 0;
  var frames = 0;
  var ticker = TweenLite.ticker;

  var lowestFrameRate = -1;
  var numberOfDrops = 0;

  ticker.addEventListener("tick", update);

  return self;

  function update() {

    var current = ticker.time;

    frames++;

    if (current > prevTime + 1) {
      var fps = Math.round(frames / (current - prevTime));
      $framerate.textContent = fps;
      prevTime = current;
      frames = 0;

      if (lowestFrameRate === -1) {
        lowestFrameRate = fps;
        $lowest.textContent = lowestFrameRate;

        self.trigger('lowest-initialized', lowestFrameRate);
      }

      if (fps < lowestFrameRate) {
        lowestFrameRate = fps;
        console.info('lowest framerate: ' + lowestFrameRate);
        $lowest.textContent = lowestFrameRate;

        self.trigger('lowest-updated', lowestFrameRate);
      }

      if (fps < self.framesThreshold) {
        numberOfDrops++;
        $drops.textContent = numberOfDrops;

        self.trigger('drops-updated', lowestFrameRate);
      }

      if ((alwaysTrigger || self.firstDropsTrigger) && numberOfDrops >= self.dropsThreshold) {
        self.trigger('drops-limit', numberOfDrops);
        self.firstDropsTrigger = false;
        $drops.textContent = numberOfDrops;
      }
    }
  }
}

function toEmitter(obj) {
  obj.eventHash = {};

  obj.trigger = function() {
    var eventName = arguments[0];
    var args = Array.prototype.slice.call(arguments, 1);

    if (obj.eventHash[eventName])
      obj.eventHash[eventName].forEach(function(handler) {
        handler.apply(this, args);
      });
  }

  obj.on = function(eventName, handler) {
    (obj.eventHash[eventName]) ?
    obj.eventHash[eventName].push(handler):
      obj.eventHash[eventName] = [handler];
  }
}

 

Here's the code added to a fork of an animation on codepen. On PC, I don't get anywhere near 30fps, but on mobile, if I release enough confetti, I can create lots of frame drops, and the event triggers.

 

I still need to check this on tab change. there might be a problem there.

 

I also implemented this on one of my animations (WIP. link might change): http://kibibit.io/achievibit-demo

See the Pen QOGoqy?editors=0100 by neilkalman (@neilkalman) on CodePen

 

  • Like 4
Link to comment
Share on other sites

3 hours ago, thatkookooguy said:

 still need to check this on tab change. there might be a problem there.

 

When the page looses visibility, requestAnimationFrame will be paused or reduced to like a second.

https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API#Policies_in_place_to_aid_background_page_performance

 

This fork should give you a lot of framerate drops.

 

See the Pen gXLNqO by osublake (@osublake) on CodePen

 

 

Link to comment
Share on other sites

6 hours ago, OSUblake said:

 

When the page looses visibility, requestAnimationFrame will be paused or reduced to like a second.

https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API#Policies_in_place_to_aid_background_page_performance

1

 

@OSUblake That's exactly what I was talking about. When going back into focus, the first second usually has a drop in frames (just as when you load the page initially).

That is why I set the minimum frame drop count as 2 - so I can skip the initial drop (sort of a false positive).

 

I think I need to add something similar on page focus.

 

maybe the strategy should be 2 consecutive seconds of frame drops to consider it as one.

 

But I still need to test this out on devices with different specs to check average times and stuff.

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

×