javascript timers, power consumption, and performance

Post on 15-May-2015

12.594 Views

Category:

Technology

2 Downloads

Preview:

Click to see full reader

DESCRIPTION

E

TRANSCRIPT

Timers, Power Consumption, and Performance

flickr.com/photos/barbourians/6662357209/

Nicholas C. ZakasChief Architect, WellFurnished

New

@slicknet(Complaints:@souders)

flickr.com/photos/jepoirrier/954701212/

UI Thread

Update UI Execute JavaScript

flickr.com/photos/55733754@N00/3325000738/

<button id="btn" style="font-size: 30px; padding: 0.5em 1em">Click Me</button>

<script>

window.onload = function(){

document.getElementById("btn").onclick = function(){

//do something

};

};

</script>

Before ClickUI Thread

UI Queuetime

When ClickedUI Thread

UI Queuetime

Update UI

Update UI

onclick

When ClickedUI Thread

UI Queuetime

Update UI

Update UI

onclickDraw down state

When ClickedUI Thread

UI Queuetime

Update UI

Update UI

onclick

When ClickedUI Thread

UI Queuetime

Update UI Update UIonclick

Draw up state

No UI updates while JavaScript is executing

JavaScript May Cause UI Update<button id="btn" style="font-size: 30px; padding: 0.5em

1em">Click Me</button>

<script>

window.onload = function(){

document.getElementById("btn").onclick = function(){

var div = document.createElement("div");

div.className = "tip";

div.innerHTML = "You clicked me!";

document.body.appendChild(div);

};

};

</script>

Each UI update applies

ALL CHANGESsince the last UI update

I gonna make a

namination!!

flickr.com/photos/oakleyoriginals/3065393607/

function naminate(element){

// start here

element.style.left = "10px";

// move to here

element.style.left = "30px";

// then to here

element.style.left = "50px";

// finally to here

element.style.left = "70px";

}

Why you no work???

flickr.com/photos/tudor/318123668/

function namimate(element){

// start here

element.style.left = "10px";

// move to here

element.style.left = "30px";

// then to here

element.style.left = "50px";

// finally to here

element.style.left = "70px";

}

Last state wins

setTimeout()

var tId = setTimeout(function(){

// do something

}, 1500);

// optional

clearTimeout(tId)

Code to execute

Delay in milliseconds

setTimeout()DOES NOT SAY

“Run this code after this delay”

setTimeout()DOES SAY

“Add this code to the queue after this delay”

<button id="btn" style="font-size: 30px; padding: 0.5em 1em">Click Me</button>

<script>

window.onload = function(){

document.getElementById("btn").onclick = function(){

setTimeout(function() {

//do something

}, 25);

};

};

</script>

When ClickedUI Thread

UI Queuetime

Update UI

Update UI

onclick

When ClickedUI Thread

UI Queuetime

Update UI

Update UI

onclickDraw down state

When ClickedUI Thread

UI Queuetime

Update UI

Update UI

onclick

When ClickedUI Thread

UI Queuetime

Update UI Update UI

Draw up state

onclick

After 25msUI Thread

UI Queuetime

Update UI Update UIonclick

JavaScript

Added to back of queue

FutureUI Thread

UI Queuetime

Update UI Update UIonclick JavaScript

FutureUI Thread

UI Queuetime

Update UI Update UIonclick JavaScript

Update UI

If the JavaScript changes the UI, it triggers another

update

setTimeout() sends your code into the future

setTimeout(function(){

element.style.left = "10px";

}, 50);

setTimeout(function(){

element.style.left = "30px";

}, 100);

setTimeout(function(){

element.style.left = "50px";

}, 150);

setTimeout(function(){

element.style.left = "70px";

}, 200);

(function(){

var delay = 100;

function moveTheThing(){

// actually move the thing

setTimeout(moveTheThing, delay);

}

setTimeout(moveTheThing, delay);

}());

Animation Loop

(function(){

var msg = "Some reasonably long text that keeps scrolling.",

len = 25,

pos = 0,

padding = msg.replace(/./g, " ").substr(0,len)

finalMsg = padding + msg,

delay = 100;

function updateText(){

var curMsg = finalMsg.substr(pos++, len);

window.status = curMsg;

if (pos == finalMsg.length){

pos = 0;

}

setTimeout(updateText, delay);

}

setTimeout(updateText, delay);

}());

