tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

getbuffersubdata-nonblocking-benchmark.html (6899B)


      1 <!--
      2 Copyright (c) 2019 The Khronos Group Inc.
      3 Use of this source code is governed by an MIT-style license that can be
      4 found in the LICENSE.txt file.
      5 -->
      6 
      7 <!DOCTYPE html>
      8 <html>
      9 <head>
     10 <meta charset="utf-8">
     11 <title>getBufferSubData non-blocking test</title>
     12 <link rel="stylesheet" href="../resources/js-test-style.css"/>
     13 <script src="../js/js-test-pre.js"></script>
     14 <script src="../js/webgl-test-utils.js"> </script>
     15 </head>
     16 <body>
     17 <div id="description"></div>
     18 <div id="console"></div>
     19 <script>
     20 "use strict";
     21 description("Test that getBufferSubData is non-blocking when used with fenceSync");
     22 
     23 var wtu = WebGLTestUtils;
     24 
     25 var gl = wtu.create3DContext(undefined, undefined, 2);
     26 
     27 const srcData = new Uint8Array([ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0 ]);
     28 const zeroData = new Uint8Array(8);
     29 
     30 const srcBuffer = gl.createBuffer();
     31 gl.bindBuffer(gl.COPY_READ_BUFFER, srcBuffer);
     32 gl.bufferData(gl.COPY_READ_BUFFER, srcData, gl.STATIC_DRAW);
     33 
     34 const readbackBuffer = gl.createBuffer();
     35 gl.bindBuffer(gl.COPY_WRITE_BUFFER, readbackBuffer);
     36 gl.bufferData(gl.COPY_WRITE_BUFFER, 8, gl.STREAM_READ);
     37 
     38 // unrelated buffers for tests
     39 gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer()); // used as copy dst
     40 gl.bufferData(gl.ARRAY_BUFFER, 8, gl.STATIC_DRAW);
     41 gl.bindBuffer(gl.UNIFORM_BUFFER, gl.createBuffer()); // used as copy src
     42 gl.bufferData(gl.UNIFORM_BUFFER, 8, gl.STATIC_DRAW);
     43 
     44 const dest = new Uint8Array(8);
     45 
     46 // Makes a new "resolvable" Promise
     47 function resolvable() {
     48    let resolve;
     49    const promise = new Promise(res => { resolve = res; });
     50    promise.resolve = resolve;
     51    return promise;
     52 }
     53 
     54 function fence() {
     55    const promise = resolvable();
     56 
     57    const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
     58    gl.flush();
     59    function check() {
     60        const status = gl.clientWaitSync(sync, 0, 0);
     61        if (status == gl.ALREADY_SIGNALED || status == gl.CONDITION_SATISFIED) {
     62            gl.deleteSync(sync);
     63            promise.resolve();
     64        } else {
     65            setTimeout(check, 0);
     66        }
     67    }
     68    setTimeout(check, 0);
     69 
     70    return promise;
     71 }
     72 
     73 function writeToReadbackBuffer() {
     74    gl.copyBufferSubData(gl.COPY_READ_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, 8);
     75 }
     76 
     77 function timedGetBufferSubData() {
     78    dest.fill(0);
     79    const t0 = performance.now();
     80    gl.getBufferSubData(gl.COPY_WRITE_BUFFER, 0, dest);
     81    return (performance.now() - t0);
     82 }
     83 
     84 function timeBlockingReadback() {
     85    const promise = resolvable();
     86    setTimeout(() => {
     87        writeToReadbackBuffer();
     88        const tBlocking = timedGetBufferSubData();
     89        const tLatency = tBlocking;
     90        promise.resolve({latency: tLatency, blocking: tBlocking});
     91    }, 0);
     92    return promise;
     93 }
     94 
     95 function timeNonblockingReadback() {
     96    writeToReadbackBuffer();
     97    const tLatency0 = performance.now();
     98    return fence().then(() => {
     99        const tBlocking = timedGetBufferSubData();
    100        const tLatency = performance.now() - tLatency0;
    101        return {latency: tLatency, blocking: tBlocking};
    102    });
    103 }
    104 
    105 function timeReadbackWithUnrelatedCopy() {
    106    writeToReadbackBuffer();
    107    const tLatency0 = performance.now();
    108    const f = fence();
    109    // copy to a buffer unrelated to the readback
    110    gl.copyBufferSubData(gl.COPY_READ_BUFFER, gl.ARRAY_BUFFER, 0, 0, 8);
    111    return f.then(() => {
    112        const tBlocking = timedGetBufferSubData();
    113        const tLatency = performance.now() - tLatency0;
    114        return {latency: tLatency, blocking: tBlocking};
    115    });
    116 }
    117 
    118 function timeReadbackInterrupted() {
    119    writeToReadbackBuffer();
    120    const tLatency0 = performance.now();
    121    const f = fence();
    122    // interrupt the readback by inserting another write
    123    gl.copyBufferSubData(gl.UNIFORM_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, 8);
    124    return f.then(() => {
    125        const tBlocking = timedGetBufferSubData();
    126        const tLatency = performance.now() - tLatency0;
    127        return {latency: tLatency, blocking: tBlocking};
    128    });
    129 }
    130 
    131 function computeMean(timings) {
    132    let total = 0;
    133    for (let i = 0; i < timings.length; ++i) {
    134        total += timings[i];
    135    }
    136    return total / timings.length;
    137 }
    138 
    139 function measureMean(fn, iterations) {
    140    const timingsLatency = Array(iterations);
    141    const timingsBlocking = Array(iterations);
    142 
    143    // Chain together `iterations` promises to call `fn` sequentially.
    144    let promise = Promise.resolve();
    145    for (let i = 0; i < iterations; ++i) {
    146        promise = promise
    147            .then(fn)
    148            .then(t => {
    149                timingsLatency[i] = t.latency;
    150                timingsBlocking[i] = t.blocking;
    151            });
    152    }
    153 
    154    return promise.then(() => {
    155        const meanLatency = computeMean(timingsLatency);
    156        const meanBlocking = computeMean(timingsBlocking);
    157        return { latency: meanLatency, blocking: meanBlocking };
    158    });
    159 }
    160 
    161 let t_blocking, t_nonblocking;
    162 let t_unrelated;
    163 let t_interrupted;
    164 Promise.resolve()
    165    .then(() => {
    166        let iterations = 500;
    167        debug(`blocking readback: mean over ${iterations} iterations...`);
    168        return measureMean(timeBlockingReadback, iterations);
    169    })
    170    .then(t => {
    171        t_blocking = t;
    172        debug(`... latency = ${t.latency}ms, blocking = ${t.blocking}ms`);
    173    })
    174    .then(() => shouldBeTrue("areArraysEqual(dest, srcData)"))
    175 
    176    .then(() => debug(""))
    177    .then(() => {
    178        let iterations = 500;
    179        debug(`nonblocking readback: mean over ${iterations} iterations...`);
    180        return measureMean(timeNonblockingReadback, iterations);
    181    })
    182    .then(t => {
    183        t_nonblocking = t;
    184        debug(`... latency = ${t.latency}ms, blocking = ${t.blocking}ms`);
    185    })
    186    .then(() => shouldBeTrue("areArraysEqual(dest, srcData)"))
    187 
    188    .then(() => debug(""))
    189    .then(() => {
    190        let iterations = 500;
    191        debug(`readback interrupted by unrelated read from copy source: mean over ${iterations} iterations...`);
    192        return measureMean(timeReadbackWithUnrelatedCopy, iterations);
    193    })
    194    .then(t => {
    195        t_unrelated = t;
    196        debug(`... latency = ${t.latency}ms, blocking = ${t.blocking}ms`);
    197    })
    198    .then(() => shouldBeTrue("areArraysEqual(dest, srcData)"))
    199 
    200    .then(() => debug(""))
    201    .then(() => {
    202        let iterations = 500;
    203        debug(`readback interrupted by write to readback source: mean over ${iterations} iterations...`);
    204        return measureMean(timeReadbackInterrupted, iterations);
    205    })
    206    .then(t => {
    207        t_interrupted = t;
    208        debug(`... latency = ${t.latency}ms, blocking = ${t.blocking}ms`);
    209    })
    210    .then(() => shouldBeTrue("areArraysEqual(dest, zeroData)"))
    211 
    212    .then(() => {
    213        debug("");
    214        shouldBeTrue("t_nonblocking.blocking < t_blocking.blocking");
    215        shouldBeTrue("t_unrelated.blocking < t_blocking.blocking");
    216        shouldBeTrue("t_nonblocking.blocking < t_interrupted.blocking");
    217    })
    218    .then(finishTest);
    219 
    220 var successfullyParsed = true;
    221 </script>
    222 </body>
    223 </html>