• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Shared benchmarking functions such as surface creation, measurement, publishing to perf.skia.org
2
3function getSurface(CanvasKit, webglversion) {
4  let surface;
5  if (window.location.hash.indexOf('gpu') !== -1) {
6    surface = CanvasKit.MakeWebGLCanvasSurface('anim', null /* colorspace */, {'majorVersion': webglversion});
7    if (!surface) {
8      window._error = 'Could not make GPU surface';
9      return null;
10    }
11    let c = document.getElementById('anim');
12    // If CanvasKit was unable to instantiate a WebGL context, it will fallback
13    // to CPU and add a ck-replaced class to the canvas element.
14    if (c.classList.contains('ck-replaced')) {
15      window._error = 'fell back to CPU';
16      return null;
17    }
18  } else {
19    surface = CanvasKit.MakeSWCanvasSurface('anim');
20    if (!surface) {
21      window._error = 'Could not make CPU surface';
22      return null;
23    }
24  }
25  return surface;
26}
27
28// Time the drawing and flushing of a frame drawing function on a given surface.
29// drawFn is expected to be a zero arg function making draw calls to a canvas
30// warmupFrames - Run this number of frames before starting to measure things.
31//   This allows us to make sure the noise from the first few renders (e.g shader
32//   compilation, caches) is removed from the data we capture.
33// Stops after timeoutMillis if provided
34// Teturns a promise that resolves with the dict of measurements.
35function startTimingFrames(drawFn, surface, warmupFrames, maxFrames, timeoutMillis) {
36  return new Promise((resolve, reject) => {
37    const totalFrame = new Float32Array(maxFrames);
38    const withFlush = new Float32Array(maxFrames);
39    const withoutFlush = new Float32Array(maxFrames);
40    let warmUp = warmupFrames > 0;
41    let idx = -1;
42    let previousFrame;
43
44    function drawFrame() {
45      let start, afterDraw, end;
46      try {
47        start = performance.now();
48        drawFn();
49        afterDraw = performance.now();
50        surface.flush();
51        end = performance.now();
52      } catch (e) {
53        console.error(e);
54        window._error = e.stack || e.toString();
55        return;
56      }
57
58      if (warmUp) {
59        idx++;
60        if (idx >= warmupFrames) {
61          idx = -1;
62          warmUp = false;
63        }
64        window.requestAnimationFrame(drawFrame);
65        return;
66      }
67      if (idx >= 0) {
68        // Fill out total time the previous frame took to draw.
69        totalFrame[idx] = start - previousFrame;
70      }
71      previousFrame = start;
72      idx++;
73      // If we have maxed out the frames we are measuring or have completed the animation,
74      // we stop benchmarking.
75      if (!window._perfData) {
76        window._perfData = {};
77      }
78      if (idx >= withFlush.length) {
79        resolve({
80          // The total time elapsed between the same point during the drawing of each frame.
81          // This is the most relevant measurement for normal drawing tests.
82          'total_frame_ms': Array.from(totalFrame).slice(0, idx),
83          // The time taken to run the code under test and call surface.flush()
84          'with_flush_ms': Array.from(withFlush).slice(0, idx),
85          // The time taken to run the code under test
86          // This is the most relevant measurement for non-drawing tests such as matrix inversion.
87          'without_flush_ms': Array.from(withoutFlush).slice(0, idx),
88        });
89        return;
90      }
91
92      // We can fill out this frame's intermediate steps.
93      withFlush[idx] = end - start;
94      withoutFlush[idx] = afterDraw - start;
95
96      if (timeoutMillis && ((beginTest + timeoutMillis) < performance.now())) {
97        console.log(`test aborted due to timeout after ${idx} frames`);
98        reject(`test aborted due to timeout after ${idx} frames`);
99        return;
100      }
101      window.requestAnimationFrame(drawFrame);
102    }
103    const beginTest = performance.now();
104    window.requestAnimationFrame(drawFrame);
105  }); // new promise
106}
107