And More!

setTimout() all the things!!!

Problems

15.6

The default system-wide timer resolution in Windows is 15.6 ms, which means that every 15.6 ms the operating system receives a clock interrupt from the system timer hardware.

-Timers, Timer Resolution, and Development of Efficient Code (Microsoft)

var tId = setTimeout(function(){

// do something

}, 10);

What does it mean?

http://ejohn.org/blog/accuracy-of-javascript-time/

60

(function(){

var delay = 17;

function moveTheThing(){

// actually move the thing

setTimeout(moveTheThing, delay);

}

setTimeout(moveTheThing, delay);

}());

Animation Loop

Pretty please?!?!

http://ejohn.org/blog/analyzing-timer-performance/

Jumpy animationsInaccurate benchmarks

1ms all the timers!!!

http://www.belshe.com/2010/06/04/chrome-cranking-up-the-clock/

timeBeginPeriod()

timeBeginPeriod(1)

setTimout() all the things!!!

flickr.com/photos/antonfomkin/3046849320/

Modern CPUs are narcoleptic

ActiveC0

C1C2

C3

x86 CPU States

Low Power

HaltStop-Clock

SleepDeep Sleep

Enhanced Deep SleepDeep Power Down

C4C5C6

http://software.intel.com/en-us/articles/cpu-power-utilization-on-intel-architectures/

CPUs go to sleep when idle

The default timer resolution on Windows 7 is 15.6 milliseconds (ms). Some applications reduce this to 1 ms, which reduces the battery run time on mobile systems by as much as 25 percent.

-Timers, Timer Resolution, and Development of Efficient Code (Microsoft)

Laptops!

Plugged In 4ms 4ms 4ms 4ms 4ms

Battery 4ms 15.6ms 4ms 15.6ms 4ms

Background 1s 1s 4ms 1s* 4ms

* Internet Explorer 10

Web Timer Resolution Today

Battery 4ms 10ms 10ms 10ms 4ms

Background Tab - 10ms 10ms 10ms 1s

Web Timer Resolution Today

Background App - * * * 1s

* “Catches up” when switched back

Experiment• Hard shutdown and restart so

no other apps are running• Turn off brightness auto-adjust• Turn off screen locking• Leave WiFi/Mobile on• Load test page in browser• Profit!

Experiment• Test single timer at different

intervals:• 1000ms – 10ms

Low Frequency >= 1000ms

High Frequency < 1000ms

Time For 10% Power UseBy Frequency

Minutes 52-56 42-48 62-65

Timer frequency doesn’t matter

http://googlecode.blogspot.com/2009/07/gmail-for-mobile-html5-series-using.html

Experiment• Test single timer at different

intervals:• 1000ms – 10ms

• Test multiple timers at different intervals• 1000ms – 10ms x 10

Time For 10% Power UseBy Count

Minutes 52-56 42-48 62-65

(same)

Number of timers doesn’t matter

Number of timers does matter(accuracy)

http://ejohn.org/apps/timers

http://ejohn.org/apps/timers

http://ejohn.org/apps/timers

Flooding the QueueUI Thread

UI Queuetime

timer

timer

timer

Too many timers affects rendering

Elsewhere…

http://www.w3.org/TR/css3-animations/

Optimized animations using CSS

div {

animation-name: diagonal-slide;

animation-duration: 5s;

animation-iteration-count: 10;

}

@keyframes diagonal-slide {

from {

left: 0;

top: 0;

}

to {

left: 100px;

top: 100px;

}

}

Hey browser! I’m animating!

var tId = setTimeout(function(){

// do something

}, 1500);

Hey browser!

I want to do something

later

Could be animation. Could be polling.

Don’t sweat it.

http://www.w3.org/2010/webperf/

http://www.w3.org/TR/animation-timing/

moz webkit

var rId = requestAnimationFrame(function(time){

// do something

});

// optional

clearAnimationFrame(rId)

Code to execute

Time when the paint will happen

(function(){

function moveTheThing(){

// actually move the thing

requestAnimationFrame(moveTheThing);

}

requestAnimationFrame(moveTheThing);

}());

New Animation Loop

Hey browser! I’m animating!

(function(){

var element = document.getElementById("box");

function moveTheThing(){

element.style.left = (element.offsetLeft + 5) + "px";

requestAnimationFrame(moveTheThing);

}

requestAnimationFrame(moveTheThing);

}());

