Author: tim.bunce
Date: Wed Jul 15 04:53:40 2009
New Revision: 827
Modified:
trunk/bin/nytprofcg
trunk/bin/nytprofhtml
trunk/lib/Devel/NYTProf/SubInfo.pm
trunk/lib/Devel/NYTProf/js/jit/jit.js
Log:
Implemented a basic interactive Radial Graph view of the subroutine call
tree.
Uses the RGraph visualization
(http://thejit.org/Jit/Examples/RGraph/example1.html)
It's cute, but doesn't scale well to large apps, partly because the nodes
aren't placed very well by JIT.
Modified: trunk/bin/nytprofcg
==============================================================================
--- trunk/bin/nytprofcg (original)
+++ trunk/bin/nytprofcg Wed Jul 15 04:53:40 2009
@@ -41,7 +41,7 @@
for my $sub (values %$subname_subinfo_map) {
- my $callers = $sub->callers;
+ my $callers = $sub->caller_fid_line_places;
next unless ($callers && %$callers);
my $fi = eval { $sub->fileinfo };
Modified: trunk/bin/nytprofhtml
==============================================================================
--- trunk/bin/nytprofhtml (original)
+++ trunk/bin/nytprofhtml Wed Jul 15 04:53:40 2009
@@ -26,6 +26,7 @@
get_abs_paths_alternation_regex
html_safe_filename
);
+use Devel::NYTProf::Constants qw(NYTP_SCi_CALLING_SUB);
our $VERSION = '2.10';
@@ -477,7 +478,7 @@
# for each of the subs defined on this line, who called them
for my $sub_info (@$subs) {
- my $callers = $sub_info->callers;
+ my $callers = $sub_info->caller_fid_line_places;
next unless $callers && %$callers;
my @callers;
@@ -580,7 +581,7 @@
"Subroutine Exclusive Time Treemap", sub { shift->excl_time });
output_subs_treemap_page($reporter, "subs-treemap-incl.html",
"Subroutine Inclusive Time Treemap", sub { shift->incl_time });
-#output_subs_callgraph_page($reporter, "subs-callgraph.html");
+output_subs_callgraph_page($reporter, "subs-callgraph.html");
output_index_page($reporter, "index.html");
output_js_files($reporter);
@@ -672,7 +673,7 @@
}
print OUT q{<br/>You can view subroutines as treemap of <a
href="subs-treemap-excl.html">exclusive</a> or <a
href="subs-treemap-incl.html">inclusive</a> time, grouped by package.<br/>};
- #print OUT q{<br/><a href="subs-callgraph.html">View subroutine call
graph</a><br/>};
+ print OUT q{<br/><a href="subs-callgraph.html">View subroutine call
graph</a><br/>};
print OUT file_table($profile, $stats, 1);
@@ -971,6 +972,7 @@
our $json_any ||= JSON::Any->new;
my $new_args_json = $json_any->objToJson($new_args);
+#$tree_data = do('/tmp/x') or die;
my $tree_data_json = $json_any->objToJson($tree_data);
#http://thejit.org/Jit/Examples/RGraph/example2.code.html
@@ -983,7 +985,7 @@
//Where to inject the canvas. Any div container will do.
'injectInto':'infovis1',
//width and height for canvas. Default's to 200.
- 'width': 900, 'height':500,
+ 'width': 800, 'height':600,
//Optional: Create a background canvas
//for painting concentric circles.
'backgroundCanvas': {
@@ -993,7 +995,7 @@
'impl': {
'init': function(){},
'plot': function(canvas, ctx){
- var times = 6, d = 100;
+ var times = 6, d = 100; // see levelDistance
below
var pi2 = Math.PI * 2;
for (var i = 1; i <= times; i++) {
ctx.beginPath();
@@ -1008,9 +1010,9 @@
var $name = new RGraph(canvas, {
//interpolation type, can be linear or polar
- interpolation: 'linear',
+ //interpolation: 'polar',
//parent-children distance
- levelDistance: 100,
+ levelDistance: 100, // see backgroundCanvas d above
//Set node/edge styles
Node: { color: '#ccddee' },
Edge: { color: '#772277' },
@@ -1021,6 +1023,10 @@
domElement.onclick = function() {
$name.onClick(node.id); };
//Add the node's name into the label
domElement.innerHTML = node.name;
+ var style = domElement.style;
+ style.cursor = 'pointer';
+ style.fontSize = "0.8em";
+ style.color = "#fff";
},
//Change the node's style based on its position.
@@ -1029,17 +1035,25 @@
onPlaceLabel: function(domElement, node){
var style = domElement.style;
style.display = '';
+ domElement.innerHTML = node.name;
if (node._depth <= 1) {
style.fontSize = "0.8em";
+ style.color = "#fff";
+
+ } else if(node._depth <= 2){
+ style.fontSize = "0.5em";
style.color = "#ccc";
- } else if(node._depth == 2){
- style.fontSize = "0.7em";
- style.color = "#494949";
+ } else if(node._depth <= 4){
+ style.fontSize = "0.4em";
+ style.color = "#999";
+ domElement.innerHTML = ' ';
+ //style.display = 'none';
} else {
style.display = 'none';
+ //domElement.innerHTML = ' ';
}
var left = parseInt(style.left);
@@ -1066,7 +1080,18 @@
my $root_id = 'infovis'.$spec{id};
my $callgraph_data = $spec{get_data}->();
- $callgraph_data->{name} = $spec{title} if $spec{title};
+
+
+ my $rg_args = {
+ Node => {
+ 'overridable' => 1,
+ 'color' => '#cc0000',
+ },
+ Edge => {
+ 'overridable' => 1,
+ 'color' => '#cccc00' ,
+ },
+ };
my $cg_js = js_for_new_callgraph($cg_id, { rootId => $root_id },
$callgraph_data);
print OUT qq{<script type="text/javascript">$cg_js\n</script>\n};
@@ -1077,6 +1102,66 @@
sub sub_callgraph_data {
+ my ($profile) = @_;
+ my $subinfos = $profile->subname_subinfo_map;
+
+ my %sub2called; # { subname => { sub_called => [...], ... } }
+
+ for my $subname (keys %$subinfos) {
+ my $si = $subinfos->{$subname};
+
+ # which subs called this sub...
+ my %called_by;
+ if (my $callers = $si->caller_fid_line_places) {
+ # { fid => { line => [...] } } => ([...], ...)
+ my @called_by_sc =
+ map { keys %{$_->[NYTP_SCi_CALLING_SUB]} }
+ map { values %$_ }
+ values %$callers;
+
+ for my $cb_subname (@called_by_sc) {
+ $sub2called{$subname}{$cb_subname} = [];
+ }
+ }
+ }
+
+ # { called_subname => { calling_subname => [...], ... } }
+ my %sub2callers;
+ while ( my ($subname, $subs_called) = each %sub2called ) {
+ while ( my ($called_subname, $call_info) = each %$subs_called ) {
+ $sub2callers{ $called_subname }{$subname} = $call_info;
+ }
+ }
+
+ my $mk_adj = sub {
+ my ($subname, $note) = @_;
+ return {
+ nodeTo => "rg_$subname",
+ data => {
+ note => $note
+ },
+ }
+ };
+
+ my %nodes;
+ for my $subname (keys %$subinfos) {
+ my $si = $subinfos->{$subname};
+
+ my $into = $sub2called{$subname} || {};
+ my $from = $sub2callers{$subname} || {};
+ my %all = (%$into, %$from); # eliminate dups
+
+ my @adjacencies = map { $mk_adj->($_) } keys %all;
+
+ $nodes{$subname} = {
+ id => "rg_$subname",
+ name => $subname,
+ data => {
+ },
+ adjacencies => \...@adjacencies,
+ } if %$into or %$from;
+ }
+ return [ values %nodes ];
}
@@ -1095,7 +1180,7 @@
id => 1,
title => "Subroutine Call Graph",
get_data => sub {
- sub_callgraph_data();
+ sub_callgraph_data($profile);
}
};
Modified: trunk/lib/Devel/NYTProf/SubInfo.pm
==============================================================================
--- trunk/lib/Devel/NYTProf/SubInfo.pm (original)
+++ trunk/lib/Devel/NYTProf/SubInfo.pm Wed Jul 15 04:53:40 2009
@@ -54,7 +54,7 @@
sub recur_incl_time { shift->[NYTP_SIi_RECI_RTIME] }
# { fid => { line => [ count, incl_time ] } }
-sub callers { shift->[NYTP_SIi_CALLED_BY] }
+sub caller_fid_line_places { shift->[NYTP_SIi_CALLED_BY] }
sub is_xsub {
my $self = shift;
@@ -168,7 +168,7 @@
sub caller_fids {
my ($self, $merge_evals) = @_;
- my $callers = $self->callers($merge_evals) || {};
+ my $callers = $self->caller_fid_line_places($merge_evals) || {};
my @fids = keys %$callers;
return @fids; # count in scalar context
}
@@ -178,7 +178,7 @@
# array of [ $fid, $line, $sub_call_info ], ...
sub caller_places {
my ($self, $merge_evals) = @_;
- my $callers = $self->callers || {};
+ my $callers = $self->caller_fid_line_places || {};
my @callers;
for my $fid (sort { $a <=> $b } keys %$callers) {
@@ -202,7 +202,7 @@
my $subname = $self->subname(' and ');
# { fid => { line => [ count, incl, excl, ucpu, scpu, reci, recdepth ]
} }
- my $callers = $self->callers || {};
+ my $callers = $self->caller_fid_line_places || {};
# zero per-call-location subroutine inclusive time
for my $sc (map { values %$_ } values %$callers) {
Modified: trunk/lib/Devel/NYTProf/js/jit/jit.js
==============================================================================
--- trunk/lib/Devel/NYTProf/js/jit/jit.js (original)
+++ trunk/lib/Devel/NYTProf/js/jit/jit.js Wed Jul 15 04:53:40 2009
@@ -3298,7 +3298,12 @@
data = node.data;
node = node.nodeTo;
}
- ans.addAdjacence(json[i], getNode(node), data);
+ var other_node = getNode(node);
+ if (other_node == undefined) {
+ console.log("Graph node "+node+" not defined");
+ continue;
+ }
+ ans.addAdjacence(json[i], other_node, data);
}
}
})(ans, json);
--~--~---------~--~----~------------~-------~--~----~
You've received this message because you are subscribed to
the Devel::NYTProf Development User group.
Group hosted at: http://groups.google.com/group/develnytprof-dev
Project hosted at: http://perl-devel-nytprof.googlecode.com
CPAN distribution: http://search.cpan.org/dist/Devel-NYTProf
To post, email: [email protected]
To unsubscribe, email: [email protected]
-~----------~----~----~----~------~----~------~--~---