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 = '&nbsp;';
+                        //style.display = 'none';

                      } else {
                          style.display = 'none';
+                        //domElement.innerHTML = '&nbsp;';
                      }

                      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]
-~----------~----~----~----~------~----~------~--~---

Reply via email to