Author: tim.bunce
Date: Tue Dec  9 12:31:42 2008
New Revision: 648

Added:
    trunk/t/test61-submerge.p
    trunk/t/test61-submerge.rdt
Modified:
    trunk/MANIFEST
    trunk/NYTProf.xs
    trunk/lib/Devel/NYTProf/Data.pm
    trunk/lib/Devel/NYTProf/FileInfo.pm
    trunk/lib/Devel/NYTProf/SubInfo.pm

Log:
Remove sub_callers element from profile data. Move data about callers to a  
sub
into the sub_subinfo object for that sub.
(sub_caller data is currently regenerated for the dump used by tests.)
Merge anon subs defined on the same line of instances of the same string  
eval.


Modified: trunk/MANIFEST
==============================================================================
--- trunk/MANIFEST      (original)
+++ trunk/MANIFEST      Tue Dec  9 12:31:42 2008
@@ -108,6 +108,8 @@
  t/test50-disable.x
  t/test60-subname.p
  t/test60-subname.rdt
+t/test61-submerge.p
+t/test61-submerge.rdt
  t/test70-subexcl.p
  t/test80-recurs.p
  t/test80-recurs.rdt

Modified: trunk/NYTProf.xs
==============================================================================
--- trunk/NYTProf.xs    (original)
+++ trunk/NYTProf.xs    Tue Dec  9 12:31:42 2008
@@ -2835,7 +2835,6 @@
      AV* fid_block_time_av = NULL;
      AV* fid_sub_time_av = NULL;
      HV* sub_subinfo_hv = newHV();
-    HV* sub_callers_hv = newHV();
      SV *tmp_str_sv = newSVpvn("",0);
      HV *file_info_stash = gv_stashpv("Devel::NYTProf::FileInfo",  
GV_ADDWARN);

@@ -3247,14 +3246,11 @@

                  subinfo_av = lookup_subinfo_av(aTHX_ subname_sv,  
sub_subinfo_hv);

-                /* { 'pkg::sub' => { fid => { line => [ count, incl_time,  
excl_time ] } } } */
-                he = hv_fetch_ent(sub_callers_hv, subname_sv, 1, 0);
-                sv = HeVAL(he);
+                /* { caller_fid => { caller_line => [ count, incl_time,  
excl_time ] } } */
+                sv = *av_fetch(subinfo_av, NYTP_SIi_CALLED_BY, 1);
                  if (!SvROK(sv))                   /* autoviv */
                      sv_setsv(sv, newRV_noinc((SV*)newHV()));

-                sv_setsv(*av_fetch(subinfo_av, NYTP_SIi_CALLED_BY, 1), sv);
-
                  len = sprintf(text, "%u", fid);
                  sv = *hv_fetch((HV*)SvRV(sv), text, len, 1);
                  if (!SvROK(sv))                   /* autoviv */
@@ -3267,8 +3263,9 @@
                      sv = *hv_fetch((HV*)SvRV(sv), text, len, 1);
                      if (!SvROK(sv))               /* autoviv */
                          sv_setsv(sv, newRV_noinc((SV*)newAV()));
-                    else warn("sub_caller info for %s %d:%d already  
exists!",
-                        SvPV_nolen(subname_sv), fid, line);
+                    else /* XXX the code below should accumulate instead  
of set values */
+                        warn("sub caller info for %s %d:%d already  
exists!",
+                            SvPV_nolen(subname_sv), fid, line);
                      sv = SvRV(sv);
                      sv_setuv(*av_fetch((AV *)sv, NYTP_SCi_CALL_COUNT, 1),  
count);
                      sv_setnv(*av_fetch((AV *)sv, NYTP_SCi_INCL_RTIME, 1),  
incl_time);
@@ -3487,7 +3484,6 @@
          SvREFCNT_dec(fid_block_time_av);
          SvREFCNT_dec(fid_sub_time_av);
          SvREFCNT_dec(sub_subinfo_hv);
-        SvREFCNT_dec(sub_callers_hv);
          SvREFCNT_dec(tmp_str_sv);

          return newHV(); /* dummy */
