Author: tim.bunce
Date: Fri Jul 17 05:44:54 2009
New Revision: 834
Modified:
trunk/Changes
trunk/NYTProf.xs
trunk/t/lib/NYTProfTest.pm
Log:
Added reuse of called_sub* details from outer subr_entr if they're
available.
(They're not available for xsubs or slowops, in which case we caclcuate the
caller).
This is fast and gives a well connected call tree: the sub name we called
becomes
the name of the caller when we go deeper. If we were to calculate the caller
each time then in some cases the name would differ. Sometimes the
calculated caller
is more accurate so I've added a findcaller option to enable that.
If a test profile aborts (eg a core dump) then skip the rest of the tests
in the group.
Modified: trunk/Changes
==============================================================================
--- trunk/Changes (original)
+++ trunk/Changes Fri Jul 17 05:44:54 2009
@@ -8,6 +8,7 @@
XXX slowops needs docs and more ops
XXX subroutine profiler docs need update
+XXX doc findcaller option
Note: The file format has changed. Old files can't be read.
Modified: trunk/NYTProf.xs
==============================================================================
--- trunk/NYTProf.xs (original)
+++ trunk/NYTProf.xs Fri Jul 17 05:44:54 2009
@@ -244,7 +244,9 @@
#define profile_stmts options[9].option_value
{ "stmts", 1 }, /* statement exclusive
times */
#define profile_slowops options[10].option_value
- { "slowops", 0 } /* slow opcodes,
typically system calls */
+ { "slowops", 0 }, /* slow opcodes,
typically system calls */
+#define profile_findcaller options[11].option_value
+ { "findcaller", 0 } /* find sub caller
instead of trusting outer */
};
/* time tracking */
@@ -2079,6 +2081,7 @@
struct subr_entry_st {
int completed;
UV subr_call_seqn;
+ I32 prev_subr_entry_ix; /* ix to callers subr_entry */
time_of_day_t initial_call_time;
NV initial_overhead_ticks;
@@ -2086,7 +2089,6 @@
unsigned int caller_fid;
int caller_line;
- CV *caller_cv;
char *caller_subpkg_pv;
SV *caller_subnam_sv;
@@ -2101,6 +2103,9 @@
/* save stack index to the current subroutine entry structure */
static I32 subr_entry_ix = 0;
+#define subr_entry_ix_ptr(ix) ((ix) ? SSPTR(ix, subr_entry_t *) : NULL)
+
+
static void
subr_entry_destroy(pTHX_ subr_entry_t *subr_entry)
{
@@ -2112,6 +2117,7 @@
sv_free(subr_entry->called_subnam_sv);
subr_entry->called_subnam_sv = Nullsv;
}
+ subr_entry_ix = subr_entry->prev_subr_entry_ix;
}
@@ -2263,14 +2269,12 @@
SETERRNO(saved_errno, 0);
}
-
-static void /* wrapper called via scope exit due to
save_destructor below */
+static void /* wrapper called at scope exit due to save_destructor
below */
incr_sub_inclusive_time_ix(pTHX_ void *subr_entry_ix_void)
{
- /* convert the I32-stored-as-void-ptr to an I32, then to a pointer */
+ /* recover the I32 ix that was stored as a void pointer */
I32 save_ix = (I32)PTR2IV(subr_entry_ix_void);
- subr_entry_t *subr_entry = SSPTR(save_ix, subr_entry_t *);
- incr_sub_inclusive_time(aTHX_ subr_entry);
+ incr_sub_inclusive_time(aTHX_ subr_entry_ix_ptr(save_ix));
}
@@ -2395,6 +2399,9 @@
);
if (profile_sub_call) {
+ I32 prev_subr_entry_ix = subr_entry_ix;
+ subr_entry_t *caller_subr_entry =
subr_entry_ix_ptr(prev_subr_entry_ix);
+ char *found_caller_by;
char *file;
int saved_errno = errno;
sub_sv = *SP;
@@ -2409,16 +2416,12 @@
sv_dump(sub_sv);
}
- /* save the current subr_entry_ix, which will be restored just
after the
- * new subr_entry, which we create below, gets processed and
destroyed
- */
- SAVEI32(subr_entry_ix);
-
/* allocate struct to save stack (very efficient) */
/* XXX "warning: cast from pointer to integer of different size"
with use64bitall=define */
subr_entry_ix = SSNEWa(sizeof(*subr_entry), MEM_ALIGNBYTES);
- subr_entry = SSPTR(subr_entry_ix, subr_entry_t *);
- subr_entry->completed = 0;
+ subr_entry = subr_entry_ix_ptr(subr_entry_ix);
+ Zero(subr_entry, 1, sizeof(subr_entry_t));
+ subr_entry->prev_subr_entry_ix = prev_subr_entry_ix;
get_time_of_day(subr_entry->initial_call_time);
subr_entry->initial_overhead_ticks = cumulative_overhead_ticks;
@@ -2431,39 +2434,64 @@
: get_file_id(aTHX_ file, strlen(file), NYTP_FIDf_VIA_SUB);
subr_entry->caller_line = CopLINE(prev_cop);
- /* gather details about the caller */
- subr_entry->caller_cv = current_cv(aTHX_ cxstack_ix, NULL);
- subr_entry->caller_subnam_sv = newSV(0); /* XXX add cache/stack
thing for these SVs */
- if (subr_entry->caller_cv == PL_main_cv) {
- subr_entry->caller_subpkg_pv = "main";
- sv_setpv(subr_entry->caller_subnam_sv, "BEGIN");
- }
- else {
- HV *stash_hv = NULL;
- GV *gv = CvGV(subr_entry->caller_cv);
- GV *egv = GvEGV(gv);
- if (!egv)
- gv = egv;
-
- if (gv && (stash_hv = GvSTASH(gv))) {
- subr_entry->caller_subpkg_pv = HvNAME(stash_hv);
-
sv_setpvn(subr_entry->caller_subnam_sv,GvNAME(gv),GvNAMELEN(gv));
+ /* Gather details about the caller */
+ /* Should we calculate the caller or can we reuse the
caller_subr_entry?
+ * Sometimes we'll have a caller_subr_entry but it won't have the
name yet.
+ * For example if the caller is an xsub or slowop that's
callbacked into perl.
+ */
+ if (profile_findcaller /* user wants us to calculate
each time */
+ || !caller_subr_entry /* we don't have a
caller struct */
+ || !caller_subr_entry->called_subpkg_pv /* we don't have caller
details */
+ || !SvOK(caller_subr_entry->called_subnam_sv)
+ ) {
+ /* get the current CV and determine the current sub name from
that */
+ CV *caller_cv = current_cv(aTHX_ cxstack_ix, NULL);
+ subr_entry->caller_subnam_sv = newSV(0); /* XXX add
cache/stack thing for these SVs */
+
+ if (caller_cv == PL_main_cv) {
+ subr_entry->caller_subpkg_pv = "main";
+ sv_setpv(subr_entry->caller_subnam_sv, "BEGIN");
}
else {
- logwarn("Can't determine name of calling sub (GV %p,
Stash %p, CV flags %d) at %s line %d\n",
- gv, stash_hv, (int)CvFLAGS(subr_entry->caller_cv),
- OutCopFILE(prev_cop), (int)CopLINE(prev_cop));
- sv_dump((SV*)subr_entry->caller_cv);
+ HV *stash_hv = NULL;
+ GV *gv = CvGV(caller_cv);
+ GV *egv = GvEGV(gv);
+ if (!egv)
+ gv = egv;
+
+ if (gv && (stash_hv = GvSTASH(gv))) {
+ subr_entry->caller_subpkg_pv = HvNAME(stash_hv);
+
sv_setpvn(subr_entry->caller_subnam_sv,GvNAME(gv),GvNAMELEN(gv));
+ }
+ else {
+ logwarn("Can't determine name of calling sub (GV %p,
Stash %p, CV flags %d) at %s line %d\n",
+ gv, stash_hv, (int)CvFLAGS(caller_cv),
+ OutCopFILE(prev_cop), (int)CopLINE(prev_cop));
+ sv_dump((SV*)caller_cv);
- subr_entry->caller_subpkg_pv = "__UNKNOWN__";
- sv_setpv(subr_entry->caller_subnam_sv, "__UNKNOWN__");
+ subr_entry->caller_subpkg_pv = "__UNKNOWN__";
+ sv_setpv(subr_entry->caller_subnam_sv, "__UNKNOWN__");
+ }
}
+ found_caller_by = (profile_findcaller) ? "" : "(calculated)";
}
+ else {
+ subr_entry->caller_subpkg_pv =
caller_subr_entry->called_subpkg_pv;
+ subr_entry->caller_subnam_sv =
SvREFCNT_inc(caller_subr_entry->called_subnam_sv);
+ found_caller_by = "(inherited)";
+ }
+
+ if (trace_level >= 4)
+ logwarn("Making sub at %u:%d from %s::%s %s\n",
+ subr_entry->caller_fid, subr_entry->caller_line,
+ subr_entry->caller_subpkg_pv,
+ SvPV_nolen(subr_entry->caller_subnam_sv),
+ found_caller_by
+ );
/* initialize items we'll set later */
subr_entry->called_subnam_sv = &PL_sv_undef; /* see
incr_sub_inclusive_time */
subr_entry->called_is_xs = "?"; /* we don't know yet */
- subr_entry->called_cv_depth = 0;
SETERRNO(saved_errno, 0);
}
@@ -2492,7 +2520,6 @@
*/
save_destructor_x(incr_sub_inclusive_time_ix, INT2PTR(void *,
(IV)subr_entry_ix));
-
called_subnam_sv = newSV(0);
if (is_sop) {
/* pretend builtins are xsubs in the same package
@@ -3138,8 +3165,8 @@
caller_subname_len = fid_line_start-caller_subname;
output_tag_int(NYTP_TAG_SUB_CALLERS, fid);
- output_str(caller_subname, caller_subname_len);
output_int(line);
+ output_str(caller_subname, caller_subname_len);
sc[NYTP_SCi_CALL_COUNT] = output_uv_from_av(aTHX_ av,
NYTP_SCi_CALL_COUNT, 0) * 1.0;
sc[NYTP_SCi_INCL_RTIME] = output_nv_from_av(aTHX_ av,
NYTP_SCi_INCL_RTIME, 0.0);
sc[NYTP_SCi_EXCL_RTIME] = output_nv_from_av(aTHX_ av,
NYTP_SCi_EXCL_RTIME, 0.0);
@@ -3863,8 +3890,8 @@
AV *subinfo_av;
int len;
unsigned int fid = read_int();
- SV *caller_subname_sv = normalize_eval_seqn(aTHX_
read_str(aTHX_ tmp_str2_sv));
unsigned int line = read_int();
+ SV *caller_subname_sv = normalize_eval_seqn(aTHX_
read_str(aTHX_ tmp_str2_sv));
unsigned int count = read_int();
NV incl_time = read_nv();
NV excl_time = read_nv();
@@ -3921,8 +3948,11 @@
sv = *hv_fetch((HV*)SvRV(sv), text, len, 1);
if (!SvROK(sv)) /* autoviv */
sv_setsv(sv, newRV_noinc((SV*)newAV()));
- else if
(!instr(SvPV_nolen(called_subname_sv), "__ANON__[(eval") || trace_level)
- logwarn("Merging extra sub caller info
for %s %d:%d\n",
+ else if (trace_level)
+ /* calls to sub1 from the same fid:line could have
different caller subs
+ * due to evals or if profile_findcaller is off.
+ */
+ logwarn("Merging extra sub caller info for %s
called at %d:%d\n",
SvPV_nolen(called_subname_sv), fid, line);
av = (AV *)SvRV(sv);
sv = *av_fetch(av, NYTP_SCi_CALL_COUNT, 1);
Modified: trunk/t/lib/NYTProfTest.pm
==============================================================================
--- trunk/t/lib/NYTProfTest.pm (original)
+++ trunk/t/lib/NYTProfTest.pm Fri Jul 17 05:44:54 2009
@@ -117,7 +117,8 @@
my $context = "NYTPROF=$ENV{NYTPROF}\n";
($opts{v}) ? warn $context : print $context;
- $code->(\%env);
+ ok eval { $code->(\%env) };
+ diag "Test group aborted: $@" if $@;
# did any tests fail?
my $failed = (count_of_failed_tests() - $prev_failures) ? 1 : 0;
@@ -181,7 +182,7 @@
print "nytprofcvs: $nytprofcsv\n";
}
- my $tests_per_env = number_of_tests(@tests) + $extra_test_count;
+ my $tests_per_env = number_of_tests(@tests) + $extra_test_count + 1;
plan tests => 1 + $tests_per_env * @env_combinations;
@@ -211,6 +212,7 @@
$extra_test_code->($profile, $env);
}
+ return 1;
} );
report_env_influence($group);
@@ -233,7 +235,8 @@
if ($type eq 'p') {
unlink_old_profile_datafiles($profile_datafile);
- profile($test, $profile_datafile);
+ profile($test, $profile_datafile)
+ or die "Profiling $test failed\n";
if ($opts{html}) {
my $cmd = "$perl $nytprofhtml --file=$profile_datafile
--out=$outdir";
@@ -290,7 +293,7 @@
my ($test, $profile_datafile) = @_;
my $cmd = "$perl $opts{profperlopts} $test";
- ok run_command($cmd), "$test runs ok under the profiler";
+ return ok run_command($cmd), "$test runs ok under the profiler";
}
--~--~---------~--~----~------------~-------~--~----~
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]
-~----------~----~----~----~------~----~------~--~---