Perf is a lightweight library for collecting and reporting performance data, which works for standalone applications and for distributed systems.
Add this line to your application's Gemfile:
gem 'perf'
And then execute:
$ bundle
Or install it yourself as:
$ gem install perf
Perf is a simple mix-in module; include it into your class (with include/extend) - and you're ready to go.
include Perf
This will not make your code run faster, but it will set up the environment for figuring out where your bottlenecks are. Now your class has a method called collect that lets you measuring performance of a code block. ###Collecting Data Collecting performance data is very simple:
def foo
# Some code
collect counter do
# code to measure
end
# Some code
end
Perf module provides the following counters out of the box:
- hits increments values before executing the code block.
- totals increments values upon successful execution (i.e. no exceptions) of the code block.
- activity increments values before the code block, and decrements afterwards.
- failures increments values when the code block throws an exception.
- duration records duration of the code block (in seconds) upon successful execution by incrementing specified value.
- throughput records duration and volume.
A call to collect may include any number of counters:
collect activity(:acive_uploads, active_upload_size: file.size), totals(:total_uploads, uploaded_size: file.size) do
# Upload a file
end
The code block following collect is optional, and you can easily write something like that:
# Some code
collect totals(:total_uploads, uploaded_size: file.size)
# More code
Note that without the code block hits and totals counters behave the same way, and activity counters do nothing.
For hits, totals, and activity counters you may explicity specify value by which counter should be changed:
collect totals(:uploaded_count, uploaded_size: file.size)
In this case value of uploaded_count counter will be incremented by one, but value of uploaded_size - by file.size.
Hits counters increment specified value(s) by one (by default) or by explicitly specified delta before executing the code block. They answer questions like:
- How many times have we tried to perform this operation?
- What's the overall volume of data have we tried to process?
The example below collects statistics on uploading operations:
collect hits(:attempted_uploads, attempted_upload_size: file.size) do
# upload a file
end
The code will increment attempted_uploads and attempted_upload_size counters before trying to upload. The actual result of uploading doesn't really matter.
Totals counter report data for successful operations only - when code block did not throw any exceptions. Like hits counter, they increment values by one by default, or by explicitly specified delta:
collect totals(:successful_uploads, successful_upload_size: file.size) do
# upload a file
end
Activity counters increment values before the code block and decrement them after. They are used to report 'active' data:
- How many tasks are being executed at this moment?
- How much data are we processing right now?
Once again, you can explicitly specify delta by which certain counters should be incremented/decremented:
collect activity(:active_uploads, active_upload_size: file.size) do
# upload a file
end
Unlike hits and totals, activity is a volatile counter. If a process executing the code block crashes, or if the mahcine looses connectivity, pending activity counters will eventually fix themselves. The time-to-live period is implementation-specific.
Failures counter reports errors. The values get incremented only if the code block throws an exception.
collect failures(:failed_upload_count) do
# upload a file
end
Duration counter records duration of the code block (in seconds). Only successful execution counts - if the block throws, nothing gets reported.
collect duration(:total_upload_time) do
# upload a file
end
Throughput counter reports duration and volume of a call. It is a combination of a duration and a totals counter.
collect throughput(upload: file.size) do
# Upload a file
end
The example below will increment two counters: upload.duration for the durarion of upload, and upload.volume for the file size.
Current values of all counters can be obtained by calling Perf::Data.get method, which returns a hash table with counters and their values:
data = Perf::Data.get
# Do whatever you want
There may be situations in which you may want to reset all perf data and start from scratch:
Perf::Data.reset
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request