ffi-yajl 2.2.0 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -2
- data/Rakefile +11 -12
- data/bin/ffi-yajl-bench +4 -5
- data/ext/ffi_yajl/ext/dlopen/extconf.rb +1 -0
- data/ext/ffi_yajl/ext/encoder/encoder.c +9 -4
- data/ext/ffi_yajl/ext/encoder/extconf.rb +2 -1
- data/ext/ffi_yajl/ext/parser/extconf.rb +2 -1
- data/ext/ffi_yajl/ext/parser/parser.c +1 -0
- data/lib/ffi_yajl/benchmark/encode.rb +32 -90
- data/lib/ffi_yajl/benchmark/encode_json_and_marshal.rb +14 -14
- data/lib/ffi_yajl/benchmark/encode_json_and_yaml.rb +13 -19
- data/lib/ffi_yajl/benchmark/encode_profile.rb +11 -15
- data/lib/ffi_yajl/benchmark/http.rb +9 -13
- data/lib/ffi_yajl/benchmark/parse.rb +71 -124
- data/lib/ffi_yajl/benchmark/parse_json_and_marshal.rb +17 -17
- data/lib/ffi_yajl/benchmark/parse_json_and_yaml.rb +19 -19
- data/lib/ffi_yajl/benchmark/parse_profile.rb +10 -14
- data/lib/ffi_yajl/benchmark/parse_profile_ruby_prof.rb +11 -16
- data/lib/ffi_yajl/benchmark/parse_stream.rb +17 -17
- data/lib/ffi_yajl/benchmark.rb +0 -1
- data/lib/ffi_yajl/encoder.rb +3 -3
- data/lib/ffi_yajl/ffi/encoder.rb +29 -32
- data/lib/ffi_yajl/ffi/parser.rb +30 -37
- data/lib/ffi_yajl/ffi.rb +23 -24
- data/lib/ffi_yajl/map_library_name.rb +0 -1
- data/lib/ffi_yajl/parser.rb +5 -6
- data/lib/ffi_yajl/version.rb +1 -1
- data/spec/ffi_yajl/encoder_spec.rb +24 -25
- data/spec/ffi_yajl/map_library_name_spec.rb +0 -2
- data/spec/ffi_yajl/parser_spec.rb +54 -56
- data/spec/spec_helper.rb +8 -9
- metadata +2 -2
@@ -1,17 +1,12 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'benchmark'
|
3
|
-
require 'yaml'
|
4
3
|
require 'yajl'
|
5
4
|
require 'ffi_yajl'
|
6
5
|
if !defined?(RUBY_ENGINE) || RUBY_ENGINE !~ /jruby/
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
puts "INFO: yajl-ruby not installed"
|
12
|
-
end
|
13
|
-
else
|
14
|
-
puts "INFO: skipping yajl-ruby because we're using the C extension"
|
6
|
+
begin
|
7
|
+
require 'yajl'
|
8
|
+
rescue LoadError
|
9
|
+
puts "INFO: yajl-ruby not installed"
|
15
10
|
end
|
16
11
|
else
|
17
12
|
puts "INFO: skipping yajl-ruby on jruby"
|
@@ -20,127 +15,79 @@ begin
|
|
20
15
|
require 'json'
|
21
16
|
rescue LoadError
|
22
17
|
end
|
23
|
-
begin
|
24
|
-
require 'psych'
|
25
|
-
rescue LoadError
|
26
|
-
end
|
27
|
-
begin
|
28
|
-
require 'active_support'
|
29
|
-
rescue LoadError
|
30
|
-
end
|
31
18
|
begin
|
32
19
|
require 'oj'
|
33
20
|
rescue LoadError
|
34
21
|
end
|
35
22
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
23
|
+
module FFI_Yajl
|
24
|
+
class Benchmark
|
25
|
+
class Parse
|
26
|
+
def run
|
27
|
+
filename = File.expand_path(File.join(File.dirname(__FILE__), "subjects", "item.json"))
|
28
|
+
json = File.new(filename, 'r')
|
29
|
+
json_str = json.read
|
42
30
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
31
|
+
times = ARGV[1] ? ARGV[1].to_i : 10_000
|
32
|
+
puts "Starting benchmark parsing #{File.size(filename)} bytes of JSON data #{times} times\n\n"
|
33
|
+
::Benchmark.bmbm do |x|
|
34
|
+
x.report do
|
35
|
+
puts "FFI_Yajl::Parser.parse (from a String)"
|
36
|
+
times.times { FFI_Yajl::Parser.parse(json_str) }
|
37
|
+
end
|
38
|
+
# ffi_parser = FFI_Yajl::Parser.new
|
39
|
+
# x.report {
|
40
|
+
# puts "FFI_Yajl::Parser#parse (from a String)"
|
41
|
+
# times.times {
|
42
|
+
# json.rewind
|
43
|
+
# ffi_parser.parse(json.read)
|
44
|
+
# }
|
45
|
+
# }
|
46
|
+
if defined?(Yajl::Parser)
|
47
|
+
x.report do
|
48
|
+
puts "Yajl::Parser.parse (from a String)"
|
49
|
+
times.times { Yajl::Parser.parse(json_str) }
|
50
|
+
end
|
51
|
+
io_parser = Yajl::Parser.new
|
52
|
+
io_parser.on_parse_complete = ->(obj) {} if times > 1
|
53
|
+
x.report do
|
54
|
+
puts "Yajl::Parser#parse (from an IO)"
|
55
|
+
times.times do
|
56
|
+
json.rewind
|
57
|
+
io_parser.parse(json)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
string_parser = Yajl::Parser.new
|
61
|
+
string_parser.on_parse_complete = ->(obj) {} if times > 1
|
62
|
+
x.report do
|
63
|
+
puts "Yajl::Parser#parse (from a String)"
|
64
|
+
times.times do
|
65
|
+
json.rewind
|
66
|
+
string_parser.parse(json_str)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
if defined?(Oj)
|
71
|
+
x.report do
|
72
|
+
puts "Oj.load"
|
73
|
+
times.times do
|
74
|
+
json.rewind
|
75
|
+
Oj.load(json.read)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
if defined?(JSON)
|
80
|
+
x.report do
|
81
|
+
puts "JSON.parse"
|
82
|
+
times.times do
|
83
|
+
json.rewind
|
84
|
+
JSON.parse(json.read, max_nesting: false)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
json.close
|
85
90
|
end
|
86
|
-
|
87
|
-
x.report {
|
88
|
-
puts "Oj.load"
|
89
|
-
times.times {
|
90
|
-
json.rewind
|
91
|
-
Oj.load(json.read)
|
92
|
-
}
|
93
|
-
}
|
94
|
-
end
|
95
|
-
if defined?(JSON)
|
96
|
-
x.report {
|
97
|
-
puts "JSON.parse"
|
98
|
-
times.times {
|
99
|
-
json.rewind
|
100
|
-
JSON.parse(json.read, :max_nesting => false)
|
101
|
-
}
|
102
|
-
}
|
103
|
-
end
|
104
|
-
if defined?(ActiveSupport::JSON)
|
105
|
-
x.report {
|
106
|
-
puts "ActiveSupport::JSON.decode"
|
107
|
-
times.times {
|
108
|
-
json.rewind
|
109
|
-
ActiveSupport::JSON.decode(json.read)
|
110
|
-
}
|
111
|
-
}
|
112
|
-
end
|
113
|
-
x.report {
|
114
|
-
puts "YAML.load (from an IO)"
|
115
|
-
times.times {
|
116
|
-
json.rewind
|
117
|
-
YAML.load(json)
|
118
|
-
}
|
119
|
-
}
|
120
|
-
x.report {
|
121
|
-
puts "YAML.load (from a String)"
|
122
|
-
times.times {
|
123
|
-
YAML.load(json_str)
|
124
|
-
}
|
125
|
-
}
|
126
|
-
if defined?(Psych)
|
127
|
-
x.report {
|
128
|
-
puts "Psych.load (from an IO)"
|
129
|
-
times.times {
|
130
|
-
json.rewind
|
131
|
-
Psych.load(json)
|
132
|
-
}
|
133
|
-
}
|
134
|
-
x.report {
|
135
|
-
puts "Psych.load (from a String)"
|
136
|
-
times.times {
|
137
|
-
Psych.load(json_str)
|
138
|
-
}
|
139
|
-
}
|
140
|
-
end
|
141
|
-
}
|
142
|
-
json.close
|
143
|
-
|
91
|
+
end
|
144
92
|
end
|
145
93
|
end
|
146
|
-
|
@@ -19,32 +19,32 @@ hash = {}
|
|
19
19
|
|
20
20
|
times = ARGV[0] ? ARGV[0].to_i : 1000
|
21
21
|
puts "Starting benchmark parsing #{File.size(filename)} bytes of JSON data #{times} times\n\n"
|
22
|
-
Benchmark.bmbm
|
23
|
-
x.report
|
22
|
+
Benchmark.bmbm do |x|
|
23
|
+
x.report do
|
24
24
|
puts "Yajl::Parser#parse"
|
25
25
|
yajl = Yajl::Parser.new
|
26
|
-
yajl.on_parse_complete =
|
27
|
-
times.times
|
26
|
+
yajl.on_parse_complete = ->(obj) {} if times > 1
|
27
|
+
times.times do
|
28
28
|
json.rewind
|
29
29
|
hash = yajl.parse(json)
|
30
|
-
|
31
|
-
|
30
|
+
end
|
31
|
+
end
|
32
32
|
if defined?(JSON)
|
33
|
-
x.report
|
33
|
+
x.report do
|
34
34
|
puts "JSON.parse"
|
35
|
-
times.times
|
35
|
+
times.times do
|
36
36
|
json.rewind
|
37
|
-
JSON.parse(json.read, :
|
38
|
-
|
39
|
-
|
37
|
+
JSON.parse(json.read, max_nesting: false)
|
38
|
+
end
|
39
|
+
end
|
40
40
|
end
|
41
|
-
x.report
|
41
|
+
x.report do
|
42
42
|
puts "Marshal.load"
|
43
|
-
times.times
|
43
|
+
times.times do
|
44
44
|
marshal_file.rewind
|
45
45
|
Marshal.load(marshal_file)
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
49
|
json.close
|
50
|
-
marshal_file.close
|
50
|
+
marshal_file.close
|
@@ -16,26 +16,26 @@ json = File.new(filename, 'r')
|
|
16
16
|
|
17
17
|
times = ARGV[0] ? ARGV[0].to_i : 1000
|
18
18
|
puts "Starting benchmark parsing #{File.size(filename)} bytes of JSON data #{times} times\n\n"
|
19
|
-
Benchmark.bmbm
|
19
|
+
Benchmark.bmbm do |x|
|
20
20
|
parser = Yajl::Parser.new
|
21
|
-
parser.on_parse_complete =
|
22
|
-
x.report
|
21
|
+
parser.on_parse_complete = ->(obj) {} if times > 1
|
22
|
+
x.report do
|
23
23
|
puts "Yajl::Parser#parse"
|
24
|
-
times.times
|
24
|
+
times.times do
|
25
25
|
json.rewind
|
26
26
|
parser.parse(json)
|
27
|
-
|
28
|
-
|
27
|
+
end
|
28
|
+
end
|
29
29
|
if defined?(JSON)
|
30
|
-
x.report
|
30
|
+
x.report do
|
31
31
|
puts "JSON.parse"
|
32
|
-
times.times
|
32
|
+
times.times do
|
33
33
|
json.rewind
|
34
|
-
JSON.parse(json.read, :
|
35
|
-
|
36
|
-
|
34
|
+
JSON.parse(json.read, max_nesting: false)
|
35
|
+
end
|
36
|
+
end
|
37
37
|
end
|
38
|
-
|
38
|
+
end
|
39
39
|
json.close
|
40
40
|
|
41
41
|
# YAML section
|
@@ -43,13 +43,13 @@ filename = 'benchmark/subjects/ohai.yml'
|
|
43
43
|
yaml = File.new(filename, 'r')
|
44
44
|
|
45
45
|
puts "Starting benchmark parsing #{File.size(filename)} bytes of YAML data #{times} times\n\n"
|
46
|
-
Benchmark.bmbm
|
47
|
-
x.report
|
46
|
+
Benchmark.bmbm do |x|
|
47
|
+
x.report do
|
48
48
|
puts "YAML.load_stream"
|
49
|
-
times.times
|
49
|
+
times.times do
|
50
50
|
yaml.rewind
|
51
51
|
YAML.load(yaml)
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
yaml.close
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
yaml.close
|
@@ -5,7 +5,7 @@ require 'rubygems'
|
|
5
5
|
require 'ffi_yajl'
|
6
6
|
begin
|
7
7
|
require 'perftools'
|
8
|
-
rescue
|
8
|
+
rescue LoadError
|
9
9
|
puts "INFO: perftools.rb gem not installed"
|
10
10
|
end
|
11
11
|
|
@@ -14,24 +14,20 @@ ENV['CPUPROFILE_FREQUENCY'] = "4000"
|
|
14
14
|
module FFI_Yajl
|
15
15
|
class Benchmark
|
16
16
|
class ParseProfile
|
17
|
-
|
18
17
|
def run
|
19
|
-
if defined?(PerfTools)
|
20
|
-
|
21
|
-
|
18
|
+
return if defined?(PerfTools)
|
19
|
+
|
20
|
+
filename = File.expand_path(File.join(File.dirname(__FILE__), "subjects", "ohai.json"))
|
21
|
+
json = File.new(filename, 'r').read
|
22
22
|
|
23
|
-
|
24
|
-
|
23
|
+
times = 1000
|
24
|
+
puts "Starting profiling encoding #{filename} #{times} times\n\n"
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
output = FFI_Yajl::Parser.parse(json)
|
29
|
-
}
|
30
|
-
end
|
31
|
-
system("pprof.rb --text /tmp/ffi_yajl_encode_profile.out")
|
26
|
+
PerfTools::CpuProfiler.start("/tmp/ffi_yajl_encode_profile.out") do
|
27
|
+
times.times { FFI_Yajl::Parser.parse(json) }
|
32
28
|
end
|
29
|
+
system("pprof.rb --text /tmp/ffi_yajl_encode_profile.out")
|
33
30
|
end
|
34
|
-
|
35
31
|
end
|
36
32
|
end
|
37
33
|
end
|
@@ -7,33 +7,28 @@ require 'ffi_yajl'
|
|
7
7
|
module FFI_Yajl
|
8
8
|
class Benchmark
|
9
9
|
class ParseProfileRubyProf
|
10
|
-
|
11
10
|
def run
|
12
11
|
begin
|
13
12
|
require 'ruby-prof'
|
14
|
-
rescue
|
13
|
+
rescue LoadError
|
15
14
|
puts "INFO: perftools.rb gem not installed"
|
16
15
|
end
|
17
16
|
|
18
|
-
if defined?(RubyProf)
|
19
|
-
filename = File.expand_path(File.join(File.dirname(__FILE__), "subjects", "ohai.json"))
|
20
|
-
json = File.new(filename, 'r').read
|
21
|
-
|
22
|
-
times = 1000
|
23
|
-
puts "Starting profiling encoding #{filename} #{times} times\n\n"
|
17
|
+
return if defined?(RubyProf)
|
24
18
|
|
25
|
-
|
26
|
-
|
27
|
-
output = FFI_Yajl::Parser.parse(json)
|
28
|
-
}
|
29
|
-
end
|
19
|
+
filename = File.expand_path(File.join(File.dirname(__FILE__), "subjects", "ohai.json"))
|
20
|
+
json = File.new(filename, 'r').read
|
30
21
|
|
31
|
-
|
32
|
-
|
22
|
+
times = 1000
|
23
|
+
puts "Starting profiling encoding #{filename} #{times} times\n\n"
|
33
24
|
|
25
|
+
result = RubyProf.profile do
|
26
|
+
times.times { FFI_Yajl::Parser.parse(json) }
|
34
27
|
end
|
35
|
-
end
|
36
28
|
|
29
|
+
printer = RubyProf::GraphPrinter.new(result)
|
30
|
+
printer.print(STDOUT, {})
|
31
|
+
end
|
37
32
|
end
|
38
33
|
end
|
39
34
|
end
|
@@ -18,37 +18,37 @@ json = File.new(filename, 'r')
|
|
18
18
|
|
19
19
|
times = ARGV[0] ? ARGV[0].to_i : 100
|
20
20
|
puts "Starting benchmark parsing JSON stream (#{File.size(filename)} bytes of JSON data with 430 JSON separate strings) #{times} times\n\n"
|
21
|
-
Benchmark.bmbm
|
21
|
+
Benchmark.bmbm do |x|
|
22
22
|
parser = Yajl::Parser.new
|
23
|
-
parser.on_parse_complete =
|
24
|
-
x.report
|
23
|
+
parser.on_parse_complete = ->(obj) {}
|
24
|
+
x.report do
|
25
25
|
puts "Yajl::Parser#parse"
|
26
|
-
times.times
|
26
|
+
times.times do
|
27
27
|
json.rewind
|
28
28
|
parser.parse(json)
|
29
|
-
|
30
|
-
|
29
|
+
end
|
30
|
+
end
|
31
31
|
if defined?(JSON)
|
32
|
-
x.report
|
32
|
+
x.report do
|
33
33
|
puts "JSON.parse"
|
34
|
-
times.times
|
34
|
+
times.times do
|
35
35
|
json.rewind
|
36
36
|
while chunk = json.gets
|
37
|
-
JSON.parse(chunk, :
|
37
|
+
JSON.parse(chunk, max_nesting: false)
|
38
38
|
end
|
39
|
-
|
40
|
-
|
39
|
+
end
|
40
|
+
end
|
41
41
|
end
|
42
42
|
if defined?(ActiveSupport::JSON)
|
43
|
-
x.report
|
43
|
+
x.report do
|
44
44
|
puts "ActiveSupport::JSON.decode"
|
45
|
-
times.times
|
45
|
+
times.times do
|
46
46
|
json.rewind
|
47
47
|
while chunk = json.gets
|
48
48
|
ActiveSupport::JSON.decode(chunk)
|
49
49
|
end
|
50
|
-
|
51
|
-
|
50
|
+
end
|
51
|
+
end
|
52
52
|
end
|
53
|
-
|
54
|
-
json.close
|
53
|
+
end
|
54
|
+
json.close
|
data/lib/ffi_yajl/benchmark.rb
CHANGED
data/lib/ffi_yajl/encoder.rb
CHANGED
@@ -41,7 +41,7 @@ module FFI_Yajl
|
|
41
41
|
# call either the ext or ffi hook
|
42
42
|
str = do_yajl_encode(obj, yajl_gen_opts, opts)
|
43
43
|
# we can skip cleaning the whole string for utf-8 issues if we have yajl validate as we go
|
44
|
-
str.encode!("utf-8", "binary", :
|
44
|
+
str.encode!("utf-8", "binary", undef: :replace) unless yajl_gen_opts[:yajl_gen_validate_utf8]
|
45
45
|
str
|
46
46
|
end
|
47
47
|
|
@@ -54,9 +54,9 @@ module FFI_Yajl
|
|
54
54
|
@opts ||= {}
|
55
55
|
end
|
56
56
|
|
57
|
-
def self.raise_error_for_status(status, token=nil)
|
57
|
+
def self.raise_error_for_status(status, token = nil)
|
58
58
|
# scrub token to valid utf-8 since we may be issuing an exception on an invalid utf-8 token
|
59
|
-
token = token.to_s.encode("utf-8", "binary", :
|
59
|
+
token = token.to_s.encode("utf-8", "binary", undef: :replace)
|
60
60
|
case status
|
61
61
|
when 1 # yajl_gen_keys_must_be_strings
|
62
62
|
raise FFI_Yajl::EncodeError, "YAJL internal error: attempted use of non-string object as key"
|