Инструменты разработчика могут добавить много дополнительной нагрузки на устройство. Тем более, когда вы записываете журнал производительности.
Реакция - это последнее, что я бы использовал для приложения реального времени, поскольку оно добавляет закулисное пространство JS даже к самым простым задачам.
Расчет производительности путем измерения времени между кадрами не дает точного указания производительности.
Производительность
Для измерения производительности функции используйте API performance
. Самый простой способ - использовать performance.now
, чтобы получить время, необходимое для выполнения функции.
Например, чтобы получить время основной функции l oop в игре
function mainLoop(frameTime) {
const now = performance.now(); // MUST BE FIRST LINE OF CODE TO TEST!!!!
requestAnimationFrame(mainLoop);
const executeTime = performance.now() - now; // MUST BE LAST LINE OF CODE TO TEST!!!
}
Это даст вам время для выполнения в миллисекундах. Поскольку JS блокирует, измеряется только код внутри двух строк.
Примечание НЕТ дополнительных накладных расходов, таких как G C, Компоновка, синхронная загрузка и т. Д. c ...
Примечание миллисекунды (1 / 1,000,000th)
ПРИМЕЧАНИЕ точность этого значения performance.now
было намеренно уменьшено для защиты пользователей и составляет от 100 мс до 200 мс в зависимости от браузера (доступ к 1 мс возможен за флагами и конфигурацией системы))
Значимая производительность
JS выполнение не является детерминированным c, что делает единственную временную меру абсолютно ненадежной. (Причина, почему лучше использовать performance.now
, чем peformance.mark
)
Чтобы преодолеть JS недетерминированность выполнения и неточность таймера, используйте текущее среднее время ваш код. Пример ниже показывает, как это сделать.
Вместо того, чтобы показывать время, используйте metri c, который относится к потребностям приложения. Например, сколько кадра тратится на выполнение кода. (см. пример)
Пример
В этом примере анимируется некоторое содержимое холста с использованием requestAnimationFrame
.
С помощью ползунка можно выбрать приблизительное количество времени, которое функция должна потратить на рендеринг.
Текст Info в верхней части отображает результаты синхронизации как среднее значение.
Вы заметите, что идеализированная нагрузка кадра (IFL) намного ниже 100%, прежде чем частота кадров упадет.
Эксперименты
- Как Dev Tools и мониторинг производительности влияют на производительность.
Переместите ползунок чуть ниже, когда частота кадров падает ниже 60.
Откройте инструменты разработчика, чтобы увидеть, может ли и как это повлиять на кажущуюся производительность. Принять к сведению любые изменения. Есть ли эффект, и если да, то сколько?
Запишите журнал производительности и посмотрите, влияют ли на FPS и / или IFL запись
Каково максимальное время, которое ваше устройство может выделить для рендеринга до того, как будет изменена частота кадров.
Медленно перемещайте ползунок вправо.
Когда частота кадров падает ниже 60, сдвиньте слайд на шаг назад, пока он снова не покажет 60FPS.
Значения IFL дадут% идеального кадра (60-й во-вторых) выполнение кода. Время Абсолютное время выполнения в мс.
Math.rand = (min, max) => Math.random() * (max - min) + min;
Math.randItem = arr => arr[Math.random() * arr.length | 0];
CPULoad.addEventListener("input",() => loadTimeMS = Number(CPULoad.value));
var loadTimeMS = Number(CPULoad.value);
const ctx = canvas.getContext("2d");
requestAnimationFrame(mainLoop);
function mainLoop(frameTime) {
/* Timed section starts on next line */
const now = performance.now();
CPU_Load(loadTimeMS);
ctx.globalAlpha = 0.3;
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
requestAnimationFrame(mainLoop);
const exeTime = performance.now() - now;
/* Timed section ends at above line*/
measure(info, frameTime, exeTime);
}
const measure = (() => {
const MEAN = (t, f) => t += f;
const fTimes = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], bTimes = [...fTimes];
var pos = 0, prevTime, busyFraction;
return (el, time, busy) => {
if (prevTime) {
bTimes[pos % bTimes.length] = busy;
fTimes[(pos ++) % fTimes.length] = time - prevTime;
const meanBusy = bTimes.reduce(MEAN, 0) / bTimes.length;
const meanFPS = fTimes.reduce(MEAN, 0) / fTimes.length;
el.textContent = "Load: " + loadTimeMS.toFixed(1) + "ms " +
" FPS: " + Math.round(1000 / meanFPS) +
" IFL: " + (meanBusy / (1000 / 60) * 100).toFixed(1) + "%" +
" Time: " + meanBusy.toFixed(3) + "ms";
busyFraction = meanBusy / (1000/60);
}
prevTime = time;
};
})();
const colors = "#F00,#FF0,#0F0,#0FF,#00F,#F0F,#000,#FFF".split(",");
// This function shares the load between CPU and GPU reducing CPU
// heating and preventing clock speed throttling on slower systems.
function CPU_Load(ms) { // ms = microsecond and is a min value only
const now = performance.now();
ctx.globalAlpha = 0.1;
do {
ctx.fillStyle = Math.randItem(colors);
ctx.fillRect(Math.rand(-50,250), Math.rand(-50, 100), Math.rand(1, 200), Math.rand(1,100))
} while(performance.now()-now <= ms);
ctx.globalAlpha = 1;
}
body {
font-family: arial;
}
#info {
position: absolute;
top: 10px;
left: 10px;
background: white;
font-size:small;
width:345px;
padding-left: 3px;
}
#canvas {
background: #8AF;
border: 1px solid black;
}
#CPULoad {
font-family: arial;
position: absolute;
top: 130px;
left: 10px;
color: black;
width: 340px !important;
}
<code id="info"></code>
<input id="CPULoad" min="0" max="36" step="0.5" value="2" type="range" list="marks"/>
<canvas id="canvas" width="350"></canvas>
<datalist id="marks">
<option value="0"></option>
<option value="4"></option>
<option value="8"></option>
<option value="12"></option>
<option value="16"></option>
<option value="20"></option>
<option value="24"></option>
<option value="28"></option>
<option value="32"></option>
<option value="36"></option>
</datalist>
ПРИМЕЧАНИЕ Отображение времени влияет на результаты. Тот факт, что этот код выполняется в песочнице, повлияет на результаты Для получения наиболее точных результатов запустите код на независимой странице. Записать результаты в JS структуру данных и отобразить результаты после тестового прогона.
Load : Запрошенная загрузка процессора / графического процессора за 1/1000-ую секунду.
FPS : среднее значение кадров в секунду.
IFL : идеальная нагрузка на раму, процент от 60-й код выполнения.
Время : среднее измеренное время выполнения в 1/1000-й секунде.