Benchmarking GuidesOctober 22, 202612 min read

How to Compare GPU Benchmark Results with CSV and JSON

Build a repeatable Volume Shader BM Test report: export CSV or JSON, document test conditions, compare repeated runs, and interpret FPS changes accurately.

A GPU benchmark screenshot captures a number. A useful benchmark report explains how that number was produced and whether another run supports the same conclusion. That difference matters when you compare two laptops, investigate a browser update, or check whether a power setting changes performance.

Suppose one result says 48 FPS and another says 51 FPS. The second number is higher, but several explanations remain possible. The browser version may have changed, the first device may have been running on battery, or the second run may have used a different shader. Even a correctly measured number becomes misleading when the surrounding conditions disappear.

The Volume Shader BM Test can download its current results as CSV or JSON. Those files provide a practical starting point for a comparison, provided you understand their contents and keep a separate record of conditions they do not include. This guide develops that workflow from the initial question through a report somebody else can assess.

Start with one question you can answer

Write your comparison question before running the test. A narrow question gives you a clear choice of conditions and a sensible interpretation afterward. For example: does this laptop produce a different average FPS in the default browser shader when connected to power, under otherwise similar conditions?

That question defines the device, workload, comparison, and measured outcome. It also prevents a common leap from a small experiment to a broad claim. A result about one browser shader does not establish which laptop is best for every game, which graphics architecture is fastest, or whether a component is healthy.

For a browser comparison, keep the hardware and operating environment stable while changing the browser. For a device comparison, document the differences you cannot hold constant. For a shader experiment, save both versions of the shader and describe what changed. These are different investigations, and their reports should make that distinction visible.

Choose the outcome in advance as well. Average FPS is a reasonable primary value for a short throughput comparison within this tool. Whether a run completes successfully and whether the image renders correctly can also matter. Deciding this first makes it less tempting to select whichever metric happens to favor the result you expected.

Understand the workload behind the export

The current benchmark uses WebGL 1 and a drawing buffer fixed at 1024 × 1024 pixels. It runs a default shader unless you apply an edited kernel. Resizing the browser changes how the canvas appears on the page; it does not provide a new selectable internal benchmark resolution.

The rendering loop requests browser animation callbacks, draws the scene, waits for submitted graphics work through gl.finish(), and counts completed iterations. Its FPS therefore describes this particular browser rendering loop. It is not a direct reading of shader execution time in isolation. Browser scheduling and the work around rendering remain part of the observed result.

This distinction also explains why two capable devices can return similar scores near a scheduling ceiling. Animation callbacks generally follow the display refresh cycle, according to the requestAnimationFrame documentation. A comparison near that ceiling may reveal little about additional GPU capacity. Check the browser refresh-rate guide before treating a matching score as evidence of matching hardware performance.

There is another limitation worth recording for careful experiments: the scene rotates by a fixed angle per rendered frame. Devices running at different frame rates therefore move through viewing angles at different speeds. Reloading the page restores the initial view, but it does not create an identical camera trajectory across devices. Treat this as a practical browser workload comparison with a moving scene, rather than a rigorously matched sequence of rendered views.

Record conditions the download cannot know

Create a short experiment note next to your result files. Include the device model, operating-system version, browser version, power connection, selected power mode, active display, and operating-system refresh-rate setting. Write down whether background video, recording software, or other graphics applications were active.

These details need not become a hardware inventory. Record the conditions that could explain your comparison. If you are investigating an external display, its connection and selected mode belong in the note. If you are comparing battery and plugged-in operation, include the relevant power settings and approximate battery state. Keep unrelated details out so the meaningful differences remain easy to find.

The export includes a browser-reported GPU description, but that description can be generic or masked. An unknown renderer is missing identification information, not proof of a graphics failure. If device capabilities matter to your question, save a separate WebGL report and use the report interpretation guide to explain it.

Record your preparation procedure too. State whether you ran a preliminary test, how you decided the device was ready, and how you handled recovery between runs. There is no universal waiting period that makes every laptop or phone start at the same temperature. Consistency and an honest description are more useful than claiming a cooling interval guarantees equivalent conditions.

Use a consistent run procedure

For an initial comparison, choose a practical target such as approximately 30 seconds of active running time. This is an example protocol, not a built-in duration preset or a claim that 30 seconds is sufficient for every investigation. The benchmark currently requires you to stop the run manually, so preserve the actual recorded duration.

