Author: tim.bunce
Date: Wed Apr 22 06:50:48 2009
New Revision: 741

Modified:
    trunk/Changes
    trunk/NYTProf.xs
    trunk/bin/nytprofcg
    trunk/lib/Devel/NYTProf.pm
    trunk/t/test50-disable.rdt
    trunk/t/test51-enable.p
    trunk/t/test51-enable.rdt
    trunk/t/test51-enable.t
    trunk/t/test51-enable.x
    trunk/t/test60-subname.rdt

Log:
Fixed call count for XSubs that was one too high.
Minor tweaks to bin/nytprofcg
Added more docs for disable_profile/enable_profile/finish_profile.
Extended tests for disable_profile/enable_profile/finish_profile.
Removed unused sub_xsubs_hv variable.
Avoid infinite loop in eval_outer_fid() when data is corrupt.


Modified: trunk/Changes
==============================================================================
--- trunk/Changes       (original)
+++ trunk/Changes       Wed Apr 22 06:50:48 2009
@@ -4,6 +4,13 @@

  (As of $Date$ $Revision$)

+=head2 Changes in Devel::NYTProf 2.10 (svn rXXX) XXX
+
+  Fixed call count for XSubs that was one too high.
+
+  Added nytprofcg utility to generate callgrind data for
+    viewing via Kcachegrind, thanks to Chia-liang Kao.
+
  =head2 Changes in Devel::NYTProf 2.09 (svn r733) 29th March 2009

    Added support for modules using AutoLoader, e.g., POSIX & Storable,

Modified: trunk/NYTProf.xs
==============================================================================
--- trunk/NYTProf.xs    (original)
+++ trunk/NYTProf.xs    Wed Apr 22 06:50:48 2009
@@ -329,7 +329,6 @@
  static OP *pp_entersub_profiler(pTHX);
  static OP *pp_leaving_profiler(pTHX);
  static HV *sub_callers_hv;
-static HV *sub_xsubs_hv;    /* like PL_DBsub but for xsubs only */
  static HV *pkg_fids_hv;     /* currently just package names */

  /* macros for outputing profile data */
@@ -1742,7 +1741,8 @@
              cop = PL_curcop_nytprof;
          last_executed_line = CopLINE(cop);
          if (!last_executed_line) {                /* i.e. finish_profile  
called by END */
-            if (op)                               /* should never happen */
+            /* XXX maybe code due to command line options, like -Mblib */
+            if (op)
                  warn("Unable to determine line number in %s",  
OutCopFILE(cop));
              last_executed_line = 1;               /* don't want zero line  
numbers in data */
          }
@@ -2284,9 +2284,10 @@
              HV *hv = newHV();
              sv_setsv(sv_tmp, newRV_noinc((SV *)hv));

