Count newlines of text nodes in native code.

Instead of relying on String#count for counting newlines in text nodes, Oga now
does this in C/Java. String#count isn't exactly the fastest way of counting
characters. Performance was measured using
benchmark/xml/lexer/string_average_bench.rb. Before this patch the results were
as following:

    MRI:   0.529s
    Rbx:   4.965s
    JRuby: 0.622s

After this patch:

    MRI:   0.424s
    Rbx:   1.942s
    JRuby: 0.665s => numbers vary a bit, seem roughly the same as before

The commands used for benchmarking:

    $ rake clean # to make sure that C exts aren't shared between MRI/Rbx
    $ rake generate
    $ rake fixtures
    $ ruby benchmark/xml/lexer/string_average_bench.rb

The big difference for Rbx is probably due to the implementation of String#count
not being super fast. Some changes were made
(https://github.com/rubinius/rubinius/pull/3133) to the method, but this hasn't
been released yet.

JRuby seems to perform in a similar way, so either it was already optimizing
things for me or I suck at writing well performing Java code.

This fixes #51.
This commit is contained in:
Yorick Peterse committed 2014-09-25 22:49:11 +02:00
1 parent 4469ffc5b1
commit 8db77c0a09
4 files changed
+46 -25

No files matched your search

+18 -6
View File
@@ -90,12 +90,13 @@ public class Lexer extends RubyObject
byte[] data = rb_str.getBytes();
int ts = 0;
int te = 0;
int p = 0;
int mark = 0;
int pe = data.length;
int eof = data.length;
int ts = 0;
int te = 0;
int p = 0;
int mark = 0;
int lines = 0;
int pe = data.length;
int eof = data.length;
%% write exec;
@@ -141,6 +142,17 @@ public class Lexer extends RubyObject
this.callMethod(context, name);
}
/**
* Advances the line number by `amount` lines.
*/
public void advance_line(int amount)
{
ThreadContext context = this.runtime.getCurrentContext();
RubyFixnum lines = this.runtime.newFixnum(amount);
this.callMethod(context, "advance_line", lines);
}
}
%%{