Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve performance of reused patterns. #13770

Merged
merged 1 commit into from
Jul 23, 2021

Conversation

brendandahl
Copy link
Contributor

Bug 1721218 has a shading pattern that was used thousands of times.
To improve performance of this PDF:

  • add a cache for patterns in the evaluator and only send the IR form once
    to the main thread (this also makes caching in canvas easier)
  • cache the created canvas radial/axial patterns
  • for shading fill radial/axial use the pattern directly instead of creating temporary
    canvas

@brendandahl
Copy link
Contributor Author

/botio test

@pdfjsbot
Copy link

From: Bot.io (Linux m4)


Received

Command cmd_test from @brendandahl received. Current queue size: 0

Live output at: http://54.67.70.0:8877/d5d9b646423c11d/output.txt

@pdfjsbot
Copy link

From: Bot.io (Windows)


Received

Command cmd_test from @brendandahl received. Current queue size: 0

Live output at: http://3.101.106.178:8877/3d0d28086e2d419/output.txt

@pdfjsbot
Copy link

From: Bot.io (Linux m4)


Failed

Full output at http://54.67.70.0:8877/d5d9b646423c11d/output.txt

Total script time: 32.70 mins

  • Font tests: Passed
  • Unit tests: Passed
  • Integration Tests: Passed
  • Regression tests: FAILED
  different ref/snapshot: 29
  different first/second rendering: 1

Image differences available at: http://54.67.70.0:8877/d5d9b646423c11d/reftest-analyzer.html#web=eq.log

@pdfjsbot
Copy link

From: Bot.io (Windows)


Failed

Full output at http://3.101.106.178:8877/3d0d28086e2d419/output.txt

Total script time: 38.24 mins

  • Font tests: Passed
  • Unit tests: Passed
  • Integration Tests: Passed
  • Regression tests: FAILED
  different ref/snapshot: 24
  different first/second rendering: 1

Image differences available at: http://3.101.106.178:8877/3d0d28086e2d419/reftest-analyzer.html#web=eq.log

const patternIR = shadingFill.getIR();
id = `pattern_${this.idFactory.createObjId()}`;
localPatternCache.set(keyObj, id);
this.handler.send("obj", [id, this.pageIndex, "Pattern", patternIR], []);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The third argument is the transfers, and since there isn't any here I'd suggest just removing the empty Array.

localColorSpaceCache,
localPatternCache,
});
operatorList.addOp(fn, ["Shading", objId]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To prevent any future issues, I believe that you also want to add operatorList.addDependency(objId); before this line since you're no longer sending the data inline here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pattern should always be sent before the id is created, so a dependency pause shouldn't be needed. If it isn't sent first there will be an error on the main thread when we try to fetch the object (I did this accidentally).

localColorSpaceCache,
localPatternCache,
});
args = [patternId];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned above, you probably want to add a operatorList.addDependency(patternId); before this line.

@@ -1513,6 +1542,7 @@ class PartialEvaluator {
const localColorSpaceCache = new LocalColorSpaceCache();
const localGStateCache = new LocalGStateCache();
const localTilingPatternCache = new LocalTilingPatternCache();
const localPatternCache = new Map();
Copy link
Collaborator

@Snuffleupagus Snuffleupagus Jul 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it perhaps help to implement a more "proper" cache here, see the existing ones in https://github.com/mozilla/pdf.js/blob/master/src/core/image_utils.js, since that may help improve overall caching given you could then cache by e.g. actual Refs instead?

(This may, or may not, help all that much for the particular data in question, but I wanted to ask.)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, perhaps localShadingPatternCache instead to provide a slightly clearer distinction between this new cache and the existing one just above?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I started out using the localTilingPatternCache, but found some issues with it and and was planning to file some bugs. The patterns can't be cached by name alone since they could be in different resources dictionaries with duplicate names (issue6737.pdf has an example, but with radial gradients). There also seemed to be a number of pdfs where the pattern/shading dictionary is inline and caching by ref can't be used.

As for perf, I don't think caching by ref should speed it up much, the shading/pattern dict should be in the xref's cache map, so it should be a pretty fast lookup.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I started out using the localTilingPatternCache,

You probably would've needed to implement a new and separate cache, rather than simply re-using the existing localTilingPatternCache for the Shadings-case that this patch is about.

but found some issues with it and and was planning to file some bugs.

What sort of bugs did you encounter?

There also seemed to be a number of pdfs where the pattern/shading dictionary is inline and caching by ref can't be used.

As for perf, I don't think caching by ref should speed it up much, the shading/pattern dict should be in the xref's cache map, so it should be a pretty fast lookup.

I wasn't really worried about the Dict lookups themselves, since as you say the data is being cached, but was mostly wondering if caching by Ref could possibly have improved the hit/miss ratio in the cache. It doesn't sound like that'd been the case here though :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tiling patterns and shadings can both be patterns, so I should have been able to re-use that cache. I filed #13780 to further explain the issue.

}
applyBoundingBox(tmpCtx, this._bbox);

