SlideShare a Scribd company logo
tDiary Anniversary Party
High Performance tDiary
tDiary は遅い
stackprof
tDiary endpoint for stackprof
index.rb
(snip)
if encoding_error.empty?
@cgi = cgi
else
@cgi = CGI::new(accept_charset: 'shift_jis')
@cgi.params = cgi.params
end
request = TDiary::Request.new( ENV, @cgi )
status, headers, body = TDiary::Dispatcher.index.dispatch_cgi( request, @cgi )
TDiary::Dispatcher.send_headers( status, headers )
::Rack::Handler::CGI.send_body(body)
(snip)
tDiary endpoint for stackprof
index.rb
(snip)
if encoding_error.empty?
@cgi = cgi
else
@cgi = CGI::new(accept_charset: 'shift_jis')
@cgi.params = cgi.params
end
request = TDiary::Request.new( ENV, @cgi )
status = headers = body = nil
StackProf.run(mode: :cpu, out: “path/to/stackprof-cpu-#{Time.now.to_i}.dump”) do
status, headers, body = TDiary::Dispatcher.index.dispatch_cgi( request, @cgi )
end
TDiary::Dispatcher.send_headers( status, headers )
::Rack::Handler::CGI.send_body(body)
(snip)
StackProf results
==================================
Mode: cpu(1000)
Samples: 36989 (6.05% miss rate)
GC: 5689 (15.38%)
==================================
TOTAL (pct) SAMPLES (pct) FRAME
3293 (8.9%) 3290 (8.9%) Dalli::Server#deserialize
1497 (4.0%) 1497 (4.0%) block (2 levels) in TDiary::IO::Default#calendar
2733 (7.4%) 1371 (3.7%) REXML::Attributes#get_attribute
2549 (6.9%) 1145 (3.1%) REXML::Parsers::BaseParser#pull_event
2532 (6.8%) 931 (2.5%) ERB::Compiler::SimpleScanner2#scan
1861 (5.0%) 928 (2.5%) REXML::Element#root
1601 (4.3%) 865 (2.3%) block in ERB::Compiler#compile
838 (2.3%) 838 (2.3%) block in REXML::Document#doctype
8633 (23.3%) 619 (1.7%) REXML::Element#namespace
603 (1.6%) 603 (1.6%) REXML::Source#match
612 (1.7%) 594 (1.6%) block in TDiary::Plugin#load_plugin
5071 (13.7%) 579 (1.6%) TDiary::IO::Default#transaction
739 (2.0%) 572 (1.5%) CGI::Util#unescape
564 (1.5%) 535 (1.4%) REXML::Text.check
(snip)
Dalli::Server#deserialize
memcached サーバーに cache を保存するやつ
サーバー1台だと不要なので File + PStore に戻す
REXML::*
amazon.rb や flickr.rb の response をパース
native extension の Oga に書き換える
benchmark-ips
benchmark-ips
require 'benchmark/ips'
Benchmark.ips do |x|
xml = File.read('../spec/fixtures/jpB00H91KK26.xml')
require_relative '../misc/plugin/amazon'
x.report('rexml') do
item = AmazonItem.new(xml)
amazon_detail_html( item )
end
x.report('oga') do
require 'oga'
item = AmazonItem.new(xml, :oga)
amazon_detail_html(item)
end
end
Results of Improvement
% ruby benchmark_amazon_plugin.rb
Warming up --------------------------------------
rexml 2.000 i/100ms
oga 14.000 i/100ms
Calculating -------------------------------------
rexml 37.678 (±15.9%) i/s - 182.000 in 5.013022s
oga 159.203 (±13.2%) i/s - 784.000 in 5.034065s
4.2 times faster!!1
Migration strategy for REXML and Oga
class AmazonItem
def initialize(xml, parser = :rexml)
@parser = parser
if parser == :oga
doc = Oga.parse_xml(xml)
@item = doc.xpath('*/*/Item')[0]
else
doc = REXML::Document::new( REXML::Source::new( xml ) ).root
@item = doc.elements.to_a( '*/Item' )[0]
end
end
def nodes(path)
if @parser == :oga
@item.xpath(path)
else
@item.elements.to_a(path)
end
end
end
IO::Default#calendar
日記データをすべて参照して月のリストを作るメソッ
ド、リクエストの度に毎回呼ばれている
tDiary のテストのしにくさよ…
ひたすら stub/mock module を用意する
class DummyTDiary
attr_accessor :conf
def initialize
@conf = DummyConf.new
@conf.data_path = TDiary.root + "/tmp/"
end
def ignore_parser_cache
false
end
end
class DummyConf
attr_accessor :data_path
def cache_path
TDiary.root + "/tmp/cache"
end
def options
{}
end
def style
"wiki"
end
end
module TDiary
PATH = File::dirname( __FILE__ ).untaint
class << self
def root
File.expand_path(File.join(library_root, '..'))
end
def library_root
File.expand_path('..', __FILE__)
end
def server_root
Dir.pwd.untaint
end
end
end
benchmark-ips(2)
conf = DummyConf.new
conf.data_path = TDiary.root + '/tmp/data/'
diary = DummyTDiary.new
diary.conf = conf
io = TDiary::IO::Default.new(diary)
require 'benchmark/ips'
Benchmark.ips do |x|
x.report('calendar') do
io.calendar
end
x.report('calendar2') do
io.calendar2
end
end
Improvement for calendar
def calendar
calendar = {}
Dir["#{@data_path}????"].sort.each do |dir|
next unless %r[/d{4}$] =~ dir
Dir["#{dir.untaint}/??????.td2"].sort.each do |file|
year, month = file.scan( %r[/(d{4})(dd).td2$] )[0]
next unless year
calendar[year] = [] unless calendar[year]
calendar[year] << month
end
end
calendar
end def calendar2
calendar = {}
Dir["#{@data_path}????/??????.td2"].sort.each do |file|
if file =~ /(d{4})(d{2}).td2$/
calendar[$1] = [] unless calendar[$1]
calendar[$1] << $2
end
end
calendar
end
benchmark-ips
% ruby benchmark_io_default.rb
Warming up --------------------------------------
calendar 16.000 i/100ms
calendar2 22.000 i/100ms
Calculating -------------------------------------
calendar 195.073 (±14.9%) i/s - 960.000 in 5.070197s
calendar2 237.695 (±13.9%) i/s - 1.166k in 5.039136s
1.21 times faster!!1
Results and Conclusion
StackProf results(2)
==================================
Mode: cpu(1000)
Samples: 15391 (14.55% miss rate)
GC: 2682 (17.43%)
==================================
TOTAL (pct) SAMPLES (pct) FRAME
43760 (284.3%) 3371 (21.9%) TDiary::Plugin#load_plugin
1014 (6.6%) 1014 (6.6%) PStore#load
487 (3.2%) 487 (3.2%) <module:Flickr>
445 (2.9%) 445 (2.9%) TDiary::Configuration#[]
768 (5.0%) 384 (2.5%) TDiary::IO::Default#calendar
374 (2.4%) 374 (2.4%) CGI::Util#unescape
614 (4.0%) 339 (2.2%) TDiary::RefererManager#add_referer
335 (2.2%) 335 (2.2%) TDiary::Plugin#add_header_proc
293 (1.9%) 293 (1.9%) <module:Category>
1798 (11.7%) 276 (1.8%) Kernel#open
224 (1.5%) 224 (1.5%) TDiary::Plugin#enable_js
220 (1.4%) 220 (1.4%) TDiary::Plugin#add_conf_proc
1620 (10.5%) 212 (1.4%) TDiary::IO::Default#transaction
1213 (7.9%) 199 (1.3%) PStore#load_data
(snip)
速くなったかな…
CGI::Util.unescape
Ruby 2.4.0 で nobu が C ext で書き換えたので速くな
る。2.2/2.3 向けに gem にバックポートしてもいいか
も。
flickr プラグイン
amazon プラグイン同様に REXML が遅いので Oga に
書き換える予定
TDiary::Plugin#load_plugin
プラグインを全部読み込んで eval してるアレ…
プラグイン機構を変えるとかして速くしたいなあ…
まずは eval の仕組みを利用すれば速くできそう
→プラグインを File.read する度に eval するのではな
く全てを File.read して繋げてから eval すると速そう
速かった
Warming up --------------------------------------
multi-eval 283.000 i/100ms
single-eval 565.000 i/100ms
Calculating -------------------------------------
multi-eval 2.918k (±14.8%) i/s - 14.433k in 5.100649s
single-eval 5.444k (±18.5%) i/s - 25.990k in 5.015969s
Benchmark.ips do |x|
o = Object.new
x.report('multi-eval') do
o.instance_eval("def a; puts 'a'; end")
(snip)
o.instance_eval("def z; puts 'z'; end")
end
x.report('single-eval') do
o.instance_eval("def a; puts 'a'; end; (snip) def z; puts 'z'; end")
end
end
tDiary 楽しい!!1
15年やってもまだまだ hack しがいがある!!1

More Related Content

PDF
Practical Testing of Ruby Core
PDF
The worst Ruby codes I’ve seen in my life - RubyKaigi 2015
PDF
Practical ngx_mruby
PDF
node ffi
PDF
Interceptors: Into the Core of Pedestal
PDF
Using ngx_lua in UPYUN
ZIP
AnyMQ, Hippie, and the real-time web
Practical Testing of Ruby Core
The worst Ruby codes I’ve seen in my life - RubyKaigi 2015
Practical ngx_mruby
node ffi
Interceptors: Into the Core of Pedestal
Using ngx_lua in UPYUN
AnyMQ, Hippie, and the real-time web

What's hot (20)

PDF
RestMQ - HTTP/Redis based Message Queue
PDF
PL/Perl - New Features in PostgreSQL 9.0
PDF
Lightweight wrapper for Hive on Amazon EMR
PDF
Gemification plan of Standard Library on Ruby
PDF
Perl at SkyCon'12
PDF
Nodejs - A quick tour (v6)
PPT
Working with databases in Perl
PDF
Hacking with ruby2ruby
PDF
Roll Your Own API Management Platform with nginx and Lua
PDF
服务框架: Thrift & PasteScript
KEY
Python在豆瓣的应用
PDF
Middleware as Code with mruby
PDF
Lua tech talk
PPTX
DevOps with Fabric
PDF
Application Logging in the 21st century - 2014.key
PDF
Perl Memory Use - LPW2013
PDF
Python高级编程(二)
PPTX
PSGI and Plack from first principles
PDF
Devinsampa nginx-scripting
PPT
On UnQLite
RestMQ - HTTP/Redis based Message Queue
PL/Perl - New Features in PostgreSQL 9.0
Lightweight wrapper for Hive on Amazon EMR
Gemification plan of Standard Library on Ruby
Perl at SkyCon'12
Nodejs - A quick tour (v6)
Working with databases in Perl
Hacking with ruby2ruby
Roll Your Own API Management Platform with nginx and Lua
服务框架: Thrift & PasteScript
Python在豆瓣的应用
Middleware as Code with mruby
Lua tech talk
DevOps with Fabric
Application Logging in the 21st century - 2014.key
Perl Memory Use - LPW2013
Python高级编程(二)
PSGI and Plack from first principles
Devinsampa nginx-scripting
On UnQLite
Ad

Viewers also liked (13)

PDF
How to Begin Developing Ruby Core
PDF
Middleware as Code with mruby
PDF
GitHub Enterprise with GMO Pepabo
PDF
Large-scaled Deploy Over 100 Servers in 3 Minutes
PDF
How DSL works on Ruby
PDF
How to test code with mruby
PDF
How to Begin to Develop Ruby Core
PDF
成長を加速する minne の技術基盤戦略
PDF
mruby で mackerel のプラグインを作るはなし
PDF
The story of language development
PDF
Advanced technic for OS upgrading in 3 minutes
PDF
Usecase examples of Packer
PDF
技術的負債との付き合い方
How to Begin Developing Ruby Core
Middleware as Code with mruby
GitHub Enterprise with GMO Pepabo
Large-scaled Deploy Over 100 Servers in 3 Minutes
How DSL works on Ruby
How to test code with mruby
How to Begin to Develop Ruby Core
成長を加速する minne の技術基盤戦略
mruby で mackerel のプラグインを作るはなし
The story of language development
Advanced technic for OS upgrading in 3 minutes
Usecase examples of Packer
技術的負債との付き合い方
Ad

Similar to High Performance tDiary (20)

PDF
All I Need to Know I Learned by Writing My Own Web Framework
PDF
SparkR - Play Spark Using R (20160909 HadoopCon)
PDF
Fluentd unified logging layer
PDF
Building Testable PHP Applications
PPTX
Improving go-git performance
KEY
Railsconf2011 deployment tips_for_slideshare
PDF
Design Summit - Rails 4 Migration - Aaron Patterson
PPTX
Drupal 8 migrate!
PDF
파이썬 개발환경 구성하기의 끝판왕 - Docker Compose
PDF
Drupal 7 database api
PDF
DataMapper
PDF
Perl web frameworks
PDF
Curscatalyst
PDF
Architecting Alive Apps
PDF
Advanced symfony Techniques
PDF
Debugging of (C)Python applications
PDF
Perforce Object and Record Model
PPTX
Keeping Spark on Track: Productionizing Spark for ETL
PPT
Oracle database - Get external data via HTTP, FTP and Web Services
PDF
Building Lithium Apps
All I Need to Know I Learned by Writing My Own Web Framework
SparkR - Play Spark Using R (20160909 HadoopCon)
Fluentd unified logging layer
Building Testable PHP Applications
Improving go-git performance
Railsconf2011 deployment tips_for_slideshare
Design Summit - Rails 4 Migration - Aaron Patterson
Drupal 8 migrate!
파이썬 개발환경 구성하기의 끝판왕 - Docker Compose
Drupal 7 database api
DataMapper
Perl web frameworks
Curscatalyst
Architecting Alive Apps
Advanced symfony Techniques
Debugging of (C)Python applications
Perforce Object and Record Model
Keeping Spark on Track: Productionizing Spark for ETL
Oracle database - Get external data via HTTP, FTP and Web Services
Building Lithium Apps

More from Hiroshi SHIBATA (20)

PDF
Introduction of Cybersecurity with Ruby at RedDotRubyConf 2024
PDF
Introduction of Cybersecurity with OSS at Code Europe 2024
PDF
Long journey of Ruby Standard library at RubyKaigi 2024
PDF
Long journey of Ruby standard library at RubyConf AU 2024
PDF
Deep dive into Ruby's require - RubyConf Taiwan 2023
PDF
How resolve Gem dependencies in your code?
PDF
How resolve Gem dependencies in your code?
PDF
Ruby コミッターと歩む Ruby を用いたプロダクト開発
PDF
Why ANDPAD commit Ruby and RubyKaigi?
PDF
RailsGirls から始める エンジニアリングはじめの一歩
PDF
How to develop the Standard Libraries of Ruby?
PDF
The details of CI/CD environment for Ruby
PDF
Dependency Resolution with Standard Libraries
PDF
Roadmap for RubyGems 4 and Bundler 3
PDF
The Future of library dependency management of Ruby
PDF
Ruby Security the Hard Way
PDF
OSS Security the hard way
PDF
The Future of library dependency manageement of Ruby
PDF
The Future of Dependency Management for Ruby
PDF
The Future of Bundled Bundler
Introduction of Cybersecurity with Ruby at RedDotRubyConf 2024
Introduction of Cybersecurity with OSS at Code Europe 2024
Long journey of Ruby Standard library at RubyKaigi 2024
Long journey of Ruby standard library at RubyConf AU 2024
Deep dive into Ruby's require - RubyConf Taiwan 2023
How resolve Gem dependencies in your code?
How resolve Gem dependencies in your code?
Ruby コミッターと歩む Ruby を用いたプロダクト開発
Why ANDPAD commit Ruby and RubyKaigi?
RailsGirls から始める エンジニアリングはじめの一歩
How to develop the Standard Libraries of Ruby?
The details of CI/CD environment for Ruby
Dependency Resolution with Standard Libraries
Roadmap for RubyGems 4 and Bundler 3
The Future of library dependency management of Ruby
Ruby Security the Hard Way
OSS Security the hard way
The Future of library dependency manageement of Ruby
The Future of Dependency Management for Ruby
The Future of Bundled Bundler

Recently uploaded (20)

PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PDF
cuic standard and advanced reporting.pdf
DOCX
The AUB Centre for AI in Media Proposal.docx
PPTX
Cloud computing and distributed systems.
PDF
NewMind AI Monthly Chronicles - July 2025
PDF
Empathic Computing: Creating Shared Understanding
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
Advanced Soft Computing BINUS July 2025.pdf
PDF
Electronic commerce courselecture one. Pdf
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PPTX
breach-and-attack-simulation-cybersecurity-india-chennai-defenderrabbit-2025....
PDF
Modernizing your data center with Dell and AMD
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PDF
solutions_manual_-_materials___processing_in_manufacturing__demargo_.pdf
PDF
GamePlan Trading System Review: Professional Trader's Honest Take
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
cuic standard and advanced reporting.pdf
The AUB Centre for AI in Media Proposal.docx
Cloud computing and distributed systems.
NewMind AI Monthly Chronicles - July 2025
Empathic Computing: Creating Shared Understanding
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
Reach Out and Touch Someone: Haptics and Empathic Computing
Mobile App Security Testing_ A Comprehensive Guide.pdf
Advanced Soft Computing BINUS July 2025.pdf
Electronic commerce courselecture one. Pdf
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
breach-and-attack-simulation-cybersecurity-india-chennai-defenderrabbit-2025....
Modernizing your data center with Dell and AMD
The Rise and Fall of 3GPP – Time for a Sabbatical?
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
solutions_manual_-_materials___processing_in_manufacturing__demargo_.pdf
GamePlan Trading System Review: Professional Trader's Honest Take

High Performance tDiary

  • 1. tDiary Anniversary Party High Performance tDiary
  • 4. tDiary endpoint for stackprof index.rb (snip) if encoding_error.empty? @cgi = cgi else @cgi = CGI::new(accept_charset: 'shift_jis') @cgi.params = cgi.params end request = TDiary::Request.new( ENV, @cgi ) status, headers, body = TDiary::Dispatcher.index.dispatch_cgi( request, @cgi ) TDiary::Dispatcher.send_headers( status, headers ) ::Rack::Handler::CGI.send_body(body) (snip)
  • 5. tDiary endpoint for stackprof index.rb (snip) if encoding_error.empty? @cgi = cgi else @cgi = CGI::new(accept_charset: 'shift_jis') @cgi.params = cgi.params end request = TDiary::Request.new( ENV, @cgi ) status = headers = body = nil StackProf.run(mode: :cpu, out: “path/to/stackprof-cpu-#{Time.now.to_i}.dump”) do status, headers, body = TDiary::Dispatcher.index.dispatch_cgi( request, @cgi ) end TDiary::Dispatcher.send_headers( status, headers ) ::Rack::Handler::CGI.send_body(body) (snip)
  • 6. StackProf results ================================== Mode: cpu(1000) Samples: 36989 (6.05% miss rate) GC: 5689 (15.38%) ================================== TOTAL (pct) SAMPLES (pct) FRAME 3293 (8.9%) 3290 (8.9%) Dalli::Server#deserialize 1497 (4.0%) 1497 (4.0%) block (2 levels) in TDiary::IO::Default#calendar 2733 (7.4%) 1371 (3.7%) REXML::Attributes#get_attribute 2549 (6.9%) 1145 (3.1%) REXML::Parsers::BaseParser#pull_event 2532 (6.8%) 931 (2.5%) ERB::Compiler::SimpleScanner2#scan 1861 (5.0%) 928 (2.5%) REXML::Element#root 1601 (4.3%) 865 (2.3%) block in ERB::Compiler#compile 838 (2.3%) 838 (2.3%) block in REXML::Document#doctype 8633 (23.3%) 619 (1.7%) REXML::Element#namespace 603 (1.6%) 603 (1.6%) REXML::Source#match 612 (1.7%) 594 (1.6%) block in TDiary::Plugin#load_plugin 5071 (13.7%) 579 (1.6%) TDiary::IO::Default#transaction 739 (2.0%) 572 (1.5%) CGI::Util#unescape 564 (1.5%) 535 (1.4%) REXML::Text.check (snip)
  • 7. Dalli::Server#deserialize memcached サーバーに cache を保存するやつ サーバー1台だと不要なので File + PStore に戻す
  • 8. REXML::* amazon.rb や flickr.rb の response をパース native extension の Oga に書き換える
  • 10. benchmark-ips require 'benchmark/ips' Benchmark.ips do |x| xml = File.read('../spec/fixtures/jpB00H91KK26.xml') require_relative '../misc/plugin/amazon' x.report('rexml') do item = AmazonItem.new(xml) amazon_detail_html( item ) end x.report('oga') do require 'oga' item = AmazonItem.new(xml, :oga) amazon_detail_html(item) end end
  • 11. Results of Improvement % ruby benchmark_amazon_plugin.rb Warming up -------------------------------------- rexml 2.000 i/100ms oga 14.000 i/100ms Calculating ------------------------------------- rexml 37.678 (±15.9%) i/s - 182.000 in 5.013022s oga 159.203 (±13.2%) i/s - 784.000 in 5.034065s 4.2 times faster!!1
  • 12. Migration strategy for REXML and Oga class AmazonItem def initialize(xml, parser = :rexml) @parser = parser if parser == :oga doc = Oga.parse_xml(xml) @item = doc.xpath('*/*/Item')[0] else doc = REXML::Document::new( REXML::Source::new( xml ) ).root @item = doc.elements.to_a( '*/Item' )[0] end end def nodes(path) if @parser == :oga @item.xpath(path) else @item.elements.to_a(path) end end end
  • 14. tDiary のテストのしにくさよ… ひたすら stub/mock module を用意する class DummyTDiary attr_accessor :conf def initialize @conf = DummyConf.new @conf.data_path = TDiary.root + "/tmp/" end def ignore_parser_cache false end end class DummyConf attr_accessor :data_path def cache_path TDiary.root + "/tmp/cache" end def options {} end def style "wiki" end end module TDiary PATH = File::dirname( __FILE__ ).untaint class << self def root File.expand_path(File.join(library_root, '..')) end def library_root File.expand_path('..', __FILE__) end def server_root Dir.pwd.untaint end end end
  • 15. benchmark-ips(2) conf = DummyConf.new conf.data_path = TDiary.root + '/tmp/data/' diary = DummyTDiary.new diary.conf = conf io = TDiary::IO::Default.new(diary) require 'benchmark/ips' Benchmark.ips do |x| x.report('calendar') do io.calendar end x.report('calendar2') do io.calendar2 end end
  • 16. Improvement for calendar def calendar calendar = {} Dir["#{@data_path}????"].sort.each do |dir| next unless %r[/d{4}$] =~ dir Dir["#{dir.untaint}/??????.td2"].sort.each do |file| year, month = file.scan( %r[/(d{4})(dd).td2$] )[0] next unless year calendar[year] = [] unless calendar[year] calendar[year] << month end end calendar end def calendar2 calendar = {} Dir["#{@data_path}????/??????.td2"].sort.each do |file| if file =~ /(d{4})(d{2}).td2$/ calendar[$1] = [] unless calendar[$1] calendar[$1] << $2 end end calendar end
  • 17. benchmark-ips % ruby benchmark_io_default.rb Warming up -------------------------------------- calendar 16.000 i/100ms calendar2 22.000 i/100ms Calculating ------------------------------------- calendar 195.073 (±14.9%) i/s - 960.000 in 5.070197s calendar2 237.695 (±13.9%) i/s - 1.166k in 5.039136s 1.21 times faster!!1
  • 19. StackProf results(2) ================================== Mode: cpu(1000) Samples: 15391 (14.55% miss rate) GC: 2682 (17.43%) ================================== TOTAL (pct) SAMPLES (pct) FRAME 43760 (284.3%) 3371 (21.9%) TDiary::Plugin#load_plugin 1014 (6.6%) 1014 (6.6%) PStore#load 487 (3.2%) 487 (3.2%) <module:Flickr> 445 (2.9%) 445 (2.9%) TDiary::Configuration#[] 768 (5.0%) 384 (2.5%) TDiary::IO::Default#calendar 374 (2.4%) 374 (2.4%) CGI::Util#unescape 614 (4.0%) 339 (2.2%) TDiary::RefererManager#add_referer 335 (2.2%) 335 (2.2%) TDiary::Plugin#add_header_proc 293 (1.9%) 293 (1.9%) <module:Category> 1798 (11.7%) 276 (1.8%) Kernel#open 224 (1.5%) 224 (1.5%) TDiary::Plugin#enable_js 220 (1.4%) 220 (1.4%) TDiary::Plugin#add_conf_proc 1620 (10.5%) 212 (1.4%) TDiary::IO::Default#transaction 1213 (7.9%) 199 (1.3%) PStore#load_data (snip)
  • 21. CGI::Util.unescape Ruby 2.4.0 で nobu が C ext で書き換えたので速くな る。2.2/2.3 向けに gem にバックポートしてもいいか も。
  • 22. flickr プラグイン amazon プラグイン同様に REXML が遅いので Oga に 書き換える予定
  • 23. TDiary::Plugin#load_plugin プラグインを全部読み込んで eval してるアレ… プラグイン機構を変えるとかして速くしたいなあ… まずは eval の仕組みを利用すれば速くできそう →プラグインを File.read する度に eval するのではな く全てを File.read して繋げてから eval すると速そう
  • 24. 速かった Warming up -------------------------------------- multi-eval 283.000 i/100ms single-eval 565.000 i/100ms Calculating ------------------------------------- multi-eval 2.918k (±14.8%) i/s - 14.433k in 5.100649s single-eval 5.444k (±18.5%) i/s - 25.990k in 5.015969s Benchmark.ips do |x| o = Object.new x.report('multi-eval') do o.instance_eval("def a; puts 'a'; end") (snip) o.instance_eval("def z; puts 'z'; end") end x.report('single-eval') do o.instance_eval("def a; puts 'a'; end; (snip) def z; puts 'z'; end") end end