Author: tim.bunce
Date: Thu Oct 16 02:22:48 2008
New Revision: 509
Modified:
trunk/Changes
trunk/INSTALL
trunk/Makefile.PL
trunk/NYTProf.xs
trunk/README
trunk/lib/Devel/NYTProf/Data.pm
trunk/lib/Devel/NYTProf/Util.pm
trunk/test.pl
Log:
Patch from Jan Dubois to port to windows. Yeah!
Modified: trunk/Changes
==============================================================================
--- trunk/Changes (original)
+++ trunk/Changes Thu Oct 16 02:22:48 2008
@@ -9,6 +9,8 @@
NOTE: The file format has changed. Files from 2.04 and 2.05
can still be read by this version.
+ Now builds on Windows, with thanks to Jan Dubois!
+
Subroutine inclusive time no longer counts time
spent recursed into the same subroutine. That time is
now recorded separately, along with the max recursion depth.
Modified: trunk/INSTALL
==============================================================================
--- trunk/INSTALL (original)
+++ trunk/INSTALL Thu Oct 16 02:22:48 2008
@@ -19,15 +19,6 @@
make sure those are in your INCLUDE path. It is also sometimes named
fpurge
_fpurge or __fpurge.
-WINDOWS
-
-Windows users are currently out of luck. The module will not compile
properly
-due to file locking headers, and some other POSIX/GNU code being absent.
It
-should be possible to port the module, but this has not yet been done.
Feel
-free to do it. Also, file paths throughout the module are assumed to
use "/"
-instead of Windows "\", and assumed that "/...." will start at the file
system
-root. These things can also be pathed if you feel the urge.
-
COMPILE NOTES
The module was written to compile silently with -Wall -pedantic -ansi.
Some
Modified: trunk/Makefile.PL
==============================================================================
--- trunk/Makefile.PL (original)
+++ trunk/Makefile.PL Thu Oct 16 02:22:48 2008
@@ -34,13 +34,6 @@
} );
}
-# --- Bail out on Windows
-if ($^O eq 'MSWin32') {
- print "This module does not currently support Windows.\n"
- . "Please help us port it - contact us at
[EMAIL PROTECTED]";
- die "No support for OS" if $ENV{AUTOMATED_TESTING}; # keep
cpan-testers happy
-}
-
# --- Options
GetOptions(
'g!' => \my $opt_g,
Modified: trunk/NYTProf.xs
==============================================================================
--- trunk/NYTProf.xs (original)
+++ trunk/NYTProf.xs Thu Oct 16 02:22:48 2008
@@ -90,7 +90,7 @@
#define NYTP_TAG_NO_TAG '\0' /* Used as a flag to mean "no tag"
*/
-#define output_int(i) output_tag_int(NYTP_TAG_NO_TAG, (i))
+#define output_int(i) output_tag_int(NYTP_TAG_NO_TAG, (unsigned
int)(i))
/* Hash table definitions */
#define MAX_HASH_SIZE 512
@@ -293,6 +293,7 @@
* Devel::NYTProf Functions *
***********************************/
+/* XXX The proper return value would be Off_t */
static long
NYTP_tell(NYTP_file file) {
#ifdef HAS_ZLIB
@@ -303,7 +304,7 @@
? file->zs.total_out : file->zs.total_in;
}
#endif
- return ftell(file->file);
+ return (long)ftell(file->file);
}
static const char *
@@ -495,10 +496,10 @@
#endif
-static unsigned int
-NYTP_read_unchecked(NYTP_file ifile, void *buffer, unsigned int len) {
+static size_t
+NYTP_read_unchecked(NYTP_file ifile, void *buffer, size_t len) {
#ifdef HAS_ZLIB
- unsigned int result = 0;
+ size_t result = 0;
#endif
if (FILE_STATE(ifile) == NYTP_FILE_STDIO) {
return fread(buffer, 1, len, ifile->file);
@@ -531,12 +532,12 @@
}
-static unsigned int
-NYTP_read(NYTP_file ifile, void *buffer, unsigned int len, char *what) {
- unsigned int got = NYTP_read_unchecked(ifile, buffer, len);
+static size_t
+NYTP_read(NYTP_file ifile, void *buffer, size_t len, char *what) {
+ size_t got = NYTP_read_unchecked(ifile, buffer, len);
if (got != len) {
croak("Profile format error whilst reading %s at %ld%s:
expected %d got %d, %s",
- what, NYTP_tell(ifile), NYTP_type_of_offset(ifile), len,
got,
+ what, NYTP_tell(ifile), NYTP_type_of_offset(ifile),
(int)len, (int)got,
(NYTP_eof(in)) ? "end of file" : NYTP_fstrerror(in));
}
return len;
@@ -626,10 +627,10 @@
}
#endif
-static unsigned int
-NYTP_write(NYTP_file ofile, const void *buffer, unsigned int len) {
+static size_t
+NYTP_write(NYTP_file ofile, const void *buffer, size_t len) {
#ifdef HAS_ZLIB
- unsigned int result = 0;
+ size_t result = 0;
#endif
if (FILE_STATE(ofile) == NYTP_FILE_STDIO) {
if (fwrite(buffer, 1, len, ofile->file) < 1) {
@@ -668,9 +669,9 @@
#endif
}
-static unsigned int
+static int
NYTP_printf(NYTP_file ofile, const char *format, ...) {
- unsigned int retval;
+ int retval;
va_list args;
if (FILE_STATE(ofile) != NYTP_FILE_STDIO) {
@@ -818,9 +819,9 @@
static void
output_str(char *str, I32 len) { /* negative len signifies utf8 */
- int tag = NYTP_TAG_STRING;
+ unsigned char tag = NYTP_TAG_STRING;
if (!len)
- len = strlen(str);
+ len = (I32)strlen(str);
else if (len < 0) {
tag = NYTP_TAG_STRING_UTF8;
len = -len;
@@ -973,7 +974,23 @@
output_int(fid_info->fid_flags);
output_int(fid_info->file_size);
output_int(fid_info->file_mtime);
- output_str(file_name, file_name_len);
+
+#ifdef WIN32
+ /* Make sure we only use forward slashes in filenames */
+ if (memchr(file_name, '\\', file_name_len)) {
+ STRLEN i;
+ char *file_name_copy = (char*)safemalloc(file_name_len);
+ for (i=0; i<file_name_len; ++i) {
+ char ch = file_name[i];
+ file_name_copy[i] = ch == '\\' ? '/' : ch;
+ }
+ output_str(file_name_copy, (I32)file_name_len);
+ Safefree(file_name_copy);
+ return;
+ }
+#endif
+
+ output_str(file_name, (I32)file_name_len);
}
@@ -1048,10 +1065,10 @@
file_name_len = new_end - file_name;
}
entry.key = file_name;
- entry.key_len = file_name_len;
+ entry.key_len = (unsigned int)file_name_len;
/* inserted new entry */
- if (1 == hash_op(entry, &found, created_via)) {
+ if (1 == hash_op(entry, &found, (bool)created_via)) {
AV *src_av = Nullav;
/* if this is a synthetic filename for an 'eval'
@@ -1077,7 +1094,16 @@
/* determine absolute path if file_name is relative */
found->key_abs = NULL;
- if (!found->eval_fid && *file_name != '/') {
+ if (!found->eval_fid &&
+#ifdef WIN32
+ /* XXX should we check for UNC names too? */
+ (file_name_len < 3 || !isALPHA(file_name[0]) ||
file_name[1] != ':' ||
+ (file_name[2] != '/' && file_name[2] != '\\'))
+#else
+ *file_name != '/'
+#endif
+ )
+ {
char file_name_abs[MAXPATHLEN * 2];
/* Note that the current directory may have changed
* between loading the file and profiling it.
@@ -1088,11 +1114,23 @@
/* eg permission */
warn("getcwd: %s\n", strerror(errno));
}
- else if (strNE(file_name_abs, "/")) {
- if (strnEQ(file_name, "./", 2))
- ++file_name;
- else
- strcat(file_name_abs, "/");
+ else {
+#ifdef WIN32
+ char *p = file_name_abs;
+ while (*p) {
+ if ('\\' == *p)
+ *p = '/';
+ ++p;
+ }
+ if (p[-1] != '/') {
+#else
+ if (strNE(file_name_abs, "/")) {
+#endif
+ if (strnEQ(file_name, "./", 2))
+ ++file_name;
+ else
+ strcat(file_name_abs, "/");
+ }
strncat(file_name_abs, file_name, file_name_len);
found->key_abs = strdup(file_name_abs);
}
@@ -1138,7 +1176,7 @@
* is a little inefficient, but not enough to worry about
*/
output_tag_int(NYTP_TAG_SRC_LINE, found->id);
output_int(line);
- output_str(src, len); /* includes newline */
+ output_str(src, (I32)len); /* includes newline */
if (trace_level >= 5)
warn("fid %d src line %d: %s", found->id, line, src);
}
@@ -1157,7 +1195,7 @@
/**
* 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)
- * does tHis for you.
+ * 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
*/
@@ -1315,7 +1353,7 @@
}
/* find next cop from OP */
o = start_op;
- while ( o && (type = (o->op_type) ? o->op_type : o->op_targ) ) {
+ while ( o && (type = (o->op_type) ? o->op_type : (int)o->op_targ) ) {
if (type == OP_NEXTSTATE || type == OP_SETSTATE || type ==
OP_DBSTATE) {
if (trace_level >= trace)
warn("\tstart_cop_of_context %s is %s line %d of %s\n",
@@ -1530,7 +1568,7 @@
if (last_executed_fid) {
reinit_if_forked(aTHX);
- output_tag_int(((profile_blocks)
+ output_tag_int((unsigned char)((profile_blocks)
? NYTP_TAG_TIME_BLOCK : NYTP_TAG_TIME_LINE), elapsed);
output_int(last_executed_fid);
output_int(last_executed_line);
@@ -1694,7 +1732,7 @@
{
char filename_buf[MAXPATHLEN];
- if (profile_opts & NYTP_OPTf_ADDPID
+ if ((profile_opts & NYTP_OPTf_ADDPID)
|| out /* already opened so assume forking */
) {
sprintf(filename_buf, "%s.%d", filename, getpid());
@@ -1704,7 +1742,7 @@
/* some protection against multiple processes writing to the same file
*/
unlink(filename); /* throw away any previous file */
- out = NYTP_open(filename, "wbx");
+ out = NYTP_open(filename, "wb");
if (!out) {
int fopen_errno = errno;
char *hint = "";
@@ -1793,7 +1831,7 @@
SV *incl_time_sv = *av_fetch(av, 1, 1);
SV *excl_time_sv = *av_fetch(av, 2, 1);
/* statement overheads we've accumulated since we entered the sub */
- int overhead_ticks = (cumulative_overhead_ticks -
sub_call_start->current_overhead_ticks);
+ int overhead_ticks = (int)(cumulative_overhead_ticks -
sub_call_start->current_overhead_ticks);
/* seconds spent in subroutines called by this subroutine */
NV called_sub_secs = (cumulative_subr_secs -
sub_call_start->current_subr_secs);
NV incl_subr_sec;
@@ -1846,7 +1884,7 @@
static void /* wrapper called via
scope exit due to save_destructor below */
incr_sub_inclusive_time_ix(pTHX_ void *save_ix_void)
{
- I32 save_ix = (I32)save_ix_void;
+ I32 save_ix = (I32)PTR2IV(save_ix_void);
sub_call_start_t *sub_call_start = SSPTR(save_ix, sub_call_start_t *);
incr_sub_inclusive_time(aTHX_ sub_call_start);
}
@@ -2001,7 +2039,7 @@
/* { subname => { "fid:line" => [ count, incl_time ] } } */
sv_tmp = *hv_fetch(sub_callers_hv, SvPV_nolen(subname_sv),
- SvCUR(subname_sv), 1);
+ (I32)SvCUR(subname_sv), 1);
if (!SvROK(sv_tmp)) { /* autoviv hash ref - is first call of this
subname from anywhere */
HV *hv = newHV();
@@ -2019,7 +2057,7 @@
* The reader can try to associate the xsubs with the
* corresonding .pm file using the package part of the
subname.
*/
- SV *sv = *hv_fetch(GvHV(PL_DBsub),
SvPV_nolen(subname_sv), SvCUR(subname_sv), 1);
+ SV *sv = *hv_fetch(GvHV(PL_DBsub),
SvPV_nolen(subname_sv), (I32)SvCUR(subname_sv), 1);
sv_setpv(sv, ":0-0"); /* empty file name */
if (trace_level >= 2)
warn("Adding fake DBsub entry for '%s' xsub\n",
SvPV_nolen(subname_sv));
@@ -2036,7 +2074,7 @@
sub_call_start.sub_av = av;
if (stash_name) /* note that a sub in this package was called
*/
- hv_fetch(pkg_fids_hv, stash_name, strlen(stash_name), 1);
+ hv_fetch(pkg_fids_hv, stash_name, (I32)strlen(stash_name),
1);
}
else {
sub_call_start.sub_av = (AV *)SvRV(sv_tmp);
@@ -2067,7 +2105,7 @@
I32 save_ix = SSNEWa(sizeof(sub_call_start),
MEM_ALIGNBYTES);
Copy(&sub_call_start, SSPTR(save_ix, sub_call_start_t *),
1, sub_call_start_t);
/* defer acculumating time spent until we leave the sub */
- save_destructor_x(incr_sub_inclusive_time_ix, (void
*)save_ix);
+ save_destructor_x(incr_sub_inclusive_time_ix, INT2PTR(void
*, (IV)save_ix));
}
}
else {
@@ -2345,7 +2383,7 @@
sv_setnv(time_sv, time + SvNV(time_sv));
if (count) {
SV *sv = *av_fetch(line_av, 1, 1);
- (count == 1) ? sv_inc(sv) : sv_setiv(sv, time + SvIV(sv));
+ (count == 1) ? sv_inc(sv) : sv_setiv(sv, (IV)time + SvIV(sv));
}
}
return line_av;
@@ -2359,7 +2397,7 @@
char *colon = strrchr(sub_name, ':'); /* end of package name */
if (!colon || colon == sub_name || *--colon != ':')
return Nullsv; /* no :: delimiter */
- svp = hv_fetch(pkg_fids_hv, sub_name, colon-sub_name, 0);
+ svp = hv_fetch(pkg_fids_hv, sub_name, (I32)(colon-sub_name), 0);
if (!svp)
return Nullsv; /* not a package we've profiled sub calls into */
return *svp;
@@ -2408,7 +2446,7 @@
if (trace_level >= 3)
warn("Associating package of %s with %.*s (fid %d)\n",
- sub_name, filename_len, filename, fid );
+ sub_name, (int)filename_len, filename, fid );
}
/* Iterate over PL_DBsub writing out fid and source line range of subs.
@@ -2438,7 +2476,7 @@
if (SvOK(pkg_filename_sv)) {
filename = SvPV(pkg_filename_sv, filename_len);
if (trace_level >= 2)
- warn("Sub %s is xsub, we'll associate it with
filename %.*s\n", sub_name, filename_len, filename);
+ warn("Sub %s is xsub, we'll associate it with
filename %.*s\n", sub_name, (int)filename_len, filename);
}
}
@@ -2491,13 +2529,13 @@
output_tag_int(NYTP_TAG_SUB_CALLERS, fid);
output_int(line);
- sc[NYTP_SCi_CALL_COUNT] = output_uv_from_av(aTHX_ av,
NYTP_SCi_CALL_COUNT, 0);
+ sc[NYTP_SCi_CALL_COUNT] = (NV)output_uv_from_av(aTHX_ av,
NYTP_SCi_CALL_COUNT, 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);
sc[NYTP_SCi_INCL_UTIME] = output_nv_from_av(aTHX_ av,
NYTP_SCi_INCL_UTIME, 0.0);
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);
+ sc[NYTP_SCi_REC_DEPTH] = (NV)output_uv_from_av(aTHX_ av,
NYTP_SCi_REC_DEPTH , 0);
output_str(sub_name, sub_name_len);
if (trace_level >= 3)
@@ -2702,8 +2740,8 @@
}
else {
AV *fid_av = (AV *)SvRV(fid_info_rvav);
- eval_file_num = SvUV(*av_fetch(fid_av,1,1));
- eval_line_num = SvUV(*av_fetch(fid_av,2,1));
+ eval_file_num = (unsigned
int)SvUV(*av_fetch(fid_av,1,1));
+ eval_line_num = (unsigned
int)SvUV(*av_fetch(fid_av,2,1));
}
if (eval_file_num) { /* fid is an eval */
@@ -2964,12 +3002,12 @@
}
*value++ = '\0';
value_sv = newSVpvn(value, end-value);
- (void)hv_store(attr_hv, text, strlen(text), value_sv, 0);
+ (void)hv_store(attr_hv, text, (I32)strlen(text), value_sv,
0);
if (trace_level >= 2)
/* includes \n */
warn(": %s = '%s'\n", text, SvPV_nolen(value_sv));
if ('t' == *text && strEQ(text, "ticks_per_sec")) {
- ticks_per_sec = SvUV(value_sv);
+ ticks_per_sec = (unsigned int)SvUV(value_sv);
}
else if ('n' == *text && strEQ(text, "nv_size")) {
if (sizeof(NV) != atoi(value))
Modified: trunk/README
==============================================================================
--- trunk/README (original)
+++ trunk/README Thu Oct 16 02:22:48 2008
@@ -6,9 +6,8 @@
Devel::NYTProf is a powerful feature-rich perl source code profiler.
-Devel::NYTProf was written and tested on Linux, Solaris and OS X.
+Devel::NYTProf was written and tested on Linux, Solaris, OS X and Windows.
Please report any problems you encounter on other platforms.
-(Except for windows as we can't help you, but we'd love someone to port it
for us.)
INSTALLATION
Modified: trunk/lib/Devel/NYTProf/Data.pm
==============================================================================
--- trunk/lib/Devel/NYTProf/Data.pm (original)
+++ trunk/lib/Devel/NYTProf/Data.pm Thu Oct 16 02:22:48 2008
@@ -441,7 +441,8 @@
# remove_internal_data_of library files
# (the definition of which is quite vague at the moment)
- my @abs_inc = grep { $_ =~ m:^/: } $self->inc;
+ my $abs_path_regex = $^O eq "MSWin32" ? qr,^\w:/, : qr,^/,;
+ my @abs_inc = grep { $_ =~ $abs_path_regex } $self->inc;
my $is_lib_regex = get_abs_paths_alternation_regex([EMAIL PROTECTED]);
for my $fileinfo ($self->all_fileinfos) {
Modified: trunk/lib/Devel/NYTProf/Util.pm
==============================================================================
--- trunk/lib/Devel/NYTProf/Util.pm (original)
+++ trunk/lib/Devel/NYTProf/Util.pm Thu Oct 16 02:22:48 2008
@@ -73,8 +73,9 @@
# rewrite relative directories to be absolute
# the logic here should match that in get_file_id()
+ my $abs_path_regex = $^O eq "MSWin32" ? qr,^\w:/, : qr,^/,;
for (@inc) {
- next if m{^\/}; # already absolute
+ next if $_ =~ $abs_path_regex; # already absolute
$_ =~ s/^\.\///; # remove a leading './'
$cwd ||= getcwd();
$_ = ($_ eq '.') ? $cwd : "$cwd/$_";
Modified: trunk/test.pl
==============================================================================
--- trunk/test.pl (original)
+++ trunk/test.pl Thu Oct 16 02:22:48 2008
@@ -30,6 +30,7 @@
'test06' => ($] >= 5.008) ? 0 : "needs perl >= 5.8",
'test15' => ($] < 5.008) ? 0 : "needs perl < 5.8",
'test16' => ($] >= 5.010) ? 0 : "needs perl >= 5.10",
+ 'test30-fork' => ($^O ne "MSWin32") ? 0 : "doesn't work with fork()
emulation",
);
my %opts = (
@@ -99,7 +100,8 @@
print "nytprofcvs: $nytprofcsv\n";
}
-ok(-x $nytprofcsv, "Where's nytprofcsv?");
+# Windows emulates the executable bit based on file extension only
+ok($^O eq "MSWin32" ? -f $nytprofcsv : -x $nytprofcsv, "Where's
nytprofcsv?");
# run all tests in various configurations
for my $leave (@test_opt_leave) {
--~--~---------~--~----~------------~-------~--~----~
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]
-~----------~----~----~----~------~----~------~--~---