From 2dfde98b0ffa1d6743752b565c04fee9a46c2dfa Mon Sep 17 00:00:00 2001 From: DaneBettis Date: Fri, 18 Mar 2022 09:10:57 +0000 Subject: [PATCH] Adds %meme and %xray hints. %meme reports mem usage at callsite. %xray prints the vere bytecode of the hoon tree wrapped by the hint. --- pkg/arvo/tests/run/hints.hoon | 14 +- pkg/urbit/include/c/motes.h | 1 + pkg/urbit/include/noun/trace.h | 33 ++- pkg/urbit/noun/manage.c | 9 +- pkg/urbit/noun/nock.c | 419 +++++++++++++++++++++++-------- pkg/urbit/noun/trace.c | 438 ++++++++++++++++++++++++++++++++- 6 files changed, 812 insertions(+), 102 deletions(-) diff --git a/pkg/arvo/tests/run/hints.hoon b/pkg/arvo/tests/run/hints.hoon index 7481b105bd..a1ab2fe7a3 100644 --- a/pkg/arvo/tests/run/hints.hoon +++ b/pkg/arvo/tests/run/hints.hoon @@ -2,7 +2,7 @@ :: there is no need to include the hints for dynamic %bout :: since all hoon tests exersize dynamic %bout |% -:: these test that the hilt-trace hints +:: these test that the hilt trace hints :: are safe to run or ignore ++ test-hela-hilt ~> %hela @@ -10,7 +10,12 @@ ++ test-nara-hilt ~> %nara ~ -:: these test that the hint-trace hints +:: test that the hilt memory-report hint +:: is safe to run or ignore +++ test-meme-hilt + ~> %meme + ~ +:: these test that the hint trace hints :: are safe to run or ignore ++ test-hela-hint ~> %hela.[1 leaf+"test-hela-trace-hint"] @@ -18,4 +23,9 @@ ++ test-nara-hint ~> %nara.[1 leaf+"test-nara-trace-hint"] ~ +:: test that the hilt memory-report hint +:: is safe to run or ignore +++ test-meme-hint + ~> %meme.[1 leaf+"test-meme-hint"] + ~ -- diff --git a/pkg/urbit/include/c/motes.h b/pkg/urbit/include/c/motes.h index e8b944394d..78460b5dfe 100644 --- a/pkg/urbit/include/c/motes.h +++ b/pkg/urbit/include/c/motes.h @@ -1296,6 +1296,7 @@ # define c3__wtts c3_s4('w','t','t','s') # define c3__wtzp c3_s4('w','t','z','p') # define c3__wyrd c3_s4('w','y','r','d') +# define c3__xray c3_s4('x','r','a','y') # define c3__yell c3_s4('y','e','l','l') # define c3__yelp c3_s4('y','e','l','p') # define c3__z c3_s1('z') diff --git a/pkg/urbit/include/noun/trace.h b/pkg/urbit/include/noun/trace.h index e887feb3a0..0b0b0ae0b8 100644 --- a/pkg/urbit/include/noun/trace.h +++ b/pkg/urbit/include/noun/trace.h @@ -154,8 +154,37 @@ void u3t_slog_hela(c3_l pri_l); - /** Globals. - **/ + /* u3t_meme(): report memory stats at call time + */ + void + u3t_slog_meme(c3_l pri_l); + + /* u3t_xray(): collect the bytecode data + ** for the expression wrapped in the 'calling' hint + ** and print it to the terminal + */ + void + u3t_slog_xray(c3_l pri_l, u3_noun inf); + + /* u3t_slog_xray_raw(): this is for me to hack on + ** it must be replace with u3t_xray() before release. + */ + void + u3t_slog_xray_raw(c3_l pri_l, u3_noun fol, c3_w ip_w); + + /* u3t_slog_memory(): + */ + void + u3t_slog_memory(c3_l pri_l, c3_c* cap_c, float percent, c3_w wor_w); + + /* u3t_slog_steps(): + */ + void + u3t_slog_steps(c3_l pri_l, c3_c* cap_c, c3_d sep_d); + + + /* Globals. + */ /* u3_Trace / u3C: global memory control. */ c3_global u3t_trace u3t_Trace; diff --git a/pkg/urbit/noun/manage.c b/pkg/urbit/noun/manage.c index ae2375ae19..5af4d38d8a 100644 --- a/pkg/urbit/noun/manage.c +++ b/pkg/urbit/noun/manage.c @@ -1136,11 +1136,17 @@ u3m_soft_run(u3_noun gul, u3t_off(coy_o); pro = fun_f(aga, agb); + /* #ifdef U3_CPU_DEBUG + // TODO: maybe this should just go away since the %meme hint reports this better if ( u3R->all.max_w > 1000000 ) { + // the old interupting way u3a_print_memory(stderr, "execute: run", u3R->all.max_w); + // the new well behaved way + u3t_slog_memory(2, "execute: run", 0.0, u3R->all.max_w*4); } #endif + */ /* Today you can't run -g without memory debug, but you should be * able to. @@ -1830,7 +1836,8 @@ u3m_boot(c3_c* dir_c) if ( c3n == nuu_o ) { u3j_ream(); u3n_ream(); - + // TODO: remove me before PR + u3m_reclaim(); return u3A->eve_d; } else { diff --git a/pkg/urbit/noun/nock.c b/pkg/urbit/noun/nock.c index 3722f1d619..d96a632379 100644 --- a/pkg/urbit/noun/nock.c +++ b/pkg/urbit/noun/nock.c @@ -388,102 +388,107 @@ _n_nock_on(u3_noun bus, u3_noun fol) // the opcode's enum name, string representation, and computed goto into a // single structure. #define OPCODES \ - /* general purpose */ \ - X(HALT, "halt", &&do_halt), /* 0 */ \ - X(BAIL, "bail", &&do_bail), /* 1 */ \ + /* non-nock bytecodes */ \ + X(HALT, "halt", &&do_halt), /* 0: terminator, end of bytcode program */ \ + X(BAIL, "bail", &&do_bail), /* 1: deterministic crash */ \ + /* stack manipulation */ \ X(COPY, "copy", &&do_copy), /* 2 */ \ X(SWAP, "swap", &&do_swap), /* 3 */ \ X(TOSS, "toss", &&do_toss), /* 4 */ \ - X(AUTO, "auto", &&do_auto), /* 5 */ \ - X(AULT, "ault", &&do_ault), /* 6 */ \ - X(SNOC, "snoc", &&do_snoc), /* 7 */ \ - X(SNOL, "snol", &&do_snol), /* 8 */ \ - X(HEAD, "head", &&do_head), /* 9 */ \ - X(HELD, "held", &&do_held), /* 10 */ \ - X(TAIL, "tail", &&do_tail), /* 11 */ \ - X(TALL, "tall", &&do_tall), /* 12 */ \ - /* fragment (keep) */ \ - X(FABK, "fabk", &&do_fabk), /* 13 */ \ - X(FASK, "fask", &&do_fask), /* 14 */ \ - X(FIBK, "fibk", &&do_fibk), /* 15 */ \ - X(FISK, "fisk", &&do_fisk), /* 16 */ \ - /* fragment (lose) */ \ - X(FABL, "fabl", &&do_fabl), /* 17 */ \ - X(FASL, "fasl", &&do_fasl), /* 18 */ \ - X(FIBL, "fibl", &&do_fibl), /* 19 */ \ - X(FISL, "fisl", &&do_fisl), /* 20 */ \ - /* literal (keep) */ \ - X(LIT0, "lit0", &&do_lit0), /* 21 */ \ - X(LIT1, "lit1", &&do_lit1), /* 22 */ \ - X(LITB, "litb", &&do_litb), /* 23 */ \ - X(LITS, "lits", &&do_lits), /* 24 */ \ - X(LIBK, "libk", &&do_libk), /* 25 */ \ - X(LISK, "lisk", &&do_lisk), /* 26 */ \ - /* literal (lose) */ \ - X(LIL0, "lil0", &&do_lil0), /* 27 */ \ - X(LIL1, "lil1", &&do_lil1), /* 28 */ \ - X(LILB, "lilb", &&do_lilb), /* 29 */ \ - X(LILS, "lils", &&do_lils), /* 30 */ \ - X(LIBL, "libl", &&do_libl), /* 31 */ \ - X(LISL, "lisl", &&do_lisl), /* 32 */ \ - /* nock */ \ + /* auto-cons */ \ + X(AUTO, "auto", &&do_auto), /* 5: keep */ \ + X(AULT, "ault", &&do_ault), /* 6: lose */ \ + /* general purposes */ \ + X(SNOC, "snoc", &&do_snoc), /* 7: keep */ \ + X(SNOL, "snol", &&do_snol), /* 8: lose */ \ + /* nock 0: head */ \ + X(HEAD, "head", &&do_head), /* 9: keep */ \ + X(HELD, "held", &&do_held), /* 10: lose */ \ + /* nock 0: tail */ \ + X(TAIL, "tail", &&do_tail), /* 11: keep */ \ + X(TALL, "tall", &&do_tall), /* 12: lose */ \ + /* nock 0: fragment (keep) */ \ + X(FABK, "fabk", &&do_fabk), /* 13: c3_y */ \ + X(FASK, "fask", &&do_fask), /* 14: c3_s */ \ + X(FIBK, "fibk", &&do_fibk), /* 15: c3_y */ \ + X(FISK, "fisk", &&do_fisk), /* 16: c3_s */ \ + /* nock 0: fragment (lose) */ \ + X(FABL, "fabl", &&do_fabl), /* 17: c3_y */ \ + X(FASL, "fasl", &&do_fasl), /* 18: c3_s */ \ + X(FIBL, "fibl", &&do_fibl), /* 19: c3_y */ \ + X(FISL, "fisl", &&do_fisl), /* 20: c3_s */ \ + /* nock 1: literal (keep) */ \ + X(LIT0, "lit0", &&do_lit0), /* 21: a literal 0 */ \ + X(LIT1, "lit1", &&do_lit1), /* 22: a literal 1 */ \ + X(LITB, "litb", &&do_litb), /* 23: c3_y */ \ + X(LITS, "lits", &&do_lits), /* 24: c3_s */ \ + X(LIBK, "libk", &&do_libk), /* 25: c3_y */ \ + X(LISK, "lisk", &&do_lisk), /* 26: c3_s */ \ + /* nock 1: literal (lose) */ \ + X(LIL0, "lil0", &&do_lil0), /* 27: a literal 0 */ \ + X(LIL1, "lil1", &&do_lil1), /* 28: a literal 1 */ \ + X(LILB, "lilb", &&do_lilb), /* 29: c3_y */ \ + X(LILS, "lils", &&do_lils), /* 30: c3_s */ \ + X(LIBL, "libl", &&do_libl), /* 31: c3_y */ \ + X(LISL, "lisl", &&do_lisl), /* 32: c3_s */ \ + /* nock 2: nock (lose) */ \ X(NOLK, "nolk", &&do_nolk), /* 33 */ \ X(NOCT, "noct", &&do_noct), /* 34 */ \ X(NOCK, "nock", &&do_nock), /* 35 */ \ - /* 3 & 4 */ \ + /* nock 3 & 4 */ \ X(DEEP, "deep", &&do_deep), /* 36 */ \ X(BUMP, "bump", &&do_bump), /* 37 */ \ - /* equality */ \ - X(SAM0, "sam0", &&do_sam0), /* 38 */ \ - X(SAM1, "sam1", &&do_sam1), /* 39 */ \ - X(SAMB, "samb", &&do_samb), /* 40 */ \ - X(SAMS, "sams", &&do_sams), /* 41 */ \ - X(SANB, "sanb", &&do_sanb), /* 42 */ \ - X(SANS, "sans", &&do_sans), /* 43 */ \ + /* nock 5: equality */ \ + X(SAM0, "sam0", &&do_sam0), /* 38: test that it is equal to 0 */ \ + X(SAM1, "sam1", &&do_sam1), /* 39: test that it is equal to 1 */ \ + X(SAMB, "samb", &&do_samb), /* 40: test equality for vars size c3_b */ \ + X(SAMS, "sams", &&do_sams), /* 41: test equality for vars size c3_s */ \ + X(SANB, "sanb", &&do_sanb), /* 42: test equality for vars size c3_b */ \ + X(SANS, "sans", &&do_sans), /* 43: test equality for vars size c3_s */ \ X(SAME, "same", &&do_same), /* 44 */ \ X(SALM, "salm", &&do_salm), /* 45 */ \ X(SAMC, "samc", &&do_samc), /* 46 */ \ - /* unconditional skips */ \ - X(SBIP, "sbip", &&do_sbip), /* 47 */ \ - X(SIPS, "sips", &&do_sips), /* 48 */ \ - X(SWIP, "swip", &&do_swip), /* 49 */ \ - /* conditional skips */ \ - X(SBIN, "sbin", &&do_sbin), /* 50 */ \ - X(SINS, "sins", &&do_sins), /* 51 */ \ - X(SWIN, "swin", &&do_swin), /* 52 */ \ + /* related to nock 6: unconditional skips */ \ + X(SBIP, "sbip", &&do_sbip), /* 47: c3_b */ \ + X(SIPS, "sips", &&do_sips), /* 48: c3_s */ \ + X(SWIP, "swip", &&do_swip), /* 49: c3_l */ \ + /* related to nock 6: conditional skips */ \ + X(SBIN, "sbin", &&do_sbin), /* 50: c3_b */ \ + X(SINS, "sins", &&do_sins), /* 51: c3_s */ \ + X(SWIN, "swin", &&do_swin), /* 52: c3_l */ \ /* nock 9 */ \ - X(KICB, "kicb", &&do_kicb), /* 53 */ \ - X(KICS, "kics", &&do_kics), /* 54 */ \ - X(TICB, "ticb", &&do_ticb), /* 55 */ \ - X(TICS, "tics", &&do_tics), /* 56 */ \ - /* nock 12 */ \ + X(KICB, "kicb", &&do_kicb), /* 53: c3_b */ \ + X(KICS, "kics", &&do_kics), /* 54: c3_s */ \ + X(TICB, "ticb", &&do_ticb), /* 55: c3_b */ \ + X(TICS, "tics", &&do_tics), /* 56: c3_s */ \ + /* nock 12: scry (only defined in arvo, not in base nock spec) */ \ X(WILS, "wils", &&do_wils), /* 57 */ \ X(WISH, "wish", &&do_wish), /* 58 */ \ - /* hint processing */ \ - X(BUSH, "bush", &&do_bush), /* 59 */ \ - X(SUSH, "sush", &&do_sush), /* 60 */ \ + /* nock 11: hint processing */ \ + X(BUSH, "bush", &&do_bush), /* 59: c3_b */ \ + X(SUSH, "sush", &&do_sush), /* 60: c3_s */ \ X(DROP, "drop", &&do_drop), /* 61 */ \ X(HECK, "heck", &&do_heck), /* 62 */ \ X(SLOG, "slog", &&do_slog), /* 63 */ \ - /* fast (keep) */ \ - X(BAST, "bast", &&do_bast), /* 64 */ \ - X(SAST, "sast", &&do_sast), /* 65 */ \ - /* fast (lose) */ \ - X(BALT, "balt", &&do_balt), /* 66 */ \ - X(SALT, "salt", &&do_salt), /* 67 */ \ - /* memo (keep) */ \ - X(SKIB, "skib", &&do_skib), /* 68 */ \ - X(SKIS, "skis", &&do_skis), /* 69 */ \ - /* memo (lose) */ \ - X(SLIB, "slib", &&do_slib), /* 70 */ \ - X(SLIS, "slis", &&do_slis), /* 71 */ \ + /* nock 11: fast (keep) */ \ + X(BAST, "bast", &&do_bast), /* 64: c3_b */ \ + X(SAST, "sast", &&do_sast), /* 65: c3_s */ \ + /* nock 11: fast (lose) */ \ + X(BALT, "balt", &&do_balt), /* 66: c3_b */ \ + X(SALT, "salt", &&do_salt), /* 67: c3_s */ \ + /* nock 11: memo (keep) */ \ + X(SKIB, "skib", &&do_skib), /* 68: c3_b */ \ + X(SKIS, "skis", &&do_skis), /* 69: c3_s */ \ + /* nock 11: memo (lose) */ \ + X(SLIB, "slib", &&do_slib), /* 70: c3_b */ \ + X(SLIS, "slis", &&do_slis), /* 71: c3_s */ \ X(SAVE, "save", &&do_save), /* 72 */ \ - /* before formula */ \ + /* nock 11: before formula */ \ X(HILB, "hilb", &&do_hilb), /* 73: atomic, byte */ \ X(HILS, "hils", &&do_hils), /* 74: atomic, short */ \ X(HINB, "hinb", &&do_hinb), /* 75: arbitrary, byte */ \ X(HINS, "hins", &&do_hins), /* 76: arbitrary, short */ \ - /* after formula */ \ + /* nock 11: after formula */ \ X(HILK, "hilk", &&do_hilk), /* 77: atomic, keep */ \ X(HILL, "hill", &&do_hill), /* 78: atomic, lose */ \ X(HINK, "hink", &&do_hink), /* 79: arbitrary, keep */ \ @@ -495,20 +500,20 @@ _n_nock_on(u3_noun bus, u3_noun fol) X(KUTT, "kutt", &&do_kutt), /* 84 */ \ X(MUSM, "musm", &&do_musm), /* 85 */ \ X(KUSM, "kusm", &&do_kusm), /* 86 */ \ - X(MUTB, "mutb", &&do_mutb), /* 87 */ \ - X(MUTS, "muts", &&do_muts), /* 88 */ \ - X(MITB, "mitb", &&do_mitb), /* 89 */ \ - X(MITS, "mits", &&do_mits), /* 90 */ \ - X(KUTB, "kutb", &&do_kutb), /* 91 */ \ - X(KUTS, "kuts", &&do_kuts), /* 92 */ \ - X(KITB, "kitb", &&do_kitb), /* 93 */ \ - X(KITS, "kits", &&do_kits), /* 94 */ \ + X(MUTB, "mutb", &&do_mutb), /* 87: c3_b */ \ + X(MUTS, "muts", &&do_muts), /* 88: c3_s */ \ + X(MITB, "mitb", &&do_mitb), /* 89: c3_b */ \ + X(MITS, "mits", &&do_mits), /* 90: c3_s, seems unused in codebase */ \ + X(KUTB, "kutb", &&do_kutb), /* 91: c3_b */ \ + X(KUTS, "kuts", &&do_kuts), /* 92: c3_s */ \ + X(KITB, "kitb", &&do_kitb), /* 93: c3_b */ \ + X(KITS, "kits", &&do_kits), /* 94: c3_s, seems unused in codebase */ \ X(LAST, NULL, NULL), /* 95 */ - // Opcodes. Define X to select the enum name from OPCODES. #define X(opcode, name, indirect_jump) opcode enum { OPCODES }; #undef X +/* TODO: opcodes for nock 7 & 8 seem to be missing */ /* _n_arg(): return the size (in bytes) of an opcode's argument */ @@ -779,7 +784,8 @@ _n_prog_asm(u3_noun ops, u3n_prog* pog_u, u3_noun sip) if ( c3y == u3ud(op) ) { switch ( op ) { default: - buf_y[i_w] = (c3_y) u3h(ops); + // just reuse op + buf_y[i_w] = (c3_y) op; break; /* registration site index args */ @@ -877,6 +883,49 @@ _n_prog_asm(u3_noun ops, u3n_prog* pog_u, u3_noun sip) case BUSH: case SANB: case KITB: case MITB: case HILB: case HINB: + /* TODO: + ** check tail of op for being xray + ** if so call a rendering and cons to tail of op + ** like sip list in melt? + ** take interpret buffy upto nef_w + */ + + // check tail of op for being xray + /*if ( c3__xray == u3k(u3t(op)) ) { + // TODO: render everything called until this point + // ie take whatever the analog of fol is, and run it through + // something like _slog_bytecode without sloging it, to convert + // it to a u3i_string, then store that to the tail of op + // TODO: cons the rendered data to tail of op + // TODO: slog out info on what is compiling right now + u3_noun op_string = u3i_string("xray"); + switch ( cod ) { + default: break; + case FIBK: u3t_slog_cap(1, u3i_string("FIBK"), op_string); break; + case FIBL: u3t_slog_cap(1, u3i_string("FIBL"), op_string); break; + case LIBK: u3t_slog_cap(1, u3i_string("LIBK"), op_string); break; + case LIBL: u3t_slog_cap(1, u3i_string("LIBL"), op_string); break; + case BUSH: u3t_slog_cap(1, u3i_string("BUSH"), op_string); break; + case SANB: u3t_slog_cap(1, u3i_string("SANB"), op_string); break; + case KITB: u3t_slog_cap(1, u3i_string("KITB"), op_string); break; + case MITB: u3t_slog_cap(1, u3i_string("MITB"), op_string); break; + case HILB: u3t_slog_cap(1, u3i_string("HILB"), op_string); break; + case HINB: u3t_slog_cap(1, u3i_string("HINB"), op_string); break; + } + + _n_prog_asm_inx(buf_y, &i_w, lit_s, cod); + pog_u->lit_u.non[lit_s++] = u3k(u3t(op)); + + // NOTE: buf_y is pog_u->byc_u.ops_y ie it is arg #1 for render bytecode + // NOTE: ___ is arg #2 for render_bytecode (aka c3_w her_w) + // i_W + _slog_bytecode(1, buf_y, 0); + _slog_bytecode(1, pog_u->byc_u.ops_y, 0); + } + else { + _n_prog_asm_inx(buf_y, &i_w, lit_s, cod); + pog_u->lit_u.non[lit_s++] = u3k(u3t(op)); + }*/ _n_prog_asm_inx(buf_y, &i_w, lit_s, cod); pog_u->lit_u.non[lit_s++] = u3k(u3t(op)); break; @@ -956,12 +1005,12 @@ static void _n_print_stack(u3p(u3_noun) empty) { } #endif -#ifdef VERBOSE_BYTECODE +//#ifdef VERBOSE_BYTECODE // Define X to select the opcode string representation from OPCODES. # define X(opcode, name, indirect_jump) name static c3_c* opcode_names[] = { OPCODES }; # undef X -#endif +//#endif /* _n_apen(): emit the instructions contained in src to dst */ @@ -998,6 +1047,12 @@ _n_bint(u3_noun* ops, u3_noun hif, u3_noun nef, c3_o los_o, c3_o tel_o) default: { return _n_comp(ops, nef, los_o, tel_o); } + /* TODO: + ** for case xray pack more info into HILB + ** place nef_w into HILB trel + */ + case c3__xray: + case c3__meme: case c3__nara: case c3__hela: case c3__bout: { @@ -1009,7 +1064,7 @@ _n_bint(u3_noun* ops, u3_noun hif, u3_noun nef, c3_o los_o, c3_o tel_o) ++nef_w; _n_emit(&fen, u3nc(SBIP, 1)); // call hilt_fore - // HILB overflows to HILS + // HILB overflows to HILS - NOTE: this becomes hin ++tot_w; _n_emit(ops, u3nc(HILB, u3nc(u3k(hif), u3k(nef)))); // if fore return c3n, skip fen ++tot_w; _n_emit(ops, u3nc(SBIN, nef_w)); @@ -1034,6 +1089,12 @@ _n_bint(u3_noun* ops, u3_noun hif, u3_noun nef, c3_o los_o, c3_o tel_o) ++tot_w; _n_emit(ops, TOSS); tot_w += _n_comp(ops, nef, los_o, tel_o); } break; + /* TODO: + ** for case xray pack more info into HILB + ** place nef_w into HINB trel + */ + case c3__xray: + case c3__meme: case c3__nara: case c3__hela: case c3__bout: { @@ -1047,7 +1108,7 @@ _n_bint(u3_noun* ops, u3_noun hif, u3_noun nef, c3_o los_o, c3_o tel_o) // push clue tot_w += _n_comp(ops, hod, c3n, c3n); // call hint_fore - // HINB overflows to HINS + // HINB overflows to HINS - NOTE: does this also becom hin? ++tot_w; _n_emit(ops, u3nc(HINB, u3nc(u3k(zep), u3k(nef)))); // if fore return c3n, skip fen ++tot_w; _n_emit(ops, u3nc(SBIN, nef_w)); @@ -1192,11 +1253,11 @@ _n_comp(u3_noun* ops, u3_noun fol, c3_o los_o, c3_o tel_o) u3_noun cod, arg, hed, tel; u3x_cell(fol, &cod, &arg); if ( c3y == u3du(cod) ) { - tot_w += _n_comp(ops, cod, c3n, c3n); - ++tot_w; _n_emit(ops, SWAP); - tot_w += _n_comp(ops, arg, c3n, c3n); - ++tot_w; _n_emit(ops, (c3y == los_o ) ? AULT : AUTO); - } + tot_w += _n_comp(ops, cod, c3n, c3n); // [hed bus ..] // compute head: don't lose, not in tail + ++tot_w; _n_emit(ops, SWAP); // [bus hed ..] + tot_w += _n_comp(ops, arg, c3n, c3n); // [tel bus hed ..] // compute tail: don't lose, not in tail + ++tot_w; _n_emit(ops, (c3y == los_o ) ? AULT : AUTO); // [[hed tel] ..] + } // [[hed tel] bus ..] else switch ( cod ) { case 0: if ( c3n == u3ud(arg) ) { @@ -1230,12 +1291,12 @@ _n_comp(u3_noun* ops, u3_noun fol, c3_o los_o, c3_o tel_o) case 1: switch ( arg ) { case 0: - ++tot_w; _n_emit(ops, (c3y == los_o) ? LIL0 : LIT0); + ++tot_w; _n_emit(ops, (c3y == los_o) ? LIL0 : LIT0); // an actual value of 0 break; case 1: - ++tot_w; _n_emit(ops, (c3y == los_o) ? LIL1 : LIT1); + ++tot_w; _n_emit(ops, (c3y == los_o) ? LIL1 : LIT1); // an actual value of 1 break; - default: + default: // these are all indexes op_y = (c3y == los_o) ? (arg <= 0xFF ? LILB : arg <= 0xFFFF ? LILS : LIBL) // overflows to LISL : (arg <= 0xFF ? LITB : arg <= 0xFFFF ? LITS : LIBK); // overflows to LISK @@ -1665,6 +1726,139 @@ u3n_find(u3_noun key, u3_noun fol) return pog_p; } +//-------------------DANE------ +/* _n_prog_free(): free memory retained by program +*/ +static void +_n_prog_free_willy(u3n_prog* pog_u) +{ + c3_w i_w; + for ( i_w = 0; i_w < pog_u->lit_u.len_w; ++i_w ) { + u3z(pog_u->lit_u.non[i_w]); + } + for ( i_w = 0; i_w < pog_u->mem_u.len_w; ++i_w ) { + u3z(pog_u->mem_u.sot_u[i_w].key); + } + for ( i_w = 0; i_w < pog_u->cal_u.len_w; ++i_w ) { + u3j_site_lose(&(pog_u->cal_u.sit_u[i_w])); + } + for ( i_w = 0; i_w < pog_u->reg_u.len_w; ++i_w ) { + u3j_rite_lose(&(pog_u->reg_u.rit_u[i_w])); + } + u3a_free(pog_u); +} + + +int +_intlen (int value) +{ + int x=!value; + while(value){ + value/=10; + x++; + } + return x; +} + +int _is_valid_op(int go) { + return (go == 0 || go == 1 || go == 2 | go == 4); +} +int _is_pair_op(int go) { + return (go == 1 || go == 2 | go == 4); +} + +void +_slog_bytecode(c3_l pri_l, c3_y* pog, c3_w her_w) { + c3_w ip_w = 0; + // NOTE: if we change the main loop, we should c/p + // it back up here to replace this loop, + // then replace all string ops with increments + // thats how I did it in the first place. + // lets count the chars in this string + unsigned int s_ln = 1; // opening "{" + // set go to an invalid value, so we can break imeadately if needed + unsigned int go = 5; + while ( pog[ip_w] ) { + go = _n_arg(pog[ip_w]); + // no need to stay here if we cant print it + if (!_is_valid_op(go)) break; + ip_w++; // move ip_w for reading a opcode name + s_ln += 4; // opcode name, which is always 4 char long + if (_is_pair_op(go)) { + // add the len of the number + s_ln += _intlen( + go == 4 ? _n_rewo(pog, &ip_w): + go == 2 ? _n_resh(pog, &ip_w): + pog[ip_w++]); + s_ln+= 3; // "[", the space between the opcode and number, "]" + } + s_ln++; // add trailing space before next word in string + if (ip_w == her_w) s_ln +=3; // add "[*]" before next word + } + s_ln += 5; //add "halt}" to end of the bytecode + + // reset ip_w so we can loop again + ip_w = 0; + c3_c str_c[s_ln]; + str_c[0] = 0; + strcat(str_c, "{"); + go = 5; + while ( pog[ip_w] ) { + go = _n_arg(pog[ip_w]); + // no need to stay here if we cant print it + if (!_is_valid_op(go)) break; + + // add open brace if the opcode pairs with a number + if (_is_pair_op(go)) strcat(str_c, "["); + + // add the opcode name + strncat(str_c, opcode_names[pog[ip_w++]], 4); + + // finish the pair + if (_is_pair_op(go)) { + // add the space + strcat(str_c, " "); + // get the number + int num = + go == 4 ? _n_rewo(pog, &ip_w): + go == 2 ? _n_resh(pog, &ip_w): + pog[ip_w++]; + if (num == 0) { + // handle a litteral zero + strcat(str_c, "0"); + } + else { + // add underscores to the buffer for the number + for (int x = _intlen(num); x > 0; x--) strcat(str_c, "_"); + // get the index of the last underscore we added + int f = strlen(str_c)-1; + // add num to the string by decrementing into str_c, + // stuffing the tail of num into each slot + while (num > 0) { + str_c[f--] = (num%10)+'0'; + num /= 10; + } + } + // add the closing brace + strcat(str_c, "]"); + } + strcat(str_c, " "); + if (ip_w == her_w) strcat(str_c, "[*]"); + } + strcat(str_c, "halt}"); + u3t_slog_cap(pri_l, u3i_string("bytecode"), u3i_string(str_c)); +} + + +void +_xray(c3_l pri_l, u3_noun fol) { + u3n_prog* pog_u = _n_bite(fol); + c3_y* pog = pog_u->byc_u.ops_y; + _slog_bytecode(pri_l, pog, pog_u->byc_u.len_w-1); + _n_prog_free_willy(pog_u); +} +// ---------------END DANEs EDIT ----- + /* _n_hilt_fore(): literal (atomic) dynamic hint, before formula evaluation. ** hin: [hint-atom, formula]. TRANSFER ** bus: subject. RETAIN @@ -1695,6 +1889,16 @@ _n_hilt_fore(u3_noun hin, u3_noun bus, u3_noun* out) *out = u3_nul; } break; + case c3__meme : { + u3t_slog_meme(0); + *out = u3_nul; + } break; + + case c3__xray : { + _xray(0, fol); + *out = u3_nul; + } break; + default: { *out = u3_nul; } break; @@ -1769,6 +1973,28 @@ _n_hint_fore(u3_cell hin, u3_noun bus, u3_noun* clu) *clu = u3_nul; } break; + case c3__meme : { + u3_noun pri, tan; + if ( c3y == u3r_cell(*clu, &pri, &tan) ) { + c3_l pri_l = c3y == u3a_is_cat(pri) ? pri : 0; + u3t_slog_cap(pri_l, u3i_string("memeory profile at"), u3k(tan)); + u3t_slog_meme(pri_l); + } + u3z(*clu); + *clu = u3_nul; + } break; + + case c3__xray : { + u3_noun pri, tan; + if ( c3y == u3r_cell(*clu, &pri, &tan) ) { + c3_l pri_l = c3y == u3a_is_cat(pri) ? pri : 0; + u3t_slog_cap(pri_l, u3i_string("bytecode of"), u3k(tan)); + _xray(pri_l, fol); + } + u3z(*clu); + *clu = u3_nul; + } break; + default: { u3z(*clu); *clu = u3_nul; @@ -2987,3 +3213,4 @@ u3n_nock_an(u3_noun bus, u3_noun fol) return u3n_nock_et(gul, bus, fol); } + diff --git a/pkg/urbit/noun/trace.c b/pkg/urbit/noun/trace.c index 79d290930d..11928adec2 100644 --- a/pkg/urbit/noun/trace.c +++ b/pkg/urbit/noun/trace.c @@ -609,6 +609,24 @@ u3t_slog_cap(c3_l pri_l, u3_noun cap, u3_noun tan) ); } +/* _slog_blank(): slog out a blank line with +** a given priority c3_l (assumed 0-3). +*/ +void +_slog_blank(c3_l pri_l) +{ + u3t_slog( + u3nc( + pri_l, + u3nt( + c3__rose, + u3nt(u3nt(' ', ' ', u3_nul), u3_nul, u3_nul), + u3nt(u3i_string(" "), u3i_string(" "), u3_nul) + ) + ) + ); +} + /* u3t_slog_trace(): given a c3_l priority pri and a raw stack tax ** flop the order into start-to-end, render, and slog each item @@ -620,7 +638,7 @@ u3t_slog_trace(c3_l pri_l, u3_noun tax) // render the stack // Note: ton is a reference to a data struct // we have just allocated - // lit is a used as a moving cursor pointer through + // lit is used as a moving cursor pointer through // that allocated struct // once we finish lit will be null, but ton will still // point to the whole valid allocated data structure @@ -673,3 +691,421 @@ u3t_slog_hela(c3_l pri_l) u3t_slog_trace(pri_l, tax); } +/* _roundf(): truncate a float to preciscon +** equivalant to %.2f +*/ +float +_roundf(float percent) +{ + // scale the percentage so that all siginificant digits + // would be retained when truncted to an int, then add 0.5 + // to account for rounding without using round or roundf + float percent_big_f = (percent*10000)+0.5; + // truncate to int + int percent_big_i = (int) percent_big_f; + // convert to float and scale down such that + // our last to digits are right of the decimal + float percent_truncated_f = (float) percent_big_i/100.0; + return percent_truncated_f; +} + + +float +_meme_percent(unsigned int small, unsigned int large) +{ + // get the percentage of our inputs as a float + float percent_raw_f = (float) small/large; + return _roundf(percent_raw_f); +} + +/* +void +_slog_free_discrepancy( ) +{ + c3_w fre_w = u3a_idle(u3R); + if ( fre_w != u3R->all.fre_w ) { + char* s; + int result = asprintf(&s, + "%x\n\t\t\tfre_w: %x\n\t\t all.fre_w: %x\n\t\t\t diff: %x", + u3R->par_p, + fre_w, + u3R->all.fre_w, + (u3R->all.fre_w - fre_w) + ); + if (0 <= result) { + u3t_slog_cap(2, u3i_string(" free discrepancy at par_p"), u3i_string(s)); + free(s); + } + } +} +*/ + +void _slog_road_depth(c3_l pri_l, u3_road* r, int i) { + if (r == &(u3H->rod_u)) { + // slog the info + unsigned int x = 0; + char s[8] = " 0"; + while (i > 0 && x < 8) { + s[6-x] = (i%10)+'0'; + i /= 10; + x++; + } + u3t_slog_cap(pri_l, u3i_string(" road depth"), u3i_string(s)); + } else { + // recurse + _slog_road_depth(pri_l, u3tn(u3_road, r->par_p), ++i); + } +} + + +int _all_heap_size(u3_road* r) { + if (r == &(u3H->rod_u)) { + return u3a_heap(r)*4; + } else { + // recurse + return (u3a_heap(r)*4) + _all_heap_size(u3tn(u3_road, r->par_p)); + } +} + +struct +_report_bar { + char s[105]; +}; + +struct +bar_item { + unsigned int index; + unsigned int lower; + float og; + float dif; +}; + +struct +bar_items { + struct bar_item s[6]; +}; + +float +_boost_small(float x) +{ + return + // we want zero to be zero, + // and anything between zero and one to be one + // all else goes as normal + 0.0 >= x ? 0.0: + 1.0 > x ? 1.0: + x; +} + +int +_global_difference(struct bar_items item) +{ + unsigned int lower_sum = 0; + for (unsigned int i=0; i < 6; i++) lower_sum += item.s[i].lower; + return 100 - lower_sum; +} + +struct bar_items +_get_roundoff_error(struct bar_items item) +{ + for (unsigned int i=0; i < 6; i++) { + item.s[i].dif = item.s[i].og - item.s[i].lower; + } + return item; +} + +struct bar_items +_sort_by_roundoff_error(struct bar_items item) +{ + struct bar_item temp; + for (unsigned int i=1; i < 6; i++) { + for (unsigned int j=0; j < 6-i; j++) { + if (item.s[j+1].dif > item.s[j].dif) { + temp = item.s[j]; + item.s[j] = item.s[j+1]; + item.s[j+1] = temp; + } + } + } + return item; +} + +struct bar_items +_sort_by_index(struct bar_items item) +{ + struct bar_item temp; + for (unsigned int i=1; i < 6; i++) { + for (unsigned int j=0; j < 6-i; j++) { + if (item.s[j+1].index < item.s[j].index) { + temp = item.s[j]; + item.s[j] = item.s[j+1]; + item.s[j+1] = temp; + } + } + } + return item; +} + +void +_print_bar_items(struct bar_items item) +{ + const char symbol[6] = "=-%#+~"; + for (int i=0; i < 6; i++) printf( + "item:%c,%2u, %6.2f,%6.2f, %2u\n", + symbol[i], + item.s[i].index, + item.s[i].og, + item.s[i].dif, + item.s[i].lower + ); +} + +struct bar_items +_reduce_error(struct bar_items item, int difference) +{ + for (unsigned int i=0; i < 6; i++) { + if (item.s[i].lower == 0) continue; + if (item.s[i].lower == 1) continue; + if (difference > 0) { + item.s[i].lower++; + difference--; + } + if (difference < 0) { + item.s[i].lower--; + difference++; + } + } + return item; +} + +struct _report_bar +_report_bargraph(float ih, float sh, float fh, float op, float sk, float ik) +{ + float in[6]; + in[0] = _boost_small(ih); + in[1] = _boost_small(sh); + in[2] = _boost_small(fh); + in[3] = _boost_small(op); + in[4] = _boost_small(sk); + in[5] = _boost_small(ik); + + const char symbol[6] = "=-%#+~"; + + // init the list of structs + struct bar_items item; + for (unsigned int i=0; i < 6; i++) { + item.s[i].index = i; + item.s[i].og = in[i]; + item.s[i].lower = (int) item.s[i].og; + } + + int difference = 0; + for (int x=0; x<100; x++) { + item = _get_roundoff_error(item); + difference = _global_difference(item); + if (difference == 0) break; + item = _sort_by_roundoff_error(item); + item = _reduce_error(item, difference); + } + item = _sort_by_index(item); + + struct _report_bar bar = { + .s = "[ ]" + }; + + // create our bar chart + int x = 0, y = 0; + for (int i=0; i < 6; i++) { + x++; + for (int j=0; j < item.s[i].lower; j++) { + bar.s[x+j] = symbol[i]; + y = x+j; + } + if (y > 0) x = y; + } + + return bar; +} + + +/* u3t_meme(): report memory stats at call time */ +void +u3t_slog_meme(c3_l pri_l) +{ + c3_w low = 0, + top = u3a_bytes, + full = u3a_full(u3R)*4, + fred = u3a_idle(u3R)*4, + temp = u3a_temp(u3R)*4, + heap = u3a_heap(u3R)*4, + open = u3a_open(u3R)*4; + c3_w imut = top-full; + c3_w solid = heap-fred; + + float imut_p = _meme_percent(imut, top), + heap_p = _meme_percent(solid, top), + free_p = _meme_percent(fred, top), + open_p = _meme_percent(open, top), + stak_p = _meme_percent(temp, top); + float full_p = heap_p + free_p + open_p + stak_p; + + // TODO: replace all calls of free() with calls of u3a_free() or its alias. + + c3_w imut_heap = _all_heap_size(u3R) - heap; + c3_w imut_stak = imut - imut_heap; + float imut_heap_p = _meme_percent(imut_heap, top), + imut_stak_p = _meme_percent(imut_stak, top); + + u3t_slog_cap(pri_l, u3i_string("Legend | Report"), u3i_string(" ")); + u3t_slog_memory(pri_l, " loom", 100.0, top); + u3t_slog_memory(pri_l, " road", full_p, full); + _slog_blank(pri_l); + u3t_slog_memory(pri_l, " = immutable heap", imut_heap_p, imut_heap); + u3t_slog_memory(pri_l, " - solid heap", heap_p, solid); + u3t_slog_memory(pri_l," \% freed heap", free_p, fred); + u3t_slog_memory(pri_l, " # open space", open_p, open); + u3t_slog_memory(pri_l, " + stack", stak_p, temp); + u3t_slog_memory(pri_l, " ~ immutable stack", imut_stak_p, imut_stak); + _slog_blank(pri_l); + u3t_slog_memory(pri_l, " $ allocation frame", imut_heap_p, imut_heap); +#ifdef U3_CPU_DEBUG + /* iff we are using CPU_DEBUG env var + ** we can report more facts: + ** max_w: max allocated on the current road (not global, not including child roads) + ** cel_d: max cells allocated in current road (inc closed kids, but not parents) + ** nox_d: nock steps performed in current road, less caching + */ + c3_w max = (u3R->all.max_w*4)+imut; + float max_p = _meme_percent(max, top); + c3_d cells = u3R->pro.cel_d; + c3_d nox = u3R->pro.nox_d; + u3t_slog_memory(pri_l, " | road max memory", max_p, max); + _slog_blank(pri_l); + u3t_slog_steps(pri_l, " road cells made", cells); + u3t_slog_steps(pri_l, " road nocks made", nox); +#endif + if ( u3a_is_north(u3R) == c3y ) { + u3t_slog_cap(pri_l, u3i_string(" road direction"), u3i_string(" North")); + } else { + u3t_slog_cap(pri_l, u3i_string(" road direction"), u3i_string(" South")); + } + _slog_road_depth(pri_l, u3R, 1); + _slog_blank(pri_l); + + // warn if any sanity checks have failed + if (full_p != (100.0 - imut_p)) + u3t_slog_cap(3, u3i_string("error"), u3i_string("road != (loom - immutable)")); + if (100.0 < (imut_heap_p + heap_p + free_p + open_p + stak_p + imut_stak_p)) + u3t_slog_cap(3, u3i_string("error"), u3i_string("loom sums over 100%")); + + struct _report_bar bar = _report_bargraph( + imut_heap_p, + heap_p, + free_p, + open_p, + stak_p, + imut_stak_p + ); + int dol = (int) _roundf(imut_heap_p/100); + bar.s[dol] = '$'; +#ifdef U3_CPU_DEBUG + // iff we have a max_p we will render it into the bar graph + // in other words iff we have max_p it will always replace something + c3_w inc_max = (max_p > imut_heap_p+1.0) ? (c3_w) max_p+0.5 : (c3_w) imut_heap_p+1.5; + if (max_p > 0.0) bar.s[inc_max] = '|'; +#endif + // TODO: not sure we really need _slog_free_discrepancy() + //_slog_free_discrepancy(); + u3t_slog_cap(pri_l, u3i_string("Loom"), u3i_string(bar.s)); +} + +int +_size_prefix(unsigned int wor_w) +{ + return + (wor_w / 1000000000) ? 'G': + (wor_w % 1000000000) / 1000000 ? 'M': + (wor_w % 1000000) / 1000 ? 'K': + (wor_w % 1000) ? ' ': + 'X'; +} + +// create a struct to allow passing around a fixed size string +struct _report { + char s[32]; +}; + +struct _report +report_string(unsigned int wor_w) +{ + struct _report r = { + .s = " " + }; + // add the G/M/K prefix + r.s[24] = _size_prefix(wor_w); + // consume wor_w into a string one base-10 digit at a time + // including dot formatting + unsigned int i = 0, j = 0; + while (wor_w > 0) { + if (j == 3) { + r.s[22-i] = '.'; + i++; + j = 0; + } else { + r.s[22-i] = (wor_w%10)+'0'; + wor_w /= 10; + i++; + j++; + } + } + // return our fixed size string within a struct + return r; +} + +void +u3t_slog_memory(c3_l pri_l, c3_c* cap_c, float percent, c3_w wor_w) +{ + // create the report string and apply it to our char array s + struct _report r = report_string(wor_w); + // add the Bytes postfix to the size report + r.s[25] = 'B'; + + // add the space-percentage into the report + r.s[2] = '0', r.s[3] = '.', r.s[4] = '0', r.s[5] = '0'; + int per_int = (int) (percent*100); + unsigned int i = 0; + while (per_int > 0 && i < 6) { + if (i == 2) { + r.s[5-i] = '.'; + } else { + r.s[5-i] = (per_int%10)+'0'; + per_int /= 10; + } + i++; + } + // add the percent sign + r.s[6] = '%'; + // slog it and go home + u3t_slog_cap(pri_l, u3i_string(cap_c), u3i_string(r.s)); +} + + +void +u3t_slog_steps(c3_l pri_l, c3_c* cap_c, c3_d sep_d) +{ + struct _report r = report_string(sep_d); + u3t_slog_cap(pri_l, u3i_string(cap_c), u3i_string(r.s)); +} + + +/* u3t_render_bytecode(): collect the bytecode data +** for the expression wrapped in the calling hint +** and +* +u3_noun +u3t_render_bytecode(c3_y* pog, c3_w her_w) +{ + //NOTE: this is basically the slog_byecode() function in nock.c +} +*/ +