Lift Json Serialization write optimization and patch

98 views
Skip to first unread message

Chris Webster

unread,
May 27, 2015, 10:57:56 AM5/27/15
to lif...@googlegroups.com
I was profiling an application using lift-json (2.6.2) and the profiler was showing a significant portion of time was spent in JsonAST.appendEscapedString (see https://github.com/lift/framework/blob/master/core/json/src/main/scala/net/liftweb/json/JsonAST.scala#L864). The StringBuilder.append method invoked was StringBuilder.append(Object) as both String and Char are being returned. The implementation of StringBuilder.append(Object) when applied to a Character is essentially:

* call Character.toString - which produces a one element char[] and then creates a new String with the char array, which in turn does a defensive copy of the buffer.
* the string created about is used to add to the StringBuilder

Here is a change to JsonAST.appendEscapedString to use the StringBuilder.append(Char) which directly inserts the character into the buffer avoiding the operations described above (https://github.com/lift/framework/compare/master...chriswebster:appendStringOp?expand=1). The patch attempts to minimize the change to the code but get the performance gain, by ensuring the StringBuilder.append(Character) method is used when copying unconverted characters. 


Current code:

285499.476 ±(99.9%) 5230.757 ops/s [Average]

[info]   (min, avg, max) = (279162.240, 285499.476, 289016.681), stdev = 3459.822

[info]   CI (99.9%): [280268.719, 290730.233] (assumes normal distribution)


After change:

545955.912 ±(99.9%) 9927.185 ops/s [Average]

[info]   (min, avg, max) = (533569.676, 545955.912, 556373.272), stdev = 6566.219

[info]   CI (99.9%): [536028.727, 555883.098] (assumes normal distribution)

Which represents about a 90% performance increase when writing values. Please consider this for inclusion into the lift json code base. 

Chris 



Antonio Salazar Cardozo

unread,
May 28, 2015, 10:15:10 AM5/28/15
to lif...@googlegroups.com, cwebs...@gmail.com
I think we could accept a pull request for this.

One question: if case c: Char is used, does that not select the correct overload
of StringBuilder.append?
Thanks,
Antonio

Chris Webster

unread,
May 28, 2015, 1:58:35 PM5/28/15
to lif...@googlegroups.com, cwebs...@gmail.com
Hi, 
  The javap output from case c:Char and case c for the invocation of StringBuilder.append is the same (both generate StringBuilder.append(Object) invocations). I captured the output here:

https://gist.github.com/chriswebster/dec25f150fbba24ceba2 . Let me know if pull request is ok. 

Chris 

Matt Farmer

unread,
May 29, 2015, 11:13:51 AM5/29/15
to Lift
I, too, think this is small enough that we could accept a PR for. It represents a significant benefit to other developers.


Matt Farmer Blog | Twitter

--
--
Lift, the simply functional web framework: http://liftweb.net
Code: http://github.com/lift
Discussion: http://groups.google.com/group/liftweb
Stuck? Help us help you: https://www.assembla.com/wiki/show/liftweb/Posting_example_code

---
You received this message because you are subscribed to the Google Groups "Lift" group.
To unsubscribe from this group and stop receiving emails from it, send an email to liftweb+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Chris Webster

unread,
May 29, 2015, 9:57:45 PM5/29/15
to lif...@googlegroups.com
Thanks!

Chris 
Reply all
Reply to author
Forward
0 new messages