Skip to content

Commit

Permalink
Merge pull request #116 from fatkodima/cli-profile-commands
Browse files Browse the repository at this point in the history
Add ability to profile commands via CLI
  • Loading branch information
SamSaffron authored Jun 17, 2024
2 parents 846e6b5 + 9bbdb31 commit c708521
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 29 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Changelog

- Add ability to profile commands via CLI @fatkodima

## 1.0.1 - 23-10-2022

- Adapts tests to Ruby 3.0 / 3.1
Expand Down
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,23 @@ There are two ways to use `memory_profiler`:
### Command Line

The easiest way to use memory_profiler is via the command line, which requires no modifications to your program. The basic usage is:

```
$ ruby-memory-profiler [options] run [--] command [command-options]
```
$ ruby-memory-profiler [options] <script.rb> [--] [script-options]

Example:

```
$ ruby-memory-profiler --pretty run -- rubocop --cache false
$ ruby-memory-profiler --max=10 --pretty run -- ruby notify_users.rb 1 2 3 --quiet
```
Where `script.rb` is the program you want to profile.

For a full list of options, execute the following command:

```
ruby-memory-profiler -h
$ ruby-memory-profiler -h
```

### Convenience API
Expand Down
17 changes: 17 additions & 0 deletions lib/memory_profiler/autorun.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

require "memory_profiler"
require "base64"

def deserialize_hash(data)
Marshal.load(Base64.urlsafe_decode64(data)) if data
end

options = deserialize_hash(ENV["MEMORY_PROFILER_OPTIONS"]) || {}

at_exit do
report = MemoryProfiler.stop
report.pretty_print(**options)
end

MemoryProfiler.start(options)
50 changes: 24 additions & 26 deletions lib/memory_profiler/cli.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require "optparse"
require "base64"

module MemoryProfiler
class CLI
Expand All @@ -14,20 +15,6 @@ class CLI
ignore_files: "memory_profiler/lib"
}.freeze

REPORTER_KEYS = [
:top, :trace, :ignore_files, :allow_files
].freeze

RESULTS_KEYS = [
:to_file, :color_output, :retained_strings, :allocated_strings,
:detailed_report, :scale_bytes, :normalize_paths
].freeze

private_constant :BIN_NAME, :VERSION_INFO,:STATUS_SUCCESS, :STATUS_ERROR,
:DEFAULTS, :REPORTER_KEYS, :RESULTS_KEYS

#

def run(argv)
options = {}
parser = option_parser(options)
Expand All @@ -43,17 +30,24 @@ def run(argv)
return STATUS_ERROR
end

MemoryProfiler.start(reporter_options(options))
load script

STATUS_SUCCESS
if script == "run"
# We are profiling a command.
profile_command(options, argv)
else
# We are profiling a ruby file.
begin
MemoryProfiler.start(options)
load(script)
ensure
report = MemoryProfiler.stop
report.pretty_print(**options)
end
STATUS_SUCCESS
end
rescue OptionParser::InvalidOption, OptionParser::InvalidArgument, OptionParser::MissingArgument => e
puts parser
puts e.message
STATUS_ERROR
ensure
report = MemoryProfiler.stop
report&.pretty_print(**results_options(options))
end

private
Expand All @@ -66,7 +60,7 @@ def option_parser(options)
A Memory Profiler for Ruby
Usage:
#{BIN_NAME} [options] <script.rb> [--] [script-options]
#{BIN_NAME} [options] run [--] command [command-options]
BANNER

opts.separator ""
Expand Down Expand Up @@ -138,12 +132,16 @@ def option_parser(options)
end
end

def reporter_options(options)
options.select { |k, _v| REPORTER_KEYS.include?(k) }
def profile_command(options, argv)
env = {}
env["MEMORY_PROFILER_OPTIONS"] = serialize_hash(options) if options.any?
gem_path = File.expand_path('../', __dir__)
env["RUBYOPT"] = "-I #{gem_path} -r memory_profiler/autorun #{ENV['RUBYOPT']}"
exec(env, *argv)
end

def results_options(options)
options.select { |k, _v| RESULTS_KEYS.include?(k) }
def serialize_hash(hash)
Base64.urlsafe_encode64(Marshal.dump(hash))
end
end
end
5 changes: 5 additions & 0 deletions test/test_cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,9 @@ def test_returns_error_when_script_not_specified
assert_equal 1, result
end
end

def test_profiles_commands
out = `bin/ruby-memory-profiler --pretty run -- ruby -e '[]'`
assert_includes(out, "Total allocated:")
end
end

0 comments on commit c708521

Please sign in to comment.