High average FPS but bad 1% lows: what that means

The average is the mean of every frame, which is exactly what hides the frames you feel — what a 1% low is, what a big gap between the two tells you, and how to know whether a change moved it.

The counter says 200 and the game feels like 90. Nothing is broken, nothing freezes for a whole second, but a fight never feels the way the number promises. That experience has a name and a measurement, and once you can read it you stop chasing the wrong number.

First, the honest sentence. This page explains a measurement, not a fix. w0a prints no "FPS gained" figure anywhere, so whether a change helped is something you read from your own before-and-after captures, against your own run-to-run noise — and every number below can be recomputed from the file the Benchmark page saves.

What the three numbers actually are

Sort every frame in a run from slowest to fastest.

Frame time is the same data in milliseconds, and the arithmetic is worth memorising because it makes the rest of this page concrete: 16.7 ms is 60 FPS, 6.9 ms is 144, 4.2 ms is 240.

So a run with a 200 average and a 1% low of 70 is a run where the typical frame took about 5 ms and the worst hundredth took about 14 — nearly three times as long. And at 200 FPS, one per cent of your frames is two frames every second. Twice a second, the picture is standing still for three frames' worth of time. That is what you are feeling, and no amount of average tells you about it.

Read the gap, not the number

A 1% low of 70 is excellent in a 90 FPS run and alarming in a 200 FPS one. The useful reading is the relationship:

What you seeWhat it usually means
Average and 1% low close togetherConsistent delivery. This is what "smooth" is, even at a modest frame rate.
1% low far below the averageSomething is interrupting an otherwise healthy run — an event, not a workload.
0.1% low far below the 1% lowRare, deep events: a driver reset, a paging storm, a long disk read.
Everything low togetherYou are simply asking for more than the hardware delivers. Lower a setting.

That third row is easy to misread. If your 1% low is fine and your 0.1% low is terrible, you do not have a pacing problem — you have a handful of specific incidents, and incidents can be found.

Why a bad tail is a different problem from a low average

A low average is a workload question: the machine is doing as much as it can and it is not enough. The answer is a setting, a resolution, or different hardware.

A bad tail is an event question: the machine is mostly keeping up and something periodically stops it. The answer is finding that thing. The list is short and each item leaves a trace — a driver holding a processor core, pages coming back from disk, an asset read, a background task, a shader compiling, a driver reset. Why games stutter on Windows 11 walks that list cause by cause, and what the stutter scan looks for is the automated version, which labels each finding as proven, likely, a candidate or not checked rather than handing you a confidence score it did not earn.

There is a middle case too: a machine that is not GPU-limited on average but hits a limit in the busiest moments. The frames that fall behind are exactly the frames where the most is happening — which is to say, the fight. If your GPU sits well below full occupancy while the lows suffer, GPU not at 100% is the diagnosis page for that.

The measurement discipline that makes any of this worth doing

Percentiles are noisier than averages, because they are computed from fewer frames. Two runs of the same unchanged configuration will not produce the same 1% low, and the difference between them is the smallest change you are able to detect at all.

This is why a capture is only useful next to its own noise. The Benchmark page computes a noise floor from each capture's own minute-to-minute spread and prints it for the average, the 1% low and the 0.1% low separately — and it will not claim a difference that falls inside it. That is the whole discipline in one behaviour: a result smaller than your own run-to-run wander is not a result.

The practical version:

  1. Same game, same map or replay, same length, same in-game settings.
  2. Play the same way. A run spent looking at a wall and a run spent in a firefight are not comparable.
  3. Run the unchanged configuration at least three times before you change anything, so you know what your own noise looks like.
  4. Change one thing. Five changes and one measurement tell you nothing about which one mattered — and adding five separately measured gains together is arithmetic, not measurement.
  5. Compare the lows. Reading the benchmark covers what each number on the page is for.

The exact arithmetic, number by number

This is what the Benchmark page does with a capture, in the order it does it.

