Commit 8dce5a14 authored by Matthias Käppler's avatar Matthias Käppler

Merge branch 'mk-perfbar-memory' into 'master'

Expose memory allocations in performance bar

See merge request gitlab-org/gitlab!61332
parents fa6490b6 865cd871
...@@ -73,6 +73,11 @@ export default { ...@@ -73,6 +73,11 @@ export default {
header: s__('PerformanceBar|External Http calls'), header: s__('PerformanceBar|External Http calls'),
keys: ['label', 'code', 'proxy', 'error'], keys: ['label', 'code', 'proxy', 'error'],
}, },
{
metric: 'memory',
header: s__('PerformanceBar|Memory'),
keys: ['item_header', 'item_content'],
},
{ {
metric: 'total', metric: 'total',
header: s__('PerformanceBar|Frontend resources'), header: s__('PerformanceBar|Frontend resources'),
......
...@@ -15,9 +15,15 @@ Peek.into Peek::Views::Elasticsearch ...@@ -15,9 +15,15 @@ Peek.into Peek::Views::Elasticsearch
Peek.into Peek::Views::Rugged Peek.into Peek::Views::Rugged
Peek.into Peek::Views::ExternalHttp Peek.into Peek::Views::ExternalHttp
Peek.into Peek::Views::BulletDetailed if defined?(Bullet) Peek.into Peek::Views::BulletDetailed if defined?(Bullet)
Peek.into Peek::Views::Memory
Peek.into Peek::Views::Tracing if Labkit::Tracing.tracing_url_enabled? Peek.into Peek::Views::Tracing if Labkit::Tracing.tracing_url_enabled?
# Trigger view creation here, since views might be subscribing to Rails notifications
# via setup_subscribers, which is called in the initializer.
# See https://github.com/peek/peek/blob/master/lib/peek/views/view.rb
Peek.views
ActiveSupport::Notifications.subscribe('endpoint_run.grape') do |_name, _start, _finish, _id, payload| ActiveSupport::Notifications.subscribe('endpoint_run.grape') do |_name, _start, _finish, _id, payload|
if request_id = payload[:env]['action_dispatch.request_id'] if request_id = payload[:env]['action_dispatch.request_id']
Peek.adapter.save(request_id) Peek.adapter.save(request_id)
......
...@@ -6,7 +6,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w ...@@ -6,7 +6,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Performance Bar **(FREE SELF)** # Performance Bar **(FREE SELF)**
> The **Stats** field [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/271551) in GitLab SaaS 13.9. > The **Stats** field [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/271551) in GitLab 13.9.
> The **Memory** field [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/330736) in GitLab 14.0.
You can display the GitLab Performance Bar to see statistics for the performance You can display the GitLab Performance Bar to see statistics for the performance
of a page. When activated, it looks as follows: of a page. When activated, it looks as follows:
...@@ -40,9 +41,11 @@ From left to right, it displays: ...@@ -40,9 +41,11 @@ From left to right, it displays:
Time until something was visible to the user. Time until something was visible to the user.
- [**DomContentLoaded**](https://developers.google.com/web/fundamentals/performance/critical-rendering-path/measure-crp) Event. - [**DomContentLoaded**](https://developers.google.com/web/fundamentals/performance/critical-rendering-path/measure-crp) Event.
- **Total number of requests** the page loaded. - **Total number of requests** the page loaded.
- **Trace**: If Jaeger is integrated, **Trace** links to a Jaeger tracing page - **Memory**: the amount of memory consumed and objects allocated during the selected request.
Select it to display a window with more details.
- **Trace**: if Jaeger is integrated, **Trace** links to a Jaeger tracing page
with the current request's `correlation_id` included. with the current request's `correlation_id` included.
- **+**: A link to add a request's details to the performance bar. The request - **+**: a link to add a request's details to the performance bar. The request
can be added by its full URL (authenticated as the current user), or by the value of can be added by its full URL (authenticated as the current user), or by the value of
its `X-Request-Id` header. its `X-Request-Id` header.
- **Download**: a link to download the raw JSON used to generate the Performance Bar reports. - **Download**: a link to download the raw JSON used to generate the Performance Bar reports.
...@@ -52,6 +55,11 @@ From left to right, it displays: ...@@ -52,6 +55,11 @@ From left to right, it displays:
- **Stats** (optional): if the `GITLAB_PERFORMANCE_BAR_STATS_URL` environment variable is set, - **Stats** (optional): if the `GITLAB_PERFORMANCE_BAR_STATS_URL` environment variable is set,
this URL is displayed in the bar. In GitLab 13.9 and later, used only in GitLab SaaS. this URL is displayed in the bar. In GitLab 13.9 and later, used only in GitLab SaaS.
NOTE:
Not all indicators are available in all environments. For instance, the memory view
requires to run Ruby with [specific patches](https://gitlab.com/gitlab-org/gitlab-build-images/-/blob/master/patches/ruby/2.7.2/thread-memory-allocations-2.7.patch) applied.
When running GitLab locally using the GDK this is typically not the case and the memory view cannot be used.
## Request warnings ## Request warnings
Requests that exceed predefined limits display a warning **{warning}** icon and Requests that exceed predefined limits display a warning **{warning}** icon and
......
# frozen_string_literal: true
module Peek
module Views
class Memory < View
MEM_TOTAL_LABEL = 'Total'
MEM_OBJECTS_LABEL = 'Objects allocated'
MEM_MALLOCS_LABEL = 'Allocator calls'
MEM_BYTES_LABEL = 'Large allocations'
def initialize(options = {})
super
@thread_memory = {}
end
def results
return thread_memory if thread_memory.empty?
{
calls: byte_string(thread_memory[:mem_total_bytes]),
summary: {
MEM_OBJECTS_LABEL => number_string(thread_memory[:mem_objects]),
MEM_MALLOCS_LABEL => number_string(thread_memory[:mem_mallocs]),
MEM_BYTES_LABEL => byte_string(thread_memory[:mem_bytes])
},
details: [
{
item_header: MEM_TOTAL_LABEL,
item_content: "Total memory use of this request. This includes both occupancy of existing heap slots " \
"as well as newly allocated memory due to large objects. Not adjusted for freed memory. " \
"Lower is better."
},
{
item_header: MEM_OBJECTS_LABEL,
item_content: "Total number of objects allocated by the Ruby VM during this request. " \
"Not adjusted for objects that were freed again. Lower is better."
},
{
item_header: MEM_MALLOCS_LABEL,
item_content: "Total number of times Ruby had to call `malloc`, the C memory allocator. " \
"This is necessary for objects that are too large to fit into a 40 Byte slot in Ruby's managed heap. " \
"Lower is better."
},
{
item_header: MEM_BYTES_LABEL,
item_content: "Memory allocated for objects that did not fit into a heap slot. " \
"Not adjusted for memory that was freed again. Lower is better."
}
]
}
end
private
attr_reader :thread_memory
def setup_subscribers
subscribe 'process_action.action_controller' do
# Ensure that Peek will see memory instrumentation in `results` by triggering it when
# a request is done processing. Peek itself hooks into the same notification:
# https://github.com/peek/peek/blob/master/lib/peek/railtie.rb
Gitlab::InstrumentationHelper.instrument_thread_memory_allocations(thread_memory)
end
end
def byte_string(bytes)
ActiveSupport::NumberHelper.number_to_human_size(bytes)
end
def number_string(num)
ActiveSupport::NumberHelper.number_to_human(num, units: { thousand: 'k', million: 'M', billion: 'B' })
end
end
end
end
...@@ -23973,6 +23973,9 @@ msgstr "" ...@@ -23973,6 +23973,9 @@ msgstr ""
msgid "PerformanceBar|Gitaly calls" msgid "PerformanceBar|Gitaly calls"
msgstr "" msgstr ""
msgid "PerformanceBar|Memory"
msgstr ""
msgid "PerformanceBar|Redis calls" msgid "PerformanceBar|Redis calls"
msgstr "" msgstr ""
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Peek::Views::Memory, :request_store do
subject! { described_class.new }
before do
stub_memory_instrumentation
end
context 'with process_action.action_controller notification' do
it 'returns empty results when it has not yet fired' do
expect(subject.results).to eq({})
end
it 'returns memory instrumentation data when it has fired' do
publish_notification
expect(subject.results[:calls]).to eq('2 MB')
expect(subject.results[:details]).to all(have_key(:item_header))
expect(subject.results[:details]).to all(have_key(:item_content))
expect(subject.results[:summary]).to include('Objects allocated' => '200 k')
expect(subject.results[:summary]).to include('Allocator calls' => '500')
expect(subject.results[:summary]).to include('Large allocations' => '1 KB')
end
end
def stub_memory_instrumentation
start_memory = {
total_malloc_bytes: 1,
total_mallocs: 2,
total_allocated_objects: 3
}
allow(Gitlab::Memory::Instrumentation).to receive(:start_thread_memory_allocations).and_return(start_memory)
allow(Gitlab::Memory::Instrumentation).to receive(:measure_thread_memory_allocations).with(start_memory).and_return({
mem_total_bytes: 2_097_152,
mem_bytes: 1024,
mem_mallocs: 500,
mem_objects: 200_000
})
Gitlab::InstrumentationHelper.init_instrumentation_data
end
def publish_notification
headers = double
allow(headers).to receive(:env).and_return('action_dispatch.request_id': 'req-42')
ActiveSupport::Notifications.publish(
'process_action.action_controller', Time.current - 1.second, Time.current, 'id', headers: headers
)
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment