--------------050401020503090904070402 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Im toying (once again) with the notion of combining op_next and op_sibling into a union, which could save non-trivial memory for optrees. A naive estimate is 20% Its not clear what the value of this savings is - theres generally a lot less code than data, so the total memory saved may not be worth fussing for. OTOH, maybe mod-perl servers could materially benefit. If you have a use-case where code-memory savings could matter, please say so. Im just scratching an itch, but I'll be damned if Im gonna create a rash. * optrees are created using op-siblings to tie the OPs together, so op-siblings are integral to this. * Perl_linklist traverses this 'syntax' tree, and sets op-next pointers to give the execution order for that optree. op-sibling pointers are basically unneeded after that. * I just lied - theyre needed for uninit-var chasing, and perhaps other things. But - theyre rarely needed, and could be fetched from elsewhere. Further, the cost of that fetch is nearly irrelevant, since its an error-reporting / diagnostic feature. Anyway, the 1st patch in this series is pretty straightforward, the interesting bits are here: (patch is compressed, cuz its ~ 90k otherwize) diff -ruNp -X exclude-diffs ../bleadperl/op.h ns-abstract/op.h --- ../bleadperl/op.h 2006-08-31 03:10:53.000000000 -0600 +++ ns-abstract/op.h 2006-09-02 10:40:17.000000000 -0600 @@ -46,19 +46,63 @@ #define BASEOP BASEOP_DEFINITION #else #define BASEOP \ - OP* op_next; \ - OP* op_sibling; \ + OP_NEXT_SIBL_REP \ OP* (CPERLscope(*op_ppaddr))(pTHX); \ MADPROP_IN_BASEOP \ PADOFFSET op_targ; \ unsigned op_type:9; \ unsigned op_opt:1; \ unsigned op_static:1; \ - unsigned op_spare:5; \ + unsigned op_nextset:1; \ + unsigned op_spare:4; \ U8 op_flags; \ U8 op_private; #endif +#ifndef OP_NEXT_SIBL_IMP +#define OP_NEXT_SIBL_IMP 0 /* override with -Accflags */ +#endif + +#if (OP_NEXT_SIBL_IMP == 0) /* original formulation */ + +# define OP_NEXT_SIBL_REP \ + OP* op_next; \ + OP* op_sibling; + +# define PERL_OP_NEXT(o) (o)->op_next +# define PERL_OP_SIBLING(o) (o)->op_sibling +# define PERL_OP_SETNEXT(o,what) ((o)->op_next) = (what) +# define PERL_OP_SETSIBLING(o,what) ((o)->op_sibling) = (what) +# define PERL_OP_SIBLING_ADDR(o) &((o)->op_sibling) + +#else /* nested struct/union op rep */ + +#if (OP_NEXT_SIBL_IMP == 1) /* nested struct op rep */ + +# define OP_NEXT_SIBL_REP \ + struct { \ + OP* next; \ + OP* sibling; \ + } op; + +#elif (OP_NEXT_SIBL_IMP == 2) /* nested union op rep */ + +# define OP_NEXT_SIBL_REP \ + union { \ + OP* next; \ + OP* sibling; \ + } op; +#endif + +# define PERL_OP_NEXT(o) (o)->op.next +# define PERL_OP_SIBLING(o) (o)->op.sibling +# define PERL_OP_SETNEXT(o,what) ((o)->op.next) = (what) +# define PERL_OP_SETSIBLING(o,what) ((o)->op.sibling) = (what) +# define PERL_OP_SIBLING_ADDR(o) &((o)->op.sibling) + +#endif + + #define OP_GIMME(op,dfl) \ Depending on the value of *OP_NEXT_SIBL_IMP*, we get 0 - original code 1 - a sub-struct op {OP* next, sibling} 2 - a sub-union along with 4 macros which hide those variations. ( building both 0,1 uses the compiler to prove that abstraction is complete ) Configure -des ... -Accflags="-DOP_NEXT_SIBL_IMP=1" With patch applied, bleadperl builds fine and tests pretty good for both 0 and 1; 2 failures; ext/B/t/bytecode.....................................FAILED at test 1 ext/B/t/concise......................................ok ext/B/t/concise-xs...................................# Looks like you planned 1588 tests but ran 1 extra. FAILED--expected 1588 tests, saw 1589 concise-xs.t (trivial, due to extra B constant inadvertently created (probly some patch cruft)) bytecode I dont get this one.. tested verbosely, it gets SEGV. I think its fixable, but Im looking ahead ATM. WRT the RARELY NEEDED bits .. (heres where it gets tricky/speculative) it should be possible to: - collect op-siblings in Perl-linklist, stuff them into temporary storage Im trying to use PTR_TBL code, exported from sv.c, this seems non-interfering, since its compile-time, whereas the threads use of that table is run-time. (speculating;-) IIRC, I tried to stuff the data directly into PL_compiling, but couldnt convince myself that it was workable ( recollection of confusion is all that remains ) - catch COPs in Perl-linklist, at which point (I hope) the op-next chain is complete for that statement, and could be walked. So, walk the chain, and lookup the sibling for each that was previously collected (we'd also delete those entries). - attach the collected siblings to the COP (with a newly added field) Im envisioning an array, with siblings stored at indexes corresponding to the walk-steps Im stuck somewhere in the middle of the above, and could use some advice .. Continuing on speculative path ( we have to get further for the above to be valuable) - with sibling info stored off the COP, it should be possible to fix find_uninit_var() to get the sibling data it needs, assuming that closest_cop will work there (no obvious reason it shouldnt) There look to be 5 calls to PERL_OP_SIBLING that need to be replaced. [jimc@harpo ns-cop-sibl]$ egrep -n 'OP_SIBLING|find_uninit_var' sv.c 11855:=for apidoc find_uninit_var 11875:S_find_uninit_var(pTHX_ OP* obase, SV* uninit_sv, bool match) 11913: return find_uninit_var(cUNOPx(obase)->op_first, 11985: return find_uninit_var(cBINOPo->op_last, uninit_sv, match); 11991: return find_uninit_var(cBINOPx(obase)->op_last, uninit_sv, match); 12062: return find_uninit_var(cBINOPx(obase)->op_first, uninit_sv, match); 12067: o = PERL_OP_SIBLING(o); 12069: if (!PERL_OP_SIBLING(o)) { 12108: o = PERL_OP_SIBLING(PERL_OP_SIBLING(o)); 12137: for (kid=o; kid; kid = PERL_OP_SIBLING(kid)) { 12153: return find_uninit_var(o2, uninit_sv, match); 12157: sv = find_uninit_var(o, uninit_sv, 1); 12160: o = PERL_OP_SIBLING(o); 12183: varname = find_uninit_var(PL_op, uninit_sv,0); I for one would find a lot of guidance/value if someone knowledgeable would add a handful of assertions which would document the subtle invariants buried in the optrees. op_assert( o->op_sibling == o) op_assert( o->op_next == o) This occurs a lot. its also counterintuitive. Id expect some of the properties thus exposed to be representable by flags (or some small set of states), with the useful ones reserved out of OP's spare-bits Once siblings are out of OP (and reachable via the relevant COP), further optimizations might be possible, but I'll refrain from too much more speculation. The 2nd patch hacks at Perl_linklist, adding printfs, and yielding this: [jimc@harpo ns-cop-sibling]$ ./perl -Ilib -e 'print"foo",$_+2; print"bar",$_-3' 90f3210 add s:0 n:0 90f31d0 rv2sv s:90f31f0 n:0 90f31b0 gv s:0 n:90f31b0 90f31d0 rv2sv s:90f31f0 n:90f31b0 90f31f0 const s:0 n:90f31f0 90f3210 add s:0 n:90f31b0 90f5c00 subtract s:0 n:0 90f5bc0 rv2sv s:90f5be0 n:0 90f5ba0 gv s:0 n:90f5ba0 90f5bc0 rv2sv s:90f5be0 n:90f5ba0 90f5be0 const s:0 n:90f5be0 90f5c00 subtract s:0 n:90f5ba0 90f5ae8 leave s:0 n:0 90f5c90 enter s:90f5ab0 n:90f5c90 COP 90f5ab0 -> 90f3160 print 90f5ab0 nextstate s:90f3160 n:90f5ab0 COP 90f5ab0 -> 90f3160 print 90f3160 print s:90ec070 n:0 90f5a98 pushmark s:90f3190 n:90f5a98 90f3190 const s:90f3210 n:90f3190 90f3210 add s:0 n:90f31b0 90f3160 print s:90ec070 n:90f5a98 COP 90ec070 -> 90ed078 print 90ec070 nextstate s:90ed078 n:90ec070 COP 90ec070 -> 90ed078 print 90ed078 print s:0 n:0 90f5b08 pushmark s:90f5b80 n:90f5b08 90f5b80 const s:90f5c00 n:90f5b80 90f5c00 subtract s:0 n:90f5ba0 90ed078 print s:0 n:90f5b08 90f5ae8 leave s:0 n:90f5c90 if you suppress these prints, the code passes all but the 2 tests id'd above. op_assert( o->op_next == o) This occurs a lot above, I dont get it. Is there another, final step ? Also - its obvious that this could be replaced by a flag NORMAL is o->op_next.. --------------050401020503090904070402 Content-Type: application/gzip; name="diff.ns.abstract-test-ok-99.gz" Content-Transfer-Encoding: base64 Content-Disposition: inline; filename="diff.ns.abstract-test-ok-99.gz" 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 --------------050401020503090904070402 Content-Type: text/plain; name="diff.ns-cop-sibling-proto" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="diff.ns-cop-sibling-proto" diff -ruNp -X exclude-diffs ns-abstract/op.c ns-cop-sibling/op.c --- ns-abstract/op.c 2006-09-04 13:00:26.000000000 -0600 +++ ns-cop-sibling/op.c 2006-09-05 12:29:11.000000000 -0600 @@ -527,17 +527,191 @@ Perl_op_refcnt_unlock(pTHX) OP_REFCNT_UNLOCK; } +/* +=head1 Implementation: out-of-OP op-siblings + +In the bottom up up complier pass, perly.y emits op-twigs, setting +op-type/class specific pointers in each OP to link them together +according to the expression just parsed. Sequences of + +optrees are generated using op_sibling and +represent both sequential and expression dependencies. The execution +order pass relinks the tree of OPs for fast execution, using the +op_next pointer. + +Our premise is that sibling pointers are used rarely after op_next is +set, so, at listlink()-age time, we copy op_sibling to an associative +array, and intercept later reads. This allows us to instrument that +read, find out who is using the value, and optimize later, starting +with removing in-OP storage for the pointer and getting it from the +hash. This shrinks the optree by ~20%, and may have other benefits. + +=head2 Implementation: patch development + + 1.abstract all refs to op_next, op_sibling with macros + . PERL_OP_NEXT, PERL_OP_SIBLING + . PERL_OP_SETNEXT, PERL_OP_SETSIBLING + . set OP_NEXT_SIBL_IMP to 0,1,2: to choose pair, struct, union reps + + 2.extend COP, adding struct OpPair {next; sibl} ops[30] + . populate it in linklist + +This wont work as is; in linklist(), assert(PL_curcop == &PL_compiling), +so theres no COP context + + + 3.compile vs runtime (TBC) + . PERL_OP_SIBLING should call instrumentation + . use IN_PERL_RUNTIME to toggle PERL_OP_SIBLING defn + +=head2 Future Optimizations + +At this point (patch 2), the patch increases total memory use, but +we're looking forward to several optimizations: + +1 not all ops have siblings, only those that do get added + +2 we hope that op-shrink, and segregating hot fields from cold, will + improve cache performance, though cache arguably works much better + on C code, and pp_code probably dwarfs the 20% opcode savings. + +3 analysis of the uninit-var feature may reveal that only some ops + need to be hashed to support the reporting for the vars in a given + code block. + +4 we can add a feature to allow the coder to suppress the hashing of + siblings entirely, for use on well-tested code. + +5 OpPair storage can be unioned with op_siblings vector, which its + converted to if/when linklist(op) acts upon COPs. At this point, + the op can be shrunk to fit the op_sibling vector actually needed. + +=cut +*/ + +#if 0 + +/* borrowed verbatim from util.c */ + +STATIC COP* +S_closest_cop(pTHX_ COP *cop, OP *o) +{ + /* Look for PL_op starting from o. cop is the last COP we've seen. */ + + if (!o || o == PL_op) return cop; + + if (o->op_flags & OPf_KIDS) { + OP *kid; + for (kid = cUNOPo->op_first; kid; kid = PERL_OP_SIBLING(kid)) + { + COP *new_cop; + + /* If the OP_NEXTSTATE has been optimised away we can still use it + * the get the file and line number. */ + + if (kid->op_type == OP_NULL && kid->op_targ == OP_NEXTSTATE) + cop = (COP *)kid; + + /* Keep searching, and return when we've found something. */ + + new_cop = S_closest_cop(aTHX_ cop, kid); + if (new_cop) return new_cop; + } + } + + /* Nothing found. */ + + return 0; +} +#endif + +/* during compilation (pre-cop linklist phase), we save sibling + pointers into a global 'hash', then when bottom up linklist-ing + reaches up to the COP, we can sweep those hash entries into + cop-private storage. + + With that data in place, we should be able to find it in the COP, + which allows us to pull it out of the OPs, and save ~20% storage in + the OPs themselves. + + Use of op-sibling ptr is rare once the code is linked for running, + so a higher fetch-cost is mostly irrelevant, since its needed only + to support uninit-var reporting, which is purely a debug-friendly + feature. + + Eventually, we may be able to eliminate the entries that are + representable by a flag instead, forex op->next == op, or some + other knowable (and useful) properties. For some 'production' + situations, where the code-base is well-known, it may be possible + to drop the hash entirely. +*/ + /* Contextualizers */ -#define LINKLIST(o) (PERL_OP_NEXT(o) ? PERL_OP_NEXT(o) : linklist((OP*)o)) +#define LINKLIST(o) Perl_linklist(aTHX_ o) +/* was + #define LINKLIST(o) (PERL_OP_NEXT(o) ? PERL_OP_NEXT(o) : linklist((OP*)o)) + + removing the shortcut means that Perl_linklist sees COPs, which + lets us collect and attach sibling info to the COP, where its + reasonably close at hand for (revamped) uninit-var use. +*/ + +static PTR_TBL_t *siblings; +static char indent[] = " "; +static int ipi = -1; OP * Perl_linklist(pTHX_ OP *o) { OP *first; + COP *cop; + int type; - if (PERL_OP_NEXT(o)) + assert(PL_curcop == &PL_compiling); + + /* + cop = S_closest_cop(aTHX_ PL_curcop, PERL_OP_SIBLING(PL_curcop)); + if ((COP*)o == cop) + PerlIO_printf(Perl_debug_log, "linklist closest cop\n"); + */ + + type = o->op_type; + if (type == OP_NULL) + type = (OPCODE)o->op_targ; + + if (!siblings) siblings = ptr_table_new(); + if (ipi == -1) ipi = strlen(indent)-1; + + if (type == OP_NEXTSTATE || type == OP_SETSTATE || type == OP_DBSTATE) { + PTR_TBL_ENT_t *ent; + OP *next = PERL_OP_SIBLING(o); // next not set yet + /* cop's next points back at itself !! */ + + if (next && 0) + PerlIO_printf(Perl_debug_log, "%s COP %p -> %p %s\n", + indent+ipi, o, next, + PL_op_name[next->op_type]); +#if 0 + for (; next && next != PERL_OP_NEXT(next) && next != o; + next=PERL_OP_NEXT(next)) + { + // follow chain, + ent = ptr_table_fetch(siblings, next); + if (ent && ent->newval == PERL_OP_SIBLING(next)) + PerlIO_printf(Perl_debug_log, "woohoo\n"); + } +#endif + } + if (10) + PerlIO_printf(Perl_debug_log, "%s %p %s s:%p n:%p\n", indent+ipi--, + o, PL_op_name[o->op_type], + PERL_OP_SIBLING(o), PERL_OP_NEXT(o)); + + if (PERL_OP_NEXT(o)) { + ipi++; return PERL_OP_NEXT(o); + } /* establish postfix order */ first = cUNOPo->op_first; @@ -546,7 +720,20 @@ Perl_linklist(pTHX_ OP *o) PERL_OP_SETNEXT(o, LINKLIST(first)); kid = first; for (;;) { + if (PERL_OP_SIBLING(kid)) { + + ptr_table_store(siblings, (SV*)o, PERL_OP_SIBLING(o)); + + /* save op_sibling in COP before setting op_next, + which would overwrite storage if shared/optimized */ + + /* current op entry for siblings + int opincop = cop->opct++; + cop->ops[opincop].sibl = PERL_OP_SIBLING(kid); + cop->ops[opincop].self = kid; + */ + PERL_OP_SETNEXT(kid, LINKLIST(PERL_OP_SIBLING(kid))); kid = PERL_OP_SIBLING(kid); } else { @@ -555,8 +742,15 @@ Perl_linklist(pTHX_ OP *o) } } } - else + else { + ptr_table_store(siblings, (SV*)o, PERL_OP_SIBLING(o)); PERL_OP_SETNEXT(o,o); + } + + if (10) + PerlIO_printf(Perl_debug_log, "%s %p %s s:%p n:%p\n", indent+ipi++, + o, PL_op_name[o->op_type], + PERL_OP_SIBLING(o), PERL_OP_NEXT(o)); return PERL_OP_NEXT(o); } @@ -3346,7 +3540,7 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, bo PERL_OP_SETNEXT(repl, (OP*)rcop); pm->op_pmreplroot = scalar((OP*)rcop); - pm->op_pmreplstart = (OP*) LINKLIST(rcop); + pm->op_pmreplstart = LINKLIST((OP*)rcop); PERL_OP_SETNEXT((OP*)rcop, 0); } } --------------050401020503090904070402--
![]() |
1 |
![]() |
On 9/5/06, Jim Cromie <jim.cromie@gmail.com> wrote: > Im toying (once again) with the notion of combining op_next and op_sibling > into a union, which could save non-trivial memory for optrees. > A naive estimate is 20% Gosh, no replies. Well, from my point of view this adds a lot of complexity for no given reason. Is it actually any better? Leon
![]() |
1 |
![]() |
--------------070701040305010506010003 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Leon Brocard wrote: > On 9/5/06, Jim Cromie <jim.cromie@gmail.com> wrote: > >> Im toying (once again) with the notion of combining op_next and >> op_sibling >> into a union, which could save non-trivial memory for optrees. >> A naive estimate is 20% > > Gosh, no replies. Well, from my point of view this adds a lot of > complexity for no given reason. Is it actually any better? > > Leon > Thanks for responding Leon, Its certainly a fair question, and one Ive been pondering myself. Your question prompted me to look for my own estimate of code-memory size, specifically at process size, b4 and after loading Phalanx100. PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND b4 531 jimc 15 0 9496 5976 1528 S 0.0 1.2 0:00.37 perl after 531 jimc 23 0 100m 90m 4128 S 0.0 17.9 0:06.91 perl Thats 90 MB of growth, enough I think to warrant further discussion. Ive attached my script, hopefully its repeatable. thanks again, jimc --------------070701040305010506010003 Content-Type: application/x-perl; name="usephalanx.pl" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="usephalanx.pl" #!/usr/local/bin/perl -w require Test::Harness; require Test::Reporter; require Test::Tester; require Test::Builder; require Test::Builder::Tester; require Sub::Uplevel; require Test::Exception; require Test::Tester; require Test::NoWarnings; require Test::Tester; require Pod::Escapes; require Pod::Simple; require Test::Pod; require YAML; require Cwd; require Archive::Tar; require Module::Build; require Devel::Symdump; require Pod::Coverage; require Test::Pod::Coverage; require Compress::Zlib; require IO::Zlib; require Archive::Zip; require Archive::Tar; require Storable; require Digest::MD5; require URI; require HTML::Tagset; require HTML::Parser; require LWP; require IPC::Run; require CPANPLUS; require DBI; #require DBD::mysql; require GD; require MIME::Base64; require Net::SSLeay; #require Net::LDAP; require XML::Parser; require Apache::ASP; require CGI; require Date::Manip; #require DBD::Oracle; require DBD::Pg; require Digest::SHA1; require Digest::HMAC; require HTML::Tagset; require HTML::Template; require Net::Cmd; require Mail::Mailer; require MIME::Body; require Net::DNS; require Time::HiRes; require Apache::DBI; require Apache::Session; require Apache::Test; require AppConfig; #require App::Info; require Authen::PAM; require Authen::SASL; require BerkeleyDB; require Bit::Vector; require Carp::Clan; #require Chart::Bars; #require Class::DBI; require Compress::Zlib::Perl; require Config::IniFiles; require Convert::ASN1; #require Convert::TNEF; require Convert::UUlib; require CPAN; require Crypt::CBC; require Crypt::DES; require Crypt::SSLeay; require Data::Dumper; require Date::Calc; require DateTime; #require DBD::DB2; #require DBD::ODBC; require DBD::SQLite; #require DBD::Sybase; #require Device::SerialPort; require Digest::SHA; require Encode; require Event; require Excel::Template; require Expect; require ExtUtils::MakeMaker; require File::Scan; require File::Spec; require File::Tail; require File::Temp; require GD::Graph; require GD::Text; require Getopt::Long; require HTML::Mason; require Image::Size; require IMAP::Admin; require Parse::RecDescent; require Inline; require IO; require Spiffy; require IO::All; require IO::Socket::SSL; #require IO::String; require IO::Stringy; require XML::SAX2Perl; #require Mail::Audit; #require Mail::ClamAV; #require Mail::Sendmail; #require Math::Pari; require Digest::MD5; require MIME::Lite; require MP3::Info; #require Net::Daemon; #require Net::FTP::Common; require Net::Ping; require Net::Server; require Net::SNMP; #require Net::SSH::Perl; require Net::Telnet; #require OLE::Storage_Lite; require Params::Validate; #require Image::Magick; #require RPC::PlServer; require Pod::Parser; require POE; #require SNMP; require SOAP::Lite; require Spreadsheet::ParseExcel; require Spreadsheet::WriteExcel; require Spreadsheet::WriteExcelXML; require Storable; require Template; require Term::ReadKey; #require Term::ReadLine::Perl; require Text::Iconv; require Date::Parse; require Time::Timezone; require Unicode::String; require Unix::Syslog; #require Verilog::Parser; require WWW::Mechanize; require XML::DOM; require XML::Generator; require XML::LibXML; require XML::NamespaceSupport; require XML::SAX; require XML::Simple; require XML::Writer; $DB::single = 1; print "hello world"; $DB::single = 1; --------------070701040305010506010003--
![]() |
1 |
![]() |
On Mon, Sep 11, 2006 at 07:58:30PM -0600, Jim Cromie wrote: > Your question prompted me to look for my own estimate of code-memory size, > specifically at process size, b4 and after loading Phalanx100. > > PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND > b4 > 531 jimc 15 0 9496 5976 1528 S 0.0 1.2 0:00.37 perl > after > 531 jimc 23 0 100m 90m 4128 S 0.0 17.9 0:06.91 perl > > > Thats 90 MB of growth, enough I think to warrant further discussion. > Ive attached my script, hopefully its repeatable. I don't really see what point you are trying to make here. Yes, if you load tons of modules you will use tons of memory. What you haven't shown, is (a) how much does that 100m shrink by if op_sibling and op_next are combined? (b) what proportion of total memory would that 100m be if the modules were actually used in anger - normally you only load modules to use them for something, at which point you're creating lots of SVs atc. -- I've often wanted to drown my troubles, but I can't get my wife to go swimming.
![]() |
0 |
![]() |
Dave Mitchell wrote: > On Mon, Sep 11, 2006 at 07:58:30PM -0600, Jim Cromie wrote: > >> Your question prompted me to look for my own estimate of code-memory size, >> specifically at process size, b4 and after loading Phalanx100. >> >> PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND >> b4 >> 531 jimc 15 0 9496 5976 1528 S 0.0 1.2 0:00.37 perl >> after >> 531 jimc 23 0 100m 90m 4128 S 0.0 17.9 0:06.91 perl >> >> >> Thats 90 MB of growth, enough I think to warrant further discussion. >> Ive attached my script, hopefully its repeatable. >> > > I don't really see what point you are trying to make here. Yes, if you > load tons of modules you will use tons of memory. What you haven't shown, > is > (a) how much does that 100m shrink by if op_sibling and op_next are > combined? > (b) what proportion of total memory would that 100m be if the modules > were actually used in anger - normally you only load modules to use them > for something, at which point you're creating lots of SVs atc. > > a) I cant answer, since Ive not been able to s/struct/union/ and get something working. To demonstrate 20 MB of savings (the 20% WAG), Id have to be further along. You may infer that Im looking for clues, none heard yet :-( b) is a low-effort existential proof. For more reality, substitute a large mod-perl app, with 30 or 40 processes running simultaneously. I dont have such a setup, but surely someone here does, and could run top on the box and send results. Besides, the point was to separate data (which has already been squeezed, thanks NickC) from code, not to give a real-world example. If this is seen as a purely hand-waving non-solution to a non-problem, then Ill look elsewhere for my entertainments. OTOH, If you/someone could look at 2nd patch, and help me understand why the prints I added to Perl_linklist show next == self, I might be able to make some progress towards a). Im resending patches: 1- drops the bytecode bits that were recently dropped from bleadperl. 2- disables the PerlIO_printfs added into Perl_linklist, so that make test passes. thanks
![]() |
0 |
![]() |
--------------030506010206090808080803 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Dave Mitchell wrote: > On Mon, Sep 11, 2006 at 07:58:30PM -0600, Jim Cromie wrote: > >> Your question prompted me to look for my own estimate of code-memory size, >> specifically at process size, b4 and after loading Phalanx100. >> >> PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND >> b4 >> 531 jimc 15 0 9496 5976 1528 S 0.0 1.2 0:00.37 perl >> after >> 531 jimc 23 0 100m 90m 4128 S 0.0 17.9 0:06.91 perl >> >> >> Thats 90 MB of growth, enough I think to warrant further discussion. >> Ive attached my script, hopefully its repeatable. >> > > I don't really see what point you are trying to make here. Yes, if you > load tons of modules you will use tons of memory. What you haven't shown, > is > (a) how much does that 100m shrink by if op_sibling and op_next are > combined? > (b) what proportion of total memory would that 100m be if the modules > were actually used in anger - normally you only load modules to use them > for something, at which point you're creating lots of SVs atc. > > a) I cant answer, since Ive not been able to s/struct/union/ and get something working. To demonstrate 20 MB of savings (the 20% WAG), Id have to be further along. You may infer that Im looking for clues, none heard yet :-( I'll concede that merely relocating op-siblings into the closest-cop will not, by itself, save any memory. It should improve cache-locality, which may not be visible, except perhaps with cachegrind. But eventually, it should be possible to add a 'no uninit-var-reporting' feature, which drops all op-siblings, for use where its warranted. b) is a low-effort existential proof. Substitute a large mod-perl app, with 30 or 40 processes running simultaneously for more reality. I dont have such a setup, but surely someone here does, and could run top on the box. I dont think we need to go about 'proving' that no case exists. Besides, the point was to separate data (which has already been squeezed, thanks NickC) from code, not to give a real-world example. If this is seen as a purely hand-waving non-solution to a non-problem, then I'll look elsewhere for my entertainments. OTOH, If you could look at 2nd patch, and help me understand why the prints added to Perl_linklist show next == self, I might be able to make some progress towards a). Im resending patches: 1- drops the bytecode chunks, since theyve been purged from bleadperl. 2- disables the prints I added to Perl_linklist, so that 'make test' passes. thanks --------------030506010206090808080803 Content-Type: application/x-gzip; name="diff.ns-abstract.test-ok-99a.gz" Content-Transfer-Encoding: base64 Content-Disposition: inline; filename="diff.ns-abstract.test-ok-99a.gz" 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 TQEA --------------030506010206090808080803 Content-Type: text/plain; name="diff.ns-cop-sibling-proto" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="diff.ns-cop-sibling-proto" diff -ruNp -X exclude-diffs ns-abstract/op.c ns-cop-sibling/op.c --- ns-abstract/op.c 2006-09-04 13:00:26.000000000 -0600 +++ ns-cop-sibling/op.c 2006-09-05 12:29:11.000000000 -0600 @@ -527,17 +527,191 @@ Perl_op_refcnt_unlock(pTHX) OP_REFCNT_UNLOCK; } +/* +=head1 Implementation: out-of-OP op-siblings + +In the bottom up up complier pass, perly.y emits op-twigs, setting +op-type/class specific pointers in each OP to link them together +according to the expression just parsed. Sequences of + +optrees are generated using op_sibling and +represent both sequential and expression dependencies. The execution +order pass relinks the tree of OPs for fast execution, using the +op_next pointer. + +Our premise is that sibling pointers are used rarely after op_next is +set, so, at listlink()-age time, we copy op_sibling to an associative +array, and intercept later reads. This allows us to instrument that +read, find out who is using the value, and optimize later, starting +with removing in-OP storage for the pointer and getting it from the +hash. This shrinks the optree by ~20%, and may have other benefits. + +=head2 Implementation: patch development + + 1.abstract all refs to op_next, op_sibling with macros + . PERL_OP_NEXT, PERL_OP_SIBLING + . PERL_OP_SETNEXT, PERL_OP_SETSIBLING + . set OP_NEXT_SIBL_IMP to 0,1,2: to choose pair, struct, union reps + + 2.extend COP, adding struct OpPair {next; sibl} ops[30] + . populate it in linklist + +This wont work as is; in linklist(), assert(PL_curcop == &PL_compiling), +so theres no COP context + + + 3.compile vs runtime (TBC) + . PERL_OP_SIBLING should call instrumentation + . use IN_PERL_RUNTIME to toggle PERL_OP_SIBLING defn + +=head2 Future Optimizations + +At this point (patch 2), the patch increases total memory use, but +we're looking forward to several optimizations: + +1 not all ops have siblings, only those that do get added + +2 we hope that op-shrink, and segregating hot fields from cold, will + improve cache performance, though cache arguably works much better + on C code, and pp_code probably dwarfs the 20% opcode savings. + +3 analysis of the uninit-var feature may reveal that only some ops + need to be hashed to support the reporting for the vars in a given + code block. + +4 we can add a feature to allow the coder to suppress the hashing of + siblings entirely, for use on well-tested code. + +5 OpPair storage can be unioned with op_siblings vector, which its + converted to if/when linklist(op) acts upon COPs. At this point, + the op can be shrunk to fit the op_sibling vector actually needed. + +=cut +*/ + +#if 0 + +/* borrowed verbatim from util.c */ + +STATIC COP* +S_closest_cop(pTHX_ COP *cop, OP *o) +{ + /* Look for PL_op starting from o. cop is the last COP we've seen. */ + + if (!o || o == PL_op) return cop; + + if (o->op_flags & OPf_KIDS) { + OP *kid; + for (kid = cUNOPo->op_first; kid; kid = PERL_OP_SIBLING(kid)) + { + COP *new_cop; + + /* If the OP_NEXTSTATE has been optimised away we can still use it + * the get the file and line number. */ + + if (kid->op_type == OP_NULL && kid->op_targ == OP_NEXTSTATE) + cop = (COP *)kid; + + /* Keep searching, and return when we've found something. */ + + new_cop = S_closest_cop(aTHX_ cop, kid); + if (new_cop) return new_cop; + } + } + + /* Nothing found. */ + + return 0; +} +#endif + +/* during compilation (pre-cop linklist phase), we save sibling + pointers into a global 'hash', then when bottom up linklist-ing + reaches up to the COP, we can sweep those hash entries into + cop-private storage. + + With that data in place, we should be able to find it in the COP, + which allows us to pull it out of the OPs, and save ~20% storage in + the OPs themselves. + + Use of op-sibling ptr is rare once the code is linked for running, + so a higher fetch-cost is mostly irrelevant, since its needed only + to support uninit-var reporting, which is purely a debug-friendly + feature. + + Eventually, we may be able to eliminate the entries that are + representable by a flag instead, forex op->next == op, or some + other knowable (and useful) properties. For some 'production' + situations, where the code-base is well-known, it may be possible + to drop the hash entirely. +*/ + /* Contextualizers */ -#define LINKLIST(o) (PERL_OP_NEXT(o) ? PERL_OP_NEXT(o) : linklist((OP*)o)) +#define LINKLIST(o) Perl_linklist(aTHX_ o) +/* was + #define LINKLIST(o) (PERL_OP_NEXT(o) ? PERL_OP_NEXT(o) : linklist((OP*)o)) + + removing the shortcut means that Perl_linklist sees COPs, which + lets us collect and attach sibling info to the COP, where its + reasonably close at hand for (revamped) uninit-var use. +*/ + +static PTR_TBL_t *siblings; +static char indent[] = " "; +static int ipi = -1; OP * Perl_linklist(pTHX_ OP *o) { OP *first; + COP *cop; + int type; - if (PERL_OP_NEXT(o)) + assert(PL_curcop == &PL_compiling); + + /* + cop = S_closest_cop(aTHX_ PL_curcop, PERL_OP_SIBLING(PL_curcop)); + if ((COP*)o == cop) + PerlIO_printf(Perl_debug_log, "linklist closest cop\n"); + */ + + type = o->op_type; + if (type == OP_NULL) + type = (OPCODE)o->op_targ; + + if (!siblings) siblings = ptr_table_new(); + if (ipi == -1) ipi = strlen(indent)-1; + + if (type == OP_NEXTSTATE || type == OP_SETSTATE || type == OP_DBSTATE) { + PTR_TBL_ENT_t *ent; + OP *next = PERL_OP_SIBLING(o); // next not set yet + /* cop's next points back at itself !! */ + + if (next && 0) + PerlIO_printf(Perl_debug_log, "%s COP %p -> %p %s\n", + indent+ipi, o, next, + PL_op_name[next->op_type]); +#if 0 + for (; next && next != PERL_OP_NEXT(next) && next != o; + next=PERL_OP_NEXT(next)) + { + // follow chain, + ent = ptr_table_fetch(siblings, next); + if (ent && ent->newval == PERL_OP_SIBLING(next)) + PerlIO_printf(Perl_debug_log, "woohoo\n"); + } +#endif + } + if (0) + PerlIO_printf(Perl_debug_log, "%s %p %s s:%p n:%p\n", indent+ipi--, + o, PL_op_name[o->op_type], + PERL_OP_SIBLING(o), PERL_OP_NEXT(o)); + + if (PERL_OP_NEXT(o)) { + ipi++; return PERL_OP_NEXT(o); + } /* establish postfix order */ first = cUNOPo->op_first; @@ -546,7 +720,20 @@ Perl_linklist(pTHX_ OP *o) PERL_OP_SETNEXT(o, LINKLIST(first)); kid = first; for (;;) { + if (PERL_OP_SIBLING(kid)) { + + ptr_table_store(siblings, (SV*)o, PERL_OP_SIBLING(o)); + + /* save op_sibling in COP before setting op_next, + which would overwrite storage if shared/optimized */ + + /* current op entry for siblings + int opincop = cop->opct++; + cop->ops[opincop].sibl = PERL_OP_SIBLING(kid); + cop->ops[opincop].self = kid; + */ + PERL_OP_SETNEXT(kid, LINKLIST(PERL_OP_SIBLING(kid))); kid = PERL_OP_SIBLING(kid); } else { @@ -555,8 +742,15 @@ Perl_linklist(pTHX_ OP *o) } } } - else + else { + ptr_table_store(siblings, (SV*)o, PERL_OP_SIBLING(o)); PERL_OP_SETNEXT(o,o); + } + + if (0) + PerlIO_printf(Perl_debug_log, "%s %p %s s:%p n:%p\n", indent+ipi++, + o, PL_op_name[o->op_type], + PERL_OP_SIBLING(o), PERL_OP_NEXT(o)); return PERL_OP_NEXT(o); } @@ -3346,7 +3540,7 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, bo PERL_OP_SETNEXT(repl, (OP*)rcop); pm->op_pmreplroot = scalar((OP*)rcop); - pm->op_pmreplstart = (OP*) LINKLIST(rcop); + pm->op_pmreplstart = LINKLIST((OP*)rcop); PERL_OP_SETNEXT((OP*)rcop, 0); } } --------------030506010206090808080803--
![]() |
2 |
![]() |
On Wed, Sep 13, 2006 at 10:47:46AM -0600, Jim Cromie wrote: > Dave Mitchell wrote: > >(a) how much does that 100m shrink by if op_sibling and op_next are > >combined? > a) I cant answer, since Ive not been able to s/struct/union/ and get > something working. what you could do is temporarily add an extra ptr field to BASEOP, and see how much the 100m grows by; we can then assume it would shrink by the same amount. -- Nothing ventured, nothing lost.
![]() |
0 |
![]() |
On 9/13/06, Jim Cromie <jim.cromie@gmail.com> wrote: > Dave Mitchell wrote: > > On Mon, Sep 11, 2006 at 07:58:30PM -0600, Jim Cromie wrote: > > > b) is a low-effort existential proof. Substitute a large mod-perl app, > with 30 or 40 > processes running simultaneously for more reality. I dont have such a > setup, > but surely someone here does, and could run top on the box. B::Deparse and thus Data::Dumper and Data::Dump::Streamer both care about ->sibling existing in normal, not debugging runtime. Do your processes need to be able to deparse perl? Josh
![]() |
0 |
![]() |
Dave Mitchell wrote: > On Wed, Sep 13, 2006 at 10:47:46AM -0600, Jim Cromie wrote: > >> Dave Mitchell wrote: >> >>> (a) how much does that 100m shrink by if op_sibling and op_next are >>> combined? >>> > > >> a) I cant answer, since Ive not been able to s/struct/union/ and get >> something working. >> > > what you could do is temporarily add an extra ptr field to BASEOP, and see > how much the 100m grows by; we can then assume it would shrink by the same > amount. > > with maintperl (threads) b4 30231 jimc 15 0 9868 6264 1900 S 0.0 1.2 0:00.60 perl after 30231 jimc 18 0 99.5m 88m 4596 S 0.0 17.7 0:10.81 perl with extra pointer added b4 1877 jimc 15 0 9976 6400 1900 S 0.0 1.2 0:00.62 perl 1877 jimc 16 0 99.9m 89m 4540 S 0.0 17.7 0:06.31 perl IOW - trivial growth. This may be due to the 99m being dominated by XS code, which is probably the point you were making earlier.. :-[ As time permits, I'll construct a use-pure-perl-mods script, and see if it shows anything more. thanks
![]() |
0 |
![]() |
Dave Mitchell wrote: > On Wed, Sep 13, 2006 at 10:47:46AM -0600, Jim Cromie wrote: > >> Dave Mitchell wrote: >> >>> (a) how much does that 100m shrink by if op_sibling and op_next are >>> combined? >>> > > >> a) I cant answer, since Ive not been able to s/struct/union/ and get >> something working. >> > > what you could do is temporarily add an extra ptr field to BASEOP, and see > how much the 100m grows by; we can then assume it would shrink by the same > amount. > > Rewrote the script to build then eval a big&dumb chunk of math (attached) It shows real growth in mem of 10%, 12%, 8% .../maintperl/perl -I ../maintperl/lib usepp.pl 50 PID 30959 b4 string build Size => 1783 after string build Size => 2429 after eval Size => 17027 ns-extra/perl -I ns-extra/lib usepp.pl 50 PID 30960 b4 string build Size => 2052 after string build Size => 2697 after eval Size => 18773 .../maintperl/perl -I ../maintperl/lib usepp.pl 150 PID 30962 b4 string build Size => 1785 after string build Size => 3630 after eval Size => 47611 ns-extra/perl -I ns-extra/lib usepp.pl 150 PID 30964 b4 string build Size => 2050 after string build Size => 3894 after eval Size => 53303 .../maintperl/perl -I ../maintperl/lib usepp.pl 250 PID 31120 b4 string build Size => 1783 after string build Size => 4827 after eval Size => 76158 ns-extra/perl -I ns-extra/lib usepp.pl 250 PID 31122 b4 string build Size => 2049 after string build Size => 5092 after eval Size => 82863 Yes, the hard parts remain, but now theres cause to look more closely.
![]() |
1 |
![]() |
On Fri, Sep 15, 2006 at 05:20:04PM -0600, Jim Cromie wrote: > Rewrote the script to build then eval a big&dumb chunk of math (attached) > It shows real growth in mem of 10%, 12%, 8% A couple of comments. First, I'm not sure you meant this: your eval string gets compiled as: $sum[\"$i"] = $in1[\"$i"] + $in2[\"$j"]; ... etc rather than $sum[3] = $in1[3] + $in2[7]; ... etc Second, its not a very realistic example, since you just have one extremely big sub that contains no lexical vars. -- "Do not dabble in paradox, Edward, it puts you in danger of fortuitous wit." -- Lady Croom - Arcadia
![]() |
1 |
![]() |
--------------000006040307070409040004 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Joshua ben Jore wrote: > On 9/13/06, Jim Cromie <jim.cromie@gmail.com> wrote: >> Dave Mitchell wrote: >> > On Mon, Sep 11, 2006 at 07:58:30PM -0600, Jim Cromie wrote: >> > >> b) is a low-effort existential proof. Substitute a large mod-perl app, >> with 30 or 40 >> processes running simultaneously for more reality. I dont have such a >> setup, >> but surely someone here does, and could run top on the box. > > B::Deparse and thus Data::Dumper and Data::Dump::Streamer both care > about ->sibling existing in normal, not debugging runtime. Do your > processes need to be able to deparse perl? > > Josh > Once, long ago, I worked on an app that data-dumped code. Not since then. Its not a must-have for me. But I dont want to get the dialog hung on absense/presence of any given data. My hope is that we can, in discrete steps; -abstract it -move it into cop -compress it -optionally toss it - for 99% of time when its not needed. For curiosity, I wrote attached script to instrument B::OP::sibling, and collect the siblings found in &foo() into %seen. Most are seen once, some 2 or more times. I wanted to see if there were any that werent traversed. I am puzzled that Im counting 27 siblings, and only 16 ops (The late redef of B::OP::sibling cut it from ~240 siblings) ..... &$x(); print Dumper(\%seen); print "got $opcount OPs\n"; print 'got ', scalar keys %seen, " siblings\n"; '???'; B::Concise::compile(CODE(0x9fcf5d8)) 9 0x9f6ed38 <1> leavesub[1 ref] K/REFC,1 ->(end) 0 - 0x9f6ee20 <@> lineseq KP ->9 0x9f6ed38 1 0x9ce93f8 <;> nextstate(main 300 deparseit:27) v ->2 0x9f6edf0 8 0x9f6ee48 <@> print sK ->9 0x9f6ed38 2 0x9f6edf0 <0> pushmark s ->3 0x9f6ed08 7 0x9fe2338 <2> add[t4] sK/2 ->8 0x9f6ee48 5 0x9ce9438 <2> add[t2] sK/2 ->6 0x9f6ef18 - 0x9f9ccc8 <1> ex-aelem sK/2 ->4 0x9f6ef68 - 0x9f6f038 <1> ex-rv2av sKR/1 ->- 0x9f6ee70 3 0x9f6ed08 <#> aelemfast[*_] s/1 ->4 0x9f6ef68 - 0x9f6ee70 <0> ex-const s ->- 0x9f9ccc8 4 0x9f6ef68 <$> const[IV 42] s ->5 0x9ce9438 - 0x9cd3100 <1> ex-aelem sK/2 ->7 0x9fe2338 - 0x9f6ef38 <1> ex-rv2av sKR/1 ->- 0x9f6eee8 6 0x9f6ef18 <#> aelemfast[*_] s ->7 0x9fe2338 - 0x9f6eee8 <0> ex-const s ->- 0x9cd3100 $VAR1 = { 'B::OP=SCALAR(0x9ff548c)' => 1, 'B::NULL=SCALAR(0x9fefc64)' => 3, 'B::UNOP=SCALAR(0x9ffecc0)' => 1, 'B::NULL=SCALAR(0x9fe5600)' => 1, 'B::LISTOP=SCALAR(0x9ffaf7c)' => 1, 'B::UNOP=SCALAR(0x9fefd84)' => 1, 'B::SVOP=SCALAR(0x9feb5d8)' => 1, 'B::NULL=SCALAR(0x9ffea50)' => 1, 'B::BINOP=SCALAR(0x9feb8a8)' => 1, 'B::OP=SCALAR(0x9ffb1c8)' => 1, 'B::OP=SCALAR(0x9ff599c)' => 1, 'B::NULL=SCALAR(0x9ff5abc)' => 1, 'B::NULL=SCALAR(0x9fef7c0)' => 1, 'B::NULL=SCALAR(0x9ffadd8)' => 2, 'B::NULL=SCALAR(0x9ce8468)' => 2, 'B::NULL=SCALAR(0x9ffef60)' => 1, 'B::NULL=SCALAR(0x9ffaf34)' => 1, 'B::NULL=SCALAR(0x9fe5504)' => 1, 'B::SVOP=SCALAR(0x9fff020)' => 1, 'B::BINOP=SCALAR(0x9ff8a88)' => 1, 'B::NULL=SCALAR(0x9ff4d84)' => 1, 'B::LISTOP=SCALAR(0x9ffec90)' => 1, 'B::NULL=SCALAR(0x9ffd708)' => 1, 'B::NULL=SCALAR(0x9fe9520)' => 1, 'B::NULL=SCALAR(0x9fddbc4)' => 1, 'B::OP=SCALAR(0x9ff4d84)' => 1, 'B::NULL=SCALAR(0x9fdde64)' => 1 }; got 16 OPs got 27 siblings Any comments ? thx jimc --------------000006040307070409040004 Content-Type: text/plain; name="deparseit" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="deparseit" #!/usr/local/bin/perl # -w use B; use B::Deparse; use B::Concise 'add_style'; use Data::Dumper; add_style("c2" => "#hyphseq2 #addr (*( (x( ;)x))*)<#classsym> " . "#exname#arg(?([#targarglife])?)~#flags(?(/#private)?)" . "(x(;~->#next)x) #nextaddr\n" , " (*( )*) goto #seq\n", "(?(<#seq>)?)#exname#arg(?([#targarglife])?)"); %seen; package B; my $op_sibling_base; BEGIN { $op_sibling_base = \&B::OP::sibling; } package main; sub foo { print $_[1]+ 42 + $_[0]; # print $_[1]+ 23 + $_[0]; } print "hello world\n"; my $x; $x = B::Deparse::compile(\&foo); $x->(); eval q{ package B::OP; sub sibling { my $sibling; # print "caught B::Opnext invoke @_\n"; # dump @_; $sibling = $op_sibling_base->(@_); $::seen{$sibling}++; $sibling; } }; my $opcount; $x = B::Concise::compile('-c2', \&foo); B::Concise::add_callback( sub{ $opcount++; }); #B::Concise::walk_output(\my $out); $x->(); print Dumper \%seen; print "got $opcount OPs\n"; print "got ", scalar keys %seen, " siblings\n"; if (0) { my $deparse = B::Deparse->new("-p", "-sC"); $body = $deparse->coderef2text(\&foo); eval "sub func $body"; # the inverse operation } --------------000006040307070409040004--
![]() |
0 |
![]() |
On 9/18/06, Jim Cromie <jim.cromie@gmail.com> wrote: > I am puzzled that Im counting 27 siblings, and only 16 ops > (The late redef of B::OP::sibling cut it from ~240 siblings) You forgot to count all the trailing NULL siblings. Those B::NULL ops are really just null pointers prettied up into objects. 9 0x9f6ed38 <1> leavesub[1 ref] K/REFC,1 ->(end) 0 - 0x9f6ee20 <@> lineseq KP ->9 0x9f6ed38 1 0x9ce93f8 <;> nextstate(main 300 deparseit:27) v ->2 0x9f6edf0 8 0x9f6ee48 <@> print sK ->9 0x9f6ed38 2 0x9f6edf0 <0> pushmark s ->3 0x9f6ed08 7 0x9fe2338 <2> add[t4] sK/2 ->8 0x9f6ee48 5 0x9ce9438 <2> add[t2] sK/2 ->6 0x9f6ef18 - 0x9f9ccc8 <1> ex-aelem sK/2 ->4 0x9f6ef68 - 0x9f6f038 <1> ex-rv2av sKR/1 ->- 0x9f6ee70 3 0x9f6ed08 <#> aelemfast[*_] s/1 ->4 0x9f6ef68 NULL - 0x9f6ee70 <0> ex-const s ->- 0x9f9ccc8 NULL 4 0x9f6ef68 <$> const[IV 42] s ->5 0x9ce9438 NULL - 0x9cd3100 <1> ex-aelem sK/2 ->7 0x9fe2338 - 0x9f6ef38 <1> ex-rv2av sKR/1 ->- 0x9f6eee8 6 0x9f6ef18 <#> aelemfast[*_] s ->7 0x9fe2338 NULL - 0x9f6eee8 <0> ex-const s ->- 0x9cd3100 NULL NULL NULL NULL NULL NULL Josh
![]() |
0 |
![]() |