Bug 121899 - Optimize strings copies in srcset parser
Summary: Optimize strings copies in srcset parser
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: Images (show other bugs)
Version: 528+ (Nightly build)
Hardware: All All
: P2 Normal
Assignee: Nobody
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-09-25 04:11 PDT by Romain Perier
Modified: 2013-10-04 11:39 PDT (History)
5 users (show)

See Also:


Attachments
Patch (2.42 KB, patch)
2013-09-25 04:14 PDT, Romain Perier
no flags Details | Formatted Diff | Diff
Patch (3.56 KB, patch)
2013-09-26 12:01 PDT, Romain Perier
no flags Details | Formatted Diff | Diff
Patch (3.50 KB, patch)
2013-10-04 07:08 PDT, Romain Perier
no flags Details | Formatted Diff | Diff
Patch (3.76 KB, patch)
2013-10-04 11:25 PDT, Romain Perier
ap: review+
ap: commit-queue-
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Romain Perier 2013-09-25 04:11:56 PDT
Images URLs are copied for each loop iteration during the parsing algorithm. This is important to avoid sharing the same buffer with "srcsetattribute" which might be removed after the attribute has been processed (outside of "bestFitSourceForImageAttributes")
A good optimization would be to use shadow copies during parsing and deep copies when the selection algorithm returns the good candidate (as "srcsetAttribute" is not out of scope, this string is valid as long as the function "bestFitSourceForImageAttributes" runs)
Comment 1 Romain Perier 2013-09-25 04:14:13 PDT
Created attachment 212551 [details]
Patch
Comment 2 Alexey Proskuryakov 2013-09-25 10:12:14 PDT
Comment on attachment 212551 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=212551&action=review

I think that this is a useful thing to look into. r- for regressing src preformance though.

> Source/WebCore/html/parser/HTMLParserIdioms.cpp:393
> +        image.imageURL = StringImpl::createWithoutCopying(srcsetAttribute.characters() + imageURLStart, imageURLEnd - imageURLStart);

I'm not really a fan of passing unsafe string across functions. Can we just record the start and length of the URL as indexes, and only create a string when needed?

> Source/WebCore/html/parser/HTMLParserIdioms.cpp:425
> +    return String(imageCandidates.last().imageURL.characters(), imageCandidates.last().imageURL.length());

This adds an extra copy in the common case where we have an src and no srcset.
Comment 3 Romain Perier 2013-09-26 12:01:23 PDT
Created attachment 212732 [details]
Patch
Comment 4 Romain Perier 2013-09-26 12:04:15 PDT
Something like the latest patch ? This is even better, it greatly improves performances
Comment 5 Alexey Proskuryakov 2013-09-26 12:33:13 PDT
Comment on attachment 212732 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=212732&action=review

Yes, this looks much better to me. A few questions/comment below:

> Source/WebCore/html/parser/HTMLParserIdioms.cpp:311
>      bool operator==(const ImageWithScale& image) const

Is the operator== actually needed? I don't immediately see where it's used, although I could have easily overlooked that.

> Source/WebCore/html/parser/HTMLParserIdioms.cpp:418
> +        image.imageURLStart = 0;
> +        image.imageURLLength = 0;

Can we add a constructor to ImageWithScale instead?

> Source/WebCore/html/parser/HTMLParserIdioms.cpp:433
> +    return imageCandidates.last().hasNoImage() ? srcAttribute : String(srcsetAttribute.characters() + imageCandidates.last().imageURLStart, imageCandidates.last().imageURLLength);

Please use srcsetAttribute.substring() instead. That's more readable, and could help future optimizations.

Also, I'd use a local variable for imageCandidates.last().
Comment 6 Benjamin Poulain 2013-09-26 16:08:31 PDT
Comment on attachment 212732 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=212732&action=review

> Source/WebCore/html/parser/HTMLParserIdioms.cpp:303
> +    size_t imageURLStart;

String length are unsigned. You should have imageURLStart unsigned .

> Source/WebCore/html/parser/HTMLParserIdioms.cpp:309
> +        return !imageURLStart && !imageURLLength;

Isn't !imageURLLength enough?

The method should probably be hasImageURL() and the caller use "!hasImage()".

>> Source/WebCore/html/parser/HTMLParserIdioms.cpp:433
>> -            return String(imageCandidates[i].imageURL);
>> +            return imageCandidates[i].hasNoImage() ? srcAttribute : String(srcsetAttribute.characters() + imageCandidates[i].imageURLStart, imageCandidates[i].imageURLLength);
>>      }
>> -    return String(imageCandidates.last().imageURL);
>> +    return imageCandidates.last().hasNoImage() ? srcAttribute : String(srcsetAttribute.characters() + imageCandidates.last().imageURLStart, imageCandidates.last().imageURLLength);
> 
> Please use srcsetAttribute.substring() instead. That's more readable, and could help future optimizations.
> 
> Also, I'd use a local variable for imageCandidates.last().

