Skip to content

Instantly share code, notes, and snippets.

@methodmissing
Created April 17, 2009 23:48
Show Gist options
  • Select an option

  • Save methodmissing/97353 to your computer and use it in GitHub Desktop.

Select an option

Save methodmissing/97353 to your computer and use it in GitHub Desktop.
mri:
thread:
thread_switch:
- char: 'Thread Status'
- int: 'Restore'
cache:
clear_cache:
clear_cache_by_class:
- char: 'Class'
clear_cache_by_id:
- int: 'Id'
marshal:
marshal_dump:
marshal_load:
load:
require:
- char: 'File'
- int: 'Safe level'
parse:
compile:
- char: 'File'
- int: 'Line'
lex:
variable:
global_var_get:
- char: 'Name'
global_var_set:
- char: 'Name'
class_var_get:
- char: 'Class'
- char: 'Name'
class_var_set:
- char: 'Class'
- char: 'Name'
instance_var_get:
- char: 'Class'
- char: 'Name'
instance_var_set:
- char: 'Class'
- char: 'Name'
const_get:
- char: 'Class'
- char: 'Name'
const_set:
- char: 'Class'
- char: 'Name'
gc:
gc_malloc:
gc_calloc:
gc_realloc:
gc_free:
gc_register_address:
gc_unregister_address:
gc_add_heap:
gc_new_object:
gc_data_object_alloc:
gc_source_filename:
- char: 'Class'
gc_mark_source_filename:
- char: 'Class'
gc_sweep_source_filename:
- char: 'Class'
gc_mark_all:
gc_mark_rest:
gc_is_pointer_to_heap:
213-138-234-81:matzruby lourens$ ruby instrument/runtime.rb
provider mri {
probe marshal_dump_start( );
probe marshal_dump_end( );
probe marshal_load_start( );
probe marshal_load_end( );
probe thread_switch_start( char*, int );
probe thread_switch_end( char*, int );
probe clear_cache_by_id_start( int );
probe clear_cache_by_id_end( int );
probe clear_cache_by_class_start( char* );
probe clear_cache_by_class_end( char* );
probe clear_cache_start( );
probe clear_cache_end( );
probe gc_sweep_source_filename_start( char* );
probe gc_sweep_source_filename_end( char* );
probe gc_calloc_start( );
probe gc_calloc_end( );
probe gc_unregister_address_start( );
probe gc_unregister_address_end( );
probe gc_mark_rest_start( );
probe gc_mark_rest_end( );
probe gc_new_object_start( );
probe gc_new_object_end( );
probe gc_add_heap_start( );
probe gc_add_heap_end( );
probe gc_mark_all_start( );
probe gc_mark_all_end( );
probe gc_register_address_start( );
probe gc_register_address_end( );
probe gc_mark_source_filename_start( char* );
probe gc_mark_source_filename_end( char* );
probe gc_free_start( );
probe gc_free_end( );
probe gc_data_object_alloc_start( );
probe gc_data_object_alloc_end( );
probe gc_is_pointer_to_heap_start( );
probe gc_is_pointer_to_heap_end( );
probe gc_realloc_start( );
probe gc_realloc_end( );
probe gc_malloc_start( );
probe gc_malloc_end( );
probe gc_source_filename_start( char* );
probe gc_source_filename_end( char* );
probe instance_var_set_start( char*, char* );
probe instance_var_set_end( char*, char* );
probe class_var_get_start( char*, char* );
probe class_var_get_end( char*, char* );
probe class_var_set_start( char*, char* );
probe class_var_set_end( char*, char* );
probe const_get_start( char*, char* );
probe const_get_end( char*, char* );
probe global_var_get_start( char* );
probe global_var_get_end( char* );
probe global_var_set_start( char* );
probe global_var_set_end( char* );
probe const_set_start( char*, char* );
probe const_set_end( char*, char* );
probe instance_var_get_start( char*, char* );
probe instance_var_get_end( char*, char* );
probe compile_start( char*, int );
probe compile_end( char*, int );
probe lex_start( );
probe lex_end( );
probe require_start( char*, int );
probe require_end( char*, int );
};
#!/usr/sbin/dtrace -Zs
#pragma D option quiet
dtrace:::BEGIN
{
depth = 0;
}
mri*:::lex_start
{
this->lex_start = timestamp;
}
mri*:::lex_end
/lex_start/
{
this->elapsed = timestamp - this->lex_start;
this->lex_start = 0;
this->type = "lex";
@num[this->type] = count();
@eavg[this->type] = avg(this->elapsed);
@esum[this->type] = sum(this->elapsed);
@edist[this->type] = quantize(this->elapsed);
this->depth--;
}
mri*:::thread_switch_start
{
this->thread_switch_start = timestamp;
}
mri*:::thread_switch_end
/thread_switch_start/
{
this->elapsed = timestamp - this->thread_switch_start;
this->thread_switch_start = 0;
this->type = "thread_switch";
@num[this->type] = count();
@eavg[this->type] = avg(this->elapsed);
@esum[this->type] = sum(this->elapsed);
@edist[this->type] = quantize(this->elapsed);
this->depth--;
}
dtrace:::END
{
normalize(@eavg, 1000);
normalize(@esum, 1000);
printf("ELAPSED TIME DISTRIBUTION,
");
printa(@edist);
setopt("aggsortpos", "2");
printf("%-33s %45s
", "___ OVERLAP TIMES: ___", "______ ELAPSED ______");
printf("%-24s %6s %10s %12s
", "TYPE", "COUNT", "AVG(us)", "SUM(us)");
printa("%-24.24s %@6d %@10d %@12d
", @num, @eavg, @esum);
}
require 'yaml'
module Instrument
class Runtime
# Default probe definition location
#
PROBES = File.join( File.dirname(__FILE__), 'mri_trace.yml' )
class Argument < Struct.new(:type, :description)
# Dtrace definition
#
def to_probe
char? ? 'char*' : 'int'
end
# String representation as description
#
def to_s
self.description
end
private
# Is this a character argument ?
#
def char?
self.type == 'char'
end
end
class Probe < Struct.new(:namespace, :group, :name, :arguments)
# Are we the start probe ?
#
def start?
self.name =~ /start/
end
# Dtrace representation
#
def to_probe
"probe #{self.name}( #{arguments_to_probe} );\n"
end
# D source, depending on start or end scope
#
def to_s
start? ? to_s_start : to_s_end
end
# The total amount of columns required
#
def argument_size
@argument_size ||= self.arguments.size
end
private
# Probe arguments
#
def arguments_to_probe
self.arguments.map{|a| a.to_probe }.join(', ')
end
# Probe type
#
def type
@type ||= self.name.gsub( /_(end|start)$/, '' )
end
# Start predicate
#
def start
@start ||= self.name.gsub(/end$/, 'start')
end
# Start definition
#
def to_s_start
%[ mri*:::#{self.name}
{
this->#{self.name} = timestamp;
}\n ]
end
# End definition
#
def to_s_end
%[ mri*:::#{self.name}
/#{start}/
{
this->elapsed = timestamp - this->#{start};
this->#{start} = 0;
this->type = "#{type}";
@num[this->type] = count();
@eavg[this->type] = avg(this->elapsed);
@esum[this->type] = sum(this->elapsed);
@edist[this->type] = quantize(this->elapsed);
this->depth--;
}\n ]
end
end
attr_reader :definition,
:namespace,
:probes
# Accepts the path to a YAML probe definition
#
def initialize( definition = nil )
@definition = definition || PROBES
@probes = []
setup_probes()
end
# Yield a D stream for instrumentation from given group or probe signatures
#
# TODO: regexes
#
def probe( *probes )
stream_with do
probes.map do |probe|
selected_probes( probe.to_s )
end.flatten.map{|p| p.to_s }
end
end
# Dtrace definition
#
def to_definition
%[ provider #{@namespace.to_s} {
#{@probes.map{|p| p.to_probe }.join}
}; ]
end
private
# Dtrace template
#
def stream_with
%[ #!/usr/sbin/dtrace -Zs
#pragma D option quiet
dtrace:::BEGIN
{
depth = 0;
}
#{yield}
dtrace:::END
{
normalize(@eavg, 1000);
normalize(@esum, 1000);
printf("ELAPSED TIME DISTRIBUTION,\n");
printa(@edist);
setopt("aggsortpos", "2");
printf("%-33s %45s\n", "___ OVERLAP TIMES: ___", "______ ELAPSED ______");
printf("%-24s %6s %10s %12s\n", "TYPE", "COUNT", "AVG(us)", "SUM(us)");
printa("%-24.24s %@6d %@10d %@12d\n", @num, @eavg, @esum);
}
]
end
# Find related probes
#
def selected_probes( probe )
if group?( probe )
@probes.select{|p| p.group == probe }
else
@probes.select{|p| p.name =~ /#{probe}/ }
end
end
# Is the given probe a reference to a group ?
#
def group?( probe )
@probes.detect{|p| p.group == probe }
end
# Read and parse the YAML data
#
def read
YAML.load( IO.read( @definition ) )
end
# Init probe definitions
#
def setup_probes
read.each_pair do |namespace,groups|
@namespace = namespace
groups.each do |group|
group.last.each_pair do |probe,arguments|
setup_probe( namespace, group.first, probe, arguments )
end
end
end
end
# Setup a single probe ... spawn both start and end variations
#
def setup_probe( namespace, group, probe, arguments )
%w(start end).each do |suffix|
@probes << Probe.new( namespace, group, "#{probe}_#{suffix}", setup_probe_arguments( arguments ) )
end
end
# Setup probe arguments
#
def setup_probe_arguments( arguments )
Array(arguments).compact.map do |argument|
Argument.new( argument.keys.first, argument.values.first )
end
end
end
end
puts Instrument::Runtime.new.to_definition
puts Instrument::Runtime.new.probe( :lex, :thread )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment