Skip to content

Commit 0418d1b

Browse files
committed
refactor: move executable logic into gem binaries
1 parent 57b00ea commit 0418d1b

File tree

7 files changed

+151
-69
lines changed

7 files changed

+151
-69
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ recorder.flush_trace(Dir.pwd)
3636
you can currently use it directly with
3737

3838
```bash
39-
ruby gems/codetracer-pure-ruby-recorder/lib/trace.rb [--out-dir DIR] <path to ruby file>
39+
ruby gems/codetracer-pure-ruby-recorder/bin/codetracer-pure-ruby-recorder [--out-dir DIR] <path to ruby file>
4040
# produces several trace json files in DIR,
4141
# or in `$CODETRACER_RUBY_RECORDER_OUT_DIR` if DIR is not provided.
4242
# Defaults to the current directory.
@@ -47,7 +47,7 @@ You can also invoke a lightweight CLI that loads the native tracer extension
4747
directly:
4848

4949
```bash
50-
ruby gems/codetracer-ruby-recorder/lib/native_trace.rb [--out-dir DIR] <path to ruby file>
50+
ruby gems/codetracer-ruby-recorder/bin/codetracer-ruby-recorder [--out-dir DIR] <path to ruby file>
5151
# Uses DIR or `$CODETRACER_RUBY_RECORDER_OUT_DIR` to choose where traces are saved.
5252
```
5353

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,52 @@
11
#!/usr/bin/env ruby
2-
require 'rbconfig'
3-
script = File.expand_path('../lib/trace.rb', __dir__)
4-
exec RbConfig.ruby, script, *ARGV
2+
# SPDX-License-Identifier: MIT
3+
# CLI for the pure Ruby tracer
4+
5+
require 'optparse'
6+
lib_dir = File.expand_path('../lib', __dir__)
7+
$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
8+
require 'codetracer_pure_ruby_recorder'
9+
10+
$tracer = Tracer.new($codetracer_record, debug: ENV['CODETRACER_RUBY_RECORDER_DEBUG'] == '1')
11+
CodetracerKernelPatches.install($tracer)
12+
13+
options = {}
14+
parser = OptionParser.new do |opts|
15+
opts.banner = "usage: codetracer-pure-ruby-recorder [options] <program> [args]"
16+
opts.on('-o DIR', '--out-dir DIR', 'Directory to write trace files') { |dir| options[:out_dir] = dir }
17+
opts.on('-h', '--help', 'Print this help') { puts opts; exit }
18+
end
19+
parser.order!
20+
21+
program = ARGV.shift
22+
if program.nil?
23+
$stderr.puts parser
24+
exit 1
25+
end
26+
27+
$tracer.record.register_call('', 1, '<top-level>', [])
28+
$tracer.ignore('lib/ruby')
29+
$tracer.ignore('trace.rb')
30+
$tracer.ignore('recorder.rb')
31+
$tracer.ignore('<internal:')
32+
$tracer.ignore('gems/')
33+
34+
$tracer.activate
35+
begin
36+
Kernel.load(program)
37+
rescue Exception => e
38+
if $tracer.debug
39+
old_puts ''
40+
old_puts '==== trace.rb error while tracing program ==='
41+
old_puts 'ERROR'
42+
old_puts e
43+
old_puts e.backtrace
44+
old_puts '====================='
45+
old_puts ''
46+
end
47+
end
48+
49+
$tracer.stop_tracing
50+
51+
out_dir = options[:out_dir] || ENV['CODETRACER_RUBY_RECORDER_OUT_DIR'] || Dir.pwd
52+
$tracer.record.serialize(program, out_dir)

gems/codetracer-pure-ruby-recorder/lib/trace.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ def initialize(record, debug: false)
4646
@debug = debug
4747
@record.debug = debug if @record.respond_to?(:debug=)
4848
setup_tracepoints
49+
::Codetracer::KernelPatches.install(self)
4950
end
5051

5152
def stop_tracing
@@ -216,10 +217,10 @@ def load_variables(binding)
216217
end
217218
end
218219

220+
<<<<<<< HEAD
219221
if __FILE__ == $PROGRAM_NAME
220222
$tracer = Tracer.new($codetracer_record, debug: ENV['CODETRACER_RUBY_RECORDER_DEBUG'] == '1')
221-
::Codetracer::KernelPatches.install($tracer)
222-
223+
223224
options = {}
224225
parser = OptionParser.new do |opts|
225226
opts.banner = "usage: ruby trace.rb [options] <program> [args]"
@@ -268,4 +269,4 @@ def load_variables(binding)
268269

269270
out_dir = options[:out_dir] || ENV['CODETRACER_RUBY_RECORDER_OUT_DIR'] || Dir.pwd
270271
$tracer.record.serialize(program, out_dir)
271-
end
272+
end
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
#!/usr/bin/env ruby
2-
require 'rbconfig'
3-
script = File.expand_path('../lib/native_trace.rb', __dir__)
4-
exec RbConfig.ruby, script, *ARGV
2+
# SPDX-License-Identifier: MIT
3+
# CLI wrapper for the native tracer
54

5+
lib_dir = File.expand_path('../lib', __dir__)
6+
$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
7+
require 'native_trace'
8+
exit NativeTrace.execute(ARGV)
Lines changed: 83 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,98 @@
1-
#!/usr/bin/env ruby
21
# SPDX-License-Identifier: MIT
3-
# Simple utility loading the native tracer extension and executing a program.
2+
# Library providing a helper method to execute the native tracer.
43

54
require 'optparse'
65
require 'fileutils'
76
require 'rbconfig'
87
require_relative '../../../codetracer/kernel_patches'
98

10-
options = {}
11-
parser = OptionParser.new do |opts|
12-
opts.banner = "usage: ruby native_trace.rb [options] <program> [args]"
13-
opts.on('-o DIR', '--out-dir DIR', 'Directory to write trace files') do |dir|
14-
options[:out_dir] = dir
15-
end
16-
opts.on('-h', '--help', 'Print this help') do
17-
puts opts
18-
exit
19-
end
20-
end
21-
parser.order!
9+
module NativeTrace
10+
# Execute the native tracer CLI logic with the provided +argv+.
11+
def self.execute(argv)
12+
options = {}
13+
parser = OptionParser.new do |opts|
14+
opts.banner = 'usage: codetracer-ruby-recorder [options] <program> [args]'
15+
opts.on('-o DIR', '--out-dir DIR', 'Directory to write trace files') do |dir|
16+
options[:out_dir] = dir
17+
end
18+
opts.on('-h', '--help', 'Print this help') do
19+
puts opts
20+
return 0
21+
end
22+
end
23+
parser.order!(argv)
2224

23-
if ARGV.empty?
24-
$stderr.puts parser
25-
exit 1
26-
end
25+
if argv.empty?
26+
$stderr.puts parser
27+
return 1
28+
end
2729

28-
out_dir = options[:out_dir] || ENV['CODETRACER_RUBY_RECORDER_OUT_DIR'] || Dir.pwd
29-
ENV['CODETRACER_RUBY_RECORDER_OUT_DIR'] = out_dir
30+
out_dir = options[:out_dir] || ENV['CODETRACER_RUBY_RECORDER_OUT_DIR'] || Dir.pwd
31+
ENV['CODETRACER_RUBY_RECORDER_OUT_DIR'] = out_dir
3032

31-
# Path to the compiled native extension
32-
ext_dir = File.expand_path('../ext/native_tracer/target/release', __dir__)
33-
dlext = RbConfig::CONFIG['DLEXT']
34-
target_path = File.join(ext_dir, "codetracer_ruby_recorder.#{dlext}")
35-
unless File.exist?(target_path)
36-
extensions = %w[so bundle dylib dll]
37-
alt_path = extensions
38-
.map { |ext| File.join(ext_dir, "libcodetracer_ruby_recorder.#{ext}") }
39-
.find { |path| File.exist?(path) }
40-
if alt_path
41-
begin
42-
File.symlink(alt_path, target_path)
43-
rescue StandardError
44-
FileUtils.cp(alt_path, target_path)
33+
ext_dir = File.expand_path('../ext/native_tracer/target/release', __dir__)
34+
dlext = RbConfig::CONFIG['DLEXT']
35+
target_path = File.join(ext_dir, "codetracer_ruby_recorder.#{dlext}")
36+
unless File.exist?(target_path)
37+
extensions = %w[so bundle dylib dll]
38+
alt_path = extensions
39+
.map { |ext| File.join(ext_dir, "libcodetracer_ruby_recorder.#{ext}") }
40+
.find { |path| File.exist?(path) }
41+
if alt_path
42+
begin
43+
File.symlink(alt_path, target_path)
44+
rescue StandardError
45+
FileUtils.cp(alt_path, target_path)
46+
end
47+
end
4548
end
46-
end
47-
end
4849

49-
recorder = nil
50-
begin
51-
require target_path
52-
recorder = RubyRecorder.new
53-
$recorder = recorder
54-
::Codetracer::KernelPatches.install(recorder)
50+
recorder = nil
51+
begin
52+
require target_path
53+
recorder = RubyRecorder.new
54+
$recorder = recorder
5555

56-
rescue Exception => e
57-
warn "native tracer unavailable: #{e}"
58-
end
56+
Kernel.module_eval do
57+
alias :old_p :p
58+
alias :old_puts :puts
59+
alias :old_print :print
5960

60-
program = ARGV.shift
61-
recorder.enable_tracing if recorder
62-
load program
63-
if recorder
64-
recorder.disable_tracing
65-
::Codetracer::KernelPatches.uninstall(recorder)
66-
recorder.flush_trace(out_dir)
67-
end
61+
define_method(:p) do |*args|
62+
if $recorder
63+
loc = caller_locations(1,1).first
64+
$recorder.record_event(loc.path, loc.lineno, args.join("\n"))
65+
end
66+
old_p(*args)
67+
end
6868

69+
define_method(:puts) do |*args|
70+
if $recorder
71+
loc = caller_locations(1,1).first
72+
$recorder.record_event(loc.path, loc.lineno, args.join("\n"))
73+
end
74+
old_puts(*args)
75+
end
76+
77+
define_method(:print) do |*args|
78+
if $recorder
79+
loc = caller_locations(1,1).first
80+
$recorder.record_event(loc.path, loc.lineno, args.join("\n"))
81+
end
82+
old_print(*args)
83+
end
84+
end
85+
rescue Exception => e
86+
warn "native tracer unavailable: #{e}"
87+
end
88+
89+
program = argv.shift
90+
recorder.enable_tracing if recorder
91+
load program
92+
if recorder
93+
recorder.disable_tracing
94+
recorder.flush_trace(out_dir)
95+
end
96+
0
97+
end
98+
end

test/benchmarks/run_benchmarks.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def run_benchmark(name)
5353
native_dir = File.join(TMP_DIR, name, 'native')
5454
FileUtils.mkdir_p(native_dir)
5555
elapsed = Benchmark.realtime do
56-
system(RbConfig.ruby, File.expand_path('../../gems/codetracer-ruby-recorder/lib/native_trace.rb', __dir__),
56+
system(RbConfig.ruby, File.expand_path('../../gems/codetracer-ruby-recorder/bin/codetracer-ruby-recorder', __dir__),
5757
'--out-dir', native_dir, program)
5858
raise 'Native trace failed' unless $?.success?
5959
end
@@ -64,7 +64,7 @@ def run_benchmark(name)
6464
pure_dir = File.join(TMP_DIR, name, 'pure')
6565
FileUtils.mkdir_p(pure_dir)
6666
elapsed = Benchmark.realtime do
67-
system(RbConfig.ruby, File.expand_path('../../gems/codetracer-pure-ruby-recorder/lib/trace.rb', __dir__),
67+
system(RbConfig.ruby, File.expand_path('../../gems/codetracer-pure-ruby-recorder/bin/codetracer-pure-ruby-recorder', __dir__),
6868
'--out-dir', pure_dir, program)
6969
raise 'Pure trace failed' unless $?.success?
7070
end

test/test_tracer.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ def program_args(base)
5151
Dir.glob(File.join(FIXTURE_DIR, '*_trace.json')).each do |fixture|
5252
base = File.basename(fixture, '_trace.json')
5353
define_method("test_#{base}") do
54-
pure_trace, pure_out = run_trace('gems/codetracer-pure-ruby-recorder/lib/trace.rb', "#{base}.rb", *program_args(base))
55-
native_trace, native_out = run_trace('gems/codetracer-ruby-recorder/lib/native_trace.rb', "#{base}.rb", *program_args(base))
54+
pure_trace, pure_out = run_trace('gems/codetracer-pure-ruby-recorder/bin/codetracer-pure-ruby-recorder', "#{base}.rb", *program_args(base))
55+
native_trace, native_out = run_trace('gems/codetracer-ruby-recorder/bin/codetracer-ruby-recorder', "#{base}.rb", *program_args(base))
5656

5757
expected = expected_trace("#{base}.rb")
5858
assert_equal expected, pure_trace
@@ -133,7 +133,7 @@ def test_pure_debug_smoke
133133
env = { 'CODETRACER_RUBY_RECORDER_DEBUG' => '1' }
134134
out_dir = File.join('test', 'tmp', 'debug_smoke')
135135
FileUtils.rm_rf(out_dir)
136-
stdout, stderr, status = Open3.capture3(env, RbConfig.ruby, 'gems/codetracer-pure-ruby-recorder/lib/trace.rb', '--out-dir', out_dir, File.join('test', 'programs', 'addition.rb'))
136+
stdout, stderr, status = Open3.capture3(env, RbConfig.ruby, 'gems/codetracer-pure-ruby-recorder/bin/codetracer-pure-ruby-recorder', '--out-dir', out_dir, File.join('test', 'programs', 'addition.rb'))
137137
raise "trace failed: #{stderr}" unless status.success?
138138

139139
lines = stdout.lines.map(&:chomp)

0 commit comments

Comments
 (0)