Gio Posted June 7, 2016 Share Posted June 7, 2016 I have been wondering... In my web app I have some non-important tasks that are CPU-intensive and that I would like to run when the CPU is not doing much. Can you think of a good way of detecting current CPU usage? The best solution that I can think of is measuring the time between requestAnimationFrame calls, but that only gives me a very rough indication of how busy the CPU is, as it is also a result of what the GPU is doing, and wouldn't give me any indication at all if my app was running faster than the system's vsync rate. Do you have any other ideas? Quote Link to comment Share on other sites More sharing options...
Fatalist Posted June 7, 2016 Share Posted June 7, 2016 You can try this: after each frame, check how many spare milliseconds you have before the next frame. So if rendering a frame took 10 seconds, you have 16 - 10 = 6 milliseconds left to do some additional work. You should have periodic checks in your code and when you exceed the time limit, you'll save temporary results and exit. Gio 1 Quote Link to comment Share on other sites More sharing options...
mattstyles Posted June 7, 2016 Share Posted June 7, 2016 Pretty sure there is no decent way of getting this information from the browser. As you say, measuring the rendering performance gives you some indication of how much idle time, but measuring just the time between raf (the framerate) only gives you an indication that you're maybe doing too much and your fps is suffering, measuring the time your probably synchronous render function/s takes gives you an idea of how much spare time per raf tick you have but does not account for everything else going on. I guess if you strictly delineate rendering and logic functions you could test how long each one took to run, but, sounds fiddly and unreliable. Why not use web workers though? if the tasks are cpu-intensive let the OS handle juggling the CPU, or additional threads etc etc, and get your processing done away from your JS thread rather than squeezing it into the same main JS thread. Gio 1 Quote Link to comment Share on other sites More sharing options...
Gio Posted June 7, 2016 Author Share Posted June 7, 2016 Thanks for the tips guys. To clarify and add some more restrictions: unfortunately this is not a game where things happen at set intervals, it's a (very complex) web app where there are both things happening at set intervals and lots of transactional (user-initiated) calculations that can happen at any time. Webworkers are a good idea, but the amount of work that needs to be done on the main thread to kick off the web workers (gathering all the data and sending it to a task) is what I'm worried about. Ideally I'd like to find a method to say "it looks like the user is just staring at the screen right now, they aren't actually doing anything or waiting for some expensive calculation to complete, it's a good time to run some of those tasks". But I'd need to do so without having to add code to each possible user-initiated function call, because I have literally hundreds of those. And when I add new ones, I'll forget to add this profiling code there too. What do you think of something like this, in addition to timing request animation frame? var before = performance.now(); setTimeout(function() { var after = performance.now(); if (after - before < 3) { // the main thread is not too busy } }, 0); Quote Link to comment Share on other sites More sharing options...
Fatalist Posted June 7, 2016 Share Posted June 7, 2016 I just remembered this - https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback, works only in Chrome currently. For other browsers, you could do something like this this to make it more reliable: setInterval(function() { var fps = getFpsOverLast5Seconds(); if (fps > 100) { doWork(); } }, 8); Quote Link to comment Share on other sites More sharing options...
BobF Posted June 7, 2016 Share Posted June 7, 2016 Rather than trying to guess at CPU occupancy, you may want to consider monitoring the user instead. Your code could implement a small event listener for keyboard, mouse, and touch events. Then set a timer that runs your task after x millisecs. Once the timer is set, restart it whenever an I/O event is detected. So, your task will only run after the user has been idle for x millisecs. That still leaves accounting for your other higher priority tasks that run at set intervals, but it shouldn't be too difficult to improvise a generic solution that ensures your low priority task doesn't try to run at a time that would conflict with those tasks. I agree with Matt... If your task is low priority and CPU intensive then it sounds like a good candidate to run on a web worker. Even if gathering the data is a bit of work, it is presumably significantly less work than running the task itself (which can now run on a separate core when processed by a web worker). Perhaps the data can be restructured in a way that makes it both easily usable by the main process and easy to send to the web worker. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.