diff options
Diffstat (limited to 'benchmark')
| -rw-r--r-- | benchmark/dir_pwd.yml | 2 | ||||
| -rw-r--r-- | benchmark/file_basename.yml | 6 | ||||
| -rw-r--r-- | benchmark/file_dirname.yml | 6 | ||||
| -rw-r--r-- | benchmark/file_expand_path.yml | 4 | ||||
| -rw-r--r-- | benchmark/file_extname.yml | 6 | ||||
| -rw-r--r-- | benchmark/file_join.yml | 7 | ||||
| -rw-r--r-- | benchmark/float_predicate.yml | 12 | ||||
| -rw-r--r-- | benchmark/int_to_s.yml | 25 | ||||
| -rw-r--r-- | benchmark/integer_predicate.yml | 9 | ||||
| -rw-r--r-- | benchmark/object_class.yml | 40 | ||||
| -rw-r--r-- | benchmark/pathname.yml | 15 | ||||
| -rw-r--r-- | benchmark/set.yml | 4 | ||||
| -rw-r--r-- | benchmark/string_codepoints.yml | 9 | ||||
| -rw-r--r-- | benchmark/string_coderange_scan.yml | 10 | ||||
| -rw-r--r-- | benchmark/string_concat.yml | 4 | ||||
| -rw-r--r-- | benchmark/string_gsub.yml | 11 | ||||
| -rw-r--r-- | benchmark/string_inspect.yml | 13 | ||||
| -rw-r--r-- | benchmark/string_memsearch.yml | 75 | ||||
| -rw-r--r-- | benchmark/string_scrub.yml | 48 | ||||
| -rw-r--r-- | benchmark/time_now.yml | 1 | ||||
| -rw-r--r-- | benchmark/vm_ivar_get.yml | 67 | ||||
| -rw-r--r-- | benchmark/vm_ivar_set_on_instance.yml | 63 | ||||
| -rw-r--r-- | benchmark/vm_regexp.yml | 6 |
23 files changed, 433 insertions, 10 deletions
diff --git a/benchmark/dir_pwd.yml b/benchmark/dir_pwd.yml new file mode 100644 index 0000000000..c435d3ac5e --- /dev/null +++ b/benchmark/dir_pwd.yml @@ -0,0 +1,2 @@ +benchmark: + pwd: Dir.pwd diff --git a/benchmark/file_basename.yml b/benchmark/file_basename.yml new file mode 100644 index 0000000000..fbd78785aa --- /dev/null +++ b/benchmark/file_basename.yml @@ -0,0 +1,6 @@ +prelude: | + # frozen_string_literal: true +benchmark: + long: File.basename("/Users/george/src/github.com/ruby/ruby/benchmark/file_dirname.yml") + long_name: File.basename("Users_george_src_github.com_ruby_ruby_benchmark_file_dirname.yml") + withext: File.basename("/Users/george/src/github.com/ruby/ruby/benchmark/file_dirname.yml", ".yml") diff --git a/benchmark/file_dirname.yml b/benchmark/file_dirname.yml new file mode 100644 index 0000000000..43a81c9371 --- /dev/null +++ b/benchmark/file_dirname.yml @@ -0,0 +1,6 @@ +prelude: | + # frozen_string_literal: true +benchmark: + long: File.dirname("/Users/george/src/github.com/ruby/ruby/benchmark/file_dirname.yml") + short: File.dirname("foo/bar") + n_4: File.dirname("/Users/george/src/github.com/ruby/ruby/benchmark/file_dirname.yml", 4) diff --git a/benchmark/file_expand_path.yml b/benchmark/file_expand_path.yml new file mode 100644 index 0000000000..9e503ab003 --- /dev/null +++ b/benchmark/file_expand_path.yml @@ -0,0 +1,4 @@ +prelude: | + # frozen_string_literal: true +benchmark: + expand_path: File.expand_path("../../foo.txt", __FILE__) diff --git a/benchmark/file_extname.yml b/benchmark/file_extname.yml new file mode 100644 index 0000000000..fb16e55840 --- /dev/null +++ b/benchmark/file_extname.yml @@ -0,0 +1,6 @@ +prelude: | + # frozen_string_literal: true +benchmark: + long: File.extname("/Users/george/src/github.com/ruby/ruby/benchmark/file_dirname.yml") + long_name: File.extname("Users_george_src_github.com_ruby_ruby_benchmark_file_dirname.yml") + short: File.extname("foo/bar") diff --git a/benchmark/file_join.yml b/benchmark/file_join.yml new file mode 100644 index 0000000000..845257cf1e --- /dev/null +++ b/benchmark/file_join.yml @@ -0,0 +1,7 @@ +prelude: | + # frozen_string_literal: true +benchmark: + two_strings: File.join(__FILE__, "path") + many_strings: File.join(__FILE__, "path", "a", "b", "c", "d") + array: File.join([__FILE__, "path", "a", "b", "c", "d"]) + mixed: File.join(__FILE__, "path", "a", "b", ["c", "d"]) diff --git a/benchmark/float_predicate.yml b/benchmark/float_predicate.yml new file mode 100644 index 0000000000..b946937666 --- /dev/null +++ b/benchmark/float_predicate.yml @@ -0,0 +1,12 @@ +prelude: | + floats = [1.0, -1.0, 0.0, Float::NAN, Float::INFINITY, -Float::INFINITY] + +benchmark: + float_nan?: floats.each { |f| f.nan? } + float_finite?: floats.each { |f| f.finite? } + float_infinite?: floats.each { |f| f.infinite? } + float_zero?: floats.each { |f| f.zero? } + float_positive?: floats.each { |f| f.positive? } + float_negative?: floats.each { |f| f.negative? } + +loop_count: 1000000 diff --git a/benchmark/int_to_s.yml b/benchmark/int_to_s.yml new file mode 100644 index 0000000000..000dae9612 --- /dev/null +++ b/benchmark/int_to_s.yml @@ -0,0 +1,25 @@ +prelude: | + # frozen_string_literal: true + N1 = 5 + N2 = 42 + N3 = 400 + N5 = 12345 + N10 = 1_234_567_890 + N19 = 4_611_686_018_427_387_903 + NEG = -1_234_567_890 + BIG20 = 10 ** 19 + 12_345_678_901_234_567 + BIG40 = 10 ** 39 + 123_456_789_012_345 + BIG100 = 10 ** 99 + 42 +benchmark: + fix_1digit: "N1.to_s" + fix_2digit: "N2.to_s" + fix_3digit: "N3.to_s" + fix_5digit: "N5.to_s" + fix_10digit: "N10.to_s" + fix_19digit: "N19.to_s" + fix_negative: "NEG.to_s" + big_20digit: "BIG20.to_s" + big_40digit: "BIG40.to_s" + big_100digit: "BIG100.to_s" + interp_id: '"id=#{N10}"' + interp_mixed: '"a=#{N2},b=#{N5},c=#{N10}"' diff --git a/benchmark/integer_predicate.yml b/benchmark/integer_predicate.yml new file mode 100644 index 0000000000..7c05ff2587 --- /dev/null +++ b/benchmark/integer_predicate.yml @@ -0,0 +1,9 @@ +prelude: | + nums = (0..9).to_a + +benchmark: + integer_zero?: nums.each { |n| n.zero? } + integer_even?: nums.each { |n| n.even? } + integer_odd?: nums.each { |n| n.odd? } + +loop_count: 1000000 diff --git a/benchmark/object_class.yml b/benchmark/object_class.yml new file mode 100644 index 0000000000..1e5409d1e2 --- /dev/null +++ b/benchmark/object_class.yml @@ -0,0 +1,40 @@ +prelude: | + def get_class(obj) + i = 10_000 + while i > 0 + i -= 1 + # 100 times per loop + obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; + obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; + obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; + obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; + obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; + obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; + obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; + obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; + obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; + obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; + obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; obj.class; + end + end + + class Obj + end + obj = Obj.new + + singleton = Obj.new + def singleton.bar + end + + extended = Obj.new + 2.times do + extended.extend Module.new + end + + immediate = 1.4 +benchmark: + obj: get_class(obj) + extended: get_class(extended) + singleton: get_class(singleton) + immediate: get_class(immediate) +loop_count: 1000 diff --git a/benchmark/pathname.yml b/benchmark/pathname.yml new file mode 100644 index 0000000000..bcf3011eab --- /dev/null +++ b/benchmark/pathname.yml @@ -0,0 +1,15 @@ +prelude: | + abs = Pathname("/a") + rel = Pathname("a") + p1 = Pathname.new('foo/././././bar') + p2 = Pathname.new('foo/bar/./../..') + p3 = Pathname.new('foo/bar/zot') +benchmark: + p1+p2: p1+p2 + abs.root?: abs.root? + rel.root?: rel.root? + abs.absolute?: abs.absolute? + rel.absolute?: rel.absolute? + p1.cleanpath: p1.cleanpath + p2.cleanpath: p2.cleanpath + relative_path_from: p3.relative_path_from('foo/bar/qux/quax') diff --git a/benchmark/set.yml b/benchmark/set.yml index 43217036e2..061509cb1f 100644 --- a/benchmark/set.yml +++ b/benchmark/set.yml @@ -259,7 +259,3 @@ benchmark: to_set_10: s1.to_set to_set_100: s2.to_set to_set_1000: s3.to_set - to_set_arg_0: s0.to_set set_subclass - to_set_arg_10: s1.to_set set_subclass - to_set_arg_100: s2.to_set set_subclass - to_set_arg_1000: s3.to_set set_subclass diff --git a/benchmark/string_codepoints.yml b/benchmark/string_codepoints.yml new file mode 100644 index 0000000000..6a07db7ce1 --- /dev/null +++ b/benchmark/string_codepoints.yml @@ -0,0 +1,9 @@ +prelude: | + mixed_ascii64 = ("a" * 63 + "\u{100}") * 2048 + mixed_ascii256 = ("a" * 255 + "\u{100}") * 512 + utf8_2byte = "\u{100}" * 65536 + +benchmark: + codepoints_mixed_ascii64: mixed_ascii64.codepoints + codepoints_mixed_ascii256: mixed_ascii256.codepoints + codepoints_utf8_2byte: utf8_2byte.codepoints diff --git a/benchmark/string_coderange_scan.yml b/benchmark/string_coderange_scan.yml new file mode 100644 index 0000000000..d47bbd2b30 --- /dev/null +++ b/benchmark/string_coderange_scan.yml @@ -0,0 +1,10 @@ +prelude: | + def unknown(s) = s.b.force_encoding("UTF-8") + multibyte = unknown("\u{00e9}" * 16384) # best case: every byte non-ASCII + alternating = unknown("\u{00e9}a" * 10922) # worst case: non-ASCII then ASCII + ascii = unknown("a" * 32768) # baseline + +benchmark: + coderange_multibyte: multibyte.dup.valid_encoding? + coderange_alternating: alternating.dup.valid_encoding? + coderange_ascii: ascii.dup.valid_encoding? diff --git a/benchmark/string_concat.yml b/benchmark/string_concat.yml index f11f95ee9a..c07fd21013 100644 --- a/benchmark/string_concat.yml +++ b/benchmark/string_concat.yml @@ -1,8 +1,8 @@ prelude: | CHUNK = "a" * 64 UCHUNK = "é" * 32 - SHORT = "a" * (GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] / 2) - LONG = "a" * (GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] * 2) + SHORT = "a" * (GC.stat_heap(0, :slot_size) / 2) + LONG = "a" * (GC.stat_heap(0, :slot_size) * 2) GC.disable # GC causes a lot of variance benchmark: binary_concat_7bit: | diff --git a/benchmark/string_gsub.yml b/benchmark/string_gsub.yml index 0f964337dd..c26e1a6498 100644 --- a/benchmark/string_gsub.yml +++ b/benchmark/string_gsub.yml @@ -20,8 +20,19 @@ prelude: | } ESCAPE_PATTERN = Regexp.union(ESCAPED_CHARS.keys) + NO_MATCH_SHARED_STRING = ("a" * 100_000).freeze benchmark: + gsub_no_match_shared: | + str = NO_MATCH_SHARED_STRING.dup + str.gsub!("z", "x") + str + + sub_no_match_shared: | + str = NO_MATCH_SHARED_STRING.dup + str.sub!("z", "x") + str + escape: | str = STR.dup str.gsub!(ESCAPE_PATTERN, ESCAPED_CHARS) diff --git a/benchmark/string_inspect.yml b/benchmark/string_inspect.yml new file mode 100644 index 0000000000..62a884e19d --- /dev/null +++ b/benchmark/string_inspect.yml @@ -0,0 +1,13 @@ +prelude: | + ascii = "Hello, World! This is a benchmark test string." * 100 + utf8 = "こんにちは世界。これはベンチマーク用のテスト文字列です。" * 100 + mixed = ("Hello World! " + "テスト" + " is great! ") * 100 + binary = ("\xE3\x81\x82" * 100).b + escapy = "\n\t\"\\\#" * 100 + +benchmark: + inspect_ascii: ascii.inspect + inspect_utf8: utf8.inspect + inspect_mixed: mixed.inspect + inspect_binary: binary.inspect + inspect_escapy: escapy.inspect diff --git a/benchmark/string_memsearch.yml b/benchmark/string_memsearch.yml new file mode 100644 index 0000000000..cde363289a --- /dev/null +++ b/benchmark/string_memsearch.yml @@ -0,0 +1,75 @@ +prelude: | + # Haystacks of various sizes + small_hay = "a" * 256 + medium_hay = "a" * 4096 + large_hay = "a" * 65536 + + # Short needles (2-8 bytes) that exercise rb_memsearch_ss + needle_2 = "xy" + needle_4 = "xyzw" + needle_8 = "xyzwabcd" + + # Needle whose first byte is absent from the haystack (memchr fast-path) + # vs needle whose first byte is common (rolling hash comparison) + first_byte_absent = "x" + "a" * 3 + first_byte_common = "a" + "x" * 3 + + # Haystack with match at the end + hay_match_end = "a" * 4095 + "xy" + + # Haystack with match at the start + hay_match_start = "xy" + "a" * 4094 + + # Mixed content haystack (more realistic) + mixed_hay = (("abcdefghij" * 100) + "z") * 10 + +benchmark: + # === First byte absent from haystack (biggest win for rolling hash) === + index_first_byte_absent_small: | + small_hay.index(first_byte_absent) + index_first_byte_absent_medium: | + medium_hay.index(first_byte_absent) + index_first_byte_absent_large: | + large_hay.index(first_byte_absent) + + # === First byte common in haystack (stresses comparison loop) === + index_first_byte_common_small: | + small_hay.index(first_byte_common) + index_first_byte_common_medium: | + medium_hay.index(first_byte_common) + index_first_byte_common_large: | + large_hay.index(first_byte_common) + + # === Needle length variations (all absent) === + index_needle_2_absent: | + medium_hay.index(needle_2) + index_needle_4_absent: | + medium_hay.index(needle_4) + index_needle_8_absent: | + medium_hay.index(needle_8) + + # === Match at end of haystack === + index_match_at_end: | + hay_match_end.index(needle_2) + + # === Match at start of haystack === + index_match_at_start: | + hay_match_start.index(needle_2) + + # === include? (same code path) === + include_first_byte_absent: | + medium_hay.include?(first_byte_absent) + include_first_byte_common: | + medium_hay.include?(first_byte_common) + + # === byteindex === + byteindex_first_byte_absent: | + medium_hay.byteindex(first_byte_absent) + byteindex_first_byte_common: | + medium_hay.byteindex(first_byte_common) + + # === Mixed/realistic haystack === + index_mixed_absent: | + mixed_hay.index(needle_4) + index_mixed_present: | + mixed_hay.index("ijab") diff --git a/benchmark/string_scrub.yml b/benchmark/string_scrub.yml new file mode 100644 index 0000000000..4b5faaad8e --- /dev/null +++ b/benchmark/string_scrub.yml @@ -0,0 +1,48 @@ +prelude: | + + STRING_SIZE = 1024 + def duplicate_to_length(str, target_length) + return "" if target_length <= 0 + return str[0, target_length] if str.length >= target_length + + (str * ((target_length / str.length) + 1))[0, target_length] + end + base = "Hello \u{1f600} world! \u{00e9}\u{00f1}" + padding = duplicate_to_length(base, STRING_SIZE) + + valid_utf8 = (padding.b + "OK".b).force_encoding("UTF-8") + valid_utf8.valid_encoding? + unknown_but_valid_utf8 = valid_utf8.dup.b.force_encoding("UTF-8") + invalid_utf8 = (padding.b + "\x80\xFF".b).force_encoding("UTF-8") + invalid_utf8.valid_encoding? + unknown_but_invalid_utf8 = (padding.b + "\x80\xFF".b).force_encoding("UTF-8") + + worst_case_utf8 = duplicate_to_length("\u{1f600}\u{00e9}\u{00f1}", STRING_SIZE).b.force_encoding("UTF-8") + + unknown_but_valid_utf8_worst_case = worst_case_utf8.dup.b.force_encoding("UTF-8") + unknown_but_invalid_utf8_worst_case = (worst_case_utf8.b + "\x80\xFF".b).force_encoding("UTF-8") + +benchmark: + scrub_known_valid: | + string = valid_utf8.dup + string.scrub! + + scrub_known_invalid: | + string = invalid_utf8.dup + string.scrub! + + scrub_unknown_but_valid_coderange: | + string = unknown_but_valid_utf8.dup + string.scrub! + + scrub_unknown_and_invalid_coderange: | + string = unknown_but_invalid_utf8.dup + string.scrub! + + scrub_unknown_but_valid_coderange_worst_case: | + string = unknown_but_valid_utf8_worst_case.dup + string.scrub! + + scrub_unknown_and_invalid_coderange_worst_case: | + string = unknown_but_invalid_utf8_worst_case.dup + string.scrub!
\ No newline at end of file diff --git a/benchmark/time_now.yml b/benchmark/time_now.yml index f6d6a31489..9336877cd4 100644 --- a/benchmark/time_now.yml +++ b/benchmark/time_now.yml @@ -1,3 +1,4 @@ benchmark: - 'Time.now' - 'Time.now(in: "+09:00")' + - 'Time.now.year' diff --git a/benchmark/vm_ivar_get.yml b/benchmark/vm_ivar_get.yml index 9174af6965..1e0dad665f 100644 --- a/benchmark/vm_ivar_get.yml +++ b/benchmark/vm_ivar_get.yml @@ -1,17 +1,75 @@ prelude: | class Example def initialize + @levar = 1 @v0 = 1 @v1 = 2 @v3 = 3 + end + + def get_value_loop + sum = 0 + + i = 0 + while i < 100_000 + # 10 times to de-emphasize loop overhead + sum += @levar + sum += @levar + sum += @levar + sum += @levar + sum += @levar + sum += @levar + sum += @levar + sum += @levar + sum += @levar + sum += @levar + i += 1 + end + + return sum + end + + @levar = 1 + @v0 = 1 + @v1 = 2 + @v3 = 3 + + def self.get_value_loop + sum = 0 + + i = 0 + while i < 100_000 + # 10 times to de-emphasize loop overhead + sum += @levar + sum += @levar + sum += @levar + sum += @levar + sum += @levar + sum += @levar + sum += @levar + sum += @levar + sum += @levar + sum += @levar + i += 1 + end + + return sum + end + end + + class GenExample < Time + def initialize @levar = 1 + @v0 = 1 + @v1 = 2 + @v3 = 3 end def get_value_loop sum = 0 i = 0 - while i < 1000000 + while i < 100_000 # 10 times to de-emphasize loop overhead sum += @levar sum += @levar @@ -31,7 +89,12 @@ prelude: | end obj = Example.new + gen = GenExample.new benchmark: - vm_ivar_get: | + vm_ivar_get_on_obj: | obj.get_value_loop + vm_ivar_get_on_class: | + Example.get_value_loop + vm_ivar_get_on_generic: | + gen.get_value_loop loop_count: 100 diff --git a/benchmark/vm_ivar_set_on_instance.yml b/benchmark/vm_ivar_set_on_instance.yml index 91857b7742..6ce53a86ec 100644 --- a/benchmark/vm_ivar_set_on_instance.yml +++ b/benchmark/vm_ivar_set_on_instance.yml @@ -1,16 +1,44 @@ prelude: | class TheClass def initialize + @levar = 1 @v0 = 1 @v1 = 2 @v3 = 3 + end + + def set_value_loop + # 100k + i = 0 + while i < 100_000 + # 10 times to de-emphasize loop overhead + @levar = i + @levar = i + @levar = i + @levar = i + @levar = i + @levar = i + @levar = i + @levar = i + @levar = i + @levar = i + i += 1 + end + end + end + + class Generic < Time + def initialize @levar = 1 + @v0 = 1 + @v1 = 2 + @v3 = 3 end def set_value_loop - # 1M + # 100k i = 0 - while i < 1000000 + while i < 100_000 # 10 times to de-emphasize loop overhead @levar = i @levar = i @@ -28,8 +56,39 @@ prelude: | end obj = TheClass.new + gen_obj = Generic.new + + class SomeClass + @levar = 1 + @v0 = 1 + @v1 = 2 + @v3 = 3 + + def self.set_value_loop + # 100k + i = 0 + while i < 100_000 + # 10 times to de-emphasize loop overhead + @levar = i + @levar = i + @levar = i + @levar = i + @levar = i + @levar = i + @levar = i + @levar = i + @levar = i + @levar = i + i += 1 + end + end + end benchmark: vm_ivar_set_on_instance: | obj.set_value_loop + vm_ivar_set_on_generic: | + gen_obj.set_value_loop + vm_ivar_set_on_class: | + SomeClass.set_value_loop loop_count: 100 diff --git a/benchmark/vm_regexp.yml b/benchmark/vm_regexp.yml index 2aa3d94dbd..80541332b1 100644 --- a/benchmark/vm_regexp.yml +++ b/benchmark/vm_regexp.yml @@ -3,6 +3,12 @@ prelude: | benchmark: vm_regexp: | /hoge/ =~ str + vm_regexp_alternating: | + /hoge/ =~ str + /huge/ =~ str vm_regexp_invert: | str =~ /hoge/ + vm_regexp_invert_alternating: | + str =~ /hoge/ + str =~ /huge/ loop_count: 6000000 |
