1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-03-26 08:41:47 -07:00

Remove diag facility.

Copied from Perforce
 Change: 182553
 ServerID: perforce.ravenbrook.com
This commit is contained in:
Gareth Rees 2013-06-05 18:35:40 +01:00
parent ad35f3cac3
commit 4e22988865
18 changed files with 208 additions and 1422 deletions

View file

@ -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,

View file

@ -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;

View file

@ -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)

View file

@ -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 = <abq> <arena> <arenacl> <arenavm> <arg> <boot> <bt> \
<buffer> <cbs> <dbgpool> <dbgpooli> <diag> <event> <format> \
<global> <ld> <lockw3> <locus> <message> <meter> <mpm> <mpsi> \
<mpsiw3> <pool> <poolabs> <poolmfs> <poolmrg> <poolmv2> <poolmv> \
<buffer> <cbs> <dbgpool> <dbgpooli> <event> <format> <global> \
<ld> <lockw3> <locus> <message> <meter> <mpm> <mpsi> <mpsiw3> \
<pool> <poolabs> <poolmfs> <poolmrg> <poolmv2> <poolmv> \
<protocol> <protw3> <ref> <reserv> <ring> <root> <sac> <seg> \
<shield> <splay> <ss> <table> <thw3> <trace> <traceanc> <tract> \
<vmw3> <walk>

View file

@ -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.

View file

@ -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 <stdarg.h>
#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 <http://www.ravenbrook.com/>.
* 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.
*/

View file

@ -1,6 +1,6 @@
/* <code/event.h> -- 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 <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2013 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -1,7 +1,7 @@
/* <code/eventdef.h> -- 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: <design/telemetry/>
*
@ -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 <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2013 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -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/arena/>. 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 <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2013 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -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 <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2013 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -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;

View file

@ -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 <code/mpm.c> */
@ -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 <stdio.h>
#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 <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2013 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -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"

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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
* <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.

View file

@ -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 */

View file

@ -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/