X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=Size.xs;h=3d056744eedbe5ec1a782592dc51ca62b5b2c6c8;hb=36a03132a717b527fd69cae5e04964696a086b1f;hp=1de7568be071ea3aa3e9a181242e6436c64af454;hpb=336fdadd2abc1276722306353bb6b90c473e6ce7;p=p5sagit%2FDevel-Size.git diff --git a/Size.xs b/Size.xs index 1de7568..3d05674 100644 --- a/Size.xs +++ b/Size.xs @@ -152,12 +152,18 @@ struct state { #define NPtype_MAGIC 0x04 #define NPtype_OP 0x05 +/* XXX these should probably be generalizes into flag bits */ #define NPattr_LEAFSIZE 0x00 #define NPattr_NAME 0x01 #define NPattr_PADFAKE 0x02 #define NPattr_PADNAME 0x03 #define NPattr_PADTMP 0x04 #define NPattr_NOTE 0x05 +#define NPattr_PRE_ATTR 0x06 + +#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)) +#define ADD_ATTR(st, attr_type, attr_name, attr_value) _ADD_ATTR_NP(st, attr_type, attr_name, attr_value, NP-1) +#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)) #define _NPathLink(np, nid, ntype) (((np)->id=nid), ((np)->type=ntype), ((np)->seqn=0)) #define NPathLink(nid) (_NPathLink(NP, nid, NPtype_LINK), NP) @@ -165,7 +171,6 @@ struct state { #define NPathLinkAndNode(nid, nid2) (_NPathLink(NP, nid, NPtype_LINK), _NPathLink(NP+1, nid2, NPtype_NAME), ((NP+1)->prev=NP), (NP+1)) #define NPathOpLink (NPathArg) #define NPathAddSizeCb(st, name, bytes) (st->add_attr_cb && st->add_attr_cb(st, NP-1, NPattr_LEAFSIZE, (name), (bytes))), -#define ADD_ATTR(st, attr_type, attr_name, attr_value) (st->add_attr_cb && st->add_attr_cb(st, NP-1, attr_type, attr_name, attr_value)) #else @@ -621,6 +626,17 @@ magic_size(pTHX_ const SV * const thing, struct state *st, pPATH) { dNPathNodes(1, NPathArg); MAGIC *magic_pointer = SvMAGIC(thing); + if (!magic_pointer) + return; + + if (!SvMAGICAL(thing)) { + if (0) { + warn("Ignoring suspect magic on this SV\n"); + sv_dump((SV*)thing); + } + return; + } + /* push a dummy node for NPathSetNode to update inside the while loop */ NPathPushNode("dummy", NPtype_NAME); @@ -636,6 +652,7 @@ magic_size(pTHX_ const SV * const thing, struct state *st, pPATH) { TRY_TO_CATCH_SEGV { + /* XXX only chase mg_obj if mg->mg_flags & MGf_REFCOUNTED ? */ sv_size(aTHX_ st, NPathLink("mg_obj"), magic_pointer->mg_obj, TOTAL_SIZE_RECURSION); if (magic_pointer->mg_len == HEf_SVKEY) { sv_size(aTHX_ st, NPathLink("mg_ptr"), (SV *)magic_pointer->mg_ptr, TOTAL_SIZE_RECURSION); @@ -647,7 +664,9 @@ magic_size(pTHX_ const SV * const thing, struct state *st, pPATH) { } } #endif + /* XXX also handle mg->mg_type == PERL_MAGIC_utf8 ? */ else if (magic_pointer->mg_len > 0) { + if(0)do_magic_dump(0, Perl_debug_log, magic_pointer, 0, 0, FALSE, 0); if (check_new(st, magic_pointer->mg_ptr)) { ADD_SIZE(st, "mg_len", magic_pointer->mg_len); } @@ -808,7 +827,8 @@ op_size(pTHX_ const OP * const baseop, struct state *st, pPATH) check_new_and_strlen(st, basecop->cop_file, NPathLink("cop_file")); check_new_and_strlen(st, basecop->cop_stashpv, NPathLink("cop_stashpv")); #else - sv_size(aTHX_ st, NPathLink("cop_stash"), (SV *)basecop->cop_stash, SOME_RECURSION); + if (SvREFCNT(basecop->cop_stash) == 1) /* XXX hack? */ + sv_size(aTHX_ st, NPathLink("cop_stash"), (SV *)basecop->cop_stash, SOME_RECURSION); sv_size(aTHX_ st, NPathLink("cop_filegv"), (SV *)basecop->cop_filegv, SOME_RECURSION); #endif @@ -962,9 +982,11 @@ padlist_size(pTHX_ struct state *const st, pPATH, PADLIST *padlist, SV **pname; I32 ix; - if (!padlist) { + if (!padlist) return; - } + if( 0 && !check_new(st, padlist)) + return; + pad_name = MUTABLE_AV(*av_fetch(MUTABLE_AV(padlist), 0, FALSE)); pname = AvARRAY(pad_name); @@ -974,6 +996,7 @@ padlist_size(pTHX_ struct state *const st, pPATH, PADLIST *padlist, namesv = NULL; } if (namesv) { + /* SvFAKE: On a pad name SV, that slot in the frame AV is a REFCNT'ed reference to a lexical from "outside" */ if (SvFAKE(namesv)) ADD_ATTR(st, NPattr_PADFAKE, SvPVX_const(namesv), ix); else @@ -1006,10 +1029,6 @@ sv_size(pTHX_ struct state *const st, pPATH, const SV * const orig_thing, NPathPushNode(thing, NPtype_SV); ADD_SIZE(st, "sv", sizeof(SV) + body_sizes[type]); - if (type >= SVt_PVMG) { - magic_size(aTHX_ thing, st, NPathLink("MG")); - } - switch (type) { #if (PERL_VERSION < 11) /* Is it a reference? */ @@ -1017,8 +1036,8 @@ sv_size(pTHX_ struct state *const st, pPATH, const SV * const orig_thing, #else case SVt_IV: TAG; #endif - if(recurse && SvROK(thing)) - sv_size(aTHX_ st, NPathLink("RV"), SvRV_const(thing), recurse); + if(recurse && SvROK(thing)) /* XXX maybe don't follow weakrefs */ + sv_size(aTHX_ st, (SvWEAKREF(thing) ? NPathLink("weakRV") : NPathLink("RV")), SvRV_const(thing), recurse); TAG;break; case SVt_PVAV: TAG; @@ -1031,8 +1050,10 @@ sv_size(pTHX_ struct state *const st, pPATH, const SV * const orig_thing, if (recurse >= st->min_recurse_threshold) { SSize_t i = AvFILLp(thing) + 1; - while (i--) + while (i--) { + ADD_PRE_ATTR(st, 0, "index", i); sv_size(aTHX_ st, NPathLink("AVelem"), AvARRAY(thing)[i], recurse); + } } } /* Add in the bits on the other side of the beginning */ @@ -1053,6 +1074,7 @@ sv_size(pTHX_ struct state *const st, pPATH, const SV * const orig_thing, sv_size(aTHX_ st, NPathLink("ARYLEN"), AvARYLEN(thing), recurse); #endif TAG;break; + case SVt_PVHV: TAG; /* Now the array of buckets */ ADD_SIZE(st, "hv_max", (sizeof(HE *) * (HvMAX(thing) + 1))); @@ -1066,6 +1088,7 @@ sv_size(pTHX_ struct state *const st, pPATH, const SV * const orig_thing, for (cur_bucket = 0; cur_bucket <= HvMAX(thing); cur_bucket++) { cur_entry = *(HvARRAY(thing) + cur_bucket); while (cur_entry) { +/* XXX a HE should probably be a node so the keys and values are seen as pairs */ ADD_SIZE(st, "he", sizeof(HE)); hek_size(aTHX_ st, cur_entry->hent_hek, HvSHAREKEYS(thing), NPathLink("hent_hek")); if (recurse >= st->min_recurse_threshold) { @@ -1076,6 +1099,7 @@ sv_size(pTHX_ struct state *const st, pPATH, const SV * const orig_thing, */ if (PTR2UV(HeVAL(cur_entry)) > 0xFFF) sv_size(aTHX_ st, NPathLink("HeVAL"), HeVAL(cur_entry), recurse); +else warn("skipped suspect HeVAL %p", HeVAL(cur_entry)); } cur_entry = cur_entry->hent_next; } @@ -1125,8 +1149,8 @@ if (PTR2UV(HeVAL(cur_entry)) > 0xFFF) case SVt_PVFM: TAG; - padlist_size(aTHX_ st, NPathLink("CvPADLIST"), CvPADLIST(thing), SOME_RECURSION); - sv_size(aTHX_ st, NPathLink("CvOUTSIDE"), (SV *)CvOUTSIDE(thing), recurse); + padlist_size(aTHX_ st, NPathLink("CvPADLIST"), CvPADLIST(thing), recurse); + sv_size(aTHX_ st, NPathLink("CvOUTSIDE"), (SV *)CvOUTSIDE(thing), SOME_RECURSION); if (st->go_yell && !st->fm_whine) { carp("Devel::Size: Calculated sizes for FMs are incomplete"); @@ -1136,10 +1160,11 @@ if (PTR2UV(HeVAL(cur_entry)) > 0xFFF) case SVt_PVCV: TAG; /* not CvSTASH, per https://rt.cpan.org/Ticket/Display.html?id=79366 */ + ADD_ATTR(st, NPattr_NAME, CvGV(thing) ? GvNAME(CvGV(thing)) : "UNDEFINED", 0); sv_size(aTHX_ st, NPathLink("SvSTASH"), (SV *)SvSTASH(thing), SOME_RECURSION); sv_size(aTHX_ st, NPathLink("CvGV"), (SV *)CvGV(thing), SOME_RECURSION); - padlist_size(aTHX_ st, NPathLink("CvPADLIST"), CvPADLIST(thing), SOME_RECURSION); - sv_size(aTHX_ st, NPathLink("CvOUTSIDE"), (SV *)CvOUTSIDE(thing), recurse); + padlist_size(aTHX_ st, NPathLink("CvPADLIST"), CvPADLIST(thing), recurse); + sv_size(aTHX_ st, NPathLink("CvOUTSIDE"), (SV *)CvOUTSIDE(thing), SOME_RECURSION); if (CvISXSUB(thing)) { sv_size(aTHX_ st, NPathLink("cv_const_sv"), cv_const_sv((CV *)thing), recurse); } else { @@ -1198,11 +1223,11 @@ if (PTR2UV(HeVAL(cur_entry)) > 0xFFF) if (check_new(st, GvGP(thing))) { ADD_SIZE(st, "GP", sizeof(GP)); sv_size(aTHX_ st, NPathLink("gp_sv"), (SV *)(GvGP(thing)->gp_sv), recurse); - sv_size(aTHX_ st, NPathLink("gp_form"), (SV *)(GvGP(thing)->gp_form), recurse); sv_size(aTHX_ st, NPathLink("gp_av"), (SV *)(GvGP(thing)->gp_av), recurse); sv_size(aTHX_ st, NPathLink("gp_hv"), (SV *)(GvGP(thing)->gp_hv), recurse); - sv_size(aTHX_ st, NPathLink("gp_egv"), (SV *)(GvGP(thing)->gp_egv), recurse); sv_size(aTHX_ st, NPathLink("gp_cv"), (SV *)(GvGP(thing)->gp_cv), recurse); + sv_size(aTHX_ st, NPathLink("gp_egv"), (SV *)(GvGP(thing)->gp_egv), recurse); + sv_size(aTHX_ st, NPathLink("gp_form"), (SV *)(GvGP(thing)->gp_form), recurse); } #if (PERL_VERSION >= 9) TAG; break; @@ -1231,6 +1256,11 @@ if (PTR2UV(HeVAL(cur_entry)) > 0xFFF) TAG;break; } + + if (type >= SVt_PVMG) { + magic_size(aTHX_ thing, st, NPathLink("MG")); + } + return; } @@ -1271,14 +1301,15 @@ new_state(pTHX) check_new(st, &PL_sv_placeholder); #endif #ifdef PATH_TRACKING - if (getenv("MEMNODES") && *getenv("MEMNODES")) { /* XXX quick hack */ - st->node_stream_name = getenv("MEMNODES"); + if (getenv("MEMVIEW") && *getenv("MEMVIEW")) { /* XXX quick hack */ + st->node_stream_name = getenv("MEMVIEW"); if (*st->node_stream_name == '|') st->node_stream_fh = popen(st->node_stream_name+1, "w"); else st->node_stream_fh = fopen(st->node_stream_name, "wb"); if (!st->node_stream_fh) croak("Can't open '%s' for writing: %s", st->node_stream_name, strerror(errno)); + setlinebuf(st->node_stream_fh); /* XXX temporary for debugging */ st->add_attr_cb = np_stream_node_path_info; } else @@ -1310,7 +1341,7 @@ unseen_sv_size(pTHX_ struct state *st, pPATH) SV* sv; for (sv = sva + 1; sv < svend; ++sv) { if (SvTYPE(sv) != (svtype)SVTYPEMASK && SvREFCNT(sv)) { - sv_size(aTHX_ st, NPathLink(""), sv, TOTAL_SIZE_RECURSION); + sv_size(aTHX_ st, NPathLink("arena"), sv, TOTAL_SIZE_RECURSION); } else if (check_new(st, sv)) { /* sanity check */ warn("unseen_sv_size encountered freed SV unexpectedly");