@@ -3540,7 +3536,6 @@
          (void)hv_stores(profile_modes, "fid_sub_time", newSVpvf("sub"));
      }
      (void)hv_stores(profile_hv, "sub_subinfo",       
newRV_noinc((SV*)sub_subinfo_hv));
-    (void)hv_stores(profile_hv, "sub_caller",        
newRV_noinc((SV*)sub_callers_hv));
      (void)hv_stores(profile_hv, "profile_modes",     
newRV_noinc((SV*)profile_modes));
      return profile_hv;
  }

Modified: trunk/lib/Devel/NYTProf/Data.pm
==============================================================================
--- trunk/lib/Devel/NYTProf/Data.pm     (original)
+++ trunk/lib/Devel/NYTProf/Data.pm     Tue Dec  9 12:31:42 2008
@@ -80,10 +80,8 @@

      my $fid_fileinfo = $profile->{fid_fileinfo};
      my $sub_subinfo  = $profile->{sub_subinfo};
-    my $sub_caller   = $profile->{sub_caller};

      #use Data::Dumper; warn Dumper($sub_subinfo);
-    #use Data::Dumper; warn Dumper($sub_caller);

      # add profile ref so fidinfo & subinfo objects
      # XXX circular ref, add weaken
@@ -97,16 +95,15 @@
      # XXX merge evals - should become a method optionally called here
      # (which uses other methods to do the work and those methods
      # should also be called by Devel::NYTProf::SubInfo::callers())
-    my %anon_eval_subs_merged;
      while (my ($subname, $subinfo) = each %$sub_subinfo) {

          # add subname into sub_subinfo
-        $subinfo->[6] = $subname;
+        $subinfo->[6] = $subname; # XXX breaks encapsulation
          if ($subname =~ s/(::__ANON__\[\(\w*eval) \d+\)/$1 0)/) {

              # sub names like "PPI::Node::__ANON__[(eval  
286)[PPI/Node.pm:642]:4]"
              # aren't very useful, so we merge them by changing the eval to  
0
-            my $oldname = $subinfo->[6];
+            my $oldname = $subinfo->subname;
              delete $sub_subinfo->{$oldname};    # delete old name
              if (my $newinfo = $sub_subinfo->{$subname}) {
                  $newinfo->merge_in($subinfo);
@@ -116,44 +113,9 @@

                  # is first to change, so just move ref to new name
                  $sub_subinfo->{$subname} = $subinfo;
-                $subinfo->[6] = $subname;
+                $subinfo->[6] = $subname; # XXX breaks encapsulation
                  warn "renamed sub_info $oldname into $subname\n" if $trace;
              }
-
-            # delete sub_caller info and merge into new name
-            my $old_caller_info = delete $sub_caller->{$oldname};
-
-            # { 'pkg::sub' => { fid => { line => [ count, incl_time ] } }  
} */
-            if (my $newinfo = $sub_caller->{$subname}) {
-
-                # iterate over old and merge info new
-                while (my ($fid, $line_hash) = each %$old_caller_info) {
-                    my $new_line_hash = $newinfo->{$fid};
-                    if (!$new_line_hash) {
-                        $newinfo->{$fid} = $line_hash;
-                        warn "renamed sub_caller $oldname into $subname\n"  
if $trace;
-                        next;
-                    }
-                    warn "merged sub_caller $oldname into $subname\n" if  
$trace;
-
-                    # merge lines in %$line_hash into %$new_line_hash
-                    while (my ($line, $line_info) = each %$line_hash) {
-                        my $new_line_info = $new_line_hash->{$line};
-                        if (!$new_line_info) {
-                            $new_line_hash->{$line} = $line_info;
-                            next;
-                        }
-
-                        # merge @$line_info into @$new_line_info
-                        $new_line_info->[0] += $line_info->[0];
-                        $new_line_info->[1] += $line_info->[1];
-                    }
-
-                }
-            }
-            else {
-                $sub_caller->{$subname} = $old_caller_info;
-            }
          }
      }
      $profile->_clear_caches;
@@ -257,7 +219,7 @@
      }

      # check if already a file info object
-    return $arg if ref $arg and $arg->isa('Devel::NYTProf::FileInfo');
+    return $arg if ref $arg and UNIVERSAL::can($arg,'fid') and  
$arg->isa('Devel::NYTProf::FileInfo');

      my $fid = $self->resolve_fid($arg);
      if (not $fid) {
@@ -320,72 +282,9 @@
  The default format is a Data::Dumper style whitespace-indented tree.
  The types of data present can depend on the options used when profiling.

-  {
-      attribute => {
-          basetime => 1207228764
-          ticks_per_sec => 1000000
-          xs_version => 1.13
-      }
-      fid_fileinfo => [
-          1: [
-              0: test01.p
-              1:
-              2:
-              3: 1
-              4: 0
-              5: 0
-              6: 0
-          ]
-      ]
-      fid_line_time => [
-          1: [
-              2: [ 4e-06 2 ]
-              3: [ 1.2e-05 2 ]
-              7: [ 4.6e-05 4 ]
-              11: [ 2e-06 1 ]
-              16: [ 1.2e-05 1 ]
-          ]
-      ]
-      sub_caller => {
-          main::bar => {
-              1 => {
-                  12 => 1 # main::bar was called by fid 1, line 12, 1 time.
-                  16 => 1
-                  3 => 2
-              }
-          }
-          main::foo => {
-              1 => {
-                  11 => 1
-              }
-          }
-      }
-      sub_subinfo => {
-          main::bar => [ 1 6 8 762 2e-06 ]
-          main::foo => [ 1 1 4 793 1.5e-06 ]
-      }
-  }
-
  If C<separator> is true then instead of whitespace, each item of data is
  indented with the I<path> through the structure with C<separator> used to
  separarate the elements of the path.
-
-  attribute    basetime        1207228260
-  attribute    ticks_per_sec   1000000
-  attribute    xs_version      1.13
-  fid_fileinfo 1       test01.p
-  fid_line_time        1       2       [ 4e-06 2 ]
-  fid_line_time        1       3       [ 1.1e-05 2 ]
-  fid_line_time        1       7       [ 4.4e-05 4 ]
-  fid_line_time        1       11      [ 2e-06 1 ]
-  fid_line_time        1       16      [ 1e-05 1 ]
-  sub_caller   main::bar       1       12      1
-  sub_caller   main::bar       1       16      1
-  sub_caller   main::bar       1       3       2
-  sub_caller   main::foo       1       11      1
-  sub_subinfo  main::bar       [ 1 6 8 762 2e-06 ]
-  sub_subinfo  main::foo       [ 1 1 4 793 1.5e-06 ]
-
  This format is especially useful for grep'ing and diff'ing.

  =cut
@@ -403,7 +302,9 @@
      my $startnode = { %$self, sub_caller => my $sub_caller = {} };
      for my $si (values %{ $self->{sub_subinfo} }) {
          my $sc = $si->callers or next;
-        $sub_caller->{$si->subname} = $sc;
+        my $subname = $si->subname;
+        $subname = $subname->[0] if ref $subname;
+        $sub_caller->{$subname} = $sc;
      }

      $self->_clear_caches;
@@ -588,7 +489,7 @@
      # zero sub into and sub caller times
      $_->normalize_for_test for values %{ $self->{sub_subinfo} };

-    for my $info ($self->{sub_subinfo}, $self->{sub_caller}) {
+    for my $info ($self->{sub_subinfo}) {

          # normalize eval sequence numbers in sub names to 0
          for my $subname (keys %$info) {
@@ -838,8 +739,8 @@

  Returns a reference to a hash containing information about subroutine calls
  made at individual lines within a source file. The $file
-argument can be an integer file id (fid) or a file path. Returns undef if  
the
-profile contains no C<sub_caller> data for the $file.
+argument can be an integer file id (fid) or a file path. Returns undef if
+no subroutine calling information is available.

  The keys of the returned hash are line numbers. The values are references  
to
  hashes with fully qualified subroutine names as keys. Each hash value is an

Modified: trunk/lib/Devel/NYTProf/FileInfo.pm
==============================================================================
--- trunk/lib/Devel/NYTProf/FileInfo.pm (original)
+++ trunk/lib/Devel/NYTProf/FileInfo.pm Tue Dec  9 12:31:42 2008
@@ -120,22 +120,6 @@
      return $f->[0];
  }

-sub delete_subs_called_info {
-    my $self = shift;
-    my $profile = $self->profile;
-    my $sub_caller = $profile->{sub_caller}
-        or return;
-    my $fid = $self->fid;
-    my $total_sub_calls = 0;
-    # remove sub_caller info for calls made *from within* this file
-    for my $sci (values %$sub_caller) {
-        my $info = delete $sci->{$fid};
-        # NYTP_SCi_CALL_COUNT
-        $total_sub_calls += $_->[0] for values %$info;
-    }
-    $profile->{attribute}{total_sub_calls} -= $total_sub_calls;
-    return;
-}

  sub abs_filename {
      my $self = shift;

Modified: trunk/lib/Devel/NYTProf/SubInfo.pm
==============================================================================
--- trunk/lib/Devel/NYTProf/SubInfo.pm  (original)
+++ trunk/lib/Devel/NYTProf/SubInfo.pm  Tue Dec  9 12:31:42 2008
@@ -9,6 +9,7 @@
      NYTP_SIi_CALL_COUNT NYTP_SIi_INCL_RTIME NYTP_SIi_EXCL_RTIME
      NYTP_SIi_SUB_NAME NYTP_SIi_PROFILE
      NYTP_SIi_REC_DEPTH NYTP_SIi_RECI_RTIME NYTP_SIi_CALLED_BY
+
      NYTP_SCi_INCL_RTIME NYTP_SCi_EXCL_RTIME
      NYTP_SCi_INCL_UTIME NYTP_SCi_INCL_STIME NYTP_SCi_RECI_RTIME
  );
@@ -16,15 +17,33 @@
  use List::Util qw(sum min max);

  sub fid        { $_[0]->[NYTP_SIi_FID] || croak "No fid for $_[0][6]" }
+
  sub first_line { shift->[NYTP_SIi_FIRST_LINE] }
+
  sub last_line  { shift->[NYTP_SIi_LAST_LINE] }
+
  sub calls      { shift->[NYTP_SIi_CALL_COUNT] }
+
  sub incl_time  { shift->[NYTP_SIi_INCL_RTIME] }
+
  sub excl_time  { shift->[NYTP_SIi_EXCL_RTIME] }
-sub subname    { shift->[NYTP_SIi_SUB_NAME] }
+
+sub subname    {
+    my $subname = shift->[NYTP_SIi_SUB_NAME];
+    return $subname if not ref $subname;
+    # the subname of a merged sub is a ref to an array of the merged  
subnames
+    # XXX could be ref to an array of the merged subinfos
+    # XXX or better to add a separate accessor instead of abusing subname  
like this
+    return $subname if not defined(my $join = shift);
+    return join $join, @$subname;
+}
+
  sub profile    { shift->[NYTP_SIi_PROFILE] }
+
  sub package    { (my $pkg = shift->subname) =~ s/^(.*)::.*/$1/; return  
$pkg }
+
  sub recur_max_depth { shift->[NYTP_SIi_REC_DEPTH] }
+
  sub recur_incl_time { shift->[NYTP_SIi_RECI_RTIME] }

  # { fid => { line => [ count, incl_time ] } }
@@ -55,22 +74,60 @@
  }

  # merge details of another sub into this one
-# there are few cases where this is sane thing to do
+# there are very few cases where this is sane thing to do
  # it's meant for merging things like anon-subs in evals
  # e.g., "PPI::Node::__ANON__[(eval 286)[PPI/Node.pm:642]:4]"
  sub merge_in {
-    my $self    = shift;
+    my $self = shift;
      my $new = shift;
-    $self->[NYTP_SIi_FIRST_LINE] = min($self->[NYTP_SIi_FIRST_LINE],  
$new->[NYTP_SIi_FIRST_LINE]);
-    $self->[NYTP_SIi_LAST_LINE]  = max($self->[NYTP_SIi_LAST_LINE],   
$new->[NYTP_SIi_LAST_LINE]);
+
+    $self->[NYTP_SIi_FIRST_LINE]  = min($self->[NYTP_SIi_FIRST_LINE],  
$new->[NYTP_SIi_FIRST_LINE]);
+    $self->[NYTP_SIi_LAST_LINE]   = max($self->[NYTP_SIi_LAST_LINE],   
$new->[NYTP_SIi_LAST_LINE]);
      $self->[NYTP_SIi_CALL_COUNT] += $new->[NYTP_SIi_CALL_COUNT];
      $self->[NYTP_SIi_INCL_RTIME] += $new->[NYTP_SIi_INCL_RTIME];
      $self->[NYTP_SIi_EXCL_RTIME] += $new->[NYTP_SIi_EXCL_RTIME];
-    $self->[NYTP_SIi_SUB_NAME] = [ $self->[NYTP_SIi_SUB_NAME] ]
+    $self->[NYTP_SIi_SUB_NAME]    = [ $self->[NYTP_SIi_SUB_NAME] ]
          if not ref $self->[NYTP_SIi_SUB_NAME];
      push @{$self->[NYTP_SIi_SUB_NAME]}, $new->[NYTP_SIi_SUB_NAME];
-    $self->[NYTP_SIi_REC_DEPTH] = max($self->[NYTP_SIi_REC_DEPTH],  
$new->[NYTP_SIi_REC_DEPTH]);
-    $self->[9] = max($self->[NYTP_SIi_RECI_RTIME],  
$new->[NYTP_SIi_RECI_RTIME]); # ug, plausible
+    $self->[NYTP_SIi_REC_DEPTH]   = max($self->[NYTP_SIi_REC_DEPTH],   
$new->[NYTP_SIi_REC_DEPTH]);
+    $self->[NYTP_SIi_RECI_RTIME]  = max($self->[NYTP_SIi_RECI_RTIME],  
$new->[NYTP_SIi_RECI_RTIME]); # ug, plausible
+
+    # { fid => { line => [ count, incl_time ] } }
+    my $dst_called_by = $self->[NYTP_SIi_CALLED_BY] ||= {};
+    my $src_called_by = $new ->[NYTP_SIi_CALLED_BY] ||  {};
+
+    my $trace = 0;
+    my $subname = $self->subname(' and ');
+
+    # iterate over src and merge into dst
+    while (my ($fid, $src_line_hash) = each %$src_called_by) {
+        my $dst_line_hash = $dst_called_by->{$fid};
+        if (!$dst_line_hash) {
+            $dst_called_by->{$fid} = $src_line_hash;
+            warn "renamed sub caller $self->[NYTP_SIi_SUB_NAME] into  
$subname\n" if $trace;
+            next;
+        }
+        warn "merged sub caller $self->[NYTP_SIi_SUB_NAME] into  
$subname\n" if $trace;
+
+        # merge lines in %$src_line_hash into %$dst_line_hash
+        while (my ($line, $src_line_info) = each %$src_line_hash) {
+            my $dst_line_info = $dst_line_hash->{$line};
+            if (!$dst_line_info) {
+                $dst_line_hash->{$line} = $src_line_info;
+                next;
+            }
+
+            # merge @$src_line_info into @$dst_line_info
+            $dst_line_info->[$_] += $src_line_info->[$_] for (
+                NYTP_SCi_INCL_RTIME, NYTP_SCi_EXCL_RTIME,
+                NYTP_SCi_INCL_UTIME, NYTP_SCi_INCL_STIME
+            );
+            # ug, we can't really combine recursive incl_time, but this is  
better than undef
+            $dst_line_info->[NYTP_SCi_RECI_RTIME] =  
max($dst_line_info->[NYTP_SCi_RECI_RTIME],
+                                                         
$src_line_info->[NYTP_SCi_RECI_RTIME]);
+        }
+    }
+
      return;
  }

@@ -122,15 +179,17 @@
      $self->[NYTP_SIi_EXCL_RTIME] = 0;
      $self->[NYTP_SIi_RECI_RTIME] = 0;

-    # zero per-call-location subroutine inclusive time
+    my $subname = $self->subname(' and ');
+
+    # { fid => { line => [ count, incl, excl, ucpu, scpu, reci, recdepth ]  
} }
      my $callers = $self->callers || {};
