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

Optimize TextLayerBuilder_renderLayer() for text heavy documents. #5137

Merged

Conversation

CodingFabian
Copy link
Contributor

This change improves the text layer creation of "normal" text heavy documents.
It changes 2 things:

  • If the text element is not rotated, it will neither calculate nor apply a
    textTransform: rotate(0deg) to the text layer element.
  • For scaling the text layer div, the context will measure the width of the
    text in the given font. For many text documents the font changes seldom.
    If the font stays the same, the context does not need to be set to a new font
    especially avoiding the temporary creation of the same font string over and
    over again.

The PDF from #4873 suits well as an example. I added counts for where rotation is zero, and the font is the the same. Rotation of all text elements (many thousands) is zero, and the font is often for hundreds of elements the same.

@timvandermeij
Copy link
Contributor

/botio-linux preview

@pdfjsbot
Copy link

pdfjsbot commented Aug 5, 2014

From: Bot.io (Linux)


Received

Command cmd_preview from @timvandermeij received. Current queue size: 0

Live output at: http://107.21.233.14:8877/851e015707c435a/output.txt

var textScale = textDiv.dataset.canvasWidth / width;
var rotation = textDiv.dataset.angle;
var transform = 'scale(' + textScale + ', 1)';
transform = 'rotate(' + rotation + 'deg) ' + transform;
if (rotation !== undefined) {
Copy link
Contributor

Choose a reason for hiding this comment

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

let's keep it if (rotation) { 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.

ok

@yurydelendik
Copy link
Contributor

Could you also add angle == 0 optimizations for Math.sin and Math.cos at https://github.com/mozilla/pdf.js/pull/5137/files#diff-6a8d3c6754c77cfa0876314f0f54bed7R135 ?

This change improves the text layer creation of "normal" text heavy documents.
It changes 2 things:
 * If the text element is not rotated, it will neither calculate nor apply a
   textTransform: rotate(0deg) to the text layer element.
 * For scaling the text layer div, the context will measure the width of the
   text in the given font. For many text documents the font changes seldom.
   If the font stays the same, the context does not need to be set to a new font
   especially avoiding the temporary creation of the same font string over and
   over again.
@CodingFabian
Copy link
Contributor Author

while at it i also changed the ascent calculation to a longer if/elseif block to enhance readability.

@yurydelendik
Copy link
Contributor

Could you paste before/after profiler results?

@yurydelendik
Copy link
Contributor

/botio-windows preview

@pdfjsbot
Copy link

pdfjsbot commented Aug 5, 2014

From: Bot.io (Windows)


Received

Command cmd_preview from @yurydelendik received. Current queue size: 0

Live output at: http://107.22.172.223:8877/41130516e7e3deb/output.txt

@CodingFabian
Copy link
Contributor Author

@yurydelendik profiling was a bit of a challenge because admittedly it is not the most impacting part.
I saw it mainly because I was investigating scrolling impact.

I put custom profiling code into the affected methods. Their runtime goes down from 1901ms to 1735ms - about a 10% improve. Also the "overhead" of the text layer divs goes down by 10% from about 300 bytes to 270 bytes per div.
before the patch I got frequent rendering dips to < 10 fps (measured using chrome canary fps counter), with the patch it stays most of the time above 10 fps. The fps metric is not as reliable, but it somehow also feels like a 10% improvement :-)

@CodingFabian
Copy link
Contributor Author

maybe @nnethercote could tell me how he measures rss. so that I can give it a shot as well using his metric. i expect it to go down as well (maybe also 10% :-))

@nnethercote
Copy link
Contributor

I have two scripts. The first is called rsspid:

#! /usr/bin/python

from __future__ import print_function
import subprocess
import sys
import time

if (len(sys.argv)) != 2:
    print("usage:", sys.argv[0], "<pid>")
    sys.exit(1)

pid = sys.argv[1]

peak_rss = 0

try:
    while True:
        # Use -p because --pid doesn't work on Mac.
        # Also, have to split the output because --no-headers doesn't work on
        # Mac.
        cmd = ["ps", "-o", "rss", "-p", pid];
        heading, rss = (subprocess.check_output(cmd).rstrip()).split('\n');
        rss = int(rss)
        print("{0:.2f} MiB".format(rss / 1024.0))
        if (rss > peak_rss):
            peak_rss = rss
        time.sleep(0.05)

except:
    print("\npeak: {0:.2f} MiB".format(peak_rss / 1024.0))

The second is called rss:

#! /bin/sh
#
# Runs the given program (plus its args) under |rsspid|.

"$@" &      # Start the given process in the background.
echo "Measuring RSS of process $!: $@"
rsspid $!   # $! is the pid of the last process started in the background.

If you run rss <command> it'll print RSS 20 times per second, and when the process terminates it'll print the peak RSS value.

@CodingFabian
Copy link
Contributor Author

ah cool, i was hoping for a more high tec solution, but will give it a shot :)

@CodingFabian
Copy link
Contributor Author

using @nnethercote script, i saw a peak rss of 679.90 MiB pre-patch and after the patch 653.89 MiB for the mentioned pdf. roughly 5% less.

var width = ctx.measureText(textDiv.textContent).width;
if (width > 0) {
textLayerFrag.appendChild(textDiv);
// Dataset values come of type string.
var textScale = textDiv.dataset.canvasWidth / width;
var rotation = textDiv.dataset.angle;
var transform = 'scale(' + textScale + ', 1)';
Copy link
Contributor

Choose a reason for hiding this comment

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

can't we use 'scaleX(' + textScale + ')' 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.

maybe, but that would be a different change. If desired we can sneak it in. but i do not want to delay the change by piggybacking other stuff.
I would assume that performance wise the functions are equivalent.

@nnethercote
Copy link
Contributor

i saw a peak rss

BTW, the measurements can be noisy. I usually run my before and after measurements 3 times to see how much variation there is.

yurydelendik added a commit that referenced this pull request Aug 6, 2014
…rLayer

Optimize TextLayerBuilder_renderLayer() for text heavy documents.
@yurydelendik yurydelendik merged commit 666cf02 into mozilla:master Aug 6, 2014
@yurydelendik
Copy link
Contributor

Looks good, thank you for the patch.

@CodingFabian CodingFabian deleted the optimize-textbuilder-renderLayer branch August 15, 2014 07:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants