Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'config/initializers/stackprof.rb')
-rw-r--r--config/initializers/stackprof.rb65
1 files changed, 38 insertions, 27 deletions
diff --git a/config/initializers/stackprof.rb b/config/initializers/stackprof.rb
index 797efdb9bbd..4c4d241f065 100644
--- a/config/initializers/stackprof.rb
+++ b/config/initializers/stackprof.rb
@@ -2,14 +2,18 @@
# trigger stackprof by sending a SIGUSR2 signal
#
-# default settings:
-# * collect raw samples
-# * sample at 100hz (every 10k microseconds)
-# * timeout profile after 30 seconds
-# * write to $TMPDIR/stackprof.$PID.$RAND.profile
+# Docs: https://docs.gitlab.com/ee/development/performance.html#production
module Gitlab
class StackProf
+ DEFAULT_FILE_PREFIX = Dir.tmpdir
+ DEFAULT_TIMEOUT_SEC = 30
+ DEFAULT_MODE = :cpu
+ # Sample interval as a frequency in microseconds (~100hz); appropriate for CPU profiles
+ DEFAULT_INTERVAL_US = 10_000
+ # Sample interval in event occurrences (n = every nth event); appropriate for allocation profiles
+ DEFAULT_INTERVAL_EVENTS = 1_000
+
# this is a workaround for sidekiq, which defines its own SIGUSR2 handler.
# by defering to the sidekiq startup event, we get to set up our own
# handler late enough.
@@ -32,11 +36,7 @@ module Gitlab
end
def self.on_worker_start
- Gitlab::AppJsonLogger.info(
- event: "stackprof",
- message: "listening on SIGUSR2 signal",
- pid: Process.pid
- )
+ log_event('listening for SIGUSR2 signal')
# create a pipe in order to propagate signal out of the signal handler
# see also: https://cr.yp.to/docs/selfpipe.html
@@ -55,43 +55,46 @@ module Gitlab
# a given interval (by default 30 seconds), avoiding unbounded memory
# growth from a profile that was started and never stopped.
t = Thread.new do
- timeout_s = ENV['STACKPROF_TIMEOUT_S']&.to_i || 30
+ timeout_s = ENV['STACKPROF_TIMEOUT_S']&.to_i || DEFAULT_TIMEOUT_SEC
current_timeout_s = nil
loop do
- got_value = IO.select([read], nil, nil, current_timeout_s)
- read.getbyte if got_value
+ read.getbyte if IO.select([read], nil, nil, current_timeout_s)
if ::StackProf.running?
- stackprof_file_prefix = ENV['STACKPROF_FILE_PREFIX'] || Dir.tmpdir
+ stackprof_file_prefix = ENV['STACKPROF_FILE_PREFIX'] || DEFAULT_FILE_PREFIX
stackprof_out_file = "#{stackprof_file_prefix}/stackprof.#{Process.pid}.#{SecureRandom.hex(6)}.profile"
- Gitlab::AppJsonLogger.info(
- event: "stackprof",
- message: "stopping profile",
- output_filename: stackprof_out_file,
- pid: Process.pid,
- timeout_s: timeout_s,
- timed_out: got_value.nil?
+ log_event(
+ 'stopping profile',
+ profile_filename: stackprof_out_file,
+ profile_timeout_s: timeout_s
)
::StackProf.stop
::StackProf.results(stackprof_out_file)
current_timeout_s = nil
else
- Gitlab::AppJsonLogger.info(
- event: "stackprof",
- message: "starting profile",
- pid: Process.pid
+ mode = ENV['STACKPROF_MODE']&.to_sym || DEFAULT_MODE
+ interval = ENV['STACKPROF_INTERVAL']&.to_i
+ interval ||= (mode == :object ? DEFAULT_INTERVAL_EVENTS : DEFAULT_INTERVAL_US)
+
+ log_event(
+ 'starting profile',
+ profile_mode: mode,
+ profile_interval: interval,
+ profile_timeout: timeout_s
)
::StackProf.start(
- mode: :cpu,
+ mode: mode,
raw: Gitlab::Utils.to_boolean(ENV['STACKPROF_RAW'] || 'true'),
- interval: ENV['STACKPROF_INTERVAL_US']&.to_i || 10_000
+ interval: interval
)
current_timeout_s = timeout_s
end
end
+ rescue => e
+ log_event("stackprof failed: #{e}")
end
t.abort_on_exception = true
@@ -121,6 +124,14 @@ module Gitlab
write.write('.')
end
end
+
+ def self.log_event(event, labels = {})
+ Gitlab::AppJsonLogger.info({
+ event: 'stackprof',
+ message: event,
+ pid: Process.pid
+ }.merge(labels.compact))
+ end
end
end