Kaylee Lubick
90d · built 2026-09-08
Performance
What Kaylee Lubick shipped in the selected window, measured in ETV, and how it compares with the 90 days before it.
Effective capacity
−0.2engineers
delivers like 0.8 (0.8x pre-AI)
Output (ETV)
5.3ETV
−41.6% vs 9.0 prior
Features share
18.6%
+8.2 pp vs prior window
Fixes share
24.0%
−33.6 pp vs prior window
Work mix
18.6% Features45.8% Maintenance9.7% Tests1.9% Docs24% Fixes
52 commits over 90 days, ending 2026-09-08.
Daily performance
Daily ETV, stacked by Features, Maintenance, Tests, Docs and Fixes.
Repository spread
Where this developer's commits land. Concentrated work (top1 > 80%) vs polymath spread (top1 < 30%).
Most impactful commits
Top 10 by ETV in the last 90 days.
- 0.9ETVApply min/max optimizations in lowp SkRP stages Building on https://review.skia.org/1197816, there are several other places that were not generating optimal code regarding min/max. Thus I added helpers that force the use of the intrinsic and swapped out places where it seemed to help. ``` $ python3 tools/raster_pipeline/run_benchmarks.py --run --match skrp_gather ====================================================================== Running nanobench_ml4_control... Timer overhead: 23.6ns min median mean max stddev samples bench 162ns 163ns 163ns 164ns 0% █▂▄▄▂▂▃▄▄▁ skrp_gather_rg88 190ns 191ns 192ns 211ns 3% ▁▁▁▁▁▁▁█▁▁ skrp_gather_565 121ns 121ns 121ns 121ns 0% ▇▁▂▁▄█▄▂▅▅ skrp_gather_8888 ====================================================================== Running nanobench_ml4_with_changes... Timer overhead: 23.2ns min median mean max stddev samples bench 149ns 151ns 156ns 208ns 12% ▁▁▁▁▁█▁▁▁▁ skrp_gather_rg88 188ns 188ns 188ns 189ns 0% ▆█▄▂▅▂▂▁▁▃ skrp_gather_565 119ns 119ns 120ns 129ns 3% ▁▁▁█▁▁▁▁▁▁ skrp_gather_8888 ====================================================================== Running nanobench_ml3_control... Timer overhead: 23.2ns min median mean max stddev samples bench 140ns 143ns 142ns 144ns 1% ▄▆▂█▇▁▅▆▄▆ skrp_gather_rg88 175ns 176ns 176ns 177ns 0% ▃▄▄█▆▆▁▇▂▅ skrp_gather_565 206ns 206ns 208ns 229ns 3% ▁█▁▁▁▁▁▁▁▁ skrp_gather_8888 ====================================================================== Running nanobench_ml3_with_changes... Timer overhead: 23.4ns min median mean max stddev samples bench 124ns 125ns 125ns 127ns 1% █▃▂▃▄▄▁▁▃▄ skrp_gather_rg88 145ns 145ns 147ns 162ns 4% ▁█▁▁▁▁▁▁▁▁ skrp_gather_565 191ns 191ns 191ns 191ns 0% █▅▄▃█▄▂▁▁▁ skrp_gather_8888 ====================================================================== Running nanobench_sse2_control... Timer overhead: 23.4ns min median mean max stddev samples bench 246ns 246ns 246ns 247ns 0% ▅█▅█▄▄▂▄▁▃ skrp_gather_rg88 296ns 297ns 297ns 297ns 0% █▆▆▆▂▆▅▅▃▁ skrp_gather_565 259ns 260ns 264ns 285ns 3% ▁█▁▃▁▁▁▁▂▁ skrp_gather_8888 ====================================================================== Running nanobench_sse2_with_changes... Timer overhead: 23.1ns min median mean max stddev samples bench 195ns 196ns 196ns 197ns 0% █▆▄▂▇▁▅▃█▄ skrp_gather_rg88 238ns 240ns 241ns 251ns 1% ▂▂▂▂▂▂▂▂▁█ skrp_gather_565 208ns 209ns 210ns 216ns 1% ▂█▂▁▂▁▁▁▁▅ skrp_gather_8888 ``` This is a 5-20% on the gather stages which are used in nearly every pipeline. One non-intuitive optimization we see is from decoupling the broadcast from the min/max operation in AVX512: Before: vmaxps 0x69bc63(%rip){1to16}, %zmm0, %zmm0 After: vbroadcastss 0x69bc63(%rip), %zmm1 vmaxps %zmm1, %zmm0, %zmm0 which is more parallelizable/pipeline-friendly. Change-Id: Ibff8aa5739439bdba5ac39f1569f89c6420587d7 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1282116 Commit-Queue: Kaylee Lubick <kjlubick@google.com> Reviewed-by: Thomas Smith <thomsmit@google.com>github.com-google-skia · 7dccd1e7 · 2026-07-01
- 0.8ETVRemove SkScalarHalf SkScalar is always a float so we can just do the division inline and remove the helper. This is part of the slow process of removing SkScalar things. Client CLs: - https://crrev.com/c/7994102 Change-Id: I4a68bac51a0665ed064b8c886f766614899f9188 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1255016 Reviewed-by: Alexis Cruz-Ayala <alexisdavidc@google.com> Commit-Queue: Kaylee Lubick <kjlubick@google.com>github.com-google-skia · 09a43d2f · 2026-06-24
- 0.4ETVGenerate dawn_files.bzl dynamically instead of hardcoding the lists This is step 4 of the plan outlined in https://review.skia.org/1212657 This adds a Python script to parse Dawn's cmake files to produce the dawn_files.bzl. This means as Dawn adds or removes files, we shouldn't need human intervention to update the lists of files we compile. I've removed dawn_files.bzl from being checked in (as it's dynamically produced) but the current produced version can be seen on PS19 if anyone's curious. Suggested review order: - dawn/BUILD.bazel to see we've shuffled some file lists around, removed some hardcoded names and broken up the _headers target for more granular objc support. - dawn/dawn_repo.bzl and bazel/cpp_modules.bzl to see how we added the ability to shell out to a Python file to generate dawn_files.bzl. - dawn/generate_dawn_files.py to see how we parse CMakefiles. I tried to include as many examples as I could to help understand what the parsing is doing. I'd originally considered shelling out to cmake to generate this, but I think that would be even more complicated overall. Change-Id: Idb93afb54e0c60f274e7734b5e409d5fb984ee17 Bug: b/502536510 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1234336 Commit-Queue: Kaylee Lubick <kjlubick@google.com> Reviewed-by: Eric Boren <borenet@google.com>github.com-google-skia · 1f40c109 · 2026-06-11
- 0.3ETVFix SkPathBuilder::snapshot() with non-affine matrices The fuzzer noticed some asserts that were triggered as a result of us preserving the isA part when we shouldn't have (e.g. perspective transforms). This fixes that behavior. Bug: oss-fuzz:511659804 Fixed: 511659804 Change-Id: Ifa9250000a458037dbd170163da5c2b125fe7b20 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1310197 Reviewed-by: Florin Malita <fmalita@google.com> Commit-Queue: Florin Malita <fmalita@google.com> Auto-Submit: Kaylee Lubick <kjlubick@google.com>github.com-google-skia · c81f80eb · 2026-07-31
- 0.2ETVAddress incorrect handling of a map pointer in SkRP In pushChildCall, we held on to a pointer from a fChildEffectMap and then later dereferenced it. However, in between those points was a code path that could grow the map, invalidating the pointer. This is demonstrated in the newly added test. To fix it, we just dereference it earlier. While tracking this down, I found a suspicious other usage of the map which works in newer C++, but could break in older versions. It's trivial to fix Generator::writeFunction, so I handled that as well. Bug: b/540157141 Fixed: 540157141 Change-Id: I149b070c31d4cfefa65b30972f0b8b94441e66db Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1308776 Reviewed-by: Jorge Betancourt <jmbetancourt@google.com> Commit-Queue: Kaylee Lubick <kjlubick@google.com>github.com-google-skia · 5b90a364 · 2026-07-29
- 0.2ETVAdd sanitization proc to SkTypeface::MakeDeserialize If someone wants to validate or rewrite (OTS-style) the bytes in the stream before they are passed to Fontations etc, they need a hook like this one to achieve that. Otherwise, they'd need to be able to work around Skia's stream format which includes metadata that we'd like others to not depend on. See also https://crrev.com/c/8126755 Change-Id: I765770dba32f60a76d93b75670529f30fc236bb9 Bug: b/497603247 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1297116 Commit-Queue: Kaylee Lubick <kjlubick@google.com> Reviewed-by: Florin Malita <fmalita@google.com>github.com-google-skia · a5d1e541 · 2026-07-21
- 0.2ETVAvoid timeout in SkRegion::setPath This path attempted to draw 11 billion tiles which seems excessive. I calculate how many tiles are needed and stop if it's above 1000 (chosen somewhat arbitrarily). Change-Id: Ied3794b48c2dbe56ba566eae0a99f22ef6ccc3f9 Bug: oss-fuzz:510359475 Fixed: 510359475 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1310356 Commit-Queue: Kaylee Lubick <kjlubick@google.com> Commit-Queue: Alexis Cruz-Ayala <alexisdavidc@google.com> Auto-Submit: Kaylee Lubick <kjlubick@google.com> Reviewed-by: Alexis Cruz-Ayala <alexisdavidc@google.com>github.com-google-skia · e92f5179 · 2026-07-30
- 0.2ETVOptimize div_(uint|int)_n code in SkRP When looking at the assembly for various SkRP functions, I noticed dividing by integers were the biggest stages in terms of cycles per stage [1] all weighing in 400+ cycles per iteration. I looked into why and discovered the compiler (even with LTO in chromium) was generating [2] a bunch of stack spills and div commands. x64 SIMD up through AVX512 lack a vectorized integer division operator. They do have vectorized double division and since doubles have 53 bits of mantissa, we use them to do 32 bit integer division w/o losing precision. We have to be a bit careful when dealing with unsigned integers since before AVX512 there wasn't a built in way to turn unsigned integers to doubles. I chose to cap unsigned ints at the signed INT_MAX because I don't think we'd have normal math get into that range (e.g. during a shader run). I iterated on this a few times to get things faster. For example: - Even though AVX512 can use 512-bit (zmm) instructions for division, it was slower than handling things in 256-bit (ymm) registers. - Similarly, in the AVX2 path, there was excess overhead in the skrp_div_uint_1 benchmark, so I handled this in 128-bit blocks to avoid contention and dependencies that caused latency. Before ``` $ ./nanobench_sse2_control --match rp_div min median mean max stddev samples bench 920ns 923ns 926ns 956ns 1% ▁▂▂▁▂▂█▁▁▁ skrp_div_uint_4 352ns 353ns 355ns 375ns 2% ▁▁▁▁▁▂▁▁▂█ skrp_div_uint_1 922ns 925ns 931ns 970ns 2% ▁▁▁▁█▁▄▁▁▁ skrp_div_int_4 400ns 401ns 402ns 413ns 1% ▂▂▂▂▁█▂▂▂▂ skrp_div_int_1 $ ./nanobench_ml3_control --match rp_div min median mean max stddev samples bench 908ns 909ns 914ns 960ns 2% ▁▁▁▁▁▁█▁▁▁ skrp_div_uint_4 228ns 228ns 228ns 229ns 0% █▂▅▁▄▄▃▂▂▁ skrp_div_uint_1 907ns 908ns 917ns 988ns 3% ▁█▁▁▁▁▁▁▂▁ skrp_div_int_4 400ns 401ns 401ns 410ns 1% ▂▁▂▁▂▁█▂▁▂ skrp_div_int_1 $ ./nanobench_ml4_control --match rp_div min median mean max stddev samples bench 1.01µs 1.01µs 1.03µs 1.14µs 4% ▁█▁▁▁▁▁▁▁▁ skrp_div_uint_4 323ns 324ns 325ns 345ns 2% ▁▁▁▁▁▁▁▁█▁ skrp_div_uint_1 1.03µs 1.03µs 1.04µs 1.08µs 2% ▁▁▆▁▁▁▁▁▁█ skrp_div_int_4 332ns 333ns 332ns 333ns 0% ▆▄▃▂▆▆█▁▇▂ skrp_div_int_1 ``` After ``` $ ./nanobench_sse2_with_change --match rp_div min median mean max stddev samples bench 469ns 471ns 479ns 550ns 5% ▁▁▁▁▁█▁▁▁▁ skrp_div_uint_4 # -49% 355ns 356ns 357ns 361ns 0% █▂▂▂▂▁▁▁▁▂ skrp_div_uint_1 # +1% 331ns 332ns 336ns 359ns 3% ▅▁▁█▁▁▁▁▁▁ skrp_div_int_4 # -64% 302ns 302ns 302ns 302ns 0% ▃▅▁▃▃▄▃█▃▆ skrp_div_int_1 # -25% $ ./nanobench_ml3_with_change --match rp_div min median mean max stddev samples bench 312ns 312ns 312ns 314ns 0% █▇▃▅▂▁▂▂▄▂ skrp_div_uint_4 # -67% 162ns 163ns 166ns 193ns 6% ▁▁▁▁█▁▁▁▁▁ skrp_div_uint_1 # -29% 303ns 303ns 304ns 316ns 1% ▂▁▁▁▁▁█▁▁▁ skrp_div_int_4 # -67% 142ns 142ns 142ns 142ns 0% ▁▃▂▁█▂▂▁▁▂ skrp_div_int_1 # -65% $ ./nanobench_ml4_with_change --match rp_div min median mean max stddev samples bench 305ns 306ns 306ns 307ns 0% █▄▁█▄█▃▃▂█ skrp_div_uint_4 # -70% 76.2ns 76.5ns 78.5ns 97.2ns 8% ▁▁█▁▁▁▁▁▁▁ skrp_div_uint_1 # -76% 303ns 303ns 306ns 337ns 3% ▁▁▁█▁▁▁▁▁▁ skrp_div_int_4 # -71% 76.1ns 76.8ns 77.5ns 84.4ns 3% ▁█▁▂▂▂▂▂▂▁ skrp_div_int_1 # -77% ``` There's also a noticeable improvement in the sse3 version in chrome (even with its LTO). I had to update the llvm_mca script to handle this missing namespace. [1] http://screen/3pLy34PyNes4GRK [2] http://gpaste/4735787433328640 Change-Id: I4f73ce041267adc4a030bd79443c708a56429965 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1233976 Commit-Queue: Kaylee Lubick <kjlubick@google.com> Reviewed-by: Thomas Smith <thomsmit@google.com>github.com-google-skia · 92aebcc2 · 2026-06-30
- 0.2ETV[bazel] Add support to viewer for Windows (and all Direct3D backends) bazel run //tools/viewer runs on my local windows machine with Graphite+Dawn+D3D11 and D3D12 as well as the Ganesh + D3D backend. Suggested review order: - tools/viewer/BUILD.bazel (Freetype is going to take some fiddling to get to work but we prefer to test with SkFontMgr_New_GDI anyway. - tools/window/BUILD.bazel and tools/sk_app/... (these mirror the Linux and Mac versions pretty closely) - All other BUILD.bazel files - All .cpp files (note that src/gpu/ganesh/d3d/GrD3DBackendSurface.cpp had quietly been broken during the modularization and we didn't notice it until doing a modular build). - All other files Bug: 256860862 Bug: 256870320 Change-Id: I8671a6b2c11a5b2b8703cdc44b9bbeae9fb12e7a Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1293798 Reviewed-by: Eric Boren <borenet@google.com>github.com-google-skia · e553224d · 2026-07-15
- 0.1ETVAdd new tool for easily comparing raster pipeline benchmarks One workflow I have for running benchmarks on SkRP is to build a control version of nanobench, then comment out the ML4 (AVX512) branch, then re-compile for a control version of ML3 (AVX2) and then comment out the ML3 branch and get a control version of SSE2. Then make my changes. Then build experimental versions of nanobench to mirror those three settings. This has gotten tedious, so I made a script to make this easier. ``` $ python3 tools/raster_pipeline/run_benchmarks.py --compile Checking Git status of src/opts/SkRasterPipeline_opts.h... --- Checking out Control baseline (origin/main) --- Configuring SkOpts.cpp for Control ML4... Compiling nanobench_control_ml4... Saved binary to out/Release/nanobenches/nanobench_ml4_control Configuring SkOpts.cpp for Control ML3... Compiling nanobench_control_ml3... Saved binary to out/Release/nanobenches/nanobench_ml3_control Configuring SkOpts.cpp for Control SSE2... Compiling nanobench_control_sse2... Saved binary to out/Release/nanobenches/nanobench_sse2_control --- Checking out HEAD (Optimized) --- Configuring SkOpts.cpp for Optimized ML4... Compiling nanobench_with_changes_ml4... Saved binary to out/Release/nanobenches/nanobench_ml4_with_changes ... $ python3 tools/raster_pipeline/run_benchmarks.py --run --match rp_div ====================================================================== Running nanobench_ml4_control... Timer overhead: 23.8ns curr/maxrss loops min median mean max stddev samples config bench 96/93 MB 38 303ns 304ns 304ns 305ns 0% █▂▄▃▆▃▃█▅▁ nonrendering skrp_div_uint_4 96/93 MB 215 76ns 76.2ns 78.3ns 96.9ns 8% ▁▁▁▁▁▁█▁▁▁ nonrendering skrp_div_uint_1 96/93 MB 247 302ns 303ns 303ns 312ns 1% ▂▁▁█▁▁▁▁▁▁ nonrendering skrp_div_int_4 96/93 MB 593 75.9ns 75.9ns 76.7ns 81ns 2% ▁█▁▁▁▁▁▁▁▆ nonrendering skrp_div_int_1 ====================================================================== Running nanobench_ml4_with_changes... Timer overhead: 23.3ns curr/maxrss loops min median mean max stddev samples config bench 96/94 MB 39 303ns 304ns 309ns 358ns 6% ▁▁▁▁█▁▁▁▁▁ nonrendering skrp_div_uint_4 96/94 MB 256 75.9ns 76.1ns 76.1ns 76.3ns 0% ▆█▁▄▁▄▁▆▆▁ nonrendering skrp_div_uint_1 96/94 MB 247 302ns 303ns 304ns 319ns 2% ▁▁▁▁▁█▁▁▁▁ nonrendering skrp_div_int_4 96/94 MB 506 75.8ns 76.1ns 76.1ns 76.5ns 0% ▃▄▁▂▂█▂▄▇▄ nonrendering skrp_div_int_1 ====================================================================== Running nanobench_ml3_control... Timer overhead: 24.7ns curr/maxrss loops min median mean max stddev samples config bench 95/93 MB 33 303ns 304ns 304ns 306ns 0% █▂▄▁▅▁▄▁▅▄ nonrendering skrp_div_uint_4 95/93 MB 327 162ns 162ns 162ns 164ns 0% ▂▃▃▃▂█▂▁▂▁ nonrendering skrp_div_uint_1 95/93 MB 350 302ns 302ns 306ns 339ns 4% ▁▁▁▁▁▁▁▁▁█ nonrendering skrp_div_int_4 95/93 MB 606 142ns 143ns 143ns 148ns 1% ▂▂▂▂▂▁▃▁▃█ nonrendering skrp_div_int_1 ====================================================================== ... ``` I also tweaked llvm_mca_analysis.py so one can add --reset-experiments to remove all but the first (control) set of data. This is handy when on the 3rd+ thing to try and the spreadsheet gets unweildy with no-longer-useful info. It doesn't remove the assembly files (in case we do want to go back), just the data from the .tsv Change-Id: I85362ab6fdbfffc8cca29a6ba91ea8ccc23b231d Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1283016 Auto-Submit: Kaylee Lubick <kjlubick@google.com> Reviewed-by: Florin Malita <fmalita@google.com> Commit-Queue: Florin Malita <fmalita@google.com>github.com-google-skia · 0f68f5e6 · 2026-07-01