substring() would be better indeed. StringImpl::substring takes into account the 8/16 bits strings.
You could even use String::substringSharingImpl() here since srcsetAttribute will stay alive anyway.
Comment 7 Alexey Proskuryakov 2013-09-26 17:01:47 PDT
> srcsetAttribute will stay alive anyway

What guaranteed this? E.g., can we have a dangling pointer for a while between changing the attribute via DOM and a style recalc?
Comment 8 Romain Perier 2013-09-27 00:08:36 PDT
(In reply to comment #5)
> (From update of attachment 212732 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=212732&action=review
> 
> Yes, this looks much better to me. A few questions/comment below:
> 
> > Source/WebCore/html/parser/HTMLParserIdioms.cpp:311
> >      bool operator==(const ImageWithScale& image) const
> 
> Is the operator== actually needed? I don't immediately see where it's used, although I could have easily overlooked that.

Not sure, it was probably used for sorting ... but we use a "comp" function for this... not really clear. Removing it does not introduce regressions.
Good catch.

> 
> > Source/WebCore/html/parser/HTMLParserIdioms.cpp:418
> > +        image.imageURLStart = 0;
> > +        image.imageURLLength = 0;
> 
> Can we add a constructor to ImageWithScale instead?

sure, it's more readable and probably faster

> 
> > Source/WebCore/html/parser/HTMLParserIdioms.cpp:433
> > +    return imageCandidates.last().hasNoImage() ? srcAttribute : String(srcsetAttribute.characters() + imageCandidates.last().imageURLStart, imageCandidates.last().imageURLLength);
> 
> Please use srcsetAttribute.substring() instead. That's more readable, and could help future optimizations.

OK, makes sense
> 
> Also, I'd use a local variable for imageCandidates.last().

OK
Comment 9 Benjamin Poulain 2013-09-27 14:35:31 PDT
(In reply to comment #7)
> > srcsetAttribute will stay alive anyway
> 
> What guaranteed this? E.g., can we have a dangling pointer for a while between changing the attribute via DOM and a style recalc?

Even if you were to unref srcsetAttribute, substringSharingImpl ref() the original string, you will not get a dangling pointer.
Comment 10 Romain Perier 2013-10-04 07:08:31 PDT
Created attachment 213362 [details]
Patch
Comment 11 Alexey Proskuryakov 2013-10-04 09:51:36 PDT
Comment on attachment 213362 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=213362&action=review

> Source/WebCore/html/parser/HTMLParserIdioms.cpp:306
> +    ImageWithScale() : imageURLStart(0), imageURLLength(0), scaleFactor(1.0) { }

I think that the preferred style would be the same as in non-inline case, with each initializer and each brace on its own line.

And we don't add .0 to literal values. Especially in this case, because 1.0 is a double, but scaleFactor is a float.

    ImageWithScale()
        : imageURLStart(0)
        , imageURLLength(0)
        , scaleFactor(1)
     {
     }

> Source/WebCore/html/parser/HTMLParserIdioms.cpp:414
>          ImageWithScale image;
> -        image.imageURL = srcAttribute;
> -        image.scaleFactor = 1.0;
> -
>          imageCandidates.append(image);

This is getting somewhat convoluted. Please rename "image" to "srcPlaceholderImage" for a little more clarity.

> Source/WebCore/html/parser/HTMLParserIdioms.cpp:426
> +    const ImageWithScale &lastCandidate = imageCandidates.last();

The "&" should be attached to type name, 

const ImageWithScale& lastCandidate = imageCandidates.last();
Comment 12 Romain Perier 2013-10-04 11:25:13 PDT
Created attachment 213380 [details]
Patch
Comment 13 Romain Perier 2013-10-04 11:26:12 PDT
Everything has been fixed
Comment 14 Alexey Proskuryakov 2013-10-04 11:31:21 PDT
Comment on attachment 213380 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=213380&action=review

I'll just land with a style fix manually, the iterations for minor style fixes are getting annoying.

> Source/WebCore/html/parser/HTMLParserIdioms.cpp:312
> +        { 
> +        }

These should not be indented (were not in the snippet I posted).
Comment 15 Alexey Proskuryakov 2013-10-04 11:39:54 PDT
Committed <http://trac.webkit.org/r156902>.