-    # $callers => { fid => { line => [ count, incl, excl, ucpu, scpu,  
reci, recdepth ] } }
-    for (map { values %$_ } values %$callers) {
-        $_->[NYTP_SCi_INCL_RTIME] =
-        $_->[NYTP_SCi_EXCL_RTIME] =
-        $_->[NYTP_SCi_INCL_UTIME] =
-        $_->[NYTP_SCi_INCL_STIME] =
-        $_->[NYTP_SCi_RECI_RTIME] = 0;
+    # zero per-call-location subroutine inclusive time
+    for my $sc (map { values %$_ } values %$callers) {
+        $sc->[NYTP_SCi_INCL_RTIME] =
+        $sc->[NYTP_SCi_EXCL_RTIME] =
+        $sc->[NYTP_SCi_INCL_UTIME] =
+        $sc->[NYTP_SCi_INCL_STIME] =
+        $sc->[NYTP_SCi_RECI_RTIME] = 0;
      }
  }


Added: trunk/t/test61-submerge.p
==============================================================================
--- (empty file)
+++ trunk/t/test61-submerge.p   Tue Dec  9 12:31:42 2008
@@ -0,0 +1,8 @@
+# test merging of sub info and sub callers
+# which is applied to, e.g., anon subs inside evals
+
+sub foo { print "foo @_\n" }
+
+my $code = 'sub { foo() }';
+
+eval($code)->() for 1..3;

