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 <zlib.h>
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
NYTP_tell(NYTP_file file)91 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 if (FILE_STATE(file) != NYTP_FILE_STDIO) {
98 return FILE_STATE(file) == NYTP_FILE_INFLATE
99 ? file->zs.total_out : file->zs.total_in;
100 }
101 #endif
102 {
103 dNFTHX(file);
104 return (long)ftell(file->file);
105 }
106 }
107
108 #ifdef HAS_ZLIB
109 const char *
NYTP_type_of_offset(NYTP_file file)110 NYTP_type_of_offset(NYTP_file file) {
111 switch (FILE_STATE(file)) {
112 case NYTP_FILE_STDIO:
113 return "";
114 case NYTP_FILE_DEFLATE:
115 return " in compressed output data";
116 break;
117 case NYTP_FILE_INFLATE:
118 return " in compressed input data";
119 break;
120 default:
121 return Perl_form_nocontext(" in stream in unknown state %d",
122 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
compressed_io_croak(NYTP_file file,const char * function)143 compressed_io_croak(NYTP_file file, const char *function) {
144 const char *what;
145
146 switch (FILE_STATE(file)) {
147 case NYTP_FILE_STDIO:
148 what = "stdio";
149 break;
150 case NYTP_FILE_DEFLATE:
151 what = "compressed output";
152 break;
153 case NYTP_FILE_INFLATE:
154 what = "compressed input";
155 break;
156 default:
157 croak("Can't use function %s() on a stream of type %d at offset %ld",
158 function, FILE_STATE(file), NYTP_tell(file));
159 }
160 croak("Can't use function %s() on a %s stream at offset %ld", function,
161 what, NYTP_tell(file));
162 }
163
164 void
NYTP_start_deflate(NYTP_file file,int compression_level)165 NYTP_start_deflate(NYTP_file file, int compression_level) {
166 int status;
167 ERRNO_PROBE;
168
169 CROAK_IF_NOT_STDIO(file, "NYTP_start_deflate");
170 FILE_STATE(file) = NYTP_FILE_DEFLATE;
171 file->zs.next_in = (Bytef *) file->large_buffer;
172 file->zs.avail_in = 0;
173 file->zs.next_out = (Bytef *) file->small_buffer;
174 file->zs.avail_out = NYTP_FILE_SMALL_BUFFER_SIZE;
175 file->zs.zalloc = (alloc_func) 0;
176 file->zs.zfree = (free_func) 0;
177 file->zs.opaque = 0;
178
179 status = deflateInit2(&(file->zs), compression_level, Z_DEFLATED,
180 15 /* windowBits */,
181 9 /* memLevel */, Z_DEFAULT_STRATEGY);
182 if (status != Z_OK) {
183 croak("deflateInit2 failed, error %d (%s)", status, file->zs.msg);
184 }
185 }
186
187 void
NYTP_start_inflate(NYTP_file file)188 NYTP_start_inflate(NYTP_file file) {
189 int status;
190 ERRNO_PROBE;
191
192 CROAK_IF_NOT_STDIO(file, "NYTP_start_inflate");
193 FILE_STATE(file) = NYTP_FILE_INFLATE;
194
195 file->zs.next_in = (Bytef *) file->small_buffer;
196 file->zs.avail_in = 0;
197 file->zs.next_out = (Bytef *) file->large_buffer;
198 file->zs.avail_out = NYTP_FILE_LARGE_BUFFER_SIZE;
199 file->zs.zalloc = (alloc_func) 0;
200 file->zs.zfree = (free_func) 0;
201 file->zs.opaque = 0;
202
203 status = inflateInit2(&(file->zs), 15);
204 if (status != Z_OK) {
205 croak("inflateInit2 failed, error %d (%s)", status, file->zs.msg);
206 }
207 }
208 #endif
209
210 NYTP_file
NYTP_open(const char * name,const char * mode)211 NYTP_open(const char *name, const char *mode) {
212 dTHX;
213 FILE *raw_file = fopen(name, mode);
214 NYTP_file file;
215 ERRNO_PROBE;
216
217 if (!raw_file)
218 return NULL;
219
220 /* MS libc has 4096 as default, this is too slow for GB size profiling data */
221 if (setvbuf(raw_file, NULL, _IOFBF, 16384))
222 return NULL;
223 Newx(file, 1, struct NYTP_file_t);
224 file->file = raw_file;
225
226 #ifdef PERL_IMPLICIT_CONTEXT
227 file->aTHX = aTHX;
228 #endif
229 #ifdef HAS_ZLIB
230 file->state = NYTP_FILE_STDIO;
231 file->count = 0;
232 file->stdio_at_eof = FALSE;
233 file->zlib_at_eof = FALSE;
234
235 file->zs.msg = (char *)"[Oops. zlib hasn't updated this error string]";
236 #endif
237
238 return file;
239 }
240
241 #ifdef HAS_ZLIB
242
243 static void
grab_input(NYTP_file ifile)244 grab_input(NYTP_file ifile) {
245 dNFTHX(ifile);
246 ERRNO_PROBE;
247
248 ifile->count = 0;
249 ifile->zs.next_out = (Bytef *) ifile->large_buffer;
250 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 if (ifile->zs.avail_in == 0 && !ifile->stdio_at_eof) {
260 size_t got = fread(ifile->small_buffer, 1,
261 NYTP_FILE_SMALL_BUFFER_SIZE, ifile->file);
262
263 if (got == 0) {
264 if (!feof(ifile->file)) {
265 int eno = errno;
266 croak("grab_input failed: %d (%s)", eno, strerror(eno));
267 }
268 ifile->stdio_at_eof = TRUE;
269 }
270
271 ifile->zs.avail_in = got;
272 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 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 if (!(status == Z_OK || status == Z_STREAM_END)) {
293 if (ifile->stdio_at_eof)
294 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 croak("Error reading file: inflate failed, error %d (%s) at offset %ld in input file",
299 status, ifile->zs.msg, (long)ftell(ifile->file));
300 }
301
302 if (ifile->zs.avail_out == 0 || status == Z_STREAM_END) {
303 if (status == Z_STREAM_END) {
304 ifile->zlib_at_eof = TRUE;
305 }
306 return;
307 }
308 }
309 }
310
311 #endif
312
313
314 size_t
NYTP_read_unchecked(NYTP_file ifile,void * buffer,size_t len)315 NYTP_read_unchecked(NYTP_file ifile, void *buffer, size_t len) {
316 dNFTHX(ifile);
317 #ifdef HAS_ZLIB
318 size_t result = 0;
319 #endif
320 ERRNO_PROBE;
321 if (FILE_STATE(ifile) == NYTP_FILE_STDIO) {
322 return fread(buffer, 1, len, ifile->file);
323 }
324 #ifdef HAS_ZLIB
325 else if (FILE_STATE(ifile) != NYTP_FILE_INFLATE) {
326 compressed_io_croak(ifile, "NYTP_read");
327 return 0;
328 }
329 while (1) {
330 unsigned char *p = ifile->large_buffer + ifile->count;
331 int remaining = ((unsigned char *) ifile->zs.next_out) - p;
332
333 if (remaining >= len) {
334 Copy(p, buffer, len, unsigned char);
335 ifile->count += len;
336 result += len;
337 return result;
338 }
339 Copy(p, buffer, remaining, unsigned char);
340 ifile->count = NYTP_FILE_LARGE_BUFFER_SIZE;
341 result += remaining;
342 len -= remaining;
343 buffer = (void *)(remaining + (char *)buffer);
344 if (ifile->zlib_at_eof)
345 return result;
346 grab_input(ifile);
347 }
348 #endif
349 }
350
351
352 size_t
NYTP_read(NYTP_file ifile,void * buffer,size_t len,const char * what)353 NYTP_read(NYTP_file ifile, void *buffer, size_t len, const char *what) {
354 size_t got = NYTP_read_unchecked(ifile, buffer, len);
355 if (got != len) {
356 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 (NYTP_eof(ifile)) ? "end of file" : NYTP_fstrerror(ifile));
359 }
360 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 *
NYTP_gets(NYTP_file ifile,char ** buffer_p,size_t * len_p)368 NYTP_gets(NYTP_file ifile, char **buffer_p, size_t *len_p) {
369 char *buffer = *buffer_p;
370 size_t len = *len_p;
371 size_t prev_len = 0;
372 ERRNO_PROBE;
373
374 #ifdef HAS_ZLIB
375 if (FILE_STATE(ifile) == NYTP_FILE_INFLATE) {
376 while (1) {
377 const unsigned char *const p = ifile->large_buffer + ifile->count;
378 const unsigned int remaining = ((unsigned char *) ifile->zs.next_out) - p;
379 unsigned char *const nl = (unsigned char *)memchr(p, '\n', remaining);
380 size_t got;
381 size_t want;
382 size_t extra;
383
384 if (nl) {
385 want = nl + 1 - p;
386 extra = want + 1; /* 1 more to add a \0 */
387 } else {
388 want = extra = remaining;
389 }
390
391 if (extra > len - prev_len) {
392 prev_len = len;
393 len += extra;
394 buffer = (char *)saferealloc(buffer, len);
395 }
396
397 got = NYTP_read_unchecked(ifile, buffer + prev_len, want);
398 if (got != want)
399 croak("NYTP_gets unexpected short read. got %lu, expected %lu\n",
400 (unsigned long)got, (unsigned long)want);
401
402 if (nl) {
403 buffer[prev_len + want] = '\0';
404 *buffer_p = buffer;
405 *len_p = len;
406 return buffer + prev_len + want;
407 }
408 if (ifile->zlib_at_eof) {
409 *buffer_p = buffer;
410 *len_p = len;
411 return NULL;
412 }
413 grab_input(ifile);
414 }
415 }
416 #endif
417 CROAK_IF_NOT_STDIO(ifile, "NYTP_gets");
418
419 {
420 dNFTHX(ifile);
421 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 char *end = buffer + prev_len + strlen(buffer + prev_len);
425 if (end[-1] == '\n') {
426 *buffer_p = buffer;
427 *len_p = len;
428 return end;
429 }
430 prev_len = len - 1; /* -1 to take off the '\0' at the end */
431 len *= 2;
432 buffer = (char *)saferealloc(buffer, len);
433 }
434 }
435 *buffer_p = buffer;
436 *len_p = len;
437 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
sync_avail_out_to_ftell(NYTP_file ofile)447 sync_avail_out_to_ftell(NYTP_file ofile) {
448 dNFTHX(ofile);
449 const long result = ftell(ofile->file);
450 const unsigned long where = result < 0 ? 0 : result;
451 ERRNO_PROBE;
452 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 }
459
460 /* flush has values as described for "allowed flush values" in zlib.h */
461 static void
flush_output(NYTP_file ofile,int flush)462 flush_output(NYTP_file ofile, int flush) {
463 dNFTHX(ofile);
464 ERRNO_PROBE;
465
466 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 status = deflate(&(ofile->zs), flush);
480
481 /* workaround for RT#50851 */
482 if (status == Z_BUF_ERROR && flush != Z_NO_FLUSH
483 && !ofile->zs.avail_in && ofile->zs.avail_out)
484 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 if (status == Z_OK || status == Z_STREAM_END) {
494 if (ofile->zs.avail_out == 0 || flush != Z_NO_FLUSH) {
495 int terminate
496 = ofile->zs.avail_in == 0 && ofile->zs.avail_out > 0;
497 size_t avail = ((unsigned char *) ofile->zs.next_out)
498 - ofile->small_buffer;
499 const unsigned char *where = ofile->small_buffer;
500
501 while (avail > 0) {
502 size_t count = fwrite(where, 1, avail, ofile->file);
503
504 if (count > 0) {
505 where += count;
506 avail -= count;
507 } else {
508 int eno = errno;
509 croak("fwrite in flush error %d: %s", eno,
510 strerror(eno));
511 }
512 }
513 ofile->zs.next_out = (Bytef *) ofile->small_buffer;
514 ofile->zs.avail_out = NYTP_FILE_SMALL_BUFFER_SIZE;
515 if (terminate) {
516 ofile->zs.avail_in = 0;
517 if (flush == Z_SYNC_FLUSH) {
518 sync_avail_out_to_ftell(ofile);
519 }
520 return;
521 }
522 } else {
523 ofile->zs.avail_in = 0;
524 return;
525 }
526 } else {
527 croak("deflate(%ld,%d) failed, error %d (%s) in pid %d",
528 (long)ofile->zs.avail_in, flush, status, ofile->zs.msg, getpid());
529 }
530 }
531 }
532 #endif
533
534 size_t
NYTP_write(NYTP_file ofile,const void * buffer,size_t len)535 NYTP_write(NYTP_file ofile, const void *buffer, size_t len) {
536 #ifdef HAS_ZLIB
537 size_t result = 0;
538 #endif
539 ERRNO_PROBE;
540
541 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 if (len == 0)
545 return len;
546 {
547 dNFTHX(ofile);
548 if (fwrite(buffer, 1, len, ofile->file) < 1) {
549 int eno = errno;
550 croak("fwrite error %d writing %ld bytes to fd%d: %s",
551 eno, (long)len, fileno(ofile->file), strerror(eno));
552 }
553 }
554 return len;
555 }
556 #ifdef HAS_ZLIB
557 else if (FILE_STATE(ofile) != NYTP_FILE_DEFLATE) {
558 compressed_io_croak(ofile, "NYTP_write");
559 return 0;
560 }
561 while (1) {
562 int remaining = NYTP_FILE_LARGE_BUFFER_SIZE - ofile->zs.avail_in;
563 unsigned char *p = ofile->large_buffer + ofile->zs.avail_in;
564
565 if (remaining >= len) {
566 Copy(buffer, p, len, unsigned char);
567 ofile->zs.avail_in += len;
568 result += len;
569 return result;
570 } else {
571 /* Copy what we can, then flush the buffer. Lather, rinse, repeat.
572 */
573 Copy(buffer, p, remaining, unsigned char);
574 ofile->zs.avail_in = NYTP_FILE_LARGE_BUFFER_SIZE;
575 result += remaining;
576 len -= remaining;
577 buffer = (void *)(remaining + (char *)buffer);
578 flush_output(ofile, Z_NO_FLUSH);
579 }
580 }
581 #endif
582 }
583
584 int
NYTP_printf(NYTP_file ofile,const char * format,...)585 NYTP_printf(NYTP_file ofile, const char *format, ...) {
586 int retval;
587 va_list args;
588 ERRNO_PROBE;
589
590 CROAK_IF_NOT_STDIO(ofile, "NYTP_printf");
591
592 va_start(args, format);
593 {
594 dNFTHX(ofile);
595 retval = vfprintf(ofile->file, format, args);
596 }
597 va_end(args);
598
599 return retval;
600 }
601
602 int
NYTP_flush(NYTP_file file)603 NYTP_flush(NYTP_file file) {
604 ERRNO_PROBE;
605 #ifdef HAS_ZLIB
606 if (FILE_STATE(file) == NYTP_FILE_DEFLATE) {
607 flush_output(file, Z_SYNC_FLUSH);
608 }
609 #endif
610 {
611 dNFTHX(file);
612 return fflush(file->file);
613 }
614 }
615
616 int
NYTP_eof(NYTP_file ifile)617 NYTP_eof(NYTP_file ifile) {
618 ERRNO_PROBE;
619 #ifdef HAS_ZLIB
620 if (FILE_STATE(ifile) == NYTP_FILE_INFLATE) {
621 return ifile->zlib_at_eof;
622 }
623 #endif
624 {
625 dNFTHX(ifile);
626 return feof(ifile->file);
627 }
628 }
629
630 const char *
NYTP_fstrerror(NYTP_file file)631 NYTP_fstrerror(NYTP_file file) {
632 #ifdef HAS_ZLIB
633 if (FILE_STATE(file) == NYTP_FILE_DEFLATE || FILE_STATE(file) == NYTP_FILE_INFLATE) {
634 return file->zs.msg;
635 }
636 #endif
637 {
638 dNFTHX(file);
639 return strerror(errno);
640 }
641 }
642
643 int
NYTP_close(NYTP_file file,int discard)644 NYTP_close(NYTP_file file, int discard) {
645 FILE *raw_file = file->file;
646 int result;
647 dNFTHX(file);
648 ERRNO_PROBE;
649
650 #ifdef HAS_ZLIB
651 if (!discard && FILE_STATE(file) == NYTP_FILE_DEFLATE) {
652 const double ratio = file->zs.total_in / (double) file->zs.total_out;
653 flush_output(file, Z_FINISH);
654 fprintf(raw_file, "#\n"
655 "# Compressed %lu bytes to %lu, ratio %f:1, data shrunk by %f%%\n",
656 (long)file->zs.total_in, (long)file->zs.total_out, ratio,
657 100 * (1 - 1 / ratio));
658 }
659
660 if (FILE_STATE(file) == NYTP_FILE_DEFLATE) {
661 int status = deflateEnd(&(file->zs));
662 if (status != Z_OK) {
663 if (discard && status == Z_DATA_ERROR) {
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 croak("deflateEnd failed, error %d (%s) in %d", status,
670 file->zs.msg, getpid());
671 }
672 }
673 }
674 else if (FILE_STATE(file) == NYTP_FILE_INFLATE) {
675 int err = inflateEnd(&(file->zs));
676 if (err != Z_OK) {
677 croak("inflateEnd failed, error %d (%s)", err, file->zs.msg);
678 }
679 }
680 #endif
681
682 Safefree(file);
683
684 result = ferror(raw_file) ? errno : 0;
685
686 if (discard) {
687 /* close the underlying fd first so any buffered data gets discarded
688 * when fclose is called below */
689 close(fileno(raw_file));
690 }
691
692 if (result || discard) {
693 /* Something has already gone wrong, so try to preserve its error */
694 fclose(raw_file);
695 return result;
696 }
697 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
output_tag_u32(NYTP_file file,unsigned char tag,U32 i)711 output_tag_u32(NYTP_file file, unsigned char tag, U32 i)
712 {
713 U8 buffer[6];
714 U8 *p = buffer;
715
716 if (tag != NYTP_TAG_NO_TAG)
717 *p++ = tag;
718
719 /* general case. handles all integers */
720 if (i < 0x80) { /* < 8 bits */
721 *p++ = (U8)i;
722 }
723 else if (i < 0x4000) { /* < 16 bits */
724 *p++ = (U8)((i >> 8) | 0x80);
725 *p++ = (U8)i;
726 }
727 else if (i < 0x200000) { /* < 24 bits */
728 *p++ = (U8)((i >> 16) | 0xC0);
729 *p++ = (U8)(i >> 8);
730 *p++ = (U8)i;
731 }
732 else if (i < 0x10000000) { /* < 32 bits */
733 *p++ = (U8)((i >> 24) | 0xE0);
734 *p++ = (U8)(i >> 16);
735 *p++ = (U8)(i >> 8);
736 *p++ = (U8)i;
737 }
738 else { /* need all the bytes. */
739 *p++ = 0xFF;
740 *p++ = (U8)(i >> 24);
741 *p++ = (U8)(i >> 16);
742 *p++ = (U8)(i >> 8);
743 *p++ = (U8)i;
744 }
745 return NYTP_write(file, buffer, p - buffer);
746 }
747
748 static size_t
output_tag_i32(NYTP_file file,unsigned char tag,I32 i)749 output_tag_i32(NYTP_file file, unsigned char tag, I32 i)
750 {
751 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
read_u32(NYTP_file ifile)763 read_u32(NYTP_file ifile)
764 {
765 unsigned char d;
766 U32 newint;
767
768 NYTP_read(ifile, &d, sizeof(d), "integer prefix");
769
770 if (d < 0x80) { /* < 8 bits */
771 newint = d;
772 }
773 else {
774 unsigned char buffer[4];
775 unsigned char *p = buffer;
776 unsigned int length;
777
778 if (d < 0xC0) { /* < 16 bits */
779 newint = d & 0x7F;
780 length = 1;
781 }
782 else if (d < 0xE0) { /* < 24 bits */
783 newint = d & 0x1F;
784 length = 2;
785 }
786 else if (d < 0xFF) { /* < 32 bits */
787 newint = d & 0xF;
788 length = 3;
789 }
790 else { /* d == 0xFF */ /* = 32 bits */
791 newint = 0;
792 length = 4;
793 }
794 NYTP_read(ifile, buffer, length, "integer");
795 while (length--) {
796 newint <<= 8;
797 newint |= *p++;
798 }
799 }
800 return newint;
801 }
802
803 I32
read_i32(NYTP_file ifile)804 read_i32(NYTP_file ifile) {
805 U32 u = read_u32(ifile);
806 return *( (I32*)&u );
807 }
808
809
810 static size_t
output_str(NYTP_file file,const char * str,I32 len)811 output_str(NYTP_file file, const char *str, I32 len) { /* negative len signifies utf8 */
812 unsigned char tag = NYTP_TAG_STRING;
813 size_t retval;
814 size_t total;
815
816 if (len < 0) {
817 tag = NYTP_TAG_STRING_UTF8;
818 len = -len;
819 }
820
821 total = retval = output_tag_u32(file, tag, len);
822 if (retval <= 0)
823 return retval;
824
825 if (len) {
826 total += retval = NYTP_write(file, str, len);
827 if (retval <= 0)
828 return retval;
829 }
830
831 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
output_nv(NYTP_file file,NV nv)840 output_nv(NYTP_file file, NV nv)
841 {
842 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
read_nv(NYTP_file ifile)849 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 NYTP_read(ifile, (unsigned char *)&nv, sizeof(NV), "float");
856 return nv;
857 }
858
859
860 /* ====== Higher-level protocol I/O functions ====== */
861
862 size_t
NYTP_write_header(NYTP_file ofile,U32 major,U32 minor)863 NYTP_write_header(NYTP_file ofile, U32 major, U32 minor)
864 {
865 return NYTP_printf(ofile, "NYTProf %u %u\n", major, minor);
866 }
867
868 size_t
NYTP_write_comment(NYTP_file ofile,const char * format,...)869 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 retval = NYTP_write(ofile, "#", 1);
876 if (retval != 1)
877 return retval;
878
879 va_start(args, format);
880
881 if(strEQ(format, "%s")) {
882 const char * const s = va_arg(args, char*);
883 STRLEN len = strlen(s);
884 retval = NYTP_write(ofile, s, len);
885 } else {
886 CROAK_IF_NOT_STDIO(ofile, "NYTP_printf");
887 {
888 dNFTHX(ofile);
889 retval = vfprintf(ofile->file, format, args);
890 }
891 }
892 va_end(args);
893
894 retval2 = NYTP_write(ofile, "\n", 1);
895 if (retval2 != 1)
896 return retval2;
897
898 return retval + 2;
899 }
900
901 static size_t
NYTP_write_plain_kv(NYTP_file ofile,const char prefix,const char * key,size_t key_len,const char * value,size_t value_len)902 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 total = retval = NYTP_write(ofile, &prefix, 1);
910 if (retval != 1)
911 return retval;
912
913 total += retval = NYTP_write(ofile, key, key_len);
914 if (retval != key_len)
915 return retval;
916
917 total += retval = NYTP_write(ofile, "=", 1);
918 if (retval != 1)
919 return retval;
920
921 total += retval = NYTP_write(ofile, value, value_len);
922 if (retval != value_len)
923 return retval;
924
925 total += retval = NYTP_write(ofile, "\n", 1);
926 if (retval != 1)
927 return retval;
928
929 return total;
930 }
931
932 size_t
NYTP_write_attribute_string(NYTP_file ofile,const char * key,size_t key_len,const char * value,size_t value_len)933 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 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
NYTP_write_attribute_unsigned(NYTP_file ofile,const char * key,size_t key_len,unsigned long value)946 NYTP_write_attribute_unsigned(NYTP_file ofile, const char *key,
947 size_t key_len, unsigned long value)
948 {
949 /* 3: 1 for rounding errors, 1 for the '\0' */
950 char buffer[(int)(sizeof (unsigned long) * CHAR_BIT * LOG_2_OVER_LOG_10 + 3)];
951 const size_t len = my_snprintf(buffer, sizeof(buffer), "%lu", value);
952
953 return NYTP_write_attribute_string(ofile, key, key_len, buffer, len);
954 }
955
956 size_t
NYTP_write_attribute_signed(NYTP_file ofile,const char * key,size_t key_len,long value)957 NYTP_write_attribute_signed(NYTP_file ofile, const char *key,
958 size_t key_len, long value)
959 {
960 /* 3: 1 for rounding errors, 1 for the sign, 1 for the '\0' */
961 char buffer[(int)(sizeof (long) * CHAR_BIT * LOG_2_OVER_LOG_10 + 3)];
962 const size_t len = my_snprintf(buffer, sizeof(buffer), "%ld", value);
963
964 return NYTP_write_attribute_string(ofile, key, key_len, buffer, len);
965 }
966
967 size_t
NYTP_write_attribute_nv(NYTP_file ofile,const char * key,size_t key_len,NV value)968 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 const size_t len = my_snprintf(buffer, sizeof(buffer), "%" NVgf, value);
973
974 return NYTP_write_attribute_string(ofile, key, key_len, buffer, len);
975 }
976
977 /* options */
978
979 size_t
NYTP_write_option_pv(NYTP_file ofile,const char * key,const char * value,size_t value_len)980 NYTP_write_option_pv(NYTP_file ofile,
981 const char *key,
982 const char *value, size_t value_len)
983 {
984 return NYTP_write_plain_kv(ofile, '!', key, strlen(key), value, value_len);
985 }
986
987 size_t
NYTP_write_option_iv(NYTP_file ofile,const char * key,IV value)988 NYTP_write_option_iv(NYTP_file ofile, const char *key, IV value)
989 {
990 /* 3: 1 for rounding errors, 1 for the sign, 1 for the '\0' */
991 char buffer[(int)(sizeof (IV) * CHAR_BIT * LOG_2_OVER_LOG_10 + 3)];
992 const size_t len = my_snprintf(buffer, sizeof(buffer), "%" IVdf, value);
993
994 return NYTP_write_option_pv(ofile, key, buffer, len);
995 }
996
997 /* other */
998
999 #ifdef HAS_ZLIB
1000
1001 size_t
NYTP_start_deflate_write_tag_comment(NYTP_file ofile,int compression_level)1002 NYTP_start_deflate_write_tag_comment(NYTP_file ofile, int compression_level) {
1003 const unsigned char tag = NYTP_TAG_START_DEFLATE;
1004 size_t total;
1005 size_t retval;
1006
1007 total = retval = NYTP_write_comment(ofile, "Compressed at level %d with zlib %s",
1008 compression_level, zlibVersion());
1009
1010 if (retval < 1)
1011 return retval;
1012
1013 total += retval = NYTP_write(ofile, &tag, sizeof(tag));
1014 if (retval < 1)
1015 return retval;
1016
1017 NYTP_start_deflate(ofile, compression_level);
1018
1019 return total;
1020 }
1021
1022 #endif
1023
1024 size_t
NYTP_write_process_start(NYTP_file ofile,U32 pid,U32 ppid,NV time_of_day)1025 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 total = retval = output_tag_u32(ofile, NYTP_TAG_PID_START, pid);
1032 if (retval < 1)
1033 return retval;
1034
1035 total += retval = output_u32(ofile, ppid);
1036 if (retval < 1)
1037 return retval;
1038
1039 total += retval = output_nv(ofile, time_of_day);
1040 if (retval < 1)
1041 return retval;
1042
1043 return total;
1044 }
1045
1046 size_t
NYTP_write_process_end(NYTP_file ofile,U32 pid,NV time_of_day)1047 NYTP_write_process_end(NYTP_file ofile, U32 pid, NV time_of_day)
1048 {
1049 size_t total;
1050 size_t retval;
1051
1052 total = retval = output_tag_u32(ofile, NYTP_TAG_PID_END, pid);
1053 if (retval < 1)
1054 return retval;
1055
1056 total += retval = output_nv(ofile, time_of_day);
1057 if (retval < 1)
1058 return retval;
1059
1060 return total;
1061 }
1062
1063 size_t
NYTP_write_sawampersand(NYTP_file ofile,U32 fid,U32 line)1064 NYTP_write_sawampersand(NYTP_file ofile, U32 fid, U32 line)
1065 {
1066 size_t total;
1067 size_t retval;
1068
1069 total = retval = NYTP_write_attribute_unsigned(ofile, STR_WITH_LEN("sawampersand_fid"), fid);
1070 if (retval < 1)
1071 return retval;
1072
1073 total += retval = NYTP_write_attribute_unsigned(ofile, STR_WITH_LEN("sawampersand_line"), line);
1074 if (retval < 1)
1075 return retval;
1076
1077 return total;
1078 }
1079
1080 size_t
NYTP_write_new_fid(NYTP_file ofile,U32 id,U32 eval_fid,U32 eval_line_num,U32 flags,U32 size,U32 mtime,const char * name,I32 len)1081 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 total = retval = output_tag_u32(ofile, NYTP_TAG_NEW_FID, id);
1090 if (retval < 1)
1091 return retval;
1092
1093 total += retval = output_u32(ofile, eval_fid);
1094 if (retval < 1)
1095 return retval;
1096
1097 total += retval = output_u32(ofile, eval_line_num);
1098 if (retval < 1)
1099 return retval;
1100
1101 total += retval = output_u32(ofile, flags);
1102 if (retval < 1)
1103 return retval;
1104
1105 total += retval = output_u32(ofile, size);
1106 if (retval < 1)
1107 return retval;
1108
1109 total += retval = output_u32(ofile, mtime);
1110 if (retval < 1)
1111 return retval;
1112
1113 total += retval = output_str(ofile, name, len);
1114 if (retval < 1)
1115 return retval;
1116
1117 return total;
1118 }
1119
1120 static size_t
write_time_common(NYTP_file ofile,unsigned char tag,I32 elapsed,U32 overflow,U32 fid,U32 line)1121 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 if (overflow) {
1128 dNFTHX(ofile);
1129 /* XXX needs protocol change to output a new time-overflow tag */
1130 fprintf(stderr, "profile time overflow of %lu seconds discarded!\n",
1131 (unsigned long)overflow);
1132 }
1133
1134 total = retval = output_tag_i32(ofile, tag, elapsed);
1135 if (retval < 1)
1136 return retval;
1137
1138 total += retval = output_u32(ofile, fid);
1139 if (retval < 1)
1140 return retval;
1141
1142 total += retval = output_u32(ofile, line);
1143 if (retval < 1)
1144 return retval;
1145
1146 return total;
1147 }
1148
1149 size_t
NYTP_write_time_block(NYTP_file ofile,I32 elapsed,U32 overflow,U32 fid,U32 line,U32 last_block_line,U32 last_sub_line)1150 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 total = retval = write_time_common(ofile, NYTP_TAG_TIME_BLOCK, elapsed, overflow,
1157 fid, line);
1158 if (retval < 1)
1159 return retval;
1160
1161 total += retval = output_u32(ofile, last_block_line);
1162 if (retval < 1)
1163 return retval;
1164
1165 total += retval = output_u32(ofile, last_sub_line);
1166 if (retval < 1)
1167 return retval;
1168
1169 return total;
1170 }
1171
1172 size_t
NYTP_write_time_line(NYTP_file ofile,I32 elapsed,U32 overflow,U32 fid,U32 line)1173 NYTP_write_time_line(NYTP_file ofile, I32 elapsed, U32 overflow,
1174 U32 fid, U32 line)
1175 {
1176 return write_time_common(ofile, NYTP_TAG_TIME_LINE, elapsed, overflow, fid, line);
1177 }
1178
1179
1180 size_t
NYTP_write_call_entry(NYTP_file ofile,U32 caller_fid,U32 caller_line)1181 NYTP_write_call_entry(NYTP_file ofile, U32 caller_fid, U32 caller_line)
1182 {
1183 size_t total;
1184 size_t retval;
1185
1186 total = retval = output_tag_u32(ofile, NYTP_TAG_SUB_ENTRY, caller_fid);
1187 if (retval < 1)
1188 return retval;
1189
1190 total += retval = output_u32(ofile, caller_line);
1191 if (retval < 1)
1192 return retval;
1193
1194 return total;
1195 }
1196
1197 size_t
NYTP_write_call_return(NYTP_file ofile,U32 prof_depth,const char * called_subname_pv,NV incl_subr_ticks,NV excl_subr_ticks)1198 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 total = retval = output_tag_u32(ofile, NYTP_TAG_SUB_RETURN, prof_depth);
1205 if (retval < 1)
1206 return retval;
1207
1208 total += retval = output_nv(ofile, incl_subr_ticks);
1209 if (retval < 1)
1210 return retval;
1211
1212 total += retval = output_nv(ofile, excl_subr_ticks);
1213 if (retval < 1)
1214 return retval;
1215
1216 if (!called_subname_pv)
1217 called_subname_pv = "(null)";
1218 total += retval = output_str(ofile, called_subname_pv, strlen(called_subname_pv));
1219 if (retval < 1)
1220 return retval;
1221
1222 return total;
1223 }
1224
1225
1226 size_t
NYTP_write_sub_info(NYTP_file ofile,U32 fid,const char * name,I32 len,U32 first_line,U32 last_line)1227 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 total = retval = output_tag_u32(ofile, NYTP_TAG_SUB_INFO, fid);
1235 if (retval < 1)
1236 return retval;
1237
1238 total += retval = output_str(ofile, name, (I32)len);
1239 if (retval < 1)
1240 return retval;
1241
1242 total += retval = output_u32(ofile, first_line);
1243 if (retval < 1)
1244 return retval;
1245
1246 total += retval = output_u32(ofile, last_line);
1247 if (retval < 1)
1248 return retval;
1249
1250 return total;
1251 }
1252
1253 size_t
NYTP_write_sub_callers(NYTP_file ofile,U32 fid,U32 line,const char * caller_name,I32 caller_name_len,U32 count,NV incl_rtime,NV excl_rtime,NV reci_rtime,U32 depth,const char * called_name,I32 called_name_len)1254 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 total = retval = output_tag_u32(ofile, NYTP_TAG_SUB_CALLERS, fid);
1264 if (retval < 1)
1265 return retval;
1266
1267 total += retval = output_u32(ofile, line);
1268 if (retval < 1)
1269 return retval;
1270
1271 total += retval = output_str(ofile, caller_name, caller_name_len);
1272 if (retval < 1)
1273 return retval;
1274
1275 total += retval = output_u32(ofile, count);
1276 if (retval < 1)
1277 return retval;
1278
1279 total += retval = output_nv(ofile, incl_rtime);
1280 if (retval < 1)
1281 return retval;
1282
1283 total += retval = output_nv(ofile, excl_rtime);
1284 if (retval < 1)
1285 return retval;
1286
1287 total += retval = output_nv(ofile, reci_rtime);
1288 if (retval < 1)
1289 return retval;
1290
1291 total += retval = output_u32(ofile, depth);
1292 if (retval < 1)
1293 return retval;
1294
1295 total += retval = output_str(ofile, called_name, called_name_len);
1296 if (retval < 1)
1297 return retval;
1298
1299 return total;
1300 }
1301
1302 size_t
NYTP_write_src_line(NYTP_file ofile,U32 fid,U32 line,const char * text,I32 text_len)1303 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 total = retval = output_tag_u32(ofile, NYTP_TAG_SRC_LINE, fid);
1310 if (retval < 1)
1311 return retval;
1312
1313 total += retval = output_u32(ofile, line);
1314 if (retval < 1)
1315 return retval;
1316
1317 total += retval = output_str(ofile, text, text_len);
1318 if (retval < 1)
1319 return retval;
1320
1321 return total;
1322 }
1323
1324 size_t
NYTP_write_discount(NYTP_file ofile)1325 NYTP_write_discount(NYTP_file ofile)
1326 {
1327 const unsigned char tag = NYTP_TAG_DISCOUNT;
1328 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 NYTP_file fh = NYTP_open(pathname, mode);
1342 SV *object;
1343 PPCODE:
1344 if(!fh)
1345 XSRETURN(0);
1346 object = newSV(0);
1347 sv_usepvn(object, (char *) fh, sizeof(struct NYTP_file_t));
1348 ST(0) = sv_bless(sv_2mortal(newRV_noinc(object)), gv_stashpvs("Devel::NYTProf::FileHandle", GV_ADD));
1349 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 guts = SvRV(ST(0));
1360 PERL_UNUSED_VAR(ix);
1361 RETVAL = NYTP_close(handle, 0);
1362 SvPV_set(guts, NULL);
1363 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 p = SvPVbyte(string, len);
1376 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 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 const char *const key_p = SvPVbyte(key, key_len);
1411 STRLEN value_len;
1412 const char *const value_p = SvPVbyte(value, value_len);
1413 CODE:
1414 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 const char *const key_p = SvPVbyte(key, key_len);
1426 STRLEN value_len;
1427 const char *const value_p = SvPVbyte(value, value_len);
1428 CODE:
1429 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 const char *const p = SvPV(name, len);
1459 CODE:
1460 RETVAL = NYTP_write_new_fid(handle, id, eval_fid, eval_line_num,
1461 flags, size, mtime, p,
1462 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 const char *const p = SvPV(name, len);
1508 CODE:
1509 RETVAL = NYTP_write_sub_info(handle, fid,
1510 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 const char *const caller_p = SvPV(caller, caller_len);
1530 STRLEN called_len;
1531 const char *const called_p = SvPV(called_sub, called_len);
1532 CODE:
1533 RETVAL = NYTP_write_sub_callers(handle, fid, line, caller_p,
1534 SvUTF8(caller) ? -(I32)caller_len : (I32)caller_len,
1535 count, incl_rtime, excl_rtime,
1536 reci_rtime, depth, called_p,
1537 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 const char *const p = SvPV(text, len);
1550 CODE:
1551 RETVAL = NYTP_write_src_line(handle, fid, line,
1552 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
1566