Академический Документы
Профессиональный Документы
Культура Документы
js Wiki
Words of Caution!
When it comes to performance, it's tempting to try to squeeze out as much speed as you can
right from the get-go. Writing code is a balancing act between trying to write something that is
easy to read & maintain and something that gets the job done. Performance optimizations
often come with some sacrifices, so in general, you should only worry about optimizing when
you know there is a speed problem.
https://github.com/processing/p5.js/wiki/Optimizing-p5.js-Code-for-Performance 1/10
9/25/2019 Optimizing p5.js Code for Performance · processing/p5.js Wiki
Along with that, it's important to keep in mind a general mantra of "optimize the algorithm, not
the code." Sometimes, you will get nice gains from micro-optimizing a line of code or two. But
generally speaking, the biggest gains you get tend to come from changing your approach.
E.g. if you have code that loops through every single pixel in an image, you will certainly
speed up your code if you decide that you can instead just look through every other pixel.
You can see your current FPS easily in one of two ways.
In p5, you can call frameRate() without any parameters to get the current FPS. Then you
can dump that to the console or draw it to the screen:
// Draw FPS (rounded to 2 decimal places) at the bottom left of the screen
let fps = frameRate();
fill(255);
stroke(0);
text("FPS: " + fps.toFixed(2), 10, height - 10);
With Chrome or the p5 editor, you can open up the developer tools and turn on the "Show
FPS meter" options to get a graph of FPS. This is nice because it allows you to see how the
FPS changes over time.
In Chrome, open the developer tools (Windows hotkey: Ctrl + Shift + I or F12 , Mac
hotkey: Cmd + Opt + I ) and then follow these instructions:
In the p5 Editor:
Manual Profiling
https://github.com/processing/p5.js/wiki/Optimizing-p5.js-Code-for-Performance 2/10
9/25/2019 Optimizing p5.js Code for Performance · processing/p5.js Wiki
To find out how long a piece of code takes to run, you want to know the time when the code
starts running and the time when it finishes running. In p5, you can get the current time in
milliseconds using millis() . (Under the hood, this function just returns the result of a
native JS method: performance.now() .)
Usually, you will want to run the code you are trying to profile many times and then find the
average time that it took to run. See any of the performance tests in code/ for examples.
Note: console.log() and println() will definitely slow down your code, so be sure to
remove them from the final version of your project!
Automated Profiling
Again, the developer tools in Chrome and the p5 editor come to the rescue with some
automated tools. With the CPU profiler, you can see how much time is spent in each function
within your code without adding any manual timing code. When you are dealing with a
complicated project and you are not sure where to start optimizing, this is a helpful starting
point.
When you want to profile your code, open the developer tools (hamburger icon in the p5
editor). Go to the "Profiles" tab, select "Collect JavaScript CPU Profile" and hit start. This will
start timing your code. When you've recorded a large enough sample, stop the recording and
take a look at the results:
It's helpful to look at the CPU profiler results for some real code. The recording for this
section is a p5 sketch that gets an image from the webcam, sorts the pixels by hue and then
draws them to the screen (see code/cpu-profiler-demo). There are four main functions:
https://github.com/processing/p5.js/wiki/Optimizing-p5.js-Code-for-Performance 3/10
9/25/2019 Optimizing p5.js Code for Performance · processing/p5.js Wiki
sortHue - compares the hue of two colors in order to decide how they should be
ordered
drawPixels - draw the pixels to the screen as colored rectangles
The default view of the recording is a table of functions with their associated timing. It gives
you the "self" and "total" times for all the functions in your code. Self time is the amount of
time spent on the statements in a function excluding calls to other functions. Total time is the
amount of time that it took to run that function and any functions that it calls.
From the total times, we can see that roughly equal amounts of time were spent in
samplePixels , drawPixels and sortPixels , so any of them are candidates for trying
optimizations. Here, the easiest optimization with the biggest gains would simply be to
reduce the number of pixels sampled from the camera frame. That will speed up all three
functions.
If you switch the view of the recording from "Heavy (Bottom Up)" to "Chart," you can get a
better sense of the breakdown and interactively explore the recording:
Given that the CPU profiler is simply going to show you a table that has function names, it is
important for the functions in your code to actually have names. So you should:
Benchmarking
If you have a suspicion that a p5.js function has low performance or think that you would like
to work on work on implementing some performance optimizations to p5.js, then you should
definitely check out our benchmarking system.
p5 Performance Tips
This tutorial was written using a build of the p5.js master branch on 7/21/16. This might mean
that some of the features or optimizations that are mentioned haven't rolled out in a release
on the p5.js website yet. If you want to create your own custom build from the master branch,
you can follow the instructions here.
https://github.com/processing/p5.js/wiki/Optimizing-p5.js-Code-for-Performance 4/10
9/25/2019 Optimizing p5.js Code for Performance · processing/p5.js Wiki
When you use the non-minified p5.js file (as opposed to p5.min.js), there is a friendly error
system that will warn you at times, for example, if you input unexpected arguments into a
function. This error checking system can significantly slow down your code (up to ~10x in
some cases). See the friendly error performance test.
You can disable this with one line of code at the top of your sketch:
function setup() {
// Do setup stuff
}
function draw() {
// Do drawing stuff
}
Note that this will disable the parts of the FES that cause performance slowdown (like
argument checking). Friendly errors that have no performance cost (like giving an descriptive
error if a file load fails, or warning you if you try to override p5.js functions in the global
space), will remain in place. You can learn more about the Friendly Error system here.
Switch Platforms
If possible, you can try switching platforms. As of p5.js v0.5.2 and p5 editor v0.6.0:
These are generalizations that depend on the specific code you are trying to run and what
version of the platform you are using. See the particle system performance test for a real
example.
Many of the p5 methods come with an overhead. For example: sin(...) needs to check
whether p5 is in degree mode or radian mode before it can calculate the sin; random(...)
needs to check whether you have passed in a max and/or min before calculating a random
value. In both of these cases, you can just use Math.random(...) or Math.sin(...) .
https://github.com/processing/p5.js/wiki/Optimizing-p5.js-Code-for-Performance 5/10
9/25/2019 Optimizing p5.js Code for Performance · processing/p5.js Wiki
The speed boost you will get depends on the specific p5 methods you are using. In v0.5.3,
many methods have been optimized (e.g. abs , sqrt , log ), but you can still see a
performance boost for using Math.random , Math.sin , Math.min over their p5
counterparts. This is especially true for v0.6.0 of the p5 editor. See the native vs p5
performance test:
Image Processing
Sampling/Resizing
When looping through the pixels in an image, you can get an easy performance boost by
simply reducing the size of your image or by sampling it. If you have an 1000 x 1000 image
that you are working with, you are iterating through 1000000 pixels. If you chop that image in
half to 500 x 500 (250000 pixels), you now only need to do 1/4th of the iterations you were
doing previously. That's a pretty major savings.
1. Resize the image before runtime using Photoshop, GIMP, etc. This will likely yield the
best quality shrunken image because you can control the resizing algorithm and apply
filters to sharpen the image.
2. Resize the image using p5.Image's resize method. Here, you are at the whim of the
browser for how it handles downsampling interpolation. (Well, you do have some not
https://github.com/processing/p5.js/wiki/Optimizing-p5.js-Code-for-Performance 6/10
9/25/2019 Optimizing p5.js Code for Performance · processing/p5.js Wiki
If you can, resizing the image beforehand gives you the most control over the final visuals. If
you can't (e.g. processing frames of a video), sampling or resizing should serve you well.
One last note! If you are doing drastic resizing of an image or you have an image with
important fine details (e.g. vector art, line drawing, detailed patterns, etc.), sampling or
resizing can give pretty poor results. Here's a 1900 x 1900 floral pattern (source) resized to
100 x 100:
That last method - iterative resizing - can also be found in code/resizing-images. The
approach - taken from this stack overflow answer - is to resize the image in steps. This is
helpful when you can't resize an image ahead of time, and the regular resizing approach is
dropping important details.
If you can, it's best to frontload image processing. Do as much as you can during setup() ,
so that your draw() loop can be as fast as possible. This will help prevent the interactive
parts of your sketch from becoming sluggish.
For example, if you need color information from an image for a p5 sketch, extract & store the
p5.Color objects during setup() . Then in draw() , you can look up the cached color
information when you need it, as opposed to recalculating it on the fly.
DOM Manipulation
The Document Object Model (DOM) is the programming interface that gives us access to
create, manipulate and remove HTML elements. There are some common DOM pitfalls that
will really hurt your performance.
https://github.com/processing/p5.js/wiki/Optimizing-p5.js-Code-for-Performance 7/10
9/25/2019 Optimizing p5.js Code for Performance · processing/p5.js Wiki
When working with the DOM, you want to avoid causing the browser to unnecessarily
"reflow" or re-layout all the elements on the page for every change you make. What you want
to do is batch all your DOM changes together, so you can make one large change as
opposed to many small changes. When you cause the browser to constantly re-layout the
page with many small changes, this is commonly called layout thrashing.
Here's a gist that lists many of the DOM methods and properties that can trigger a reflow.
The browser will try to be "lazy" and put off reflow as long as it can, but some things (like
asking for an element's offsetLeft ) necessitate a reflow.
There are a number of ways you can batch your changes and avoid layout thrashing.
Unfortunately, p5.Element and the p5.dom addon do not currently give you a lot of room for
batching. For instance, creating a p5.element will cause layout thrashing (via offsetWidth
and offsetHeight ).
If you are running into DOM performance issues, your best approach is likely to take control
and go with plain JavaScript or use a DOM manipulation library (e.g. fastdom). See
code/reflow-dom-manipulation for a performance test of DOM manipulation in p5 vs native
JS. In that case, native JS that avoids reflow is ~400x - 500x times faster.
Before rewriting your code, make sure that layout thrashing is the problem! The timeline tool
in Chrome is a good place to start. It will highlight code that is likely causing a forced reflow,
and it can show you how much time is spent rendering the page vs running the JS:
Minimize Searching
Searching for elements in the DOM can be costly - especially if you are doing the searching
during draw() . Minimize DOM lookups by storing references to your elements in setup() .
For example, if you have a button that you are constantly repositioning so that it runs away
from the mouse cursor:
let button;
function setup () {
// Store a reference to the element in setup
button = select("#runner");
}
function draw() {
let x, y;
// Do some stuff to figure out where to move the button
button.position(x, y);
}
https://github.com/processing/p5.js/wiki/Optimizing-p5.js-Code-for-Performance 8/10
9/25/2019 Optimizing p5.js Code for Performance · processing/p5.js Wiki
See code/cache-dom-lookups for a performance test. In the test, caching the element was
~10x faster than constantly re-searching for the element. The performance boost will vary
depending on the depth of your DOM tree and the complexity of your selector.
Math Tips
When you need to compare distances between points or magnitudes of vectors, try
using distance squared or magnitude squared (p5.Vector.magSq). See code/distance-
squared for a performance test.
https://p5js.org/
If you would like to edit this wiki and don't already have edit access, please open an issue or comment on an
existing one noting the wiki page you'd like to edit. You will then be added as a repository contributor with
edit access.
Pages 23
Find a Page…
Home
Archived Content
Educational Resources
Embedding p5.js
https://github.com/processing/p5.js/wiki/Optimizing-p5.js-Code-for-Performance 9/10
9/25/2019 Optimizing p5.js Code for Performance · processing/p5.js Wiki
JavaScript basics
Local server
https://github.com/processing/p5.js.wiki.git
https://github.com/processing/p5.js/wiki/Optimizing-p5.js-Code-for-Performance 10/10