Module: Gitlab::Metrics::System

Defined in:
lib/gitlab/metrics/system.rb

Overview

Module for gathering system/process statistics such as the memory usage.

This module relies on the /proc filesystem being available. If /proc is not available the methods of this module will be stubbed.

Constant Summary collapse

PROC_STATUS_PATH =
'/proc/self/status'
PROC_SMAPS_ROLLUP_PATH =
'/proc/self/smaps_rollup'
PROC_LIMITS_PATH =
'/proc/self/limits'
PROC_FD_GLOB =
'/proc/self/fd/*'
PRIVATE_PAGES_PATTERN =
/^(Private_Clean|Private_Dirty|Private_Hugetlb):\s+(?<value>\d+)/.freeze
PSS_PATTERN =
/^Pss:\s+(?<value>\d+)/.freeze
RSS_PATTERN =
/VmRSS:\s+(?<value>\d+)/.freeze
MAX_OPEN_FILES_PATTERN =
/Max open files\s*(?<value>\d+)/.freeze

Class Method Summary collapse

Class Method Details

.cpu_timeObject


39
40
41
# File 'lib/gitlab/metrics/system.rb', line 39

def self.cpu_time
  Process.clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID, :float_second)
end

.file_descriptor_countObject


31
32
33
# File 'lib/gitlab/metrics/system.rb', line 31

def self.file_descriptor_count
  Dir.glob(PROC_FD_GLOB).length
end

.max_open_file_descriptorsObject


35
36
37
# File 'lib/gitlab/metrics/system.rb', line 35

def self.max_open_file_descriptors
  sum_matches(PROC_LIMITS_PATH, max_fds: MAX_OPEN_FILES_PATTERN)[:max_fds]
end

.memory_usage_rssObject

Returns the current process' RSS (resident set size) in bytes.


21
22
23
# File 'lib/gitlab/metrics/system.rb', line 21

def self.memory_usage_rss
  sum_matches(PROC_STATUS_PATH, rss: RSS_PATTERN)[:rss].kilobytes
end

.memory_usage_uss_pssObject

Returns the current process' USS/PSS (unique/proportional set size) in bytes.


26
27
28
29
# File 'lib/gitlab/metrics/system.rb', line 26

def self.memory_usage_uss_pss
  sum_matches(PROC_SMAPS_ROLLUP_PATH, uss: PRIVATE_PAGES_PATTERN, pss: PSS_PATTERN)
    .transform_values(&:kilobytes)
end

.monotonic_timeObject

Returns the current monotonic clock time as seconds with microseconds precision.

Returns the time as a Float.


53
54
55
# File 'lib/gitlab/metrics/system.rb', line 53

def self.monotonic_time
  Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_second)
end

.real_time(precision = :float_second) ⇒ Object

Returns the current real time in a given precision.

Returns the time as a Float for precision = :float_second.


46
47
48
# File 'lib/gitlab/metrics/system.rb', line 46

def self.real_time(precision = :float_second)
  Process.clock_gettime(Process::CLOCK_REALTIME, precision)
end

.sum_matches(proc_file, **patterns) ⇒ Object

Given a path to a file in /proc and a hash of (metric, pattern) pairs, sums up all values found for those patterns under the respective metric.


74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/gitlab/metrics/system.rb', line 74

def self.sum_matches(proc_file, **patterns)
  results = patterns.transform_values { 0 }

  begin
    File.foreach(proc_file) do |line|
      patterns.each do |metric, pattern|
        match = line.match(pattern)
        value = match&.named_captures&.fetch('value', 0)
        results[metric] += value.to_i
      end
    end
  rescue Errno::ENOENT
    # This means the procfile we're reading from did not exist;
    # this is safe to ignore, since we initialize each metric to 0
  end

  results
end

.thread_cpu_duration(start_time) ⇒ Object


65
66
67
68
69
70
# File 'lib/gitlab/metrics/system.rb', line 65

def self.thread_cpu_duration(start_time)
  end_time = thread_cpu_time
  return unless start_time && end_time

  end_time - start_time
end

.thread_cpu_timeObject


57
58
59
60
61
62
63
# File 'lib/gitlab/metrics/system.rb', line 57

def self.thread_cpu_time
  # Not all OS kernels are supporting `Process::CLOCK_THREAD_CPUTIME_ID`
  # Refer: https://gitlab.com/gitlab-org/gitlab/issues/30567#note_221765627
  return unless defined?(Process::CLOCK_THREAD_CPUTIME_ID)

  Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID, :float_second)
end