StepThe ruleWhy it is there
Which frames countOnly frames drawn while the game was the window in front. After the game comes back to the front, the first second is left out; before a detected loss of focus, the last 0.2 seconds are left out. The time left out is reported with the run.A capture starts and stops from w0a's own window, so its edges are the game in the background. On one recorded capture, 94 of the 185 frames behind the 1% low were those edges. The one-second figure is a chosen value, not a measured one.
StallsA frame interval longer than 200 ms is excluded from the average and from every percentile, and counted separately.Over 200 ms it is a load screen, an alt-tab or a driver stall, not rendering. Averaged in, it would bury every real frame.
Average FPSThe counted frames divided by the time they took: frames × 1000 ÷ total milliseconds.
1% lowSort the counted frame times. Take the slowest 1% of them, rounded up and never fewer than one frame, average those frame times, and turn the result into FPS: 1000 ÷ that average.The other common definition, the frame rate at the 99th-percentile frame time, was rejected on purpose: with exactly 1% of frames stuttering it lands on the boundary and reports almost the same number as the average.
0.1% lowThe same, with the slowest 0.1%.
99th and 99.9th percentile frame timeReported separately, in milliseconds.For readers and tools that use the percentile definition.
Too short to readBelow 900 frames there are not enough frames for the percentile to mean anything.
Stutter countA frame is a hitch when it is longer than both twice the median of the surrounding three seconds and that median plus 8 ms, up to one second.Three seconds rather than a fixed number of frames, so the rule means the same thing at 60 FPS and at 300. The 8 ms term stops ordinary jitter at high frame rates counting as stutter. Frames between 200 ms and one second are excluded from the percentiles but included here: a 250 ms shader compilation hiccup is exactly what this count exists to catch.
Noise floorThe capture is cut into 60-second blocks. Each side of a comparison needs at least two whole blocks, or the page says "not comparable" instead of colouring a number. The floor is a 95% interval from the two sides' block-to-block spread (Welch's method), as a percentage of the "before" value. Only complete blocks with no lost events count, and a floor of zero is never produced.A difference inside your own block-to-block wander is not a result.
Paired seriesWhen you run an A/B series, a change is reported only if an exact signed-rank test and a 95% bootstrap interval of the median difference (10,000 resamples) both exclude zero, and the median is at least the smallest effect a 10-run pilot showed the setup can detect. The series needs at least 6 pairs — with 5, the smallest p-value possible is 0.0625 — and suggests 8, run in ABBA order.One before-and-after pair cannot separate a change from a warm GPU or a different spawn.

Check it yourself: recompute from the CSV

Save CSV on the Benchmark page writes one table with the columns side,kind,name,value. Rows with kind = metric are the summary figures; rows with kind = frame are the frame intervals, one per row, with the frame time in milliseconds in value. The frame rows hold the whole series, stalls included, precisely so you can apply the 200 ms rule yourself and land on the same numbers.

Two things before you start:

In a spreadsheet: filter to one side and kind = frame, remove the rows above 200, sort value from largest to smallest, average the first N rows where N is the row count divided by 100 and rounded up, and divide 1000 by that average. The result should equal low_1pct_fps for that side.

In PowerShell (replace before with after for the other side):

$ms = Import-Csv .\capture.csv |
  Where-Object { $_.kind -eq 'frame' -and $_.side -eq 'before' } |
  ForEach-Object { [double]::Parse($_.value, [Globalization.CultureInfo]::InvariantCulture) } |
  Where-Object { $_ -le 200 } |
  Sort-Object
$take = [Math]::Max(1, [Math]::Ceiling($ms.Count * 0.01))
1000 / ($ms | Select-Object -Last $take | Measure-Object -Average).Average

Use 0.001 instead of 0.01 for the 0.1% low. Two quick consistency checks from the same file: the number of frame rows at or under 200 equals the frames metric, and the number above 200 equals excluded_over_stall_ms.

Two things that quietly ruin a percentile

Frame generation. Inserted frames carry no new game state. A 1% low derived from counting frames still produces a number, but it has stopped describing responsiveness — which is the only reason you were looking at it. Turn generation off while measuring. This is a definitional point, not a claim that frame generation causes stutter.

Load screens and pauses. A three-second loading pause is a single "frame interval" of three thousand milliseconds, and left in the data it becomes your 0.1% low and buries everything real. Intervals that long are excluded from the percentiles for that reason and reported separately, so a number is never quietly built on top of one.

What does not move the 1% low

This deserves saying plainly, because the two are easy to conflate: latency features and percentile stability are different claims. Vendor low-latency modes reduce the depth of the render queue, and that reduction has been measured. There is no published measurement showing they improve frame-time percentiles. Both things can be worth having; they are not the same thing, and a page that presents one as the other is selling you something. Clean Install for Stable 1% Lows works through the published evidence with sources, and the input lag no software can fix is the honest accounting of what latency work can and cannot reach.

The same caution applies to registry lists promising better lows. Kernel memory-management values and timer-resolution overrides are refused outright here, not because they are exotic but because nobody has published a measurement of them that survives contact with a method.

What the Benchmark page does not print

If your lows are bad and you want the causes rather than the numbers, why games stutter on Windows 11 is the list and what the stutter scan looks for is what w0a checks automatically. For CS2 specifically, CS2 low FPS and stutter applies all of this to one game.

Related

Playing CS2? Which launch options still do anything, and where the frames really are in the video menu: How to fix CS2 stutter and low FPS: a measured checklist

w0a changes no Windows setting until you ask it to, and before a tweak writes a new value it saves the old one. Get notified

Did this page help?

What was missing, or what did not work? We read every one of these.

If this page did not solve it, write to us — say which article you read, and we will fix the article.