Use the same sequence for each measured run:

  1. Reload the benchmark page to restore the initial view and default shader.
  2. Confirm the intended device, browser, display, and power condition.
  3. Start the benchmark and leave the page visible without dragging or zooming the scene.
  4. Stop at the chosen target duration, allowing for normal manual timing differences.
  5. Download the result before starting another run or changing the shader.
  6. Add the run identifier, actual duration, and any interruption to your experiment note.

The stop control preserves the completed summary, including the final partial reporting window. Starting the benchmark again clears the previous metrics; it does not continue accumulating the stopped run. Camera position also persists across stopping and starting, which is why a fresh page load is useful when you want a consistent starting view.

Leaving the tab hidden stops the benchmark. If you switch away accidentally, keep the file if it is useful for documenting the interruption, but mark it as interrupted and repeat the intended run. Do not silently combine it with full-length runs. A report should explain exclusions using rules that would apply equally to both conditions.

For custom shader work, reload first, paste the exact intended source, and apply it before measuring. Editing the text alone does not change the running shader. Changing the applied kernel clears or restarts the statistics, so export the current result before applying a different kernel or restoring the default. While stopped, using Apply or Reset clears the displayed results. Resetting a shader does not restore the camera view.

Know what CSV and JSON contain

The two download formats describe the same summary. CSV contains a header row and a single data row for the exported result. JSON presents the named fields as one object. Neither format from the main benchmark contains a timestamped sequence of individual frames or a history of every reporting window.

Use CSV when you want to place several runs into a spreadsheet and compare their columns. Use JSON when you want a clearly structured original record or intend to process results with a script. You can keep both, but downloading both is not necessary to create a credible report.

FieldMeaning in the current export
exportedAtTime the file was generated, expressed as an ISO timestamp
browser, os, gpuEnvironment descriptions reported or inferred by the page
api, resolutionGraphics API label and fixed drawing-buffer dimensions
kernelWhether the applied kernel is identified as default or custom
fpsFPS for the latest reported measurement window
fpsAvgTotal rendered frames divided by total active running seconds
fpsMin, fpsMaxLowest and highest window FPS values included in the summary
frameTimeMean milliseconds per rendered frame in the latest reported window
framesRendered, durationMsTotal counted frames and measured active duration

Most reporting windows are about 500 milliseconds, while the final window on stopping can be shorter. Minimum and maximum FPS therefore describe window summaries. They are not the slowest and fastest individual frames, 1% lows, or timing percentiles.

The exportedAt field is the download time, not a precise test-start timestamp. The kernel field records a classification, not the custom GLSL source. The file also omits camera position, selected display mode, detailed power settings, GPU temperature, and physical power consumption. Keep any information required by your question in the accompanying note.

Read an example without overinterpreting it

The following JSON is an illustrative record with invented values and placeholder environment descriptions. It is not a measurement from a particular device:

{
  "exportedAt": "2026-10-22T04:00:00.000Z",
  "browser": "Example browser version",
  "os": "Example operating system",
  "gpu": "Example browser-reported renderer",
  "api": "WebGL 1.0",
  "resolution": "1024x1024",
  "kernel": "default",
  "fps": 60,
  "fpsAvg": 60,
  "fpsMin": 58,
  "fpsMax": 61,
  "frameTime": 16.67,
  "framesRendered": 1800,
  "durationMs": 30000
}

The average is consistent with 1,800 frames over 30 measured seconds. The latest window corresponds to approximately 16.67 milliseconds per frame. That agreement helps explain the units, but it does not establish that every individual frame took exactly that long.

Now imagine a different record where average FPS is 50 and the latest FPS is 40. This can happen if performance changes over the run. The exported frame-time value belongs to the latest window, so you should not expect it to equal 1000 divided by the overall average FPS. Those numbers describe different intervals.

If you need the overall mean time per counted frame, calculate total active milliseconds divided by total rendered frames. Label that derived value explicitly. The FPS calculator can help interpret rates, but a reciprocal conversion still does not reveal individual timing spikes or total input latency.

Keep original files and a separate comparison table

Give each run a stable identifier, such as A-01 or B-03, and put that identifier in your notes and working table. Store the original downloads unchanged in a results folder. A filename such as A-01-default-plugged-in.json is easier to connect to your experiment than a screenshot labeled “best score.”