createGradient(ctx) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Perhaps make this "private" with a leading underscore in the name?

@@ -1513,6 +1542,7 @@ class PartialEvaluator {
const localColorSpaceCache = new LocalColorSpaceCache();
const localGStateCache = new LocalGStateCache();
const localTilingPatternCache = new LocalTilingPatternCache();
const localPatternCache = new Map();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, perhaps localShadingPatternCache instead to provide a slightly clearer distinction between this new cache and the existing one just above?

@@ -1314,6 +1314,35 @@ class PartialEvaluator {
});
}

parsePattern({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Maybe parseShading instead.

Bug 1721218 has a shading pattern that was used thousands of times.
To improve performance of this PDF:
 - add a cache for patterns in the evaluator and only send the IR form once
   to the main thread (this also makes caching in canvas easier)
 - cache the created canvas radial/axial patterns
 - for shading fill radial/axial use the pattern directly instead of creating temporary
   canvas
Copy link
Collaborator

@Snuffleupagus Snuffleupagus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, thank you!

@Snuffleupagus
Copy link
Collaborator

/botio test

@pdfjsbot
Copy link

From: Bot.io (Linux m4)


Received

Command cmd_test from @Snuffleupagus received. Current queue size: 0

Live output at: http://54.67.70.0:8877/fb299277f7cd504/output.txt

@pdfjsbot
Copy link

From: Bot.io (Windows)


Received

Command cmd_test from @Snuffleupagus received. Current queue size: 0

Live output at: http://3.101.106.178:8877/299d4a071f8e95d/output.txt

@pdfjsbot
Copy link

From: Bot.io (Linux m4)


Failed

Full output at http://54.67.70.0:8877/fb299277f7cd504/output.txt

Total script time: 32.80 mins

  • Font tests: Passed
  • Unit tests: Passed
  • Integration Tests: Passed
  • Regression tests: FAILED
  different ref/snapshot: 25
  different first/second rendering: 2

Image differences available at: http://54.67.70.0:8877/fb299277f7cd504/reftest-analyzer.html#web=eq.log

@pdfjsbot
Copy link

From: Bot.io (Windows)


Failed

Full output at http://3.101.106.178:8877/299d4a071f8e95d/output.txt

Total script time: 38.09 mins

  • Font tests: Passed
  • Unit tests: Passed
  • Integration Tests: Passed
  • Regression tests: FAILED
  different ref/snapshot: 27
  different first/second rendering: 2

Image differences available at: http://3.101.106.178:8877/299d4a071f8e95d/reftest-analyzer.html#web=eq.log

@Snuffleupagus Snuffleupagus merged commit 51f0a81 into mozilla:master Jul 23, 2021
@Snuffleupagus
Copy link
Collaborator

/botio makeref

@pdfjsbot
Copy link

From: Bot.io (Linux m4)


Received

Command cmd_makeref from @Snuffleupagus received. Current queue size: 0

Live output at: http://54.67.70.0:8877/202b8b75c272bce/output.txt

@pdfjsbot
Copy link

From: Bot.io (Windows)


Received

Command cmd_makeref from @Snuffleupagus received. Current queue size: 1

Live output at: http://3.101.106.178:8877/ed3299def79d5c6/output.txt

@pdfjsbot
Copy link

From: Bot.io (Linux m4)


Success

Full output at http://54.67.70.0:8877/202b8b75c272bce/output.txt

Total script time: 29.64 mins

  • Lint: Passed
  • Make references: Passed
  • Check references: Passed

@pdfjsbot
Copy link

From: Bot.io (Windows)


Success

Full output at http://3.101.106.178:8877/ed3299def79d5c6/output.txt

Total script time: 35.35 mins

  • Lint: Passed
  • Make references: Passed
  • Check references: Passed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants