Skip to content

Instantly share code, notes, and snippets.

@arika
Last active October 13, 2019 08:30
Show Gist options
  • Save arika/4dbe22d2a489554f72f30168ceea0831 to your computer and use it in GitHub Desktop.
Save arika/4dbe22d2a489554f72f30168ceea0831 to your computer and use it in GitHub Desktop.
benchmark read lines and scan lines
# 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
# 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