Build a separate table with one row per run. Useful columns include the run identifier, condition, average FPS, actual duration, rendered-frame count, browser version, kernel classification, and a brief note. If your two conditions have different labels in your own table, keep those labels separate from the original exported fields.

When importing CSV, use a CSV-aware spreadsheet importer rather than splitting text at every comma. Renderer descriptions can contain punctuation, and quoted CSV fields preserve those values as a single cell. Confirm numeric columns import as numbers before calculating a median or percentage change. Keep the originals available so an import mistake can be corrected without repeating the experiment.

Do not add invented columns for data the tool never captured. An empty temperature column is acceptable if your protocol planned a separate measurement that was unavailable. A guessed temperature is not. The same rule applies to shader source, individual frame timing, and display settings that were never documented.

Repeat runs before calculating an improvement

A single run cannot show how much results vary under the same conditions. A practical starting point is several measured runs per condition, using the same preparation and duration rules. This is a workflow recommendation, not a statistical guarantee that a particular sample count proves a difference.

Consider the following hypothetical dataset. Every value is invented to demonstrate the analysis; the table does not describe a tested device or setting:

Measured runCondition A average FPSCondition B average FPS
146.848.9
247.249.1
346.949.0
447.149.3
547.049.2

Condition A has a median of 47.0 FPS and a range of 46.8–47.2 FPS. Condition B has a median of 49.1 FPS and a range of 48.9–49.3 FPS. Comparing the medians gives an increase of approximately 4.5%, calculated as the difference divided by the original condition's median.

Those repeated observations support a more useful description than selecting the highest value from each column. They show both a typical result and the spread observed in this small experiment. They do not establish statistical significance, predict future variation, or identify the physical cause of the difference.

If the two sets overlap substantially, describe that overlap. If results drift steadily downward in both conditions, investigate the run order and starting state before summarizing them with one percentage. A median is a summary of the observations you collected; it cannot repair a comparison in which the conditions changed unintentionally.

Plan the order so time does not become the hidden variable

Running every A test before every B test is convenient, but it can mix the condition with changes that happen over time. The device may warm up, a background application may start, or a battery state may change. The later group then inherits those differences.

For conditions that are easy to switch, consider alternating their order and using the same recovery procedure between measured runs. For changes requiring a reboot, keep separate batches and document the reboot and preparation steps. If you repeat the comparison on another occasion, reversing the initial order can help reveal whether the apparent benefit follows the condition or simply the time of testing.

Alternation is not an automatic cure. Plugging in a laptop, for example, can change several aspects of operation at once. That may be exactly the user experience you want to compare, but the report should say you compared operating conditions. It should not claim to have isolated a particular GPU clock, voltage, or thermal mechanism.

Pay attention to simultaneous workload changes as well. Updating a browser while changing its profile, extensions, power policy, and display setup makes the result hard to attribute. If several changes are unavoidable, list them together and narrow the conclusion accordingly.

Write a conclusion another reader can check

A useful report names the workload, conditions, sample count, observed results, and remaining limits. Using the fictional table above, a suitable conclusion would say that condition B produced a median of 49.1 FPS compared with 47.0 FPS for condition A across five runs each in the default 1024 × 1024 browser shader. It would then give the observed ranges and explain the preparation procedure.

The conclusion should stay attached to that experiment. It would not justify saying that condition B makes all games 4.5% faster. It would not demonstrate lower input latency, better energy efficiency, or cooler hardware. Those questions require measurements designed around those outcomes.

When a result suggests a problem, choose a follow-up that resolves the uncertainty. If the latest window differs sharply from the run average, a time-resolved recording may be useful. If browser work appears irregular, the Chrome DevTools runtime-performance guide describes how to inspect a performance recording. Treat profiling as a separate diagnostic run and document the changed measurement setup.

Your final package can remain simple: original exports, an experiment note, a table of repeated runs, and a short conclusion. Start with one clear question, preserve the conditions needed to interpret the answer, and save each result before changing the test. That gives the next comparison a baseline you can actually use.

#benchmarking#gpu#csv#json#testing-methodology

Ready to benchmark your GPU?

Run the free Volume Shader BM Test in your browser and measure your graphics performance in seconds.