File Coverage

FileHandle.xs
Criterion Covered Total %
statement 414 591 70.0
branch 167 320 52.1
condition n/a
subroutine n/a
pod n/a
total 581 911 63.7


line stmt bran cond sub pod time code
1             /* vim: ts=8 sw=4 expandtab:
2             * ************************************************************************
3             * This file is part of the Devel::NYTProf package.
4             * See http://metacpan.org/release/Devel-NYTProf/
5             * For Copyright see lib/Devel/NYTProf.pm
6             * For contribution history see repository logs.
7             * ************************************************************************
8             */
9              
10             #define PERL_NO_GET_CONTEXT /* we want efficiency */
11             #include "EXTERN.h"
12             #include "perl.h"
13             #include "XSUB.h"
14             #if defined(PERL_IMPLICIT_SYS) && !defined(NO_XSLOCKS)
15             # ifndef fgets
16             # define fgets PerlSIO_fgets
17             # endif
18             #endif
19              
20             #include "FileHandle.h"
21             #include "NYTProf.h"
22              
23             #define NEED_sv_2pvbyte
24             #include "ppport.h"
25              
26             #ifdef HAS_ZLIB
27             # include
28             #endif
29              
30             #define NYTP_FILE_STDIO 0
31             #define NYTP_FILE_DEFLATE 1
32             #define NYTP_FILE_INFLATE 2
33              
34             /* to help find places in NYTProf.xs where we don't save/restore errno */
35             #if 0
36             #define ERRNO_PROBE errno=__LINE__
37             #else
38             #define ERRNO_PROBE (void)0
39             #endif
40              
41             /* During profiling the large buffer collects the raw data until full.
42             * Then flush_output zips it into the small buffer and writes it to disk.
43             * A scale factor of ~90 makes the large buffer usually almost fill the small
44             * one when zipped (so calls to flush_output() almost always trigger one fwrite()).
45             * We use a lower number to save some memory as there's little performance
46             * impact either way.
47             */
48             #define NYTP_FILE_SMALL_BUFFER_SIZE 4096
49             #define NYTP_FILE_LARGE_BUFFER_SIZE (NYTP_FILE_SMALL_BUFFER_SIZE * 40)
50              
51             #ifdef HAS_ZLIB
52             # define FILE_STATE(f) ((f)->state)
53             #else
54             # define FILE_STATE(f) NYTP_FILE_STDIO
55             #endif
56              
57             #if defined(PERL_IMPLICIT_CONTEXT) && ! defined(tTHX)
58             # define tTHX PerlInterpreter*
59             #endif
60              
61             struct NYTP_file_t {
62             FILE *file;
63             #ifdef PERL_IMPLICIT_CONTEXT
64             tTHX aTHX; /* on 5.8 and older, pTHX contains a "register" which is not
65             compatible with a struct def, so use something else */
66             #endif
67             #ifdef HAS_ZLIB
68             unsigned char state;
69             bool stdio_at_eof;
70             bool zlib_at_eof;
71             /* For input only, the position we are in large_buffer. */
72             unsigned int count;
73             z_stream zs;
74             unsigned char small_buffer[NYTP_FILE_SMALL_BUFFER_SIZE];
75             unsigned char large_buffer[NYTP_FILE_LARGE_BUFFER_SIZE];
76             #endif
77             };
78              
79             /* unlike dTHX which contains a function call, and therefore can never be
80             optimized away, even if return value isn't used, the below will optimize away
81             if NO_XSLOCKS is defined and PerlIO is not being used (i.e. native C lib
82             IO is being used on Win32 )*/
83             #ifdef PERL_IMPLICIT_CONTEXT
84             # define dNFTHX(x) dTHXa((x)->aTHX)
85             #else
86             # define dNFTHX(x) dNOOP
87             #endif
88              
89             /* XXX The proper return value would be Off_t */
90             long
91 0           NYTP_tell(NYTP_file file) {
92             ERRNO_PROBE;
93              
94             #ifdef HAS_ZLIB
95             /* This has to work with compressed files as it's used in the croaking
96             routine. */
97 0 0         if (FILE_STATE(file) != NYTP_FILE_STDIO) {
98 0 0         return FILE_STATE(file) == NYTP_FILE_INFLATE
99 0           ? file->zs.total_out : file->zs.total_in;
100             }
101             #endif
102             {
103             dNFTHX(file);
104 0           return (long)ftell(file->file);
105             }
106             }
107              
108             #ifdef HAS_ZLIB
109             const char *
110 0           NYTP_type_of_offset(NYTP_file file) {
111 0           switch (FILE_STATE(file)) {
112             case NYTP_FILE_STDIO:
113 0           return "";
114             case NYTP_FILE_DEFLATE:
115 0           return " in compressed output data";
116             break;
117             case NYTP_FILE_INFLATE:
118 0           return " in compressed input data";
119             break;
120             default:
121 0           return Perl_form_nocontext(" in stream in unknown state %d",
122 0           FILE_STATE(file));
123             }
124             }
125             #endif
126              
127             #ifdef HAS_ZLIB
128             # define CROAK_IF_NOT_STDIO(file, where) \
129             STMT_START { \
130             if (FILE_STATE(file) != NYTP_FILE_STDIO) { \
131             compressed_io_croak((file), (where)); \
132             } \
133             } STMT_END
134             #else
135             # define CROAK_IF_NOT_STDIO(file, where)
136             #endif
137              
138             #ifdef HAS_ZLIB
139             #ifdef HASATTRIBUTE_NORETURN
140             __attribute__noreturn__
141             #endif
142             static void
143 0           compressed_io_croak(NYTP_file file, const char *function) {
144             const char *what;
145              
146 0           switch (FILE_STATE(file)) {
147             case NYTP_FILE_STDIO:
148 0           what = "stdio";
149 0           break;
150             case NYTP_FILE_DEFLATE:
151 0           what = "compressed output";
152 0           break;
153             case NYTP_FILE_INFLATE:
154 0           what = "compressed input";
155 0           break;
156             default:
157 0           croak("Can't use function %s() on a stream of type %d at offset %ld",
158 0           function, FILE_STATE(file), NYTP_tell(file));
159             }
160 0           croak("Can't use function %s() on a %s stream at offset %ld", function,
161             what, NYTP_tell(file));
162             }
163              
164             void
165 385           NYTP_start_deflate(NYTP_file file, int compression_level) {
166             int status;
167             ERRNO_PROBE;
168              
169 385 50         CROAK_IF_NOT_STDIO(file, "NYTP_start_deflate");
170 385           FILE_STATE(file) = NYTP_FILE_DEFLATE;
171 385           file->zs.next_in = (Bytef *) file->large_buffer;
172 385           file->zs.avail_in = 0;
173 385           file->zs.next_out = (Bytef *) file->small_buffer;
174 385           file->zs.avail_out = NYTP_FILE_SMALL_BUFFER_SIZE;
175 385           file->zs.zalloc = (alloc_func) 0;
176 385           file->zs.zfree = (free_func) 0;
177 385           file->zs.opaque = 0;
178              
179 385           status = deflateInit2(&(file->zs), compression_level, Z_DEFLATED,
180             15 /* windowBits */,
181             9 /* memLevel */, Z_DEFAULT_STRATEGY);
182 385 50         if (status != Z_OK) {
183 0           croak("deflateInit2 failed, error %d (%s)", status, file->zs.msg);
184             }
185 385           }
186              
187             void
188 755           NYTP_start_inflate(NYTP_file file) {
189             int status;
190             ERRNO_PROBE;
191              
192 755 50         CROAK_IF_NOT_STDIO(file, "NYTP_start_inflate");
193 755           FILE_STATE(file) = NYTP_FILE_INFLATE;
194              
195 755           file->zs.next_in = (Bytef *) file->small_buffer;
196 755           file->zs.avail_in = 0;
197 755           file->zs.next_out = (Bytef *) file->large_buffer;
198 755           file->zs.avail_out = NYTP_FILE_LARGE_BUFFER_SIZE;
199 755           file->zs.zalloc = (alloc_func) 0;
200 755           file->zs.zfree = (free_func) 0;
201 755           file->zs.opaque = 0;
202              
203 755           status = inflateInit2(&(file->zs), 15);
204 755 50         if (status != Z_OK) {
205 0           croak("inflateInit2 failed, error %d (%s)", status, file->zs.msg);
206             }
207 755           }
208             #endif
209              
210             NYTP_file
211 2048           NYTP_open(const char *name, const char *mode) {
212             dTHX;
213 2048           FILE *raw_file = fopen(name, mode);
214             NYTP_file file;
215             ERRNO_PROBE;
216              
217 2048 50         if (!raw_file)
218 0           return NULL;
219              
220             /* MS libc has 4096 as default, this is too slow for GB size profiling data */
221 2048 50         if (setvbuf(raw_file, NULL, _IOFBF, 16384))
222 0           return NULL;
223 2048           Newx(file, 1, struct NYTP_file_t);
224 2048           file->file = raw_file;
225              
226             #ifdef PERL_IMPLICIT_CONTEXT
227             file->aTHX = aTHX;
228             #endif
229             #ifdef HAS_ZLIB
230 2048           file->state = NYTP_FILE_STDIO;
231 2048           file->count = 0;
232 2048           file->stdio_at_eof = FALSE;
233 2048           file->zlib_at_eof = FALSE;
234              
235 2048           file->zs.msg = (char *)"[Oops. zlib hasn't updated this error string]";
236             #endif
237              
238 2048           return file;
239             }
240              
241             #ifdef HAS_ZLIB
242              
243             static void
244 787           grab_input(NYTP_file ifile) {
245             dNFTHX(ifile);
246             ERRNO_PROBE;
247              
248 787           ifile->count = 0;
249 787           ifile->zs.next_out = (Bytef *) ifile->large_buffer;
250 787           ifile->zs.avail_out = NYTP_FILE_LARGE_BUFFER_SIZE;
251              
252             #ifdef DEBUG_INFLATE
253             fprintf(stderr, "grab_input enter\n");
254             #endif
255              
256             while (1) {
257             int status;
258              
259 930 100         if (ifile->zs.avail_in == 0 && !ifile->stdio_at_eof) {
    50          
260 898           size_t got = fread(ifile->small_buffer, 1,
261             NYTP_FILE_SMALL_BUFFER_SIZE, ifile->file);
262              
263 898 50         if (got == 0) {
264 0 0         if (!feof(ifile->file)) {
265 0           int eno = errno;
266 0           croak("grab_input failed: %d (%s)", eno, strerror(eno));
267             }
268 0           ifile->stdio_at_eof = TRUE;
269             }
270              
271 898           ifile->zs.avail_in = got;
272 898           ifile->zs.next_in = (Bytef *) ifile->small_buffer;
273             }
274              
275             #ifdef DEBUG_INFLATE
276             fprintf(stderr, "grab_input predef next_in= %p avail_in= %08x\n"
277             " next_out=%p avail_out=%08x"
278             " eof=%d,%d\n", ifile->zs.next_in, ifile->zs.avail_in,
279             ifile->zs.next_out, ifile->zs.avail_out, ifile->stdio_at_eof,
280             ifile->zlib_at_eof);
281             #endif
282              
283 930           status = inflate(&(ifile->zs), Z_NO_FLUSH);
284              
285             #ifdef DEBUG_INFLATE
286             fprintf(stderr, "grab_input postdef next_in= %p avail_in= %08x\n"
287             " next_out=%p avail_out=%08x "
288             "status=%d\n", ifile->zs.next_in, ifile->zs.avail_in,
289             ifile->zs.next_out, ifile->zs.avail_out, status);
290             #endif
291              
292 930 100         if (!(status == Z_OK || status == Z_STREAM_END)) {
    50          
293 0 0         if (ifile->stdio_at_eof)
294 0           croak("Profile data incomplete, inflate error %d (%s) at end of input file,"
295             " perhaps the process didn't exit cleanly or the file has been truncated "
296             " (refer to TROUBLESHOOTING in the documentation)\n",
297             status, ifile->zs.msg);
298 0           croak("Error reading file: inflate failed, error %d (%s) at offset %ld in input file",
299 0           status, ifile->zs.msg, (long)ftell(ifile->file));
300             }
301              
302 930 100         if (ifile->zs.avail_out == 0 || status == Z_STREAM_END) {
    100          
303 787 100         if (status == Z_STREAM_END) {
304 755           ifile->zlib_at_eof = TRUE;
305             }
306 787           return;
307             }
308 143           }
309             }
310              
311             #endif
312              
313              
314             size_t
315 12356889           NYTP_read_unchecked(NYTP_file ifile, void *buffer, size_t len) {
316             dNFTHX(ifile);
317             #ifdef HAS_ZLIB
318 12356889           size_t result = 0;
319             #endif
320             ERRNO_PROBE;
321 12356889 100         if (FILE_STATE(ifile) == NYTP_FILE_STDIO) {
322 5662086           return fread(buffer, 1, len, ifile->file);
323             }
324             #ifdef HAS_ZLIB
325 6694803 50         else if (FILE_STATE(ifile) != NYTP_FILE_INFLATE) {
326 0           compressed_io_croak(ifile, "NYTP_read");
327             return 0;
328             }
329             while (1) {
330 6695590           unsigned char *p = ifile->large_buffer + ifile->count;
331 6695590           int remaining = ((unsigned char *) ifile->zs.next_out) - p;
332              
333 6695590 100         if (remaining >= len) {
334 6694048           Copy(p, buffer, len, unsigned char);
335 6694048           ifile->count += len;
336 6694048           result += len;
337 6694048           return result;
338             }
339 1542           Copy(p, buffer, remaining, unsigned char);
340 1542           ifile->count = NYTP_FILE_LARGE_BUFFER_SIZE;
341 1542           result += remaining;
342 1542           len -= remaining;
343 1542           buffer = (void *)(remaining + (char *)buffer);
344 1542 100         if (ifile->zlib_at_eof)
345 755           return result;
346 787           grab_input(ifile);
347 787           }
348             #endif
349             }
350              
351              
352             size_t
353 9982839           NYTP_read(NYTP_file ifile, void *buffer, size_t len, const char *what) {
354 9982839           size_t got = NYTP_read_unchecked(ifile, buffer, len);
355 9982839 50         if (got != len) {
356 0 0         croak("Profile format error whilst reading %s at %ld%s: expected %ld got %ld, %s (see TROUBLESHOOTING in docs)",
357             what, NYTP_tell(ifile), NYTP_type_of_offset(ifile), (long)len, (long)got,
358 0           (NYTP_eof(ifile)) ? "end of file" : NYTP_fstrerror(ifile));
359             }
360 9982839           return len;
361             }
362              
363             /* This isn't exactly fgets. It will resize the buffer as needed, and returns
364             a pointer to one beyond the read data (usually the terminating '\0'), or
365             NULL if it hit error/EOF */
366              
367             char *
368 39702           NYTP_gets(NYTP_file ifile, char **buffer_p, size_t *len_p) {
369 39702           char *buffer = *buffer_p;
370 39702           size_t len = *len_p;
371 39702           size_t prev_len = 0;
372             ERRNO_PROBE;
373              
374             #ifdef HAS_ZLIB
375 39702 100         if (FILE_STATE(ifile) == NYTP_FILE_INFLATE) {
376             while (1) {
377 755           const unsigned char *const p = ifile->large_buffer + ifile->count;
378 755           const unsigned int remaining = ((unsigned char *) ifile->zs.next_out) - p;
379 755           unsigned char *const nl = (unsigned char *)memchr(p, '\n', remaining);
380             size_t got;
381             size_t want;
382             size_t extra;
383              
384 755 50         if (nl) {
385 755           want = nl + 1 - p;
386 755           extra = want + 1; /* 1 more to add a \0 */
387             } else {
388 0           want = extra = remaining;
389             }
390              
391 755 50         if (extra > len - prev_len) {
392 0           prev_len = len;
393 0           len += extra;
394 0           buffer = (char *)saferealloc(buffer, len);
395             }
396              
397 755           got = NYTP_read_unchecked(ifile, buffer + prev_len, want);
398 755 50         if (got != want)
399 0           croak("NYTP_gets unexpected short read. got %lu, expected %lu\n",
400             (unsigned long)got, (unsigned long)want);
401              
402 755 50         if (nl) {
403 755           buffer[prev_len + want] = '\0';
404 755           *buffer_p = buffer;
405 755           *len_p = len;
406 755           return buffer + prev_len + want;
407             }
408 0 0         if (ifile->zlib_at_eof) {
409 0           *buffer_p = buffer;
410 0           *len_p = len;
411 0           return NULL;
412             }
413 0           grab_input(ifile);
414 0           }
415             }
416             #endif
417 38947 50         CROAK_IF_NOT_STDIO(ifile, "NYTP_gets");
418              
419             {
420             dNFTHX(ifile);
421 38947 50         while(fgets(buffer + prev_len, (int)(len - prev_len), ifile->file)) {
422             /* We know that there are no '\0' bytes in the part we've already
423             read, so don't bother running strlen() over that part. */
424 38947           char *end = buffer + prev_len + strlen(buffer + prev_len);
425 38947 50         if (end[-1] == '\n') {
426 38947           *buffer_p = buffer;
427 38947           *len_p = len;
428 38947           return end;
429             }
430 0           prev_len = len - 1; /* -1 to take off the '\0' at the end */
431 0           len *= 2;
432 0           buffer = (char *)saferealloc(buffer, len);
433             }
434             }
435 0           *buffer_p = buffer;
436 0           *len_p = len;
437 0           return NULL;
438             }
439              
440              
441             #ifdef HAS_ZLIB
442             /* Cheat, by telling zlib about a reduced amount of available output space,
443             such that our next write of the (slightly underused) output buffer will
444             align the underlying file pointer back with the size of our output buffer
445             (and hopefully the underlying OS block writes). */
446             static void
447 756           sync_avail_out_to_ftell(NYTP_file ofile) {
448             dNFTHX(ofile);
449 756           const long result = ftell(ofile->file);
450 756           const unsigned long where = result < 0 ? 0 : result;
451             ERRNO_PROBE;
452 756           ofile->zs.avail_out =
453             NYTP_FILE_SMALL_BUFFER_SIZE - where % NYTP_FILE_SMALL_BUFFER_SIZE;
454             #ifdef DEBUG_DEFLATE
455             fprintf(stderr, "sync_avail_out_to_ftell pos=%ld, avail_out=%lu\n",
456             result, (unsigned long) ofile->zs.avail_out);
457             #endif
458 756           }
459              
460             /* flush has values as described for "allowed flush values" in zlib.h */
461             static void
462 1150           flush_output(NYTP_file ofile, int flush) {
463             dNFTHX(ofile);
464             ERRNO_PROBE;
465              
466 1150           ofile->zs.next_in = (Bytef *) ofile->large_buffer;
467              
468             #ifdef DEBUG_DEFLATE
469             fprintf(stderr, "flush_output enter flush = %d\n", flush);
470             #endif
471             while (1) {
472             int status;
473             #ifdef DEBUG_DEFLATE
474             fprintf(stderr, "flush_output predef next_in= %p avail_in= %08x\n"
475             " next_out=%p avail_out=%08x"
476             " flush=%d\n", ofile->zs.next_in, ofile->zs.avail_in,
477             ofile->zs.next_out, ofile->zs.avail_out, flush);
478             #endif
479 1258           status = deflate(&(ofile->zs), flush);
480              
481             /* workaround for RT#50851 */
482 1258 50         if (status == Z_BUF_ERROR && flush != Z_NO_FLUSH
    0          
483 0 0         && !ofile->zs.avail_in && ofile->zs.avail_out)
    0          
484 0           status = Z_OK;
485              
486             #ifdef DEBUG_DEFLATE
487             fprintf(stderr, "flush_output postdef next_in= %p avail_in= %08x\n"
488             " next_out=%p avail_out=%08x "
489             "status=%d\n", ofile->zs.next_in, ofile->zs.avail_in,
490             ofile->zs.next_out, ofile->zs.avail_out, status);
491             #endif
492            
493 1258 100         if (status == Z_OK || status == Z_STREAM_END) {
    50          
494 1366 100         if (ofile->zs.avail_out == 0 || flush != Z_NO_FLUSH) {
    100          
495 1227           int terminate
496 1227 100         = ofile->zs.avail_in == 0 && ofile->zs.avail_out > 0;
    100          
497 2454           size_t avail = ((unsigned char *) ofile->zs.next_out)
498 1227           - ofile->small_buffer;
499 1227           const unsigned char *where = ofile->small_buffer;
500              
501 2454 100         while (avail > 0) {
502 1227           size_t count = fwrite(where, 1, avail, ofile->file);
503              
504 1227 50         if (count > 0) {
505 1227           where += count;
506 1227           avail -= count;
507             } else {
508 0           int eno = errno;
509 0           croak("fwrite in flush error %d: %s", eno,
510             strerror(eno));
511             }
512             }
513 1227           ofile->zs.next_out = (Bytef *) ofile->small_buffer;
514 1227           ofile->zs.avail_out = NYTP_FILE_SMALL_BUFFER_SIZE;
515 1227 100         if (terminate) {
516 1119           ofile->zs.avail_in = 0;
517 1119 100         if (flush == Z_SYNC_FLUSH) {
518 756           sync_avail_out_to_ftell(ofile);
519             }
520 1119           return;
521             }
522             } else {
523 31           ofile->zs.avail_in = 0;
524 31           return;
525             }
526             } else {
527 0           croak("deflate(%ld,%d) failed, error %d (%s) in pid %d",
528 0           (long)ofile->zs.avail_in, flush, status, ofile->zs.msg, getpid());
529             }
530 108           }
531             }
532             #endif
533              
534             size_t
535 4917252           NYTP_write(NYTP_file ofile, const void *buffer, size_t len) {
536             #ifdef HAS_ZLIB
537 4917252           size_t result = 0;
538             #endif
539             ERRNO_PROBE;
540              
541 4917252 100         if (FILE_STATE(ofile) == NYTP_FILE_STDIO) {
542             /* fwrite with len==0 is problematic */
543             /* http://www.opengroup.org/platform/resolutions/bwg98-007.html */
544 2138821 50         if (len == 0)
545 0           return len;
546             {
547             dNFTHX(ofile);
548 2138821 50         if (fwrite(buffer, 1, len, ofile->file) < 1) {
549 0           int eno = errno;
550 0           croak("fwrite error %d writing %ld bytes to fd%d: %s",
551             eno, (long)len, fileno(ofile->file), strerror(eno));
552             }
553             }
554 2138821           return len;
555             }
556             #ifdef HAS_ZLIB
557 2778431 50         else if (FILE_STATE(ofile) != NYTP_FILE_DEFLATE) {
558 0           compressed_io_croak(ofile, "NYTP_write");
559             return 0;
560             }
561             while (1) {
562 2778462           int remaining = NYTP_FILE_LARGE_BUFFER_SIZE - ofile->zs.avail_in;
563 2778462           unsigned char *p = ofile->large_buffer + ofile->zs.avail_in;
564              
565 2778462 100         if (remaining >= len) {
566 2778431           Copy(buffer, p, len, unsigned char);
567 2778431           ofile->zs.avail_in += len;
568 2778431           result += len;
569 2778431           return result;
570             } else {
571             /* Copy what we can, then flush the buffer. Lather, rinse, repeat.
572             */
573 31           Copy(buffer, p, remaining, unsigned char);
574 31           ofile->zs.avail_in = NYTP_FILE_LARGE_BUFFER_SIZE;
575 31           result += remaining;
576 31           len -= remaining;
577 31           buffer = (void *)(remaining + (char *)buffer);
578 31           flush_output(ofile, Z_NO_FLUSH);
579             }
580 31           }
581             #endif
582             }
583              
584             int
585 705           NYTP_printf(NYTP_file ofile, const char *format, ...) {
586             int retval;
587             va_list args;
588             ERRNO_PROBE;
589              
590 705 50         CROAK_IF_NOT_STDIO(ofile, "NYTP_printf");
591              
592 705           va_start(args, format);
593             {
594             dNFTHX(ofile);
595 705           retval = vfprintf(ofile->file, format, args);
596             }
597 705           va_end(args);
598              
599 705           return retval;
600             }
601              
602             int
603 1396           NYTP_flush(NYTP_file file) {
604             ERRNO_PROBE;
605             #ifdef HAS_ZLIB
606 1396 100         if (FILE_STATE(file) == NYTP_FILE_DEFLATE) {
607 756           flush_output(file, Z_SYNC_FLUSH);
608             }
609             #endif
610             {
611             dNFTHX(file);
612 1396           return fflush(file->file);
613             }
614             }
615              
616             int
617 1343           NYTP_eof(NYTP_file ifile) {
618             ERRNO_PROBE;
619             #ifdef HAS_ZLIB
620 1343 100         if (FILE_STATE(ifile) == NYTP_FILE_INFLATE) {
621 755           return ifile->zlib_at_eof;
622             }
623             #endif
624             {
625             dNFTHX(ifile);
626 588           return feof(ifile->file);
627             }
628             }
629              
630             const char *
631 0           NYTP_fstrerror(NYTP_file file) {
632             #ifdef HAS_ZLIB
633 0 0         if (FILE_STATE(file) == NYTP_FILE_DEFLATE || FILE_STATE(file) == NYTP_FILE_INFLATE) {
    0          
634 0           return file->zs.msg;
635             }
636             #endif
637             {
638             dNFTHX(file);
639 0           return strerror(errno);
640             }
641             }
642              
643             int
644 2048           NYTP_close(NYTP_file file, int discard) {
645 2048           FILE *raw_file = file->file;
646             int result;
647             dNFTHX(file);
648             ERRNO_PROBE;
649              
650             #ifdef HAS_ZLIB
651 2048 100         if (!discard && FILE_STATE(file) == NYTP_FILE_DEFLATE) {
    100          
652 363           const double ratio = file->zs.total_in / (double) file->zs.total_out;
653 363           flush_output(file, Z_FINISH);
654 363           fprintf(raw_file, "#\n"
655             "# Compressed %lu bytes to %lu, ratio %f:1, data shrunk by %f%%\n",
656 726           (long)file->zs.total_in, (long)file->zs.total_out, ratio,
657 363           100 * (1 - 1 / ratio));
658             }
659              
660 2048 100         if (FILE_STATE(file) == NYTP_FILE_DEFLATE) {
661 385           int status = deflateEnd(&(file->zs));
662 385 100         if (status != Z_OK) {
663 22 50         if (discard && status == Z_DATA_ERROR) {
    50          
664             /* deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
665             stream state was inconsistent, Z_DATA_ERROR if the stream
666             was freed prematurely (some input or output was discarded).
667             */
668             } else {
669 385           croak("deflateEnd failed, error %d (%s) in %d", status,
670             file->zs.msg, getpid());
671             }
672             }
673             }
674 1663 100         else if (FILE_STATE(file) == NYTP_FILE_INFLATE) {
675 755           int err = inflateEnd(&(file->zs));
676 755 50         if (err != Z_OK) {
677 0           croak("inflateEnd failed, error %d (%s)", err, file->zs.msg);
678             }
679             }
680             #endif
681              
682 2048           Safefree(file);
683              
684 2048 50         result = ferror(raw_file) ? errno : 0;
685              
686 2048 100         if (discard) {
687             /* close the underlying fd first so any buffered data gets discarded
688             * when fclose is called below */
689 30           close(fileno(raw_file));
690             }
691              
692 2048 50         if (result || discard) {
    100          
693             /* Something has already gone wrong, so try to preserve its error */
694 30           fclose(raw_file);
695 30           return result;
696             }
697 2018 50         return fclose(raw_file) == 0 ? 0 : errno;
698             }
699              
700              
701             /* ====== Low-level element I/O functions ====== */
702              
703             /**
704             * Output an integer in bytes, optionally preceded by a tag. Use the special tag
705             * NYTP_TAG_NO_TAG to suppress the tag output. A wrapper macro output_u32(fh, i)
706             * does this for you.
707             * "In bytes" means output the number in binary, using the least number of bytes
708             * possible. All numbers are positive. Use sign slot as a marker
709             */
710             static size_t
711 4324537           output_tag_u32(NYTP_file file, unsigned char tag, U32 i)
712             {
713             U8 buffer[6];
714 4324537           U8 *p = buffer;
715              
716 4324537 100         if (tag != NYTP_TAG_NO_TAG)
717 1079800           *p++ = tag;
718              
719             /* general case. handles all integers */
720 4324537 100         if (i < 0x80) { /* < 8 bits */
721 4009980           *p++ = (U8)i;
722             }
723 314557 100         else if (i < 0x4000) { /* < 16 bits */
724 314308           *p++ = (U8)((i >> 8) | 0x80);
725 314308           *p++ = (U8)i;
726             }
727 249 100         else if (i < 0x200000) { /* < 24 bits */
728 185           *p++ = (U8)((i >> 16) | 0xC0);
729 185           *p++ = (U8)(i >> 8);
730 185           *p++ = (U8)i;
731             }
732 64 50         else if (i < 0x10000000) { /* < 32 bits */
733 64           *p++ = (U8)((i >> 24) | 0xE0);
734 64           *p++ = (U8)(i >> 16);
735 64           *p++ = (U8)(i >> 8);
736 64           *p++ = (U8)i;
737             }
738             else { /* need all the bytes. */
739 0           *p++ = 0xFF;
740 0           *p++ = (U8)(i >> 24);
741 0           *p++ = (U8)(i >> 16);
742 0           *p++ = (U8)(i >> 8);
743 0           *p++ = (U8)i;
744             }
745 4324537           return NYTP_write(file, buffer, p - buffer);
746             }
747              
748             static size_t
749 863728           output_tag_i32(NYTP_file file, unsigned char tag, I32 i)
750             {
751 863728           return output_tag_u32(file, tag, *( (U32*) &i ) );
752             }
753              
754             #define output_u32(fh, i) output_tag_u32((fh), NYTP_TAG_NO_TAG, (i))
755             #define output_i32(fh, i) output_tag_i32((fh), NYTP_TAG_NO_TAG, (i))
756              
757              
758             /**
759             * Read an integer by decompressing the next 1 to 4 bytes of binary into a 32-
760             * bit integer. See output_int() for the compression details.
761             */
762             U32
763 9377387           read_u32(NYTP_file ifile)
764             {
765             unsigned char d;
766             U32 newint;
767              
768 9377387           NYTP_read(ifile, &d, sizeof(d), "integer prefix");
769              
770 9377387 100         if (d < 0x80) { /* < 8 bits */
771 9059150           newint = d;
772             }
773             else {
774             unsigned char buffer[4];
775 318237           unsigned char *p = buffer;
776             unsigned int length;
777              
778 318237 100         if (d < 0xC0) { /* < 16 bits */
779 317827           newint = d & 0x7F;
780 317827           length = 1;
781             }
782 410 100         else if (d < 0xE0) { /* < 24 bits */
783 282           newint = d & 0x1F;
784 282           length = 2;
785             }
786 128 50         else if (d < 0xFF) { /* < 32 bits */
787 128           newint = d & 0xF;
788 128           length = 3;
789             }
790             else { /* d == 0xFF */ /* = 32 bits */
791 0           newint = 0;
792 0           length = 4;
793             }
794 318237           NYTP_read(ifile, buffer, length, "integer");
795 637012 100         while (length--) {
796 318775           newint <<= 8;
797 318775           newint |= *p++;
798             }
799             }
800 9377387           return newint;
801             }
802              
803             I32
804 1812610           read_i32(NYTP_file ifile) {
805 1812610           U32 u = read_u32(ifile);
806 1812610           return *( (I32*)&u );
807             }
808              
809              
810             static size_t
811 107828           output_str(NYTP_file file, const char *str, I32 len) { /* negative len signifies utf8 */
812 107828           unsigned char tag = NYTP_TAG_STRING;
813             size_t retval;
814             size_t total;
815              
816 107828 50         if (len < 0) {
817 0           tag = NYTP_TAG_STRING_UTF8;
818 0           len = -len;
819             }
820              
821 107828           total = retval = output_tag_u32(file, tag, len);
822 107828 50         if (retval <= 0)
823 0           return retval;
824              
825 107828 100         if (len) {
826 106319           total += retval = NYTP_write(file, str, len);
827 106319 50         if (retval <= 0)
828 0           return retval;
829             }
830              
831 107828           return total;
832             }
833              
834              
835             /**
836             * Output a double precision float via a simple binary write of the memory.
837             * (Minor portbility issues are seen as less important than speed and space.)
838             */
839             size_t
840 139711           output_nv(NYTP_file file, NV nv)
841             {
842 139711           return NYTP_write(file, (unsigned char *)&nv, sizeof(NV));
843             }
844              
845             /**
846             * Read an NV by simple byte copy to memory
847             */
848             NV
849 89055           read_nv(NYTP_file ifile)
850             {
851             NV nv;
852             /* no error checking on the assumption that a later token read will
853             * detect the error/eof condition
854             */
855 89055           NYTP_read(ifile, (unsigned char *)&nv, sizeof(NV), "float");
856 89055           return nv;
857             }
858              
859              
860             /* ====== Higher-level protocol I/O functions ====== */
861              
862             size_t
863 705           NYTP_write_header(NYTP_file ofile, U32 major, U32 minor)
864             {
865 705           return NYTP_printf(ofile, "NYTProf %u %u\n", major, minor);
866             }
867              
868             size_t
869 1090           NYTP_write_comment(NYTP_file ofile, const char *format, ...) {
870             size_t retval;
871             size_t retval2;
872             va_list args;
873             ERRNO_PROBE;
874              
875 1090           retval = NYTP_write(ofile, "#", 1);
876 1090 50         if (retval != 1)
877 0           return retval;
878              
879 1090           va_start(args, format);
880              
881 1090 50         if(strEQ(format, "%s")) {
882 0 0         const char * const s = va_arg(args, char*);
883 0           STRLEN len = strlen(s);
884 0           retval = NYTP_write(ofile, s, len);
885             } else {
886 1090 50         CROAK_IF_NOT_STDIO(ofile, "NYTP_printf");
887             {
888             dNFTHX(ofile);
889 1090           retval = vfprintf(ofile->file, format, args);
890             }
891             }
892 1090           va_end(args);
893              
894 1090           retval2 = NYTP_write(ofile, "\n", 1);
895 1090 50         if (retval2 != 1)
896 0           return retval2;
897              
898 1090           return retval + 2;
899             }
900              
901             static size_t
902 19005           NYTP_write_plain_kv(NYTP_file ofile, const char prefix,
903             const char *key, size_t key_len,
904             const char *value, size_t value_len)
905             {
906             size_t total;
907             size_t retval;
908              
909 19005           total = retval = NYTP_write(ofile, &prefix, 1);
910 19005 50         if (retval != 1)
911 0           return retval;
912              
913 19005           total += retval = NYTP_write(ofile, key, key_len);
914 19005 50         if (retval != key_len)
915 0           return retval;
916              
917 19005           total += retval = NYTP_write(ofile, "=", 1);
918 19005 50         if (retval != 1)
919 0           return retval;
920              
921 19005           total += retval = NYTP_write(ofile, value, value_len);
922 19005 50         if (retval != value_len)
923 0           return retval;
924              
925 19005           total += retval = NYTP_write(ofile, "\n", 1);
926 19005 50         if (retval != 1)
927 0           return retval;
928              
929 19005           return total;
930             }
931              
932             size_t
933 6315           NYTP_write_attribute_string(NYTP_file ofile,
934             const char *key, size_t key_len,
935             const char *value, size_t value_len)
936             {
937 6315           return NYTP_write_plain_kv(ofile, ':', key, key_len, value, value_len);
938             }
939              
940             #ifndef CHAR_BIT
941             # define CHAR_BIT 8
942             #endif
943             #define LOG_2_OVER_LOG_10 0.30103
944              
945             size_t
946 2820           NYTP_write_attribute_unsigned(NYTP_file ofile, const char *key,
947             size_t key_len, unsigned long value)
948 2820           {
949             /* 3: 1 for rounding errors, 1 for the '\0' */
950 2820           char buffer[(int)(sizeof (unsigned long) * CHAR_BIT * LOG_2_OVER_LOG_10 + 3)];
951 2820 50         const size_t len = my_snprintf(buffer, sizeof(buffer), "%lu", value);
952              
953 2820           return NYTP_write_attribute_string(ofile, key, key_len, buffer, len);
954             }
955              
956             size_t
957 705           NYTP_write_attribute_signed(NYTP_file ofile, const char *key,
958             size_t key_len, long value)
959 705           {
960             /* 3: 1 for rounding errors, 1 for the sign, 1 for the '\0' */
961 705           char buffer[(int)(sizeof (long) * CHAR_BIT * LOG_2_OVER_LOG_10 + 3)];
962 705 50         const size_t len = my_snprintf(buffer, sizeof(buffer), "%ld", value);
963              
964 705           return NYTP_write_attribute_string(ofile, key, key_len, buffer, len);
965             }
966              
967             size_t
968 675           NYTP_write_attribute_nv(NYTP_file ofile, const char *key,
969             size_t key_len, NV value)
970             {
971             char buffer[NV_DIG+20]; /* see Perl_sv_2pv_flags */
972 675 50         const size_t len = my_snprintf(buffer, sizeof(buffer), "%" NVgf, value);
973              
974 675           return NYTP_write_attribute_string(ofile, key, key_len, buffer, len);
975             }
976              
977             /* options */
978              
979             size_t
980 12690           NYTP_write_option_pv(NYTP_file ofile,
981             const char *key,
982             const char *value, size_t value_len)
983             {
984 12690           return NYTP_write_plain_kv(ofile, '!', key, strlen(key), value, value_len);
985             }
986              
987             size_t
988 12690           NYTP_write_option_iv(NYTP_file ofile, const char *key, IV value)
989 12690           {
990             /* 3: 1 for rounding errors, 1 for the sign, 1 for the '\0' */
991 12690           char buffer[(int)(sizeof (IV) * CHAR_BIT * LOG_2_OVER_LOG_10 + 3)];
992 12690 50         const size_t len = my_snprintf(buffer, sizeof(buffer), "%" IVdf, value);
993              
994 12690           return NYTP_write_option_pv(ofile, key, buffer, len);
995             }
996              
997             /* other */
998              
999             #ifdef HAS_ZLIB
1000              
1001             size_t
1002 385           NYTP_start_deflate_write_tag_comment(NYTP_file ofile, int compression_level) {
1003 385           const unsigned char tag = NYTP_TAG_START_DEFLATE;
1004             size_t total;
1005             size_t retval;
1006              
1007 385           total = retval = NYTP_write_comment(ofile, "Compressed at level %d with zlib %s",
1008             compression_level, zlibVersion());
1009              
1010 385 50         if (retval < 1)
1011 0           return retval;
1012              
1013 385           total += retval = NYTP_write(ofile, &tag, sizeof(tag));
1014 385 50         if (retval < 1)
1015 0           return retval;
1016              
1017 385           NYTP_start_deflate(ofile, compression_level);
1018              
1019 385           return total;
1020             }
1021              
1022             #endif
1023              
1024             size_t
1025 705           NYTP_write_process_start(NYTP_file ofile, U32 pid, U32 ppid,
1026             NV time_of_day)
1027             {
1028             size_t total;
1029             size_t retval;
1030              
1031 705           total = retval = output_tag_u32(ofile, NYTP_TAG_PID_START, pid);
1032 705 50         if (retval < 1)
1033 0           return retval;
1034              
1035 705           total += retval = output_u32(ofile, ppid);
1036 705 50         if (retval < 1)
1037 0           return retval;
1038              
1039 705           total += retval = output_nv(ofile, time_of_day);
1040 705 50         if (retval < 1)
1041 0           return retval;
1042              
1043 705           return total;
1044             }
1045              
1046             size_t
1047 675           NYTP_write_process_end(NYTP_file ofile, U32 pid, NV time_of_day)
1048             {
1049             size_t total;
1050             size_t retval;
1051              
1052 675           total = retval = output_tag_u32(ofile, NYTP_TAG_PID_END, pid);
1053 675 50         if (retval < 1)
1054 0           return retval;
1055              
1056 675           total += retval = output_nv(ofile, time_of_day);
1057 675 50         if (retval < 1)
1058 0           return retval;
1059              
1060 675           return total;
1061             }
1062              
1063             size_t
1064 0           NYTP_write_sawampersand(NYTP_file ofile, U32 fid, U32 line)
1065             {
1066             size_t total;
1067             size_t retval;
1068              
1069 0           total = retval = NYTP_write_attribute_unsigned(ofile, STR_WITH_LEN("sawampersand_fid"), fid);
1070 0 0         if (retval < 1)
1071 0           return retval;
1072              
1073 0           total += retval = NYTP_write_attribute_unsigned(ofile, STR_WITH_LEN("sawampersand_line"), line);
1074 0 0         if (retval < 1)
1075 0           return retval;
1076              
1077 0           return total;
1078             }
1079              
1080             size_t
1081 1667           NYTP_write_new_fid(NYTP_file ofile, U32 id, U32 eval_fid,
1082             U32 eval_line_num, U32 flags,
1083             U32 size, U32 mtime,
1084             const char *name, I32 len)
1085             {
1086             size_t total;
1087             size_t retval;
1088              
1089 1667           total = retval = output_tag_u32(ofile, NYTP_TAG_NEW_FID, id);
1090 1667 50         if (retval < 1)
1091 0           return retval;
1092              
1093 1667           total += retval = output_u32(ofile, eval_fid);
1094 1667 50         if (retval < 1)
1095 0           return retval;
1096              
1097 1667           total += retval = output_u32(ofile, eval_line_num);
1098 1667 50         if (retval < 1)
1099 0           return retval;
1100              
1101 1667           total += retval = output_u32(ofile, flags);
1102 1667 50         if (retval < 1)
1103 0           return retval;
1104              
1105 1667           total += retval = output_u32(ofile, size);
1106 1667 50         if (retval < 1)
1107 0           return retval;
1108              
1109 1667           total += retval = output_u32(ofile, mtime);
1110 1667 50         if (retval < 1)
1111 0           return retval;
1112              
1113 1667           total += retval = output_str(ofile, name, len);
1114 1667 50         if (retval < 1)
1115 0           return retval;
1116              
1117 1667           return total;
1118             }
1119              
1120             static size_t
1121 863728           write_time_common(NYTP_file ofile, unsigned char tag, I32 elapsed, U32 overflow,
1122             U32 fid, U32 line)
1123             {
1124             size_t total;
1125             size_t retval;
1126              
1127 863728 50         if (overflow) {
1128             dNFTHX(ofile);
1129             /* XXX needs protocol change to output a new time-overflow tag */
1130 0           fprintf(stderr, "profile time overflow of %lu seconds discarded!\n",
1131             (unsigned long)overflow);
1132             }
1133              
1134 863728           total = retval = output_tag_i32(ofile, tag, elapsed);
1135 863728 50         if (retval < 1)
1136 0           return retval;
1137              
1138 863728           total += retval = output_u32(ofile, fid);
1139 863728 50         if (retval < 1)
1140 0           return retval;
1141              
1142 863728           total += retval = output_u32(ofile, line);
1143 863728 50         if (retval < 1)
1144 0           return retval;
1145              
1146 863728           return total;
1147             }
1148              
1149             size_t
1150 723375           NYTP_write_time_block(NYTP_file ofile, I32 elapsed, U32 overflow,
1151             U32 fid, U32 line, U32 last_block_line, U32 last_sub_line)
1152             {
1153             size_t total;
1154             size_t retval;
1155              
1156 723375           total = retval = write_time_common(ofile, NYTP_TAG_TIME_BLOCK, elapsed, overflow,
1157             fid, line);
1158 723375 50         if (retval < 1)
1159 0           return retval;
1160              
1161 723375           total += retval = output_u32(ofile, last_block_line);
1162 723375 50         if (retval < 1)
1163 0           return retval;
1164              
1165 723375           total += retval = output_u32(ofile, last_sub_line);
1166 723375 50         if (retval < 1)
1167 0           return retval;
1168              
1169 723375           return total;
1170             }
1171              
1172             size_t
1173 140353           NYTP_write_time_line(NYTP_file ofile, I32 elapsed, U32 overflow,
1174             U32 fid, U32 line)
1175             {
1176 140353           return write_time_common(ofile, NYTP_TAG_TIME_LINE, elapsed, overflow, fid, line);
1177             }
1178              
1179              
1180             size_t
1181 4583           NYTP_write_call_entry(NYTP_file ofile, U32 caller_fid, U32 caller_line)
1182             {
1183             size_t total;
1184             size_t retval;
1185              
1186 4583           total = retval = output_tag_u32(ofile, NYTP_TAG_SUB_ENTRY, caller_fid);
1187 4583 50         if (retval < 1)
1188 0           return retval;
1189              
1190 4583           total += retval = output_u32(ofile, caller_line);
1191 4583 50         if (retval < 1)
1192 0           return retval;
1193              
1194 4583           return total;
1195             }
1196              
1197             size_t
1198 60845           NYTP_write_call_return(NYTP_file ofile, U32 prof_depth, const char *called_subname_pv,
1199             NV incl_subr_ticks, NV excl_subr_ticks)
1200             {
1201             size_t total;
1202             size_t retval;
1203              
1204 60845           total = retval = output_tag_u32(ofile, NYTP_TAG_SUB_RETURN, prof_depth);
1205 60845 50         if (retval < 1)
1206 0           return retval;
1207              
1208 60845           total += retval = output_nv(ofile, incl_subr_ticks);
1209 60845 50         if (retval < 1)
1210 0           return retval;
1211              
1212 60845           total += retval = output_nv(ofile, excl_subr_ticks);
1213 60845 50         if (retval < 1)
1214 0           return retval;
1215              
1216 60845 50         if (!called_subname_pv)
1217 0           called_subname_pv = "(null)";
1218 60845           total += retval = output_str(ofile, called_subname_pv, strlen(called_subname_pv));
1219 60845 50         if (retval < 1)
1220 0           return retval;
1221              
1222 60845           return total;
1223             }
1224              
1225              
1226             size_t
1227 6045           NYTP_write_sub_info(NYTP_file ofile, U32 fid,
1228             const char *name, I32 len,
1229             U32 first_line, U32 last_line)
1230             {
1231             size_t total;
1232             size_t retval;
1233              
1234 6045           total = retval = output_tag_u32(ofile, NYTP_TAG_SUB_INFO, fid);
1235 6045 50         if (retval < 1)
1236 0           return retval;
1237              
1238 6045           total += retval = output_str(ofile, name, (I32)len);
1239 6045 50         if (retval < 1)
1240 0           return retval;
1241              
1242 6045           total += retval = output_u32(ofile, first_line);
1243 6045 50         if (retval < 1)
1244 0           return retval;
1245              
1246 6045           total += retval = output_u32(ofile, last_line);
1247 6045 50         if (retval < 1)
1248 0           return retval;
1249              
1250 6045           return total;
1251             }
1252              
1253             size_t
1254 5547           NYTP_write_sub_callers(NYTP_file ofile, U32 fid, U32 line,
1255             const char *caller_name, I32 caller_name_len,
1256             U32 count, NV incl_rtime, NV excl_rtime,
1257             NV reci_rtime, U32 depth,
1258             const char *called_name, I32 called_name_len)
1259             {
1260             size_t total;
1261             size_t retval;
1262              
1263 5547           total = retval = output_tag_u32(ofile, NYTP_TAG_SUB_CALLERS, fid);
1264 5547 50         if (retval < 1)
1265 0           return retval;
1266              
1267 5547           total += retval = output_u32(ofile, line);
1268 5547 50         if (retval < 1)
1269 0           return retval;
1270              
1271 5547           total += retval = output_str(ofile, caller_name, caller_name_len);
1272 5547 50         if (retval < 1)
1273 0           return retval;
1274              
1275 5547           total += retval = output_u32(ofile, count);
1276 5547 50         if (retval < 1)
1277 0           return retval;
1278              
1279 5547           total += retval = output_nv(ofile, incl_rtime);
1280 5547 50         if (retval < 1)
1281 0           return retval;
1282              
1283 5547           total += retval = output_nv(ofile, excl_rtime);
1284 5547 50         if (retval < 1)
1285 0           return retval;
1286              
1287 5547           total += retval = output_nv(ofile, reci_rtime);
1288 5547 50         if (retval < 1)
1289 0           return retval;
1290              
1291 5547           total += retval = output_u32(ofile, depth);
1292 5547 50         if (retval < 1)
1293 0           return retval;
1294              
1295 5547           total += retval = output_str(ofile, called_name, called_name_len);
1296 5547 50         if (retval < 1)
1297 0           return retval;
1298              
1299 5547           return total;
1300             }
1301              
1302             size_t
1303 28177           NYTP_write_src_line(NYTP_file ofile, U32 fid,
1304             U32 line, const char *text, I32 text_len)
1305             {
1306             size_t total;
1307             size_t retval;
1308              
1309 28177           total = retval = output_tag_u32(ofile, NYTP_TAG_SRC_LINE, fid);
1310 28177 50         if (retval < 1)
1311 0           return retval;
1312              
1313 28177           total += retval = output_u32(ofile, line);
1314 28177 50         if (retval < 1)
1315 0           return retval;
1316              
1317 28177           total += retval = output_str(ofile, text, text_len);
1318 28177 50         if (retval < 1)
1319 0           return retval;
1320              
1321 28177           return total;
1322             }
1323              
1324             size_t
1325 249095           NYTP_write_discount(NYTP_file ofile)
1326             {
1327 249095           const unsigned char tag = NYTP_TAG_DISCOUNT;
1328 249095           return NYTP_write(ofile, &tag, sizeof(tag));
1329             }
1330              
1331              
1332             MODULE = Devel::NYTProf::FileHandle PACKAGE = Devel::NYTProf::FileHandle PREFIX = NYTP_
1333              
1334             PROTOTYPES: DISABLE
1335              
1336             void
1337             open(pathname, mode)
1338             char *pathname
1339             char *mode
1340             PREINIT:
1341 0           NYTP_file fh = NYTP_open(pathname, mode);
1342             SV *object;
1343             PPCODE:
1344 0 0         if(!fh)
1345 0           XSRETURN(0);
1346 0           object = newSV(0);
1347 0           sv_usepvn(object, (char *) fh, sizeof(struct NYTP_file_t));
1348 0           ST(0) = sv_bless(sv_2mortal(newRV_noinc(object)), gv_stashpvs("Devel::NYTProf::FileHandle", GV_ADD));
1349 0           XSRETURN(1);
1350              
1351             int
1352             DESTROY(handle)
1353             NYTP_file handle
1354             ALIAS:
1355             close = 1
1356             PREINIT:
1357             SV *guts;
1358             CODE:
1359 0           guts = SvRV(ST(0));
1360             PERL_UNUSED_VAR(ix);
1361 0           RETVAL = NYTP_close(handle, 0);
1362 0           SvPV_set(guts, NULL);
1363 0           SvLEN_set(guts, 0);
1364             OUTPUT:
1365             RETVAL
1366              
1367             size_t
1368             write(handle, string)
1369             NYTP_file handle
1370             SV *string
1371             PREINIT:
1372             STRLEN len;
1373             char *p;
1374             CODE:
1375 0 0         p = SvPVbyte(string, len);
1376 0           RETVAL = NYTP_write(handle, p, len);
1377             OUTPUT:
1378             RETVAL
1379              
1380             #ifdef HAS_ZLIB
1381              
1382             void
1383             NYTP_start_deflate(handle, compression_level = 6)
1384             NYTP_file handle
1385             int compression_level
1386              
1387             void
1388             NYTP_start_deflate_write_tag_comment(handle, compression_level = 6)
1389             NYTP_file handle
1390             int compression_level
1391              
1392             #endif
1393              
1394             size_t
1395             NYTP_write_comment(handle, comment)
1396             NYTP_file handle
1397             char *comment
1398             CODE:
1399 0           RETVAL = NYTP_write_comment(handle, "%s", comment);
1400             OUTPUT:
1401             RETVAL
1402              
1403             size_t
1404             NYTP_write_attribute(handle, key, value)
1405             NYTP_file handle
1406             SV *key
1407             SV *value
1408             PREINIT:
1409             STRLEN key_len;
1410 0 0         const char *const key_p = SvPVbyte(key, key_len);
1411             STRLEN value_len;
1412 0 0         const char *const value_p = SvPVbyte(value, value_len);
1413             CODE:
1414 0           RETVAL = NYTP_write_attribute_string(handle, key_p, key_len, value_p, value_len);
1415             OUTPUT:
1416             RETVAL
1417              
1418             size_t
1419             NYTP_write_option(handle, key, value)
1420             NYTP_file handle
1421             SV *key
1422             SV *value
1423             PREINIT:
1424             STRLEN key_len;
1425 0 0         const char *const key_p = SvPVbyte(key, key_len);
1426             STRLEN value_len;
1427 0 0         const char *const value_p = SvPVbyte(value, value_len);
1428             CODE:
1429 0           RETVAL = NYTP_write_option_pv(handle, key_p, value_p, value_len);
1430             OUTPUT:
1431             RETVAL
1432              
1433             size_t
1434             NYTP_write_process_start(handle, pid, ppid, time_of_day)
1435             NYTP_file handle
1436             U32 pid
1437             U32 ppid
1438             NV time_of_day
1439              
1440             size_t
1441             NYTP_write_process_end(handle, pid, time_of_day)
1442             NYTP_file handle
1443             U32 pid
1444             NV time_of_day
1445              
1446             size_t
1447             NYTP_write_new_fid(handle, id, eval_fid, eval_line_num, flags, size, mtime, name)
1448             NYTP_file handle
1449             U32 id
1450             U32 eval_fid
1451             int eval_line_num
1452             U32 flags
1453             U32 size
1454             U32 mtime
1455             SV *name
1456             PREINIT:
1457             STRLEN len;
1458 0 0         const char *const p = SvPV(name, len);
1459             CODE:
1460 0 0         RETVAL = NYTP_write_new_fid(handle, id, eval_fid, eval_line_num,
1461             flags, size, mtime, p,
1462 0           SvUTF8(name) ? -(I32)len : (I32)len );
1463             OUTPUT:
1464             RETVAL
1465              
1466             size_t
1467             NYTP_write_time_block(handle, elapsed, overflow, fid, line, last_block_line, last_sub_line)
1468             NYTP_file handle
1469             U32 elapsed
1470             U32 overflow
1471             U32 fid
1472             U32 line
1473             U32 last_block_line
1474             U32 last_sub_line
1475              
1476             size_t
1477             NYTP_write_time_line(handle, elapsed, overflow, fid, line)
1478             NYTP_file handle
1479             U32 elapsed
1480             U32 overflow
1481             U32 fid
1482             U32 line
1483              
1484             size_t
1485             NYTP_write_call_entry(handle, caller_fid, caller_line)
1486             NYTP_file handle
1487             U32 caller_fid
1488             U32 caller_line
1489              
1490             size_t
1491             NYTP_write_call_return(handle, prof_depth, called_subname_pv, incl_subr_ticks, excl_subr_ticks)
1492             NYTP_file handle
1493             U32 prof_depth
1494             const char *called_subname_pv
1495             NV incl_subr_ticks
1496             NV excl_subr_ticks
1497              
1498             size_t
1499             NYTP_write_sub_info(handle, fid, name, first_line, last_line)
1500             NYTP_file handle
1501             U32 fid
1502             SV *name
1503             U32 first_line
1504             U32 last_line
1505             PREINIT:
1506             STRLEN len;
1507 0 0         const char *const p = SvPV(name, len);
1508             CODE:
1509 0 0         RETVAL = NYTP_write_sub_info(handle, fid,
1510 0           p, SvUTF8(name) ? -(I32)len : (I32)len,
1511             first_line, last_line);
1512             OUTPUT:
1513             RETVAL
1514              
1515             size_t
1516             NYTP_write_sub_callers(handle, fid, line, caller, count, incl_rtime, excl_rtime, reci_rtime, depth, called_sub)
1517             NYTP_file handle
1518             U32 fid
1519             U32 line
1520             SV *caller
1521             U32 count
1522             NV incl_rtime
1523             NV excl_rtime
1524             NV reci_rtime
1525             U32 depth
1526             SV *called_sub
1527             PREINIT:
1528             STRLEN caller_len;
1529 0 0         const char *const caller_p = SvPV(caller, caller_len);
1530             STRLEN called_len;
1531 0 0         const char *const called_p = SvPV(called_sub, called_len);
1532             CODE:
1533 0 0         RETVAL = NYTP_write_sub_callers(handle, fid, line, caller_p,
    0          
1534 0           SvUTF8(caller) ? -(I32)caller_len : (I32)caller_len,
1535             count, incl_rtime, excl_rtime,
1536             reci_rtime, depth, called_p,
1537 0           SvUTF8(called_sub) ? -(I32)called_len : (I32)called_len);
1538             OUTPUT:
1539             RETVAL
1540              
1541             size_t
1542             NYTP_write_src_line(handle, fid, line, text)
1543             NYTP_file handle
1544             U32 fid
1545             U32 line
1546             SV *text
1547             PREINIT:
1548             STRLEN len;
1549 0 0         const char *const p = SvPV(text, len);
1550             CODE:
1551 0 0         RETVAL = NYTP_write_src_line(handle, fid, line,
1552 0           p, SvUTF8(text) ? -(I32)len : (I32)len);
1553             OUTPUT:
1554             RETVAL
1555              
1556             size_t
1557             NYTP_write_discount(handle)
1558             NYTP_file handle
1559              
1560             size_t
1561             NYTP_write_header(handle, major, minor)
1562             NYTP_file handle
1563             U32 major
1564             U32 minor
1565