[JSC] Optimize Kraken stringify
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 15 Dec 2016 10:28:55 +0000 (10:28 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 15 Dec 2016 10:28:55 +0000 (10:28 +0000)
https://bugs.webkit.org/show_bug.cgi?id=165857

Reviewed by Darin Adler.

Kraken json-stringify-tinderbox performance heavily relies on StringBuilder::appendQuotedJSONString.
According to the result produced by Linux `perf`, it occupies 28% of execution time.

We tighten the hottest loop in the above function. We create the super fast path for non escaping case.
And add " and \ cases (since including " in the string is common). Then we fallback to the slow case.

It improves the performance 5.5% in Kraken json-stringify-tinderbox in MBP.

    Performance result in my MBP (dandelion).

        Collected 100 samples per benchmark/VM, with 100 VM invocations per benchmark. Emitted a call to gc()
        between sample measurements. Used 1 benchmark iteration per VM invocation for warm-up. Used the
        jsc-specific preciseTime() function to get microsecond-level timing. Reporting benchmark execution times
        with 95% confidence intervals in milliseconds.

                                           baseline                  patched

        json-stringify-tinderbox        29.243+-0.241      ^      27.701+-0.235         ^ definitely 1.0557x faster

        <arithmetic>                    29.243+-0.241      ^      27.701+-0.235         ^ definitely 1.0557x faster

    Performance result in my Linux laptop (hanayamata).

        Collected 100 samples per benchmark/VM, with 100 VM invocations per benchmark. Emitted a call to gc()
        between sample measurements. Used 1 benchmark iteration per VM invocation for warm-up. Used the
        jsc-specific preciseTime() function to get microsecond-level timing. Reporting benchmark execution times
        with 95% confidence intervals in milliseconds.

                                           baseline                  patched

        json-stringify-tinderbox        26.711+-0.475      ^      25.255+-0.034         ^ definitely 1.0577x faster

        <arithmetic>                    26.711+-0.475      ^      25.255+-0.034         ^ definitely 1.0577x faster

* wtf/text/StringBuilder.cpp:
(WTF::appendQuotedJSONStringInternalSlow):
(WTF::appendQuotedJSONStringInternal):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@209858 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WTF/ChangeLog
Source/WTF/wtf/text/StringBuilder.cpp

index 9597093..c3f27da 100644 (file)
@@ -1,3 +1,48 @@
+2016-12-15  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [JSC] Optimize Kraken stringify
+        https://bugs.webkit.org/show_bug.cgi?id=165857
+
+        Reviewed by Darin Adler.
+
+        Kraken json-stringify-tinderbox performance heavily relies on StringBuilder::appendQuotedJSONString.
+        According to the result produced by Linux `perf`, it occupies 28% of execution time.
+
+        We tighten the hottest loop in the above function. We create the super fast path for non escaping case.
+        And add " and \ cases (since including " in the string is common). Then we fallback to the slow case.
+
+        It improves the performance 5.5% in Kraken json-stringify-tinderbox in MBP.
+
+            Performance result in my MBP (dandelion).
+
+                Collected 100 samples per benchmark/VM, with 100 VM invocations per benchmark. Emitted a call to gc()
+                between sample measurements. Used 1 benchmark iteration per VM invocation for warm-up. Used the
+                jsc-specific preciseTime() function to get microsecond-level timing. Reporting benchmark execution times
+                with 95% confidence intervals in milliseconds.
+
+                                                   baseline                  patched
+
+                json-stringify-tinderbox        29.243+-0.241      ^      27.701+-0.235         ^ definitely 1.0557x faster
+
+                <arithmetic>                    29.243+-0.241      ^      27.701+-0.235         ^ definitely 1.0557x faster
+
+            Performance result in my Linux laptop (hanayamata).
+
+                Collected 100 samples per benchmark/VM, with 100 VM invocations per benchmark. Emitted a call to gc()
+                between sample measurements. Used 1 benchmark iteration per VM invocation for warm-up. Used the
+                jsc-specific preciseTime() function to get microsecond-level timing. Reporting benchmark execution times
+                with 95% confidence intervals in milliseconds.
+
+                                                   baseline                  patched
+
+                json-stringify-tinderbox        26.711+-0.475      ^      25.255+-0.034         ^ definitely 1.0577x faster
+
+                <arithmetic>                    26.711+-0.475      ^      25.255+-0.034         ^ definitely 1.0577x faster
+
+        * wtf/text/StringBuilder.cpp:
+        (WTF::appendQuotedJSONStringInternalSlow):
+        (WTF::appendQuotedJSONStringInternal):
+
 2016-12-14  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r209795.
index bd793a4..436015a 100644 (file)
@@ -386,46 +386,58 @@ void StringBuilder::shrinkToFit()
 }
 
 template <typename OutputCharacterType, typename InputCharacterType>
+static void appendQuotedJSONStringInternalSlow(OutputCharacterType*& output, const InputCharacterType character)
+{
+    switch (character) {
+    case '\t':
+        *output++ = '\\';
+        *output++ = 't';
+        break;
+    case '\r':
+        *output++ = '\\';
+        *output++ = 'r';
+        break;
+    case '\n':
+        *output++ = '\\';
+        *output++ = 'n';
+        break;
+    case '\f':
+        *output++ = '\\';
+        *output++ = 'f';
+        break;
+    case '\b':
+        *output++ = '\\';
+        *output++ = 'b';
+        break;
+    default:
+        ASSERT(!(character & 0xFF00));
+        *output++ = '\\';
+        *output++ = 'u';
+        *output++ = '0';
+        *output++ = '0';
+        *output++ = upperNibbleToLowercaseASCIIHexDigit(character);
+        *output++ = lowerNibbleToLowercaseASCIIHexDigit(character);
+        break;
+    }
+}
+
+template <typename OutputCharacterType, typename InputCharacterType>
 static void appendQuotedJSONStringInternal(OutputCharacterType*& output, const InputCharacterType* input, unsigned length)
 {
     for (const InputCharacterType* end = input + length; input != end; ++input) {
-        if (LIKELY(*input > 0x1F)) {
-            if (*input == '"' || *input == '\\')
-                *output++ = '\\';
-            *output++ = *input;
+        const InputCharacterType character = *input;
+        if (LIKELY(character != '"' && character != '\\' && character > 0x1F)) {
+            *output++ = character;
             continue;
         }
-        switch (*input) {
-        case '\t':
-            *output++ = '\\';
-            *output++ = 't';
-            break;
-        case '\r':
-            *output++ = '\\';
-            *output++ = 'r';
-            break;
-        case '\n':
-            *output++ = '\\';
-            *output++ = 'n';
-            break;
-        case '\f':
-            *output++ = '\\';
-            *output++ = 'f';
-            break;
-        case '\b':
-            *output++ = '\\';
-            *output++ = 'b';
-            break;
-        default:
-            ASSERT((*input & 0xFF00) == 0);
+
+        if (character == '"' || character == '\\') {
             *output++ = '\\';
-            *output++ = 'u';
-            *output++ = '0';
-            *output++ = '0';
-            *output++ = upperNibbleToLowercaseASCIIHexDigit(*input);
-            *output++ = lowerNibbleToLowercaseASCIIHexDigit(*input);
-            break;
+            *output++ = character;
+            continue;
         }
+
+        appendQuotedJSONStringInternalSlow(output, character);
     }
 }