Bug 158827 - Avoid some temporary String allocations for common HTTP headers in ResourceResponse::platformLazyInit()
Summary: Avoid some temporary String allocations for common HTTP headers in ResourceRe...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: Platform (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Chris Dumez
URL:
Keywords:
Depends on:
Blocks: 158857
  Show dependency treegraph
 
Reported: 2016-06-15 21:19 PDT by Chris Dumez
Modified: 2016-07-08 09:04 PDT (History)
5 users (show)

See Also:


Attachments
Patch (3.41 KB, patch)
2016-06-15 21:26 PDT, Chris Dumez
no flags Details | Formatted Diff | Diff
Patch (3.40 KB, patch)
2016-06-16 09:03 PDT, Chris Dumez
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Chris Dumez 2016-06-15 21:19:45 PDT
Avoid some temporary String allocations for common HTTP headers in ResourceResponse::platformLazyInit() by adding a HTTPHeaderMap::set() overload taking a CFStringRef in.
Comment 1 Chris Dumez 2016-06-15 21:26:50 PDT
Created attachment 281435 [details]
Patch
Comment 2 Darin Adler 2016-06-16 08:43:57 PDT
Comment on attachment 281435 [details]
Patch

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

> Source/WebCore/platform/network/HTTPHeaderMap.cpp:69
> +    if (const char* nameCharacters = CFStringGetCStringPtr(name, kCFStringEncodingMacRoman)) {

I suggest auto* here.

After doing a little research on the behavior of recent versions of CF, I suggest using kCFStringEncodingASCII instead of kCFStringEncodingMacRoman here.

> Source/WebCore/platform/network/HTTPHeaderMap.cpp:70
> +        unsigned length =  CFStringGetLength(name);

Extra space here after the "=".

> Source/WebCore/platform/network/HTTPHeaderMap.cpp:75
> +            m_uncommonHeaders.set(String(nameCharacters, length), value);

This line of code is incorrect for some non-ASCII characters. The nameCharacters might contain non-Latin-1 characters that are part of kCFStringEncodingMacRoman, and this will convert them into different characters. Easiest fix for that is probably to pass kCFStringEncodingASCII instead. Other fixes involve scanning the characters to see if they are all ASCII.
Comment 3 Chris Dumez 2016-06-16 09:03:16 PDT
Created attachment 281461 [details]
Patch
Comment 4 Chris Dumez 2016-06-16 09:04:12 PDT
(In reply to comment #2)
> Comment on attachment 281435 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=281435&action=review
> 
> > Source/WebCore/platform/network/HTTPHeaderMap.cpp:69
> > +    if (const char* nameCharacters = CFStringGetCStringPtr(name, kCFStringEncodingMacRoman)) {
> 
> I suggest auto* here.
> 
> After doing a little research on the behavior of recent versions of CF, I
> suggest using kCFStringEncodingASCII instead of kCFStringEncodingMacRoman
> here.
> 
> > Source/WebCore/platform/network/HTTPHeaderMap.cpp:70
> > +        unsigned length =  CFStringGetLength(name);
> 
> Extra space here after the "=".
> 
> > Source/WebCore/platform/network/HTTPHeaderMap.cpp:75
> > +            m_uncommonHeaders.set(String(nameCharacters, length), value);
> 
> This line of code is incorrect for some non-ASCII characters. The
> nameCharacters might contain non-Latin-1 characters that are part of
> kCFStringEncodingMacRoman, and this will convert them into different
> characters. Easiest fix for that is probably to pass kCFStringEncodingASCII
> instead. Other fixes involve scanning the characters to see if they are all
> ASCII.

Made the changes. I have confirmed that the hit rate is still around 93% when using kCFStringEncodingASCII.
Comment 5 WebKit Commit Bot 2016-06-16 09:32:05 PDT
Comment on attachment 281461 [details]
Patch

Clearing flags on attachment: 281461

Committed r202126: <http://trac.webkit.org/changeset/202126>
Comment 6 WebKit Commit Bot 2016-06-16 09:32:09 PDT
All reviewed patches have been landed.  Closing bug.
Comment 7 Sam Weinig 2016-06-19 18:09:19 PDT
Would it work to make the overload take a StringView, instead of the CFStringRef/NSString, and have callers convert to StringView if they have non-String types? Then we could keep the platform specific type out of HTTPHeaderMap?
Comment 8 Chris Dumez 2016-06-20 09:08:13 PDT
(In reply to comment #7)
> Would it work to make the overload take a StringView, instead of the
> CFStringRef/NSString, and have callers convert to StringView if they have
> non-String types? Then we could keep the platform specific type out of
> HTTPHeaderMap?

I wanted to do this at first. However,
1. The converting of a CFStringRef / NSString* into a StringView is not trivial because it is not always possible to get a pointer to the internal characters of a CFStringRef / NSString*.
2. There are 4 call sites (ResourceRequest / ResourceResponse in Cocoa and CF flavors).

I felt like duplicating the relatively complex code for converting a CFStringRef / NSString* into a StringView at 4 different places was not very nice.

What do you think?

Alternatively, I also thought about adding a StringView constructor that takes a CFStringRef in like so:
StringView(CFStringRef string, std::unique_ptr<char[]>& characters);

Which would construct a StringView from the internal CFStringRef characters when possible and would otherwise fallback to extracting those characters and transfer ownership of the characters to the caller via the second parameter.

It would reduce complexity at the 4 call sites.
Comment 9 Darin Adler 2016-06-20 10:22:01 PDT
(In reply to comment #8)
> Alternatively, I also thought about adding a StringView constructor that
> takes a CFStringRef in like so:
> StringView(CFStringRef string, std::unique_ptr<char[]>& characters);
> 
> Which would construct a StringView from the internal CFStringRef characters
> when possible and would otherwise fallback to extracting those characters
> and transfer ownership of the characters to the caller via the second
> parameter.
> 
> It would reduce complexity at the 4 call sites.

If we decide to do something like this, I suggest making it a class instead of a StringView constructor. Call the class something like CocoaStringView; just as with the String class, it needs to outlive any StringView that is made from it. It would usually be fast to destroy, but allocates storage on the heap if needed. Might have some inline capacity too so short strings still don’t require heap allocation even when GetCStringPtr fails.
Comment 10 Chris Dumez 2016-07-08 09:04:48 PDT
Confirmed 1% PLT progression on iOS :)