Class: Roby::App::Debug

Inherits:
Interface::CommandLibrary show all
Defined in:
lib/roby/app/debug.rb

Overview

A command library that allows to control StackProf to profile a Roby application

Instance Attribute Summary

Attributes inherited from Interface::CommandLibrary

#app, #subcommands

Instance Method Summary collapse

Methods inherited from Interface::CommandLibrary

command, #commands, #each_subcommand, #execution_engine, #initialize, #plan, #refresh_subcommands, #subcommand, subcommand

Constructor Details

This class inherits a constructor from Roby::Interface::CommandLibrary

Instance Method Details

#default_path(prefix) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The filename that is used by default in #stackprof_save.

It is a time tag (down to the milliseconds) followed by the sampling mode and a .dump extension



96
97
98
99
100
# File 'lib/roby/app/debug.rb', line 96

def default_path(prefix)
    path = File.join(app.log_dir, "debug")
    time = Time.now.strftime("%Y-%m-%d.%H%M%S.%3N")
    File.join(path, "#{prefix}-#{time}.dump")
end

#memdump(path: default_path("memdump"), run_gc: true) ⇒ Object

Perform a memory dump



119
120
121
122
123
124
125
126
# File 'lib/roby/app/debug.rb', line 119

def memdump(path: default_path("memdump"), run_gc: true)
    FileUtils.mkdir_p File.dirname(path)
    File.open(path, "wb") do |io|
        GC.start(full_mark: true, immediate_sweep: true) if run_gc
        ObjectSpace.dump_all(output: io)
    end
    path
end

#stackprof_active?Boolean

Returns:

  • (Boolean)


72
73
74
# File 'lib/roby/app/debug.rb', line 72

def stackprof_active?
    !!@cycle_counter_handler
end

#stackprof_save(path: default_path("stackprof-%s")) ⇒ Object

Save the current profiling results into the path given to #stackprof_start

Parameters:

  • (String)


105
106
107
108
109
110
111
112
113
114
# File 'lib/roby/app/debug.rb', line 105

def stackprof_save(path: default_path("stackprof-%s"))
    if results = StackProf.results
        path = format(path, results[:mode])
        FileUtils.mkdir_p(File.dirname(path))
        File.open(path, "wb") do |f|
            f.write Marshal.dump(results)
        end
        path
    end
end

#stackprof_start(one_shot: false, cycles: nil, mode: :cpu, interval: nil, raw: false) ⇒ Object

Start profiling

Parameters:

  • one_shot (Boolean) (defaults to: false)

    automatically stop and save after cycles cycles, or one cycle if cycles is nil

  • cycles (Integer) (defaults to: nil)

    a number of cycles after which the profiling is stopped and saved

  • path (String)

    the path into which results should be saved

  • mode (Symbol) (defaults to: :cpu)

    one of :cpu, :wall or :object

  • interval (Integer) (defaults to: nil)

    the sampling interval in microseconds for :cpu and :wall (defaults to 1000, that is 1ms), and the sampling rate in objects allocated for :object (defaults to 1)

  • raw (Boolean) (defaults to: false)

    whether the dump should include raw samples, needed e.g. for flamegraph generation



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/roby/app/debug.rb', line 25

def stackprof_start(one_shot: false, cycles: nil, mode: :cpu, interval: nil, raw: false)
    interval ||= if mode == :object then 1
                 else
                     1000
                 end
    StackProf.start(mode: mode, interval: interval, raw: raw)

    if one_shot && !cycles
        cycles = 1
    end

    if cycles
        remaining_cycles = cycles
        @cycle_counter_handler = execution_engine.at_cycle_begin do
            remaining_cycles -= 1
            if remaining_cycles == 0
                execution_engine.at_cycle_end(once: true) do
                    remaining_cycles = cycles
                    StackProf.stop
                    path = stackprof_save
                    app.notify "profiling", "INFO", "results saved in #{path} after #{cycles} cycles"
                    if one_shot
                        app.notify "profiling", "INFO", "stopped"
                        execution_engine.remove_propagation_handler(@cycle_counter_handler)
                        @cycle_counter_handler = nil
                    else
                        StackProf.start(mode: mode, interval: interval)
                    end
                end
            end
        end
        nil
    end
end

#stackprof_stopObject

Stop profiling

This does not save the results, call #stackprof_save for this



80
81
82
83
84
85
86
# File 'lib/roby/app/debug.rb', line 80

def stackprof_stop
    StackProf.stop
    if @cycle_counter_handler
        execution_engine.remove_propagation_handler(@cycle_counter_handler)
        @cycle_counter_handler = nil
    end
end

#trace_allocations(enable) ⇒ Object

Enable or disable allocation traces for #memdump



133
134
135
136
137
138
139
140
# File 'lib/roby/app/debug.rb', line 133

def trace_allocations(enable)
    if enable
        ObjectSpace.trace_object_allocations_start
    else
        ObjectSpace.trace_object_allocations_stop
        ObjectSpace.trace_object_allocations_clear
    end
end