lib/gladys/actions/benchmark.rb



# frozen_string_literal: true

module Gladys
  module Actions
    class Benchmark < Base
      WARM_UP_TIME = 5
      COOL_DOWN_TIME = 5
      SLEEP_TIME = 1

      def run(time:, threads:)
        @time = time
        @threads = threads
        optimize_database
        @context.preload_inputs

        @started_at = Time.now + WARM_UP_TIME

        @metrics = invoke(:benchmark, threads: @threads, should_stop: lambda do
          Time.now >= (@started_at + @time) + COOL_DOWN_TIME
        end)
      end

      def report
        Report.new(
          script: @script,
          threads: @threads,
          time: @time,
          started_at: @started_at,
          finished_at: @started_at + @time,
          database_size: current_database_size,
          metrics: @metrics,
          metadata: fetch_metadata
        )
      end

      private

      def fetch_metadata
        {
          client: fetch_client_settings,
          postgres: fetch_postgres_settings
        }
      end

      def fetch_client_settings
        {
          cpu_count: Concurrent.processor_count,
          platform: RUBY_PLATFORM,
          ruby_version: RUBY_VERSION
        }
      end

      # Fetches metadata from the database so we can include it in the report and
      # analyze how certain settings affect benchmark results. This is technically
      # optional so we should include a setting to disable it.
      def fetch_postgres_settings
        @database.select(:name, :setting).from(:pg_settings).all.to_h do |row|
          [row[:name], row[:setting]]
        end
      rescue Sequel::DatabaseError => e
        Gladys.log_debug "Failed to fetch metadata, skipping... (Error: #{e.message})"
        {}
      end

      def optimize_database
        Gladys.log("Running VACUUM ANALYZE before benchmark...")

        begin
          @database.run("VACUUM ANALYZE")
        rescue
          Gladys.log_debug "VACUUM ANALYZE failed, skipping..."
        end
      end
    end
  end
end