5 * Refactor this to split out D:M code from Devel::Size code.
7 * Start migrating Devel::Size's Size.xs towards the new code.
9 * ADD_PRE_ATTR for index should check if the ptr is new first. Currently we're
10 * generating lots of ADD_PRE_ATTR's for SVs that we've already seen via other paths.
11 * That's wasteful and likely to cause subtle bugs.
13 * Give HE's their own node so keys and values can be tied together
17 #undef NDEBUG /* XXX */
20 #define PERL_NO_GET_CONTEXT
27 /* Not yet in ppport.h */
29 # define CvISXSUB(cv) (CvXSUB(cv) ? TRUE : FALSE)
32 # define SvRV_const(rv) SvRV(rv)
35 # define SvOOK_offset(sv, len) STMT_START { len = SvIVX(sv); } STMT_END
38 # define SvIsCOW(sv) ((SvFLAGS(sv) & (SVf_FAKE | SVf_READONLY)) == \
39 (SVf_FAKE | SVf_READONLY))
41 #ifndef SvIsCOW_shared_hash
42 # define SvIsCOW_shared_hash(sv) (SvIsCOW(sv) && SvLEN(sv) == 0)
44 #ifndef SvSHARED_HEK_FROM_PV
45 # define SvSHARED_HEK_FROM_PV(pvx) \
46 ((struct hek*)(pvx - STRUCT_OFFSET(struct hek, hek_key)))
50 # define PL_opargs opargs
51 # define PL_op_name op_name
55 /* "structured exception" handling is a Microsoft extension to C and C++.
56 It's *not* C++ exception handling - C++ exception handling can't capture
57 SEGVs and suchlike, whereas this can. There's no known analagous
58 functionality on other platforms. */
60 # define TRY_TO_CATCH_SEGV __try
61 # define CAUGHT_EXCEPTION __except(EXCEPTION_EXECUTE_HANDLER)
63 # define TRY_TO_CATCH_SEGV if(1)
64 # define CAUGHT_EXCEPTION else
68 # define __attribute__(x)
71 #if 0 && defined(DEBUGGING)
72 #define dbg_printf(x) printf x
77 #define TAG /* printf( "# %s(%d)\n", __FILE__, __LINE__ ) */
80 /* The idea is to have a tree structure to store 1 bit per possible pointer
81 address. The lowest 16 bits are stored in a block of 8092 bytes.
82 The blocks are in a 256-way tree, indexed by the reset of the pointer.
83 This can cope with 32 and 64 bit pointers, and any address space layout,
84 without excessive memory needs. The assumption is that your CPU cache
85 works :-) (And that we're not going to bust it) */
88 #define LEAF_BITS (16 - BYTE_BITS)
89 #define LEAF_MASK 0x1FFF
91 typedef struct npath_node_st npath_node_t;
92 struct npath_node_st {
107 /* My hunch (not measured) is that for most architectures pointers will
108 start with 0 bits, hence the start of this array will be hot, and the
109 end unused. So put the flags next to the hot end. */
112 int min_recurse_threshold;
113 /* callback hooks and data */
114 int (*add_attr_cb)(struct state *st, npath_node_t *npath_node, UV attr_type, const char *name, UV value);
115 void (*free_state_cb)(pTHX_ struct state *st);
116 void *state_cb_data; /* free'd by free_state() after free_state_cb() call */
117 /* this stuff wil be moved to state_cb_data later */
119 FILE *node_stream_fh;
120 char *node_stream_name;
123 #define ADD_SIZE(st, leafname, bytes) (NPathAddSizeCb(st, leafname, bytes) (st)->total_size += (bytes))
125 #define PATH_TRACKING
128 #define pPATH npath_node_t *NPathArg
130 /* A subtle point here is that dNPathNodes and NPathPushNode leave NP pointing
131 * to the next unused slot (though with prev already filled in)
132 * whereas NPathLink leaves NP unchanged, it just fills in the slot NP points
133 * to and passes that NP value to the function being called.
134 * seqn==0 indicates the node is new (hasn't been output yet)
136 #define dNPathNodes(nodes, prev_np) \
137 npath_node_t name_path_nodes[nodes+1]; /* +1 for NPathLink */ \
138 npath_node_t *NP = &name_path_nodes[0]; \
139 NP->seqn = NP->type = 0; NP->id = Nullch; /* safety/debug */ \
141 #define NPathPushNode(nodeid, nodetype) \
143 NP->type = nodetype; \
145 if(0)fprintf(stderr,"NPathPushNode (%p <-) %p <- [%d %s]\n", NP->prev, NP, nodetype,(char*)nodeid);\
147 NP->id = Nullch; /* safety/debug */ \
150 #define NPathSetNode(nodeid, nodetype) \
151 (NP-1)->id = nodeid; \
152 (NP-1)->type = nodetype; \
153 if(0)fprintf(stderr,"NPathSetNode (%p <-) %p <- [%d %s]\n", (NP-1)->prev, (NP-1), nodetype,(char*)nodeid);\
155 #define NPathPopNode \
158 /* dNPathUseParent points NP directly the the parents' name_path_nodes array
159 * So the function can only safely call ADD_*() but not NPathLink, unless the
160 * caller has spare nodes in its name_path_nodes.
162 #define dNPathUseParent(prev_np) npath_node_t *NP = (((prev_np+1)->prev = prev_np), prev_np+1)
164 #define NPtype_NAME 0x01
165 #define NPtype_LINK 0x02
166 #define NPtype_SV 0x03
167 #define NPtype_MAGIC 0x04
168 #define NPtype_OP 0x05
170 /* XXX these should probably be generalizes into flag bits */
171 #define NPattr_LEAFSIZE 0x00
172 #define NPattr_NAME 0x01
173 #define NPattr_PADFAKE 0x02
174 #define NPattr_PADNAME 0x03
175 #define NPattr_PADTMP 0x04
176 #define NPattr_NOTE 0x05
177 #define NPattr_PRE_ATTR 0x06 /* deprecated */
179 #define _ADD_ATTR_NP(st, attr_type, attr_name, attr_value, np) (st->add_attr_cb && st->add_attr_cb(st, np, attr_type, attr_name, attr_value))
180 #define ADD_ATTR(st, attr_type, attr_name, attr_value) _ADD_ATTR_NP(st, attr_type, attr_name, attr_value, NP-1)
181 #define ADD_LINK_ATTR(st, attr_type, attr_name, attr_value) (assert(NP->seqn), _ADD_ATTR_NP(st, attr_type, attr_name, attr_value, NP))
182 #define ADD_PRE_ATTR(st, attr_type, attr_name, attr_value) (assert(!attr_type), _ADD_ATTR_NP(st, NPattr_PRE_ATTR, attr_name, attr_value, NP-1))
184 #define _NPathLink(np, nid, ntype) (((np)->id=nid), ((np)->type=ntype), ((np)->seqn=0))
185 #define NPathLink(nid) (_NPathLink(NP, nid, NPtype_LINK), NP)
186 /* add a link and a name node to the path - a special case for op_size */
187 #define NPathLinkAndNode(nid, nid2) (_NPathLink(NP, nid, NPtype_LINK), _NPathLink(NP+1, nid2, NPtype_NAME), ((NP+1)->prev=NP), (NP+1))
188 #define NPathOpLink (NPathArg)
189 #define NPathAddSizeCb(st, name, bytes) (st->add_attr_cb && st->add_attr_cb(st, NP-1, NPattr_LEAFSIZE, (name), (bytes))),
193 #define NPathAddSizeCb(st, name, bytes)
194 #define pPATH void *npath_dummy /* XXX ideally remove */
195 #define dNPathNodes(nodes, prev_np) dNOOP
196 #define NPathLink(nodeid, nodetype) NULL
197 #define NPathOpLink NULL
198 #define ADD_ATTR(st, attr_type, attr_name, attr_value) NOOP
200 #endif /* PATH_TRACKING */
207 static const char *svtypenames[SVt_LAST] = {
209 "NULL", "IV", "NV", "RV", "PV", "PVIV", "PVNV", "PVMG", "PVBM", "PVLV", "PVAV", "PVHV", "PVCV", "PVGV", "PVFM", "PVIO",
210 #elif PERL_VERSION == 10 && PERL_SUBVERSION == 0
211 "NULL", "BIND", "IV", "NV", "RV", "PV", "PVIV", "PVNV", "PVMG", "PVGV", "PVLV", "PVAV", "PVHV", "PVCV", "PVFM", "PVIO",
212 #elif PERL_VERSION == 10 && PERL_SUBVERSION == 1
213 "NULL", "BIND", "IV", "NV", "RV", "PV", "PVIV", "PVNV", "PVMG", "PVGV", "PVLV", "PVAV", "PVHV", "PVCV", "PVFM", "PVIO",
214 #elif PERL_VERSION < 13
215 "NULL", "BIND", "IV", "NV", "PV", "PVIV", "PVNV", "PVMG", "REGEXP", "PVGV", "PVLV", "PVAV", "PVHV", "PVCV", "PVFM", "PVIO",
217 "NULL", "BIND", "IV", "NV", "PV", "PVIV", "PVNV", "PVMG", "REGEXP", "PVGV", "PVLV", "PVAV", "PVHV", "PVCV", "PVFM", "PVIO",
222 gettimeofday_nv(void)
224 #ifdef HAS_GETTIMEOFDAY
226 gettimeofday(&when, (struct timezone *) 0);
227 return when.tv_sec + (when.tv_usec / 1000000.0);
231 (*u2time)(aTHX_ &time_of_day);
232 return time_of_day[0] + (time_of_day[1] / 1000000.0);
240 np_print_node_name(FILE *fp, npath_node_t *npath_node)
242 char buf[1024]; /* XXX */
244 switch (npath_node->type) {
245 case NPtype_SV: { /* id is pointer to the SV sv_size was called on */
246 const SV *sv = (SV*)npath_node->id;
247 int type = SvTYPE(sv);
248 char *typename = (type == SVt_IV && SvROK(sv)) ? "RV" : svtypenames[type];
249 fprintf(fp, "SV(%s)", typename);
250 switch(type) { /* add some useful details */
251 case SVt_PVAV: fprintf(fp, " fill=%d/%ld", av_len((AV*)sv), AvMAX((AV*)sv)); break;
252 case SVt_PVHV: fprintf(fp, " fill=%ld/%ld", HvFILL((HV*)sv), HvMAX((HV*)sv)); break;
256 case NPtype_OP: { /* id is pointer to the OP op_size was called on */
257 const OP *op = (OP*)npath_node->id;
258 fprintf(fp, "OP(%s)", OP_NAME(op));
261 case NPtype_MAGIC: { /* id is pointer to the MAGIC struct */
262 MAGIC *magic_pointer = (MAGIC*)npath_node->id;
263 /* XXX it would be nice if we could reuse mg_names.c [sigh] */
264 fprintf(fp, "MAGIC(%c)", magic_pointer->mg_type ? magic_pointer->mg_type : '0');
268 fprintf(fp, "%s", npath_node->id);
271 fprintf(fp, "%s", npath_node->id);
273 default: /* assume id is a string pointer */
274 fprintf(fp, "UNKNOWN(%d,%p)", npath_node->type, npath_node->id);
281 np_dump_indent(int depth) {
283 fprintf(stderr, ": ");
287 np_walk_new_nodes(struct state *st,
288 npath_node_t *npath_node,
289 npath_node_t *npath_node_deeper,
290 int (*cb)(struct state *st, npath_node_t *npath_node, npath_node_t *npath_node_deeper))
292 if (npath_node->seqn) /* node already output */
295 if (npath_node->prev) {
296 np_walk_new_nodes(st, npath_node->prev, npath_node, cb); /* recurse */
297 npath_node->depth = npath_node->prev->depth + 1;
299 else npath_node->depth = 0;
300 npath_node->seqn = ++st->seqn;
303 if (cb(st, npath_node, npath_node_deeper)) {
304 /* ignore this node */
305 assert(npath_node->prev);
306 assert(npath_node->depth);
307 assert(npath_node_deeper);
309 npath_node->seqn = --st->seqn;
310 npath_node_deeper->prev = npath_node->prev;
318 np_dump_formatted_node(struct state *st, npath_node_t *npath_node, npath_node_t *npath_node_deeper) {
319 if (0 && npath_node->type == NPtype_LINK)
321 np_dump_indent(npath_node->depth);
322 np_print_node_name(stderr, npath_node);
323 if (npath_node->type == NPtype_LINK)
324 fprintf(stderr, "->"); /* cosmetic */
325 fprintf(stderr, "\t\t[#%ld @%u] ", npath_node->seqn, npath_node->depth);
326 fprintf(stderr, "\n");
331 np_dump_node_path_info(struct state *st, npath_node_t *npath_node, UV attr_type, const char *attr_name, UV attr_value)
333 if (attr_type == NPattr_LEAFSIZE && !attr_value)
334 return 0; /* ignore zero sized leaf items */
335 np_walk_new_nodes(st, npath_node, NULL, np_dump_formatted_node);
336 np_dump_indent(npath_node->depth+1);
338 case NPattr_LEAFSIZE:
339 fprintf(stderr, "+%ld %s =%ld", attr_value, attr_name, attr_value+st->total_size);
342 fprintf(stderr, "~NAMED('%s') %lu", attr_name, attr_value);
345 fprintf(stderr, "~note %s %lu", attr_name, attr_value);
350 fprintf(stderr, "~pad%lu %s %lu", attr_type, attr_name, attr_value);
353 fprintf(stderr, "~??? %s %lu", attr_name, attr_value);
356 fprintf(stderr, "\n");
361 np_stream_formatted_node(struct state *st, npath_node_t *npath_node, npath_node_t *npath_node_deeper) {
362 fprintf(st->node_stream_fh, "-%u %lu %u ",
363 npath_node->type, npath_node->seqn, (unsigned)npath_node->depth
365 np_print_node_name(st->node_stream_fh, npath_node);
366 fprintf(st->node_stream_fh, "\n");
371 np_stream_node_path_info(struct state *st, npath_node_t *npath_node, UV attr_type, const char *attr_name, UV attr_value)
373 if (!attr_type && !attr_value)
374 return 0; /* ignore zero sized leaf items */
375 np_walk_new_nodes(st, npath_node, NULL, np_stream_formatted_node);
376 if (attr_type) { /* Attribute type, name and value */
377 fprintf(st->node_stream_fh, "%lu %lu ", attr_type, npath_node->seqn);
379 else { /* Leaf name and memory size */
380 fprintf(st->node_stream_fh, "L %lu ", npath_node->seqn);
382 fprintf(st->node_stream_fh, "%lu %s\n", attr_value, attr_name);
387 #endif /* PATH_TRACKING */
391 Checks to see if thing is in the bitstring.
392 Returns true or false, and
393 notes thing in the segmented bitstring.
396 check_new(struct state *st, const void *const p) {
397 unsigned int bits = 8 * sizeof(void*);
398 const size_t raw_p = PTR2nat(p);
399 /* This effectively rotates the value right by the number of low always-0
400 bits in an aligned pointer. The assmption is that most (if not all)
401 pointers are aligned, and these will be in the same chain of nodes
402 (and hence hot in the cache) but we can still deal with any unaligned
404 const size_t cooked_p
405 = (raw_p >> ALIGN_BITS) | (raw_p << (bits - ALIGN_BITS));
406 const U8 this_bit = 1 << (cooked_p & 0x7);
410 void **tv_p = (void **) (st->tracking);
412 if (NULL == p) return FALSE;
414 const char c = *(const char *)p;
417 if (st->dangle_whine)
418 warn( "Devel::Size: Encountered invalid pointer: %p\n", p );
424 /* bits now 24 (32 bit pointers) or 56 (64 bit pointers) */
426 /* First level is always present. */
428 i = (unsigned int)((cooked_p >> bits) & 0xFF);
430 Newxz(tv_p[i], 256, void *);
431 tv_p = (void **)(tv_p[i]);
433 } while (bits > LEAF_BITS + BYTE_BITS);
434 /* bits now 16 always */
435 #if !defined(MULTIPLICITY) || PERL_VERSION > 8 || (PERL_VERSION == 8 && PERL_SUBVERSION > 8)
436 /* 5.8.8 and early have an assert() macro that uses Perl_croak, hence needs
437 a my_perl under multiplicity */
440 leaf_p = (U8 **)tv_p;
441 i = (unsigned int)((cooked_p >> bits) & 0xFF);
443 Newxz(leaf_p[i], 1 << LEAF_BITS, U8);
448 i = (unsigned int)((cooked_p >> BYTE_BITS) & LEAF_MASK);
450 if(leaf[i] & this_bit)
458 free_tracking_at(void **tv, int level)
466 free_tracking_at((void **) tv[i], level);
480 free_state(struct state *st)
482 const int top_level = (sizeof(void *) * 8 - LEAF_BITS - BYTE_BITS) / 8;
483 if (st->free_state_cb)
484 st->free_state_cb(st);
485 if (st->state_cb_data)
486 Safefree(st->state_cb_data);
487 free_tracking_at((void **)st->tracking, top_level);
491 /* For now, this is somewhat a compatibility bodge until the plan comes
492 together for fine grained recursion control. total_size() would recurse into
493 hash and array members, whereas sv_size() would not. However, sv_size() is
494 called with CvSTASH() of a CV, which means that if it (also) starts to
495 recurse fully, then the size of any CV now becomes the size of the entire
496 symbol table reachable from it, and potentially the entire symbol table, if
497 any subroutine makes a reference to a global (such as %SIG). The historical
498 implementation of total_size() didn't report "everything", and changing the
499 only available size to "everything" doesn't feel at all useful. */
501 #define NO_RECURSION 0
502 #define SOME_RECURSION 1
503 #define TOTAL_SIZE_RECURSION 2
505 static bool sv_size(pTHX_ struct state *, pPATH, const SV *const, const int recurse);
521 , OPc_CONDOP /* 12 */
530 cc_opclass(const OP * const o)
536 return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
538 if (o->op_type == OP_SASSIGN)
539 return ((o->op_private & OPpASSIGN_BACKWARDS) ? OPc_UNOP : OPc_BINOP);
542 if (o->op_type == OP_GV || o->op_type == OP_GVSV || o->op_type == OP_AELEMFAST)
546 if ((o->op_type == OP_TRANS)) {
550 switch (PL_opargs[o->op_type] & OA_CLASS_MASK) {
582 #ifdef OA_PVOP_OR_SVOP
583 case OA_PVOP_OR_SVOP: TAG;
585 * Character translations (tr///) are usually a PVOP, keeping a
586 * pointer to a table of shorts used to look up translations.
587 * Under utf8, however, a simple table isn't practical; instead,
588 * the OP is an SVOP, and the SV is a reference to a swash
589 * (i.e., an RV pointing to an HV).
591 return (o->op_private & (OPpTRANS_TO_UTF|OPpTRANS_FROM_UTF))
592 ? OPc_SVOP : OPc_PVOP;
601 case OA_BASEOP_OR_UNOP: TAG;
603 * UNI(OP_foo) in toke.c returns token UNI or FUNC1 depending on
604 * whether parens were seen. perly.y uses OPf_SPECIAL to
605 * signal whether a BASEOP had empty parens or none.
606 * Some other UNOPs are created later, though, so the best
607 * test is OPf_KIDS, which is set in newUNOP.
609 return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
611 case OA_FILESTATOP: TAG;
613 * The file stat OPs are created via UNI(OP_foo) in toke.c but use
614 * the OPf_REF flag to distinguish between OP types instead of the
615 * usual OPf_SPECIAL flag. As usual, if OPf_KIDS is set, then we
616 * return OPc_UNOP so that walkoptree can find our children. If
617 * OPf_KIDS is not set then we check OPf_REF. Without OPf_REF set
618 * (no argument to the operator) it's an OP; with OPf_REF set it's
619 * an SVOP (and op_sv is the GV for the filehandle argument).
621 return ((o->op_flags & OPf_KIDS) ? OPc_UNOP :
623 (o->op_flags & OPf_REF) ? OPc_PADOP : OPc_BASEOP);
625 (o->op_flags & OPf_REF) ? OPc_SVOP : OPc_BASEOP);
627 case OA_LOOPEXOP: TAG;
629 * next, last, redo, dump and goto use OPf_SPECIAL to indicate that a
630 * label was omitted (in which case it's a BASEOP) or else a term was
631 * seen. In this last case, all except goto are definitely PVOP but
632 * goto is either a PVOP (with an ordinary constant label), an UNOP
633 * with OPf_STACKED (with a non-constant non-sub) or an UNOP for
634 * OP_REFGEN (with goto &sub) in which case OPf_STACKED also seems to
637 if (o->op_flags & OPf_STACKED)
639 else if (o->op_flags & OPf_SPECIAL)
649 warn("Devel::Size: Can't determine class of operator %s, assuming BASEOP\n",
650 PL_op_name[o->op_type]);
656 /* Figure out how much magic is attached to the SV and return the
659 magic_size(pTHX_ const SV * const thing, struct state *st, pPATH) {
660 dNPathNodes(1, NPathArg);
661 MAGIC *magic_pointer = SvMAGIC(thing);
666 if (!SvMAGICAL(thing)) {
668 warn("Ignoring suspect magic on this SV\n");
674 /* push a dummy node for NPathSetNode to update inside the while loop */
675 NPathPushNode("dummy", NPtype_NAME);
677 /* Have we seen the magic pointer? (NULL has always been seen before) */
678 while (check_new(st, magic_pointer)) {
680 NPathSetNode(magic_pointer, NPtype_MAGIC);
682 ADD_SIZE(st, "mg", sizeof(MAGIC));
683 /* magic vtables aren't freed when magic is freed, so don't count them.
684 (They are static structures. Anything that assumes otherwise is buggy.)
689 /* XXX only chase mg_obj if mg->mg_flags & MGf_REFCOUNTED ? */
690 sv_size(aTHX_ st, NPathLink("mg_obj"), magic_pointer->mg_obj, TOTAL_SIZE_RECURSION);
691 if (magic_pointer->mg_len == HEf_SVKEY) {
692 sv_size(aTHX_ st, NPathLink("mg_ptr"), (SV *)magic_pointer->mg_ptr, TOTAL_SIZE_RECURSION);
694 #if defined(PERL_MAGIC_utf8) && defined (PERL_MAGIC_UTF8_CACHESIZE)
695 else if (magic_pointer->mg_type == PERL_MAGIC_utf8) {
696 if (check_new(st, magic_pointer->mg_ptr)) {
697 ADD_SIZE(st, "PERL_MAGIC_utf8", PERL_MAGIC_UTF8_CACHESIZE * 2 * sizeof(STRLEN));
701 /* XXX also handle mg->mg_type == PERL_MAGIC_utf8 ? */
702 else if (magic_pointer->mg_len > 0) {
703 if(0)do_magic_dump(0, Perl_debug_log, magic_pointer, 0, 0, FALSE, 0);
704 if (check_new(st, magic_pointer->mg_ptr)) {
705 ADD_SIZE(st, "mg_len", magic_pointer->mg_len);
709 /* Get the next in the chain */
710 magic_pointer = magic_pointer->mg_moremagic;
713 if (st->dangle_whine)
714 warn( "Devel::Size: Encountered bad magic at: %p\n", magic_pointer );
720 check_new_and_strlen(struct state *st, const char *const p, pPATH) {
721 dNPathNodes(1, NPathArg->prev);
722 if(check_new(st, p)) {
723 NPathPushNode(NPathArg->id, NPtype_NAME);
724 ADD_SIZE(st, NPathArg->id, 1 + strlen(p));
729 regex_size(const REGEXP * const baseregex, struct state *st, pPATH) {
730 dNPathNodes(1, NPathArg);
731 if(!check_new(st, baseregex))
733 NPathPushNode("regex_size", NPtype_NAME);
734 ADD_SIZE(st, "REGEXP", sizeof(REGEXP));
735 #if (PERL_VERSION < 11)
736 /* Note the size of the paren offset thing */
737 ADD_SIZE(st, "nparens", sizeof(I32) * baseregex->nparens * 2);
738 ADD_SIZE(st, "precomp", strlen(baseregex->precomp));
740 ADD_SIZE(st, "regexp", sizeof(struct regexp));
741 ADD_SIZE(st, "nparens", sizeof(I32) * SvANY(baseregex)->nparens * 2);
742 /*ADD_SIZE(st, strlen(SvANY(baseregex)->subbeg));*/
744 if (st->go_yell && !st->regex_whine) {
745 carp("Devel::Size: Calculated sizes for compiled regexes are incompatible, and probably always will be");
751 op_size(pTHX_ const OP * const baseop, struct state *st, pPATH)
753 /* op_size recurses to follow the chain of opcodes. For the node path we
754 * don't want the chain to be 'nested' in the path so we use dNPathUseParent().
755 * Also, to avoid a link-to-a-link the caller should use NPathLinkAndNode()
756 * instead of NPathLink().
758 dNPathUseParent(NPathArg);
762 if(!check_new(st, baseop))
765 op_size(aTHX_ baseop->op_next, st, NPathOpLink);
767 switch (cc_opclass(baseop)) {
768 case OPc_BASEOP: TAG;
769 ADD_SIZE(st, "op", sizeof(struct op));
772 ADD_SIZE(st, "unop", sizeof(struct unop));
773 op_size(aTHX_ ((UNOP *)baseop)->op_first, st, NPathOpLink);
776 ADD_SIZE(st, "binop", sizeof(struct binop));
777 op_size(aTHX_ ((BINOP *)baseop)->op_first, st, NPathOpLink);
778 op_size(aTHX_ ((BINOP *)baseop)->op_last, st, NPathOpLink);
781 ADD_SIZE(st, "logop", sizeof(struct logop));
782 op_size(aTHX_ ((BINOP *)baseop)->op_first, st, NPathOpLink);
783 op_size(aTHX_ ((LOGOP *)baseop)->op_other, st, NPathOpLink);
786 case OPc_CONDOP: TAG;
787 ADD_SIZE(st, "condop", sizeof(struct condop));
788 op_size(aTHX_ ((BINOP *)baseop)->op_first, st, NPathOpLink);
789 op_size(aTHX_ ((CONDOP *)baseop)->op_true, st, NPathOpLink);
790 op_size(aTHX_ ((CONDOP *)baseop)->op_false, st, NPathOpLink);
793 case OPc_LISTOP: TAG;
794 ADD_SIZE(st, "listop", sizeof(struct listop));
795 op_size(aTHX_ ((LISTOP *)baseop)->op_first, st, NPathOpLink);
796 op_size(aTHX_ ((LISTOP *)baseop)->op_last, st, NPathOpLink);
799 ADD_SIZE(st, "pmop", sizeof(struct pmop));
800 op_size(aTHX_ ((PMOP *)baseop)->op_first, st, NPathOpLink);
801 op_size(aTHX_ ((PMOP *)baseop)->op_last, st, NPathOpLink);
802 #if PERL_VERSION < 9 || (PERL_VERSION == 9 && PERL_SUBVERSION < 5)
803 op_size(aTHX_ ((PMOP *)baseop)->op_pmreplroot, st, NPathOpLink);
804 op_size(aTHX_ ((PMOP *)baseop)->op_pmreplstart, st, NPathOpLink);
806 /* This is defined away in perl 5.8.x, but it is in there for
809 regex_size(PM_GETRE((PMOP *)baseop), st, NPathLink("PM_GETRE"));
811 regex_size(((PMOP *)baseop)->op_pmregexp, st, NPathLink("op_pmregexp"));
815 ADD_SIZE(st, "svop", sizeof(struct svop));
816 if (!(baseop->op_type == OP_AELEMFAST
817 && baseop->op_flags & OPf_SPECIAL)) {
818 /* not an OP_PADAV replacement */
819 sv_size(aTHX_ st, NPathLink("SVOP"), ((SVOP *)baseop)->op_sv, SOME_RECURSION);
824 ADD_SIZE(st, "padop", sizeof(struct padop));
829 ADD_SIZE(st, "gvop", sizeof(struct gvop));
830 sv_size(aTHX_ st, NPathLink("GVOP"), ((GVOP *)baseop)->op_gv, SOME_RECURSION);
834 check_new_and_strlen(st, ((PVOP *)baseop)->op_pv, NPathLink("op_pv"));
837 ADD_SIZE(st, "loop", sizeof(struct loop));
838 op_size(aTHX_ ((LOOP *)baseop)->op_first, st, NPathOpLink);
839 op_size(aTHX_ ((LOOP *)baseop)->op_last, st, NPathOpLink);
840 op_size(aTHX_ ((LOOP *)baseop)->op_redoop, st, NPathOpLink);
841 op_size(aTHX_ ((LOOP *)baseop)->op_nextop, st, NPathOpLink);
842 op_size(aTHX_ ((LOOP *)baseop)->op_lastop, st, NPathOpLink);
847 basecop = (COP *)baseop;
848 ADD_SIZE(st, "cop", sizeof(struct cop));
850 /* Change 33656 by nicholas@mouse-mill on 2008/04/07 11:29:51
851 Eliminate cop_label from struct cop by storing a label as the first
852 entry in the hints hash. Most statements don't have labels, so this
853 will save memory. Not sure how much.
854 The check below will be incorrect fail on bleadperls
855 before 5.11 @33656, but later than 5.10, producing slightly too
856 small memory sizes on these Perls. */
857 #if (PERL_VERSION < 11)
858 check_new_and_strlen(st, basecop->cop_label, NPathLink("cop_label"));
861 check_new_and_strlen(st, basecop->cop_file, NPathLink("cop_file"));
862 check_new_and_strlen(st, basecop->cop_stashpv, NPathLink("cop_stashpv"));
864 if (SvREFCNT(basecop->cop_stash) == 1) /* XXX hack? */
865 sv_size(aTHX_ st, NPathLink("cop_stash"), (SV *)basecop->cop_stash, SOME_RECURSION);
866 sv_size(aTHX_ st, NPathLink("cop_filegv"), (SV *)basecop->cop_filegv, SOME_RECURSION);
876 if (st->dangle_whine)
877 warn( "Devel::Size: Encountered dangling pointer in opcode at: %p\n", baseop );
882 hek_size(pTHX_ struct state *st, HEK *hek, U32 shared, pPATH)
884 dNPathUseParent(NPathArg);
886 /* Hash keys can be shared. Have we seen this before? */
887 if (!check_new(st, hek))
889 ADD_SIZE(st, "hek_len", HEK_BASESIZE + hek->hek_len
891 + 1 /* No hash key flags prior to 5.8.0 */
897 #if PERL_VERSION < 10
898 ADD_SIZE(st, "he", sizeof(struct he));
900 ADD_SIZE(st, "shared_he", STRUCT_OFFSET(struct shared_he, shared_he_hek));
906 #if PERL_VERSION < 8 || PERL_SUBVERSION < 9 /* XXX plain || seems like a bug */
911 # define MAYBE_PURIFY(normal, pure) (pure)
912 # define MAYBE_OFFSET(struct_name, member) 0
914 # define MAYBE_PURIFY(normal, pure) (normal)
915 # define MAYBE_OFFSET(struct_name, member) STRUCT_OFFSET(struct_name, member)
918 const U8 body_sizes[SVt_LAST] = {
921 MAYBE_PURIFY(sizeof(IV), sizeof(XPVIV)), /* SVt_IV */
922 MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)), /* SVt_NV */
923 sizeof(XRV), /* SVt_RV */
924 sizeof(XPV), /* SVt_PV */
925 sizeof(XPVIV), /* SVt_PVIV */
926 sizeof(XPVNV), /* SVt_PVNV */
927 sizeof(XPVMG), /* SVt_PVMG */
928 sizeof(XPVBM), /* SVt_PVBM */
929 sizeof(XPVLV), /* SVt_PVLV */
930 sizeof(XPVAV), /* SVt_PVAV */
931 sizeof(XPVHV), /* SVt_PVHV */
932 sizeof(XPVCV), /* SVt_PVCV */
933 sizeof(XPVGV), /* SVt_PVGV */
934 sizeof(XPVFM), /* SVt_PVFM */
935 sizeof(XPVIO) /* SVt_PVIO */
936 #elif PERL_VERSION == 10 && PERL_SUBVERSION == 0
940 MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)), /* SVt_NV */
942 MAYBE_PURIFY(sizeof(xpv_allocated), sizeof(XPV)), /* SVt_PV */
943 MAYBE_PURIFY(sizeof(xpviv_allocated), sizeof(XPVIV)),/* SVt_PVIV */
944 sizeof(XPVNV), /* SVt_PVNV */
945 sizeof(XPVMG), /* SVt_PVMG */
946 sizeof(XPVGV), /* SVt_PVGV */
947 sizeof(XPVLV), /* SVt_PVLV */
948 MAYBE_PURIFY(sizeof(xpvav_allocated), sizeof(XPVAV)),/* SVt_PVAV */
949 MAYBE_PURIFY(sizeof(xpvhv_allocated), sizeof(XPVHV)),/* SVt_PVHV */
950 MAYBE_PURIFY(sizeof(xpvcv_allocated), sizeof(XPVCV)),/* SVt_PVCV */
951 MAYBE_PURIFY(sizeof(xpvfm_allocated), sizeof(XPVFM)),/* SVt_PVFM */
952 sizeof(XPVIO), /* SVt_PVIO */
953 #elif PERL_VERSION == 10 && PERL_SUBVERSION == 1
957 MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)), /* SVt_NV */
959 sizeof(XPV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PV */
960 sizeof(XPVIV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PVIV */
961 sizeof(XPVNV), /* SVt_PVNV */
962 sizeof(XPVMG), /* SVt_PVMG */
963 sizeof(XPVGV), /* SVt_PVGV */
964 sizeof(XPVLV), /* SVt_PVLV */
965 sizeof(XPVAV) - MAYBE_OFFSET(XPVAV, xav_fill), /* SVt_PVAV */
966 sizeof(XPVHV) - MAYBE_OFFSET(XPVHV, xhv_fill), /* SVt_PVHV */
967 sizeof(XPVCV) - MAYBE_OFFSET(XPVCV, xpv_cur), /* SVt_PVCV */
968 sizeof(XPVFM) - MAYBE_OFFSET(XPVFM, xpv_cur), /* SVt_PVFM */
969 sizeof(XPVIO) /* SVt_PVIO */
970 #elif PERL_VERSION < 13
974 MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)), /* SVt_NV */
975 sizeof(XPV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PV */
976 sizeof(XPVIV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PVIV */
977 sizeof(XPVNV), /* SVt_PVNV */
978 sizeof(XPVMG), /* SVt_PVMG */
979 sizeof(regexp) - MAYBE_OFFSET(regexp, xpv_cur), /* SVt_REGEXP */
980 sizeof(XPVGV), /* SVt_PVGV */
981 sizeof(XPVLV), /* SVt_PVLV */
982 sizeof(XPVAV) - MAYBE_OFFSET(XPVAV, xav_fill), /* SVt_PVAV */
983 sizeof(XPVHV) - MAYBE_OFFSET(XPVHV, xhv_fill), /* SVt_PVHV */
984 sizeof(XPVCV) - MAYBE_OFFSET(XPVCV, xpv_cur), /* SVt_PVCV */
985 sizeof(XPVFM) - MAYBE_OFFSET(XPVFM, xpv_cur), /* SVt_PVFM */
986 sizeof(XPVIO) /* SVt_PVIO */
991 MAYBE_PURIFY(sizeof(NV), sizeof(XPVNV)), /* SVt_NV */
992 sizeof(XPV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PV */
993 sizeof(XPVIV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PVIV */
994 sizeof(XPVNV) - MAYBE_OFFSET(XPV, xpv_cur), /* SVt_PVNV */
995 sizeof(XPVMG), /* SVt_PVMG */
996 sizeof(regexp), /* SVt_REGEXP */
997 sizeof(XPVGV), /* SVt_PVGV */
998 sizeof(XPVLV), /* SVt_PVLV */
999 sizeof(XPVAV), /* SVt_PVAV */
1000 sizeof(XPVHV), /* SVt_PVHV */
1001 sizeof(XPVCV), /* SVt_PVCV */
1002 sizeof(XPVFM), /* SVt_PVFM */
1003 sizeof(XPVIO) /* SVt_PVIO */
1008 /* based on Perl_do_dump_pad() - wraps sv_size and adds ADD_ATTR calls for the pad names */
1010 padlist_size(pTHX_ struct state *const st, pPATH, PADLIST *padlist,
1013 dNPathUseParent(NPathArg);
1020 if( 0 && !check_new(st, padlist))
1023 pad_name = MUTABLE_AV(*av_fetch(MUTABLE_AV(padlist), 0, FALSE));
1024 pname = AvARRAY(pad_name);
1026 for (ix = 1; ix <= AvFILLp(pad_name); ix++) {
1027 const SV *namesv = pname[ix];
1028 if (namesv && namesv == &PL_sv_undef) {
1032 /* SvFAKE: On a pad name SV, that slot in the frame AV is a REFCNT'ed reference to a lexical from "outside" */
1034 ADD_ATTR(st, NPattr_PADFAKE, SvPVX_const(namesv), ix);
1036 ADD_ATTR(st, NPattr_PADNAME, SvPVX_const(namesv), ix);
1039 ADD_ATTR(st, NPattr_PADTMP, "SVs_PADTMP", ix);
1043 sv_size(aTHX_ st, NPathArg, (SV*)padlist, recurse);
1048 sv_size(pTHX_ struct state *const st, pPATH, const SV * const orig_thing,
1049 const int recurse) {
1050 const SV *thing = orig_thing;
1051 dNPathNodes(3, NPathArg);
1054 if(!check_new(st, orig_thing))
1057 type = SvTYPE(thing);
1058 if (type > SVt_LAST) {
1059 warn("Devel::Size: Unknown variable type: %d encountered\n", type);
1062 NPathPushNode(thing, NPtype_SV);
1063 ADD_SIZE(st, "sv_head", sizeof(SV));
1064 ADD_SIZE(st, "sv_body", body_sizes[type]);
1067 #if (PERL_VERSION < 11)
1068 /* Is it a reference? */
1073 if(recurse && SvROK(thing)) /* XXX maybe don't follow weakrefs */
1074 sv_size(aTHX_ st, (SvWEAKREF(thing) ? NPathLink("weakRV") : NPathLink("RV")), SvRV_const(thing), recurse);
1078 /* Is there anything in the array? */
1079 if (AvMAX(thing) != -1) {
1080 /* an array with 10 slots has AvMax() set to 9 - te 2007-04-22 */
1081 ADD_SIZE(st, "av_max", sizeof(SV *) * (AvMAX(thing) + 1));
1082 dbg_printf(("total_size: %li AvMAX: %li av_len: $i\n", st->total_size, AvMAX(thing), av_len((AV*)thing)));
1084 if (recurse >= st->min_recurse_threshold) {
1085 SSize_t i = AvFILLp(thing) + 1;
1088 if (sv_size(aTHX_ st, NPathLink("AVelem"), AvARRAY(thing)[i], recurse))
1089 ADD_LINK_ATTR(st, NPattr_NOTE, "i", i);
1093 /* Add in the bits on the other side of the beginning */
1095 dbg_printf(("total_size %li, sizeof(SV *) %li, AvARRAY(thing) %li, AvALLOC(thing)%li , sizeof(ptr) %li \n",
1096 st->total_size, sizeof(SV*), AvARRAY(thing), AvALLOC(thing), sizeof( thing )));
1098 /* under Perl 5.8.8 64bit threading, AvARRAY(thing) was a pointer while AvALLOC was 0,
1099 resulting in grossly overstated sized for arrays. Technically, this shouldn't happen... */
1100 if (AvALLOC(thing) != 0) {
1101 ADD_SIZE(st, "AvALLOC", (sizeof(SV *) * (AvARRAY(thing) - AvALLOC(thing))));
1103 #if (PERL_VERSION < 9)
1104 /* Is there something hanging off the arylen element?
1105 Post 5.9.something this is stored in magic, so will be found there,
1106 and Perl_av_arylen_p() takes a non-const AV*, hence compilers rightly
1107 complain about AvARYLEN() passing thing to it. */
1108 sv_size(aTHX_ st, NPathLink("ARYLEN"), AvARYLEN(thing), recurse);
1113 /* Now the array of buckets */
1114 if (HvENAME(thing)) {
1115 ADD_ATTR(st, NPattr_NAME, HvENAME(thing), 0);
1117 ADD_SIZE(st, "hv_max", (sizeof(HE *) * (HvMAX(thing) + 1)));
1118 /* Now walk the bucket chain */
1119 if (HvARRAY(thing)) {
1123 for (cur_bucket = 0; cur_bucket <= HvMAX(thing); cur_bucket++) {
1124 cur_entry = *(HvARRAY(thing) + cur_bucket);
1126 NPathPushNode("he", NPtype_LINK);
1127 NPathPushNode("he+hek", NPtype_NAME);
1128 ADD_SIZE(st, "he", sizeof(HE));
1129 hek_size(aTHX_ st, cur_entry->hent_hek, HvSHAREKEYS(thing), NPathLink("hent_hek"));
1130 if (recurse >= st->min_recurse_threshold) {
1131 if (orig_thing == (SV*)PL_strtab) {
1132 /* For PL_strtab the HeVAL is used as a refcnt */
1133 ADD_SIZE(st, "shared_hek", HeKLEN(cur_entry));
1136 /* I've seen a PL_strtab HeVAL == 0xC and 0x40C etc
1137 * just running perl -Mblib -Mstrict -MDevel::Size=:all -MCarp -e 'warn perl_size()'
1138 * but it seemed like a corruption - it would change come and go with irrelevant code changes.
1139 * so we protect against that here, but I'd like to know the cause.
1141 if (PTR2UV(HeVAL(cur_entry)) > 0xFFF)
1142 sv_size(aTHX_ st, NPathLink("HeVAL"), HeVAL(cur_entry), recurse);
1143 else warn("skipped suspect HeVAL %p", HeVAL(cur_entry));
1146 cur_entry = cur_entry->hent_next;
1150 } /* bucket chain */
1155 /* This direct access is arguably "naughty": */
1156 struct mro_meta *meta = HvAUX(thing)->xhv_mro_meta;
1157 #if PERL_VERSION > 13 || PERL_SUBVERSION > 8 /* XXX plain || seems like a bug */
1159 I32 count = HvAUX(thing)->xhv_name_count;
1162 HEK **names = HvAUX(thing)->xhv_name_u.xhvnameu_names;
1166 hek_size(aTHX_ st, names[count], 1, NPathLink("HvAUXelem"));
1171 hek_size(aTHX_ st, HvNAME_HEK(thing), 1, NPathLink("HvNAME_HEK"));
1174 ADD_SIZE(st, "xpvhv_aux", sizeof(struct xpvhv_aux));
1176 ADD_SIZE(st, "mro_meta", sizeof(struct mro_meta));
1177 sv_size(aTHX_ st, NPathLink("mro_nextmethod"), (SV *)meta->mro_nextmethod, TOTAL_SIZE_RECURSION);
1178 #if PERL_VERSION > 10 || (PERL_VERSION == 10 && PERL_SUBVERSION > 0)
1179 sv_size(aTHX_ st, NPathLink("isa"), (SV *)meta->isa, TOTAL_SIZE_RECURSION);
1181 #if PERL_VERSION > 10
1182 sv_size(aTHX_ st, NPathLink("mro_linear_all"), (SV *)meta->mro_linear_all, TOTAL_SIZE_RECURSION);
1183 sv_size(aTHX_ st, NPathLink("mro_linear_current"), meta->mro_linear_current, TOTAL_SIZE_RECURSION);
1185 sv_size(aTHX_ st, NPathLink("mro_linear_dfs"), (SV *)meta->mro_linear_dfs, TOTAL_SIZE_RECURSION);
1186 sv_size(aTHX_ st, NPathLink("mro_linear_c3"), (SV *)meta->mro_linear_c3, TOTAL_SIZE_RECURSION);
1191 check_new_and_strlen(st, HvNAME_get(thing), NPathLink("HvNAME"));
1197 padlist_size(aTHX_ st, NPathLink("CvPADLIST"), CvPADLIST(thing), recurse);
1198 sv_size(aTHX_ st, NPathLink("CvOUTSIDE"), (SV *)CvOUTSIDE(thing), SOME_RECURSION);
1200 if (st->go_yell && !st->fm_whine) {
1201 carp("Devel::Size: Calculated sizes for FMs are incomplete");
1207 /* not CvSTASH, per https://rt.cpan.org/Ticket/Display.html?id=79366 */
1208 ADD_ATTR(st, NPattr_NAME, CvGV(thing) ? GvNAME(CvGV(thing)) : "UNDEFINED", 0);
1209 sv_size(aTHX_ st, NPathLink("SvSTASH"), (SV *)SvSTASH(thing), SOME_RECURSION);
1210 sv_size(aTHX_ st, NPathLink("CvGV"), (SV *)CvGV(thing), SOME_RECURSION);
1211 padlist_size(aTHX_ st, NPathLink("CvPADLIST"), CvPADLIST(thing), recurse);
1212 sv_size(aTHX_ st, NPathLink("CvOUTSIDE"), (SV *)CvOUTSIDE(thing), SOME_RECURSION);
1213 if (CvISXSUB(thing)) {
1214 sv_size(aTHX_ st, NPathLink("cv_const_sv"), cv_const_sv((CV *)thing), recurse);
1216 if(1)op_size(aTHX_ CvSTART(thing), st, NPathLinkAndNode("CvSTART", "OPs")); /* XXX ? */
1217 op_size(aTHX_ CvROOT(thing), st, NPathLinkAndNode("CvROOT", "OPs"));
1222 /* Some embedded char pointers */
1223 check_new_and_strlen(st, ((XPVIO *) SvANY(thing))->xio_top_name, NPathLink("xio_top_name"));
1224 check_new_and_strlen(st, ((XPVIO *) SvANY(thing))->xio_fmt_name, NPathLink("xio_fmt_name"));
1225 check_new_and_strlen(st, ((XPVIO *) SvANY(thing))->xio_bottom_name, NPathLink("xio_bottom_name"));
1226 /* Throw the GVs on the list to be walked if they're not-null */
1227 sv_size(aTHX_ st, NPathLink("xio_top_gv"), (SV *)((XPVIO *) SvANY(thing))->xio_top_gv, recurse);
1228 sv_size(aTHX_ st, NPathLink("xio_bottom_gv"), (SV *)((XPVIO *) SvANY(thing))->xio_bottom_gv, recurse);
1229 sv_size(aTHX_ st, NPathLink("xio_fmt_gv"), (SV *)((XPVIO *) SvANY(thing))->xio_fmt_gv, recurse);
1231 /* Only go trotting through the IO structures if they're really
1232 trottable. If USE_PERLIO is defined we can do this. If
1233 not... we can't, so we don't even try */
1235 /* Dig into xio_ifp and xio_ofp here */
1236 warn("Devel::Size: Can't size up perlio layers yet\n");
1241 #if (PERL_VERSION < 9)
1246 if(isGV_with_GP(thing)) {
1248 hek_size(aTHX_ st, GvNAME_HEK(thing), 1, NPathLink("GvNAME_HEK"));
1250 ADD_SIZE(st, "GvNAMELEN", GvNAMELEN(thing));
1252 ADD_ATTR(st, NPattr_NAME, GvNAME_get(thing), 0);
1254 hek_size(aTHX_ st, GvFILE_HEK(thing), 1, NPathLink("GvFILE_HEK"));
1255 #elif defined(GvFILE)
1256 # if !defined(USE_ITHREADS) || (PERL_VERSION > 8 || (PERL_VERSION == 8 && PERL_SUBVERSION > 8))
1257 /* With itreads, before 5.8.9, this can end up pointing to freed memory
1258 if the GV was created in an eval, as GvFILE() points to CopFILE(),
1259 and the relevant COP has been freed on scope cleanup after the eval.
1260 5.8.9 adds a binary compatible fudge that catches the vast majority
1261 of cases. 5.9.something added a proper fix, by converting the GP to
1262 use a shared hash key (porperly reference counted), instead of a
1263 char * (owned by who knows? possibly no-one now) */
1264 check_new_and_strlen(st, GvFILE(thing), NPathLink("GvFILE"));
1267 /* Is there something hanging off the glob? */
1268 if (check_new(st, GvGP(thing))) {
1269 ADD_SIZE(st, "GP", sizeof(GP));
1270 sv_size(aTHX_ st, NPathLink("gp_sv"), (SV *)(GvGP(thing)->gp_sv), recurse);
1271 sv_size(aTHX_ st, NPathLink("gp_av"), (SV *)(GvGP(thing)->gp_av), recurse);
1272 sv_size(aTHX_ st, NPathLink("gp_hv"), (SV *)(GvGP(thing)->gp_hv), recurse);
1273 sv_size(aTHX_ st, NPathLink("gp_cv"), (SV *)(GvGP(thing)->gp_cv), recurse);
1274 sv_size(aTHX_ st, NPathLink("gp_egv"), (SV *)(GvGP(thing)->gp_egv), recurse);
1275 sv_size(aTHX_ st, NPathLink("gp_form"), (SV *)(GvGP(thing)->gp_form), recurse);
1277 #if (PERL_VERSION >= 9)
1281 #if PERL_VERSION <= 8
1289 if(recurse && SvROK(thing))
1290 sv_size(aTHX_ st, NPathLink("RV"), SvRV_const(thing), recurse);
1291 else if (SvIsCOW_shared_hash(thing))
1292 hek_size(aTHX_ st, SvSHARED_HEK_FROM_PV(SvPVX(thing)), 1, NPathLink("SvSHARED_HEK_FROM_PV"));
1294 ADD_SIZE(st, "SvLEN", SvLEN(thing));
1298 SvOOK_offset(thing, len);
1299 ADD_SIZE(st, "SvOOK", len);
1305 if (type >= SVt_PVMG) {
1306 magic_size(aTHX_ thing, st, NPathLink("MG"));
1313 free_memnode_state(pTHX_ struct state *st)
1315 if (st->node_stream_fh && st->node_stream_name && *st->node_stream_name) {
1316 fprintf(st->node_stream_fh, "E %d %f %s\n",
1317 getpid(), gettimeofday_nv()-st->start_time_nv, "unnamed");
1318 if (*st->node_stream_name == '|') {
1319 if (pclose(st->node_stream_fh))
1320 warn("%s exited with an error status\n", st->node_stream_name);
1323 if (fclose(st->node_stream_fh))
1324 warn("Error closing %s: %s\n", st->node_stream_name, strerror(errno));
1329 static struct state *
1335 Newxz(st, 1, struct state);
1337 st->min_recurse_threshold = TOTAL_SIZE_RECURSION;
1338 if (NULL != (warn_flag = perl_get_sv("Devel::Size::warn", FALSE))) {
1339 st->dangle_whine = st->go_yell = SvIV(warn_flag) ? TRUE : FALSE;
1341 if (NULL != (warn_flag = perl_get_sv("Devel::Size::dangle", FALSE))) {
1342 st->dangle_whine = SvIV(warn_flag) ? TRUE : FALSE;
1344 st->start_time_nv = gettimeofday_nv();
1345 check_new(st, &PL_sv_undef);
1346 check_new(st, &PL_sv_no);
1347 check_new(st, &PL_sv_yes);
1348 #if PERL_VERSION > 8 || (PERL_VERSION == 8 && PERL_SUBVERSION > 0)
1349 check_new(st, &PL_sv_placeholder);
1352 #ifdef PATH_TRACKING
1353 /* XXX quick hack */
1354 st->node_stream_name = getenv("SIZEME");
1355 if (st->node_stream_name) {
1356 if (*st->node_stream_name) {
1357 if (*st->node_stream_name == '|')
1358 st->node_stream_fh = popen(st->node_stream_name+1, "w");
1360 st->node_stream_fh = fopen(st->node_stream_name, "wb");
1361 if (!st->node_stream_fh)
1362 croak("Can't open '%s' for writing: %s", st->node_stream_name, strerror(errno));
1363 if(0)setlinebuf(st->node_stream_fh); /* XXX temporary for debugging */
1364 st->add_attr_cb = np_stream_node_path_info;
1365 fprintf(st->node_stream_fh, "S %d %f %s\n",
1366 getpid(), st->start_time_nv, "unnamed");
1369 st->add_attr_cb = np_dump_node_path_info;
1371 st->free_state_cb = free_memnode_state;
1377 /* XXX based on S_visit() in sv.c */
1379 unseen_sv_size(pTHX_ struct state *st, pPATH)
1384 dNPathNodes(1, NPathArg);
1386 NPathPushNode("unseen", NPtype_NAME);
1388 /* by this point we should have visited all the SVs
1389 * so now we'll run through all the SVs via the arenas
1390 * in order to find any thet we've missed for some reason.
1391 * Once the rest of the code is finding all the SVs then any
1392 * found here will be leaks.
1394 for (sva = PL_sv_arenaroot; sva; sva = MUTABLE_SV(SvANY(sva))) {
1395 const SV * const svend = &sva[SvREFCNT(sva)];
1397 for (sv = sva + 1; sv < svend; ++sv) {
1398 if (SvTYPE(sv) != (svtype)SVTYPEMASK && SvREFCNT(sv)) {
1399 sv_size(aTHX_ st, NPathLink("arena"), sv, TOTAL_SIZE_RECURSION);
1401 else if (check_new(st, sv)) { /* sanity check */
1403 warn("unseen_sv_size encountered freed SV unexpectedly"); /* XXX warn uses an SV, I think */
1410 perl_size(pTHX_ struct state *const st, pPATH)
1412 dNPathNodes(3, NPathArg);
1414 /* if(!check_new(st, interp)) return; */
1415 NPathPushNode("perl", NPtype_NAME);
1421 * unknown <== = O/S Heap size - perl - free_malloc_space
1423 /* start with PL_defstash to get everything reachable from \%main:: */
1424 sv_size(aTHX_ st, NPathLink("PL_defstash"), (SV*)PL_defstash, TOTAL_SIZE_RECURSION);
1426 NPathPushNode("others", NPtype_NAME); /* group these (typically much smaller) items */
1427 sv_size(aTHX_ st, NPathLink("PL_defgv"), (SV*)PL_defgv, TOTAL_SIZE_RECURSION);
1428 sv_size(aTHX_ st, NPathLink("PL_incgv"), (SV*)PL_incgv, TOTAL_SIZE_RECURSION);
1429 sv_size(aTHX_ st, NPathLink("PL_rs"), (SV*)PL_rs, TOTAL_SIZE_RECURSION);
1430 sv_size(aTHX_ st, NPathLink("PL_fdpid"), (SV*)PL_fdpid, TOTAL_SIZE_RECURSION);
1431 sv_size(aTHX_ st, NPathLink("PL_modglobal"), (SV*)PL_modglobal, TOTAL_SIZE_RECURSION);
1432 sv_size(aTHX_ st, NPathLink("PL_errors"), (SV*)PL_errors, TOTAL_SIZE_RECURSION);
1433 sv_size(aTHX_ st, NPathLink("PL_stashcache"), (SV*)PL_stashcache, TOTAL_SIZE_RECURSION);
1434 sv_size(aTHX_ st, NPathLink("PL_patchlevel"), (SV*)PL_patchlevel, TOTAL_SIZE_RECURSION);
1435 sv_size(aTHX_ st, NPathLink("PL_apiversion"), (SV*)PL_apiversion, TOTAL_SIZE_RECURSION);
1436 sv_size(aTHX_ st, NPathLink("PL_registered_mros"), (SV*)PL_registered_mros, TOTAL_SIZE_RECURSION);
1438 sv_size(aTHX_ st, NPathLink("PL_regex_padav"), (SV*)PL_regex_padav, TOTAL_SIZE_RECURSION);
1440 sv_size(aTHX_ st, NPathLink("PL_warnhook"), (SV*)PL_warnhook, TOTAL_SIZE_RECURSION);
1441 sv_size(aTHX_ st, NPathLink("PL_diehook"), (SV*)PL_diehook, TOTAL_SIZE_RECURSION);
1442 sv_size(aTHX_ st, NPathLink("PL_endav"), (SV*)PL_endav, TOTAL_SIZE_RECURSION);
1443 sv_size(aTHX_ st, NPathLink("PL_main_cv"), (SV*)PL_main_cv, TOTAL_SIZE_RECURSION);
1444 sv_size(aTHX_ st, NPathLink("PL_main_root"), (SV*)PL_main_root, TOTAL_SIZE_RECURSION);
1445 sv_size(aTHX_ st, NPathLink("PL_main_start"), (SV*)PL_main_start, TOTAL_SIZE_RECURSION);
1446 /* TODO PL_pidstatus */
1447 /* TODO PL_stashpad */
1448 /* TODO PL_compiling? COP */
1450 /* TODO stacks: cur, main, tmps, mark, scope, save */
1451 /* TODO PL_exitlist */
1452 /* TODO PL_reentrant_buffers etc */
1454 /* TODO PerlIO? PL_known_layers PL_def_layerlist PL_perlio_fd_refcnt etc */
1456 /* TODO anything missed? */
1458 /* --- by this point we should have seen all reachable SVs --- */
1460 /* in theory we shouldn't have any elements in PL_strtab that haven't been seen yet */
1461 sv_size(aTHX_ st, NPathLink("PL_strtab-unseen"), (SV*)PL_strtab, TOTAL_SIZE_RECURSION);
1463 /* unused space in sv head arenas */
1467 # define SvARENA_CHAIN(sv) SvANY(sv) /* XXX breaks encapsulation*/
1468 while ((p = MUTABLE_SV(SvARENA_CHAIN(p)))) {
1469 if (!check_new(st, p)) /* sanity check */
1470 warn("Free'd SV head unexpectedly already seen");
1473 NPathPushNode("unused_sv_heads", NPtype_NAME);
1474 ADD_SIZE(st, "sv", free_heads * sizeof(SV));
1477 /* XXX iterate over bodies_by_type and crawl the free chains for each */
1479 /* iterate over all SVs to find any we've not accounted for yet */
1480 /* once the code above is visiting all SVs, any found here have been leaked */
1481 unseen_sv_size(aTHX_ st, NPathLink("unaccounted"));
1485 MODULE = Devel::SizeMe PACKAGE = Devel::SizeMe
1493 total_size = TOTAL_SIZE_RECURSION
1496 SV *thing = orig_thing;
1497 struct state *st = new_state(aTHX);
1499 /* If they passed us a reference then dereference it. This is the
1500 only way we can check the sizes of arrays and hashes */
1502 thing = SvRV(thing);
1505 sv_size(aTHX_ st, NULL, thing, ix);
1506 RETVAL = st->total_size;
1516 /* just the current perl interpreter */
1517 struct state *st = new_state(aTHX);
1518 st->min_recurse_threshold = NO_RECURSION; /* so always recurse */
1519 perl_size(aTHX_ st, NULL);
1520 RETVAL = st->total_size;
1530 /* the current perl interpreter plus malloc, in the context of total heap size */
1531 # ifdef _MALLOC_MALLOC_H_ /* OSX. Now sure where else mstats is available */
1535 /* some systems have the SVID2/XPG mallinfo structure and function */
1536 struct mstats ms = mstats(); /* mstats() first */
1538 struct state *st = new_state(aTHX);
1539 dNPathNodes(1, NULL);
1540 NPathPushNode("heap", NPtype_NAME);
1542 st->min_recurse_threshold = NO_RECURSION; /* so always recurse */
1544 perl_size(aTHX_ st, NPathLink("perl_interp"));
1546 NPathSetNode("free_malloc_space", NPtype_NAME);
1547 ADD_SIZE(st, "bytes_free", ms.bytes_free);
1548 ADD_ATTR(st, NPattr_NOTE, "bytes_total", ms.bytes_total);
1549 ADD_ATTR(st, NPattr_NOTE, "bytes_used", ms.bytes_used);
1550 ADD_ATTR(st, NPattr_NOTE, "chunks_used", ms.chunks_used);
1551 ADD_ATTR(st, NPattr_NOTE, "chunks_free", ms.chunks_free);
1552 /* TODO get heap size from OS and add a node: unknown = heapsize - perl - ms.bytes_free */
1553 /* for now we use bytes_total as an approximation */
1554 NPathSetNode("unknown", NPtype_NAME);
1555 ADD_SIZE(st, "unknown", ms.bytes_total - st->total_size);
1560 RETVAL = st->total_size;