On Thu, Dec 17, 2009 at 01:38:43PM +0000, Tim Bunce wrote:
> On Thu, Dec 17, 2009 at 10:52:35AM +0000, Nicholas Clark wrote:
> > It moves the call to normalize_eval_seqn() after the callback runs.
> > With this change, it's possible to write a program to output a byte-for-byte
> > identical file via the callback interface.
>
> I'm curious about why you might want to do that.
Ah, well. Because you can test whether you've read in and written out *one*
file correctly.
At which point it's not a huge step to read in multiple files, and write one
out...
Which I believe might be useful.
Appended is the summary, attached are all the commits. Should I push these?
(I'm using git-svn)
Nicholas Clark
diff --git a/MANIFEST b/MANIFEST
index fe496a2..096c366 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -12,6 +12,7 @@ benchmark.pl
bin/nytprofcg
bin/nytprofcsv
bin/nytprofhtml
+bin/nytprofmerge
demo/README
demo/demo-code.pl
demo/demo-run.pl
diff --git a/NYTProf.xs b/NYTProf.xs
index 5c9b9a5..2bad944 100644
--- a/NYTProf.xs
+++ b/NYTProf.xs
@@ -361,10 +361,10 @@ static unsigned int ticks_per_sec = 0; /* 0
forces error if not set *
/* prototypes */
static void output_header(pTHX);
-static void output_tag_int(unsigned char tag, unsigned int);
-#define output_int(i) output_tag_int(NYTP_TAG_NO_TAG, (unsigned int)(i))
-static void output_str(char *str, I32 len);
-static void output_nv(NV nv);
+static void output_tag_int(NYTP_file file, unsigned char tag, unsigned int);
+#define output_int(fh, i) output_tag_int(fh, NYTP_TAG_NO_TAG, (unsigned
int)(i))
+static void output_str(NYTP_file file, char *str, I32 len);
+static void output_nv(NYTP_file file, NV nv);
static unsigned int read_int(void);
static SV *read_str(pTHX_ SV *sv);
static unsigned int get_file_id(pTHX_ char*, STRLEN, int created_via);
@@ -971,9 +971,9 @@ output_header(pTHX)
}
#endif
- output_tag_int(NYTP_TAG_PID_START, getpid());
- output_int(getppid());
- output_nv(gettimeofday_nv());
+ output_tag_int(out, NYTP_TAG_PID_START, getpid());
+ output_int(out, getppid());
+ output_nv(out, gettimeofday_nv());
write_cached_fids(); /* empty initially,
non-empty after fork */
@@ -982,7 +982,7 @@ output_header(pTHX)
static void
-output_str(char *str, I32 len) { /* negative len signifies utf8 */
+output_str(NYTP_file file, char *str, I32 len) { /* negative len signifies
utf8 */
unsigned char tag = NYTP_TAG_STRING;
if (len < 0) {
tag = NYTP_TAG_STRING_UTF8;
@@ -990,8 +990,8 @@ output_str(char *str, I32 len) { /* negative len
signifies utf8 */
}
if (trace_level >= 10)
logwarn("output_str('%.*s', %d)\n", (int)len, str, (int)len);
- output_tag_int(tag, len);
- NYTP_write(out, str, len);
+ output_tag_int(file, tag, len);
+ NYTP_write(file, str, len);
}
@@ -1131,12 +1131,12 @@ emit_fid (Hash_entry *fid_info)
file_name = fid_info->key_abs;
file_name_len = strlen(file_name);
}
- output_tag_int(NYTP_TAG_NEW_FID, fid_info->id);
- output_int(fid_info->eval_fid);
- output_int(fid_info->eval_line_num);
- output_int(fid_info->fid_flags);
- output_int(fid_info->file_size);
- output_int(fid_info->file_mtime);
+ output_tag_int(out, NYTP_TAG_NEW_FID, fid_info->id);
+ output_int(out, fid_info->eval_fid);
+ output_int(out, fid_info->eval_line_num);
+ output_int(out, fid_info->fid_flags);
+ output_int(out, fid_info->file_size);
+ output_int(out, fid_info->file_mtime);
#ifdef WIN32
/* Make sure we only use forward slashes in filenames */
@@ -1147,13 +1147,13 @@ emit_fid (Hash_entry *fid_info)
char ch = file_name[i];
file_name_copy[i] = ch == '\\' ? '/' : ch;
}
- output_str(file_name_copy, (I32)file_name_len);
+ output_str(out, file_name_copy, (I32)file_name_len);
Safefree(file_name_copy);
return;
}
#endif
- output_str(file_name, (I32)file_name_len);
+ output_str(out, file_name, (I32)file_name_len);
}
@@ -1446,13 +1446,13 @@ get_file_id(pTHX_ char* file_name, STRLEN
file_name_len, int created_via)
/**
* Output an integer in bytes, optionally preceded by a tag. Use the special
tag
- * NYTP_TAG_NO_TAG to suppress the tag output. A wrapper macro output_int(i)
+ * NYTP_TAG_NO_TAG to suppress the tag output. A wrapper macro output_int(fh,
i)
* does this for you.
* "In bytes" means output the number in binary, using the least number of
bytes
* possible. All numbers are positive. Use sign slot as a marker
*/
static void
-output_tag_int(unsigned char tag, unsigned int i)
+output_tag_int(NYTP_file file, unsigned char tag, unsigned int i)
{
U8 buffer[6];
U8 *p = buffer;
@@ -1486,7 +1486,7 @@ output_tag_int(unsigned char tag, unsigned int i)
*p++ = (U8)(i >> 8);
*p++ = (U8)i;
}
- NYTP_write(out, buffer, p - buffer);
+ NYTP_write(file, buffer, p - buffer);
}
@@ -1495,7 +1495,7 @@ output_uv_from_av(pTHX_ AV *av, int idx, UV default_uv)
{
SV **svp = av_fetch(av, idx, 0);
UV uv = (!svp || !SvOK(*svp)) ? default_uv : SvUV(*svp);
- output_int( uv );
+ output_int( out, uv );
return uv;
}
@@ -1506,9 +1506,9 @@ output_uv_from_av(pTHX_ AV *av, int idx, UV default_uv)
* (Minor portbility issues are seen as less important than speed and space.)
*/
static void
-output_nv(NV nv)
+output_nv(NYTP_file file, NV nv)
{
- NYTP_write(out, (unsigned char *)&nv, sizeof(NV));
+ NYTP_write(file, (unsigned char *)&nv, sizeof(NV));
}
@@ -1517,7 +1517,7 @@ output_nv_from_av(pTHX_ AV *av, int idx, NV default_nv)
{
SV **svp = av_fetch(av, idx, 0);
NV nv = (!svp || !SvOK(*svp)) ? default_nv : SvNV(*svp);
- output_nv( nv );
+ output_nv( out, nv );
return nv;
}
@@ -1855,13 +1855,13 @@ DB_stmt(pTHX_ COP *cop, OP *op)
if (last_executed_fid) {
- output_tag_int((unsigned char)((profile_blocks)
+ output_tag_int(out, (unsigned char)((profile_blocks)
? NYTP_TAG_TIME_BLOCK : NYTP_TAG_TIME_LINE), elapsed);
- output_int(last_executed_fid);
- output_int(last_executed_line);
+ output_int(out, last_executed_fid);
+ output_int(out, last_executed_line);
if (profile_blocks) {
- output_int(last_block_line);
- output_int(last_sub_line);
+ output_int(out, last_block_line);
+ output_int(out, last_sub_line);
}
if (trace_level >= 4)
logwarn("Wrote %d:%-4d %2ld ticks (%u, %u)\n", last_executed_fid,
@@ -2123,8 +2123,8 @@ close_output_file(pTHX) {
/* mark end of profile data for last_pid pid
* which is the pid that this file relates to
*/
- output_tag_int(NYTP_TAG_PID_END, last_pid);
- output_nv(gettimeofday_nv());
+ output_tag_int(out, NYTP_TAG_PID_END, last_pid);
+ output_nv(out, gettimeofday_nv());
if (-1 == NYTP_close(out, 0))
logwarn("Error closing profile data file: %s\n", strerror(errno));
@@ -3503,11 +3503,11 @@ write_sub_line_ranges(pTHX)
logwarn("Sub %s fid %u lines %lu..%lu\n",
sub_name, fid, (unsigned long)first_line, (unsigned
long)last_line);
- output_tag_int(NYTP_TAG_SUB_INFO, fid);
- output_str(sub_name, sub_name_len);
- output_int(first_line);
- output_int(last_line);
- output_int(0); /* how many extra items follow */
+ output_tag_int(out, NYTP_TAG_SUB_INFO, fid);
+ output_str(out, sub_name, sub_name_len);
+ output_int(out, first_line);
+ output_int(out, last_line);
+ output_int(out, 0); /* how many extra items follow */
}
}
@@ -3559,9 +3559,9 @@ write_sub_callers(pTHX)
/* trim length to effectively hide the [fid:line] suffix */
caller_subname_len = fid_line_start-caller_subname;
- output_tag_int(NYTP_TAG_SUB_CALLERS, fid);
- output_int(line);
- output_str(caller_subname, caller_subname_len);
+ output_tag_int(out, NYTP_TAG_SUB_CALLERS, fid);
+ output_int(out, line);
+ output_str(out, 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);
@@ -3569,7 +3569,7 @@ write_sub_callers(pTHX)
sc[NYTP_SCi_INCL_STIME] = output_nv_from_av(aTHX_ av,
NYTP_SCi_INCL_STIME, 0.0);
sc[NYTP_SCi_RECI_RTIME] = output_nv_from_av(aTHX_ av,
NYTP_SCi_RECI_RTIME, 0.0);
sc[NYTP_SCi_REC_DEPTH] = output_uv_from_av(aTHX_ av,
NYTP_SCi_REC_DEPTH , 0) * 1.0;
- output_str(called_subname, called_subname_len);
+ output_str(out, called_subname, called_subname_len);
/* sanity check - early warning */
if (sc[NYTP_SCi_INCL_RTIME] < 0.0 || sc[NYTP_SCi_EXCL_RTIME] <
0.0) {
@@ -3659,9 +3659,9 @@ write_src_of_files(pTHX)
char *src = (svp) ? SvPV(*svp, len) : "";
/* outputting the tag and fid for each (non empty) line
* is a little inefficient, but not enough to worry about */
- output_tag_int(NYTP_TAG_SRC_LINE, e->id);
- output_int(line);
- output_str(src, (I32)len); /* includes newline */
+ output_tag_int(out, NYTP_TAG_SRC_LINE, e->id);
+ output_int(out, line);
+ output_str(out, src, (I32)len); /* includes newline */
if (trace_level >= 5) {
logwarn("fid %d src line %d: %s%s", e->id, line, src,
(*src && src[strlen(src)-1]=='\n') ? "" : "\n");
@@ -4494,7 +4494,7 @@ load_profile_data_from_stream(SV *cb)
HvKEYS(live_pids_hv), profiler_end_time);
store_attrib_sv(aTHX_ attr_hv, "profiler_end_time",
newSVnv(profiler_end_time));
- profiler_duration = profiler_end_time - profiler_start_time;
+ profiler_duration += profiler_end_time - profiler_start_time;
store_attrib_sv(aTHX_ attr_hv, "profiler_duration",
newSVnv(profiler_duration));
break;
@@ -4853,3 +4853,108 @@ SV* cb;
NYTP_close(in, 0);
OUTPUT:
RETVAL
+
+MODULE = Devel::NYTProf PACKAGE = Devel::NYTProf::FileHandle
+
+PROTOTYPES: DISABLE
+
+void
+open(pathname, mode)
+char *pathname
+char *mode
+ PREINIT:
+ NYTP_file fh = NYTP_open(pathname, mode);
+ SV *object;
+ PPCODE:
+ if(!fh)
+ XSRETURN(0);
+ object = newSV(0);
+ sv_usepvn(object, (char *) fh, sizeof(NYTP_file_t));
+ ST(0) = sv_bless(sv_2mortal(newRV_noinc(object)),
gv_stashpvs("Devel::NYTProf::FileHandle", GV_ADD));
+ XSRETURN(1);
+
+int
+DESTROY(handle)
+SV *handle
+ ALIAS:
+ close = 1
+ PREINIT:
+ SV *guts;
+ CODE:
+ if (ix == ix) {
+ /* Unused argument. */
+ }
+ if(!sv_isa(handle, "Devel::NYTProf::FileHandle"))
+ croak("handle is not a Devel::NYTProf::FileHandle");
+ guts = SvRV(handle);
+ RETVAL = NYTP_close((NYTP_file)SvPVX(guts), 0);
+ SvPV_set(guts, NULL);
+ SvLEN_set(guts, 0);
+ OUTPUT:
+ RETVAL
+
+size_t
+write(handle, string)
+SV *handle
+SV *string
+ PREINIT:
+ STRLEN len;
+ char *p;
+ NYTP_file fh;
+ CODE:
+ if(!sv_isa(handle, "Devel::NYTProf::FileHandle"))
+ croak("handle is not a Devel::NYTProf::FileHandle");
+ p = SvPVbyte(string, len);
+ fh = (NYTP_file)SvPVX(SvRV(handle));
+ RETVAL = NYTP_write(fh, p, len);
+ OUTPUT:
+ RETVAL
+
+void
+output_int(handle, ...)
+SV *handle
+ PREINIT:
+ NYTP_file fh;
+ SV **last = sp + items;
+ PPCODE:
+ if(!sv_isa(handle, "Devel::NYTProf::FileHandle"))
+ croak("handle is not a Devel::NYTProf::FileHandle");
+ fh = (NYTP_file)SvPVX(SvRV(handle));
+ ++sp; /* A pointer to the function is first item on the stack.
+ It's not included in items */
+ while(sp++ < last)
+ output_int(fh, SvUV(*sp));
+ XSRETURN(0);
+
+void
+output_nv(handle, ...)
+SV *handle
+NV value
+ PREINIT:
+ NYTP_file fh;
+ SV **last = sp + items;
+ PPCODE:
+ if(!sv_isa(handle, "Devel::NYTProf::FileHandle"))
+ croak("handle is not a Devel::NYTProf::FileHandle");
+ fh = (NYTP_file)SvPVX(SvRV(handle));
+ ++sp; /* A pointer to the function is first item on the stack.
+ It's not included in items */
+ while(sp++ < last)
+ output_nv(fh, SvNV(*sp));
+ XSRETURN(0);
+
+
+void
+output_str(handle, value)
+SV *handle
+SV *value
+ PREINIT:
+ STRLEN len;
+ char *p;
+ NYTP_file fh;
+ CODE:
+ if(!sv_isa(handle, "Devel::NYTProf::FileHandle"))
+ croak("handle is not a Devel::NYTProf::FileHandle");
+ fh = (NYTP_file)SvPVX(SvRV(handle));
+ p = SvPV(value, len);
+ output_str(fh, p, SvUTF8(value) ? -(I32)len : (I32) len);
diff --git a/bin/nytprofmerge b/bin/nytprofmerge
new file mode 100755
index 0000000..c15b0fe
--- /dev/null
+++ b/bin/nytprofmerge
@@ -0,0 +1,205 @@
+#!/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/dist/Devel-NYTProf/
+#
+##########################################################
+# $Id$
+##########################################################
+
+use warnings;
+use strict;
+use Devel::NYTProf::ReadStream qw(for_chunks);
+
+use Getopt::Long;
+use Carp;
+
+my %opt = (
+ out => 'nytprof-merged.out',
+ );
+
+GetOptions(\%opt, qw/out|o=s help|h/)
+ or do {
+ usage();
+ exit 1;
+ };
+
+if (defined($opt{help})) {
+ usage();
+ exit;
+}
+
+sub usage {
+ print <<END
+usage: [perl] nytprofmerge [opts]
+ --out <dir>, -o <dir> Place merged file [default: ./nytprof-merged.out]
+ --help, -h Print this message
+
+This script of part of the Devel::NYTProf distribution.
+See http://search.cpan.org/dist/Devel-NYTProf/ for details and copyright.
+END
+}
+
+my $out = Devel::NYTProf::FileHandle::open($opt{out}, "wb");
+
+my $next_fid = 1;
+my %file_to_fid;
+my %fids = (0 => 0);
+
+my $version;
+my %seen_subs;
+
+my %callers;
+
+sub _time_block_or_line {
+ my ($tag, undef, undef, $ticks, $fid, $line, $block_line, $sub_line) = @_;
+ my $is_line = $tag eq 'TIME_LINE';
+ $out->write($is_line ? '+' : '*');
+ $out->output_int($ticks, $fid, $line);
+ if (!$is_line) {
+ $out->output_int($block_line);
+ $out->output_int($sub_line);
+ }
+}
+
+# Effectively, this is a global variable. Sorry.
+my $input;
+
+my %dispatcher =
+ (
+ VERSION => sub {
+ my (undef, $major, $minor) = @_;
+ my $this_version = "$major $minor";
+ if($version) {
+ die "Incompatible version '$this_version' in $input, expected
'$version'"
+ unless $this_version eq $version;
+ } else {
+ $version = $this_version;
+ $out->write("NYTProf $version\n");
+ }
+ },
+ COMMENT => sub {
+ my (undef, $text) = @_;
+ $out->write("#$text");
+ },
+ ATTRIBUTE => sub {
+ my (undef, $key, $value) = @_;
+ $out->write(":$key=$value\n");
+ },
+
+ START_DEFLATE => sub {
+ },
+
+ PID_START => sub {
+ my (undef, $pid, $parent, $time) = @_;
+ $out->write('P');
+ $out->output_int($pid, $parent);
+ $out->output_nv($time);
+ },
+ PID_END => sub {
+ my (undef, $pid, $time) = @_;
+ $out->write('p');
+ $out->output_int($pid);
+ $out->output_nv($time);
+ },
+
+ NEW_FID => sub {
+ my (undef, $fid, $eval_fid, $eval_line, $flags, $size, $mtime, $name)
= @_;
+ my ($new_fid, $new_eval_fid);
+ if($eval_fid) {
+ $new_eval_fid = $fids{$eval_fid};
+ confess("unknown eval_fid $eval_fid") unless defined $new_eval_fid;
+ $new_fid = $next_fid++;
+ $fids{$fid} = $new_fid;
+ } else {
+ $new_eval_fid = $eval_fid;
+ $new_fid = $file_to_fid{$name};
+ return if defined $new_fid;
+
+ $new_fid = $next_fid++;
+ $fids{$fid} = $new_fid;
+ $file_to_fid{$name} = $fid;
+ }
+ $out->write('@');
+ $out->output_int($new_fid, $new_eval_fid, $eval_line, $flags, $size,
$mtime);
+ $out->output_str($name);
+ },
+ TIME_BLOCK => \&_time_block_or_line,
+ TIME_LINE => \&_time_block_or_line,
+
+ DISCOUNT => sub {
+ $out->write('-');
+ },
+ SUB_INFO => sub {
+ my (undef, $fid, $first_line, $last_line, $name) = @_;
+ if(!$seen_subs{"$fid,$name"}++) {
+ $out->write('s');
+ $out->output_int($fids{$fid});
+ $out->output_str($name);
+ $out->output_int($first_line, $last_line, 0);
+ }
+ },
+ SUB_CALLERS => sub {
+ my (undef, $fid, $line, $count, $incl_time, $excl_time, $ucpu_time,
$scpu_time, $reci_time, $rec_depth, $called, $caller) = @_;
+ $fid = $fids{$fid};
+
+ if ($callers{"$fid,$line"}{$called}{$caller}) {
+ my $sum = $callers{"$fid,$line"}{$called}{$caller};
+ $sum->{count} += $count;
+ $sum->{incl} += $incl_time;
+ $sum->{excl} += $excl_time;
+ $sum->{ucpu} += $ucpu_time;
+ $sum->{scpu} += $scpu_time;
+ $sum->{reci} += $reci_time;
+ $sum->{depth} = $rec_depth if $rec_depth > $sum->{depth};
+ } else {
+ # New;
+ $callers{"$fid,$line"}{$called}{$caller} =
+ {
+ depth => $rec_depth,
+ count => $count,
+ incl => $incl_time,
+ excl => $excl_time,
+ ucpu => $ucpu_time,
+ scpu => $scpu_time,
+ reci => $reci_time,
+ };
+ }
+ },
+ SRC_LINE => sub {
+ my (undef, $fid, $line, $text) = @_;
+ $out->write('S');
+ $out->output_int($fids{$fid}, $line);
+ $out->output_str($text);
+ },
+ );
+
+foreach $input (@ARGV) {
+ for_chunks {
+ my $tag = $_[0];
+
+ my $sub = $dispatcher{$tag};
+ die "Unknown tag '$tag'" unless defined $sub;
+ &$sub(@_);
+ } filename => $input;
+}
+
+# Deterministic order is useful for testing.
+foreach my $fid_line (sort keys %callers) {
+ my ($fid, $line) = split ',', $fid_line;
+ foreach my $called (sort keys %{$callers{$fid_line}}) {
+ foreach my $caller (sort keys %{$callers{$fid_line}{$called}}) {
+ my $sum = $callers{$fid_line}{$called}{$caller};
+ $out->write('c');
+ $out->output_int($fid, $line);
+ $out->output_str($caller);
+ $out->output_int($sum->{count});
+ $out->output_nv(@{$sum}{qw(incl excl ucpu scpu reci)});
+ $out->output_int($sum->{depth});
+ $out->output_str($called);
+ }
+ }
+}
--
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]>From b28874e4271cdf5e20da2a1557863064ae6e6a52 Mon Sep 17 00:00:00 2001
From: Nicholas Clark <[email protected]>
Date: Wed, 16 Dec 2009 13:32:02 +0000
Subject: [PATCH] Create a package Devel::NYTProf::FileHandle which can open and close NYYProf's
file handles.
---
NYTProf.xs | 39 +++++++++++++++++++++++++++++++++++++++
1 files changed, 39 insertions(+), 0 deletions(-)
diff --git a/NYTProf.xs b/NYTProf.xs
index 5c9b9a5..2c13fc1 100644
--- a/NYTProf.xs
+++ b/NYTProf.xs
@@ -4853,3 +4853,42 @@ SV* cb;
NYTP_close(in, 0);
OUTPUT:
RETVAL
+
+MODULE = Devel::NYTProf PACKAGE = Devel::NYTProf::FileHandle
+
+PROTOTYPES: DISABLE
+
+void
+open(pathname, mode)
+char *pathname
+char *mode
+ PREINIT:
+ NYTP_file fh = NYTP_open(pathname, mode);
+ SV *object;
+ PPCODE:
+ if(!fh)
+ XSRETURN(0);
+ object = newSV(0);
+ sv_usepvn(object, (char *) fh, sizeof(NYTP_file_t));
+ ST(0) = sv_bless(sv_2mortal(newRV_noinc(object)), gv_stashpvs("Devel::NYTProf::FileHandle", GV_ADD));
+ XSRETURN(1);
+
+int
+DESTROY(handle)
+SV *handle
+ ALIAS:
+ close = 1
+ PREINIT:
+ SV *guts;
+ CODE:
+ if (ix == ix) {
+ /* Unused argument. */
+ }
+ if(!sv_isa(handle, "Devel::NYTProf::FileHandle"))
+ croak("handle is not a Devel::NYTProf::FileHandle");
+ guts = SvRV(handle);
+ RETVAL = NYTP_close((NYTP_file)SvPVX(guts), 0);
+ SvPV_set(guts, NULL);
+ SvLEN_set(guts, 0);
+ OUTPUT:
+ RETVAL
--
1.6.0
>From f602c348a0faa90d6cbd3fdce690cb679ccbd3fa Mon Sep 17 00:00:00 2001
From: Nicholas Clark <[email protected]>
Date: Wed, 16 Dec 2009 16:11:25 +0000
Subject: [PATCH] Refactor output_int() and output_tag_int() to take an explict file handle.
---
NYTProf.xs | 58 +++++++++++++++++++++++++++++-----------------------------
1 files changed, 29 insertions(+), 29 deletions(-)
diff --git a/NYTProf.xs b/NYTProf.xs
index 2c13fc1..91461c2 100644
--- a/NYTProf.xs
+++ b/NYTProf.xs
@@ -361,8 +361,8 @@ static unsigned int ticks_per_sec = 0; /* 0 forces error if not set *
/* prototypes */
static void output_header(pTHX);
-static void output_tag_int(unsigned char tag, unsigned int);
-#define output_int(i) output_tag_int(NYTP_TAG_NO_TAG, (unsigned int)(i))
+static void output_tag_int(NYTP_file file, unsigned char tag, unsigned int);
+#define output_int(fh, i) output_tag_int(fh, NYTP_TAG_NO_TAG, (unsigned int)(i))
static void output_str(char *str, I32 len);
static void output_nv(NV nv);
static unsigned int read_int(void);
@@ -971,8 +971,8 @@ output_header(pTHX)
}
#endif
- output_tag_int(NYTP_TAG_PID_START, getpid());
- output_int(getppid());
+ output_tag_int(out, NYTP_TAG_PID_START, getpid());
+ output_int(out, getppid());
output_nv(gettimeofday_nv());
write_cached_fids(); /* empty initially, non-empty after fork */
@@ -990,7 +990,7 @@ output_str(char *str, I32 len) { /* negative len signifies utf8 */
}
if (trace_level >= 10)
logwarn("output_str('%.*s', %d)\n", (int)len, str, (int)len);
- output_tag_int(tag, len);
+ output_tag_int(out, tag, len);
NYTP_write(out, str, len);
}
@@ -1131,12 +1131,12 @@ emit_fid (Hash_entry *fid_info)
file_name = fid_info->key_abs;
file_name_len = strlen(file_name);
}
- output_tag_int(NYTP_TAG_NEW_FID, fid_info->id);
- output_int(fid_info->eval_fid);
- output_int(fid_info->eval_line_num);
- output_int(fid_info->fid_flags);
- output_int(fid_info->file_size);
- output_int(fid_info->file_mtime);
+ output_tag_int(out, NYTP_TAG_NEW_FID, fid_info->id);
+ output_int(out, fid_info->eval_fid);
+ output_int(out, fid_info->eval_line_num);
+ output_int(out, fid_info->fid_flags);
+ output_int(out, fid_info->file_size);
+ output_int(out, fid_info->file_mtime);
#ifdef WIN32
/* Make sure we only use forward slashes in filenames */
@@ -1446,13 +1446,13 @@ get_file_id(pTHX_ char* file_name, STRLEN file_name_len, int created_via)
/**
* Output an integer in bytes, optionally preceded by a tag. Use the special tag
- * NYTP_TAG_NO_TAG to suppress the tag output. A wrapper macro output_int(i)
+ * NYTP_TAG_NO_TAG to suppress the tag output. A wrapper macro output_int(fh, i)
* does this for you.
* "In bytes" means output the number in binary, using the least number of bytes
* possible. All numbers are positive. Use sign slot as a marker
*/
static void
-output_tag_int(unsigned char tag, unsigned int i)
+output_tag_int(NYTP_file file, unsigned char tag, unsigned int i)
{
U8 buffer[6];
U8 *p = buffer;
@@ -1486,7 +1486,7 @@ output_tag_int(unsigned char tag, unsigned int i)
*p++ = (U8)(i >> 8);
*p++ = (U8)i;
}
- NYTP_write(out, buffer, p - buffer);
+ NYTP_write(file, buffer, p - buffer);
}
@@ -1495,7 +1495,7 @@ output_uv_from_av(pTHX_ AV *av, int idx, UV default_uv)
{
SV **svp = av_fetch(av, idx, 0);
UV uv = (!svp || !SvOK(*svp)) ? default_uv : SvUV(*svp);
- output_int( uv );
+ output_int( out, uv );
return uv;
}
@@ -1855,13 +1855,13 @@ DB_stmt(pTHX_ COP *cop, OP *op)
if (last_executed_fid) {
- output_tag_int((unsigned char)((profile_blocks)
+ output_tag_int(out, (unsigned char)((profile_blocks)
? NYTP_TAG_TIME_BLOCK : NYTP_TAG_TIME_LINE), elapsed);
- output_int(last_executed_fid);
- output_int(last_executed_line);
+ output_int(out, last_executed_fid);
+ output_int(out, last_executed_line);
if (profile_blocks) {
- output_int(last_block_line);
- output_int(last_sub_line);
+ output_int(out, last_block_line);
+ output_int(out, last_sub_line);
}
if (trace_level >= 4)
logwarn("Wrote %d:%-4d %2ld ticks (%u, %u)\n", last_executed_fid,
@@ -2123,7 +2123,7 @@ close_output_file(pTHX) {
/* mark end of profile data for last_pid pid
* which is the pid that this file relates to
*/
- output_tag_int(NYTP_TAG_PID_END, last_pid);
+ output_tag_int(out, NYTP_TAG_PID_END, last_pid);
output_nv(gettimeofday_nv());
if (-1 == NYTP_close(out, 0))
@@ -3503,11 +3503,11 @@ write_sub_line_ranges(pTHX)
logwarn("Sub %s fid %u lines %lu..%lu\n",
sub_name, fid, (unsigned long)first_line, (unsigned long)last_line);
- output_tag_int(NYTP_TAG_SUB_INFO, fid);
+ output_tag_int(out, NYTP_TAG_SUB_INFO, fid);
output_str(sub_name, sub_name_len);
- output_int(first_line);
- output_int(last_line);
- output_int(0); /* how many extra items follow */
+ output_int(out, first_line);
+ output_int(out, last_line);
+ output_int(out, 0); /* how many extra items follow */
}
}
@@ -3559,8 +3559,8 @@ write_sub_callers(pTHX)
/* trim length to effectively hide the [fid:line] suffix */
caller_subname_len = fid_line_start-caller_subname;
- output_tag_int(NYTP_TAG_SUB_CALLERS, fid);
- output_int(line);
+ output_tag_int(out, NYTP_TAG_SUB_CALLERS, fid);
+ output_int(out, 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);
@@ -3659,8 +3659,8 @@ write_src_of_files(pTHX)
char *src = (svp) ? SvPV(*svp, len) : "";
/* outputting the tag and fid for each (non empty) line
* is a little inefficient, but not enough to worry about */
- output_tag_int(NYTP_TAG_SRC_LINE, e->id);
- output_int(line);
+ output_tag_int(out, NYTP_TAG_SRC_LINE, e->id);
+ output_int(out, line);
output_str(src, (I32)len); /* includes newline */
if (trace_level >= 5) {
logwarn("fid %d src line %d: %s%s", e->id, line, src,
--
1.6.0
>From 59baad18f78045ffafdfa5435f590813f3d25f1e Mon Sep 17 00:00:00 2001
From: Nicholas Clark <[email protected]>
Date: Wed, 16 Dec 2009 16:16:31 +0000
Subject: [PATCH] Refactor output_nv() to take an explict file handle.
---
NYTProf.xs | 12 ++++++------
1 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/NYTProf.xs b/NYTProf.xs
index 91461c2..457fb73 100644
--- a/NYTProf.xs
+++ b/NYTProf.xs
@@ -364,7 +364,7 @@ static void output_header(pTHX);
static void output_tag_int(NYTP_file file, unsigned char tag, unsigned int);
#define output_int(fh, i) output_tag_int(fh, NYTP_TAG_NO_TAG, (unsigned int)(i))
static void output_str(char *str, I32 len);
-static void output_nv(NV nv);
+static void output_nv(NYTP_file file, NV nv);
static unsigned int read_int(void);
static SV *read_str(pTHX_ SV *sv);
static unsigned int get_file_id(pTHX_ char*, STRLEN, int created_via);
@@ -973,7 +973,7 @@ output_header(pTHX)
output_tag_int(out, NYTP_TAG_PID_START, getpid());
output_int(out, getppid());
- output_nv(gettimeofday_nv());
+ output_nv(out, gettimeofday_nv());
write_cached_fids(); /* empty initially, non-empty after fork */
@@ -1506,9 +1506,9 @@ output_uv_from_av(pTHX_ AV *av, int idx, UV default_uv)
* (Minor portbility issues are seen as less important than speed and space.)
*/
static void
-output_nv(NV nv)
+output_nv(NYTP_file file, NV nv)
{
- NYTP_write(out, (unsigned char *)&nv, sizeof(NV));
+ NYTP_write(file, (unsigned char *)&nv, sizeof(NV));
}
@@ -1517,7 +1517,7 @@ output_nv_from_av(pTHX_ AV *av, int idx, NV default_nv)
{
SV **svp = av_fetch(av, idx, 0);
NV nv = (!svp || !SvOK(*svp)) ? default_nv : SvNV(*svp);
- output_nv( nv );
+ output_nv( out, nv );
return nv;
}
@@ -2124,7 +2124,7 @@ close_output_file(pTHX) {
* which is the pid that this file relates to
*/
output_tag_int(out, NYTP_TAG_PID_END, last_pid);
- output_nv(gettimeofday_nv());
+ output_nv(out, gettimeofday_nv());
if (-1 == NYTP_close(out, 0))
logwarn("Error closing profile data file: %s\n", strerror(errno));
--
1.6.0
>From 126cca93496d090f45d0f74cba2d95a4721fb968 Mon Sep 17 00:00:00 2001
From: Nicholas Clark <[email protected]>
Date: Wed, 16 Dec 2009 16:18:59 +0000
Subject: [PATCH] Refactor output_str() to take an explict file handle.
---
NYTProf.xs | 20 ++++++++++----------
1 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/NYTProf.xs b/NYTProf.xs
index 457fb73..26e6d22 100644
--- a/NYTProf.xs
+++ b/NYTProf.xs
@@ -363,7 +363,7 @@ static unsigned int ticks_per_sec = 0; /* 0 forces error if not set *
static void output_header(pTHX);
static void output_tag_int(NYTP_file file, unsigned char tag, unsigned int);
#define output_int(fh, i) output_tag_int(fh, NYTP_TAG_NO_TAG, (unsigned int)(i))
-static void output_str(char *str, I32 len);
+static void output_str(NYTP_file file, char *str, I32 len);
static void output_nv(NYTP_file file, NV nv);
static unsigned int read_int(void);
static SV *read_str(pTHX_ SV *sv);
@@ -982,7 +982,7 @@ output_header(pTHX)
static void
-output_str(char *str, I32 len) { /* negative len signifies utf8 */
+output_str(NYTP_file file, char *str, I32 len) { /* negative len signifies utf8 */
unsigned char tag = NYTP_TAG_STRING;
if (len < 0) {
tag = NYTP_TAG_STRING_UTF8;
@@ -990,8 +990,8 @@ output_str(char *str, I32 len) { /* negative len signifies utf8 */
}
if (trace_level >= 10)
logwarn("output_str('%.*s', %d)\n", (int)len, str, (int)len);
- output_tag_int(out, tag, len);
- NYTP_write(out, str, len);
+ output_tag_int(file, tag, len);
+ NYTP_write(file, str, len);
}
@@ -1147,13 +1147,13 @@ emit_fid (Hash_entry *fid_info)
char ch = file_name[i];
file_name_copy[i] = ch == '\\' ? '/' : ch;
}
- output_str(file_name_copy, (I32)file_name_len);
+ output_str(out, file_name_copy, (I32)file_name_len);
Safefree(file_name_copy);
return;
}
#endif
- output_str(file_name, (I32)file_name_len);
+ output_str(out, file_name, (I32)file_name_len);
}
@@ -3504,7 +3504,7 @@ write_sub_line_ranges(pTHX)
sub_name, fid, (unsigned long)first_line, (unsigned long)last_line);
output_tag_int(out, NYTP_TAG_SUB_INFO, fid);
- output_str(sub_name, sub_name_len);
+ output_str(out, sub_name, sub_name_len);
output_int(out, first_line);
output_int(out, last_line);
output_int(out, 0); /* how many extra items follow */
@@ -3561,7 +3561,7 @@ write_sub_callers(pTHX)
output_tag_int(out, NYTP_TAG_SUB_CALLERS, fid);
output_int(out, line);
- output_str(caller_subname, caller_subname_len);
+ output_str(out, 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);
@@ -3569,7 +3569,7 @@ write_sub_callers(pTHX)
sc[NYTP_SCi_INCL_STIME] = output_nv_from_av(aTHX_ av, NYTP_SCi_INCL_STIME, 0.0);
sc[NYTP_SCi_RECI_RTIME] = output_nv_from_av(aTHX_ av, NYTP_SCi_RECI_RTIME, 0.0);
sc[NYTP_SCi_REC_DEPTH] = output_uv_from_av(aTHX_ av, NYTP_SCi_REC_DEPTH , 0) * 1.0;
- output_str(called_subname, called_subname_len);
+ output_str(out, called_subname, called_subname_len);
/* sanity check - early warning */
if (sc[NYTP_SCi_INCL_RTIME] < 0.0 || sc[NYTP_SCi_EXCL_RTIME] < 0.0) {
@@ -3661,7 +3661,7 @@ write_src_of_files(pTHX)
* is a little inefficient, but not enough to worry about */
output_tag_int(out, NYTP_TAG_SRC_LINE, e->id);
output_int(out, line);
- output_str(src, (I32)len); /* includes newline */
+ output_str(out, src, (I32)len); /* includes newline */
if (trace_level >= 5) {
logwarn("fid %d src line %d: %s%s", e->id, line, src,
(*src && src[strlen(src)-1]=='\n') ? "" : "\n");
--
1.6.0
>From 929ae42738461e568cd2045d196a3a9f02cfc7a5 Mon Sep 17 00:00:00 2001
From: Nicholas Clark <[email protected]>
Date: Wed, 16 Dec 2009 17:53:53 +0000
Subject: [PATCH] Add methods write(), output_int(), output_nv() and output_str() to
Devel::NYTProf::FileHandle. It's now possible to write out a profile file from
Perl.
---
NYTProf.xs | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 57 insertions(+), 0 deletions(-)
diff --git a/NYTProf.xs b/NYTProf.xs
index 26e6d22..c39ad96 100644
--- a/NYTProf.xs
+++ b/NYTProf.xs
@@ -4892,3 +4892,60 @@ SV *handle
SvLEN_set(guts, 0);
OUTPUT:
RETVAL
+
+size_t
+write(handle, string)
+SV *handle
+SV *string
+ PREINIT:
+ STRLEN len;
+ char *p;
+ NYTP_file fh;
+ CODE:
+ if(!sv_isa(handle, "Devel::NYTProf::FileHandle"))
+ croak("handle is not a Devel::NYTProf::FileHandle");
+ p = SvPVbyte(string, len);
+ fh = (NYTP_file)SvPVX(SvRV(handle));
+ RETVAL = NYTP_write(fh, p, len);
+ OUTPUT:
+ RETVAL
+
+void
+output_int(handle, value)
+SV *handle
+unsigned int value
+ PREINIT:
+ NYTP_file fh;
+ CODE:
+ if(!sv_isa(handle, "Devel::NYTProf::FileHandle"))
+ croak("handle is not a Devel::NYTProf::FileHandle");
+ fh = (NYTP_file)SvPVX(SvRV(handle));
+ output_int(fh, value);
+
+void
+output_nv(handle, value)
+SV *handle
+NV value
+ PREINIT:
+ NYTP_file fh;
+ CODE:
+ if(!sv_isa(handle, "Devel::NYTProf::FileHandle"))
+ croak("handle is not a Devel::NYTProf::FileHandle");
+ fh = (NYTP_file)SvPVX(SvRV(handle));
+ output_nv(fh, value);
+
+
+void
+output_str(handle, value)
+SV *handle
+SV *value
+ PREINIT:
+ STRLEN len;
+ char *p;
+ NYTP_file fh;
+ CODE:
+ if(!sv_isa(handle, "Devel::NYTProf::FileHandle"))
+ croak("handle is not a Devel::NYTProf::FileHandle");
+ fh = (NYTP_file)SvPVX(SvRV(handle));
+ p = SvPV(value, len);
+ output_str(fh, p, SvUTF8(value) ? -(I32)len : (I32) len);
--
1.6.0
>From 6391daffa999ca6d8d659cf49026c7fff5cf145a Mon Sep 17 00:00:00 2001
From: Nicholas Clark <[email protected]>
Date: Thu, 17 Dec 2009 09:59:45 +0000
Subject: [PATCH] Refactor Devel::NYTProf::ReadStream::output_iv() to take a list of values.
---
NYTProf.xs | 12 ++++++++----
1 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/NYTProf.xs b/NYTProf.xs
index c39ad96..b5bd19b 100644
--- a/NYTProf.xs
+++ b/NYTProf.xs
@@ -4911,16 +4911,20 @@ SV *string
RETVAL
void
-output_int(handle, value)
+output_int(handle, ...)
SV *handle
-unsigned int value
PREINIT:
NYTP_file fh;
- CODE:
+ SV **last = sp + items;
+ PPCODE:
if(!sv_isa(handle, "Devel::NYTProf::FileHandle"))
croak("handle is not a Devel::NYTProf::FileHandle");
fh = (NYTP_file)SvPVX(SvRV(handle));
- output_int(fh, value);
+ ++sp; /* A pointer to the function is first item on the stack.
+ It's not included in items */
+ while(sp++ < last)
+ output_int(fh, SvUV(*sp));
+ XSRETURN(0);
void
output_nv(handle, value)
--
1.6.0
>From 1cfb80197db59a7463c62bad1a98b154b63dce17 Mon Sep 17 00:00:00 2001
From: Nicholas Clark <[email protected]>
Date: Thu, 17 Dec 2009 10:19:02 +0000
Subject: [PATCH] Refactor Devel::NYTProf::ReadStream::output_nv() to take a list of values.
Unlike output_iv, this isn't much of a performance win, but given the
similarity of the two XSubs, it's trivial to make this change.
---
NYTProf.xs | 11 ++++++++---
1 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/NYTProf.xs b/NYTProf.xs
index b5bd19b..ba58e52 100644
--- a/NYTProf.xs
+++ b/NYTProf.xs
@@ -4927,16 +4927,21 @@ SV *handle
XSRETURN(0);
void
-output_nv(handle, value)
+output_nv(handle, ...)
SV *handle
NV value
PREINIT:
NYTP_file fh;
- CODE:
+ SV **last = sp + items;
+ PPCODE:
if(!sv_isa(handle, "Devel::NYTProf::FileHandle"))
croak("handle is not a Devel::NYTProf::FileHandle");
fh = (NYTP_file)SvPVX(SvRV(handle));
- output_nv(fh, value);
+ ++sp; /* A pointer to the function is first item on the stack.
+ It's not included in items */
+ while(sp++ < last)
+ output_nv(fh, SvNV(*sp));
+ XSRETURN(0);
void
--
1.6.0
>From c63d1813b4cde7203ced4ba7d59f387326e070e7 Mon Sep 17 00:00:00 2001
From: Nicholas Clark <[email protected]>
Date: Thu, 17 Dec 2009 14:18:25 +0000
Subject: [PATCH] A tool for merging NYTProf profile files. This prototype can't merge yet.
---
MANIFEST | 1 +
bin/nytprofmerge | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 136 insertions(+), 0 deletions(-)
create mode 100755 bin/nytprofmerge
diff --git a/MANIFEST b/MANIFEST
index fe496a2..096c366 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -12,6 +12,7 @@ benchmark.pl
bin/nytprofcg
bin/nytprofcsv
bin/nytprofhtml
+bin/nytprofmerge
demo/README
demo/demo-code.pl
demo/demo-run.pl
diff --git a/bin/nytprofmerge b/bin/nytprofmerge
new file mode 100755
index 0000000..b55b389
--- /dev/null
+++ b/bin/nytprofmerge
@@ -0,0 +1,135 @@
+#!/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/dist/Devel-NYTProf/
+#
+##########################################################
+# $Id$
+##########################################################
+
+use warnings;
+use strict;
+use Devel::NYTProf::ReadStream qw(for_chunks);
+
+use Getopt::Long;
+use Carp;
+
+my %opt = (
+ out => 'nytprof-merged.out',
+ );
+
+GetOptions(\%opt, qw/out|o=s help|h/)
+ or do {
+ usage();
+ exit 1;
+ };
+
+if (defined($opt{help})) {
+ usage();
+ exit;
+}
+
+sub usage {
+ print <<END
+usage: [perl] nytprofmerge [opts]
+ --out <dir>, -o <dir> Place merged file [default: ./nytprof-merged.out]
+ --help, -h Print this message
+
+This script of part of the Devel::NYTProf distribution.
+See http://search.cpan.org/dist/Devel-NYTProf/ for details and copyright.
+END
+}
+
+my $out = Devel::NYTProf::FileHandle::open($opt{out}, "wb");
+
+sub _time_block_or_line {
+ my ($tag, undef, undef, $ticks, $fid, $line, $block_line, $sub_line) = @_;
+ my $is_line = $tag eq 'TIME_LINE';
+ $out->write($is_line ? '+' : '*');
+ $out->output_int($ticks, $fid, $line);
+ if (!$is_line) {
+ $out->output_int($block_line);
+ $out->output_int($sub_line);
+ }
+}
+
+my %dispatcher =
+ (
+ VERSION => sub {
+ my (undef, $major, $minor) = @_;
+ $out->write("NYTProf $major $minor\n");
+ },
+ COMMENT => sub {
+ my (undef, $text) = @_;
+ $out->write("#$text");
+ },
+ ATTRIBUTE => sub {
+ my (undef, $key, $value) = @_;
+ $out->write(":$key=$value\n");
+ },
+
+ START_DEFLATE => sub {
+ },
+
+ PID_START => sub {
+ my (undef, $pid, $parent, $time) = @_;
+ $out->write('P');
+ $out->output_int($pid, $parent);
+ $out->output_nv($time);
+ },
+ PID_END => sub {
+ my (undef, $pid, $time) = @_;
+ $out->write('p');
+ $out->output_int($pid);
+ $out->output_nv($time);
+ },
+
+ NEW_FID => sub {
+ my (undef, $fid, $eval_fid, $eval_line, $flags, $size, $mtime, $name) = @_;
+ $out->write('@');
+ $out->output_int($fid, $eval_fid, $eval_line, $flags, $size, $mtime);
+ $out->output_str($name);
+ },
+ TIME_BLOCK => \&_time_block_or_line,
+ TIME_LINE => \&_time_block_or_line,
+
+ DISCOUNT => sub {
+ $out->write('-');
+ },
+ SUB_INFO => sub {
+ my (undef, $fid, $first_line, $last_line, $name) = @_;
+ $out->write('s');
+ $out->output_int($fid);
+ $out->output_str($name);
+ $out->output_int($first_line, $last_line, 0);
+ },
+ SUB_CALLERS => sub {
+ my (undef, $fid, $line, $count, $incl_time, $excl_time, $ucpu_time, $scpu_time, $reci_time, $rec_depth, $called, $caller) = @_;
+ $out->write('c');
+ $out->output_int($fid, $line);
+ $out->output_str($caller);
+ $out->output_int($count);
+ $out->output_nv($incl_time, $excl_time, $ucpu_time, $scpu_time, $reci_time);
+ $out->output_int($rec_depth);
+ $out->output_str($called);
+ },
+ SRC_LINE => sub {
+ my (undef, $fid, $line, $text) = @_;
+ $out->write('S');
+ $out->output_int($fid, $line);
+ $out->output_str($text);
+ },
+ );
+
+my $input = shift @ARGV;
+
+for_chunks {
+ my $tag = $_[0];
+
+ my $sub = $dispatcher{$tag};
+ die "Unknown tag '$tag'" unless defined $sub;
+ &$sub(@_);
+} filename => $input;
--
1.6.0
>From 91e01e76af6a7e9bcc223b810acececef5f2c551 Mon Sep 17 00:00:00 2001
From: Nicholas Clark <[email protected]>
Date: Thu, 17 Dec 2009 15:49:26 +0000
Subject: [PATCH] An initial implementation of FID remapping.
---
bin/nytprofmerge | 27 +++++++++++++++++++++++----
1 files changed, 23 insertions(+), 4 deletions(-)
diff --git a/bin/nytprofmerge b/bin/nytprofmerge
index b55b389..fa6ed73 100755
--- a/bin/nytprofmerge
+++ b/bin/nytprofmerge
@@ -45,6 +45,10 @@ END
my $out = Devel::NYTProf::FileHandle::open($opt{out}, "wb");
+my $next_fid = 1;
+my %file_to_fid;
+my %fids = (0 => 0);
+
sub _time_block_or_line {
my ($tag, undef, undef, $ticks, $fid, $line, $block_line, $sub_line) = @_;
my $is_line = $tag eq 'TIME_LINE';
@@ -89,8 +93,23 @@ my %dispatcher =
NEW_FID => sub {
my (undef, $fid, $eval_fid, $eval_line, $flags, $size, $mtime, $name) = @_;
+ my ($new_fid, $new_eval_fid);
+ if($eval_fid) {
+ $new_eval_fid = $fids{$eval_fid};
+ confess("unknown eval_fid $eval_fid") unless defined $new_eval_fid;
+ $new_fid = $next_fid++;
+ $fids{$fid} = $new_fid;
+ } else {
+ $new_eval_fid = $eval_fid;
+ $new_fid = $file_to_fid{$name};
+ unless(defined $new_fid) {
+ $new_fid = $next_fid++;
+ $fids{$fid} = $new_fid;
+ $file_to_fid{$name} = $fid;
+ }
+ }
$out->write('@');
- $out->output_int($fid, $eval_fid, $eval_line, $flags, $size, $mtime);
+ $out->output_int($new_fid, $new_eval_fid, $eval_line, $flags, $size, $mtime);
$out->output_str($name);
},
TIME_BLOCK => \&_time_block_or_line,
@@ -102,14 +121,14 @@ my %dispatcher =
SUB_INFO => sub {
my (undef, $fid, $first_line, $last_line, $name) = @_;
$out->write('s');
- $out->output_int($fid);
+ $out->output_int($fids{$fid});
$out->output_str($name);
$out->output_int($first_line, $last_line, 0);
},
SUB_CALLERS => sub {
my (undef, $fid, $line, $count, $incl_time, $excl_time, $ucpu_time, $scpu_time, $reci_time, $rec_depth, $called, $caller) = @_;
$out->write('c');
- $out->output_int($fid, $line);
+ $out->output_int($fids{$fid}, $line);
$out->output_str($caller);
$out->output_int($count);
$out->output_nv($incl_time, $excl_time, $ucpu_time, $scpu_time, $reci_time);
@@ -119,7 +138,7 @@ my %dispatcher =
SRC_LINE => sub {
my (undef, $fid, $line, $text) = @_;
$out->write('S');
- $out->output_int($fid, $line);
+ $out->output_int($fids{$fid}, $line);
$out->output_str($text);
},
);
--
1.6.0
>From e378d429bebc1ea0a2b1e3686d4be4cc4299faa0 Mon Sep 17 00:00:00 2001
From: Nicholas Clark <[email protected]>
Date: Thu, 17 Dec 2009 16:57:54 +0000
Subject: [PATCH] profiler_duracion needs to sum over all PIDs run, not just the last PID seen.
---
NYTProf.xs | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/NYTProf.xs b/NYTProf.xs
index ba58e52..2bad944 100644
--- a/NYTProf.xs
+++ b/NYTProf.xs
@@ -4494,7 +4494,7 @@ load_profile_data_from_stream(SV *cb)
HvKEYS(live_pids_hv), profiler_end_time);
store_attrib_sv(aTHX_ attr_hv, "profiler_end_time", newSVnv(profiler_end_time));
- profiler_duration = profiler_end_time - profiler_start_time;
+ profiler_duration += profiler_end_time - profiler_start_time;
store_attrib_sv(aTHX_ attr_hv, "profiler_duration", newSVnv(profiler_duration));
break;
--
1.6.0
>From f6264238296b138ec6951a17ad4521df1b3cf94e Mon Sep 17 00:00:00 2001
From: Nicholas Clark <[email protected]>
Date: Thu, 17 Dec 2009 16:58:35 +0000
Subject: [PATCH] Merge 2 (or more) NYTProf output files. Unpolished - error checking, sanity
checking and tests not present yet.
---
bin/nytprofmerge | 99 +++++++++++++++++++++++++++++++++++++++++-------------
1 files changed, 75 insertions(+), 24 deletions(-)
diff --git a/bin/nytprofmerge b/bin/nytprofmerge
index fa6ed73..c15b0fe 100755
--- a/bin/nytprofmerge
+++ b/bin/nytprofmerge
@@ -49,6 +49,11 @@ my $next_fid = 1;
my %file_to_fid;
my %fids = (0 => 0);
+my $version;
+my %seen_subs;
+
+my %callers;
+
sub _time_block_or_line {
my ($tag, undef, undef, $ticks, $fid, $line, $block_line, $sub_line) = @_;
my $is_line = $tag eq 'TIME_LINE';
@@ -60,11 +65,21 @@ sub _time_block_or_line {
}
}
+# Effectively, this is a global variable. Sorry.
+my $input;
+
my %dispatcher =
(
VERSION => sub {
my (undef, $major, $minor) = @_;
- $out->write("NYTProf $major $minor\n");
+ my $this_version = "$major $minor";
+ if($version) {
+ die "Incompatible version '$this_version' in $input, expected '$version'"
+ unless $this_version eq $version;
+ } else {
+ $version = $this_version;
+ $out->write("NYTProf $version\n");
+ }
},
COMMENT => sub {
my (undef, $text) = @_;
@@ -102,11 +117,11 @@ my %dispatcher =
} else {
$new_eval_fid = $eval_fid;
$new_fid = $file_to_fid{$name};
- unless(defined $new_fid) {
- $new_fid = $next_fid++;
- $fids{$fid} = $new_fid;
- $file_to_fid{$name} = $fid;
- }
+ return if defined $new_fid;
+
+ $new_fid = $next_fid++;
+ $fids{$fid} = $new_fid;
+ $file_to_fid{$name} = $fid;
}
$out->write('@');
$out->output_int($new_fid, $new_eval_fid, $eval_line, $flags, $size, $mtime);
@@ -120,20 +135,39 @@ my %dispatcher =
},
SUB_INFO => sub {
my (undef, $fid, $first_line, $last_line, $name) = @_;
- $out->write('s');
- $out->output_int($fids{$fid});
- $out->output_str($name);
- $out->output_int($first_line, $last_line, 0);
+ if(!$seen_subs{"$fid,$name"}++) {
+ $out->write('s');
+ $out->output_int($fids{$fid});
+ $out->output_str($name);
+ $out->output_int($first_line, $last_line, 0);
+ }
},
SUB_CALLERS => sub {
my (undef, $fid, $line, $count, $incl_time, $excl_time, $ucpu_time, $scpu_time, $reci_time, $rec_depth, $called, $caller) = @_;
- $out->write('c');
- $out->output_int($fids{$fid}, $line);
- $out->output_str($caller);
- $out->output_int($count);
- $out->output_nv($incl_time, $excl_time, $ucpu_time, $scpu_time, $reci_time);
- $out->output_int($rec_depth);
- $out->output_str($called);
+ $fid = $fids{$fid};
+
+ if ($callers{"$fid,$line"}{$called}{$caller}) {
+ my $sum = $callers{"$fid,$line"}{$called}{$caller};
+ $sum->{count} += $count;
+ $sum->{incl} += $incl_time;
+ $sum->{excl} += $excl_time;
+ $sum->{ucpu} += $ucpu_time;
+ $sum->{scpu} += $scpu_time;
+ $sum->{reci} += $reci_time;
+ $sum->{depth} = $rec_depth if $rec_depth > $sum->{depth};
+ } else {
+ # New;
+ $callers{"$fid,$line"}{$called}{$caller} =
+ {
+ depth => $rec_depth,
+ count => $count,
+ incl => $incl_time,
+ excl => $excl_time,
+ ucpu => $ucpu_time,
+ scpu => $scpu_time,
+ reci => $reci_time,
+ };
+ }
},
SRC_LINE => sub {
my (undef, $fid, $line, $text) = @_;
@@ -143,12 +177,29 @@ my %dispatcher =
},
);
-my $input = shift @ARGV;
+foreach $input (@ARGV) {
+ for_chunks {
+ my $tag = $_[0];
-for_chunks {
- my $tag = $_[0];
+ my $sub = $dispatcher{$tag};
+ die "Unknown tag '$tag'" unless defined $sub;
+ &$sub(@_);
+ } filename => $input;
+}
- my $sub = $dispatcher{$tag};
- die "Unknown tag '$tag'" unless defined $sub;
- &$sub(@_);
-} filename => $input;
+# Deterministic order is useful for testing.
+foreach my $fid_line (sort keys %callers) {
+ my ($fid, $line) = split ',', $fid_line;
+ foreach my $called (sort keys %{$callers{$fid_line}}) {
+ foreach my $caller (sort keys %{$callers{$fid_line}{$called}}) {
+ my $sum = $callers{$fid_line}{$called}{$caller};
+ $out->write('c');
+ $out->output_int($fid, $line);
+ $out->output_str($caller);
+ $out->output_int($sum->{count});
+ $out->output_nv(@{$sum}{qw(incl excl ucpu scpu reci)});
+ $out->output_int($sum->{depth});
+ $out->output_str($called);
+ }
+ }
+}
--
1.6.0