Added: trunk/t/test61-submerge.rdt
==============================================================================
--- (empty file)
+++ trunk/t/test61-submerge.rdt Tue Dec  9 12:31:42 2008
@@ -0,0 +1,45 @@
+attribute      application     test61-submerge.p
+attribute      basetime        0
+attribute      clock_id        0
+attribute      nv_size 0
+attribute      perl_version    0
+attribute      profiler_duration       0
+attribute      profiler_end_time       0
+attribute      profiler_start_time     0
+attribute      ticks_per_sec   0
+attribute      total_stmts_discounted  0
+attribute      total_stmts_duration    0
+attribute      total_stmts_measured    0
+attribute      total_sub_calls 6
+attribute      xs_version      0
+fid_block_time 1       4       [ 0 3 ]
+fid_block_time 1       6       [ 0 1 ]
+fid_block_time 1       8       0       0
+fid_block_time 1       8       1       2
+fid_block_time 1       8       2       1       [ 0 3 ]
+fid_block_time 1       8       2       2       [ 0 3 ]
+fid_fileinfo   1       [ /.../test61-submerge.p   1 2 0 0 ]
+fid_fileinfo   2       [ (eval 0)[test61-submerge.p:8] 1 8 2 2 0 0 ]
+fid_fileinfo   3       [ (eval 0)[test61-submerge.p:8] 1 8 3 2 0 0 ]
+fid_fileinfo   4       [ (eval 0)[test61-submerge.p:8] 1 8 4 2 0 0 ]
+fid_line_time  1       4       [ 0 3 ]
+fid_line_time  1       6       [ 0 1 ]
+fid_line_time  1       8       0       0
+fid_line_time  1       8       1       2
+fid_line_time  1       8       2       1       [ 0 3 ]
+fid_line_time  1       8       2       2       [ 0 3 ]
+fid_sub_time   1       4       [ 0 3 ]
+fid_sub_time   1       6       [ 0 1 ]
+fid_sub_time   1       8       0       0
+fid_sub_time   1       8       1       2
+fid_sub_time   1       8       2       1       [ 0 3 ]
+fid_sub_time   1       8       2       2       [ 0 3 ]
+profile_modes  fid_block_time  block
+profile_modes  fid_line_time   line
+profile_modes  fid_sub_time    sub
+sub_caller     main::__ANON__[(eval 0)[test61-submerge.p:8]:1] 1       8       
[ 1 0 0 0 0  
0 0 ]
+sub_caller     main::foo       2       1       [ 1 0 0 0 0 0 0 ]
+sub_caller     main::foo       3       1       [ 1 0 0 0 0 0 0 ]
+sub_caller     main::foo       4       1       [ 1 0 0 0 0 0 0 ]
+sub_subinfo    main::__ANON__[(eval 0)[test61-submerge.p:8]:1] [ 3 1 1 3 0 0  
0 0 ]
+sub_subinfo    main::foo       [ 1 4 4 3 0 0 0 0 ]

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