-            if (is_xs) { /* create dummy item to hold flag to indicate xs  
*/
+            if (is_xs) {
+                /* create dummy item with fid=0 & line=0 to act as flag to  
indicate xs */
                  AV *av = new_sub_call_info_av(aTHX);
-                /* flag to indicate xs */
+                av_store(av, NYTP_SCi_CALL_COUNT, newSVuv(0));
                  sv_setsv(*hv_fetch(hv, "0:0", 3, 1), newRV_noinc((SV  
*)av));

                  if (cv && SvTYPE(cv) == SVt_PVCV) {
@@ -2452,6 +2453,12 @@

      close_output_file(aTHX);

+    /* reset sub profiler data  */
+    hv_clear(sub_callers_hv);
+    /* reset other state */
+    cumulative_overhead_ticks = 0;
+    cumulative_subr_secs = 0;
+
      SETERRNO(saved_errno, 0);
  }

@@ -2523,9 +2530,8 @@
  #endif

      /* create file id mapping hash */
-    hashtable_memwidth = sizeof(Hash_entry*) * hashtable.size;
-    hashtable.table = (Hash_entry**)safemalloc(hashtable_memwidth);
-    memset(hashtable.table, 0, hashtable_memwidth);
+    hashtable.table = (Hash_entry**)safemalloc(sizeof(Hash_entry*) *  
hashtable.size);
+    memset(hashtable.table, 0, sizeof(Hash_entry*) * hashtable.size);

      open_output_file(aTHX_ PROF_output_file);

@@ -2562,8 +2568,6 @@
          sub_callers_hv = newHV();
      if (!pkg_fids_hv)
          pkg_fids_hv = newHV();
-    if (!sub_xsubs_hv)
-        sub_xsubs_hv = newHV();
      PL_ppaddr[OP_ENTERSUB] = pp_entersub_profiler;

      if (!PL_checkav) PL_checkav = newAV();
@@ -3025,20 +3029,25 @@
      unsigned int *eval_file_num_ptr,
      unsigned int *eval_line_num_ptr
  ) {
+    unsigned int outer_fid;
      AV *av;
      SV *fid_info_rvav = *av_fetch(fid_fileinfo_av, fid, 1);
      if (!SvROK(fid_info_rvav)) /* should never happen */
          return 0;
      av = (AV *)SvRV(fid_info_rvav);
-    fid = (unsigned int)SvUV(*av_fetch(av,NYTP_FIDi_EVAL_FID,1));
-    if (!fid)
+    outer_fid = (unsigned int)SvUV(*av_fetch(av,NYTP_FIDi_EVAL_FID,1));
+    if (!outer_fid)
          return 0;
+    if (outer_fid == fid) {
+        warn("Possible corruption: eval_outer_fid of %d is %d!\n", fid,  
outer_fid);
+        return 0;
+    }
      if (eval_file_num_ptr)
-        *eval_file_num_ptr = fid;
+        *eval_file_num_ptr = outer_fid;
      if (eval_line_num_ptr)
          *eval_line_num_ptr = (unsigned  
int)SvUV(*av_fetch(av,NYTP_FIDi_EVAL_LINE,1));
      if (recurse)
-        eval_outer_fid(aTHX_ fid_fileinfo_av, fid, recurse,  
eval_file_num_ptr, eval_line_num_ptr);
+        eval_outer_fid(aTHX_ fid_fileinfo_av, outer_fid, recurse,  
eval_file_num_ptr, eval_line_num_ptr);
      return 1;
  }


Modified: trunk/bin/nytprofcg
==============================================================================
--- trunk/bin/nytprofcg (original)
+++ trunk/bin/nytprofcg Wed Apr 22 06:50:48 2009
@@ -1,10 +1,8 @@
  #!/usr/bin/perl
  ##########################################################
  ## This script is part of the Devel::NYTProf distribution
-##
-## Copyright, contact and other information can be found
-## at the bottom of this file, or by going to:
-## http://search.cpan.org/~akaplan/Devel-NYTProf
+## Released under the same terms as Perl 5.8.0
+## See http://search.cpan.org/dist/Devel-NYTProf/
  ##
  ##########################################################
  # $Id: /mirror/devel-nytprof/bin/nytprofhtml 13295  
2009-04-06T20:34:49.946854Z tim.bunce  $
@@ -16,27 +14,36 @@

  my %opt = (
      file => 'nytprof.out',
-    out  => 'nytprof',
+    out  => 'nytprof.callgrind',
  );

  process_cli();

-print "Generating report...\n";
+print "Reading $opt{file} ...\n";

  my $profile = Devel::NYTProf::Data->new( { filename => $opt{file},
                                             quiet => 1 } );

-open my $fh, '>', $opt{out};
+print "Writing $opt{out} ...\n";
+
+# calltree format specification
+#  
http://kcachegrind.sourceforge.net/cgi-bin/show.cgi/KcacheGrindCalltreeFormat
+
+open my $fh, '>', $opt{out}
+    or die "Can't write to $opt{out}: $!\n";

  print $fh "events: Ticks".$/;
  print $fh $/;


  my %callmap;
+my $subname_subinfo_map = $profile->subname_subinfo_map;
+
+for my $sub (values %$subname_subinfo_map) {

-for my $sub (values %{ $profile->{sub_subinfo} }) {
      my $callers = $sub->callers;
      next unless ($callers && %$callers);
+
      my $fi = eval { $sub->fileinfo };

      print $fh 'fl='.( $fi ? $fi->filename : "Unknown").$/;
@@ -48,6 +55,7 @@
      while ( my ( $fid, $fid_line_info ) = each %$callers ) {
          for my $line ( keys %$fid_line_info ) {
              my ( $count, $incl_time, $excl_time ) = @{  
$fid_line_info->{$line} };
+
              my @subnames = $profile->subname_at_file_line( $fid, $line );
              ref $_ and $_ = sprintf "%s (merge of %d subs)", $_->[0],  
scalar @$_
                  for @subnames;
@@ -86,41 +94,13 @@
  }

  sub process_cli {
-    GetOptions( \%opt, qw/file|f=s delete|d out|o=s lib|l=s help|h open/ )  
or exit 1;
+    GetOptions( \%opt, qw/file|f=s out|o=s help|h/ )
+        or exit 1;

      if ( defined( $opt{help} ) ) {
-        &usage;
+        usage();
          exit 1;
      }
-
-    # handle file selection option
-    if ( !-r $opt{file} ) {
-        die "$0: Unable to access $opt{file}\n";
-    }
-
-    # handle handle output location
-    if ( !-e $opt{out} ) {
-
-        # will be created
-    }
-    elsif ( !-w $opt{out} ) {
-        die "$0: Unable to write to output file `$opt{out}'\n";
-    }
-
-    # handle deleting old db's
-    if ( defined( $opt{'delete'} ) ) {
-        # XXX don't need to
-    }
-
-    # handle custom lib path
-    if ( defined( $opt{lib} ) ) {
-        if ( -d $opt{lib} ) {
-            unshift( @INC, $opt{lib} );
-        }
-        else {
-            die "$0: Specified lib directory `$opt{lib}' does not  
exist.\n";
-        }
-    }
  }

  sub usage {
@@ -132,9 +112,9 @@
   --delete,      -d         Delete the old output [uses --out]
   --help,        -h         Print this message

-This script of part of the Devel::NYTProf package by Adam J Kaplan.
-Copyright 2008 Adam J Kaplan, http://search.cpan.org/~akaplan, Released  
under
-the same terms as Perl itself.
+This script of part of the Devel::NYTProf distribution.
+Released under the same terms as Perl 5.8.0
+See http://search.cpan.org/dist/Devel-NYTProf/
  END
  }


Modified: trunk/lib/Devel/NYTProf.pm
==============================================================================
--- trunk/lib/Devel/NYTProf.pm  (original)
+++ trunk/lib/Devel/NYTProf.pm  Wed Apr 22 06:50:48 2009
@@ -421,19 +421,30 @@
  Using the C<start=no> option lets you leave the profiler disabled initially
  until you call DB::enable_profile() at the right moment.

-You can finish profiling completely by calling DB::finish_profile().
-This may be useful if perl is exiting abnormally, leaving the profile data  
file
-in an incomplete state.  You can use DB::enable_profile() after
-DB::finish_profile() to enable profiling again.  If the filename is not  
given,
-the current profile output file will be overwritten.
-
-=head2 Multiple Output Files
-
-You can pass a filename argument to DB::enable_profile() to make NYTProf  
write
-future profile data to that file. The current output file, if any, is  
closed.
-Any existing file with the new name will be deleted before being written  
to.
-When combined with DB::disable_profile() this lets you profile individual
-sections of code.
+The profile output file can't be used until it's been properly completed  
and
+closed.  Calling DB::disable_profile() doesn't do that.  To make a profile  
file
+usable before the profiled application has completed you can call
+DB::finish_profile(). Alternatively you could call  
DB::enable_profile($newfile).
+
+=head2 DB::disable_profile()
+
+Stops collection of profile data.
+
+Subroutine calls which were made while profiling was enabled and are still  
on
+the call stack (have not yet exited) will still have their profile data
+collected when they exit.
+
+=head2 DB::enable_profile($newfile)
+
+Enables collection of profile data. If $newfile is true the profile data  
will be
+written to $newfile (after completing and closing the previous file, if  
any).
+If $newfile already exists it will be deleted first.
+
+=head2 DB::finish_profile()
+
+Calls DB::disable_profile(), then completes the profile data file by  
writing
+subroutine profile data, and then closes the file. The in memory subroutine
+profile data is then discarded.

  =head1 REPORTS


Modified: trunk/t/test50-disable.rdt
==============================================================================
--- trunk/t/test50-disable.rdt  (original)
+++ trunk/t/test50-disable.rdt  Wed Apr 22 06:50:48 2009
@@ -30,6 +30,6 @@
  profile_modes fid_block_time  block
  profile_modes fid_line_time   line
  profile_modes fid_sub_time    sub
-sub_subinfo    DB::disable_profile     [ undef 0 0 3 0 0 0 0 ]
+sub_subinfo    DB::disable_profile     [ undef 0 0 2 0 0 0 0 ]
  sub_subinfo   DB::disable_profile     called_by       1       2       [ 1 0 0 
0 0 0 0 ]
  sub_subinfo   DB::disable_profile     called_by       1       6       [ 1 0 0 
0 0 0 0 ]

Modified: trunk/t/test51-enable.p
==============================================================================
--- trunk/t/test51-enable.p     (original)
+++ trunk/t/test51-enable.p     Wed Apr 22 06:50:48 2009
@@ -1,20 +1,42 @@
  # test using enable_profile() to write multiple profile files

-sub foo { 1 }
-foo();
+my $file_b = "nytprof-test51-b.out";
+my $file_c = "nytprof-test51-c.out";
+unlink $file_b, $file_c;
+
+eval "sub sub$_ { 1 }" for (1..10);
+
+sub1(); # profiled

  DB::disable_profile();
-foo();
+
+sub2(); # not profiled

  # switch to new file and (re)enable profiling
-DB::enable_profile("nytprof-test51-b.out");
-foo();
+# the new file includes accumulated fid and subs-called data
+DB::enable_profile($file_b);
+
+sub3(); # profiled
+
+DB::finish_profile();
+die "$file_b should exist" unless -s $file_b;
+
+sub4(); # not profiled
+
+# enable to new file
+DB::enable_profile($file_c);
+
+sub5(); # profiled but file will be overwritten by enable_profile() below
+
+DB::finish_profile();
+
+sub6(); # not profiled
+
+DB::enable_profile(); # enable to current file
+
+sub7(); # profiled
+
  DB::finish_profile();
-# switch to new file while already enabled
-DB::enable_profile("nytprof-test51-c.out");
-foo();

  # This can be removed once we have a better test harness
--f $_ or die "$_ should exist"
-    for ("nytprof-test51-b.out", "nytprof-test51-c.out");
-BEGIN { unlink "nytprof-test51-b.out", "nytprof-test51-c.out" }
+-f $_ or die "$_ should exist" for ($file_b, $file_c);

Modified: trunk/t/test51-enable.rdt
==============================================================================
--- trunk/t/test51-enable.rdt   (original)
+++ trunk/t/test51-enable.rdt   Wed Apr 22 06:50:48 2009
@@ -14,20 +14,38 @@
  attribute     xs_version      0
  fid_block_time        1       3       [ 0 1 ]
  fid_block_time        1       4       [ 0 1 ]
+fid_block_time 1       5       [ 0 1 ]
+fid_block_time 1       7       0       0
+fid_block_time 1       7       1       2
+fid_block_time 1       7       2       1       [ 0 1 ]
+fid_block_time 1       9       [ 0 1 ]
  fid_fileinfo  1       [ test51-enable.p   1 2 0 0 ]
-fid_fileinfo   1       sub     main::BEGIN     20-20
-fid_fileinfo   1       sub     main::foo       3-3
-fid_fileinfo   1       call    4       main::foo       [ 1 0 0 0 0 0 0 ]
-fid_fileinfo   1       call    6       DB::disable_profile     [ 1 0 0 0 0 0 0 
]
+fid_fileinfo   1       call    9       main::sub1      [ 1 0 0 0 0 0 0 ]
+fid_fileinfo   1       call    11      DB::disable_profile     [ 1 0 0 0 0 0 0 
]
+fid_fileinfo   1       eval    7       [ 2 0 ]
+fid_fileinfo   2       [ (eval 0)[test51-enable.p:7] 1 7 2 2 0 0 ]
+fid_fileinfo   2       sub     main::sub1      1-1
+fid_fileinfo   3       [ (eval 0)[test51-enable.p:7] 1 7 3 4 0 0 ]
+fid_fileinfo   3       sub     main::sub9      1-1
  fid_line_time 1       3       [ 0 1 ]
  fid_line_time 1       4       [ 0 1 ]
+fid_line_time  1       5       [ 0 1 ]
+fid_line_time  1       7       0       0
+fid_line_time  1       7       1       2
+fid_line_time  1       7       2       1       [ 0 1 ]
+fid_line_time  1       9       [ 0 1 ]
  fid_sub_time  1       3       [ 0 1 ]
  fid_sub_time  1       4       [ 0 1 ]
+fid_sub_time   1       5       [ 0 1 ]
+fid_sub_time   1       7       0       0
+fid_sub_time   1       7       1       2
+fid_sub_time   1       7       2       1       [ 0 1 ]
+fid_sub_time   1       9       [ 0 1 ]
  profile_modes fid_block_time  block
  profile_modes fid_line_time   line
  profile_modes fid_sub_time    sub
-sub_subinfo    DB::disable_profile     [ undef 0 0 2 0 0 0 0 ]
-sub_subinfo    DB::disable_profile     called_by       1       6       [ 1 0 0 
0 0 0 0 ]
-sub_subinfo    main::BEGIN     [ 1 20 20 0 0 0 0 0 ]
-sub_subinfo    main::foo       [ 1 3 3 1 0 0 0 0 ]
-sub_subinfo    main::foo       called_by       1       4       [ 1 0 0 0 0 0 0 
]
+sub_subinfo    DB::disable_profile     [ undef 0 0 1 0 0 0 0 ]
+sub_subinfo    DB::disable_profile     called_by       1       11      [ 1 0 0 
0 0 0 0 ]
+sub_subinfo    main::sub1      [ 2 1 1 1 0 0 0 0 ]
+sub_subinfo    main::sub1      called_by       1       9       [ 1 0 0 0 0 0 0 
]
+sub_subinfo    main::sub9      [ 3 1 1 0 0 0 0 0 ]

Modified: trunk/t/test51-enable.t
==============================================================================
--- trunk/t/test51-enable.t     (original)
+++ trunk/t/test51-enable.t     Wed Apr 22 06:50:48 2009
@@ -3,4 +3,42 @@
  use lib qw(t/lib);
  use NYTProfTest;

-run_test_group;
+run_test_group({
+    extra_test_count => 3,
+    extra_test_code  => sub {
+        my ($profile, $env) = @_;
+
+        is_deeply(sub_calls($profile), {
+            'main::sub1' => 1,
+            'DB::disable_profile' => 1,
+        });
+
+        my $file_b = "nytprof-test51-b.out";
+        my $file_c = "nytprof-test51-c.out";
+
+        my $pb = Devel::NYTProf::Data->new( { filename => $file_b, quiet  
=> 1 } );
+        is_deeply(sub_calls($pb), {
+            'main::sub1' => 1,
+            'main::sub3' => 1,
+            'DB::disable_profile' => 1,
+        }, "$file_b sub calls");
+
+        my $pc = Devel::NYTProf::Data->new( { filename => $file_c, quiet  
=> 1 } );
+        is_deeply(sub_calls($pc), {
+            'main::sub7' => 1,
+            'DB::finish_profile' => 1,
+        }, "$file_c sub calls");
+    },
+});
+
+sub sub_calls {
+    my ($profile) = @_;
+    my %sub_calls;
+    for my $si (values %{ $profile->subname_subinfo_map }) {
+        my $calls = $si->calls
+            or next;
+        $sub_calls{ $si->subname } = $calls;
+    }
+    print "sub_calls: { @{[ %sub_calls ]} }\n";
+    return \%sub_calls;
+}

Modified: trunk/t/test51-enable.x
==============================================================================
--- trunk/t/test51-enable.x     (original)
+++ trunk/t/test51-enable.x     Wed Apr 22 06:50:48 2009
@@ -3,21 +3,43 @@
  # Format: time,calls,time/call,code
  0,0,0,# test using enable_profile() to write multiple profile files
  0,0,0,
-0,1,0,sub foo { 1 }
-0,1,0,foo();
+0,1,0,my $file_b = "nytprof-test51-b.out";
+0,1,0,my $file_c = "nytprof-test51-c.out";
+0,1,0,unlink $file_b, $file_c;
+0,0,0,
+0,2,0,eval "sub sub$_ { 1 }" for (1..10);
+0,0,0,
+0,1,0,sub1(); # profiled
  0,0,0,
  0,0,0,DB::disable_profile();
-0,0,0,foo();
+0,0,0,
+0,0,0,sub2(); # not profiled
  0,0,0,
  0,0,0,# switch to new file and (re)enable profiling
-0,0,0,DB::enable_profile("nytprof-test51-b.out");
-0,0,0,foo();
+0,0,0,# the new file includes accumulated fid and subs-called data
+0,0,0,DB::enable_profile($file_b);
+0,0,0,
+0,0,0,sub3(); # profiled
+0,0,0,
+0,0,0,DB::finish_profile();
+0,0,0,die "$file_b should exist" unless -s $file_b;
+0,0,0,
+0,0,0,sub4(); # not profiled
+0,0,0,
+0,0,0,# enable to new file
+0,0,0,DB::enable_profile($file_c);
+0,0,0,
+0,0,0,sub5(); # profiled but file will be overwritten by enable_profile()  
below
+0,0,0,
+0,0,0,DB::finish_profile();
+0,0,0,
+0,0,0,sub6(); # not profiled
+0,0,0,
+0,0,0,DB::enable_profile(); # enable to current file
+0,0,0,
+0,0,0,sub7(); # profiled
+0,0,0,
  0,0,0,DB::finish_profile();
-0,0,0,# switch to new file while already enabled
-0,0,0,DB::enable_profile("nytprof-test51-c.out");
-0,0,0,foo();
  0,0,0,
  0,0,0,# This can be removed once we have a better test harness
-0,0,0,-f $_ or die "$_ should exist"
-0,0,0,for ("nytprof-test51-b.out", "nytprof-test51-c.out");
-0,0,0,BEGIN { unlink "nytprof-test51-b.out", "nytprof-test51-c.out" }
+0,0,0,-f $_ or die "$_ should exist" for ($file_b, $file_c);

Modified: trunk/t/test60-subname.rdt
==============================================================================
--- trunk/t/test60-subname.rdt  (original)
+++ trunk/t/test60-subname.rdt  Wed Apr 22 06:50:48 2009
@@ -55,7 +55,7 @@
  profile_modes fid_line_time   line
  profile_modes fid_sub_time    sub
  sub_subinfo   Devel::NYTProf::Test::example_sub       [ 2 13 13 0 0 0 0 0 ]
-sub_subinfo    Devel::NYTProf::Test::example_xsub      [ 2 0 0 6 0 0 0 0 ]
+sub_subinfo    Devel::NYTProf::Test::example_xsub      [ 2 0 0 5 0 0 0 0 ]
  sub_subinfo   Devel::NYTProf::Test::example_xsub      called_by       1       
5       [ 1 0 0 0 0 0  
0 ]
  sub_subinfo   Devel::NYTProf::Test::example_xsub      called_by       1       
9       [ 1 0 0 0 0 0  
0 ]
  sub_subinfo   Devel::NYTProf::Test::example_xsub      called_by       1       
12      [ 1 0 0 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