diff --git a/.gitignore b/.gitignore index 6184ec3995..5adf6ccf52 100644 --- a/.gitignore +++ b/.gitignore @@ -60,6 +60,7 @@ lcov*.info /archive /autom4te*.cache /automake +/benchmark/benchmark-driver /beos /bmlog-* /breakpoints.gdb diff --git a/Makefile.in b/Makefile.in index 8a1271c7ab..863e573baa 100644 --- a/Makefile.in +++ b/Makefile.in @@ -515,6 +515,11 @@ gcov: lcov: $(Q) $(BASERUBY) $(srcdir)/tool/run-lcov.rb +update-benchmark-driver: + $(Q) $(srcdir)/tool/git-refresh -C $(srcdir)/benchmark $(Q1:0=-q) \ + --branch $(BENCHMARK_DRIVER_GIT_REF) \ + $(BENCHMARK_DRIVER_GIT_URL) benchmark-driver $(GIT_OPTS) + update-doclie: $(Q) $(srcdir)/tool/git-refresh -C $(srcdir)/coverage $(Q1:0=-q) \ --branch $(DOCLIE_GIT_REF) \ diff --git a/benchmark/bm_require.rb b/benchmark/bm_require.rb deleted file mode 100644 index b8abc88f41..0000000000 --- a/benchmark/bm_require.rb +++ /dev/null @@ -1,7 +0,0 @@ -$:.push File.join(File.dirname(__FILE__), "bm_require.data") - -1.upto(10000) do |i| - require "c#{i}" -end - -$:.pop diff --git a/benchmark/bm_require_thread.rb b/benchmark/bm_require_thread.rb deleted file mode 100644 index e54db6c6e5..0000000000 --- a/benchmark/bm_require_thread.rb +++ /dev/null @@ -1,15 +0,0 @@ -$:.push File.join(File.dirname(__FILE__), "bm_require.data") - -i=0 -t = Thread.new do - while true - i = i+1 # dummy loop - end -end - -1.upto(100) do |i| - require "c#{i}" -end - -$:.pop -t.kill diff --git a/benchmark/bm_so_count_words.rb b/benchmark/bm_so_count_words.rb deleted file mode 100644 index 65f6337a4a..0000000000 --- a/benchmark/bm_so_count_words.rb +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/ruby -# -*- mode: ruby -*- -# $Id: wc-ruby.code,v 1.4 2004/11/13 07:43:32 bfulgham Exp $ -# http://www.bagley.org/~doug/shootout/ -# with help from Paul Brannan - -input = open(File.join(File.dirname($0), 'wc.input'), 'rb') - -nl = nw = nc = 0 -while true - tmp = input.read(4096) or break - data = tmp << (input.gets || "") - nc += data.length - nl += data.count("\n") - ((data.strip! || data).tr!("\n", " ") || data).squeeze! - nw += data.count(" ") + 1 -end -# STDERR.puts "#{nl} #{nw} #{nc}" - diff --git a/benchmark/bm_so_k_nucleotide.rb b/benchmark/bm_so_k_nucleotide.rb deleted file mode 100644 index dadab3e79c..0000000000 --- a/benchmark/bm_so_k_nucleotide.rb +++ /dev/null @@ -1,48 +0,0 @@ -# The Computer Language Shootout -# http://shootout.alioth.debian.org -# -# contributed by jose fco. gonzalez -# modified by Sokolov Yura - -seq = String.new - -def frecuency( seq,length ) - n, table = seq.length - length + 1, Hash.new(0) - f, i = nil, nil - (0 ... length).each do |f| - (f ... n).step(length) do |i| - table[seq[i,length]] += 1 - end - end - [n,table] - -end - -def sort_by_freq( seq,length ) - n,table = frecuency( seq,length ) - a, b, v = nil, nil, nil - table.sort{|a,b| b[1] <=> a[1]}.each do |v| - puts "%s %.3f" % [v[0].upcase,((v[1]*100).to_f/n)] - end - puts -end - -def find_seq( seq,s ) - n,table = frecuency( seq,s.length ) - puts "#{table[s].to_s}\t#{s.upcase}" -end - -input = open(File.join(File.dirname($0), 'fasta.output.100000'), 'rb') - -line = input.gets while line !~ /^>THREE/ -line = input.gets - -while (line !~ /^>/) & line do - seq << line.chomp - line = input.gets -end - -[1,2].each {|i| sort_by_freq( seq,i ) } - -%w(ggt ggta ggtatt ggtattttaatt ggtattttaatttatagt).each{|s| find_seq( seq,s) } - diff --git a/benchmark/bm_so_reverse_complement.rb b/benchmark/bm_so_reverse_complement.rb deleted file mode 100644 index 82ea666994..0000000000 --- a/benchmark/bm_so_reverse_complement.rb +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/ruby -# The Great Computer Language Shootout -# http://shootout.alioth.debian.org/ -# -# Contributed by Peter Bjarke Olsen -# Modified by Doug King - -seq=Array.new - -def revcomp(seq) - seq.reverse!.tr!('wsatugcyrkmbdhvnATUGCYRKMBDHVN','WSTAACGRYMKVHDBNTAACGRYMKVHDBN') - stringlen=seq.length - 0.step(stringlen-1,60) {|x| print seq.slice(x,60) , "\n"} -end - -input = open(File.join(File.dirname($0), 'fasta.output.2500000'), 'rb') - -while input.gets - if $_ =~ />/ - if seq.length != 0 - revcomp(seq.join) - seq=Array.new - end - puts $_ - else - $_.sub(/\n/,'') - seq.push $_ - end -end -revcomp(seq.join) diff --git a/benchmark/driver.rb b/benchmark/driver.rb index c166c80edb..3536d9abd4 100755 --- a/benchmark/driver.rb +++ b/benchmark/driver.rb @@ -10,256 +10,66 @@ rescue LoadError require 'optparse' end -require 'benchmark' -require 'pp' +require 'shellwords' require 'tempfile' class BenchmarkDriver - def self.benchmark(opt) - driver = self.new(opt[:execs], opt[:dir], opt) - begin - driver.run - ensure - driver.show_results + # Run benchmark-driver prepared by `make update-benchmark-driver` + def self.run(*args) + benchmark_driver = File.expand_path('./benchmark-driver/exe/benchmark-driver', __dir__) + command = [benchmark_driver, *args] + unless system(command.shelljoin) + abort "Failed to execute: #{command.shelljoin}" end end - def self.load(input, type, opt) - case type - when 'yaml' - require 'yaml' - h = YAML.load(input) - when 'json' - require 'json' - h = JSON.load(input) - else - h = eval(input.read) - end - results = h[:results] || h["results"] - obj = allocate - obj.instance_variable_set("@execs", h[:executables] || h["executables"]) - obj.instance_variable_set("@results", results) - obj.instance_variable_set("@opt", opt) - [1, 2].each do |i| - loop = results.assoc((n = "loop_whileloop#{i}").intern) || results.assoc(n) - obj.instance_variable_set("@loop_wl#{i}", loop ? loop[1].map {|t,*|t} : nil) - end - obj.instance_variable_set("@measure_target", opt[:measure_target] || opt["measure_target"]) - obj - end - - def output *args - puts(*args) - @output and @output.puts(*args) - end - - def message *args - output(*args) if @verbose - end - - def message_print *args - if @verbose - print(*args) - STDOUT.flush - @output and @output.print(*args) - end - end - - def progress_message *args - unless STDOUT.tty? - STDERR.print(*args) - STDERR.flush - end - end - - def initialize execs, dir, opt = {} - @execs = execs.map{|e| - e.strip! - next if e.empty? - - if /(.+)::(.+)/ =~ e - # ex) ruby-a::/path/to/ruby-a - label = $1.strip - path = $2 - version = `#{path} --version`.chomp - else - path = e - version = label = `#{path} --version`.chomp - end - [path, label, version] - }.compact - + def initialize(dir, opt = {}) @dir = dir - @repeat = opt[:repeat] || 1 - @repeat = 1 if @repeat < 1 @pattern = opt[:pattern] || nil @exclude = opt[:exclude] || nil - @verbose = opt[:quiet] ? false : (opt[:verbose] || false) - @output = opt[:output] ? open(opt[:output], 'w') : nil - @loop_wl1 = @loop_wl2 = nil - @ruby_arg = opt[:ruby_arg] || nil - @measure_target = opt[:measure_target] - @opt = opt - - # [[name, [[r-1-1, r-1-2, ...], [r-2-1, r-2-2, ...]]], ...] - @results = [] - - if @verbose - @start_time = Time.now - message @start_time - @execs.each_with_index{|(path, label, version), i| - message "target #{i}: " + (label == version ? "#{label}" : "#{label} (#{version})") + " at \"#{path}\"" - } - message "measure target: #{@measure_target}" - end end - def adjusted_results name, results - s = nil - results.each_with_index{|e, i| - r = e.min - case name - when /^vm1_/ - if @loop_wl1 - r -= @loop_wl1[i] - r = 0 if r < 0 - s = '*' - end - when /^vm2_/ - if @loop_wl2 - r -= @loop_wl2[i] - r = 0 if r < 0 - s = '*' + def with_yamls(&block) + ios = files.map do |file| + Tempfile.open.tap do |io| + if file.end_with?('.yml') + io.write(File.read(file)) + else + io.write(build_yaml(file)) end + io.close end - yield r - } - s + end + block.call(ios.map(&:path)) + ensure + ios.each(&:close) end - def show_results - case @opt[:format] - when :tsv - strformat = "\t%1$s" - numformat = "\t%1$*2$.3f" - minwidth = 0 - name_width = 0 - when :markdown - markdown = true - strformat = "|%1$-*2$s" - numformat = "|%1$*2$.3f" - when :plain - strformat = " %1$-*2$s" - numformat = " %1$*2$.3f" + private + + def build_yaml(file) + magic_comment = '# prelude' # bm_so_nsieve_bits hangs without magic comment + name = File.basename(file).sub(/\Abm_/, '').sub(/\.rb\z/, '') + script = File.read(file).sub(/^__END__\n(.+\n)*/m, '').sub(/\A(^#.+\n)+/m) do |comment| + magic_comment = comment + '' end - name_width ||= @results.map {|v, result| - v.size + (case v; when /^vm1_/; @loop_wl1; when /^vm2_/; @loop_wl2; end ? 1 : 0) - }.max - minwidth ||= 7 - width = @execs.map{|(_, v)| [v.size, minwidth].max} - - output - - if @verbose - message '-----------------------------------------------------------' - message 'raw data:' - message - message PP.pp(@results, "", 79) - message - message "Elapsed time: #{Time.now - @start_time} (sec)" - end - - if rawdata_output = @opt[:rawdata_output] - h = {} - h[:cpuinfo] = File.read('/proc/cpuinfo') if File.exist?('/proc/cpuinfo') - h[:executables] = @execs - h[:results] = @results - if (type = File.extname(rawdata_output)).empty? - type = rawdata_output - rawdata_output = @output.path.sub(/\.[^.\/]+\z/, '') << '.' << rawdata_output - end - case type - when 'yaml' - require 'yaml' - h = YAML.dump(h) - when 'json' - require 'json' - h = JSON.pretty_generate(h) - else - require 'pp' - h = h.pretty_inspect - end - open(rawdata_output, 'w') {|f| f.puts h} - end - - output '-----------------------------------------------------------' - output 'benchmark results:' - - if @verbose and @repeat > 1 - output "minimum results in each #{@repeat} measurements." - end - - output({ - real: "Execution time (sec)", - utime: "user CPU time", - stime: "system CPU time", - cutime: "user CPU time of children", - cstime: "system CPU time of children", - total: "all CPU time", - peak: "Memory usage (peak) (B)", - size: "Memory usage (last size) (B)", - }[@measure_target]) - output if markdown - output ["name".ljust(name_width), @execs.map.with_index{|(_, v), i| sprintf(strformat, v, width[i])}].join("").rstrip - output ["-"*name_width, width.map{|n|":".rjust(n, "-")}].join("|") if markdown - @results.each{|v, result| - rets = [] - s = adjusted_results(v, result){|r| - rets << sprintf(numformat, r, width[rets.size]) - } - v += s if s - output [v.ljust(name_width), rets].join("") - } - - if @execs.size > 1 - output - output({ - real: "Speedup ratio: compare with the result of `#{@execs[0][1]}' (greater is better)", - peak: "Memory consuming ratio (peak) with the result of `#{@execs[0][1]}' (greater is better)", - size: "Memory consuming ratio (size) with the result of `#{@execs[0][1]}' (greater is better)", - }[@measure_target]) - output if markdown - output ["name".ljust(name_width), @execs[1..-1].map.with_index{|(_, v), i| sprintf(strformat, v, width[i])}].join("").rstrip - output ["-"*name_width, width[1..-1].map{|n|":".rjust(n, "-")}].join("|") if markdown - @results.each{|v, result| - rets = [] - first_value = nil - s = adjusted_results(v, result){|r| - if first_value - if r == 0 - rets << "Error" - else - rets << sprintf(numformat, first_value/Float(r), width[rets.size+1]) - end - else - first_value = r - end - } - v += s if s - output [v.ljust(name_width), rets].join("") - } - end - - if @opt[:output] - output - output "Log file: #{@opt[:output]}" - end + <<-YAML +prelude: | +#{magic_comment.gsub(/^/, ' ')} +benchmark: + #{name}: | +#{script.gsub(/^/, ' ')} +loop_count: 1 + YAML end def files flag = {} - @files = Dir.glob(File.join(@dir, 'bm*.rb')).map{|file| + legacy_files = Dir.glob(File.join(@dir, 'bm*.rb')) + yaml_files = Dir.glob(File.join(@dir, '*.yml')) + files = (legacy_files + yaml_files).map{|file| next if @pattern && /#{@pattern}/ !~ File.basename(file) next if @exclude && /#{@exclude}/ =~ File.basename(file) case file @@ -270,90 +80,13 @@ class BenchmarkDriver }.compact if flag['vm1'] && !flag['whileloop'] - @files << File.join(@dir, 'bm_loop_whileloop.rb') + files << File.join(@dir, 'bm_loop_whileloop.rb') elsif flag['vm2'] && !flag['whileloop2'] - @files << File.join(@dir, 'bm_loop_whileloop2.rb') + files << File.join(@dir, 'bm_loop_whileloop2.rb') end - @files.sort! - progress_message "total: #{@files.size * @repeat} trial(s) (#{@repeat} trial(s) for #{@files.size} benchmark(s))\n" - @files - end - - def run - files.each_with_index{|file, i| - @i = i - r = measure_file(file) - - if /bm_loop_whileloop.rb/ =~ file - @loop_wl1 = r[1].map{|e| e.min} - elsif /bm_loop_whileloop2.rb/ =~ file - @loop_wl2 = r[1].map{|e| e.min} - end - } - end - - def measure_file file - name = File.basename(file, '.rb').sub(/^bm_/, '') - prepare_file = File.join(File.dirname(file), "prepare_#{name}.rb") - load prepare_file if FileTest.exist?(prepare_file) - - if @verbose - output - output '-----------------------------------------------------------' - output name - output - output File.read(file) - output - end - - result = [name] - result << @execs.map{|(e, v)| - (0...@repeat).map{ - message_print "#{v}\t" - progress_message '.' - - m = measure(e, file) - message "#{m}" - m - } - } - @results << result - result - end - - unless defined?(File::NULL) - if File.exist?('/dev/null') - File::NULL = '/dev/null' - end - end - - def measure executable, file - case @measure_target - when :real, :utime, :stime, :cutime, :cstime, :total - cmd = "#{executable} #{@ruby_arg} #{file}" - m = Benchmark.measure{ - system(cmd, out: File::NULL) - } - result = m.__send__(@measure_target) - when :peak, :size - tmp = Tempfile.new("benchmark-memory-wrapper-data") - wrapper = "#{File.join(__dir__, 'memory_wrapper.rb')} #{tmp.path} #{@measure_target}" - cmd = "#{executable} #{@ruby_arg} #{wrapper} #{file}" - system(cmd, out: File::NULL) - result = tmp.read.to_i - tmp.close - else - raise "unknown measure target" - end - - if $? != 0 - raise $?.inspect if $? && $?.signaled? - output "\`#{cmd}\' exited with abnormal status (#{$?})" - 0 - else - result - end + files.sort! + files end end @@ -362,15 +95,7 @@ if __FILE__ == $0 :execs => [], :dir => File.dirname(__FILE__), :repeat => 1, - :measure_target => :real, - :output => nil, - :raw_output => nil, - :format => :tsv, - } - formats = { - :tsv => ".tsv", - :markdown => ".md", - :plain => ".txt", + :verbose => 1, } parser = OptionParser.new{|o| @@ -397,44 +122,18 @@ if __FILE__ == $0 o.on('-r', '--repeat-count [NUM]', "Repeat count"){|n| opt[:repeat] = n.to_i } - o.on('-o', '--output-file [FILE]', "Output file"){|f| - opt[:output] = f - } - o.on('--ruby-arg [ARG]', "Optional argument for ruby"){|a| - opt[:ruby_arg] = a - } - o.on('--measure-target [TARGET]', - 'real (execution time), peak, size (memory), total'){|mt| - opt[:measure_target] = mt.to_sym - } - o.on('--rawdata-output [FILE]', 'output rawdata'){|r| - opt[:rawdata_output] = r - } - o.on('--load-rawdata=FILE', 'input rawdata'){|r| - opt[:rawdata_input] = r - } - o.on('-f', "--format=FORMAT", "output format (#{formats.keys.join(",")})", formats.keys){|r| - opt[:format] = r - } o.on('-v', '--verbose'){|v| - opt[:verbose] = v + opt[:verbose] = 2 } o.on('-q', '--quiet', "Run without notify information except result table."){|q| - opt[:quiet] = q - opt[:verbose] = false + opt[:verbose] = 0 } } parser.parse!(ARGV) - if input = opt[:rawdata_input] - b = open(input) {|f| - BenchmarkDriver.load(f, File.extname(input)[1..-1], opt) - } - b.show_results - else - opt[:output] ||= "bmlog-#{Time.now.strftime('%Y%m%d-%H%M%S')}.#{$$}#{formats[opt[:format]]}" - BenchmarkDriver.benchmark(opt) + execs = opt[:execs].map { |exec| ['--executables', exec.shellsplit.join(',')] }.flatten + BenchmarkDriver.new(opt[:dir], opt).with_yamls do |yamls| + BenchmarkDriver.run(*yamls, *execs, "--verbose=#{opt[:verbose]}", "--repeat-count=#{opt[:repeat]}") end end - diff --git a/benchmark/make_fasta_output.rb b/benchmark/make_fasta_output.rb deleted file mode 100644 index b6d787ae27..0000000000 --- a/benchmark/make_fasta_output.rb +++ /dev/null @@ -1,19 +0,0 @@ -# prepare 'fasta.output' - -def prepare_fasta_output n - filebase = File.join(File.dirname($0), 'fasta.output') - script = File.join(File.dirname($0), 'bm_so_fasta.rb') - file = "#{filebase}.#{n}" - - unless FileTest.exist?(file) - STDERR.puts "preparing #{file}" - - open(file, 'w'){|f| - ARGV[0] = n - $stdout = f - load script - $stdout = STDOUT - } - end -end - diff --git a/benchmark/prepare_require.rb b/benchmark/prepare_require.rb deleted file mode 100644 index c4786f04ad..0000000000 --- a/benchmark/prepare_require.rb +++ /dev/null @@ -1,25 +0,0 @@ -require "fileutils" - -def prepare - num_files = 10000 - - basename = File.dirname($0) - data_dir = File.join(basename, "bm_require.data") - - # skip if all of files exists - if File.exist?(File.join(data_dir, "c#{num_files}.rb")) - return - end - - FileUtils.mkdir_p(data_dir) - - 1.upto(num_files) do |i| - f = File.open("#{data_dir}/c#{i}.rb", "w") - f.puts <<-END - class C#{i} - end - END - end -end - -prepare diff --git a/benchmark/prepare_require_thread.rb b/benchmark/prepare_require_thread.rb deleted file mode 100644 index 339ecb8b39..0000000000 --- a/benchmark/prepare_require_thread.rb +++ /dev/null @@ -1,2 +0,0 @@ -load File.join(File.dirname(__FILE__), "prepare_require.rb") - diff --git a/benchmark/prepare_so_count_words.rb b/benchmark/prepare_so_count_words.rb deleted file mode 100644 index ee2138cdb2..0000000000 --- a/benchmark/prepare_so_count_words.rb +++ /dev/null @@ -1,15 +0,0 @@ -# prepare 'wc.input' - -def prepare_wc_input - wcinput = File.join(File.dirname($0), 'wc.input') - wcbase = File.join(File.dirname($0), 'wc.input.base') - unless FileTest.exist?(wcinput) - data = File.read(wcbase) - 13.times{ - data << data - } - open(wcinput, 'w'){|f| f.write data} - end -end - -prepare_wc_input diff --git a/benchmark/prepare_so_k_nucleotide.rb b/benchmark/prepare_so_k_nucleotide.rb deleted file mode 100644 index d83aeb7a7e..0000000000 --- a/benchmark/prepare_so_k_nucleotide.rb +++ /dev/null @@ -1,2 +0,0 @@ -require_relative 'make_fasta_output' -prepare_fasta_output(100_000) diff --git a/benchmark/prepare_so_reverse_complement.rb b/benchmark/prepare_so_reverse_complement.rb deleted file mode 100644 index da3ec2df14..0000000000 --- a/benchmark/prepare_so_reverse_complement.rb +++ /dev/null @@ -1,2 +0,0 @@ -require_relative 'make_fasta_output' -prepare_fasta_output(2_500_000) diff --git a/benchmark/require.yml b/benchmark/require.yml new file mode 100644 index 0000000000..711d8e11e9 --- /dev/null +++ b/benchmark/require.yml @@ -0,0 +1,36 @@ +prelude: | + require "fileutils" + + def prepare + num_files = 10000 + + basename = File.dirname($0) + data_dir = File.join(basename, "bm_require.data") + + # skip if all of files exists + if File.exist?(File.join(data_dir, "c#{num_files}.rb")) + return + end + + FileUtils.mkdir_p(data_dir) + + 1.upto(num_files) do |i| + f = File.open("#{data_dir}/c#{i}.rb", "w") + f.puts <<-END + class C#{i} + end + END + end + end + + prepare +benchmark: + require: | + $:.push File.join(File.dirname(__FILE__), "bm_require.data") + + 1.upto(10000) do |i| + require "c#{i}" + end + + $:.pop +loop_count: 1 diff --git a/benchmark/require_thread.yml b/benchmark/require_thread.yml new file mode 100644 index 0000000000..87e0ba888b --- /dev/null +++ b/benchmark/require_thread.yml @@ -0,0 +1,44 @@ +prelude: | + require "fileutils" + + def prepare + num_files = 10000 + + basename = File.dirname($0) + data_dir = File.join(basename, "bm_require.data") + + # skip if all of files exists + if File.exist?(File.join(data_dir, "c#{num_files}.rb")) + return + end + + FileUtils.mkdir_p(data_dir) + + 1.upto(num_files) do |i| + f = File.open("#{data_dir}/c#{i}.rb", "w") + f.puts <<-END + class C#{i} + end + END + end + end + + prepare +benchmark: + require_thread: | + $:.push File.join(File.dirname(__FILE__), "bm_require.data") + + i=0 + t = Thread.new do + while true + i = i+1 # dummy loop + end + end + + 1.upto(100) do |i| + require "c#{i}" + end + + $:.pop + t.kill +loop_count: 1 diff --git a/benchmark/wc.input.base b/benchmark/so_count_words.yml similarity index 70% rename from benchmark/wc.input.base rename to benchmark/so_count_words.yml index 41143fbac0..d0a6c8dd3e 100644 --- a/benchmark/wc.input.base +++ b/benchmark/so_count_words.yml @@ -1,25 +1,66 @@ -Subject: Re: Who was Izchak Miller? -From: "Jane D. Anonymous" -Date: 1996/04/28 -Message-Id: <4lv7bc$oh@news.ycc.yale.edu> -References: <317C405E.5DFA@panix.com> <4lk6vl$gde@ns.oar.net> -To: 75176.2330@compuserve.com -Content-Type: text/plain; charset=us-ascii -Organization: Yale University -X-Url: news:4lk6vl$gde@ns.oar.net -Mime-Version: 1.0 -Newsgroups: rec.games.roguelike.nethack -X-Mailer: Mozilla 1.1N (Macintosh; I; 68K) +prelude: | + #!/usr/bin/ruby + # -*- mode: ruby -*- -Hello there, Izchak Miller was my father. When I was younger I spent -many a night, hunched over the keyboard with a cup of tea, playing -nethack with him and my brother. my dad was a philosopher with a strong -weakness for fantasy/sci fi. I remember when he started to get involved -with the Nethack team- my brother's Dungeons and Dragons monster book -found a regular place beside my dad's desk. it's nice to see him living -on in the game he loved so much :-). - Tamar Miller + wc_input_base = < + Date: 1996/04/28 + Message-Id: <4lv7bc$oh@news.ycc.yale.edu> + References: <317C405E.5DFA@panix.com> <4lk6vl$gde@ns.oar.net> + To: 75176.2330@compuserve.com + Content-Type: text/plain; charset=us-ascii + Organization: Yale University + X-Url: news:4lk6vl$gde@ns.oar.net + Mime-Version: 1.0 + Newsgroups: rec.games.roguelike.nethack + X-Mailer: Mozilla 1.1N (Macintosh; I; 68K) -The following is a really long word of 5000 characters: + Hello there, Izchak Miller was my father. When I was younger I spent + many a night, hunched over the keyboard with a cup of tea, playing + nethack with him and my brother. my dad was a philosopher with a strong + weakness for fantasy/sci fi. I remember when he started to get involved + with the Nethack team- my brother's Dungeons and Dragons monster book + found a regular place beside my dad's desk. it's nice to see him living + on in the game he loved so much :-). + Tamar Miller -wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww + The following is a really long word of 5000 characters: + + wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww + EOS + + # prepare 'wc.input' + + def prepare_wc_input(wcbase) + wcinput = File.join(File.dirname($0), 'wc.input') + unless FileTest.exist?(wcinput) + data = wcbase.dup + 13.times{ + data << data + } + open(wcinput, 'w'){|f| f.write data} + end + end + + prepare_wc_input(wc_input_base) + +benchmark: + so_count_words: | + # $Id: wc-ruby.code,v 1.4 2004/11/13 07:43:32 bfulgham Exp $ + # http://www.bagley.org/~doug/shootout/ + # with help from Paul Brannan + input = open(File.join(File.dirname($0), 'wc.input'), 'rb') + + nl = nw = nc = 0 + while true + tmp = input.read(4096) or break + data = tmp << (input.gets || "") + nc += data.length + nl += data.count("\n") + ((data.strip! || data).tr!("\n", " ") || data).squeeze! + nw += data.count(" ") + 1 + end + # STDERR.puts "#{nl} #{nw} #{nc}" + +loop_count: 1 diff --git a/benchmark/so_k_nucleotide.yml b/benchmark/so_k_nucleotide.yml new file mode 100644 index 0000000000..d7df086c39 --- /dev/null +++ b/benchmark/so_k_nucleotide.yml @@ -0,0 +1,155 @@ +prelude: | + bm_so_fasta = <<'EOS' + # The Computer Language Shootout + # http://shootout.alioth.debian.org/ + # Contributed by Sokolov Yura + + $last = 42.0 + def gen_random(max, im=139968, ia=3877, ic=29573) + (max * ($last = ($last * ia + ic) % im)) / im + end + + alu = + "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG"+ + "GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA"+ + "CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT"+ + "ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA"+ + "GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG"+ + "AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC"+ + "AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA" + + iub = [ + ["a", 0.27], + ["c", 0.12], + ["g", 0.12], + ["t", 0.27], + + ["B", 0.02], + ["D", 0.02], + ["H", 0.02], + ["K", 0.02], + ["M", 0.02], + ["N", 0.02], + ["R", 0.02], + ["S", 0.02], + ["V", 0.02], + ["W", 0.02], + ["Y", 0.02], + ] + homosapiens = [ + ["a", 0.3029549426680], + ["c", 0.1979883004921], + ["g", 0.1975473066391], + ["t", 0.3015094502008], + ] + + def make_repeat_fasta(id, desc, src, n) + puts ">#{id} #{desc}" + v = nil + width = 60 + l = src.length + s = src * ((n / l) + 1) + s.slice!(n, l) + puts(s.scan(/.{1,#{width}}/).join("\n")) + end + + def make_random_fasta(id, desc, table, n) + puts ">#{id} #{desc}" + rand, v = nil,nil + width = 60 + chunk = 1 * width + prob = 0.0 + table.each{|v| v[1]= (prob += v[1])} + for i in 1..(n/width) + puts((1..width).collect{ + rand = gen_random(1.0) + table.find{|v| v[1]>rand}[0] + }.join) + end + if n%width != 0 + puts((1..(n%width)).collect{ + rand = gen_random(1.0) + table.find{|v| v[1]>rand}[0] + }.join) + end + end + + + n = (ARGV[0] or 250_000).to_i + + make_repeat_fasta('ONE', 'Homo sapiens alu', alu, n*2) + make_random_fasta('TWO', 'IUB ambiguity codes', iub, n*3) + make_random_fasta('THREE', 'Homo sapiens frequency', homosapiens, n*5) + EOS +benchmark: + - name: so_k_nucleotide + prelude: | + script = File.join(File.dirname($0), 'bm_so_fasta.rb') + File.write(script, bm_so_fasta) + + def prepare_fasta_output n + filebase = File.join(File.dirname($0), 'fasta.output') + script = File.join(File.dirname($0), 'bm_so_fasta.rb') + file = "#{filebase}.#{n}" + + unless FileTest.exist?(file) + STDERR.puts "preparing #{file}" + + open(file, 'w'){|f| + ARGV[0] = n + $stdout = f + load script + $stdout = STDOUT + } + end + end + prepare_fasta_output(100_000) + script: | + # The Computer Language Shootout + # http://shootout.alioth.debian.org + # + # contributed by jose fco. gonzalez + # modified by Sokolov Yura + + seq = String.new + + def frecuency( seq,length ) + n, table = seq.length - length + 1, Hash.new(0) + f, i = nil, nil + (0 ... length).each do |f| + (f ... n).step(length) do |i| + table[seq[i,length]] += 1 + end + end + [n,table] + + end + + def sort_by_freq( seq,length ) + n,table = frecuency( seq,length ) + a, b, v = nil, nil, nil + table.sort{|a,b| b[1] <=> a[1]}.each do |v| + puts "%s %.3f" % [v[0].upcase,((v[1]*100).to_f/n)] + end + puts + end + + def find_seq( seq,s ) + n,table = frecuency( seq,s.length ) + puts "#{table[s].to_s}\t#{s.upcase}" + end + + input = open(File.join(File.dirname($0), 'fasta.output.100000'), 'rb') + + line = input.gets while line !~ /^>THREE/ + line = input.gets + + while (line !~ /^>/) & line do + seq << line.chomp + line = input.gets + end + + [1,2].each {|i| sort_by_freq( seq,i ) } + + %w(ggt ggta ggtatt ggtattttaatt ggtattttaatttatagt).each{|s| find_seq( seq,s) } + loop_count: 1 diff --git a/benchmark/so_reverse_complement.yml b/benchmark/so_reverse_complement.yml new file mode 100644 index 0000000000..de05eedfc4 --- /dev/null +++ b/benchmark/so_reverse_complement.yml @@ -0,0 +1,137 @@ +prelude: | + bm_so_fasta = <<'EOS' + # The Computer Language Shootout + # http://shootout.alioth.debian.org/ + # Contributed by Sokolov Yura + + $last = 42.0 + def gen_random(max, im=139968, ia=3877, ic=29573) + (max * ($last = ($last * ia + ic) % im)) / im + end + + alu = + "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG"+ + "GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA"+ + "CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT"+ + "ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA"+ + "GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG"+ + "AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC"+ + "AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA" + + iub = [ + ["a", 0.27], + ["c", 0.12], + ["g", 0.12], + ["t", 0.27], + + ["B", 0.02], + ["D", 0.02], + ["H", 0.02], + ["K", 0.02], + ["M", 0.02], + ["N", 0.02], + ["R", 0.02], + ["S", 0.02], + ["V", 0.02], + ["W", 0.02], + ["Y", 0.02], + ] + homosapiens = [ + ["a", 0.3029549426680], + ["c", 0.1979883004921], + ["g", 0.1975473066391], + ["t", 0.3015094502008], + ] + + def make_repeat_fasta(id, desc, src, n) + puts ">#{id} #{desc}" + v = nil + width = 60 + l = src.length + s = src * ((n / l) + 1) + s.slice!(n, l) + puts(s.scan(/.{1,#{width}}/).join("\n")) + end + + def make_random_fasta(id, desc, table, n) + puts ">#{id} #{desc}" + rand, v = nil,nil + width = 60 + chunk = 1 * width + prob = 0.0 + table.each{|v| v[1]= (prob += v[1])} + for i in 1..(n/width) + puts((1..width).collect{ + rand = gen_random(1.0) + table.find{|v| v[1]>rand}[0] + }.join) + end + if n%width != 0 + puts((1..(n%width)).collect{ + rand = gen_random(1.0) + table.find{|v| v[1]>rand}[0] + }.join) + end + end + + + n = (ARGV[0] or 250_000).to_i + + make_repeat_fasta('ONE', 'Homo sapiens alu', alu, n*2) + make_random_fasta('TWO', 'IUB ambiguity codes', iub, n*3) + make_random_fasta('THREE', 'Homo sapiens frequency', homosapiens, n*5) + EOS +benchmark: + - name: so_reverse_complement + prelude: | + script = File.join(File.dirname($0), 'bm_so_fasta.rb') + File.write(script, bm_so_fasta) + + def prepare_fasta_output n + filebase = File.join(File.dirname($0), 'fasta.output') + script = File.join(File.dirname($0), 'bm_so_fasta.rb') + file = "#{filebase}.#{n}" + + unless FileTest.exist?(file) + STDERR.puts "preparing #{file}" + + open(file, 'w'){|f| + ARGV[0] = n + $stdout = f + load script + $stdout = STDOUT + } + end + end + prepare_fasta_output(2_500_000) + script: | + # The Great Computer Language Shootout + # http://shootout.alioth.debian.org/ + # + # Contributed by Peter Bjarke Olsen + # Modified by Doug King + + seq=Array.new + + def revcomp(seq) + seq.reverse!.tr!('wsatugcyrkmbdhvnATUGCYRKMBDHVN','WSTAACGRYMKVHDBNTAACGRYMKVHDBN') + stringlen=seq.length + 0.step(stringlen-1,60) {|x| print seq.slice(x,60) , "\n"} + end + + input = open(File.join(File.dirname($0), 'fasta.output.2500000'), 'rb') + + while input.gets + if $_ =~ />/ + if seq.length != 0 + revcomp(seq.join) + seq=Array.new + end + puts $_ + else + $_.sub(/\n/,'') + seq.push $_ + end + end + revcomp(seq.join) + loop_count: 1 diff --git a/common.mk b/common.mk index 07e03bd2d5..dd1f7a7102 100644 --- a/common.mk +++ b/common.mk @@ -41,6 +41,8 @@ GEM_HOME = GEM_PATH = GEM_VENDOR = +BENCHMARK_DRIVER_GIT_URL = https://github.com/benchmark-driver/benchmark-driver +BENCHMARK_DRIVER_GIT_REF = v0.13.2 SIMPLECOV_GIT_URL = git://github.com/colszowka/simplecov.git SIMPLECOV_GIT_REF = v0.15.0 SIMPLECOV_HTML_GIT_URL = git://github.com/colszowka/simplecov-html.git @@ -1117,14 +1119,16 @@ OPTS = # for example, # $ make benchmark COMPARE_RUBY="ruby-trunk" OPTS="-e ruby-2.2.2" # This command compares trunk and built-ruby and 2.2.2 -benchmark: miniruby$(EXEEXT) PHONY - $(BASERUBY) $(srcdir)/benchmark/driver.rb -v \ - --executables="$(COMPARE_RUBY) -I$(srcdir)/lib -I. -I$(EXTOUT)/common --disable-gem; built-ruby::$(MINIRUBY) -r$(srcdir)/prelude --disable-gem" \ +benchmark: miniruby$(EXEEXT) update-benchmark-driver PHONY + $(BASERUBY) $(srcdir)/benchmark/driver.rb \ + --executables="compare-ruby::$(COMPARE_RUBY) -I$(EXTOUT)/common --disable-gem" \ + --executables="built-ruby::$(MINIRUBY) -r$(srcdir)/prelude --disable-gem" \ --pattern='bm_' --directory=$(srcdir)/benchmark $(OPTS) -benchmark-each: miniruby$(EXEEXT) PHONY - $(BASERUBY) $(srcdir)/benchmark/driver.rb -v \ - --executables="$(COMPARE_RUBY) -I$(srcdir)/lib -I. -I$(EXTOUT)/common --disable-gem; built-ruby::$(MINIRUBY) -r$(srcdir)/prelude --disable-gem" \ +benchmark-each: miniruby$(EXEEXT) update-benchmark-driver PHONY + $(BASERUBY) $(srcdir)/benchmark/driver.rb \ + --executables="compare-ruby::$(COMPARE_RUBY) -I$(EXTOUT)/common --disable-gem" \ + --executables="built-ruby::$(MINIRUBY) -r$(srcdir)/prelude --disable-gem" \ --pattern=$(ITEM) --directory=$(srcdir)/benchmark $(OPTS) run.gdb: diff --git a/win32/Makefile.sub b/win32/Makefile.sub index 20b47a581a..3c9fc07648 100644 --- a/win32/Makefile.sub +++ b/win32/Makefile.sub @@ -1182,6 +1182,10 @@ test-bundled-gems-run: exit /b %STATUS% \ ) +update-benchmark-driver: + $(GIT) clone https://github.com/benchmark-driver/benchmark-driver $(srcdir)/benchmark/benchmark-driver || \ + $(GIT) -C $(srcdir)/benchmark/benchmark-driver pull origin master + $(ruby_pc): $(RBCONFIG) @$(BOOTSTRAPRUBY) $(srcdir)/tool/expand-config.rb \ -output=$@ -mode=$(INSTALL_DATA_MODE) -config=rbconfig.rb \