From 4e22988865dbb385582bf9ea26151a151d98568d Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 5 Jun 2013 18:35:40 +0100 Subject: [PATCH] Remove diag facility. Copied from Perforce Change: 182553 ServerID: perforce.ravenbrook.com --- mps/code/arenavm.c | 89 +---- mps/code/chain.h | 10 +- mps/code/comm.gmk | 15 +- mps/code/commpre.nmk | 6 +- mps/code/config.h | 41 --- mps/code/diag.c | 773 ------------------------------------------- mps/code/event.h | 22 +- mps/code/eventdef.h | 65 +++- mps/code/global.c | 19 +- mps/code/locus.c | 11 +- mps/code/mpm.c | 16 +- mps/code/mpm.h | 111 +------ mps/code/mps.c | 1 - mps/code/poolamc.c | 64 +--- mps/code/poolmrg.c | 3 - mps/code/trace.c | 145 +------- mps/code/vmix.c | 17 +- mps/design/diag.txt | 222 +++---------- 18 files changed, 208 insertions(+), 1422 deletions(-) delete mode 100644 mps/code/diag.c diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c index 4095740d61d..f94632d3adf 100644 --- a/mps/code/arenavm.c +++ b/mps/code/arenavm.c @@ -1135,12 +1135,7 @@ static Res vmArenaExtend(VMArena vmArena, Size size) } while(0); EVENT3(vmArenaExtendStart, size, chunkSize, - VMArenaReserved(VMArena2Arena(vmArena))); - DIAG_SINGLEF(( "vmArenaExtend_Start", - "to accommodate size $W, try chunkSize $W", (WriteFW)size, (WriteFW)chunkSize, - " (VMArenaReserved currently $W bytes)\n", - (WriteFW)VMArenaReserved(VMArena2Arena(vmArena)), - NULL )); + VMArenaReserved(VMArena2Arena(vmArena))); /* .chunk-create.fail: If we fail, try again with a smaller size */ { @@ -1163,12 +1158,7 @@ static Res vmArenaExtend(VMArena vmArena, Size size) for(; chunkSize > chunkHalf; chunkSize -= sliceSize) { if(chunkSize < chunkMin) { EVENT2(vmArenaExtendFail, chunkMin, - VMArenaReserved(VMArena2Arena(vmArena))); - DIAG_SINGLEF(( "vmArenaExtend_FailMin", - "no remaining address-space chunk >= min($W)", (WriteFW)chunkMin, - " (so VMArenaReserved remains $W bytes)\n", - (WriteFW)VMArenaReserved(VMArena2Arena(vmArena)), - NULL )); + VMArenaReserved(VMArena2Arena(vmArena))); return ResRESOURCE; } res = VMChunkCreate(&newChunk, vmArena, chunkSize); @@ -1179,14 +1169,7 @@ static Res vmArenaExtend(VMArena vmArena, Size size) } vmArenaExtend_Done: - EVENT2(vmArenaExtendDone, chunkSize, VMArenaReserved(VMArena2Arena(vmArena))); - DIAG_SINGLEF(( "vmArenaExtend_Done", - "Request for new chunk of VM $W bytes succeeded", (WriteFW)chunkSize, - " (VMArenaReserved now $W bytes)\n", - (WriteFW)VMArenaReserved(VMArena2Arena(vmArena)), - NULL )); - return res; } @@ -1677,46 +1660,17 @@ static void VMFree(Addr base, Size size, Pool pool) } -/* M_whole, M_frac -- print count of bytes as Megabytes - * - * Split into a whole number of MB, "m" for the decimal point, and - * then the decimal fraction (thousandths of a MB, ie. kB). - * - * Input: 208896 - * Output: (Megabytes) 0m209 - */ -#define bPerM ((Size)1000000) /* Megabytes */ -#define bThou ((Size)1000) -DIAG_DECL( -static Count M_whole(Size bytes) -{ - Count M; /* MBs */ - M = (bytes + (bThou / 2)) / bPerM; - return M; -} -static Count M_frac(Size bytes) -{ - Count Mthou; /* thousandths of a MB */ - Mthou = (bytes + (bThou / 2)) / bThou; - Mthou = Mthou % 1000; - return Mthou; -} -) - - static void VMCompact(Arena arena, Trace trace) { VMArena vmArena; Ring node, next; - DIAG_DECL( Size vmem1; ) + Size vmem1; vmArena = Arena2VMArena(arena); AVERT(VMArena, vmArena); AVERT(Trace, trace); - DIAG( - vmem1 = VMArenaReserved(arena); - ); + vmem1 = VMArenaReserved(arena); /* Destroy any empty chunks (except the primary). */ sparePagesPurge(vmArena); @@ -1728,44 +1682,19 @@ static void VMCompact(Arena arena, Trace trace) } } - DIAG( + { Size vmem0 = trace->preTraceArenaReserved; Size vmem2 = VMArenaReserved(arena); - Size vmemD = vmem1 - vmem2; - Size live = trace->forwardedSize + trace->preservedInPlaceSize; - Size livePerc = 0; - if(trace->condemned / 100 != 0) - livePerc = live / (trace->condemned / 100); - - /* VMCompact diag: emit for all client-requested collections, */ + /* VMCompact event: emit for all client-requested collections, */ /* plus any others where chunks were gained or lost during the */ /* collection. */ if(trace->why == TraceStartWhyCLIENTFULL_INCREMENTAL || trace->why == TraceStartWhyCLIENTFULL_BLOCK || vmem0 != vmem1 - || vmem1 != vmem2) { - DIAG_SINGLEF(( "VMCompact", - "pre-collection vmem was $Um$3, ", - (WriteFU)M_whole(vmem0), (WriteFU)M_frac(vmem0), - "peaked at $Um$3, ", (WriteFU)M_whole(vmem1), (WriteFU)M_frac(vmem1), - "released $Um$3, ", (WriteFU)M_whole(vmemD), (WriteFU)M_frac(vmemD), - "now $Um$3", (WriteFU)M_whole(vmem2), (WriteFU)M_frac(vmem2), - " (why $U", (WriteFU)trace->why, - ": $Um$3", - (WriteFU)M_whole(trace->condemned), (WriteFU)M_frac(trace->condemned), - "[->$Um$3", (WriteFU)M_whole(live), (WriteFU)M_frac(live), - " $U%-live", (WriteFU)livePerc, - " $Um$3-stuck]", - (WriteFU)M_whole(trace->preservedInPlaceSize), - (WriteFU)M_frac(trace->preservedInPlaceSize), - " ($Um$3-not)", - (WriteFU)M_whole(trace->notCondemned), - (WriteFU)M_frac(trace->notCondemned), - " )", - NULL)); - } - ); + || vmem1 != vmem2) + EVENT3(VMCompact, vmem0, vmem1, vmem2); + } } mps_res_t mps_arena_vm_growth(mps_arena_t mps_arena, diff --git a/mps/code/chain.h b/mps/code/chain.h index 0d2be1de068..0ef5e2ff9f0 100644 --- a/mps/code/chain.h +++ b/mps/code/chain.h @@ -51,11 +51,11 @@ typedef struct PoolGenStruct { RingStruct genRing; Size totalSize; /* total size of segs in gen in this pool */ Size newSize; /* size allocated since last GC */ - /* newSize when TraceCreate is called. This is for diagnostic */ - /* purposes only. It's used in a DIAG message emitted in TraceStart; */ - /* at that time, newSize has already been diminished by Whiten so we */ - /* can't use that value. This will not work well with multiple */ - /* traces. */ + /* newSize when TraceCreate was called. This is used in the + * TraceStartPoolGen event emitted at the start of a trace; at that + * time, newSize has already been diminished by Whiten so we can't + * use that value. TODO: This will not work well with multiple + * traces. */ Size newSizeAtCreate; } PoolGenStruct; diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index 40d2a8f6a3c..9146ed7b779 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -131,10 +131,6 @@ ifeq ($(VARIETY),hot) CFLAGS=$(CFLAGSCOMMON) $(CFHOT) CFLAGSLAX=$(CFLAGSCOMMONLAX) $(CFHOT) else -ifeq ($(VARIETY),diag) -CFLAGS=$(CFLAGSCOMMON) $(CFDIAG) -CFLAGSLAX=$(CFLAGSCOMMONLAX) $(CFDIAG) -else ifeq ($(VARIETY),cool) CFLAGS=$(CFLAGSCOMMON) $(CFCOOL) CFLAGSLAX=$(CFLAGSCOMMONLAX) $(CFCOOL) @@ -168,10 +164,10 @@ FMTHETST = fmthe.c fmtdy.c fmtno.c fmtdytst.c PLINTH = mpsliban.c mpsioan.c EVENTPROC = eventcnv.c eventpro.c table.c MPMCOMMON = abq.c arena.c arenacl.c arenavm.c arg.c boot.c bt.c \ - buffer.c cbs.c dbgpool.c dbgpooli.c diag.c event.c format.c \ - global.c ld.c locus.c message.c meter.c mpm.c mpsi.c pool.c \ - poolabs.c poolmfs.c poolmrg.c poolmv.c protocol.c ref.c reserv.c \ - ring.c root.c sac.c seg.c shield.c splay.c ss.c table.c trace.c \ + buffer.c cbs.c dbgpool.c dbgpooli.c event.c format.c global.c \ + ld.c locus.c message.c meter.c mpm.c mpsi.c pool.c poolabs.c \ + poolmfs.c poolmrg.c poolmv.c protocol.c ref.c reserv.c ring.c \ + root.c sac.c seg.c shield.c splay.c ss.c table.c trace.c \ traceanc.c tract.c walk.c MPM = $(MPMCOMMON) $(MPMPF) @@ -326,9 +322,6 @@ endif $(PFM)/rash/mps.a: $(PFM)/rash/mps.o $(PFM)/hot/mps.a: $(PFM)/hot/mps.o -$(PFM)/diag/mps.a: \ - $(MPMOBJ) $(AMCOBJ) $(AMSOBJ) $(AWLOBJ) $(LOOBJ) $(SNCOBJ) \ - $(MV2OBJ) $(MVFFOBJ) $(PLINTHOBJ) $(POOLNOBJ) $(PFM)/cool/mps.a: \ $(MPMOBJ) $(AMCOBJ) $(AMSOBJ) $(AWLOBJ) $(LOOBJ) $(SNCOBJ) \ $(MV2OBJ) $(MVFFOBJ) $(PLINTHOBJ) $(POOLNOBJ) diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk index eb49c3259b3..4d1af5079a0 100644 --- a/mps/code/commpre.nmk +++ b/mps/code/commpre.nmk @@ -88,9 +88,9 @@ ALL_TARGETS=$(LIB_TARGETS) $(AUTO_TEST_TARGETS) $(OTHER_TEST_TARGETS) $(EXTRA_TA # %%PART: When adding a new part, add the sources for the new part here. MPMCOMMON = \ - \ - \ - \ + \ + \ + \ \ \ diff --git a/mps/code/config.h b/mps/code/config.h index f355added0d..445784a7048 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -39,29 +39,6 @@ /* no telemetry log events */ -/* CONFIG_VAR_DIAG -- diagnostic variety - * - * Deprecated. The diagnostic variety prints messages about the internals - * of the MPS to an output stream. This is being replaced by an extended - * telemetry system. RB 2012-08-31 - */ - -#elif defined(CONFIG_VAR_DIAG) /* Diagnostic variety */ -#define CONFIG_ASSERT -#define CONFIG_ASSERT_ABORT -#ifndef CHECKLEVEL -#define CHECKLEVEL CheckLevelMINIMAL -#endif -#define CONFIG_STATS -/* For diagnostics, choose a DIAG_WITH_... output method. - * (We need to choose because the DIAG output system is under - * development. RHSK 2007-05-21). - */ -#define DIAG_WITH_STREAM_AND_WRITEF -/* #define DIAG_WITH_PRINTF */ -#define CONFIG_LOG - - /* CONFIG_VAR_COOL -- cool variety * * The cool variety is intended for use when developing an integration with @@ -129,10 +106,6 @@ #if defined(CONFIG_STATS) /* CONFIG_STATS = STATISTICS = METERs */ -/* Note: the STATISTICS define used to be called "DIAGNOSTICS" (even */ -/* though it controls the STATISTIC system), but the term */ -/* "diagnostic" means something else now: see design/diag/. */ -/* RHSK 2007-06-28 */ /* WARNING: this may change the size and fields of MPS structs */ /* (...but see STATISTIC_DECL, which is invariant) */ #define STATISTICS @@ -414,20 +387,6 @@ #define ASSERT_BUFFER_SIZE ((Size)512) -/* Diagnostics Buffer */ - -#ifdef DIAG_WITH_STREAM_AND_WRITEF -/* DIAG_BUFFER_SIZE: 100 screenfuls: 100x80x25 = 200000 */ -#define DIAG_BUFFER_SIZE ((Size)200000) -#else -#define DIAG_BUFFER_SIZE ((Size)1) -#endif - -#define DIAG_PREFIX_TAGSTART "MPS." -#define DIAG_PREFIX_LINE " " -#define DIAG_PREFIX_TAGEND "" - - /* memory operator configuration * * We need efficient operators similar to memcpy, memset, and memcmp. diff --git a/mps/code/diag.c b/mps/code/diag.c deleted file mode 100644 index 289e7fd77c6..00000000000 --- a/mps/code/diag.c +++ /dev/null @@ -1,773 +0,0 @@ -/* diag.c: MEMORY POOL MANAGER DIAGNOSTICS - * - * $Id$ - * Copyright (c) 2007 Ravenbrook Limited. See end of file for license. - * - * To Do: [RHSK 2007-08-13] - * @@ sigs and AVERTs for Rule, and macro for Rules initializer - * @@ deprecate un-tagged diags, remove old macros - * @@ every diag should end with \n: warn if this is missing. - */ - -#include - -#include "mpm.h" -#include "mpslib.h" /* for mps_lib_stdout */ - -#if defined(DIAG_WITH_STREAM_AND_WRITEF) - -typedef struct RuleStruct { - const char *action; - const char *tag; - const char *para; - const char *line; - int tpMatch; /* .tpmatch */ - /* @@ needs sig; (at end, to make initializer expression easy?) */ -} *Rule; - - -/* RulesGlobal -- throw away some diags (see INSTRUCTIONS below) */ - -struct RuleStruct RulesGlobal[] = { - { "-", "*", "*", "*" }, - { "+", "DiagFilter_Rules", "*", "*" }, - { "+", "VMCompact", "*", "*" }, - /* ----v---- always on please (RHSK) ----v---- */ - { "+", "MPSVersion", "*", "*" }, - { "+", "traceSetSignalEmergency", "*", "*" }, - { NULL, "", "", "" } -}; - -struct RuleStruct RulesGlobal_RHSK[] = { - { "+", "*", "*", "*" }, - { "+", "DiagFilter_Rules", "*", "*" }, - { "-", "DIAGTEST_", "*", "*" }, - { "+", "AMCTraceEnd_pageret", "*", "*" }, - { "-", "ChainCondemnAuto", "*", "*" }, - { "+", "VM_ix_", "*", "*" }, - { "-", "vmArenaExtend_", "*", "*" }, - { "-", "traceFindGrey", "*", "*" }, - { "-", "TraceStart", "*", "*" }, - { "+", "TraceStart", "*", "controlPool" }, - { "+", "TraceStart", "*", "reserved" }, - { "+", "TraceStart", "*", "committed" }, - { "+", "TraceStart", "*", "genZoneSet" }, - { "-", "TraceStart", "because code 1", "*" }, - { "+", "VMCompact", "*", "*" }, - { "-", "VMCompact_hex", "*", "*" }, - { "+", "VM_ix_Create", "*", "*" }, - /* ----v---- always on please (RHSK) ----v---- */ - { "+", "traceSetSignalEmergency", "*", "*" }, - { NULL, "", "", "" } -}; - -struct RuleStruct RulesGlobalExample[] = { - { "+", "*", "*", "*" }, - { "+", "DiagFilter_Rules", "*", "*" }, - { "-", "DIAGTEST_", "*", "*" }, - { "+", "ChainCondemnAuto", "gens [0..0]", "*" }, - { "+", "TraceStart", "*", "*" }, - { "+", "TraceStart", "because code 1:", "*" }, - { "-", "TraceStart", "*", "controlPool" }, - { "-", "TraceStart", "*", "ommit" }, - { "-", "TraceStart", "*", "zoneShift" }, - { "-", "TraceStart", "*", "alignment" }, - { "-", "amcScanNailed-loop", "*", "*" }, - { NULL, "", "", "" } -}; - -/* RulesGlobal -- INSTRUCTIONS - * - * In your local copy of diag.c, you can modify RulesGlobal as you - * wish, to control what diags you see. - * - * Each rule consists of: action, tag, para, and line. A rule that - * matches on TAG, PARA and LINE determines what ACTION is taken - * for that line of that diag. Later rules override earlier rules, - * ie. the lowest matching rule wins. (And at least one rule must - * match, so the first rule should be a catch-all). - * - * ACTION = "+" (output this line of diag), or "-" (skip this line). - * - * TAG: does pattern (text or *) appear in diag's tag? - * - * PARA: does pattern (text or *) appear anywhere in diag's text output - * (does not match the tag)? - * - * LINE: does pattern (text or *) appear on this line of the diag - * text? - * - * Note: a diag that deliberately has no output, eg. - * DIAG_SINGLEF(( "MyTag", NULL )), - * is treated as having a single empty 'line'. See .empty-diag. - * - * Note: for help debugging your ruleset, see .rules.debug below. - * - * Note: the entire filtering mechanism can be turned off, so that - * diagnostics go immediately to mps_lib_stdout: see .filter-disable. - */ - - -/* Forward declarations */ - -static mps_lib_FILE *filterStream(void); -static int filterStream_fputc(int c, mps_lib_FILE *stream); -static int filterStream_fputs(const char *s, mps_lib_FILE *stream); -static void diag_test(void); - - -/* Stream -- output to filterStream or to a real mps_lib_FILE stream - * - * There are only two functions and two destinations; a full class - * hierarchy would be overkill! RHSK 2007-08-08. - */ - -int Stream_fputc(int c, mps_lib_FILE *stream) -{ - if(stream == filterStream()) - return filterStream_fputc(c, stream); - else - return mps_lib_fputc(c, stream); -} - -int Stream_fputs(const char *s, mps_lib_FILE *stream) -{ - if(stream == filterStream()) - return filterStream_fputs(s, stream); - else - return mps_lib_fputs(s, stream); -} - - -/* Diag -- a buffer to store a diagnostic - * - */ - -#define DiagSig ((Sig)0x519D1A99) /* SIGnature DIAG */ - -typedef struct DiagStruct { - Sig sig; - const char *tag; - Bool overflow; /* diag > buf? set flag, truncate, force output */ - Count n; - char buf[DIAG_BUFFER_SIZE]; -} *Diag; - -static Bool DiagCheck(Diag diag) -{ - CHECKS(Diag, diag); - CHECKL(diag->n <= sizeof(diag->buf)); - return TRUE; -} - - - -/* filterStream -- capable of filtering diagnostics - * - * This is not really an mps_lib_FILE*; it is a single global instance - * of a DiagStruct. - * - * Output is stored in a DiagStruct, to be filtered and output - * (or not) when complete. - */ - -static struct DiagStruct filterDiagGlobal = { DiagSig, NULL, FALSE, 0 }; - -static mps_lib_FILE *filterStream(void) -{ - return (mps_lib_FILE*)&filterDiagGlobal; -} - -/* filterStream_under: the underlying stream used to output diags */ -/* that pass the filter. */ -static mps_lib_FILE *filterStream_under(void) -{ - return mps_lib_stdout; -} - -/* .tpmatch: does this rule match current diag's tag and para? */ -enum { - TPMatch_Unknown = 0, /* initial value = 0 */ - TPMatch_Yes, - TPMatch_No -}; - -static void version_diag(void) -{ - DIAG_SINGLEF(( "MPSVersion", - "$S", (WriteFS)MPSVersion(), NULL )); -} - -static void rules_diag(Rule rules) -{ - Index ir; - - AVER(rules); - DIAG_FIRSTF(( "DiagFilter_Rules", - "Only showing diags permitted by these tag/paragraph/line" - " rules:\n", NULL )); - for(ir = 0; rules[ir].action != NULL; ir++) { - DIAG_DECL( Rule rule = &rules[ir]; ) - DIAG_MOREF(( "$S$S/$S/$S\n", (WriteFS)rule->action, (WriteFS)rule->tag, - (WriteFS)rule->para, (WriteFS)rule->line, - NULL )); - } - DIAG_END("DiagFilter_Rules"); -} - - -/* patternOccurs -- does patt occur in buf[i..j)? - * - * Returns true iff patt[0..pattLen) literally occurs in buf[i..j). - */ - -static Bool patternOccurs(const char *patt, Count pattLen, - const char *buf, Index i, Index j) -{ - Index im; /* start of tentative match */ - Index ip; /* index into patt */ - - AVER(patt); - AVER(buf); - AVER(i <= j); - - /* Search (naively) for patt anywhere inside buf[i..j) */ - for(im = i; im + pattLen <= j; im++) { - /* Consider upto pattLen chars starting at patt[0] and buf[im] */ - for(ip = 0; ip < pattLen; ip++) { - if(patt[ip] != buf[im + ip]) - break; - } - if(ip == pattLen) { - return TRUE; - } - } - - return FALSE; -} - -static Bool matchLine(Rule rule, Diag diag, Index i, Index j) -{ - AVER(rule); - AVER(diag); - AVER(i <= j); - AVER(j <= diag->n); - - if(rule->line[0] == '*') - return TRUE; - - return patternOccurs(rule->line, StringLength(rule->line), - diag->buf, i, j); -} - -static Bool matchPara(Rule rule, Diag diag) -{ - AVER(rule); - AVER(diag); - - if(rule->para[0] == '*') - return TRUE; - - return patternOccurs(rule->para, StringLength(rule->para), - diag->buf, 0, diag->n); -} - -static Bool matchTag(Rule rule, const char *tag) -{ - AVER(rule); - AVER(rule->tag); - AVER(tag); - - if(rule->tag[0] == '*') - return TRUE; - - return patternOccurs(rule->tag, StringLength(rule->tag), - tag, 0, StringLength(tag)); -} - -static void filterStream_LineOut(Diag diag, Index i, Index j) -{ - int r; - - AVER(diag); - AVER(i <= j); - AVER(j <= diag->n); - - r = Stream_fputs(DIAG_PREFIX_LINE, filterStream_under()); - AVER(r != mps_lib_EOF); - - for(; i < j; i++) { - char c; - c = diag->buf[i]; - r = Stream_fputc(c, filterStream_under()); - AVER(r != mps_lib_EOF); - } -} - - -/* filterStream_Output -- output this diag, if the rules select it - * - */ - -static void filterStream_Output(Diag diag, Rule rules) -{ - static Bool inside = FALSE; - Res res; - Count nr; - Index ir; - Index i, j; - Bool nolinesyet = TRUE; - Bool emptyonce; - - AVER(!inside); - inside = TRUE; - AVER(diag); - AVER(rules); - - if(diag->tag == NULL) - diag->tag = "(no tag)"; - - /* Count the rules */ - for(ir = 0; rules[ir].action != NULL; ir++) { - rules[ir].tpMatch = TPMatch_Unknown; - } - nr = ir; - - /* Filter */ - /* .empty-diag: Treat a diag that deliberately has no output, */ - /* eg: DIAG_SINGLEF(( "Tag", NULL )), as having a single empty */ - /* 'line'. This is the only time a line may be empty. */ - emptyonce = (diag->n == 0); - for(i = 0; emptyonce || i < diag->n; i = j) { - - /* Get the next line [i..j) */ - for(j = i; j < diag->n; j++) { - if(diag->buf[j] == '\n') { - j++; - break; - } - } - AVER(emptyonce || i < j); /* .empty-diag */ - emptyonce = FALSE; - - /* Find the lowest rule that matches it. */ - ir = nr - 1; - for(;;) { - Rule rule = &rules[ir]; - if(rule->tpMatch == TPMatch_Unknown) { - /* memoize .tpMatch */ - if(matchTag(rule, diag->tag) && matchPara(rule, diag)) { - rule->tpMatch = TPMatch_Yes; - } else { - rule->tpMatch = TPMatch_No; - } - } - if(rule->tpMatch == TPMatch_Yes && matchLine(rule, diag, i, j)) - break; - AVER(ir != 0); /* there must ALWAYS be a matching rule */ - ir--; - } - - /* Do the rule's action. */ - if(0) { - /* .rules.debug: Turn this on to show which rule applied. */ - Rule rule = &rules[ir]; - (void) WriteF(filterStream_under(), "[$U/$U:", ir, nr, - " $S$S/$S/$S] ", rule->action, rule->tag, - rule->para, rule->line, NULL); - } - if(rules[ir].action[0] == '+' || diag->overflow) { - if(nolinesyet) { - res = WriteF(filterStream_under(), - DIAG_PREFIX_TAGSTART "$S {", (WriteFS)diag->tag, NULL); - AVER(res == ResOK); - nolinesyet = FALSE; - } - filterStream_LineOut(diag, i, j); - } - } - - if(diag->overflow) { - res = WriteF(filterStream_under(), - "\n--- diagnostic too large: " - "forced to output, but truncated here ---\n" - "--- (for a bigger buffer, change DIAG_BUFFER_SIZE) ---\n", NULL); - AVER(res == ResOK); - } - if(!nolinesyet) { - res = WriteF(filterStream_under(), DIAG_PREFIX_TAGEND "}\n", NULL); - AVER(res == ResOK); - } - inside = FALSE; -} - -static void filterStream_TagBegin(mps_lib_FILE *stream, const char *tag) -{ - static Bool first = TRUE; - Diag diag; - - AVER(stream); - AVER(tag); - - diag = (Diag)stream; - AVERT(Diag, diag); - - if(first) { - first = FALSE; - version_diag(); - rules_diag(&RulesGlobal[0]); - diag_test(); - } - - if(diag->tag != NULL) { - /* Be helpful to the poor programmer! */ - (void) WriteF(filterStream_under(), - "\nWARNING: diag tag \"$S\" is still current" - " (missing DIAG_END()).", - diag->tag, NULL); - } - AVER(diag->tag == NULL); - - /* @@ when all diags are tagged, the buffer must be empty */ - /* @@ but for now, as a courtesy... */ - if(diag->n > 0) { - filterStream_Output(diag, &RulesGlobal[0]); - diag->n = 0; - } - - diag->tag = tag; - diag->overflow = FALSE; - AVER(diag->n == 0); -} - -static void filterStream_TagEnd(mps_lib_FILE *stream, const char *tag) -{ - Diag diag; - diag = (Diag)stream; - AVERT(Diag, diag); - - AVER(diag->tag != NULL); - - if(!StringEqual(diag->tag, tag)) { - /* Be helpful to the poor programmer! */ - (void) WriteF(filterStream_under(), - "\nWARNING: diag tag \"$S\" is current, " - "but got DIAG_END(\"$S\"). (They must match).", - (WriteFS)diag->tag, (WriteFS)tag, NULL); - } - AVER(StringEqual(diag->tag, tag)); - - /* Output the diag */ - filterStream_Output(diag, &RulesGlobal[0]); - - diag->tag = NULL; - diag->n = 0; -} - -static int filterStream_fputc(int c, mps_lib_FILE *stream) -{ - Diag diag; - - AVER(c != mps_lib_EOF); - AVER(stream == filterStream()); - - diag = (Diag)stream; - AVERT(Diag, diag); - /* @@ when all diags are tagged: AVER(diag->tag != NULL); */ - - /* AVER(diag->n + 1 <= sizeof(diag->buf)); */ - if(!(diag->n + 1 <= sizeof(diag->buf))) { - diag->overflow = TRUE; - /* ignore failure; do not return mps_lib_EOF */ - return c; - } - - /* add c to buffer */ - diag->buf[diag->n++] = (char)c; - return c; -} - -static int filterStream_fputs(const char *s, mps_lib_FILE *stream) -{ - Diag diag; - Count l; - Index i; - - AVER(s); - AVER(stream == filterStream()); - - diag = (Diag)stream; - AVERT(Diag, diag); - /* @@ when all diags are tagged: AVER(diag->tag != NULL); */ - - l = StringLength(s); - - /* AVER(diag->n + l <= sizeof(diag->buf)); */ - if(!(diag->n + l <= sizeof(diag->buf))) { - diag->overflow = TRUE; - /* ignore failure; do not return mps_lib_EOF */ - return 1; - } - - /* add s to buffer */ - for (i = 0; i < l; i++) { - diag->buf[diag->n++] = s[i]; - } - return 1; -} - - -/* DIAG_WITH_STREAM_AND_WRITEF -- Diagnostic output channel - * - * Only used for DIAG_WITH_STREAM_AND_WRITEF; see config.h. - */ - -Bool DiagEnabledGlobal = TRUE; - -Bool DiagIsOn(void) -{ - return DiagEnabledGlobal; -} - -mps_lib_FILE *DiagStream(void) -{ - /* .filter-disable: the entire filtering mechanism can be turned */ - /* off, so that diagnostics go immediately to mps_lib_stdout, */ - /* with no buffering or filtering. */ - Bool filter = TRUE; - - if(filter) { - return filterStream(); - } else { - return mps_lib_stdout; - } -} - -static void diagTagBegin(mps_lib_FILE *stream, const char *tag) -{ - AVER(stream); - AVER(tag); - - if(stream == filterStream()) { - filterStream_TagBegin(stream, tag); - } else { - Res res; - res = WriteF(stream, DIAG_PREFIX_TAGSTART "$S {\n", (WriteFS)tag, NULL); - AVER(res == ResOK); - } -} - -static void diagTagEnd(mps_lib_FILE *stream, const char *tag) -{ - AVER(stream); - AVER(tag); - - if(stream == filterStream()) { - filterStream_TagEnd(stream, tag); - } else { - Res res; - res = WriteF(stream, DIAG_PREFIX_TAGEND "}\n", tag, NULL); - AVER(res == ResOK); - } -} - - -/* Diag*F functions -- interface for general MPS code (via macros) - * - * These function manage TagBegin/End, and WriteF the text to - * DiagStream(). - * - * Direct writing to DiagStream() is also permitted (eg. from a - * Describe method). - */ - -void DiagSingleF(const char *tag, ...) -{ - va_list args; - Res res; - - diagTagBegin(DiagStream(), tag); - - va_start(args, tag); - res = WriteF_v(DiagStream(), args); - AVER(res == ResOK); - va_end(args); - - diagTagEnd(DiagStream(), tag); -} - -void DiagFirstF(const char *tag, ...) -{ - va_list args; - Res res; - - diagTagBegin(DiagStream(), tag); - - va_start(args, tag); - res = WriteF_v(DiagStream(), args); - AVER(res == ResOK); - va_end(args); -} - -void DiagMoreF(const char *firstformat, ...) -{ - va_list args; - Res res; - - /* ISO C says there must be at least one named parameter: hence */ - /* the named firstformat. It only looks different: there is no */ - /* change from the expected WriteF protocol. (In particular, */ - /* firstformat may legally be NULL, with the variable part empty). */ - - va_start(args, firstformat); - res = WriteF_firstformat_v(DiagStream(), firstformat, args); - AVER(res == ResOK); - va_end(args); -} - -void DiagEnd(const char *tag) -{ - diagTagEnd(DiagStream(), tag); -} - - -/* Test Code -- unit tests for this source file - * - * These are for developers to run if they modify this source file. - * There's no point running them otherwise. RHSK. - */ - -static void patternOccurs_test(Bool expect, const char *patt, - const char *text) -{ - Count pattLen = StringLength(patt); - Count textLen = StringLength(text); - enum {bufLen = 100}; - char buf[bufLen]; - Index start, i; - Count padLen; - Bool occurs; - - /* Call patternOccurs with this patt and text 3 times: each time */ - /* putting the text in the buffer at a different offset, to */ - /* verify that patternOccurs is not accepting matches outside the */ - /* [i..j) portion of the buffer. */ - - for(start = 0; start < 21; start += 7) { - AVER(bufLen > (start + textLen)); - /* put text into buf at start */ - for(i = 0; i < start; i++) { - buf[i] = 'X'; - } - for(i = 0; i < textLen; i++) { - (buf+start)[i] = text[i]; - } - padLen = bufLen - (start + textLen); - for(i = 0; i < padLen; i++) { - (buf+start+textLen)[i] = 'X'; - } - occurs = patternOccurs(patt, pattLen, buf, start, start+textLen); - AVER(occurs == expect); - } -} - -static void diag_test(void) -{ - DIAG_SINGLEF(( "DIAGTEST_Tag1", "text $U.\n", (WriteFU)42, NULL )); - - DIAG_SINGLEF(( "DIAGTEST_EmptyDiag", NULL )); - - DIAG_FIRSTF(( - "DIAGTEST_StringEqual", - "Fred = Fred: $U.\n", - StringEqual("Fred", "Fred"), - NULL - )); - DIAG_MOREF(("Fred = Tom: $U.\n", (WriteFU)StringEqual("Fred", "Tom"), NULL)); - DIAG_MOREF(("Tom = Fred: $U.\n", (WriteFU)StringEqual("Tom", "Fred"), NULL)); - DIAG_MOREF(("0 = Fred: $U.\n", (WriteFU)StringEqual("", "Fred"), NULL)); - DIAG_MOREF(("Fred = 0: $U.\n", (WriteFU)StringEqual("Fred", ""), NULL)); - DIAG_MOREF(("0 = 0: $U.\n", (WriteFU)StringEqual("", ""), NULL)); - DIAG_MOREF(("0 = 000: $U.\n", (WriteFU)StringEqual("", "\0\0"), NULL)); - DIAG_END("DIAGTEST_StringEqual"); - - DIAG_FIRSTF(( "DIAGTEST_patternOccurs", NULL )); - patternOccurs_test(TRUE, "Fred", "Fred"); - patternOccurs_test(TRUE, "Fred", "XFredX"); - patternOccurs_test(TRUE, "Fred", "FFred"); - patternOccurs_test(TRUE, "Fred", "FrFred"); - patternOccurs_test(TRUE, "Fred", "FreFred"); - patternOccurs_test(TRUE, "Fred", "FreFreFFred"); - patternOccurs_test(TRUE, "Fred", "FredFred"); - patternOccurs_test(TRUE, "Fred", "FFredFre"); - patternOccurs_test(TRUE, "Fred", "FrFredFr"); - patternOccurs_test(TRUE, "Fred", "FreFredF"); - patternOccurs_test(TRUE, "Fred", "FreFreFFredFre"); - patternOccurs_test(TRUE, "Fred", "FredFredF"); - patternOccurs_test(TRUE, "X", "X"); - patternOccurs_test(TRUE, "", "X"); - patternOccurs_test(TRUE, "", "Whatever"); - patternOccurs_test(FALSE, "Fred", "Tom"); - patternOccurs_test(FALSE, "X", "Tom"); - patternOccurs_test(FALSE, "X", "x"); - patternOccurs_test(FALSE, "X", ""); - patternOccurs_test(FALSE, "Whatever", ""); - patternOccurs_test(FALSE, "Fred", "Fre"); - patternOccurs_test(FALSE, "Fred", "red"); - patternOccurs_test(FALSE, "Fred", "Fxred"); - patternOccurs_test(FALSE, "Fred", "Frexd"); - DIAG_END("DIAGTEST_patternOccurs"); - -#if 0 - DIAG_FIRSTF(( "TestTag2", "text $U.\n", (WriteFU)42, NULL )); - DIAG_MOREF(( NULL )); - DIAG_MOREF(( "string $S.\n", (WriteFS)"fooey!", NULL )); - DIAG_MOREF(( NULL )); - DIAG_MOREF(( "Another string $S.\n", (WriteFS)"baloney!", NULL )); - DIAG_END( "TestTag2" ); -#endif -} - -#endif /* DIAG_WITH_STREAM_AND_WRITEF */ - - -/* C. COPYRIGHT AND LICENSE - * - * Copyright (C) 2007 Ravenbrook Limited . - * All rights reserved. This is an open source license. Contact - * Ravenbrook for commercial licensing options. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Redistributions in any form must be accompanied by information on how - * to obtain complete source code for this software and any accompanying - * software that uses this software. The source code must either be - * included in the distribution or be available for no more than the cost - * of distribution plus a nominal fee, and must be freely redistributable - * under reasonable conditions. For an executable file, complete source - * code means the source code for all modules it contains. It does not - * include source code for modules or files that typically accompany the - * major components of the operating system on which the executable file - * runs. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ diff --git a/mps/code/event.h b/mps/code/event.h index b16e2af4b9c..3e1463527ba 100644 --- a/mps/code/event.h +++ b/mps/code/event.h @@ -1,6 +1,6 @@ /* -- Event Logging Interface * - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license. * $Id$ * * READERSHIP @@ -95,7 +95,7 @@ extern Word EventKindControl; #define EVENT0(name) EVENT_BEGIN(name, sizeof(EventAnyStruct)) EVENT_END(name, sizeof(EventAnyStruct)) /* The following lines were generated with - python -c 'for i in range(1,15): print "#define EVENT%d(name, %s) EVENT_BEGIN(name, sizeof(Event##name##Struct)) %s EVENT_END(name, sizeof(Event##name##Struct))" % (i, ", ".join(["p%d" % j for j in range(0, i)]), " ".join(["_event->f%d = (p%d);" % (j, j) for j in range(0, i)]))' + python -c 'for i in range(1,22): print "#define EVENT%d(name, %s) EVENT_BEGIN(name, sizeof(Event##name##Struct)) %s EVENT_END(name, sizeof(Event##name##Struct))" % (i, ", ".join(["p%d" % j for j in range(0, i)]), " ".join(["_event->f%d = (p%d);" % (j, j) for j in range(0, i)]))' */ #define EVENT1(name, p0) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); EVENT_END(name, sizeof(Event##name##Struct)) #define EVENT2(name, p0, p1) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); _event->f1 = (p1); EVENT_END(name, sizeof(Event##name##Struct)) @@ -111,6 +111,13 @@ extern Word EventKindControl; #define EVENT12(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); _event->f1 = (p1); _event->f2 = (p2); _event->f3 = (p3); _event->f4 = (p4); _event->f5 = (p5); _event->f6 = (p6); _event->f7 = (p7); _event->f8 = (p8); _event->f9 = (p9); _event->f10 = (p10); _event->f11 = (p11); EVENT_END(name, sizeof(Event##name##Struct)) #define EVENT13(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); _event->f1 = (p1); _event->f2 = (p2); _event->f3 = (p3); _event->f4 = (p4); _event->f5 = (p5); _event->f6 = (p6); _event->f7 = (p7); _event->f8 = (p8); _event->f9 = (p9); _event->f10 = (p10); _event->f11 = (p11); _event->f12 = (p12); EVENT_END(name, sizeof(Event##name##Struct)) #define EVENT14(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); _event->f1 = (p1); _event->f2 = (p2); _event->f3 = (p3); _event->f4 = (p4); _event->f5 = (p5); _event->f6 = (p6); _event->f7 = (p7); _event->f8 = (p8); _event->f9 = (p9); _event->f10 = (p10); _event->f11 = (p11); _event->f12 = (p12); _event->f13 = (p13); EVENT_END(name, sizeof(Event##name##Struct)) +#define EVENT15(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); _event->f1 = (p1); _event->f2 = (p2); _event->f3 = (p3); _event->f4 = (p4); _event->f5 = (p5); _event->f6 = (p6); _event->f7 = (p7); _event->f8 = (p8); _event->f9 = (p9); _event->f10 = (p10); _event->f11 = (p11); _event->f12 = (p12); _event->f13 = (p13); _event->f14 = (p14); EVENT_END(name, sizeof(Event##name##Struct)) +#define EVENT16(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); _event->f1 = (p1); _event->f2 = (p2); _event->f3 = (p3); _event->f4 = (p4); _event->f5 = (p5); _event->f6 = (p6); _event->f7 = (p7); _event->f8 = (p8); _event->f9 = (p9); _event->f10 = (p10); _event->f11 = (p11); _event->f12 = (p12); _event->f13 = (p13); _event->f14 = (p14); _event->f15 = (p15); EVENT_END(name, sizeof(Event##name##Struct)) +#define EVENT17(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); _event->f1 = (p1); _event->f2 = (p2); _event->f3 = (p3); _event->f4 = (p4); _event->f5 = (p5); _event->f6 = (p6); _event->f7 = (p7); _event->f8 = (p8); _event->f9 = (p9); _event->f10 = (p10); _event->f11 = (p11); _event->f12 = (p12); _event->f13 = (p13); _event->f14 = (p14); _event->f15 = (p15); _event->f16 = (p16); EVENT_END(name, sizeof(Event##name##Struct)) +#define EVENT18(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); _event->f1 = (p1); _event->f2 = (p2); _event->f3 = (p3); _event->f4 = (p4); _event->f5 = (p5); _event->f6 = (p6); _event->f7 = (p7); _event->f8 = (p8); _event->f9 = (p9); _event->f10 = (p10); _event->f11 = (p11); _event->f12 = (p12); _event->f13 = (p13); _event->f14 = (p14); _event->f15 = (p15); _event->f16 = (p16); _event->f17 = (p17); EVENT_END(name, sizeof(Event##name##Struct)) +#define EVENT19(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); _event->f1 = (p1); _event->f2 = (p2); _event->f3 = (p3); _event->f4 = (p4); _event->f5 = (p5); _event->f6 = (p6); _event->f7 = (p7); _event->f8 = (p8); _event->f9 = (p9); _event->f10 = (p10); _event->f11 = (p11); _event->f12 = (p12); _event->f13 = (p13); _event->f14 = (p14); _event->f15 = (p15); _event->f16 = (p16); _event->f17 = (p17); _event->f18 = (p18); EVENT_END(name, sizeof(Event##name##Struct)) +#define EVENT20(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); _event->f1 = (p1); _event->f2 = (p2); _event->f3 = (p3); _event->f4 = (p4); _event->f5 = (p5); _event->f6 = (p6); _event->f7 = (p7); _event->f8 = (p8); _event->f9 = (p9); _event->f10 = (p10); _event->f11 = (p11); _event->f12 = (p12); _event->f13 = (p13); _event->f14 = (p14); _event->f15 = (p15); _event->f16 = (p16); _event->f17 = (p17); _event->f18 = (p18); _event->f19 = (p19); EVENT_END(name, sizeof(Event##name##Struct)) +#define EVENT21(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); _event->f1 = (p1); _event->f2 = (p2); _event->f3 = (p3); _event->f4 = (p4); _event->f5 = (p5); _event->f6 = (p6); _event->f7 = (p7); _event->f8 = (p8); _event->f9 = (p9); _event->f10 = (p10); _event->f11 = (p11); _event->f12 = (p12); _event->f13 = (p13); _event->f14 = (p14); _event->f15 = (p15); _event->f16 = (p16); _event->f17 = (p17); _event->f18 = (p18); _event->f19 = (p19); _event->f20 = (p20); EVENT_END(name, sizeof(Event##name##Struct)) #else /* EVENT not */ @@ -118,7 +125,7 @@ extern Word EventKindControl; #define EVENT0(name) NOOP /* The following lines were generated with - python -c 'for i in range(1,15): print "#define EVENT%d(name, %s) BEGIN %s END" % (i, ", ".join(["p%d" % j for j in range(0, i)]), " ".join(["UNUSED(p%d);" % j for j in range(0, i)]))' + python -c 'for i in range(1,22): print "#define EVENT%d(name, %s) BEGIN %s END" % (i, ", ".join(["p%d" % j for j in range(0, i)]), " ".join(["UNUSED(p%d);" % j for j in range(0, i)]))' */ #define EVENT1(name, p0) BEGIN UNUSED(p0); END #define EVENT2(name, p0, p1) BEGIN UNUSED(p0); UNUSED(p1); END @@ -134,6 +141,13 @@ extern Word EventKindControl; #define EVENT12(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) BEGIN UNUSED(p0); UNUSED(p1); UNUSED(p2); UNUSED(p3); UNUSED(p4); UNUSED(p5); UNUSED(p6); UNUSED(p7); UNUSED(p8); UNUSED(p9); UNUSED(p10); UNUSED(p11); END #define EVENT13(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12) BEGIN UNUSED(p0); UNUSED(p1); UNUSED(p2); UNUSED(p3); UNUSED(p4); UNUSED(p5); UNUSED(p6); UNUSED(p7); UNUSED(p8); UNUSED(p9); UNUSED(p10); UNUSED(p11); UNUSED(p12); END #define EVENT14(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13) BEGIN UNUSED(p0); UNUSED(p1); UNUSED(p2); UNUSED(p3); UNUSED(p4); UNUSED(p5); UNUSED(p6); UNUSED(p7); UNUSED(p8); UNUSED(p9); UNUSED(p10); UNUSED(p11); UNUSED(p12); UNUSED(p13); END +#define EVENT15(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14) BEGIN UNUSED(p0); UNUSED(p1); UNUSED(p2); UNUSED(p3); UNUSED(p4); UNUSED(p5); UNUSED(p6); UNUSED(p7); UNUSED(p8); UNUSED(p9); UNUSED(p10); UNUSED(p11); UNUSED(p12); UNUSED(p13); UNUSED(p14); END +#define EVENT16(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15) BEGIN UNUSED(p0); UNUSED(p1); UNUSED(p2); UNUSED(p3); UNUSED(p4); UNUSED(p5); UNUSED(p6); UNUSED(p7); UNUSED(p8); UNUSED(p9); UNUSED(p10); UNUSED(p11); UNUSED(p12); UNUSED(p13); UNUSED(p14); UNUSED(p15); END +#define EVENT17(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16) BEGIN UNUSED(p0); UNUSED(p1); UNUSED(p2); UNUSED(p3); UNUSED(p4); UNUSED(p5); UNUSED(p6); UNUSED(p7); UNUSED(p8); UNUSED(p9); UNUSED(p10); UNUSED(p11); UNUSED(p12); UNUSED(p13); UNUSED(p14); UNUSED(p15); UNUSED(p16); END +#define EVENT18(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17) BEGIN UNUSED(p0); UNUSED(p1); UNUSED(p2); UNUSED(p3); UNUSED(p4); UNUSED(p5); UNUSED(p6); UNUSED(p7); UNUSED(p8); UNUSED(p9); UNUSED(p10); UNUSED(p11); UNUSED(p12); UNUSED(p13); UNUSED(p14); UNUSED(p15); UNUSED(p16); UNUSED(p17); END +#define EVENT19(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18) BEGIN UNUSED(p0); UNUSED(p1); UNUSED(p2); UNUSED(p3); UNUSED(p4); UNUSED(p5); UNUSED(p6); UNUSED(p7); UNUSED(p8); UNUSED(p9); UNUSED(p10); UNUSED(p11); UNUSED(p12); UNUSED(p13); UNUSED(p14); UNUSED(p15); UNUSED(p16); UNUSED(p17); UNUSED(p18); END +#define EVENT20(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19) BEGIN UNUSED(p0); UNUSED(p1); UNUSED(p2); UNUSED(p3); UNUSED(p4); UNUSED(p5); UNUSED(p6); UNUSED(p7); UNUSED(p8); UNUSED(p9); UNUSED(p10); UNUSED(p11); UNUSED(p12); UNUSED(p13); UNUSED(p14); UNUSED(p15); UNUSED(p16); UNUSED(p17); UNUSED(p18); UNUSED(p19); END +#define EVENT21(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20) BEGIN UNUSED(p0); UNUSED(p1); UNUSED(p2); UNUSED(p3); UNUSED(p4); UNUSED(p5); UNUSED(p6); UNUSED(p7); UNUSED(p8); UNUSED(p9); UNUSED(p10); UNUSED(p11); UNUSED(p12); UNUSED(p13); UNUSED(p14); UNUSED(p15); UNUSED(p16); UNUSED(p17); UNUSED(p18); UNUSED(p19); UNUSED(p20); END #endif /* EVENT */ @@ -144,7 +158,7 @@ extern Word EventKindControl; /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2013 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/eventdef.h b/mps/code/eventdef.h index ca5609962f8..fa2940011da 100644 --- a/mps/code/eventdef.h +++ b/mps/code/eventdef.h @@ -1,7 +1,7 @@ /* -- Event Logging Definitions * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license. * * .source: * @@ -68,7 +68,7 @@ */ #define EventNameMAX ((size_t)19) -#define EventCodeMAX ((EventCode)0x0078) +#define EventCodeMAX ((EventCode)0x0082) #define EVENT_LIST(EVENT, X) \ /* 0123456789012345678 <- don't exceed without changing EventNameMAX */ \ @@ -184,11 +184,14 @@ EVENT(X, EventClockSync , 0x0075, TRUE, Arena) \ EVENT(X, ArenaAccess , 0x0076, TRUE, Arena) \ EVENT(X, ArenaPoll , 0x0077, TRUE, Arena) \ - EVENT(X, ArenaSetEmergency , 0x0078, TRUE, Arena) - + EVENT(X, ArenaSetEmergency , 0x0078, TRUE, Arena) \ + EVENT(X, VMCompact , 0x0079, TRUE, Arena) \ + EVENT(X, amcScanNailed , 0x0080, TRUE, Seg) \ + EVENT(X, AMCTraceEnd , 0x0081, TRUE, Trace) \ + EVENT(X, TraceStartPoolGen , 0x0082, TRUE, Trace) -/* Remember to update EventNameMAX and EventCodeMAX in eventcom.h! +/* Remember to update EventNameMAX and EventCodeMAX above! (These are checked in EventInit.) */ @@ -668,12 +671,62 @@ PARAM(X, 6, W, white) /* white reference set */ \ PARAM(X, 7, W, rate) /* segs to scan per increment */ +#define EVENT_VMCompact_PARAMS(PARAM, X) \ + PARAM(X, 0, W, vmem0) /* pre-collection reserved size */ \ + PARAM(X, 1, W, vmem1) /* pre-compact reseved size*/ \ + PARAM(X, 2, W, vmem2) /* post-compact reserved size */ + +#define EVENT_amcScanNailed_PARAMS(PARAM, X) \ + PARAM(X, 0, W, loops) /* number of times around the loop */ \ + PARAM(X, 1, W, summary) /* summary of segment being scanned */ \ + PARAM(X, 2, W, white) /* scan state white set */ \ + PARAM(X, 3, W, unfixed) /* scan state unfixed summary */ \ + PARAM(X, 4, W, fixed) /* scan state fixed summary */ \ + PARAM(X, 5, W, refset) /* scan state refset */ + +#define EVENT_AMCTraceEnd_PARAMS(PARAM, X) \ + PARAM(X, 0, W, epoch) /* current arena epoch */ \ + PARAM(X, 1, U, why) /* reason trace started */ \ + PARAM(X, 2, W, align) /* arena alignment */ \ + PARAM(X, 3, W, large) /* AMCLargeSegPAGES */ \ + PARAM(X, 4, W, pRetMin) /* threshold for event */ \ + /* remaining parameters are copy of PageRetStruct, which see */ \ + PARAM(X, 5, W, pCond) \ + PARAM(X, 6, W, pRet) \ + PARAM(X, 7, W, pCS) \ + PARAM(X, 8, W, pRS) \ + PARAM(X, 9, W, sCM) \ + PARAM(X, 10, W, pCM) \ + PARAM(X, 11, W, sRM) \ + PARAM(X, 12, W, pRM) \ + PARAM(X, 13, W, pRM1) \ + PARAM(X, 14, W, pRMrr) \ + PARAM(X, 15, W, pRMr1) \ + PARAM(X, 16, W, sCL) \ + PARAM(X, 17, W, pCL) \ + PARAM(X, 18, W, sRL) \ + PARAM(X, 19, W, pRL) \ + PARAM(X, 20, W, pRLr) + +#define EVENT_TraceStartPoolGen_PARAMS(PARAM, X) \ + PARAM(X, 0, P, chain) /* chain (or NULL for topGen) */ \ + PARAM(X, 1, B, top) /* 1 for topGen, 0 otherwise */ \ + PARAM(X, 2, W, index) /* index of generation in the chain */ \ + PARAM(X, 3, P, gendesc) /* generation description */ \ + PARAM(X, 4, W, capacity) /* capacity of generation */ \ + PARAM(X, 5, D, mortality) /* mortality of generation */ \ + PARAM(X, 6, W, zone) /* zone set of generation */ \ + PARAM(X, 7, P, pool) /* pool */ \ + PARAM(X, 8, W, serial) /* pool gen serial number */ \ + PARAM(X, 9, W, totalSize) /* total size of pool gen */ \ + PARAM(X, 10, W, newSizeAtCreate) /* new size of pool gen at trace create */ + #endif /* eventdef_h */ /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2013 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/global.c b/mps/code/global.c index 1ba7db30d86..eb624509620 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -1,7 +1,7 @@ /* global.c: ARENA-GLOBAL INTERFACES * * $Id$ - * Copyright (c) 2001,2003 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * * .sources: See . design.mps.thread-safety is relevant @@ -447,24 +447,17 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals) TraceIdMessagesDestroy(arena, ti); TRACE_SET_ITER_END(ti, trace, TraceSetUNIV, arena); - /* report dropped messages (currently in diagnostic varieties only) */ - if(arena->droppedMessages > 0) { + /* report dropped messages */ + if(arena->droppedMessages > 0) EVENT1(MessagesDropped, arena->droppedMessages); - DIAG_SINGLEF(( "GlobalsPrepareToDestroy_dropped", - "arena->droppedMessages = $U", (WriteFU)arena->droppedMessages, - NULL )); - } /* .message.queue.empty: Empty the queue of messages before */ /* proceeding to finish the arena. It is important that this */ /* is done before destroying the finalization pool as otherwise */ /* the message queue would have dangling pointers to messages */ /* whose memory has been unmapped. */ - if(MessagePoll(arena)) { + if(MessagePoll(arena)) EVENT0(MessagesExist); - DIAG_SINGLEF(( "GlobalsPrepareToDestroy_queue", - "Message queue not empty", NULL )); - } MessageEmpty(arena); /* throw away the BT used by messages */ @@ -1104,8 +1097,6 @@ void ArenaSetEmergency(Arena arena, Bool emergency) AVERT(Arena, arena); AVERT(Bool, emergency); - DIAG_SINGLEF(( "ArenaSetEmergency", - "emergency: $U", (WriteFU)emergency, NULL )); EVENT2(ArenaSetEmergency, arena, emergency); arena->emergency = emergency; @@ -1121,7 +1112,7 @@ Bool ArenaEmergency(Arena arena) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2003, 2008 Ravenbrook Limited . + * Copyright (C) 2001-2013 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/locus.c b/mps/code/locus.c index 6ea5127ee12..0074bb3b6e8 100644 --- a/mps/code/locus.c +++ b/mps/code/locus.c @@ -1,7 +1,7 @@ /* locus.c: LOCUS MANAGER * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license. * * DESIGN * @@ -296,12 +296,7 @@ Res ChainCondemnAuto(double *mortalityReturn, Chain chain, Trace trace) } while (genNewSize >= gen->capacity * (Size)1024); EVENT3(ChainCondemnAuto, chain, topCondemnedGenSerial, chain->genCount); - DIAG_SINGLEF(( "ChainCondemnAuto", - "condemn gens [0..$U]", (WriteFU)topCondemnedGenSerial, - " (of $U)", (WriteFU)chain->genCount, - " of this chain $P.", (WriteFP)chain, - NULL )); - UNUSED(topCondemnedGenSerial); /* only used for DIAG */ + UNUSED(topCondemnedGenSerial); /* only used for EVENT */ /* Condemn everything in these zones. */ if (condemnedSet != ZoneSetEMPTY) { @@ -488,7 +483,7 @@ Bool LocusCheck(Arena arena) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2013 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/mpm.c b/mps/code/mpm.c index 04195a859dd..5436327c7ef 100644 --- a/mps/code/mpm.c +++ b/mps/code/mpm.c @@ -267,7 +267,7 @@ static Res WriteULongest(mps_lib_FILE *stream, ULongest w, unsigned base, buf[i] = pad; } - r = Stream_fputs(&buf[i], stream); + r = mps_lib_fputs(&buf[i], stream); if (r == mps_lib_EOF) return ResIO; @@ -308,7 +308,7 @@ static Res WriteDouble(mps_lib_FILE *stream, double d) int j = 0; if (F == 0.0) { - if (Stream_fputs("0", stream) == mps_lib_EOF) + if (mps_lib_fputs("0", stream) == mps_lib_EOF) return ResIO; return ResOK; } @@ -323,7 +323,7 @@ static Res WriteDouble(mps_lib_FILE *stream, double d) for ( ; F >= 1.0 ; F /= 10.0) { E++; if (E > DBL_MAX_10_EXP) { - if (Stream_fputs("Infinity", stream) == mps_lib_EOF) + if (mps_lib_fputs("Infinity", stream) == mps_lib_EOF) return ResIO; return ResOK; } @@ -410,7 +410,7 @@ static Res WriteDouble(mps_lib_FILE *stream, double d) } buf[j] = '\0'; /* arnold */ - if (Stream_fputs(buf, stream) == mps_lib_EOF) + if (mps_lib_fputs(buf, stream) == mps_lib_EOF) return ResIO; return ResOK; } @@ -469,7 +469,7 @@ Res WriteF_firstformat_v(mps_lib_FILE *stream, while(*format != '\0') { if (*format != '$') { - r = Stream_fputc(*format, stream); /* Could be more efficient */ + r = mps_lib_fputc(*format, stream); /* Could be more efficient */ if (r == mps_lib_EOF) return ResIO; } else { ++format; @@ -505,13 +505,13 @@ Res WriteF_firstformat_v(mps_lib_FILE *stream, case 'S': { /* string */ WriteFS s = va_arg(args, WriteFS); - r = Stream_fputs((const char *)s, stream); + r = mps_lib_fputs((const char *)s, stream); if (r == mps_lib_EOF) return ResIO; } break; case 'C': { /* character */ WriteFC c = va_arg(args, WriteFC); /* promoted */ - r = Stream_fputc((int)c, stream); + r = mps_lib_fputc((int)c, stream); if (r == mps_lib_EOF) return ResIO; } break; @@ -541,7 +541,7 @@ Res WriteF_firstformat_v(mps_lib_FILE *stream, } break; case '$': { /* dollar char */ - r = Stream_fputc('$', stream); + r = mps_lib_fputc('$', stream); if (r == mps_lib_EOF) return ResIO; } break; diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 4292f9fa671..3bdd46dda71 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -1,7 +1,7 @@ /* mpm.h: MEMORY POOL MANAGER DEFINITIONS * * $Id$ - * Copyright (c) 2001,2003 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * * .trans.bufferinit: The Buffer data structure has an Init field and @@ -155,14 +155,6 @@ extern Res WriteF_v(mps_lib_FILE *stream, va_list args); extern Res WriteF_firstformat_v(mps_lib_FILE *stream, const char *firstformat, va_list args); -#if defined(DIAG_WITH_STREAM_AND_WRITEF) -extern int Stream_fputc(int c, mps_lib_FILE *stream); -extern int Stream_fputs(const char *s, mps_lib_FILE *stream); -#else -#define Stream_fputc mps_lib_fputc -#define Stream_fputs mps_lib_fputs -#endif - /* Miscellaneous support -- see */ @@ -991,6 +983,9 @@ extern void StackProbe(Size depth); * STATISTIC_WRITE is inserted in WriteF arguments to output the values * of statistic fields. * + * STATISTIC_BEGIN and STATISTIC_END can be used around a block of + * statements. + * * .statistic.whitehot: The implementation of STATISTIC for * non-statistical varieties passes the parameter to DISCARD to ensure * the parameter is syntactically an expression. The parameter is @@ -1002,115 +997,29 @@ extern void StackProbe(Size depth); #define STATISTIC(gather) BEGIN (gather); END #define STATISTIC_STAT(gather) BEGIN gather; END #define STATISTIC_WRITE(format, arg) (format), (arg), +#define STATISTIC_BEGIN BEGIN +#define STATISTIC_END END #elif defined(STATISTICS_NONE) #define STATISTIC(gather) DISCARD(((gather), 0)) #define STATISTIC_STAT DISCARD_STAT #define STATISTIC_WRITE(format, arg) +#define STATISTIC_BEGIN BEGIN if (0) { +#define STATISTIC_END } END -#else +#else /* !defined(STATISTICS) && !defined(STATISTICS_NONE) */ #error "No statistics configured." #endif - -/* ------------ DIAG_WITH_STREAM_AND_WRITEF --------------- */ - -Bool DiagIsOn(void); -mps_lib_FILE *DiagStream(void); - - -/* Diag*F functions -- formatted diagnostic output - * - * Note: do not call these directly; use the DIAG_*F macros below. - */ - -extern void DiagSingleF(const char *tag, ...); -extern void DiagFirstF(const char *tag, ...); -extern void DiagMoreF(const char *format, ...); -extern void DiagEnd(const char *tag); - - -#if defined(DIAG_WITH_STREAM_AND_WRITEF) - -/* Diagnostic Calculation and Output */ -#define DIAG_DECL(decl) decl -#define DIAG_STREAM (DiagStream()) -#define DIAG(s) BEGIN \ - s \ - END - - -/* DIAG_*F macros -- formatted diagnostic output - * - * Note: when invoking these macros, the value passed as macro - * argument "args" might contain commas; it must therefore be - * enclosed in parentheses. That makes these macros unclean in - * all sorts of ways. - */ - -#define DIAG_WRITEF(args) DIAG( \ - if(DiagIsOn()) { \ - WriteF args; \ - } \ -) -#define DIAG_SINGLEF(args) DIAG( \ - DiagSingleF args; \ -) -#define DIAG_FIRSTF(args) DIAG( \ - DiagFirstF args; \ -) -#define DIAG_MOREF(args) DIAG( \ - DiagMoreF args; \ -) - -/* Note: extra parens *not* required when invoking DIAG_END */ -#define DIAG_END(tag) DIAG( \ - DiagEnd(tag); \ -) - - -#else - -/* Diagnostic Calculation and Output */ -#define DIAG_DECL(decl) -#define DIAG(s) BEGIN END -#define DIAG_WRITEF(args) BEGIN END - -/* DIAG_*F macros */ -#define DIAG_SINGLEF(args) BEGIN END -#define DIAG_FIRSTF(args) BEGIN END -#define DIAG_MOREF(args) BEGIN END -#define DIAG_END(tag) BEGIN END - -#endif - -/* ------------ DIAG_WITH_PRINTF --------------- */ - -#if defined(DIAG_WITH_PRINTF) - -#include - -#define DIAG_PRINTF(args) BEGIN\ - printf args ; \ - END - -#else - -#define DIAG_PRINTF(args) BEGIN\ - END - -#endif - - #endif /* mpm_h */ /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2003, 2008 Ravenbrook Limited . + * Copyright (C) 2001-2013 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/mps.c b/mps/code/mps.c index 99cf42d5a33..e6e712451c7 100644 --- a/mps/code/mps.c +++ b/mps/code/mps.c @@ -66,7 +66,6 @@ #include "meter.c" #include "splay.c" #include "cbs.c" -#include "diag.c" #include "ss.c" #include "version.c" #include "table.c" diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index 1558c9c18f2..09254deba9c 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -1595,24 +1595,9 @@ static Res amcScanNailed(Bool *totalReturn, ScanState ss, Pool pool, refset = ScanStateSummary(ss); -#if 1 /* A rare event, which might prompt a rare defect to appear. */ - DIAG_SINGLEF(( "amcScanNailed_loop", - "scan completed, but had to loop $U times:\n", (WriteFU)loops, - " SegSummary: $B\n", (WriteFB)SegSummary(seg), - " ss.white: $B\n", (WriteFB)ScanStateWhite(ss), - " ss.unfixedSummary: $B", (WriteFB)ScanStateUnfixedSummary(ss), - "$S\n", (WriteFS)( - (RefSetSub(ScanStateUnfixedSummary(ss), SegSummary(seg))) - ? "" - : " <=== This would have failed .verify.segsummary!" - ), - " ss.fixedSummary: $B\n", (WriteFB)ss->fixedSummary, - "ScanStateSummary: $B\n", (WriteFB)refset, - "MOVING ScanStateSummary TO fixedSummary, " - "RESETTING unfixedSummary.\n", NULL - )); -#endif + EVENT6(amcScanNailed, loops, SegSummary(seg), ScanStateWhite(ss), + ScanStateUnfixedSummary(ss), ss->fixedSummary, refset); ScanStateSetSummary(ss, refset); } @@ -2231,14 +2216,12 @@ static void AMCReclaim(Pool pool, Trace trace, Seg seg) } -/* AMCTraceEnd -- emit end-of-trace diagnostics - * - */ +/* AMCTraceEnd -- emit end-of-trace event */ + static void AMCTraceEnd(Pool pool, Trace trace) { AMC amc; TraceId ti; - Count pRetMin = 100; AVERT(Pool, pool); AVERT(Trace, trace); @@ -2248,33 +2231,18 @@ static void AMCTraceEnd(Pool pool, Trace trace) ti = trace->ti; AVER(TraceIdCheck(ti)); - if(amc->pageretstruct[ti].pRet >= pRetMin) { - DIAG_SINGLEF(( "AMCTraceEnd_pageret", - " $U", (WriteFU)ArenaEpoch(pool->arena), - " $U", (WriteFU)trace->why, - " $U", (WriteFU)amc->pageretstruct[ti].pCond, - " $U", (WriteFU)amc->pageretstruct[ti].pRet, ",", - " $U", (WriteFU)amc->pageretstruct[ti].pCS, - " $U", (WriteFU)amc->pageretstruct[ti].pRS, ",", - " $U", (WriteFU)amc->pageretstruct[ti].sCM, - " $U", (WriteFU)amc->pageretstruct[ti].pCM, - " $U", (WriteFU)amc->pageretstruct[ti].sRM, - " $U", (WriteFU)amc->pageretstruct[ti].pRM, - " $U", (WriteFU)amc->pageretstruct[ti].pRM1, - " $U", (WriteFU)amc->pageretstruct[ti].pRMrr, - " $U", (WriteFU)amc->pageretstruct[ti].pRMr1, ",", - " $U", (WriteFU)amc->pageretstruct[ti].sCL, - " $U", (WriteFU)amc->pageretstruct[ti].pCL, - " $U", (WriteFU)amc->pageretstruct[ti].sRL, - " $U", (WriteFU)amc->pageretstruct[ti].pRL, - " $U", (WriteFU)amc->pageretstruct[ti].pRLr, - " (page = $Ub,", (WriteFU)ArenaAlign(pool->arena), - " Large >= $Up,", (WriteFU)AMCLargeSegPAGES, - " pRetMin $U)", (WriteFU)pRetMin, - NULL )); - } - - STATISTIC(amc->pageretstruct[ti] = pageretstruct_Zero); + STATISTIC_BEGIN { + Count pRetMin = 100; + PageRetStruct *pr = &amc->pageretstruct[ti]; + if(pr->pRet >= pRetMin) { + EVENT21(AMCTraceEnd, ArenaEpoch(pool->arena), (EventFU)trace->why, + ArenaAlign(pool->arena), AMCLargeSegPAGES, pRetMin, pr->pCond, + pr->pRet, pr->pCS, pr->pRS, pr->sCM, pr->pCM, pr->sRM, pr->pRM, + pr->pRM1, pr->pRMrr, pr->pRMr1, pr->sCL, pr->pCL, pr->sRL, + pr->pRL, pr->pRLr); + } + *pr = pageretstruct_Zero; + } STATISTIC_END; } diff --git a/mps/code/poolmrg.c b/mps/code/poolmrg.c index 743920a7ddf..1bb63b0bd88 100644 --- a/mps/code/poolmrg.c +++ b/mps/code/poolmrg.c @@ -642,9 +642,6 @@ static Res MRGInit(Pool pool, ArgList args) mrg->sig = MRGSig; AVERT(MRG, mrg); - DIAG_PRINTF(( "mrg->extendBy = %u, MRGGuardiansPerSeg = %u\n", - (unsigned int) mrg->extendBy, - (unsigned int) MRGGuardiansPerSeg(mrg) )); EVENT3(PoolInit, pool, PoolArena(pool), ClassOfPool(pool)); return ResOK; } diff --git a/mps/code/trace.c b/mps/code/trace.c index 7659cdda36f..596e2ed944b 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1,7 +1,7 @@ /* trace.c: GENERIC TRACER IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2003, 2006, 2007 Ravenbrook Limited. + * Copyright (c) 2001-2013 Ravenbrook Limited. * See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * @@ -18,7 +18,6 @@ Rank traceBand(Trace); Bool traceBandAdvance(Trace); Bool traceBandFirstStretch(Trace); void traceBandFirstStretchDone(Trace); -DIAG_DECL( static void traceFindGrey_diag(Bool found, Rank rank); ) /* Types */ @@ -1016,7 +1015,6 @@ static Bool traceFindGrey(Seg *segReturn, Rank *rankReturn, *segReturn = seg; *rankReturn = rank; EVENT4(TraceFindGrey, arena, ti, seg, rank); - DIAG( traceFindGrey_diag(TRUE, rank); ); return TRUE; } } @@ -1025,77 +1023,12 @@ static Bool traceFindGrey(Seg *segReturn, Rank *rankReturn, AVER(RingIsSingle(ArenaGreyRing(arena, RankAMBIG))); if(!traceBandAdvance(trace)) { /* No grey segments for this trace. */ - DIAG( traceFindGrey_diag(FALSE, rank); ); return FALSE; } } } -/* diagnostic output for traceFindGrey */ -DIAG_DECL( -static void traceFindGrey_diag(Bool found, Rank rank) -{ - char this; - static char prev = '.'; - static int segcount; - static char report_array[20]; - static char *report_lim; - int report_maxchars = sizeof(report_array) - 2; /* '.' + '\0' */ - - this = (char)(!found ? '.' - : (rank == RankAMBIG) ? 'A' - : (rank == RankEXACT) ? 'E' - : (rank == RankFINAL) ? 'F' - : (rank == RankWEAK) ? 'W' - : '?'); - - if(prev == '.') { - /* First seg of new trace */ - prev = this; - segcount = 0; - report_lim = report_array; - } - - if(this == prev) { - segcount += 1; - } else { - /* Change of rank: add prev rank and segcount to report */ - if((report_lim - report_array) + 2 > report_maxchars) { - /* no space to add 2 chars */ - report_array[0] = '!'; - } else { - /* prev rank */ - *report_lim++ = prev; - /* prev rank's segcount [0..9, a..z (x10), or *] */ - if(segcount < 10) { - *report_lim++ = (char)('0' + segcount); - } else if(segcount < 260) { - *report_lim++ = (char)(('a' - 1) + (segcount / 10)); - } else { - *report_lim++ = '*'; - } - } - /* begin new rank */ - prev = this; - segcount = 1; - } - - if(!found) { - /* No more grey in this trace: output report */ - AVER(this == '.'); - AVER(segcount == 1); /* single failed attempt to find a seg */ - *report_lim++ = this; - *report_lim++ = '\0'; - DIAG_SINGLEF(( "traceFindGrey", - "rank sequence: $S", - (WriteFS)report_array, - NULL )); - } - return; -} -) - /* ScanStateSetSummary -- set the summary of scanned references * * This function sets unfixedSummary and fixedSummary such that @@ -1626,36 +1559,15 @@ static Res rootGrey(Root root, void *p) } -static void TraceStartGenDesc_diag(GenDesc desc, Bool top, Index i) +static void TraceStartPoolGen(Chain chain, GenDesc desc, Bool top, Index i) { Ring n, nn; - -#if !defined(DIAG_WITH_STREAM_AND_WRITEF) - UNUSED(i); -#endif - - if(top) { - DIAG_WRITEF(( DIAG_STREAM, - " GenDesc [top]", - NULL )); - } else { - DIAG_WRITEF(( DIAG_STREAM, - " GenDesc [$U]", (WriteFU)i, - NULL )); - } - DIAG_WRITEF(( DIAG_STREAM, - " $P capacity: $U KiB, mortality $D\n", - (WriteFP)desc, (WriteFU)desc->capacity, (WriteFD)desc->mortality, - " ZoneSet:$B\n", (WriteFB)desc->zones, - NULL )); RING_FOR(n, &desc->locusRing, nn) { - DIAG_DECL( PoolGen gen = RING_ELT(PoolGen, genRing, n); ) - DIAG_WRITEF(( DIAG_STREAM, - " PoolGen $U ($S)", - (WriteFU)gen->nr, (WriteFS)gen->pool->class->name, - " totalSize $U", (WriteFU)gen->totalSize, - " newSize $U\n", (WriteFU)gen->newSizeAtCreate, - NULL )); + PoolGen gen = RING_ELT(PoolGen, genRing, n); + EVENT11(TraceStartPoolGen, chain, top, i, desc, + desc->capacity, desc->mortality, desc->zones, + gen->pool, gen->nr, gen->totalSize, + gen->newSizeAtCreate); } } @@ -1729,45 +1641,24 @@ Res TraceStart(Trace trace, double mortality, double finishingTime) } while (SegNext(&seg, arena, base)); } - DIAG_FIRSTF(( "TraceStart", - "because code $U: $S\n", - (WriteFU)trace->why, (WriteFS)TraceStartWhyToString(trace->why), - NULL )); - - DIAG( ArenaDescribe(arena, DIAG_STREAM); ); - - DIAG_MOREF(( - " white set:$B\n", - (WriteFB)trace->white, - NULL )); - - { + STATISTIC_BEGIN { /* @@ */ /* Iterate over all chains, all GenDescs within a chain, */ /* (and all PoolGens within a GenDesc). */ Ring node, nextNode; Index i; - + RING_FOR(node, &arena->chainRing, nextNode) { Chain chain = RING_ELT(Chain, chainRing, node); - DIAG_WRITEF(( DIAG_STREAM, - " Chain $P\n", (WriteFP)chain, - NULL )); - for(i = 0; i < chain->genCount; ++i) { GenDesc desc = &chain->gens[i]; - TraceStartGenDesc_diag(desc, FALSE, i); + TraceStartPoolGen(chain, desc, FALSE, i); } } - + /* Now do topgen GenDesc (and all PoolGens within it). */ - DIAG_WRITEF(( DIAG_STREAM, - " topGen\n", - NULL )); - TraceStartGenDesc_diag(&arena->topGen, TRUE, 0); - } - - DIAG_END( "TraceStart" ); + TraceStartPoolGen(NULL, &arena->topGen, TRUE, 0); + } STATISTIC_END; res = RootsIterate(ArenaGlobals(arena), rootGrey, (void *)trace); AVER(res == ResOK); @@ -1790,7 +1681,7 @@ Res TraceStart(Trace trace, double mortality, double finishingTime) trace->rate = (trace->foundation + sSurvivors) / (unsigned long)nPolls + 1; } - /* @@ DIAG for rate of scanning here. */ + /* TODO: compute rate of scanning here. */ EVENT8(TraceStart, trace, mortality, finishingTime, trace->condemned, trace->notCondemned, @@ -1798,9 +1689,9 @@ Res TraceStart(Trace trace, double mortality, double finishingTime) trace->rate); STATISTIC_STAT(EVENT7(TraceStatCondemn, trace, - trace->condemned, trace->notCondemned, - trace->foundation, trace->rate, - mortality, finishingTime)); + trace->condemned, trace->notCondemned, + trace->foundation, trace->rate, + mortality, finishingTime)); trace->state = TraceUNFLIPPED; TracePostStartMessage(trace); @@ -2009,7 +1900,7 @@ failStart: /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2003, 2006, 2007 Ravenbrook Limited + * Copyright (C) 2001-2013 Ravenbrook Limited * . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. diff --git a/mps/code/vmix.c b/mps/code/vmix.c index 9b06f09b032..01a0919b820 100644 --- a/mps/code/vmix.c +++ b/mps/code/vmix.c @@ -1,7 +1,7 @@ /* vmix.c: VIRTUAL MEMORY MAPPING FOR UNIX (ISH) * * $Id$ - * Copyright (c) 2001,2007 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license. * * .purpose: This is the implementation of the virtual memory mapping * interface (vm.h) for Unix-like operating systems. It was created @@ -167,13 +167,6 @@ Res VMCreate(VM *vmReturn, Size size, void *params) AVERT(VM, vm); EVENT3(VMCreate, vm, vm->base, vm->limit); - DIAG_SINGLEF(( - "VM_ix_Create_ok", - "[$W..<$W>..$W)", - (WriteFW)vm->base, - (WriteFW)AddrOffset(vm->base, vm->limit), - (WriteFW)vm->limit, - NULL )); *vmReturn = vm; return ResOK; @@ -193,14 +186,6 @@ void VMDestroy(VM vm) AVERT(VM, vm); AVER(vm->mapped == (Size)0); - DIAG_SINGLEF(( - "VM_ix_Destroy", - "[$W..<$W>..$W)", - (WriteFW)vm->base, - (WriteFW)AddrOffset(vm->base, vm->limit), - (WriteFW)vm->limit, - NULL )); - /* This appears to be pretty pointless, since the descriptor */ /* page is about to vanish completely. However, munmap might fail */ /* for some reason, and this would ensure that it was still */ diff --git a/mps/design/diag.txt b/mps/design/diag.txt index cbc2e2ddfbd..577f2610ac3 100644 --- a/mps/design/diag.txt +++ b/mps/design/diag.txt @@ -25,14 +25,14 @@ Overview -------- Diagnostic feedback is information created by the MPS diagnostic -system for the purpose of helping MPS programmers client-code +system for the purpose of helping MPS programmers and client programmers. Such a piece of information is called "a diagnostic". (See also `.parts`_.) -A diagnostic is not intended to be end-user readable (or visible), or -machine-parseable. +A diagnostic is not intended to be visible to end users, or readable +by them. A diagnostic is not intended to be stable from one release to the next: it may be modified or removed at any time. @@ -48,203 +48,78 @@ MPS diagnostic feedback code must do these things: - control (for example, filter) output of diagnostics; - use a channel to get the diagnostic out. -Note: the knowledge/code/logic for constructing the human-useful -message is kept inside normal MPS source code. This means it is always -in-sync with changes to the MPS. This also means that any external -utilities used to display the messages do not need to understand, or -keep in sync with, the details of what's going inside the MPS. - Usage ----- -To run the MPS and get diagnostic output from it: +To get diagnostic output from the MPS, you must use a variety with +diagnostics compiled-in. Currently, that means variety.cool. See +``config.h``. -1. Use a variety with diagnostics compiled-in. Currently, that means - variety.di. See ``config.h``. +There are two mechanism for getting diagnostic output: -2. Check that the diagnostics you require are generated, by looking in - MPS source for invocations of the appropriate macro (for example, - ``DIAG_SINGLEF()``). +1. Automatically via the telemetry system. See design.mps.telemetry, + and the "Telemetry" chapter in the manual. -3. Check that the diagnostics you require will be output, by looking - at the diagnostic filter rules in ``diag.c``. +2. Manually via the debugger. In the debugger, set break points at the + places where you want to inspect data structures (or wait for the + debugger to be entered via an ``abort()`` call or unhandled + segmentation fault). Then at the debugger command prompt, run + ``Describe()`` commands of your choice. For example:: -4. Run the MPS and client in an environment that supports the channel - used (for example, at a command-line if using ``WriteF()``). + (gdb) run + Starting program: mv2test + Reading symbols for shared libraries +............................. done + cbs.c:94: MPS ASSERTION FAILED: !cbs->inCBS - -What is a diagnostic? -..................... - -A diagnostic has three parts: - -1. a trigger condition, that causes this diagnostic to be emitted; -2. a text tag (for example, "TraceStart") which is the name of this - diagnostic; and -3. a paragraph of human-useful text. - -A diagnostic is emitted by the MPS at a certain point in time when a -certain event happens. - -Diagnostics are not nested. Every diagnostic must have a tag. Each -diagnostic should have a unique tag (uniqueness is just to help the -humans; the diagnostic system does not care). - -The paragraph of text can be many lines long. It usually explains what -event caused the diagnostic to be emitted, and commonly also includes -the output of some ``Describe()`` methods for various relevant -objects. (For example, the ``TraceStart`` diagnostic might call, and -include the output generated by, the ``TraceDescribe()`` method). - -How do I control (filter) which diagnostics I see? -.................................................. - -All diagnostics are emitted and then filtered according to the -"diagnostic filter rules". - -The first level of control is filtering by tag. (For example, only -show ``TraceStart`` diagnostics). - -The second level of control is filtering by paragraph content. (For -example, only show ``TraceStart`` diagnostics where the trace is -started because a nursery generation is full). - -The third level of control is filtering by line content. (For example, -only show lines containing the word ``whiteSet``). - -See ``diag.c`` for details. - -Note: the entire filtering mechanism can be turned off, so that -diagnostics go immediately to ``mps_lib_get_stdout(0``, with no -buffering or filtering See impl.c.diag.filter-disable. + Program received signal SIGABRT, Aborted. + 0x00007fff83e42d46 in __kill () + (gdb) frame 12 + #12 0x000000010000b1fc in MVTFree (pool=0x103ffe160, base=0x101dfd000, size=5024) at poolmv2.c:711 + 711 Res res = CBSInsert(MVTCBS(mvt), base, limit); + (gdb) p MVTDescribe(mvt, mps_lib_get_stdout()) + MVT 0000000103FFE160 + { + minSize: 8 + meanSize: 42 + maxSize: 8192 + fragLimit: 30 + reuseSize: 16384 + fillSize: 8192 + availLimit: 1110835 + abqOverflow: FALSE + splinter: TRUE + splinterSeg: 0000000103FEE780 + splinterBase: 0000000101D7ABB8 + splinterLimit: 0000000101D7B000 + # ... etc ... + } How to write a diagnostic ------------------------- -Improve stateless Describe methods where possible -................................................. - -Where possible, don't put clever code into an event-triggered -diagnostic: put it into a stateless ``Describe()`` method instead, and -then call that method when emitting your diagnostic. - -For example:: - - FooDescribe(Foo foo, mps_lib_FILE *stream) - { - /* show value of new "quux" field */ - WriteF(stream, "Foo: $P { quux: $U }\n", foo, foo->quux); - } - - FooWibble(Foo foo) - { - ... - DIAG_FIRSTF(( "FooWibble", "Wibbling foo $P", foo, NULL)); - DIAG( FooDescribe(foo, DIAG_STREAM); ); - DIAG_END("FooWibble"); - ... - } - -This is much better, because other people can use your human-useful -output in their diagnostics, or 'live' in a debugger. - - -Use the output macros -..................... - -For a simple diagnostic, use ``DIAG_SINGLEF()``. This begins the tag, -puts text into the paragraph, and ends the tag immediately. - -For a more complex diagnostic, the first call must be -``DIAG_FIRSTF()``, which begins a diag tag. - -While a tag is current, you can add text to the diagnostic's paragraph -using ``DIAG_MOREF()``, and ``WriteF( DIAG_STREAM, ... )``. - -.. note:: - - ``DIAG_STREAM`` is not a real standard C library stream. If you - want stream-level access, you may use ``Stream_fputc()`` and - ``Stream_fputs()``. - -End the tag by calling ``DIAG_END``. - - Compile away in non-diag varieties; no side effects ................................................... -Wrap non-output code with the ``DIAG()`` and ``DIAG_DECL()`` macros, -to make sure that non-diag varieties do not execute -diagnostic-generating code. +Wrap code with the ``STATISTIC`` and ``METER`` macros, to make sure +that non-diagnostic varieties do not execute diagnostic-generating +code. -For complex diagnostic-generating code, it may be cleaner to move it -into a separate local function. Put ``_diag`` on the end of the function -name (for example, ``TraceStart_diag()``). - -Obviously, diagnostic-generating code must have no side effects. - - -Choosing tags -............. - -Tags should be valid C identifiers. Unless you know of a good reason -why not. (Not currently checked). - -There's no formal scheme for tag naming, but make it helpful and -informally hierarchical, for example, ``TraceBegin``, ``TraceStart``, -``TraceEnd``, and so on, not ``BeginTrace``, ``EndTrace``. +Diagnostic-generating code must have no side effects. Writing good paragraph text ........................... -IMPORTANT: Make your diagnostics easy to understand! Other people will -read your diagnostics! Make them clear and helpful. Do not make them -terse and cryptic. If you use symbols, print a key in the diagnostic. -(If you don't want to see this the screen clutter, then you can always -add a filter rule to your personal rule set to filter it out). - - -Maintaining helpful filter rules -................................ - -If you add a noisy diagnostic, add a rule to the default ruleset to -turn it off. +Make your diagnostics easy to understand! Other people will read your +diagnostics! Make them clear and helpful. Do not make them terse and +cryptic. If you use symbols, print a key in the diagnostic. How the MPS diagnostic system works ----------------------------------- -Channels -........ - -The recommended channel is ``WriteF()`` to standard output. - -Other possible of future channels might be: - -- ``printf()``; -- a new type (yet to be defined) of ``mps_message``; -- squirt them into the telemetry-log-events system; -- telnet. - -Currently, only ``printf()`` and ``WriteF()`` are supported. See the -``DIAG_WITH_`` macros in ``mpm.h``. - -You can also use a debugger to call ``Describe()`` methods directly, -from within the debugger. - -Note: it is unfortunate that choice of channel may (for some channels) -also dictate the form of the code that synthesises the message. (For -example, ``WriteF()`` style parameter-expansion is not possible when -using the ``printf()`` channel, because there is no way to get -``WriteF()`` to produce its output into a string). This is just a -technical hitch; logically, the code that synthesises a diagnostic -message should not care which channel will be used to transmit it out -of the MPS. - - Parts of the MPS diagnostic system .................................. @@ -252,7 +127,6 @@ _`.parts`: The following facilities are considered part of the MPS diagnostic system: - the ``Describe()`` methods. -- the ``DIAG`` macros (``DIAG``, ``DIAG_DECL``, ``DIAG_*F``, and so on); - the ``STATISTIC`` macros (see ``mpm.h``); - the ``METER`` macros and meter subsystem. @@ -305,6 +179,8 @@ Document History - 2013-05-23 GDR_ Converted to reStructuredText. +- 2013-06-05 GDR_ DIAG part of the system has been removed. + .. _GDR: http://www.ravenbrook.com/consultants/gdr/