New Animation Loop

(function(){

var element = document.getElementById("box"),

start = Date.now();

function moveTheThing(time){

var since = (time || Date.now()) – start;

element.style.left = (element.offsetLeft + since)+ "px";

requestAnimationFrame(moveTheThing);

}

requestAnimationFrame(moveTheThing);

}());

New Animation Loop

<button id="btn" style="font-size: 30px; padding: 0.5em 1em">Click Me</button>

<script>

window.onload = function(){

document.getElementById("btn").onclick = function(){

requestAnimationFrame(function() {

//do something

});

};

};

</script>

When ClickedUI Thread

UI Queuetime

Update UI

Update UI

onclick

When ClickedUI Thread

UI Queuetime

Update UI

Update UI

onclickDraw down state

When ClickedUI Thread

UI Queuetime

Update UI

Update UI

onclick

Call to requestAnimationFrame()UI Thread

UI Queuetime

Update UI

Update UI

onclick

Changes

Anim Frame

When ClickedUI Thread

UI Queuetime

Update UI Update UI

Draw up state

onclick

Changes

Anim Frame

Before Next FrameUI Thread

UI Queuetime

Update UI Update UIonclick

Anim Frame

Changes

Naminate!UI Thread

UI Queuetime

Update UI Update UIonclick Changes Anim Frame

Draw whatever changes are necessary

[requestAnimationFrame()’s framerate is] capped at 1000/(16 + N) fps, where N is the number of ms it takes your callback to execute. If your callback takes 1000ms to execute, then it's capped at under 1fps. If your callback takes 1ms to execute, you get about 60fps.

-Boris Zbarsky (Mozilla) via Paul Irish (Google)

Animate all the things!!!…with CSS and requestAnimationFrame

What about other things?

https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/setImmediate/Overview.html

var iId = setImmediate(function(){

// do something

});

// optional

clearImmediate(iId)

Code to execute

msSetImmediate()msClearImmediate()

<button id="btn" style="font-size: 30px; padding: 0.5em 1em">Click Me</button>

<script>

window.onload = function(){

document.getElementById("btn").onclick = function(){

setImmediate(function() {

//do something

});

};

};

</script>

When ClickedUI Thread

UI Queuetime

Update UI

Update UI

onclick

When ClickedUI Thread

UI Queuetime

Update UI

Update UI

onclickDraw down state

When ClickedUI Thread

UI Queuetime

Update UI

Update UI

onclick

Call to setImmediate()UI Thread

UI Queuetime

Update UI

Update UI

onclick

ChangesAlways added after the last UI update in

the queue

When ClickedUI Thread

UI Queuetime

Update UI Update UI

Draw up state

onclick

Changes

Immediately!UI Thread

UI Queuetime

Update UI Update UIonclick Changes

https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/setImmediate/Overview.html

ON HOLD!

http://www.w3.org/TR/workers/

//in page

var worker = new Worker("process.js");

worker.onmessage = function(event){

useData(event.data);

};

worker.postMessage(values);

//in process.js

self.onmessage = function(event){

var items = event.data;

for (var i=0,len=items.length; i < len; i++){

process(items[i]);

}

self.postMessage(items);

};

When ClickedUI Thread

UI Queuetime

Update UI

Update UI

onclick

When ClickedUI Thread

UI Queuetime

Update UI

Update UI

onclickDraw down state

When ClickedUI Thread

UI Queuetime

Update UI

Update UI

onclick

Create Web WorkerUI Thread

UI Queuetime

Update UI

Update UI

onclick

Creates a background

thread/process/etc.

postMessage()UI Thread

UI Queuetime

Update UI Update UIonclick

process

Worker CompleteUI Thread

UI Queuetime

Update UI Update UIonclick

onmessage

FutureUI Thread

UI Queuetime

Update UI Update UIonclick onmessage

Recommendations

• Use as few as necessary• If multiple are necessary, use a single timer that can

accommodate allTimers

• Use CSS transitions and animations first• If not possible, use requestAnimationFrame()Animation

• Use web workers for efficient data processing• If no other options, use timers (see first point)Other

EtceteraMy company: • wellfurnished.com

My blog: • nczonline.net

Twitter • @slicknet

These Slides: • slideshare.net/nzakas

top related