From f44719f39cb9ee88c63759caa582d484cd6d4e9a Mon Sep 17 00:00:00 2001
From: Aleksei Lipniagov <alipniagov@gitlab.com>
Date: Tue, 25 Jun 2019 15:11:06 +0300
Subject: [PATCH] Get memory data after booting app in production

Preload the app in `production` env, hit it with a single request, and
gather total gem memory consumption data using `derailed exec perf:mem`
from `derailed_benchmarks`. Present the result as MR metrics.
---
 .gitlab/ci/memory.gitlab-ci.yml         | 23 +++++++++++++++++++++++
 config/boot.rb                          |  2 +-
 scripts/generate-memory-metrics-on-boot | 11 +++++++++++
 scripts/prepare_build.sh                | 10 ++++++----
 4 files changed, 41 insertions(+), 5 deletions(-)
 create mode 100755 scripts/generate-memory-metrics-on-boot

diff --git a/.gitlab/ci/memory.gitlab-ci.yml b/.gitlab/ci/memory.gitlab-ci.yml
index 2f3907a331acf..ffe5dbdc31b70 100644
--- a/.gitlab/ci/memory.gitlab-ci.yml
+++ b/.gitlab/ci/memory.gitlab-ci.yml
@@ -17,3 +17,26 @@ memory-static:
       - tmp/memory_*.txt
     reports:
       metrics: tmp/memory_metrics.txt
+
+# Show memory usage caused by invoking require per gem.
+# Unlike `memory-static`, it hits the app with one request to ensure that any last minute require-s have been called.
+# The application is booted in `production` environment.
+# All tests are run without a webserver (directly using Rack::Mock by default).
+memory-on-boot:
+  extends: .rspec-metadata-pg-10
+  variables:
+    NODE_ENV: "production"
+    RAILS_ENV: "production"
+    SETUP_DB: "true"
+    SKIP_STORAGE_VALIDATION: "true"
+    # we override the max_old_space_size to prevent OOM errors
+    NODE_OPTIONS: --max_old_space_size=3584
+  script:
+    # Both bootsnap and derailed monkey-patch Kernel#require, which leads to circular dependency
+    - DISABLE_BOOTSNAP=true PATH_TO_HIT="/users/sign_in" CUT_OFF=0.3 bundle exec derailed exec perf:mem >> 'tmp/memory_on_boot.txt'
+    - scripts/generate-memory-metrics-on-boot tmp/memory_on_boot.txt >> 'tmp/memory_on_boot_metrics.txt'
+  artifacts:
+    paths:
+      - tmp/memory_*.txt
+    reports:
+      metrics: tmp/memory_on_boot_metrics.txt
diff --git a/config/boot.rb b/config/boot.rb
index 2811f0e61889c..b76b26a5e75ea 100644
--- a/config/boot.rb
+++ b/config/boot.rb
@@ -3,7 +3,7 @@
 # Set up gems listed in the Gemfile.
 require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
 begin
-  require 'bootsnap/setup'
+  require 'bootsnap/setup' unless ENV['DISABLE_BOOTSNAP']
 rescue LoadError
   # bootsnap is an optional dependency, so if we don't have it, it's fine
 end
diff --git a/scripts/generate-memory-metrics-on-boot b/scripts/generate-memory-metrics-on-boot
new file mode 100755
index 0000000000000..5197a8fcdcd9f
--- /dev/null
+++ b/scripts/generate-memory-metrics-on-boot
@@ -0,0 +1,11 @@
+#!/usr/bin/env ruby
+
+abort "usage: #{__FILE__} <memory_bundle_mem_file_name>" unless ARGV.length == 1
+memory_bundle_mem_file_name = ARGV.first
+
+full_report = File.open(memory_bundle_mem_file_name).read
+
+stats = /TOP: (?<total_mibs_str>.*) MiB/.match(full_report)
+abort 'failed to process the benchmark output' unless stats
+
+puts "total_memory_used_by_dependencies_on_boot_prod_env_mb #{stats[:total_mibs_str].to_f.round(1)}"
diff --git a/scripts/prepare_build.sh b/scripts/prepare_build.sh
index 9b0d5d4f719ab..0950ec272a53d 100644
--- a/scripts/prepare_build.sh
+++ b/scripts/prepare_build.sh
@@ -35,9 +35,11 @@ sed -i 's/username: root/username: gitlab/g' config/database.yml
 
 if [ "$GITLAB_DATABASE" = 'postgresql' ]; then
   sed -i 's/localhost/postgres/g' config/database.yml
+  sed -i 's/username: git/username: postgres/g' config/database.yml
 
   if [ -f config/database_geo.yml ]; then
     sed -i 's/localhost/postgres/g' config/database_geo.yml
+    sed -i 's/username: git/username: postgres/g' config/database_geo.yml
   fi
 else # Assume it's mysql
   sed -i 's/localhost/mysql/g' config/database.yml
@@ -48,16 +50,16 @@ else # Assume it's mysql
 fi
 
 cp config/resque.yml.example config/resque.yml
-sed -i 's/localhost/redis/g' config/resque.yml
+sed -i 's|url:.*$|url: redis://redis:6379|g' config/resque.yml
 
 cp config/redis.cache.yml.example config/redis.cache.yml
-sed -i 's/localhost/redis/g' config/redis.cache.yml
+sed -i 's|url:.*$|url: redis://redis:6379/10|g' config/redis.cache.yml
 
 cp config/redis.queues.yml.example config/redis.queues.yml
-sed -i 's/localhost/redis/g' config/redis.queues.yml
+sed -i 's|url:.*$|url: redis://redis:6379/11|g' config/redis.queues.yml
 
 cp config/redis.shared_state.yml.example config/redis.shared_state.yml
-sed -i 's/localhost/redis/g' config/redis.shared_state.yml
+sed -i 's|url:.*$|url: redis://redis:6379/12|g' config/redis.shared_state.yml
 
 if [ "$SETUP_DB" != "false" ]; then
   setup_db
-- 
GitLab