README.md in pilfer-0.0.1.pre4 vs README.md in pilfer-1.0.0

- old
+ new

@@ -1,100 +1,201 @@ # Pilfer -Look into your ruby with [rblineprof](https://github.com/tmm1/rblineprof/). +Profile Ruby code and find out _exactly_ how slow it runs. +Pilfer uses [rblineprof][] to measure how long each line of code takes to +execute and the number of times it was called. + +![Pilfer Profile.png](http://cl.ly/image/2a1d332M2w05/Pilfer%20Profile.png) + +Take a look at some [Pilfer profiles of the Bundler API site][bundler-pilfer]. + +## Installation + +Using with Bundler is as simple as adding `pilfer` to your `Gemfile`. + +```ruby +gem 'pilfer', '~> 1.0.0' +``` + +Or install it locally like any other gem. + +```bash +$ gem install pilfer +``` + ## Usage Profile a block of code saving the report to the file `profile.log`. ```ruby +require 'pilfer' + reporter = Pilfer::Logger.new('pilfer.log') profiler = Pilfer::Profiler.new(reporter) -profiler.profile { do_something } +profiler.profile('bubble sorting') do + array = (0..100).to_a.shuffle + bubble_sort array +end ``` -The report prints the source of each line of code executed and includes the -total execution time and the number of times the line was executed. +Profile your Rack or Rails app using `Pilfer::Middleware`. -_TODO: Show profile response._ +```ruby +reporter = Pilfer::Logger.new('pilfer.log') +profiler = Pilfer::Profiler.new(reporter) +use Pilfer::Middleware :profiler => profiler +``` +The profile report consists of the wall time and call count for each line of +code executed along with the total wall and CPU times for each file. + +``` +Profile start="2013-05-12 00:41:16 UTC" description="bubble sorting" +/Users/Larry/Sites/pilfer/sort.rb wall_time=42.5ms cpu_time=29.7ms + | require 'pilfer' + | + | def bubble_sort(container) + 42.5ms ( 1) | loop do + | swapped = false + 42.3ms ( 94) | (container.size-1).times do |i| + 10.2ms ( 9400) | if (container[i] <=> container[i+1]) == 1 + 6.2ms ( 5092) | container[i], container[i+1] = container[i+1], container[i] # Swap + | swapped = true + | end + | end + | break unless swapped + | end + | container + | end + | + | reporter = Pilfer::Logger.new($stdout) + | profiler = Pilfer::Profiler.new(reporter) + | profiler.profile_files_matching(/sort\.rb/, 'bubble sorting') do + 0.1ms ( 3) | array = (0..100).to_a.shuffle + 42.5ms ( 1) | bubble_sort array + | end +``` + ### Step 1: Create a reporter -Profiles can be sent to a [pilfer-server][] or written to a file or `IO` -object. +Decide how you want line profiles to be reported. Profiles can be sent to a +[pilfer-server][] or written to a file path or `IO` object. ```ruby -reporter = Pilfer::Server.new('https://pilfer.com', 'abc123') +# Send reports to a pilfer-server +reporter = Pilfer::Server.new('https://pilfer.com', 'my-pilfer-server-token') + +# Append reports to a file reporter = Pilfer::Logger.new('pilfer.log') + +# Print reports to standard out reporter = Pilfer::Logger.new($stdout) ``` The absolute path to each profiled file is used in the report. Set the path to the application root with `:app_root` to have it trimmed from reported file paths. ```ruby -reporter = Pilfer::Logger.new($stdout, :app_root => '/my/app') +reporter = Pilfer::Logger.new('pilfer.log') +# Profile start=2013-05-02 14:17:26 UTC +# /Sites/bundler-api/lib/bundler-api/web.rb wall_time=1009.5ms cpu_time=0.5ms +# ... + +reporter = Pilfer::Logger.new('pilfer.log', :app_root => '/Sites/bundler-api/') +# Profile start=2013-05-02 14:17:26 UTC +# lib/bundler-api/web.rb wall_time=1009.5ms cpu_time=0.5ms +# ... ``` ### Step 2: Create a profiler -Pass the reporter to a new `Pilfer::Profiler`. +A `Profiler` runs the line profiler and sends it to a reporter. Create one +passing the reporter created in the previous step. ```ruby profiler = Pilfer::Profiler.new(reporter) ``` ### Step 3: Profile a block of code -Profile a block of code with `#profile`. +Use `Profiler#profile` to profile a block of code. Optionally, provide a +description of the code being profiling. ```ruby -profiler.profile { do_something } +profiler.profile('bubble sorting') do + array = (0..100).to_a.shuffle + bubble_sort array +end ``` -Every file that's executed by the block--including code outside the -application like gems and standard libraries--will be included in the profile. -Use `#profile_files_matching` and provide a regular expression to limit -profiling to only matching file paths. +Every file that's executed by the block including code outside the +application like gems and standard libraries will be included in the profile. +Use `#profile_files_matching` to limit profiling to files whose paths match a +regular expression. ```ruby +# Only profile Rails models matcher = %r{^#{Regexp.escape(Rails.root.to_s)}/app/models} -profiler.profile_files_matching(matcher) { do_something } +profiler.profile_files_matching(matcher, 'User.find_by_email') do + User.find_by_email('arthur@dent.com') +end ``` -## Pilfer Server +Additional arguments to `#profile` and `#profile_files_matching` will be +passed to the reporter. The `Pilfer::Server` reporter, for example, can submit +profiles asynchronously. -[pilfer-server][] is your own, personal service for collecting and viewing -profile reports. Follow the [pilfer-server setup instructions][pilfer-server] -to stand up a new server and send it reports using its URL and token. +```ruby +profiler.profile('bubble sorting', :submit => :async) do + array = (0..100).to_a.shuffle + bubble_sort array +end +``` +## Extras + +### Pilfer Server + +[Pilfer Server][pilfer-server] is your own, personal service for collecting +and viewing line profiles gathered by Pilfer. Follow the +[Pilfer Server setup instructions][pilfer-server-readme] to stand up a new +server. + ```ruby -reporter = Pilfer::Server.new('https://pilfer.com', 'abc123') +reporter = Pilfer::Server.new('https://pilfer.com', 'my-pilfer-server-token') +profiler = Pilfer::Profiler.new(reporter) +profiler.profile('bubble sorting') do + array = (0..100).to_a.shuffle + bubble_sort array +end ``` -## Rack Middleware +### Rack Middleware -Profile your Rack or Rails app using `Pilfer::Middleware`. +Profile your entire Rack or Rails app using `Pilfer::Middleware`. Pass it a +`Profiler` created with a reporter as normal. ```ruby -reporter = Pilfer::Logger.new($stdout, :app_root => Rails.root) +reporter = Pilfer::Server.new('https://pilfer.com', 'my-pilfer-server-token') profiler = Pilfer::Profiler.new(reporter) use Pilfer::Middleware :profiler => profiler ``` -Restrict the files profiled by passing a regular expression with -`:files_matching`. +Restrict profiling to files matching a regular expression using the +`:files_matching` option. This calls `Profiler#profile_files_matching` using +the given regular expression. ```ruby matcher = %r{^#{Regexp.escape(Rails.root.to_s)}/(app|config|lib|vendor/plugin)} -use Pilfer::Middleware, :files_matching => matcher, - :profiler => profiler +use Pilfer::Middleware, :profiler => profiler, + :files_matching => matcher ``` -You probably don't want to profile _every_ request. The given block will be -evaluated on each request to determine if a profile should be run. +You almost certainly don't want to profile _every_ request. Provide a block to +determine if a profile should be run on the incoming request. ```ruby use Pilfer::Middleware, :profiler => profiler do # Profile 1% of requests. rand(100) == 1 @@ -102,12 +203,41 @@ ``` The Rack environment is available to allow profiling on demand. ```ruby +# Profile requests containing the query string ?profile=true use Pilfer::Middleware, :profiler => profiler do |env| env.query_string.include? 'profile=true' end + +# Profile requests containing a header whose value matches a secret +use Pilfer::Middleware, :profiler => profiler do |env| + env['HTTP_PROFILE_AUTHORIZATION'] == 'super-secret' +end ``` +## Supported Ruby Versions -[pilfer-server]: https://github.com/eric/pilfer-server +This library is [tested against][travis] the following Ruby versions. + + - MRI 1.9.3 + - MRI 1.8.7 + - REE + +If you need a specific version supported, open and issue or send a pull +request. + +## License + +The MIT License (MIT) + +Copyright (c) 2013 Eric Lindvall and Larry Marburger. See [LICENSE][] for +details. + + +[rblineprof]: https://github.com/tmm1/rblineprof +[bundler-pilfer]: https://pilfer.herokuapp.com/dashboard +[pilfer-server]: https://github.com/eric/pilfer-server +[pilfer-server-readme]: https://github.com/eric/pilfer-server#readme +[travis]: https://travis-ci.org/eric/pilfer +[license]: LICENSE