Revision: 965
Author: [email protected]
Date: Fri Dec 18 07:09:33 2009
Log: Move all NYTP_* file handling functions into FileHandle.xs
http://code.google.com/p/perl-devel-nytprof/source/detail?r=965

Added:
  /trunk/FileHandle.h
  /trunk/FileHandle.xs
Modified:
  /trunk/MANIFEST
  /trunk/Makefile.PL
  /trunk/NYTProf.xs

=======================================
--- /dev/null
+++ /trunk/FileHandle.h Fri Dec 18 07:09:33 2009
@@ -0,0 +1,46 @@
+/* vim: ts=8 sw=4 expandtab:
+ * ************************************************************************
+ * This file is part of the Devel::NYTProf package.
+ * Copyright 2008 Adam J. Kaplan, The New York Times Company.
+ * Copyright 2008 Tim Bunce, Ireland.
+ * Released under the same terms as Perl 5.8
+ * See http://search.cpan.org/dist/Devel-NYTProf/
+ *
+ * Contributors:
+ * Adam Kaplan, akaplan at nytimes.com
+ * Tim Bunce, http://www.tim.bunce.name and http://blog.timbunce.org
+ * Steve Peters, steve at fisharerojo.org
+ *
+ * ************************************************************************
+ * $Id$
+ * ************************************************************************
+ */
+
+/* Arguably this header is naughty, as it's not self contained, because it
+   assumes that stdlib.h has already been included (via perl.h)  */
+
+typedef struct NYTP_file_t *NYTP_file;
+
+void NYTP_start_deflate(NYTP_file file, int compression_level);
+void NYTP_start_inflate(NYTP_file file);
+
+NYTP_file NYTP_open(const char *name, const char *mode);
+char *NYTP_gets(NYTP_file ifile, char *buffer, unsigned int len);
+size_t NYTP_read_unchecked(NYTP_file ifile, void *buffer, size_t len);
+size_t NYTP_read(NYTP_file ifile, void *buffer, size_t len, const char  
*what);
+size_t NYTP_write(NYTP_file ofile, const void *buffer, size_t len);
+int NYTP_scanf(NYTP_file ifile, const char *format, ...);
+int NYTP_printf(NYTP_file ofile, const char *format, ...);
+int NYTP_flush(NYTP_file file);
+int NYTP_eof(NYTP_file ifile);
+long NYTP_tell(NYTP_file file);
+int NYTP_close(NYTP_file file, int discard);
+
+const char *NYTP_fstrerror(NYTP_file file);
+#ifdef HAS_ZLIB
+const char *NYTP_type_of_offset(NYTP_file file);
+#else
+#  define NYTP_type_of_offset(file) ""
+#endif
+
+void NYTProf_croak_if_not_stdio(NYTP_file file, const char *function);
=======================================
--- /dev/null
+++ /trunk/FileHandle.xs        Fri Dec 18 07:09:33 2009
@@ -0,0 +1,571 @@
+/* vim: ts=8 sw=4 expandtab:
+ * ************************************************************************
+ * This file is part of the Devel::NYTProf package.
+ * Copyright 2008 Adam J. Kaplan, The New York Times Company.
+ * Copyright 2008 Tim Bunce, Ireland.
+ * Released under the same terms as Perl 5.8
+ * See http://search.cpan.org/dist/Devel-NYTProf/
+ *
+ * Contributors:
+ * Adam Kaplan, akaplan at nytimes.com
+ * Tim Bunce, http://www.tim.bunce.name and http://blog.timbunce.org
+ * Steve Peters, steve at fisharerojo.org
+ *
+ * ************************************************************************
+ * $Id$
+ * ************************************************************************
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#include "FileHandle.h"
+
+#ifdef HAS_ZLIB
+#  include <zlib.h>
+#endif
+
+#define NYTP_FILE_STDIO         0
+#define NYTP_FILE_DEFLATE       1
+#define NYTP_FILE_INFLATE       2
+
+/* During profiling the large buffer collects the raw data until full.
+ * Then flush_output zips it into the small buffer and writes it to disk.
+ * A scale factor of ~90 makes the large buffer usually almost fill the  
small
+ * one when zipped (so calls to flush_output() almost always trigger one  
fwrite()).
+ * We use a lower number to save some memory as there's little performance
+ * impact either way.
+ */
+#define NYTP_FILE_SMALL_BUFFER_SIZE   4096
+#define NYTP_FILE_LARGE_BUFFER_SIZE   (NYTP_FILE_SMALL_BUFFER_SIZE * 40)
+
+#ifdef HAS_ZLIB
+#  define FILE_STATE(f)         ((f)->state)
+#else
+#  define FILE_STATE(f)         NYTP_FILE_STDIO
+#endif
+
+struct NYTP_file_t {
+    FILE *file;
+#ifdef HAS_ZLIB
+    unsigned char state;
+    bool stdio_at_eof;
+    bool zlib_at_eof;
+    /* For input only, the position we are in large_buffer.  */
+    unsigned int count;
+    z_stream zs;
+    unsigned char small_buffer[NYTP_FILE_SMALL_BUFFER_SIZE];
+    unsigned char large_buffer[NYTP_FILE_LARGE_BUFFER_SIZE];
+#endif
+};
+
+/* XXX The proper return value would be Off_t */
+long
+NYTP_tell(NYTP_file file) {
+#ifdef HAS_ZLIB
+    /* This has to work with compressed files as it's used in the croaking
+       routine.  */
+    if (FILE_STATE(file) != NYTP_FILE_STDIO) {
+        return FILE_STATE(file) == NYTP_FILE_INFLATE
+            ? file->zs.total_out : file->zs.total_in;
+    }
+#endif
+    return (long)ftell(file->file);
+}
+
+#ifdef HAS_ZLIB
+const char *
+NYTP_type_of_offset(NYTP_file file) {
+    switch (FILE_STATE(file)) {
+    case NYTP_FILE_STDIO:
+        return "";
+    case NYTP_FILE_DEFLATE:
+        return " in compressed output data";
+        break;
+    case NYTP_FILE_INFLATE:
+        return " in compressed input data";
+        break;
+    default:
+        return Perl_form_nocontext(" in stream in unknown state %d",
+                                   FILE_STATE(file));
+    }
+}
+#endif
+
+#ifdef HAS_ZLIB
+#  define CROAK_IF_NOT_STDIO(file, where)           \
+    STMT_START {                                    \
+        if (FILE_STATE(file) != NYTP_FILE_STDIO) {  \
+            compressed_io_croak((file), (where));   \
+        }                                           \
+    } STMT_END
+#else
+#  define CROAK_IF_NOT_STDIO(file, where)
+#endif
+
+#ifdef HAS_ZLIB
+#ifdef HASATTRIBUTE_NORETURN
+__attribute__noreturn__
+#endif
+static void
+compressed_io_croak(NYTP_file file, const char *function) {
+    const char *what;
+
+    switch (FILE_STATE(file)) {
+    case NYTP_FILE_STDIO:
+        what = "stdio";
+        break;
+    case NYTP_FILE_DEFLATE:
+        what = "compressed output";
+        break;
+    case NYTP_FILE_INFLATE:
+        what = "compressed input";
+        break;
+    default:
+        croak("Can't use function %s() on a stream of type %d at  
offset %ld",
+              function, FILE_STATE(file), NYTP_tell(file));
+    }
+    croak("Can't use function %s() on a %s stream at offset %ld", function,
+          what, NYTP_tell(file));
+}
+
+void
+NYTP_start_deflate(NYTP_file file, int compression_level) {
+    int status;
+
+    CROAK_IF_NOT_STDIO(file, "NYTP_start_deflate");
+    FILE_STATE(file) = NYTP_FILE_DEFLATE;
+    file->zs.next_in = (Bytef *) file->large_buffer;
+    file->zs.avail_in = 0;
+    file->zs.next_out = (Bytef *) file->small_buffer;
+    file->zs.avail_out = NYTP_FILE_SMALL_BUFFER_SIZE;
+    file->zs.zalloc = (alloc_func) 0;
+    file->zs.zfree = (free_func) 0;
+    file->zs.opaque = 0;
+
+    status = deflateInit2(&(file->zs), compression_level, Z_DEFLATED,
+        15 /* windowBits */,
+        9 /* memLevel */, Z_DEFAULT_STRATEGY);
+    if (status != Z_OK) {
+        croak("deflateInit2 failed, error %d (%s)", status, file->zs.msg);
+    }
+}
+
+void
+NYTP_start_inflate(NYTP_file file) {
+    int status;
+    CROAK_IF_NOT_STDIO(file, "NYTP_start_inflate");
+    FILE_STATE(file) = NYTP_FILE_INFLATE;
+
+    file->zs.next_in = (Bytef *) file->small_buffer;
+    file->zs.avail_in = 0;
+    file->zs.next_out = (Bytef *) file->large_buffer;
+    file->zs.avail_out = NYTP_FILE_LARGE_BUFFER_SIZE;
+    file->zs.zalloc = (alloc_func) 0;
+    file->zs.zfree = (free_func) 0;
+    file->zs.opaque = 0;
+
+    status = inflateInit2(&(file->zs), 15);
+    if (status != Z_OK) {
+        croak("inflateInit2 failed, error %d (%s)", status, file->zs.msg);
+    }
+}
+#endif
+
+NYTP_file
+NYTP_open(const char *name, const char *mode) {
+    FILE *raw_file = fopen(name, mode);
+    NYTP_file file;
+
+    if (!raw_file)
+        return NULL;
+
+    Newx(file, 1, struct NYTP_file_t);
+    file->file = raw_file;
+
+#ifdef HAS_ZLIB
+    file->state = NYTP_FILE_STDIO;
+    file->count = 0;
+    file->stdio_at_eof = FALSE;
+    file->zlib_at_eof = FALSE;
+
+    file->zs.msg = "[Oops. zlib hasn't updated this error string]";
+#endif
+
+    return file;
+}
+
+char *
+NYTP_gets(NYTP_file ifile, char *buffer, unsigned int len) {
+    CROAK_IF_NOT_STDIO(ifile, "NYTP_gets");
+
+    return fgets(buffer, len, ifile->file);
+}
+
+#ifdef HAS_ZLIB
+
+static void
+grab_input(NYTP_file ifile) {
+    ifile->count = 0;
+    ifile->zs.next_out = (Bytef *) ifile->large_buffer;
+    ifile->zs.avail_out = NYTP_FILE_LARGE_BUFFER_SIZE;
+
+#ifdef DEBUG_INFLATE
+    fprintf(stderr, "grab_input enter\n");
+#endif
+
+    while (1) {
+        int status;
+
+        if (ifile->zs.avail_in == 0 && !ifile->stdio_at_eof) {
+            size_t got = fread(ifile->small_buffer, 1,
+                               NYTP_FILE_SMALL_BUFFER_SIZE, ifile->file);
+
+            if (got == 0) {
+                if (!feof(ifile->file)) {
+                    dTHX;
+                    croak("grab_input failed: %d (%s)", errno,  
strerror(errno));
+                }
+                ifile->stdio_at_eof = TRUE;
+            }
+
+            ifile->zs.avail_in = got;
+            ifile->zs.next_in = (Bytef *) ifile->small_buffer;
+        }
+
+#ifdef DEBUG_INFLATE
+        fprintf(stderr, "grab_input predef  next_in= %p avail_in= %08x\n"
+                        "                   next_out=%p avail_out=%08x"
+                " eof=%d,%d\n", ifile->zs.next_in, ifile->zs.avail_in,
+                ifile->zs.next_out, ifile->zs.avail_out,  
ifile->stdio_at_eof,
+                ifile->zlib_at_eof);
+#endif
+
+        status = inflate(&(ifile->zs), Z_NO_FLUSH);
+
+#ifdef DEBUG_INFLATE
+        fprintf(stderr, "grab_input postdef next_in= %p avail_in= %08x\n"
+                        "                   next_out=%p avail_out=%08x "
+                "status=%d\n", ifile->zs.next_in, ifile->zs.avail_in,
+                ifile->zs.next_out, ifile->zs.avail_out, status);
+#endif
+
+        if (!(status == Z_OK || status == Z_STREAM_END)) {
+            if (ifile->stdio_at_eof)
+                croak("Error reading file: inflate failed, error %d (%s)  
at end of input file, "
+                    " perhaps the process didn't exit cleanly or the file  
has been truncated",
+                    status, ifile->zs.msg);
+            croak("Error reading file: inflate failed, error %d (%s) at  
offset %ld in input file",
+                  status, ifile->zs.msg, (long)ftell(ifile->file));
+        }
+
+        if (ifile->zs.avail_out == 0 || status == Z_STREAM_END) {
+            if (status == Z_STREAM_END) {
+                ifile->zlib_at_eof = TRUE;
+            }
+            return;
+        }
+    }
+}
+
+#endif
+
+
+size_t
+NYTP_read_unchecked(NYTP_file ifile, void *buffer, size_t len) {
+#ifdef HAS_ZLIB
+    size_t result = 0;
+#endif
+    if (FILE_STATE(ifile) == NYTP_FILE_STDIO) {
+        return fread(buffer, 1, len, ifile->file);
+    }
+#ifdef HAS_ZLIB
+    else if (FILE_STATE(ifile) != NYTP_FILE_INFLATE) {
+        compressed_io_croak(ifile, "NYTP_read");
+        return 0;
+    }
+    while (1) {
+        unsigned char *p = ifile->large_buffer + ifile->count;
+        unsigned int remaining = ((unsigned char *) ifile->zs.next_out) -  
p;
+
+        if (remaining >= len) {
+            Copy(p, buffer, len, unsigned char);
+            ifile->count += len;
+            result += len;
+            return result;
+        }
+        Copy(p, buffer, remaining, unsigned char);
+        ifile->count = NYTP_FILE_LARGE_BUFFER_SIZE;
+        result += remaining;
+        len -= remaining;
+        buffer = (void *)(remaining + (char *)buffer);
+        if (ifile->zlib_at_eof)
+            return result;
+        grab_input(ifile);
+    }
+#endif
+}
+
+
+size_t
+NYTP_read(NYTP_file ifile, void *buffer, size_t len, const 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 %ld got %ld, %s",
+              what, NYTP_tell(ifile), NYTP_type_of_offset(ifile),  
(long)len, (long)got,
+                (NYTP_eof(ifile)) ? "end of file" : NYTP_fstrerror(ifile));
+    }
+    return len;
+}
+
+
+#ifdef HAS_ZLIB
+/* Cheat, by telling zlib about a reduced amount of available output space,
+   such that our next write of the (slightly underused) output buffer will
+   align the underlying file pointer back with the size of our output  
buffer
+   (and hopefully the underlying OS block writes).  */
+static void
+sync_avail_out_to_ftell(NYTP_file ofile) {
+    const long result = ftell(ofile->file);
+    const unsigned long where = result < 0 ? 0 : result;
+    ofile->zs.avail_out =
+        NYTP_FILE_SMALL_BUFFER_SIZE - where % NYTP_FILE_SMALL_BUFFER_SIZE;
+#ifdef DEBUG_DEFLATE
+    fprintf(stderr, "sync_avail_out_to_ftell pos=%ld, avail_out=%lu\n",
+            result, (unsigned long) ofile->zs.avail_out);
+#endif
+}
+
+/* flush has values as described for "allowed flush values" in zlib.h  */
+static void
+flush_output(NYTP_file ofile, int flush) {
+    ofile->zs.next_in = (Bytef *) ofile->large_buffer;
+
+#ifdef DEBUG_DEFLATE
+    fprintf(stderr, "flush_output enter   flush = %d\n", flush);
+#endif
+    while (1) {
+        int status;
+#ifdef DEBUG_DEFLATE
+        fprintf(stderr, "flush_output predef  next_in= %p avail_in= %08x\n"
+                        "                     next_out=%p avail_out=%08x"
+                " flush=%d\n", ofile->zs.next_in, ofile->zs.avail_in,
+                ofile->zs.next_out, ofile->zs.avail_out, flush);
+#endif
+        status = deflate(&(ofile->zs), flush);
+
+        /* workaround for RT#50851 */
+        if (status == Z_BUF_ERROR && flush != Z_NO_FLUSH
+                && !ofile->zs.avail_in && ofile->zs.avail_out)
+            status = Z_OK;
+
+#ifdef DEBUG_DEFLATE
+        fprintf(stderr, "flush_output postdef next_in= %p avail_in= %08x\n"
+                        "                     next_out=%p avail_out=%08x "
+                "status=%d\n", ofile->zs.next_in, ofile->zs.avail_in,
+                ofile->zs.next_out, ofile->zs.avail_out, status);
+#endif
+
+        if (status == Z_OK || status == Z_STREAM_END) {
+            if (ofile->zs.avail_out == 0 || flush != Z_NO_FLUSH) {
+                int terminate
+                    = ofile->zs.avail_in == 0 && ofile->zs.avail_out > 0;
+                size_t avail = ((unsigned char *) ofile->zs.next_out)
+                    - ofile->small_buffer;
+                const unsigned char *where = ofile->small_buffer;
+
+                while (avail > 0) {
+                    size_t count = fwrite(where, 1, avail, ofile->file);
+
+                    if (count > 0) {
+                        where += count;
+                        avail -= count;
+                    } else {
+                        dTHX;
+                        croak("fwrite in flush error %d: %s", errno,
+                              strerror(errno));
+                    }
+                }
+                ofile->zs.next_out = (Bytef *) ofile->small_buffer;
+                ofile->zs.avail_out = NYTP_FILE_SMALL_BUFFER_SIZE;
+                if (terminate) {
+                    ofile->zs.avail_in = 0;
+                    if (flush == Z_SYNC_FLUSH) {
+                        sync_avail_out_to_ftell(ofile);
+                    }
+                    return;
+                }
+            } else {
+                ofile->zs.avail_in = 0;
+                return;
+            }
+        } else {
+            croak("deflate(%ld,%d) failed, error %d (%s) in pid %d",
+                (long)ofile->zs.avail_in, flush, status, ofile->zs.msg,  
getpid());
+        }
+    }
+}
+#endif
+
+size_t
+NYTP_write(NYTP_file ofile, const void *buffer, size_t len) {
+#ifdef HAS_ZLIB
+    size_t result = 0;
+#endif
+    if (FILE_STATE(ofile) == NYTP_FILE_STDIO) {
+        /* fwrite with len==0 is problematic */
+        /* http://www.opengroup.org/platform/resolutions/bwg98-007.html */
+        if (len == 0)
+            return len;
+        if (fwrite(buffer, 1, len, ofile->file) < 1) {
+            dTHX;
+            croak("fwrite error %d writing %ld bytes to fd%d: %s",
+                errno, (long)len, fileno(ofile->file), strerror(errno));
+        }
+        return len;
+    }
+#ifdef HAS_ZLIB
+    else if (FILE_STATE(ofile) != NYTP_FILE_DEFLATE) {
+        compressed_io_croak(ofile, "NYTP_write");
+        return 0;
+    }
+    while (1) {
+        unsigned int remaining
+            = NYTP_FILE_LARGE_BUFFER_SIZE - ofile->zs.avail_in;
+        unsigned char *p = ofile->large_buffer + ofile->zs.avail_in;
+
+        if (remaining >= len) {
+            Copy(buffer, p, len, unsigned char);
+            ofile->zs.avail_in += len;
+            result += len;
+            return result;
+        } else {
+            /* Copy what we can, then flush the buffer. Lather, rinse,  
repeat.
+             */
+            Copy(buffer, p, remaining, unsigned char);
+            ofile->zs.avail_in = NYTP_FILE_LARGE_BUFFER_SIZE;
+            result += remaining;
+            len -= remaining;
+            buffer = (void *)(remaining + (char *)buffer);
+            flush_output(ofile, Z_NO_FLUSH);
+        }
+    }
+#endif
+}
+
+int
+NYTP_scanf(NYTP_file ofile, const char *format, ...) {
+    int retval;
+    va_list args;
+
+    CROAK_IF_NOT_STDIO(ofile, "NYTP_scanf");
+
+    va_start(args, format);
+    retval = vfscanf(ofile->file, format, args);
+    va_end(args);
+
+    return retval;
+}
+
+int
+NYTP_printf(NYTP_file ofile, const char *format, ...) {
+    int retval;
+    va_list args;
+
+    CROAK_IF_NOT_STDIO(ofile, "NYTP_printf");
+
+    va_start(args, format);
+    retval = vfprintf(ofile->file, format, args);
+    va_end(args);
+
+    return retval;
+}
+
+int
+NYTP_flush(NYTP_file file) {
+#ifdef HAS_ZLIB
+    if (FILE_STATE(file) == NYTP_FILE_DEFLATE) {
+        flush_output(file, Z_SYNC_FLUSH);
+    }
+#endif
+    return fflush(file->file);
+}
+
+int
+NYTP_eof(NYTP_file ifile) {
+#ifdef HAS_ZLIB
+    if (FILE_STATE(ifile) == NYTP_FILE_INFLATE) {
+        return ifile->zlib_at_eof;
+    }
+#endif
+    return feof(ifile->file);
+}
+
+const char *
+NYTP_fstrerror(NYTP_file file) {
+    dTHX;
+#ifdef HAS_ZLIB
+    if (FILE_STATE(file) == NYTP_FILE_DEFLATE || FILE_STATE(file) ==  
NYTP_FILE_INFLATE) {
+        return file->zs.msg;
+    }
+#endif
+    return strerror(errno);
+}
+
+int
+NYTP_close(NYTP_file file, int discard) {
+    FILE *raw_file = file->file;
+    int result;
+
+#ifdef HAS_ZLIB
+    if (!discard && FILE_STATE(file) == NYTP_FILE_DEFLATE) {
+        const double ratio = file->zs.total_in / (double)  
file->zs.total_out;
+        flush_output(file, Z_FINISH);
+        fprintf(raw_file, "#\n"
+                "# Total uncompressed bytes %lu\n"
+                "# Total compressed bytes %lu\n"
+                "# Compression ratio 1:%2f, data shrunk by %.2f%%\n",
+                file->zs.total_in, file->zs.total_out, ratio,
+                100 * (1 - 1 / ratio));
+    }
+
+    if (FILE_STATE(file) == NYTP_FILE_DEFLATE) {
+        int status = deflateEnd(&(file->zs));
+        if (status != Z_OK) {
+            if (discard && status == Z_DATA_ERROR) {
+                /* deflateEnd returns Z_OK if success, Z_STREAM_ERROR if  
the
+                   stream state was inconsistent, Z_DATA_ERROR if the  
stream
+                   was freed prematurely (some input or output was  
discarded).
+                */
+            } else {
+                croak("deflateEnd failed, error %d (%s) in %d", status,
+                      file->zs.msg, getpid());
+            }
+        }
+    }
+    else if (FILE_STATE(file) == NYTP_FILE_INFLATE) {
+        int err = inflateEnd(&(file->zs));
+        if (err != Z_OK) {
+            croak("inflateEnd failed, error %d (%s)", err, file->zs.msg);
+        }
+    }
+#endif
+
+    Safefree(file);
+
+    result = ferror(raw_file) ? errno : 0;
+
+    if (discard) {
+        /* close the underlying fd first so any buffered data gets  
discarded
+         * when fclose is called below */
+        close(fileno(raw_file));
+    }
+
+    if (result || discard) {
+        /* Something has already gone wrong, so try to preserve its error  
*/
+        fclose(raw_file);
+        return result;
+    }
+    return fclose(raw_file) == 0 ? 0 : errno;
+}
=======================================
--- /trunk/MANIFEST     Tue Dec 15 14:54:06 2009
+++ /trunk/MANIFEST     Fri Dec 18 07:09:33 2009
@@ -2,6 +2,8 @@
  .indent.pro
  .perltidyrc
  Changes
+FileHandle.h
+FileHandle.xs
  HACKING
  INSTALL
  MANIFEST
=======================================
--- /trunk/Makefile.PL  Thu Dec 10 04:08:45 2009
+++ /trunk/Makefile.PL  Fri Dec 18 07:09:33 2009
@@ -135,6 +135,7 @@
        'JSON::Any'    => 0,
      },
      LIBS      => [join ' ', @libs],
+    OBJECT    => q/$(O_FILES)/,
      EXE_FILES => ['bin/nytprofhtml', 'bin/nytprofcsv', 'bin/nytprofcg'],
      @man,
      INC   => $INCLUDE,
=======================================
--- /trunk/NYTProf.xs   Fri Dec 18 07:09:26 2009
+++ /trunk/NYTProf.xs   Fri Dec 18 07:09:33 2009
@@ -23,6 +23,8 @@
  #include "perl.h"
  #include "XSUB.h"

+#include "FileHandle.h"
+
  #ifndef NO_PPPORT_H
  #define NEED_eval_pv
  #define NEED_grok_number
@@ -211,44 +213,6 @@
  static Hash_table hashtable = { NULL, MAX_HASH_SIZE, NULL, NULL };
  /* END Hash table definitions */

-#define NYTP_FILE_STDIO         0
-#define NYTP_FILE_DEFLATE       1
-#define NYTP_FILE_INFLATE       2
-
-/* During profiling the large buffer collects the raw data until full.
- * Then flush_output zips it into the small buffer and writes it to disk.
- * A scale factor of ~90 makes the large buffer usually almost fill the  
small
- * one when zipped (so calls to flush_output() almost always trigger one  
fwrite()).
- * We use a lower number to save some memory as there's little performance
- * impact either way.
- */
-#define NYTP_FILE_SMALL_BUFFER_SIZE   4096
-#define NYTP_FILE_LARGE_BUFFER_SIZE   (NYTP_FILE_SMALL_BUFFER_SIZE * 40)
-
-#ifdef HAS_ZLIB
-#  define FILE_STATE(f)         ((f)->state)
-#else
-#  define FILE_STATE(f)         NYTP_FILE_STDIO
-#endif
-
-typedef struct {
-    FILE *file;
-#ifdef HAS_ZLIB
-    unsigned char state;
-    bool stdio_at_eof;
-    bool zlib_at_eof;
-    /* For input only, the position we are in large_buffer.  */
-    unsigned int count;
-    z_stream zs;
-    unsigned char small_buffer[NYTP_FILE_SMALL_BUFFER_SIZE];
-    unsigned char large_buffer[NYTP_FILE_LARGE_BUFFER_SIZE];
-#endif
-} NYTP_file_t;
-
-typedef NYTP_file_t *NYTP_file;
-
-static int NYTP_eof(NYTP_file ifile);
-static const char * NYTP_fstrerror(NYTP_file file);

  /* defaults */
  static NYTP_file out;
@@ -419,505 +383,6 @@
   * Devel::NYTProf Functions        *
   ***********************************/

-/* XXX The proper return value would be Off_t */
-static long
-NYTP_tell(NYTP_file file) {
-#ifdef HAS_ZLIB
-    /* This has to work with compressed files as it's used in the croaking
-       routine.  */
-    if (FILE_STATE(file) != NYTP_FILE_STDIO) {
-        return FILE_STATE(file) == NYTP_FILE_INFLATE
-            ? file->zs.total_out : file->zs.total_in;
-    }
-#endif
-    return (long)ftell(file->file);
-}
-
-#ifdef HAS_ZLIB
-static const char *
-NYTP_type_of_offset(NYTP_file file) {
-    switch (FILE_STATE(file)) {
-    case NYTP_FILE_STDIO:
-        return "";
-    case NYTP_FILE_DEFLATE:
-        return " in compressed output data";
-        break;
-    case NYTP_FILE_INFLATE:
-        return " in compressed input data";
-        break;
-    default:
-        return Perl_form_nocontext(" in stream in unknown state %d",
-                                   FILE_STATE(file));
-    }
-}
-#else
-#define NYTP_type_of_offset(file) ""
-#endif
-
-#ifdef HAS_ZLIB
-#  define CROAK_IF_NOT_STDIO(file, where)           \
-    STMT_START {                                    \
-        if (FILE_STATE(file) != NYTP_FILE_STDIO) {  \
-            compressed_io_croak((file), (where));   \
-        }                                           \
-    } STMT_END
-#else
-#  define CROAK_IF_NOT_STDIO(file, where)
-#endif
-
-#ifdef HAS_ZLIB
-#ifdef HASATTRIBUTE_NORETURN
-__attribute__noreturn__
-#endif
-static void
-compressed_io_croak(NYTP_file file, const char *function) {
-    const char *what;
-
-    switch (FILE_STATE(file)) {
-    case NYTP_FILE_STDIO:
-        what = "stdio";
-        break;
-    case NYTP_FILE_DEFLATE:
-        what = "compressed output";
-        break;
-    case NYTP_FILE_INFLATE:
-        what = "compressed input";
-        break;
-    default:
-        croak("Can't use function %s() on a stream of type %d at  
offset %ld",
-              function, FILE_STATE(file), NYTP_tell(file));
-    }
-    croak("Can't use function %s() on a %s stream at offset %ld", function,
-          what, NYTP_tell(file));
-}
-
-static void
-NYTP_start_deflate(NYTP_file file) {
-    int status;
-
-    CROAK_IF_NOT_STDIO(file, "NYTP_start_deflate");
-    FILE_STATE(file) = NYTP_FILE_DEFLATE;
-    file->zs.next_in = (Bytef *) file->large_buffer;
-    file->zs.avail_in = 0;
-    file->zs.next_out = (Bytef *) file->small_buffer;
-    file->zs.avail_out = NYTP_FILE_SMALL_BUFFER_SIZE;
-    file->zs.zalloc = (alloc_func) 0;
-    file->zs.zfree = (free_func) 0;
-    file->zs.opaque = 0;
-
-    status = deflateInit2(&(file->zs), compression_level, Z_DEFLATED,
-        15 /* windowBits */,
-        9 /* memLevel */, Z_DEFAULT_STRATEGY);
-    if (status != Z_OK) {
-        croak("deflateInit2 failed, error %d (%s)", status, file->zs.msg);
-    }
-}
-
-static void
-NYTP_start_inflate(NYTP_file file) {
-    int status;
-    CROAK_IF_NOT_STDIO(file, "NYTP_start_inflate");
-    FILE_STATE(file) = NYTP_FILE_INFLATE;
-
-    file->zs.next_in = (Bytef *) file->small_buffer;
-    file->zs.avail_in = 0;
-    file->zs.next_out = (Bytef *) file->large_buffer;
-    file->zs.avail_out = NYTP_FILE_LARGE_BUFFER_SIZE;
-    file->zs.zalloc = (alloc_func) 0;
-    file->zs.zfree = (free_func) 0;
-    file->zs.opaque = 0;
-
-    status = inflateInit2(&(file->zs), 15);
-    if (status != Z_OK) {
-        croak("inflateInit2 failed, error %d (%s)", status, file->zs.msg);
-    }
-}
-#endif
-
-static NYTP_file_t *
-NYTP_open(const char *name, const char *mode) {
-    FILE *raw_file = fopen(name, mode);
-    NYTP_file file;
-
-    if (!raw_file)
-        return NULL;
-
-    Newx(file, 1, NYTP_file_t);
-    file->file = raw_file;
-
-#ifdef HAS_ZLIB
-    file->state = NYTP_FILE_STDIO;
-    file->count = 0;
-    file->stdio_at_eof = FALSE;
-    file->zlib_at_eof = FALSE;
-
-    file->zs.msg = "[Oops. zlib hasn't updated this error string]";
-#endif
-
-    return file;
-}
-
-static char *
-NYTP_gets(NYTP_file ifile, char *buffer, unsigned int len) {
-    CROAK_IF_NOT_STDIO(ifile, "NYTP_gets");
-
-    return fgets(buffer, len, ifile->file);
-}
-
-#ifdef HAS_ZLIB
-
-static void
-grab_input(NYTP_file ifile) {
-    ifile->count = 0;
-    ifile->zs.next_out = (Bytef *) ifile->large_buffer;
-    ifile->zs.avail_out = NYTP_FILE_LARGE_BUFFER_SIZE;
-
-#ifdef DEBUG_INFLATE
-    fprintf(stderr, "grab_input enter\n");
-#endif
-
-    while (1) {
-        int status;
-
-        if (ifile->zs.avail_in == 0 && !ifile->stdio_at_eof) {
-            size_t got = fread(ifile->small_buffer, 1,
-                               NYTP_FILE_SMALL_BUFFER_SIZE, ifile->file);
-
-            if (got == 0) {
-                if (!feof(ifile->file)) {
-                    dTHX;
-                    croak("grab_input failed: %d (%s)", errno,  
strerror(errno));
-                }
-                ifile->stdio_at_eof = TRUE;
-            }
-
-            ifile->zs.avail_in = got;
-            ifile->zs.next_in = (Bytef *) ifile->small_buffer;
-        }
-
-#ifdef DEBUG_INFLATE
-        fprintf(stderr, "grab_input predef  next_in= %p avail_in= %08x\n"
-                        "                   next_out=%p avail_out=%08x"
-                " eof=%d,%d\n", ifile->zs.next_in, ifile->zs.avail_in,
-                ifile->zs.next_out, ifile->zs.avail_out,  
ifile->stdio_at_eof,
-                ifile->zlib_at_eof);
-#endif
-
-        status = inflate(&(ifile->zs), Z_NO_FLUSH);
-
-#ifdef DEBUG_INFLATE
-        fprintf(stderr, "grab_input postdef next_in= %p avail_in= %08x\n"
-                        "                   next_out=%p avail_out=%08x "
-                "status=%d\n", ifile->zs.next_in, ifile->zs.avail_in,
-                ifile->zs.next_out, ifile->zs.avail_out, status);
-#endif
-
-        if (!(status == Z_OK || status == Z_STREAM_END)) {
-            if (ifile->stdio_at_eof)
-                croak("Error reading file: inflate failed, error %d (%s)  
at end of input file, "
-                    " perhaps the process didn't exit cleanly or the file  
has been truncated",
-                    status, ifile->zs.msg);
-            croak("Error reading file: inflate failed, error %d (%s) at  
offset %ld in input file",
-                  status, ifile->zs.msg, (long)ftell(ifile->file));
-        }
-
-        if (ifile->zs.avail_out == 0 || status == Z_STREAM_END) {
-            if (status == Z_STREAM_END) {
-                ifile->zlib_at_eof = TRUE;
-            }
-            return;
-        }
-    }
-}
-
-#endif
-
-
-static size_t
-NYTP_read_unchecked(NYTP_file ifile, void *buffer, size_t len) {
-#ifdef HAS_ZLIB
-    size_t result = 0;
-#endif
-    if (FILE_STATE(ifile) == NYTP_FILE_STDIO) {
-        return fread(buffer, 1, len, ifile->file);
-    }
-#ifdef HAS_ZLIB
-    else if (FILE_STATE(ifile) != NYTP_FILE_INFLATE) {
-        compressed_io_croak(ifile, "NYTP_read");
-        return 0;
-    }
-    while (1) {
-        unsigned char *p = ifile->large_buffer + ifile->count;
-        unsigned int remaining = ((unsigned char *) ifile->zs.next_out) -  
p;
-
-        if (remaining >= len) {
-            Copy(p, buffer, len, unsigned char);
-            ifile->count += len;
-            result += len;
-            return result;
-        }
-        Copy(p, buffer, remaining, unsigned char);
-        ifile->count = NYTP_FILE_LARGE_BUFFER_SIZE;
-        result += remaining;
-        len -= remaining;
-        buffer = (void *)(remaining + (char *)buffer);
-        if (ifile->zlib_at_eof)
-            return result;
-        grab_input(ifile);
-    }
-#endif
-}
-
-
-static size_t
-NYTP_read(NYTP_file ifile, void *buffer, size_t len, const 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 %ld got %ld, %s",
-              what, NYTP_tell(ifile), NYTP_type_of_offset(ifile),  
(long)len, (long)got,
-                (NYTP_eof(ifile)) ? "end of file" : NYTP_fstrerror(ifile));
-    }
-    return len;
-}
-
-
-#ifdef HAS_ZLIB
-/* Cheat, by telling zlib about a reduced amount of available output space,
-   such that our next write of the (slightly underused) output buffer will
-   align the underlying file pointer back with the size of our output  
buffer
-   (and hopefully the underlying OS block writes).  */
-static void
-sync_avail_out_to_ftell(NYTP_file ofile) {
-    const long result = ftell(ofile->file);
-    const unsigned long where = result < 0 ? 0 : result;
-    ofile->zs.avail_out =
-        NYTP_FILE_SMALL_BUFFER_SIZE - where % NYTP_FILE_SMALL_BUFFER_SIZE;
-#ifdef DEBUG_DEFLATE
-    fprintf(stderr, "sync_avail_out_to_ftell pos=%ld, avail_out=%lu\n",
-            result, (unsigned long) ofile->zs.avail_out);
-#endif
-}
-
-/* flush has values as described for "allowed flush values" in zlib.h  */
-static void
-flush_output(NYTP_file ofile, int flush) {
-    ofile->zs.next_in = (Bytef *) ofile->large_buffer;
-
-#ifdef DEBUG_DEFLATE
-    fprintf(stderr, "flush_output enter   flush = %d\n", flush);
-#endif
-    while (1) {
-        int status;
-#ifdef DEBUG_DEFLATE
-        fprintf(stderr, "flush_output predef  next_in= %p avail_in= %08x\n"
-                        "                     next_out=%p avail_out=%08x"
-                " flush=%d\n", ofile->zs.next_in, ofile->zs.avail_in,
-                ofile->zs.next_out, ofile->zs.avail_out, flush);
-#endif
-        status = deflate(&(ofile->zs), flush);
-
-        /* workaround for RT#50851 */
-        if (status == Z_BUF_ERROR && flush != Z_NO_FLUSH
-                && !ofile->zs.avail_in && ofile->zs.avail_out)
-            status = Z_OK;
-
-#ifdef DEBUG_DEFLATE
-        fprintf(stderr, "flush_output postdef next_in= %p avail_in= %08x\n"
-                        "                     next_out=%p avail_out=%08x "
-                "status=%d\n", ofile->zs.next_in, ofile->zs.avail_in,
-                ofile->zs.next_out, ofile->zs.avail_out, status);
-#endif
-
-        if (status == Z_OK || status == Z_STREAM_END) {
-            if (ofile->zs.avail_out == 0 || flush != Z_NO_FLUSH) {
-                int terminate
-                    = ofile->zs.avail_in == 0 && ofile->zs.avail_out > 0;
-                size_t avail = ((unsigned char *) ofile->zs.next_out)
-                    - ofile->small_buffer;
-                const unsigned char *where = ofile->small_buffer;
-
-                while (avail > 0) {
-                    size_t count = fwrite(where, 1, avail, ofile->file);
-
-                    if (count > 0) {
-                        where += count;
-                        avail -= count;
-                    } else {
-                        dTHX;
-                        croak("fwrite in flush error %d: %s", errno,
-                              strerror(errno));
-                    }
-                }
-                ofile->zs.next_out = (Bytef *) ofile->small_buffer;
-                ofile->zs.avail_out = NYTP_FILE_SMALL_BUFFER_SIZE;
-                if (terminate) {
-                    ofile->zs.avail_in = 0;
-                    if (flush == Z_SYNC_FLUSH) {
-                        sync_avail_out_to_ftell(ofile);
-                    }
-                    return;
-                }
-            } else {
-                ofile->zs.avail_in = 0;
-                return;
-            }
-        } else {
-            croak("deflate(%ld,%d) failed, error %d (%s) in pid %d",
-                (long)ofile->zs.avail_in, flush, status, ofile->zs.msg,  
getpid());
-        }
-    }
-}
-#endif
-
-static size_t
-NYTP_write(NYTP_file ofile, const void *buffer, size_t len) {
-#ifdef HAS_ZLIB
-    size_t result = 0;
-#endif
-    if (FILE_STATE(ofile) == NYTP_FILE_STDIO) {
-        /* fwrite with len==0 is problematic */
-        /* http://www.opengroup.org/platform/resolutions/bwg98-007.html */
-        if (len == 0)
-            return len;
-        if (fwrite(buffer, 1, len, ofile->file) < 1) {
-            dTHX;
-            croak("fwrite error %d writing %ld bytes to fd%d: %s",
-                errno, (long)len, fileno(ofile->file), strerror(errno));
-        }
-        return len;
-    }
-#ifdef HAS_ZLIB
-    else if (FILE_STATE(ofile) != NYTP_FILE_DEFLATE) {
-        compressed_io_croak(ofile, "NYTP_write");
-        return 0;
-    }
-    while (1) {
-        unsigned int remaining
-            = NYTP_FILE_LARGE_BUFFER_SIZE - ofile->zs.avail_in;
-        unsigned char *p = ofile->large_buffer + ofile->zs.avail_in;
-
-        if (remaining >= len) {
-            Copy(buffer, p, len, unsigned char);
-            ofile->zs.avail_in += len;
-            result += len;
-            return result;
-        } else {
-            /* Copy what we can, then flush the buffer. Lather, rinse,  
repeat.
-             */
-            Copy(buffer, p, remaining, unsigned char);
-            ofile->zs.avail_in = NYTP_FILE_LARGE_BUFFER_SIZE;
-            result += remaining;
-            len -= remaining;
-            buffer = (void *)(remaining + (char *)buffer);
-            flush_output(ofile, Z_NO_FLUSH);
-        }
-    }
-#endif
-}
-
-static int
-NYTP_printf(NYTP_file ofile, const char *format, ...) {
-    int retval;
-    va_list args;
-
-    CROAK_IF_NOT_STDIO(ofile, "NYTP_printf");
-
-    va_start(args, format);
-    retval = vfprintf(ofile->file, format, args);
-    va_end(args);
-
-    return retval;
-}
-
-static int
-NYTP_flush(NYTP_file file) {
-#ifdef HAS_ZLIB
-    if (FILE_STATE(file) == NYTP_FILE_DEFLATE) {
-        flush_output(file, Z_SYNC_FLUSH);
-    }
-#endif
-    return fflush(file->file);
-}
-
-static int
-NYTP_eof(NYTP_file ifile) {
-#ifdef HAS_ZLIB
-    if (FILE_STATE(ifile) == NYTP_FILE_INFLATE) {
-        return ifile->zlib_at_eof;
-    }
-#endif
-    return feof(ifile->file);
-}
-
-static const char *
-NYTP_fstrerror(NYTP_file file) {
-    dTHX;
-#ifdef HAS_ZLIB
-    if (FILE_STATE(file) == NYTP_FILE_DEFLATE || FILE_STATE(file) ==  
NYTP_FILE_INFLATE) {
-        return file->zs.msg;
-    }
-#endif
-    return strerror(errno);
-}
-
-static int
-NYTP_close(NYTP_file file, int discard) {
-    FILE *raw_file = file->file;
-    int result;
-
-#ifdef HAS_ZLIB
-    if (!discard && FILE_STATE(file) == NYTP_FILE_DEFLATE) {
-        const double ratio = file->zs.total_in / (double)  
file->zs.total_out;
-        flush_output(file, Z_FINISH);
-        fprintf(raw_file, "#\n"
-                "# Total uncompressed bytes %lu\n"
-                "# Total compressed bytes %lu\n"
-                "# Compression ratio 1:%2f, data shrunk by %.2f%%\n",
-                file->zs.total_in, file->zs.total_out, ratio,
-                100 * (1 - 1 / ratio));
-    }
-
-    if (FILE_STATE(file) == NYTP_FILE_DEFLATE) {
-        int status = deflateEnd(&(file->zs));
-        if (status != Z_OK) {
-            if (discard && status == Z_DATA_ERROR) {
-                /* deflateEnd returns Z_OK if success, Z_STREAM_ERROR if  
the
-                   stream state was inconsistent, Z_DATA_ERROR if the  
stream
-                   was freed prematurely (some input or output was  
discarded).
-                */
-            } else {
-                croak("deflateEnd failed, error %d (%s) in %d", status,
-                      file->zs.msg, getpid());
-            }
-        }
-    }
-    else if (FILE_STATE(file) == NYTP_FILE_INFLATE) {
-        int err = inflateEnd(&(file->zs));
-        if (err != Z_OK) {
-            croak("inflateEnd failed, error %d (%s)", err, file->zs.msg);
-        }
-    }
-#endif
-
-    Safefree(file);
-
-    result = ferror(raw_file) ? errno : 0;
-
-    if (discard) {
-        /* close the underlying fd first so any buffered data gets  
discarded
-         * when fclose is called below */
-        close(fileno(raw_file));
-    }
-
-    if (result || discard) {
-        /* Something has already gone wrong, so try to preserve its error  
*/
-        fclose(raw_file);
-        return result;
-    }
-    return fclose(raw_file) == 0 ? 0 : errno;
-}
-
-
  static NV
  gettimeofday_nv(void)
  {
@@ -979,7 +444,7 @@
          NYTP_printf(out, "# Compressed at level %d with zlib %s\n",
                      compression_level, zlibVersion());
          NYTP_write(out, &tag, sizeof(tag));
-        NYTP_start_deflate(out);
+        NYTP_start_deflate(out, compression_level);
      }
  #endif

@@ -3942,8 +3407,7 @@
      av_extend(fid_srclines_av, 64);
      av_extend(fid_line_time_av, 64);

-    CROAK_IF_NOT_STDIO(in, "load_profile_data_from_stream");
-    if (2 != fscanf(in->file, "NYTProf %d %d\n", &file_major,  
&file_minor)) {
+    if (2 != NYTP_scanf(in, "NYTProf %d %d\n", &file_major, &file_minor)) {
          croak("NYTProf data format error while parsing header");
      }
      if (file_major != 3)

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