Last active
October 13, 2019 08:30
-
-
Save arika/4dbe22d2a489554f72f30168ceea0831 to your computer and use it in GitHub Desktop.
benchmark read lines and scan lines
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
require "benchmark" | |
require "strscan" | |
def open_file(filename = "development.log") | |
File.open(filename, "r") do |io| | |
yield io | |
end | |
end | |
def action(line) | |
# noop | |
end | |
Benchmark.bmbm do |bm| | |
bm.report("#read [all]") do | |
open_file do |io| | |
io.read | |
end | |
end | |
bm.report("#gets") do | |
open_file do |io| | |
while line = io.gets | |
action(line) | |
end | |
end | |
end | |
bm.report("#each_line") do | |
open_file do |io| | |
io.each_line do |line| | |
action(line) | |
end | |
end | |
end | |
[128, 512, 1024, 4096, 8192].each do |size| | |
bm.report("#sysread [#{size}]") do | |
open_file do |io| | |
buf = +"" | |
rest = nil | |
while buf << io.sysread(size) | |
buf.each_line do |line| | |
unless line[-1] == "\n" | |
rest = line | |
break | |
end | |
action(line) | |
rest = nil | |
end | |
buf = rest || +"" | |
end | |
rescue EOFError | |
action(rest) if rest | |
end | |
end | |
end | |
[128, 512, 1024, 4096, 8192].each do |size| | |
bm.report("#read [#{size}]") do | |
open_file do |io| | |
buf = +"" | |
rest = nil | |
while buf << io.read(size) | |
buf.each_line do |line| | |
unless line[-1] == "\n" | |
rest = line | |
break | |
end | |
action(line) | |
rest = nil | |
end | |
if io.eof? | |
action(rest) if rest | |
break | |
end | |
buf = rest || +"" | |
end | |
end | |
end | |
end | |
[128, 512, 1024, 4096, 8192].each do |size| | |
bm.report("#readpartial [#{size}]") do | |
open_file do |io| | |
buf = +"" | |
rest = nil | |
while buf << io.readpartial(size) | |
buf.each_line do |line| | |
unless line[-1] == "\n" | |
rest = line | |
break | |
end | |
action(line) | |
rest = nil | |
end | |
if io.eof? | |
action(rest) if rest | |
break | |
end | |
buf = rest || +"" | |
end | |
end | |
end | |
end | |
[128, 512, 1024, 4096, 8192].each do |size| | |
bm.report("StringScanner [#{size}]") do | |
s = StringScanner.new(+"") | |
open_file do |io| | |
while s << io.readpartial(size) | |
while line = s.scan_until(/\n/) | |
action(line) | |
end | |
if io.eof? | |
action(s.rest) if s.rest? | |
break | |
end | |
end | |
end | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
require "benchmark" | |
require "strscan" | |
def open_file(filename = "development.log") | |
File.open(filename, "r") do |io| | |
yield io | |
end | |
end | |
def time(year, month, day, hour, min, sec, usec) | |
Time.local(year.to_i, month.to_i, day.to_i, hour.to_i, min.to_i, sec.to_i, usec.to_i) | |
end | |
def action(*args) | |
$result << args if $result.size < 100 | |
end | |
def setup | |
$result = [] | |
end | |
def check | |
return if $expected == $result | |
raise unless $expected.size == $result.size | |
$expected.each_with_index do |expected, idx| | |
result = $result[idx] | |
unless expected == result | |
puts | |
p expected | |
p result | |
raise | |
end | |
end | |
end | |
pattern = "(.), \\[(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2}).(\\d+) #(\\d+)\\] \\S+ -- : " | |
setup | |
open_file do |io| | |
io.read.scan(/^#{pattern}(.*)\n/o) do |severity, *time_segs, pid, message| | |
time = time(*time_segs) | |
action(severity, time, pid.to_i, message.chomp) | |
end | |
end | |
$expected = $result | |
Benchmark.bmbm do |bm| | |
bm.report("#read [all]") do | |
setup | |
open_file do |io| | |
io.read.scan(/^#{pattern}(.*)\n/o) do |severity, *time_segs, pid, message| | |
time = time(*time_segs) | |
action(severity, time, pid.to_i, message.chomp) | |
end | |
end | |
check | |
end | |
bm.report("#gets") do | |
setup | |
open_file do |io| | |
while line = io.gets | |
next unless /\A#{pattern}/o =~ line | |
time = time($2, $3, $4, $5, $6, $7, $8) | |
action($1, time, $9.to_i, $'.chomp) | |
end | |
end | |
check | |
end | |
bm.report("#each_line") do | |
setup | |
open_file do |io| | |
io.each_line do |line| | |
next unless /\A#{pattern}/o =~ line | |
time = time($2, $3, $4, $5, $6, $7, $8) | |
action($1, time, $9.to_i, $'.chomp) | |
end | |
end | |
check | |
end | |
[4096, 8192, 1024 * 16, 1024 * 64, 1024 * 256].each do |size| | |
bm.report("#readpartial [#{size}]") do | |
setup | |
open_file do |io| | |
buf = +"" | |
while buf << io.readpartial(size) | |
buf.scan(/^#{pattern}(.*)\n/o) do |severity, *time_segs, pid, message| | |
time = time(*time_segs) | |
action(severity, time, pid.to_i, message) | |
end | |
break if io.eof? | |
buf = $'.empty? ? +"" : $' if $' | |
end | |
end | |
check | |
end | |
end | |
[4096, 8192, 1024 * 16, 1024 * 64, 1024 * 256].each do |size| | |
bm.report("StringScanner [#{size}]") do | |
setup | |
s = StringScanner.new(+"") | |
open_file do |io| | |
while s << io.readpartial(size) | |
while line = s.skip_until(/^#{pattern}(.*)\n/o) | |
time = time(s[2], s[3], s[4], s[5], s[6], s[7], s[8]) | |
action(s[1], time, s[9].to_i, s[10]) | |
end | |
break if io.eof? | |
end | |
end | |
check | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment