<commit_before># frozen_string_literal: true

module TestProf
  # StackProf wrapper.
  #
  # Has 2 modes: global and per-example.
  #
  # Example:
  #
  #   # To activate global profiling you can use env variable
  #   TEST_STACK_PROF=1 rspec ...
  #
  #   # or in your code
  #   TestProf::StackProf.run
  #
  # To profile a specific examples add :sprof tag to it:
  #
  #   it "is doing heavy stuff", :sprof do
  #     ...
  #   end
  #
  module StackProf
    # StackProf configuration
    class Configuration
      attr_accessor :mode, :interval, :raw

      def initialize
        @mode = ENV.fetch('TEST_STACK_PROF_MODE', :wall).to_sym
        @raw = ENV['TEST_STACK_PROF_RAW'] == '1'
      end
    end

    class << self
      include Logging

      def config
        @config ||= Configuration.new
      end

      def configure
        yield config
      end

      # Run StackProf and automatically dump
      # a report when the process exits.
      #
      # Use this method to profile the whole run.
      def run
        return unless profile

        @locked = true

        log :info, "StackProf enabled"

        at_exit { dump("total") }
      end

      def profile(name = nil)
        return if locked?
        return unless init_stack_prof

        options = {
          mode: config.mode,
          raw: config.raw
        }

        options[:interval] = config.interval if config.interval

        if block_given?
          options[:out] = build_path(name)
          ::StackProf.run(options) { yield }
        else
          ::StackProf.start(options)
        end
        true
      end

      def dump(name)
        ::StackProf.stop

        path = build_path(name)

        ::StackProf.results(path)

        log :info, "StackProf report generated: #{path}"
      end

      private

      def build_path(name)
        TestProf.artefact_path(
          "stack-prof-report-#{config.mode}#{config.raw ? '-raw' : ''}-#{name}.dump"
        )
      end

      def locked?
        @locked == true
      end

      def init_stack_prof
        return @initialized if instance_variable_defined?(:@initialized)
        @initialized = TestProf.require(
          'stackprof',
          <<~MSG
            Please, install 'stackprof' first:
               # Gemfile
              gem 'stackprof', require: false
          MSG
        )
      end
    end
  end
end

require "test_prof/stack_prof/rspec" if defined?(RSpec)

# Hook to run StackProf globally
TestProf.activate('TEST_STACK_PROF') do
  TestProf::StackProf.run
end
<commit_msg>Add stackprof flamegraph hint message<commit_after># frozen_string_literal: true

module TestProf
  # StackProf wrapper.
  #
  # Has 2 modes: global and per-example.
  #
  # Example:
  #
  #   # To activate global profiling you can use env variable
  #   TEST_STACK_PROF=1 rspec ...
  #
  #   # or in your code
  #   TestProf::StackProf.run
  #
  # To profile a specific examples add :sprof tag to it:
  #
  #   it "is doing heavy stuff", :sprof do
  #     ...
  #   end
  #
  module StackProf
    # StackProf configuration
    class Configuration
      attr_accessor :mode, :interval, :raw

      def initialize
        @mode = ENV.fetch('TEST_STACK_PROF_MODE', :wall).to_sym
        @raw = ENV['TEST_STACK_PROF_RAW'] == '1'
      end
    end

    class << self
      include Logging

      def config
        @config ||= Configuration.new
      end

      def configure
        yield config
      end

      # Run StackProf and automatically dump
      # a report when the process exits.
      #
      # Use this method to profile the whole run.
      def run
        return unless profile

        @locked = true

        log :info, "StackProf enabled"

        at_exit { dump("total") }
      end

      def profile(name = nil)
        return if locked?
        return unless init_stack_prof

        options = {
          mode: config.mode,
          raw: config.raw
        }

        options[:interval] = config.interval if config.interval

        if block_given?
          options[:out] = build_path(name)
          ::StackProf.run(options) { yield }
        else
          ::StackProf.start(options)
        end
        true
      end

      def dump(name)
        ::StackProf.stop

        path = build_path(name)

        ::StackProf.results(path)

        log :info, "StackProf report generated: #{path}"

        return unless config.raw

        html_path = path.gsub(/\.dump$/, '.html')

        log :info, <<~MSG
          Run the following command to generate a flame graph report:

          stackprof --flamegraph #{path} > #{html_path} && stackprof --flamegraph-viewer=#{html_path}
        MSG
      end

      private

      def build_path(name)
        TestProf.artefact_path(
          "stack-prof-report-#{config.mode}#{config.raw ? '-raw' : ''}-#{name}.dump"
        )
      end

      def locked?
        @locked == true
      end

      def init_stack_prof
        return @initialized if instance_variable_defined?(:@initialized)
        @initialized = TestProf.require(
          'stackprof',
          <<~MSG
            Please, install 'stackprof' first:
               # Gemfile
              gem 'stackprof', require: false
          MSG
        )
      end
    end
  end
end

require "test_prof/stack_prof/rspec" if defined?(RSpec)

# Hook to run StackProf globally
TestProf.activate('TEST_STACK_PROF') do
  TestProf::StackProf.run
end

{'fraction_non_alphanumeric': 0.09226794611551947, 'fraction_numerical': 0.0011072153533862336, 'mean_word_length': 1.8677248677248677, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1178644', 'n_tokens_mistral': 1670, 'n_tokens_neox': 1590, 'n_words': 444}