bench.rb 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. #!/usr/bin/env ruby
  2. ###
  3. ### $Release: 2.7.0 $
  4. ### copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
  5. ###
  6. require 'erb'
  7. require 'erubis'
  8. require 'erubis/tiny'
  9. require 'erubis/engine/enhanced'
  10. require 'yaml'
  11. require 'cgi'
  12. include ERB::Util
  13. begin
  14. require 'eruby'
  15. rescue LoadError
  16. ERuby = nil
  17. end
  18. def File.write(filename, content)
  19. File.open(filename, 'w') { |f| f.write(content) }
  20. end
  21. ## change benchmark library to use $stderr instead of $stdout
  22. require 'benchmark'
  23. module Benchmark
  24. class Report
  25. def print(*args)
  26. $stderr.print(*args)
  27. end
  28. end
  29. module_function
  30. def print(*args)
  31. $stderr.print(*args)
  32. end
  33. end
  34. class BenchmarkApplication
  35. TARGETS = %w[eruby
  36. ERB ERB(cached)
  37. Erubis::Eruby Erubis::Eruby(cached)
  38. Erubis::FastEruby Erubis::FastEruby(cached)
  39. Erubis::TinyEruby
  40. Erubis::ArrayBufferEruby
  41. Erubis::PrintOutEruby
  42. Erubis::StdoutEruby
  43. ]
  44. def initialize(ntimes, context, targets=nil, params={})
  45. @ntimes = ntimes
  46. @context = context
  47. @targets = targets && !targets.empty? ? targets : TARGETS.dup
  48. @testmode = params[:testmode] || 'execute'
  49. @erubyfile = params[:erubyfile] || 'erubybench.rhtml'
  50. @printout = params[:printout] || false
  51. end
  52. attr_accessor :ntimes, :targets
  53. attr_accessor :testmode, :erubyfile, :contextfile, :printout
  54. def context2code(context, varname='context')
  55. s = ''
  56. context.each { |k, | s << "#{k} = #{varname}[#{k.inspect}]; " }
  57. return s
  58. end
  59. def perform_benchmark
  60. width = 30
  61. $stderr.puts "*** ntimes=#{@ntimes}, testmode=#{@testmode}"
  62. Benchmark.bm(width) do |job|
  63. for target in @targets do
  64. method = "#{@testmode}_#{target.gsub(/::|-|\(/, '_').gsub(/\)/, '').downcase}"
  65. #$stderr.puts "*** debug: method=#{method.inspect}"
  66. next unless self.respond_to?(method)
  67. filename = "bench_#{(target =~ /^(\w+)/) && $1.downcase}.rhtml"
  68. title = target
  69. output = nil
  70. job.report(title) do
  71. output = self.__send__(method, filename, @context)
  72. end
  73. File.write("output.#{target.gsub(/[^\w]/,'')}", output) if @printout && output && !output.empty?
  74. end
  75. end
  76. end
  77. ##
  78. def execute_eruby(filename, context)
  79. return unless ERuby
  80. #eval context2code(context)
  81. list = context['list']
  82. @ntimes.times do
  83. ERuby.import(filename)
  84. end
  85. return nil
  86. end
  87. def execute_erb(filename, context)
  88. #eval context2code(context)
  89. list = context['list']
  90. output = nil
  91. @ntimes.times do
  92. eruby = ERB.new(File.read(filename))
  93. output = eruby.result(binding())
  94. print output
  95. end
  96. return output
  97. end
  98. def execute_erb_cached(filename, context)
  99. #eval context2code(context)
  100. list = context['list']
  101. output = nil
  102. cachefile = filename + '.cache'
  103. File.unlink(cachefile) if test(?f, cachefile)
  104. @ntimes.times do
  105. if !test(?f, cachefile) || File.mtime(filename) > File.mtime(cachefile)
  106. eruby = ERB.new(File.read(filename))
  107. File.write(cachefile, eruby.src)
  108. else
  109. eruby = ERB.new('')
  110. #eruby.src = File.read(cachefile)
  111. eruby.instance_variable_set("@src", File.read(cachefile))
  112. end
  113. output = eruby.result(binding())
  114. print output
  115. end
  116. return output
  117. end
  118. ## no cached
  119. for klass in %w[Eruby FastEruby TinyEruby ArrayBufferEruby PrintOutEruby StdoutEruby] do
  120. s = <<-END
  121. def execute_erubis_#{klass.downcase}(filename, context)
  122. #eval context2code(context)
  123. list = context['list']
  124. output = nil
  125. @ntimes.times do
  126. eruby = Erubis::#{klass}.new(File.read(filename))
  127. output = eruby.result(binding())
  128. print output
  129. end
  130. return output
  131. end
  132. END
  133. eval s
  134. end
  135. ## cached
  136. for klass in %w[Eruby FastEruby] do
  137. s = <<-END
  138. def execute_erubis_#{klass.downcase}_cached(filename, context)
  139. #eval context2code(context)
  140. list = context['list']
  141. cachefile = filename + '.cache'
  142. File.unlink(cachefile) if test(?f, cachefile)
  143. output = nil
  144. @ntimes.times do
  145. eruby = Erubis::#{klass}.load_file(filename)
  146. output = eruby.result(binding())
  147. print output
  148. end
  149. savefile = cachefile.sub(/\\.cache$/, '.#{klass.downcase}.cache')
  150. File.rename(cachefile, savefile)
  151. return output
  152. end
  153. END
  154. eval s
  155. end
  156. ##
  157. def convert_eruby(filename, context)
  158. return unless ERuby
  159. #eval context2code(context)
  160. list = context['list']
  161. output = nil
  162. @ntimes.times do
  163. output = ERuby::Compiler.new.compile_string(File.read(filename))
  164. end
  165. return output
  166. end
  167. def convert_erb(filename, context)
  168. #eval context2code(context)
  169. list = context['list']
  170. output = nil
  171. @ntimes.times do
  172. eruby = ERB.new(File.read(filename))
  173. output = eruby.src
  174. end
  175. return output
  176. end
  177. for klass in %w[Eruby FastEruby TinyEruby]
  178. s = <<-END
  179. def convert_erubis_#{klass.downcase}(filename, context)
  180. #eval context2code(context)
  181. list = context['list']
  182. output = nil
  183. @ntimes.times do
  184. eruby = Erubis::#{klass}.new(File.read(filename))
  185. output = eruby.src
  186. end
  187. return output
  188. end
  189. END
  190. eval s
  191. end
  192. end
  193. require 'optparse'
  194. class MainApplication
  195. def parse_argv(argv=ARGV)
  196. optparser = OptionParser.new
  197. options = {}
  198. ['-h', '-n N', '-t erubyfile', '-f contextfile', '-A', '-e',
  199. '-x exclude', '-m testmode', '-X', '-p', '-D'].each do |opt|
  200. optparser.on(opt) { |val| options[opt[1].chr] = val }
  201. end
  202. begin
  203. targets = optparser.parse!(argv)
  204. rescue => ex
  205. $stderr.puts "#{@script}: #{ex.to_s}"
  206. exit(1)
  207. end
  208. return options, targets
  209. end
  210. def execute
  211. @script = File.basename($0)
  212. ntimes = 1000
  213. targets = BenchmarkApplication::TARGETS.dup
  214. testmode = 'execute'
  215. contextfile = 'bench_context.yaml'
  216. #
  217. options, args = parse_argv(ARGV)
  218. ntimes = options['n'].to_i if options['n']
  219. targets = args if args && !args.empty?
  220. targets = targets - options['x'].split(/,/) if options['x']
  221. testmode = options['m'] if options['m']
  222. contextfile = options['f'] if options['f']
  223. erubyfile = options['t'] if options['t']
  224. #
  225. if options['h']
  226. $stderr.puts "Usage: ruby #{@script} [..options..] [..targets..]"
  227. $stderr.puts " -h : help"
  228. $stderr.puts " -n N : loop N times"
  229. $stderr.puts " -f datafile : context data filename (*.yaml)"
  230. $stderr.puts " -x exclude : exclude target name"
  231. $stdout.puts " -m testmode : 'execute' or 'convert' (default 'execute')"
  232. $stderr.puts " -p : print output to file (filename: 'output.TARGETNAME')"
  233. return
  234. end
  235. #
  236. #if ! options['t']
  237. for item in %w[eruby erb erubis]
  238. fname = "bench_#{item}.rhtml"
  239. header = File.read("templates/_header.html")
  240. #body = File.read("templates/#{erubyfile}")
  241. body = File.read("templates/#{fname}")
  242. footer = File.read("templates/_footer.html")
  243. content = header + body + footer
  244. File.write(fname, content)
  245. end
  246. #
  247. if options['e'] # escape
  248. tuples = [
  249. [ 'bench_eruby.rhtml', '<%= CGI.escapeHTML((\1).to_s) %>' ],
  250. [ 'bench_erb.rhtml', '<%=h \1 %>' ],
  251. [ 'bench_erubis.rhtml', '<%== \1 %>' ],
  252. ]
  253. for fname, replace in tuples
  254. content = File.read(fname).gsub(/<%= ?(.*?) ?%>/, replace)
  255. File.write(fname, content)
  256. end
  257. targets.delete('Erubis::TinyEruby') ## because TinyEruby doesn't support '<%== =>'
  258. end
  259. #
  260. context = YAML.load_file(contextfile)
  261. #
  262. params = {
  263. :printout=>options['p'],
  264. :testmode=>testmode,
  265. }
  266. app = BenchmarkApplication.new(ntimes, context, targets, params)
  267. app.perform_benchmark()
  268. end
  269. end
  270. if __FILE__ == $0
  271. ## open /dev/null
  272. $stdout = File.open('/dev/null', 'w')
  273. at_exit do
  274. $stdout.close()
  275. end
  276. ## start benchmark
  277. MainApplication.new().execute()
  278. end