Closed Bug 1724331 Opened 4 years ago Closed 4 years ago

canvas.toDataURI() takes 3x as long in Firefox as in Chrome (with most time spent in MOZ_Z_deflate_slow)

Categories

(Core :: Graphics: ImageLib, defect)

defect

Tracking

()

VERIFIED FIXED
96 Branch
Performance Impact low
Tracking Status
firefox96 --- verified

People

(Reporter: dholbert, Assigned: tnikkel)

References

(Regressed 1 open bug)

Details

(Keywords: perf:responsiveness)

Attachments

(7 files)

Attached file testcase 1

STR:

  1. Load attached testcase.
  2. Inspect your web console to see how long the data URI serialization of the canvas took.

ACTUAL RESULTS:
In Chrome, the duration is approximately 30ms.
In Firefox, the duration is approximately 100ms.

These durations are pretty reliable for me; I can reload the page and the measurement stays the same.

EXPECTED RESULTS:
Performance on-par with Chrome.

I ran into this at https://kidpix.app , which happens to serialize to a data URL after each click, as part of its "undo" support. So our toDataURL() slowness causes jank on each click there, i.e. each paint operation.

Firefox Nightly profile: https://share.firefox.dev/3rUUJMG

In this profile, the toDataURL() operation takes 107ms, which is mostly spent in MOZ_Z_deflate_slow.

Summary: canvas.toDataURI() takes 3x as long in Firefox as in Chrome → canvas.toDataURI() takes 3x as long in Firefox as in Chrome (with most time spent in MOZ_Z_deflate_slow)

Here's a profile of Chrome for comparison:
https://share.firefox.dev/3fDmvZo

This Chrome profile shows about 42ms being spent in toDataURL, which matches my console.log() output from this particular run. (Note there are 66 samples during that period, but that's just because Chrome seems to be doing more than 1 sample per millisecond -- so 66 samples != 66ms.)

Are we maybe just using a higher compression setting? Logging dataURL.length I get 192214 in Firefox, 293902 in Safari, and 285330 in Chrome.

Indeed, looks like they set the zlib level to 3

https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/platform/graphics/image_data_buffer.cc;l=166;drc=d9b810ead6d1624c430250d63fbec836e3e5640c

and the default is 6, which we do not ever change (0-9 being the options, which higher values being slower by smaller produced result).

They also limit the filters to only the sub filter, whereas I think the libpng default is to allow all filters.

At this link

https://source.chromium.org/chromium/chromium/src/+/217d81bc49377c2235b8325a2f03dfce9ef45f95

in the file

third_party/WebKit/Source/platform/image-encoders/PNGImageEncoder.cpp

you can find Chromium's rationale for the png encoder settings that they use.

Did a few tests with shippable builds. First number is length of the data url string, second number is the time taken. We seem to have filters disabled for png encoding, and on this testcase they don't seem to help. Changing our zlib level to 3 seems to be a good pick, gets us on par with Chrome's speed and slightly better compression than Chrome (some other setting of the png encoder must still differ because we don't match them exactly with any filter).

nightly, zlib level 6, png write filters disabled
192214
58ms

zlib level 3, png write filters disabled
254810
25ms

zlib level 3, png write filters enabled, PNG_NO_FILTERS
287294
95ms

zlib level 3, png write filters enabled, PNG_FILTER_NONE
254810
27ms

zlib level 3, png write filters enabled, PNG_FILTER_SUB
290130
32ms

zlib level 3, png write filters enabled, PNG_FILTER_UP
281394
33ms

zlib level 3, png write filters enabled, PNG_FILTER_AVG
324938
40ms

zlib level 3, png write filters enabled, PNG_FILTER_PAETH
288610
49ms

zlib level 3, png write filters enabled, PNG_FAST_FILTERS
286970
58ms

zlib level 3, png write filters enabled, PNG_ALL_FILTERS
287294
77ms

chrome
285330
23ms

safari
293902
36ms

I also did a comparison with a photo

photo

nightly, zlib level 6, png write filters disabled
Duration: 251ms
length 4193966

zlib level 3, png write filters disabled
Duration: 129ms
length 3754074

zlib level 3, png write filters enabled, PNG_NO_FILTERS
Duration: 223ms
length 2681950

zlib level 3, png write filters enabled, PNG_FILTER_NONE
Duration: 131ms
length 3754074

zlib level 3, png write filters enabled, PNG_FILTER_SUB
Duration: 149ms
length 2936234

zlib level 3, png write filters enabled, PNG_FILTER_UP
Duration: 134ms
length 2592058

zlib level 3, png write filters enabled, PNG_FILTER_AVG
Duration: 163ms
length 2875366

zlib level 3, png write filters enabled, PNG_FILTER_PAETH
Duration: 159ms
length 2687346

zlib level 3, png write filters enabled, PNG_FAST_FILTERS
Duration: 166ms
length 2573646

zlib level 3, png write filters enabled, PNG_ALL_FILTERS
Duration: 210ms
length 2681950

chrome
Duration: 135.5ms
length 2992822

safari
Duration: 90ms
length 2701834

Whiteboard: [qf] → [qf:p3:responsiveness]
Severity: -- → S3
Depends on: 1737038
Attached file data.txt

Did a further comparison with bug 1737038 fixed.

The interesting thing here is that for photos with the sub filter, zlib level 3 is actually smaller than zlib level 4, in addition to being faster.

The sub filter makes things that are more suitable to png compression larger, and of course going to zlib level 3 increase the size of these types of images as well, but we are much faster, which is the main point here.

Other than compiler a bit more code this should have no functional effect, we're setting the values to their default values we had before.

Depends on D130020

Assignee: nobody → tnikkel
Status: NEW → ASSIGNED

Rationale is in the bug. Short version we match what Chrome does for much faster encoding, producing larger files for content that png compression works well for, and smaller files (while still being faster) for photo like content.

Depends on D130021

I verified that the pngs I'm changing here were pixel identifical before/after.

Depends on D130022

This lets me write a test for this and lets other consumers tweak the compression settings if they would like.

Depends on D130023

Depends on D130024

Pushed by tnikkel@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/55ee4bab11fc Enable libpng defines PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED and PNG_WRITE_FILTER_SUPPORTED. r=aosmond https://hg.mozilla.org/integration/autoland/rev/2c630a9af345 Change default png encoder settings. r=aosmond https://hg.mozilla.org/integration/autoland/rev/04ee2e8dedff Adjust tests that depend on the exact output of the png encoder. r=aosmond https://hg.mozilla.org/integration/autoland/rev/df68f8ee22b3 Allow the png encoder to take options specifying the zlib level and filters to use. r=aosmond https://hg.mozilla.org/integration/autoland/rev/4b7da81f442b Add a test. r=aosmond
QA Whiteboard: [qa-96b-p2]

Was able to reproduce the issue on Firefox 92.0a1 (2021-08-05) under macOS 12.1 by using the TC provided in Comment 0.

Got substantially lower duration times on Firefox 96.0. Tests were performed under macOS 12.1, Ubuntu 20.04 and Windows 7.

Status: RESOLVED → VERIFIED
QA Whiteboard: [qa-96b-p2]
Regressions: 1755037
No longer regressions: 1755037
Performance Impact: --- → P3
Whiteboard: [qf:p3:responsiveness]
Duplicate of this bug: 1137016
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: