diff options
Diffstat (limited to 'doc/development')
-rw-r--r-- | doc/development/README.md | 1 | ||||
-rw-r--r-- | doc/development/benchmarking.md | 69 | ||||
-rw-r--r-- | doc/development/profiling.md | 56 |
3 files changed, 126 insertions, 0 deletions
diff --git a/doc/development/README.md b/doc/development/README.md index 6bc8e1888db..d5bf166ad32 100644 --- a/doc/development/README.md +++ b/doc/development/README.md @@ -8,3 +8,4 @@ - [UI guide](ui_guide.md) for building GitLab with existing css styles and elements - [Migration Style Guide](migration_style_guide.md) for creating safe migrations - [How to dump production data to staging](dump_db.md) +- [Benchmarking](benchmarking.md) diff --git a/doc/development/benchmarking.md b/doc/development/benchmarking.md new file mode 100644 index 00000000000..88e18ee95f9 --- /dev/null +++ b/doc/development/benchmarking.md @@ -0,0 +1,69 @@ +# Benchmarking + +GitLab CE comes with a set of benchmarks that are executed for every build. This +makes it easier to measure performance of certain components over time. + +Benchmarks are written as RSpec tests using a few extra helpers. To write a +benchmark, first tag the top-level `describe`: + +```ruby +describe MaruTheCat, benchmark: true do + +end +``` + +This ensures the benchmark is executed separately from other test collections. +It also exposes the various RSpec matchers used for writing benchmarks to the +test group. + +Next, lets write the actual benchmark: + +```ruby +describe MaruTheCat, benchmark: true do + let(:maru) { MaruTheChat.new } + + describe '#jump_in_box' do + benchmark_subject { maru.jump_in_box } + + it { is_expected.to iterate_per_second(9000) } + end +end +``` + +Here `benchmark_subject` is a small wrapper around RSpec's `subject` method that +makes it easier to specify the subject of a benchmark. Using RSpec's regular +`subject` would require us to write the following instead: + +```ruby +subject { -> { maru.jump_in_box } } +``` + +The `iterate_per_second` matcher defines the amount of times per second a +subject should be executed. The higher the amount of iterations the better. + +By default the allowed standard deviation is a maximum of 30%. This can be +adjusted by chaining the `with_maximum_stddev` on the `iterate_per_second` +matcher: + +```ruby +it { is_expected.to iterate_per_second(9000).with_maximum_stddev(50) } +``` + +This can be useful if the code in question depends on external resources of +which the performance can vary a lot (e.g. physical HDDs, network calls, etc). +However, in most cases 30% should be enough so only change this when really +needed. + +## Benchmarks Location + +Benchmarks should be stored in `spec/benchmarks` and should follow the regular +Rails specs structure. That is, model benchmarks go in `spec/benchmark/models`, +benchmarks for code in the `lib` directory go in `spec/benchmarks/lib`, etc. + +## Underlying Technology + +The benchmark setup uses [benchmark-ips][benchmark-ips] which takes care of the +heavy lifting such as warming up code, calculating iterations, standard +deviation, etc. + +[benchmark-ips]: https://github.com/evanphx/benchmark-ips diff --git a/doc/development/profiling.md b/doc/development/profiling.md new file mode 100644 index 00000000000..80c86ef921e --- /dev/null +++ b/doc/development/profiling.md @@ -0,0 +1,56 @@ +# Profiling + +To make it easier to track down performance problems GitLab comes with a set of +profiling tools, some of these are available by default while others need to be +explicitly enabled. + +## rack-mini-profiler + +This Gem is enabled by default in development only. It allows you to see the +timings of the various components that made up a web request (e.g. the SQL +queries executed and their execution timings). + +## Bullet + +Bullet is a Gem that can be used to track down N+1 query problems. Because +Bullet adds quite a bit of logging noise it's disabled by default. To enable +Bullet, set the environment variable `ENABLE_BULLET` to a non-empty value before +starting GitLab. For example: + + ENABLE_BULLET=true bundle exec rails s + +Bullet will log query problems to both the Rails log as well as the Chrome +console. + +## ActiveRecord Query Trace + +This Gem adds backtraces for every ActiveRecord query in the Rails console. This +can be useful to track down where a query was executed. Because this Gem adds +quite a bit of noise (5-10 extra lines per ActiveRecord query) it's disabled by +default. To use this Gem you'll need to set `ENABLE_QUERY_TRACE` to a non empty +file before starting GitLab. For example: + + ENABLE_QUERY_TRACE=true bundle exec rails s + +## rack-lineprof + +This is a Gem that can trace the execution time of code on a per line basis. +Because this Gem can add quite a bit of overhead it's disabled by default. To +enable it, set the environment variable `ENABLE_LINEPROF` to a non-empty value. +For example: + + ENABLE_LINEPROF=true bundle exec rails s + +Once enabled you'll need to add a query string parameter to a request to +actually profile code execution. The name of the parameter is `lineprof` and +should be set to a regular expression (minus the starting/ending slash) used to +select what files to profile. To profile all files containing "foo" somewhere in +the path you'd use the following parameter: + + ?lineprof=foo + +Or when filtering for files containing "foo" and "bar" in their path: + + ?lineprof=foo|bar + +Once set the profiling output will be displayed in your terminal. |