Ruby deserializer speed improvements
------------------------------------

                 Key: THRIFT-1189
                 URL: https://issues.apache.org/jira/browse/THRIFT-1189
             Project: Thrift
          Issue Type: Improvement
          Components: Ruby - Library
    Affects Versions: 0.6.1
         Environment: OS X 10.6 i686 / Linux x86_64
Ruby 1.8.7-p334 / Ruby 1.9.2-p180
            Reporter: Ilya Maykov


I have a patch to the Ruby libraries that greatly increases deserializer speed. 
We've been running our production systems at Ooyala with this patch for weeks 
but it was previously just a standalone file which changed some methods inside 
Thrift code and we loaded it after requiring thrift. Over the weekend, I ported 
it into a proper patch against the 0.6.1 tag and would like to commit it back.

I originally wrote this while trying to speed up some code we have that has to 
deserialize a lot of thrift objects. I ran it under ruby-prof and noticed that 
a huge amount of time was spent inside thrift deserialization code. Digging 
deeper still, I saw a lot of time spent in String allocation and copy methods. 
It turns out that there are several low-hanging fruit:

1) XProtocol#read_byte() methods end up calling read_all(1), getting back a 
string of size 1, and converting it to a byte. This is an unnecessary string 
alloc + copy that's pretty easy to get around. The patch does this by adding a 
read_byte method to the XTransport classes. The transports that have buffering 
of some kind (BufferedTransport, FramedTransport, MemoryBufferTransport) can 
look up the byte, convert to unsigned, and return it without doing the extra 
alloc + copy.
2) the BaseProtocol#read_all() method always allocates an empty buffer string, 
reads bytes from the underlying transport, then appends the result to the 
buffer. This extra string alloc + copy is also removed in my patch as it's not 
needed.
3) Thrift::Struct#hash() is inefficient - it allocates an array and copies all 
struct fields into it. Replaced with logic copied from Apache's Java 
HashCodeBuilder class.

I've built a gem locally (i gave it version number 0.6.1.1) and wrote a simple 
benchmark to test the changes. Here are the results:

|| Benchmark/Platform || r1.8.7-p334/thrift-0.6.0 || r1.8.7-p334/thrift-0.6.1.1 
|| r1.9.2-p180/thrift-0.6.0 || r1.9.2-p180/thrift-0.6.1.1 ||
| Deserialization: BinaryProtocol | 16.01 | 10.23 | 8.73 | 5.58 |
| Deserialization: BinaryProtocolAccelerated | 11.46 | 6.31 | 5.73 | 3.64 |
| Deserialization: CompactProtocol | 11.56 | 3.73 | 5.70 | 2.61 |
| Hashing | 1.5 | 1.23 | 0.95 | 0.49 |

I will be attaching the patch and benchmark code shortly.

--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira

Reply via email to