aboutsummaryrefslogtreecommitdiffstats
path: root/mps/code
diff options
context:
space:
mode:
authorRichard Brooksby2013-02-08 16:17:34 +0000
committerRichard Brooksby2013-02-08 16:17:34 +0000
commit2706097eab7b3d1aa9429ef0e4ea1ac9f3c6edbe (patch)
tree01b97e7abdada2c711cf5139952feee4ec71ba97 /mps/code
parentab2c28cae42410c7b5edca80f1de8a9789494b52 (diff)
parentb31cda511d16f6a9947cead9341a1dfff5524cce (diff)
downloademacs-2706097eab7b3d1aa9429ef0e4ea1ac9f3c6edbe.tar.gz
emacs-2706097eab7b3d1aa9429ef0e4ea1ac9f3c6edbe.zip
Integrating branch/2012-10-09/user-guide back to master.
Copied from Perforce Change: 180943 ServerID: perforce.ravenbrook.com
Diffstat (limited to 'mps/code')
-rw-r--r--mps/code/buffer.c2
-rw-r--r--mps/code/clock.h9
-rw-r--r--mps/code/comm.gmk46
-rw-r--r--mps/code/commpost.nmk18
-rw-r--r--mps/code/commpre.nmk2
-rw-r--r--mps/code/event.c40
-rw-r--r--mps/code/eventcnv.c616
-rw-r--r--mps/code/eventdef.h40
-rw-r--r--mps/code/eventsql.c1004
-rw-r--r--mps/code/eventtxt.c540
-rw-r--r--mps/code/fri3gc.gmk3
-rw-r--r--mps/code/gc.gmk13
-rw-r--r--mps/code/global.c13
-rw-r--r--mps/code/mpmtypes.h2
-rw-r--r--mps/code/mps.h11
-rw-r--r--mps/code/mps.xcodeproj/project.pbxproj235
-rw-r--r--mps/code/mpscamc.h4
-rw-r--r--mps/code/mpscmfs.h56
-rw-r--r--mps/code/mpscmvt.h77
-rw-r--r--mps/code/mpsi.c35
-rw-r--r--mps/code/mpsliban.c56
-rw-r--r--mps/code/mpstd.h1
-rw-r--r--mps/code/mv2test.c2
-rw-r--r--mps/code/poolamc.c27
-rw-r--r--mps/code/poolmfs.c11
-rw-r--r--mps/code/poolmv2.c2
-rw-r--r--mps/code/seg.c2
-rw-r--r--mps/code/testlib.h24
-rw-r--r--mps/code/w3i3mv.nmk5
-rw-r--r--mps/code/w3i6mv.nmk5
30 files changed, 2318 insertions, 583 deletions
diff --git a/mps/code/buffer.c b/mps/code/buffer.c
index 2128ffda0cf..f911a28c6b9 100644
--- a/mps/code/buffer.c
+++ b/mps/code/buffer.c
@@ -1494,8 +1494,6 @@ DEFINE_CLASS(SegBufClass, class)
1494 1494
1495static Res rankBufInit (Buffer buffer, Pool pool, va_list args) 1495static Res rankBufInit (Buffer buffer, Pool pool, va_list args)
1496{ 1496{
1497 /* Assumes pun compatibility between Rank and mps_rank_t */
1498 /* Which is checked by mpsi_check in <code/mpsi.c> */
1499 Rank rank = va_arg(args, Rank); 1497 Rank rank = va_arg(args, Rank);
1500 BufferClass super; 1498 BufferClass super;
1501 Res res; 1499 Res res;
diff --git a/mps/code/clock.h b/mps/code/clock.h
index 881d74e2715..b9205f2e9be 100644
--- a/mps/code/clock.h
+++ b/mps/code/clock.h
@@ -21,14 +21,13 @@
21 * RB 2012-09-11 21 * RB 2012-09-11
22 */ 22 */
23 23
24/* TODO: Clang supposedly provides a cross-platform builtin for a fast 24/* Clang provides a cross-platform builtin for a fast timer, but it
25 timer, but it doesn't seem to be present on Mac OS X 10.8. We should 25 was not available on Mac OS X 10.8 until the release of XCode 4.6.
26 use it if it ever appears.
27 <http://clang.llvm.org/docs/LanguageExtensions.html#builtins> */ 26 <http://clang.llvm.org/docs/LanguageExtensions.html#builtins> */
28#if defined(MPS_BUILD_LL) 27#if defined(MPS_BUILD_LL)
29 28
30#if __has_builtin(__builtin_readcyclecounter) 29#if __has_builtin(__builtin_readcyclecounter)
31#error "__builtin_readcyclecounter is available but not used" 30/* TODO: use this for EVENT_CLOCK. See job003411. */
32#endif /* __has_builtin(__builtin_readcyclecounter) */ 31#endif /* __has_builtin(__builtin_readcyclecounter) */
33 32
34#endif 33#endif
@@ -120,7 +119,7 @@ __extension__ typedef unsigned long long EventClock;
120#define EVENT_CLOCK_PRINT(stream, clock) \ 119#define EVENT_CLOCK_PRINT(stream, clock) \
121 fprintf(stream, "%08lX%08lX", \ 120 fprintf(stream, "%08lX%08lX", \
122 (unsigned long)((clock) >> 32), \ 121 (unsigned long)((clock) >> 32), \
123 (unsigned long)(clock)) 122 (unsigned long)((clock) & 0xffffffff))
124 123
125#define EVENT_CLOCK_WRITE(stream, clock) \ 124#define EVENT_CLOCK_WRITE(stream, clock) \
126 WriteF(stream, "$W$W", (WriteFW)((clock) >> 32), (WriteFW)clock, NULL) 125 WriteF(stream, "$W$W", (WriteFW)((clock) >> 32), (WriteFW)clock, NULL)
diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk
index 2e16905eab7..bfdf9a20c7a 100644
--- a/mps/code/comm.gmk
+++ b/mps/code/comm.gmk
@@ -11,7 +11,12 @@
11# PARAMETERS 11# PARAMETERS
12# 12#
13# Assumes the following variables and definitions: 13# Assumes the following variables and definitions:
14# EXTRA_TARGETS a list of extra targets to build
14# CFLAGSCOMPILER a list of flags for all compilations 15# CFLAGSCOMPILER a list of flags for all compilations
16# CFLAGSSTRICT a list of flags for almost all compilations
17# CFLAGSLAX a list of flags for compilations which can't be as
18# strict (e.g. because they have to include a third-
19# party header file that isn't -ansi -pedantic).
15# CFLAGSDEBUG a list of flags for compilations with maximum debug 20# CFLAGSDEBUG a list of flags for compilations with maximum debug
16# information, and any optimization possible 21# information, and any optimization possible
17# CFLAGSOPT a list of flags for compilations with maximum 22# CFLAGSOPT a list of flags for compilations with maximum
@@ -63,6 +68,15 @@ ifndef CFLAGSOPT
63error "comm.gmk: CFLAGSOPT not defined" 68error "comm.gmk: CFLAGSOPT not defined"
64endif 69endif
65 70
71
72# EXTRA TARGETS
73#
74# Don't build mpseventsql by default (might not have sqlite3 installed),
75# but do build mpseventcnv and mpseventtxt.
76
77EXTRA_TARGETS ?= mpseventcnv mpseventtxt
78
79
66# 80#
67# %%PART: When adding a new part, add checks for the parameter with the 81# %%PART: When adding a new part, add checks for the parameter with the
68# sources for the new part. 82# sources for the new part.
@@ -92,7 +106,8 @@ endif
92# These flags are included in all compilations. 106# These flags are included in all compilations.
93# Avoid using PFMDEFS in platform makefiles, as they prevent the MPS being 107# Avoid using PFMDEFS in platform makefiles, as they prevent the MPS being
94# built with a simple command like "cc -c mps.c". 108# built with a simple command like "cc -c mps.c".
95CFLAGSCOMMON = $(PFMDEFS) $(CFLAGSCOMPILER) 109CFLAGSCOMMON = $(PFMDEFS) $(CFLAGSCOMPILER) $(CFLAGSCOMPILERSTRICT)
110CFLAGSCOMMONLAX = $(PFMDEFS) $(CFLAGSCOMPILER) $(CFLAGSCOMPILERLAX)
96 111
97# %%VARIETY: When adding a new variety, define a macro containing the set 112# %%VARIETY: When adding a new variety, define a macro containing the set
98# of flags for the new variety. 113# of flags for the new variety.
@@ -108,15 +123,19 @@ CFCOOL = -DCONFIG_VAR_COOL $(CFLAGSDEBUG)
108# CFLAGS here. 123# CFLAGS here.
109ifeq ($(VARIETY),rash) 124ifeq ($(VARIETY),rash)
110CFLAGS=$(CFLAGSCOMMON) $(CFRASH) 125CFLAGS=$(CFLAGSCOMMON) $(CFRASH)
126CFLAGSLAX=$(CFLAGSCOMMONLAX) $(CFRASH)
111else 127else
112ifeq ($(VARIETY),hot) 128ifeq ($(VARIETY),hot)
113CFLAGS=$(CFLAGSCOMMON) $(CFHOT) 129CFLAGS=$(CFLAGSCOMMON) $(CFHOT)
130CFLAGSLAX=$(CFLAGSCOMMONLAX) $(CFHOT)
114else 131else
115ifeq ($(VARIETY),diag) 132ifeq ($(VARIETY),diag)
116CFLAGS=$(CFLAGSCOMMON) $(CFDIAG) 133CFLAGS=$(CFLAGSCOMMON) $(CFDIAG)
134CFLAGSLAX=$(CFLAGSCOMMONLAX) $(CFDIAG)
117else 135else
118ifeq ($(VARIETY),cool) 136ifeq ($(VARIETY),cool)
119CFLAGS=$(CFLAGSCOMMON) $(CFCOOL) 137CFLAGS=$(CFLAGSCOMMON) $(CFCOOL)
138CFLAGSLAX=$(CFLAGSCOMMONLAX) $(CFCOOL)
120else 139else
121endif 140endif
122endif 141endif
@@ -203,7 +222,7 @@ all: mpmss sacss amcss amcsshe amsss amssshe segsmss awlut awluthe \
203 finalcv finaltest arenacv bttest teletest \ 222 finalcv finaltest arenacv bttest teletest \
204 abqtest cbstest btcv mv2test messtest steptest \ 223 abqtest cbstest btcv mv2test messtest steptest \
205 walkt0 zcoll zmess \ 224 walkt0 zcoll zmess \
206 eventcnv \ 225 $(EXTRA_TARGETS) \
207 mps.a mpsplan.a 226 mps.a mpsplan.a
208 227
209 228
@@ -232,7 +251,7 @@ mpmss sacss amcss amcssth amcsshe amsss amssshe segsmss awlut awlutth \
232 walkt0 \ 251 walkt0 \
233 exposet0 \ 252 exposet0 \
234 zcoll zmess \ 253 zcoll zmess \
235 eventcnv replay replaysw \ 254 $(EXTRA_TARGETS) replay replaysw \
236 mps.a mpsplan.a: phony 255 mps.a mpsplan.a: phony
237ifdef VARIETY 256ifdef VARIETY
238 $(MAKE) -f $(PFM).gmk TARGET=$@ variety 257 $(MAKE) -f $(PFM).gmk TARGET=$@ variety
@@ -414,9 +433,15 @@ $(PFM)/$(VARIETY)/zcoll: $(PFM)/$(VARIETY)/zcoll.o \
414$(PFM)/$(VARIETY)/zmess: $(PFM)/$(VARIETY)/zmess.o \ 433$(PFM)/$(VARIETY)/zmess: $(PFM)/$(VARIETY)/zmess.o \
415 $(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a 434 $(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
416 435
417$(PFM)/$(VARIETY)/eventcnv: $(PFM)/$(VARIETY)/eventcnv.o \ 436$(PFM)/$(VARIETY)/mpseventcnv: $(PFM)/$(VARIETY)/eventcnv.o \
418 $(PFM)/$(VARIETY)/eventpro.o $(PFM)/$(VARIETY)/mps.a 437 $(PFM)/$(VARIETY)/eventpro.o $(PFM)/$(VARIETY)/mps.a
419 438
439$(PFM)/$(VARIETY)/mpseventtxt: $(PFM)/$(VARIETY)/eventtxt.o \
440 $(PFM)/$(VARIETY)/mps.a
441
442$(PFM)/$(VARIETY)/mpseventsql: $(PFM)/$(VARIETY)/eventsql.o \
443 $(PFM)/$(VARIETY)/mps.a
444
420$(PFM)/$(VARIETY)/replay: $(PFM)/$(VARIETY)/replay.o \ 445$(PFM)/$(VARIETY)/replay: $(PFM)/$(VARIETY)/replay.o \
421 $(PFM)/$(VARIETY)/eventrep.o \ 446 $(PFM)/$(VARIETY)/eventrep.o \
422 $(PFM)/$(VARIETY)/eventpro.o $(PFM)/$(VARIETY)/table.o \ 447 $(PFM)/$(VARIETY)/eventpro.o $(PFM)/$(VARIETY)/table.o \
@@ -440,10 +465,20 @@ mkdir -p $(PFM)/$(VARIETY)
440$(CC) $(CFLAGS) -c -o $@ $< 465$(CC) $(CFLAGS) -c -o $@ $<
441endef 466endef
442 467
468define run-cc-lax
469$(ECHO) "$(PFM): $@ - compiling with lax flags."
470mkdir -p $(PFM)
471mkdir -p $(PFM)/$(VARIETY)
472$(CC) $(CFLAGSLAX) -c -o $@ $<
473endef
474
443# .rule.c-to-o: 475# .rule.c-to-o:
444$(PFM)/$(VARIETY)/%.o: %.c 476$(PFM)/$(VARIETY)/%.o: %.c
445 $(run-cc) 477 $(run-cc)
446 478
479$(PFM)/$(VARIETY)/eventsql.o: eventsql.c
480 $(run-cc-lax)
481
447$(PFM)/$(VARIETY)/%.o: %.s 482$(PFM)/$(VARIETY)/%.o: %.s
448 $(run-cc) 483 $(run-cc)
449 484
@@ -507,6 +542,9 @@ $(PFM)/$(VARIETY)/%:
507 $(ECHO) "$(PFM): $@" 542 $(ECHO) "$(PFM): $@"
508 $(CC) $(CFLAGS) $(LINKFLAGS) -o $@ $^ $(LIBS) 543 $(CC) $(CFLAGS) $(LINKFLAGS) -o $@ $^ $(LIBS)
509 544
545$(PFM)/$(VARIETY)/mpseventsql:
546 $(ECHO) "$(PFM): $@"
547 $(CC) $(CFLAGS) $(LINKFLAGS) -o $@ $^ $(LIBS) -lsqlite3
510 548
511# Special targets for development 549# Special targets for development
512 550
diff --git a/mps/code/commpost.nmk b/mps/code/commpost.nmk
index 15b77940b29..793ec8e6035 100644
--- a/mps/code/commpost.nmk
+++ b/mps/code/commpost.nmk
@@ -19,7 +19,7 @@ all: mpmss.exe amcss.exe amsss.exe amssshe.exe segsmss.exe awlut.exe awluthe.exe
19 arenacv.exe bttest.exe teletest.exe \ 19 arenacv.exe bttest.exe teletest.exe \
20 abqtest.exe cbstest.exe btcv.exe mv2test.exe messtest.exe steptest.exe \ 20 abqtest.exe cbstest.exe btcv.exe mv2test.exe messtest.exe steptest.exe \
21 locbwcss.exe locusss.exe zcoll.exe zmess.exe \ 21 locbwcss.exe locusss.exe zcoll.exe zmess.exe \
22 eventcnv.exe \ 22 mpseventcnv.exe mpseventtxt.exe \
23 mps.lib 23 mps.lib
24 24
25 25
@@ -37,7 +37,7 @@ mpmss.exe amcss.exe amcsshe.exe amsss.exe amssshe.exe segsmss.exe awlut.exe awlu
37 abqtest.exe cbstest.exe btcv.exe mv2test.exe messtest.exe steptest.exe \ 37 abqtest.exe cbstest.exe btcv.exe mv2test.exe messtest.exe steptest.exe \
38 walkt0.exe locbwcss.exe locusss.exe \ 38 walkt0.exe locbwcss.exe locusss.exe \
39 exposet0.exe zcoll.exe zmess.exe \ 39 exposet0.exe zcoll.exe zmess.exe \
40 replay.exe replaysw.exe eventcnv.exe \ 40 replay.exe replaysw.exe mpseventcnv.exe mpseventtxt.exe mpseventsql.exe \
41 mps.lib: 41 mps.lib:
42!IFDEF VARIETY 42!IFDEF VARIETY
43 $(MAKE) /nologo /f $(PFM).nmk TARGET=$@ variety 43 $(MAKE) /nologo /f $(PFM).nmk TARGET=$@ variety
@@ -231,9 +231,15 @@ $(PFM)\$(VARIETY)\zmess.exe: $(PFM)\$(VARIETY)\zmess.obj \
231 $(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) \ 231 $(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) \
232 $(TESTLIBOBJ) 232 $(TESTLIBOBJ)
233 233
234$(PFM)\$(VARIETY)\eventcnv.exe: $(PFM)\$(VARIETY)\eventcnv.obj \ 234$(PFM)\$(VARIETY)\mpseventcnv.exe: $(PFM)\$(VARIETY)\eventcnv.obj \
235 $(PFM)\$(VARIETY)\eventpro.obj $(PFM)\$(VARIETY)\mps.lib 235 $(PFM)\$(VARIETY)\eventpro.obj $(PFM)\$(VARIETY)\mps.lib
236 236
237$(PFM)\$(VARIETY)\mpseventtxt.exe: $(PFM)\$(VARIETY)\eventtxt.obj \
238 $(PFM)\$(VARIETY)\mps.lib
239
240$(PFM)\$(VARIETY)\mpseventsql.exe: $(PFM)\$(VARIETY)\eventsql.obj \
241 $(PFM)\$(VARIETY)\sqlite3.obj $(PFM)\$(VARIETY)\mps.lib
242
237$(PFM)\$(VARIETY)\replay.exe: $(PFM)\$(VARIETY)\replay.obj \ 243$(PFM)\$(VARIETY)\replay.exe: $(PFM)\$(VARIETY)\replay.obj \
238 $(PFM)\$(VARIETY)\eventrep.obj \ 244 $(PFM)\$(VARIETY)\eventrep.obj \
239 $(PFM)\$(VARIETY)\eventpro.obj $(PFM)\$(VARIETY)\table.obj \ 245 $(PFM)\$(VARIETY)\eventpro.obj $(PFM)\$(VARIETY)\table.obj \
@@ -270,6 +276,12 @@ $(PFM)\$(VARIETY)\exposet0.exe: $(PFM)\$(VARIETY)\exposet0.obj \
270 @if not exist $(PFM)\$(VARIETY) mkdir $(PFM)\$(VARIETY) 276 @if not exist $(PFM)\$(VARIETY) mkdir $(PFM)\$(VARIETY)
271 cl /c $(CFLAGS) /Fd$(PFM)\$(VARIETY)\ /Fo$@ $< 277 cl /c $(CFLAGS) /Fd$(PFM)\$(VARIETY)\ /Fo$@ $<
272 278
279$(PFM)\$(VARIETY)\sqlite3.obj:
280 $(ECHO) $@
281 @if not exist $(PFM) mkdir $(PFM)
282 @if not exist $(PFM)\$(VARIETY) mkdir $(PFM)\$(VARIETY)
283 cl /c $(CFLAGSSQL) /Fd$(PFM)\$(VARIETY)\ /Fo$@ sqlite3.c
284
273{}.asm{$(PFM)\$(VARIETY)}.obj: 285{}.asm{$(PFM)\$(VARIETY)}.obj:
274 $(ECHO) $@ 286 $(ECHO) $@
275 @if not exist $(PFM) mkdir $(PFM) 287 @if not exist $(PFM) mkdir $(PFM)
diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk
index 0afcab6fe96..5ae4ffb49aa 100644
--- a/mps/code/commpre.nmk
+++ b/mps/code/commpre.nmk
@@ -95,7 +95,9 @@ CRTFLAGSCOOL = /MTd
95LINKFLAGSHOT = libcmt.lib 95LINKFLAGSHOT = libcmt.lib
96LINKFLAGSCOOL = libcmtd.lib 96LINKFLAGSCOOL = libcmtd.lib
97 97
98CFLAGSSQLPRE = /nologo $(PFMDEFS)
98CFLAGSCOMMONPRE = /nologo /W4 /WX $(PFMDEFS) $(CFLAGSTARGETPRE) 99CFLAGSCOMMONPRE = /nologo /W4 /WX $(PFMDEFS) $(CFLAGSTARGETPRE)
100CFLAGSSQLPOST =
99CFLAGSCOMMONPOST = $(CFLAGSTARGETPOST) 101CFLAGSCOMMONPOST = $(CFLAGSTARGETPOST)
100 102
101# Flags for use in the variety combinations 103# Flags for use in the variety combinations
diff --git a/mps/code/event.c b/mps/code/event.c
index a3331d18c18..1bdbafb34f6 100644
--- a/mps/code/event.c
+++ b/mps/code/event.c
@@ -46,6 +46,31 @@ char *EventLast[EventKindLIMIT];
46EventControlSet EventKindControl; /* Bit set used to control output. */ 46EventControlSet EventKindControl; /* Bit set used to control output. */
47 47
48 48
49/* A single event structure output once per buffer flush. */
50EventEventClockSyncStruct eventClockSyncStruct;
51
52
53/* eventClockSync -- Populate and write the clock sync event. */
54
55static Res eventClockSync(void)
56{
57 Res res;
58 size_t size;
59
60 size= size_tAlignUp(sizeof(eventClockSyncStruct), MPS_PF_ALIGN);
61 eventClockSyncStruct.code = EventEventClockSyncCode;
62 eventClockSyncStruct.size = (EventSize)size;
63 EVENT_CLOCK(eventClockSyncStruct.clock);
64 eventClockSyncStruct.f0 = (Word)mps_clock();
65 res = (Res)mps_io_write(eventIO, (void *)&eventClockSyncStruct, size);
66 if (res != ResOK)
67 goto failWrite;
68
69 res = ResOK;
70failWrite:
71 return res;
72}
73
49/* EventFlush -- flush event buffer to the event stream */ 74/* EventFlush -- flush event buffer to the event stream */
50 75
51Res EventFlush(EventKind kind) 76Res EventFlush(EventKind kind)
@@ -78,7 +103,12 @@ Res EventFlush(EventKind kind)
78 goto failCreate; 103 goto failCreate;
79 eventIOInited = TRUE; 104 eventIOInited = TRUE;
80 } 105 }
81 106
107 /* Send an EventClockSync event */
108 res = eventClockSync();
109 if (res != ResOK)
110 goto failClockSync;
111
82 /* Writing might be faster if the size is aligned to a multiple of the 112 /* Writing might be faster if the size is aligned to a multiple of the
83 C library or kernel's buffer size. We could pad out the buffer with 113 C library or kernel's buffer size. We could pad out the buffer with
84 a marker for this purpose. */ 114 a marker for this purpose. */
@@ -88,9 +118,10 @@ Res EventFlush(EventKind kind)
88 goto failWrite; 118 goto failWrite;
89 119
90 } 120 }
91 121
92 res = ResOK; 122 res = ResOK;
93 123
124failClockSync:
94failWrite: 125failWrite:
95failCreate: 126failCreate:
96 127
@@ -178,6 +209,11 @@ void EventInit(void)
178 EventKindControl = (Word)mps_lib_telemetry_control(); 209 EventKindControl = (Word)mps_lib_telemetry_control();
179 EventInternSerial = (Serial)1; /* 0 is reserved */ 210 EventInternSerial = (Serial)1; /* 0 is reserved */
180 (void)EventInternString(MPSVersion()); /* emit version */ 211 (void)EventInternString(MPSVersion()); /* emit version */
212 EVENT7(EventInit, EVENT_VERSION_MAJOR, EVENT_VERSION_MEDIAN,
213 EVENT_VERSION_MINOR, EventCodeMAX, EventNameMAX, MPS_WORD_WIDTH,
214 mps_clocks_per_sec());
215 /* flush these initial events to get the first ClockSync out. */
216 EventSync();
181 } else { 217 } else {
182 ++eventUserCount; 218 ++eventUserCount;
183 } 219 }
diff --git a/mps/code/eventcnv.c b/mps/code/eventcnv.c
index fcd569add74..99974831908 100644
--- a/mps/code/eventcnv.c
+++ b/mps/code/eventcnv.c
@@ -2,40 +2,49 @@
2 * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. 2 * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
3 * 3 *
4 * This is a command-line tool that converts a binary format telemetry output 4 * This is a command-line tool that converts a binary format telemetry output
5 * stream from the MPS into several textual formats. 5 * stream from the MPS into a more-portable textual format.
6 * 6 *
7 * The default MPS library will write a telemetry stream to a file called 7 * eventcnv can only read binary-format files that come from an MPS
8 * "mpsio.log" when the environment variable MPS_TELEMETRY_CONTROL is set 8 * compiled on the same platform, whereas the text-format files it
9 * to an integer whose bits select event kinds. For example: 9 * produces can be processed on any platform.
10 * 10 *
11 * MPS_TELEMETRY_CONTROL=7 amcss 11 * The default MPS library will write a telemetry stream to a file
12 * when the environment variable MPS_TELEMETRY_CONTROL is set to an
13 * integer whose bits select event kinds. For example:
12 * 14 *
13 * will run the amcss test program and emit a file with event kinds 0, 1, 2. 15 * MPS_TELEMETRY_CONTROL=7 amcss
14 * The file can then be converted into text format with a command like:
15 * 16 *
16 * eventcnv -v | sort 17 * will run the amcss test program and emit a telemetry file with
18 * event kinds 0, 1, 2. The file can then be converted into a sorted
19 * text format log with a command like:
17 * 20 *
18 * Note that the eventcnv program can only read streams that come from an 21 * eventcnv | sort > mps-events.txt
19 * MPS compiled on the same platform.
20 * 22 *
23 * These text-format files have one line per event, and can be
24 * manipulated by various programs systems in the usual Unix way.
25 *
26 * The binary telemetry filename can be specified with a -f
27 * command-line argument (use -f - to specify standard input). If no
28 * filename is specified on the command line, the environment variable
29 * MPS_TELEMETRY_FILENAME is consulted (this is the same environment
30 * variable used to specify the telemetry file to the MPS library).
31 * If the environment variable does not exist, the default filename of
32 * "mpsio.log" is used.
33 *
21 * $Id$ 34 * $Id$
22 */ 35 */
23 36
24#include "config.h" 37#include "config.h"
25
26#include "eventdef.h" 38#include "eventdef.h"
27#include "eventcom.h" 39#include "eventcom.h"
28#include "eventpro.h" 40#include "eventpro.h"
29#include "mpmtypes.h"
30#include "testlib.h" /* for ulongest_t and associated print formats */ 41#include "testlib.h" /* for ulongest_t and associated print formats */
31 42
32#include <stddef.h> /* for size_t */ 43#include <stddef.h> /* for size_t */
33#include <stdio.h> /* for printf */ 44#include <stdio.h> /* for printf */
34#include <stdarg.h> /* for va_list */
35#include <stdlib.h> /* for EXIT_FAILURE */ 45#include <stdlib.h> /* for EXIT_FAILURE */
36#include <assert.h> /* for assert */ 46#include <assert.h> /* for assert */
37#include <string.h> /* for strcmp */ 47#include <string.h> /* for strcmp */
38#include <math.h> /* for sqrt */
39#include "mpstd.h" 48#include "mpstd.h"
40 49
41#ifdef MPS_BUILD_MV 50#ifdef MPS_BUILD_MV
@@ -44,47 +53,45 @@
44#pragma warning( disable : 4996 ) 53#pragma warning( disable : 4996 )
45#endif 54#endif
46 55
47 56#define DEFAULT_TELEMETRY_FILENAME "mpsio.log"
48 57#define TELEMETRY_FILENAME_ENVAR "MPS_TELEMETRY_FILENAME"
49typedef unsigned int uint;
50typedef unsigned long ulong;
51
52 58
53static EventClock eventTime; /* current event time */ 59static EventClock eventTime; /* current event time */
60static char *prog; /* program name */
54 61
62/* Errors and Warnings */
55 63
56/* event counters */ 64/* fevwarn -- flush stdout, write message to stderr */
57
58typedef unsigned long eventCountArray[EventCodeMAX+1];
59static unsigned long bucketEventCount[EventCodeMAX+1];
60static unsigned long totalEventCount[EventCodeMAX+1];
61
62
63static char *prog; /* program name */
64 65
66static void fevwarn(const char *prefix, const char *format, va_list args)
67{
68 fflush(stdout); /* sync */
69 fprintf(stderr, "%s: %s @", prog, prefix);
70 EVENT_CLOCK_PRINT(stderr, eventTime);
71 fprintf(stderr, " ");
72 vfprintf(stderr, format, args);
73 fprintf(stderr, "\n");
74}
65 75
66/* command-line arguments */ 76/* evwarn -- flush stdout, warn to stderr */
67 77
68static Bool verbose = FALSE; 78static void evwarn(const char *format, ...)
69/* style: '\0' for human-readable, 'L' for Lisp, 'C' for CDF. */ 79{
70static char style = '\0'; 80 va_list args;
71static Bool reportStats = FALSE;
72static Bool eventEnabled[EventCodeMAX+1];
73static Word bucketSize = 0;
74 81
82 va_start(args, format);
83 fevwarn("Warning", format, args);
84 va_end(args);
85}
75 86
76/* everror -- error signalling */ 87/* everror -- flush stdout, mesage to stderr, exit */
77 88
78static void everror(const char *format, ...) 89static void everror(const char *format, ...)
79{ 90{
80 va_list args; 91 va_list args;
81 92
82 fflush(stdout); /* sync */
83 fprintf(stderr, "%s: @", prog);
84 EVENT_CLOCK_PRINT(stderr, eventTime);
85 va_start(args, format); 93 va_start(args, format);
86 vfprintf(stderr, format, args); 94 fevwarn("Error", format, args);
87 fprintf(stderr, "\n");
88 va_end(args); 95 va_end(args);
89 exit(EXIT_FAILURE); 96 exit(EXIT_FAILURE);
90} 97}
@@ -95,8 +102,8 @@ static void everror(const char *format, ...)
95static void usage(void) 102static void usage(void)
96{ 103{
97 fprintf(stderr, 104 fprintf(stderr,
98 "Usage: %s [-f logfile] [-p] [-v] [-e events] [-b size]" 105 "Usage: %s [-f logfile] [-h]\n"
99 " [-S[LC]] [-?]\nSee guide.mps.telemetry for instructions.\n", 106 "See \"Telemetry\" in the reference manual for instructions.\n",
100 prog); 107 prog);
101} 108}
102 109
@@ -110,41 +117,11 @@ static void usageError(void)
110} 117}
111 118
112 119
113/* parseEventSpec -- parses an event spec
114 *
115 * The spec is of the form: <name>[(+|-)<name>]...
116 * The first name can be 'all'.
117 */
118
119static void parseEventSpec(const char *arg)
120{
121 size_t arglen;
122 EventCode i;
123 const char *end;
124 char name[EventNameMAX+1];
125 Bool enabled = TRUE;
126
127 end = arg + strlen(arg);
128 for(i = 0; i <= EventCodeMAX; ++i)
129 eventEnabled[i] = FALSE;
130 do {
131 arglen = strcspn(arg, "+-");
132 strncpy(name, arg, arglen); name[arglen] = '\0';
133 if (strcmp(name, "all") == 0) {
134 for(i = 0; i <= EventCodeMAX; ++i)
135 eventEnabled[i] = EventCodeIsValid(i);
136 } else
137 eventEnabled[EventName2Code(name)] = enabled;
138 enabled = (arg[arglen] == '+'); arg += arglen + 1;
139 } while (arg < end);
140}
141
142
143/* parseArgs -- parse command line arguments, return log file name */ 120/* parseArgs -- parse command line arguments, return log file name */
144 121
145static char *parseArgs(int argc, char *argv[]) 122static char *parseArgs(int argc, char *argv[])
146{ 123{
147 char *name = "mpsio.log"; 124 char *name = NULL;
148 int i = 1; 125 int i = 1;
149 126
150 if (argc >= 1) 127 if (argc >= 1)
@@ -162,34 +139,9 @@ static char *parseArgs(int argc, char *argv[])
162 else 139 else
163 name = argv[i]; 140 name = argv[i];
164 break; 141 break;
165 case 'v': /* verbosity */
166 verbose = TRUE;
167 break;
168 case 'e': { /* event statistics */
169 reportStats = TRUE;
170 ++ i;
171 if (i == argc)
172 usageError();
173 else
174 parseEventSpec(argv[i]);
175 } break;
176 case 'b': { /* bucket size */
177 ++ i;
178 if (i == argc)
179 usageError();
180 else {
181 int n;
182
183 n = sscanf(argv[i], "%lu", &bucketSize);
184 if (n != 1) usageError();
185 }
186 } break;
187 case 'S': /* style */
188 style = argv[i][2]; /* '\0' for human-readable, 'L' for Lisp, */
189 break; /* 'C' for CDF. */
190 case '?': case 'h': /* help */ 142 case '?': case 'h': /* help */
191 usage(); 143 usage();
192 break; 144 exit(EXIT_SUCCESS);
193 default: 145 default:
194 usageError(); 146 usageError();
195 } 147 }
@@ -200,252 +152,41 @@ static char *parseArgs(int argc, char *argv[])
200} 152}
201 153
202 154
203/* recordEvent -- record event 155/* Printing routines */
204 *
205 * This is the beginning of a system to model MPS state as events are read,
206 * but for the moment it just records which strings have been interned
207 * and which addresses have been labelled with them.
208 *
209 * NOTE: Since branch/2012-08-21/diagnostic-telemetry events are no longer
210 * in order in the event stream, so eventcnv would need some serious
211 * rethinking to model state. It's questionable that it should attempt it
212 * or event try to label addresses, but instead leave that to later stages of
213 * processing. RB 2012-09-07
214 */
215 156
216static void recordEvent(EventProc proc, Event event, EventClock etime) 157static void printHex(ulongest_t val)
217{ 158{
218 Res res; 159 printf(" %"PRIXLONGEST, (ulongest_t)val);
219 160}
220 res = EventRecord(proc, event, etime); 161
221 if (res != ResOK) 162#define printParamP(p) printHex((ulongest_t)p)
222 everror("Can't record event: error %d.", res); 163#define printParamA(a) printHex((ulongest_t)a)
223 switch(event->any.code) { 164#define printParamU(u) printHex((ulongest_t)u)
224 default: 165#define printParamW(w) printHex((ulongest_t)w)
225 break; 166#define printParamB(b) printHex((ulongest_t)b)
226 } 167
168static void printParamD(double d)
169{
170 printf(" %.10G", d);
227} 171}
228 172
229 173static void printParamS(const char *str)
230/* Printing routines */
231
232
233/* printStr -- print an EventString */
234
235static void printStr(const char *str, Bool quotes)
236{ 174{
237 size_t i; 175 size_t i;
238 176 putchar(' ');
239 if (quotes) putchar('"'); 177 putchar('"');
240 for (i = 0; str[i] != '\0'; ++i) { 178 for (i = 0; str[i] != '\0'; ++i) {
241 char c = str[i]; 179 char c = str[i];
242 if (quotes && (c == '"' || c == '\\')) putchar('\\'); 180 if (c == '"' || c == '\\') putchar('\\');
243 putchar(c); 181 putchar(c);
244 } 182 }
245 if (quotes) putchar('"'); 183 putchar('"');
246}
247
248
249/* printAddr -- print an Addr or its label */
250
251static void printAddr(EventProc proc, Addr addr)
252{
253 Word label;
254
255 label = AddrLabel(proc, addr);
256 if (label != 0 && addr != 0) {
257 /* We assume labelling zero is meant to record a point in time */
258 const char *sym = LabelText(proc, label);
259 if (sym != NULL) {
260 putchar(' ');
261 printStr(sym, (style == 'C'));
262 } else {
263 printf((style == '\0') ?
264 " sym%05"PRIXLONGEST :
265 " \"sym %"PRIXLONGEST"\"",
266 (ulongest_t)label);
267 }
268 } else
269 printf(style != 'C' ?
270 " %0"PRIwWORD PRIXLONGEST :
271 " %"PRIuLONGEST,
272 (ulongest_t)addr);
273} 184}
274 185
275 186/* readLog -- read and parse log */
276/* reportEventResults -- report event counts from a count array */
277
278static void reportEventResults(eventCountArray eventCounts)
279{
280 EventCode i;
281 unsigned long total = 0;
282
283 for(i = 0; i <= EventCodeMAX; ++i) {
284 total += eventCounts[i];
285 if (eventEnabled[i])
286 switch (style) {
287 case '\0':
288 printf(" %5lu", eventCounts[i]);
289 break;
290 case 'L':
291 printf(" %lX", eventCounts[i]);
292 break;
293 case 'C':
294 printf(", %lu", eventCounts[i]);
295 break;
296 }
297 }
298 switch (style) {
299 case '\0':
300 printf(" %5lu\n", total);
301 break;
302 case 'L':
303 printf(" %lX)\n", total);
304 break;
305 case 'C':
306 printf(", %lu\n", total);
307 break;
308 }
309}
310
311
312/* reportBucketResults -- report results of the current bucket */
313
314static void reportBucketResults(EventClock bucketLimit)
315{
316 switch (style) {
317 case '\0':
318 EVENT_CLOCK_PRINT(stdout, bucketLimit);
319 putchar(':');
320 break;
321 case 'L':
322 putchar('(');
323 EVENT_CLOCK_PRINT(stdout, bucketLimit);
324 break;
325 case 'C':
326 EVENT_CLOCK_PRINT(stdout, bucketLimit);
327 break;
328 }
329 if (reportStats) {
330 reportEventResults(bucketEventCount);
331 }
332}
333
334
335/* clearBucket -- clear bucket */
336
337static void clearBucket(void)
338{
339 EventCode i;
340
341 for(i = 0; i <= EventCodeMAX; ++i)
342 bucketEventCount[i] = 0;
343}
344
345
346/* printParam* -- printing functions for event parameter types */
347
348static void printParamA(EventProc proc, char *styleConv, Addr addr)
349{
350 if (style != 'L') {
351 if (style == 'C') putchar(',');
352 printAddr(proc, addr);
353 } else
354 printf(styleConv, (ulongest_t)addr);
355}
356
357static void printParamP(EventProc proc, char *styleConv, void *p)
358{
359 UNUSED(proc);
360 printf(styleConv, (ulongest_t)p);
361}
362
363static void printParamU(EventProc proc, char *styleConv, unsigned u)
364{
365 UNUSED(proc);
366 printf(styleConv, (ulongest_t)u);
367}
368
369static void printParamW(EventProc proc, char *styleConv, Word w)
370{
371 UNUSED(proc);
372 printf(styleConv, (ulongest_t)w);
373}
374
375static void printParamD(EventProc proc, char *styleConv, double d)
376{
377 UNUSED(proc);
378 UNUSED(styleConv);
379 switch (style) {
380 case '\0':
381 printf(" %#8.3g", d); break;
382 case 'C':
383 printf(", %.10G", d); break;
384 case 'L':
385 printf(" %#.10G", d); break;
386 }
387}
388
389static void printParamS(EventProc proc, char *styleConv, const char *s)
390{
391 UNUSED(proc);
392 UNUSED(styleConv);
393 if (style == 'C') putchar(',');
394 putchar(' ');
395 printStr(s, (style == 'C' || style == 'L'));
396}
397
398static void printParamB(EventProc proc, char *styleConv, Bool b)
399{
400 UNUSED(proc);
401 UNUSED(proc);
402 printf(styleConv, (ulongest_t)b);
403}
404
405
406/* readLog -- read and parse log
407 *
408 * This is the heart of eventcnv: It reads an event log using EventRead.
409 * It updates the counters. If verbose is true, it looks up the format,
410 * parses the arguments, and prints a representation of the event. Each
411 * argument is printed using printArg (see RELATION, below), except for
412 * some event types that are handled specially.
413 */
414 187
415static void readLog(EventProc proc) 188static void readLog(EventProc proc)
416{ 189{
417 EventCode c;
418 Word bucketLimit = bucketSize;
419 char *styleConv = NULL; /* suppress uninit warning */
420
421 /* Print event count header. */
422 if (reportStats) {
423 if (style == '\0') {
424 printf(" bucket:");
425 for(c = 0; c <= EventCodeMAX; ++c)
426 if (eventEnabled[c])
427 printf(" %04X", (unsigned)c);
428 printf(" all\n");
429 }
430 }
431
432 /* Init event counts. */
433 for(c = 0; c <= EventCodeMAX; ++c)
434 totalEventCount[c] = 0;
435 clearBucket();
436
437 /* Init style. */
438 switch (style) {
439 case '\0':
440 styleConv = " %8"PRIXLONGEST; break;
441 case 'C':
442 styleConv = ", %"PRIuLONGEST; break;
443 case 'L':
444 styleConv = " %"PRIXLONGEST; break;
445 default:
446 everror("Unknown style code '%c'", style);
447 }
448
449 while (TRUE) { /* loop for each event */ 190 while (TRUE) { /* loop for each event */
450 Event event; 191 Event event;
451 EventCode code; 192 EventCode code;
@@ -457,181 +198,56 @@ static void readLog(EventProc proc)
457 if (res != ResOK) everror("Truncated log"); 198 if (res != ResOK) everror("Truncated log");
458 eventTime = event->any.clock; 199 eventTime = event->any.clock;
459 code = event->any.code; 200 code = event->any.code;
460 201
461 /* Output bucket, if necessary, and update counters */ 202 /* Special handling for some events, prior to text output */
462 if (bucketSize != 0 && eventTime >= bucketLimit) { 203
463 reportBucketResults(bucketLimit-1); 204 switch(code) {
464 clearBucket(); 205 case EventEventInitCode:
465 do { 206 if ((event->EventInit.f0 != EVENT_VERSION_MAJOR) ||
466 bucketLimit += bucketSize; 207 (event->EventInit.f1 != EVENT_VERSION_MEDIAN) ||
467 } while (eventTime >= bucketLimit); 208 (event->EventInit.f2 != EVENT_VERSION_MINOR))
468 } 209 evwarn("Event log version does not match: %d.%d.%d vs %d.%d.%d",
469 if (reportStats) { 210 event->EventInit.f0,
470 ++bucketEventCount[code]; 211 event->EventInit.f1,
471 ++totalEventCount[code]; 212 event->EventInit.f2,
213 EVENT_VERSION_MAJOR,
214 EVENT_VERSION_MEDIAN,
215 EVENT_VERSION_MINOR);
216
217 if (event->EventInit.f3 > EventCodeMAX)
218 evwarn("Event log may contain unknown events with codes from %d to %d",
219 EventCodeMAX+1, event->EventInit.f3);
220
221 if (event->EventInit.f5 != MPS_WORD_WIDTH)
222 /* This probably can't happen; other things will break
223 * before we get here */
224 evwarn("Event log has incompatible word width: %d instead of %d",
225 event->EventInit.f5,
226 MPS_WORD_WIDTH);
227 break;
472 } 228 }
473 229
474 /* Output event. */ 230 EVENT_CLOCK_PRINT(stdout, eventTime);
475 if (verbose) { 231 printf(" %4X", (unsigned)code);
476 if (style == 'L') putchar('(');
477 232
478 switch (style) { 233 switch (code) {
479 case '\0': case 'L': 234#define EVENT_PARAM_PRINT(name, index, sort, ident) \
480 EVENT_CLOCK_PRINT(stdout, eventTime); 235 printParam##sort(event->name.f##index);
481 putchar(' '); 236#define EVENT_PRINT(X, name, code, always, kind) \
237 case code: \
238 EVENT_##name##_PARAMS(EVENT_PARAM_PRINT, name) \
482 break; 239 break;
483 case 'C': 240 EVENT_LIST(EVENT_PRINT, X)
484 EVENT_CLOCK_PRINT(stdout, eventTime); 241 default:
485 fputs(", ", stdout); 242 evwarn("Unknown event code %d", code);
486 break;
487 }
488
489 switch (style) {
490 case '\0': case 'L': {
491 printf("%-19s ", EventCode2Name(code));
492 } break;
493 case 'C':
494 printf("%u", (unsigned)code);
495 break;
496 }
497
498 switch (code) {
499
500 case EventLabelCode:
501 switch (style) {
502 case '\0': case 'C':
503 {
504 const char *sym = LabelText(proc, event->Label.f1);
505 printf(style == '\0' ?
506 " %08"PRIXLONGEST" " :
507 ", %"PRIuLONGEST", ",
508 (ulongest_t)event->Label.f0);
509 if (sym != NULL) {
510 printStr(sym, (style == 'C'));
511 } else {
512 printf(style == '\0' ?
513 "sym %05"PRIXLONGEST :
514 "sym %"PRIXLONGEST"\"",
515 (ulongest_t)event->Label.f1);
516 }
517 }
518 break;
519 case 'L':
520 printf(" %"PRIXLONGEST" %"PRIXLONGEST,
521 (ulongest_t)event->Label.f0,
522 (ulongest_t)event->Label.f1);
523 break;
524 }
525 break;
526
527 case EventMeterValuesCode:
528 switch (style) {
529 case '\0':
530 if (event->MeterValues.f3 == 0) {
531 printf(" %08"PRIXLONGEST" 0 N/A N/A N/A N/A",
532 (ulongest_t)event->MeterValues.f0);
533 } else {
534 double mean = event->MeterValues.f1 / (double)event->MeterValues.f3;
535 /* .stddev: stddev = sqrt(meanSquared - mean^2), but see */
536 /* <code/meter.c#limitation.variance>. */
537 double stddev = sqrt(fabs(event->MeterValues.f2
538 - (mean * mean)));
539 printf(" %08"PRIXLONGEST" %8u %8u %8u %#8.3g %#8.3g",
540 (ulongest_t)event->MeterValues.f0, (uint)event->MeterValues.f3,
541 (uint)event->MeterValues.f4, (uint)event->MeterValues.f5,
542 mean, stddev);
543 }
544 printAddr(proc, (Addr)event->MeterValues.f0);
545 break;
546
547 case 'C':
548 putchar(',');
549 printAddr(proc, (Addr)event->MeterValues.f0);
550 printf(", %.10G, %.10G, %u, %u, %u",
551 event->MeterValues.f1, event->MeterValues.f2,
552 (uint)event->MeterValues.f3, (uint)event->MeterValues.f4,
553 (uint)event->MeterValues.f5);
554 break;
555
556 case 'L':
557 printf(" %"PRIXLONGEST" %#.10G %#.10G %X %X %X",
558 (ulongest_t)event->MeterValues.f0,
559 event->MeterValues.f1, event->MeterValues.f2,
560 (uint)event->MeterValues.f3, (uint)event->MeterValues.f4,
561 (uint)event->MeterValues.f5);
562 break;
563 }
564 break;
565
566 case EventPoolInitCode: /* pool, arena, class */
567 printf(styleConv, (ulongest_t)event->PoolInit.f0);
568 printf(styleConv, (ulongest_t)event->PoolInit.f1);
569 /* class is a Pointer, but we label them, so call printAddr */
570 if (style != 'L') {
571 if (style == 'C') putchar(',');
572 printAddr(proc, (Addr)event->PoolInit.f2);
573 } else
574 printf(styleConv, (ulongest_t)event->PoolInit.f2);
575 break;
576
577 default:
578#define EVENT_PARAM_PRINT(name, index, sort, ident) \
579 printParam##sort(proc, styleConv, event->name.f##index);
580#define EVENT_PRINT(X, name, code, always, kind) \
581 case code: \
582 EVENT_##name##_PARAMS(EVENT_PARAM_PRINT, name) \
583 break;
584 switch (code) { EVENT_LIST(EVENT_PRINT, X) }
585 }
586
587 if (style == 'L') putchar(')');
588 putchar('\n');
589 fflush(stdout);
590 } 243 }
591 recordEvent(proc, event, eventTime); 244
245 putchar('\n');
246 fflush(stdout);
592 EventDestroy(proc, event); 247 EventDestroy(proc, event);
593 } /* while(!feof(input)) */ 248 } /* while(!feof(input)) */
594
595 /* report last bucket (partial) */
596 if (bucketSize != 0) {
597 reportBucketResults(eventTime);
598 }
599 if (reportStats) {
600 /* report totals */
601 switch (style) {
602 case '\0':
603 printf("\n run:");
604 break;
605 case 'L':
606 printf("(t");
607 break;
608 case 'C':
609 {
610 /* FIXME: This attempted to print the event stats on a row that
611 resembled a kind of final event, but the event clock no longer runs
612 monotonically upwards. */
613 EventClock last = eventTime + 1;
614 EVENT_CLOCK_PRINT(stdout, last);
615 }
616 break;
617 }
618 reportEventResults(totalEventCount);
619
620 /* explain event codes */
621 if (style == '\0') {
622 printf("\n");
623 for(c = 0; c <= EventCodeMAX; ++c)
624 if (eventEnabled[c])
625 printf(" %04X %s\n", (unsigned)c, EventCode2Name(c));
626 if (bucketSize == 0)
627 printf("\nevent clock stopped at ");
628 EVENT_CLOCK_PRINT(stdout, eventTime);
629 printf("\n");
630 }
631 }
632} 249}
633 250
634
635/* logReader -- reader function for a file log */ 251/* logReader -- reader function for a file log */
636 252
637static FILE *input; 253static FILE *input;
@@ -663,9 +279,13 @@ int main(int argc, char *argv[])
663 assert(CHECKCONV(ulongest_t, Addr)); 279 assert(CHECKCONV(ulongest_t, Addr));
664 assert(CHECKCONV(ulongest_t, void *)); 280 assert(CHECKCONV(ulongest_t, void *));
665 assert(CHECKCONV(ulongest_t, EventCode)); 281 assert(CHECKCONV(ulongest_t, EventCode));
666 assert(CHECKCONV(Addr, void *)); /* for labelled pointers */
667 282
668 filename = parseArgs(argc, argv); 283 filename = parseArgs(argc, argv);
284 if (!filename) {
285 filename = getenv(TELEMETRY_FILENAME_ENVAR);
286 if(!filename)
287 filename = DEFAULT_TELEMETRY_FILENAME;
288 }
669 289
670 if (strcmp(filename, "-") == 0) 290 if (strcmp(filename, "-") == 0)
671 input = stdin; 291 input = stdin;
@@ -688,7 +308,7 @@ int main(int argc, char *argv[])
688 308
689/* C. COPYRIGHT AND LICENSE 309/* C. COPYRIGHT AND LICENSE
690 * 310 *
691 * Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>. 311 * Copyright (C) 2001-2012 Ravenbrook Limited <http://www.ravenbrook.com/>.
692 * All rights reserved. This is an open source license. Contact 312 * All rights reserved. This is an open source license. Contact
693 * Ravenbrook for commercial licensing options. 313 * Ravenbrook for commercial licensing options.
694 * 314 *
diff --git a/mps/code/eventdef.h b/mps/code/eventdef.h
index df80bb6d1c2..70a32393d3d 100644
--- a/mps/code/eventdef.h
+++ b/mps/code/eventdef.h
@@ -37,8 +37,8 @@
37 */ 37 */
38 38
39#define EVENT_VERSION_MAJOR ((unsigned)1) 39#define EVENT_VERSION_MAJOR ((unsigned)1)
40#define EVENT_VERSION_MEDIAN ((unsigned)0) 40#define EVENT_VERSION_MEDIAN ((unsigned)1)
41#define EVENT_VERSION_MINOR ((unsigned)0) 41#define EVENT_VERSION_MINOR ((unsigned)3)
42 42
43 43
44/* EVENT_LIST -- list of event types and general properties 44/* EVENT_LIST -- list of event types and general properties
@@ -68,7 +68,7 @@
68 */ 68 */
69 69
70#define EventNameMAX ((size_t)19) 70#define EventNameMAX ((size_t)19)
71#define EventCodeMAX ((EventCode)0x0073) 71#define EventCodeMAX ((EventCode)0x0078)
72 72
73#define EVENT_LIST(EVENT, X) \ 73#define EVENT_LIST(EVENT, X) \
74 /* 0123456789012345678 <- don't exceed without changing EventNameMAX */ \ 74 /* 0123456789012345678 <- don't exceed without changing EventNameMAX */ \
@@ -179,7 +179,13 @@
179 EVENT(X, TraceFindGrey , 0x0070, TRUE, Trace) \ 179 EVENT(X, TraceFindGrey , 0x0070, TRUE, Trace) \
180 EVENT(X, TraceBandAdvance , 0x0071, TRUE, Trace) \ 180 EVENT(X, TraceBandAdvance , 0x0071, TRUE, Trace) \
181 EVENT(X, AWLDeclineTotal , 0x0072, TRUE, Trace) \ 181 EVENT(X, AWLDeclineTotal , 0x0072, TRUE, Trace) \
182 EVENT(X, AWLDeclineSeg , 0x0073, TRUE, Trace) 182 EVENT(X, AWLDeclineSeg , 0x0073, TRUE, Trace) \
183 EVENT(X, EventInit , 0x0074, TRUE, Arena) \
184 EVENT(X, EventClockSync , 0x0075, TRUE, Arena) \
185 EVENT(X, ArenaAccess , 0x0076, TRUE, Arena) \
186 EVENT(X, ArenaPoll , 0x0077, TRUE, Arena) \
187 EVENT(X, ArenaSetEmergency , 0x0078, TRUE, Arena)
188
183 189
184 190
185/* Remember to update EventNameMAX and EventCodeMAX in eventcom.h! 191/* Remember to update EventNameMAX and EventCodeMAX in eventcom.h!
@@ -620,6 +626,32 @@
620 PARAM(X, 0, P, seg) /* segment declined single access */ \ 626 PARAM(X, 0, P, seg) /* segment declined single access */ \
621 PARAM(X, 1, W, singleAccesses) /* single accesses this cycle */ 627 PARAM(X, 1, W, singleAccesses) /* single accesses this cycle */
622 628
629#define EVENT_EventInit_PARAMS(PARAM, X) \
630 PARAM(X, 0, U, major) /* EVENT_VERSION_MAJOR */ \
631 PARAM(X, 1, U, median) /* EVENT_VERSION_MEDIAN */ \
632 PARAM(X, 2, U, minor) /* EVENT_VERSION_MINOR */ \
633 PARAM(X, 3, U, maxCode) /* EventCodeMAX */ \
634 PARAM(X, 4, U, maxNameLen) /* EventNameMAX */ \
635 PARAM(X, 5, U, wordWidth) /* MPS_WORD_WIDTH */ \
636 PARAM(X, 6, W, clocksPerSec) /* mps_clocks_per_sec() */
637
638#define EVENT_EventClockSync_PARAMS(PARAM, X) \
639 PARAM(X, 0, W, clock) /* mps_clock() value */
640
641#define EVENT_ArenaAccess_PARAMS(PARAM, X) \
642 PARAM(X, 0, P, arena) \
643 PARAM(X, 1, W, count) \
644 PARAM(X, 2, P, addr) \
645 PARAM(X, 3, U, mode)
646
647#define EVENT_ArenaPoll_PARAMS(PARAM, X) \
648 PARAM(X, 0, P, arena) \
649 PARAM(X, 1, W, start) \
650 PARAM(X, 2, W, quanta)
651
652#define EVENT_ArenaSetEmergency_PARAMS(PARAM, X) \
653 PARAM(X, 0, P, arena) \
654 PARAM(X, 1, B, emergency)
623 655
624#endif /* eventdef_h */ 656#endif /* eventdef_h */
625 657
diff --git a/mps/code/eventsql.c b/mps/code/eventsql.c
new file mode 100644
index 00000000000..1fdafe4624e
--- /dev/null
+++ b/mps/code/eventsql.c
@@ -0,0 +1,1004 @@
1/* eventsql.c: event log to SQLite importer.
2 *
3 * $Id$
4 *
5 * Copyright (c) 2012 Ravenbrook Limited. See end of file for license.
6 *
7 * This is a command-line tool that imports events from a text-format
8 * MPS telemetry file into a SQLite database file.
9 *
10 * The default MPS library will write a binary-format telemetry file
11 * which can be converted into a text-format file using the eventcnv
12 * program (q.v.).
13 *
14 * Each event type gets its own table in the database. These tables
15 * are created from the definitions in eventdef.h if they don't
16 * already exist. Each event becomes a single row in the appropriate
17 * table, which has a column for each event parameter, a time column
18 * for the event time field, and a log_serial column to identify the
19 * source log file. Because the database schema depends on the event
20 * definitions in eventdef.h, eventsql has to be compiled using the
21 * same event header files as those used to compile the MPS and
22 * eventcnv which generated and processed the telemetry output.
23 *
24 * The program also creates several other tables: three 'glue' tables
25 * containing event metadata - event_kind (one row per kind),
26 * event_type (one row per type), and event_param (one row per
27 * parameter), all derived from eventdef.h - and the event_log table
28 * which has one row per log file imported (the log_serial column in
29 * the event tables is a primary key to this event_log table).
30 *
31 * No tables are created if they already exist, unless the -r
32 * (rebuild) switch is given.
33 *
34 * Options:
35 *
36 * -v (verbose): Increase verbosity. eventsql logs to stderr. By
37 * default, it doesn't log much; it can be made more and more
38 * loquacious by adding more -v switches.
39 *
40 * -p (progress): Show progress with a series of dots written to
41 * standard output (one dot per 100,000 events processed). Defaults
42 * on if -v specified, off otherwise.
43 *
44 * -t (test): Run unit tests on parts of eventsql. There aren't many
45 * of these. TODO: write more unit tests.
46 *
47 * -d (delete): Delete the SQL file before importing.
48 *
49 * -f (force): Import the events to SQL even if the SQL database
50 * already includes a record of importing a matching log file.
51 *
52 * -r (rebuild): Drop the glue tables from SQL, which will force them
53 * to be recreated. Important if you change event types or kinds in
54 * eventdef.h.
55 *
56 * -i <logfile>: Import events from the named logfile. Defaults to
57 * standard input. If the specified file (matched by size and
58 * modtime) has previously been imported to the same database, it will
59 * not be imported again unless -f is specified.
60 *
61 * -o <database>: Import events to the named database file. If not
62 * specified, eventsql will use the MPS_TELEMETRY_DATABASE environment
63 * variable, and default to "mpsevent.db".
64 *
65 * $Id$
66 */
67
68#include "misc.h"
69#include "config.h"
70#include "eventdef.h"
71#include "eventcom.h"
72
73#include <stdio.h>
74#include <stdlib.h>
75#include <string.h>
76#include <sys/stat.h>
77
78/* on Windows, we build SQLite locally from the amalgamated sources */
79#ifdef MPS_BUILD_MV
80#include "sqlite3.h"
81#else
82#include <sqlite3.h>
83#endif
84
85#define DATABASE_NAME_ENVAR "MPS_TELEMETRY_DATABASE"
86#define DEFAULT_DATABASE_NAME "mpsevent.db"
87
88#ifdef MPS_BUILD_MV
89/* MSVC warning 4996 = stdio / C runtime 'unsafe' */
90/* Objects to: getenv, sprintf. See job001934. */
91#pragma warning( disable : 4996 )
92#define strtoll _strtoi64
93#endif
94
95
96typedef sqlite3_int64 int64;
97
98/* At non-zero verbosity levels we output rows of dots. One dot per
99 * SMALL_TICK events, BIG_TICK dots per row. */
100
101#define SMALL_TICK 100000
102#define BIG_TICK 50
103
104/* Utility code for logging to stderr with multiple log levels,
105 * and for reporting errors.
106 */
107
108unsigned int verbosity = 0;
109
110#define LOG_ALWAYS 0
111#define LOG_OFTEN 1
112#define LOG_SOMETIMES 2
113#define LOG_SELDOM 3
114#define LOG_RARELY 4
115
116static void vlog(unsigned int level, const char *format, va_list args)
117{
118 if (level <= verbosity) {
119 fflush(stderr); /* sync */
120 fprintf(stderr, "log %d: ", level);
121 vfprintf(stderr, format, args);
122 fprintf(stderr, "\n");
123 }
124}
125
126static void evlog(unsigned int level, const char *format, ...)
127{
128 va_list args;
129 va_start(args, format);
130 vlog(level, format, args);
131 va_end(args);
132}
133
134static void error(const char *format, ...)
135{
136 va_list args;
137 fprintf(stderr, "Fatal error: ");
138 va_start(args, format);
139 vlog(LOG_ALWAYS, format, args);
140 va_end(args);
141 exit(1);
142}
143
144static void sqlite_error(int res, sqlite3 *db, const char *format, ...)
145{
146 va_list args;
147 evlog(LOG_ALWAYS, "Fatal SQL error %d", res);
148 va_start(args, format);
149 vlog(LOG_ALWAYS, format, args);
150 va_end(args);
151 evlog(LOG_ALWAYS, "SQLite message: %s\n", sqlite3_errmsg(db));
152 exit(1);
153}
154
155/* global control variables set by command-line parameters. */
156
157static char *prog; /* program name */
158static int rebuild = FALSE;
159static int deleteDatabase = FALSE;
160static int runTests = FALSE;
161static int force = FALSE;
162static int progress = FALSE;
163static char *databaseName = NULL;
164static char *logFileName = NULL;
165
166static void usage(void)
167{
168 fprintf(stderr,
169 "Usage: %s [-rfdvt] [-i <logfile>] [-o <database>]\n"
170 " -h (help) : this message.\n"
171 " -r (rebuild) : re-create glue tables.\n"
172 " -f (force) : ignore previous import of same logfile.\n"
173 " -d (delete) : delete and recreate database file.\n"
174 " -v (verbose) : increase logging to stderr.\n"
175 " -p (progress): show progress with dots to stdout.\n"
176 " -t (test) : run self-tests.\n"
177 " -i <logfile> : read logfile (defaults to stdin)\n"
178 " -o <database>: write database (defaults to\n"
179 " "
180 DATABASE_NAME_ENVAR " or " DEFAULT_DATABASE_NAME ").\n",
181 prog);
182}
183
184static void usageError(void)
185{
186 usage();
187 error("Bad usage");
188}
189
190/* parseArgs -- parse command line arguments */
191
192static void parseArgs(int argc, char *argv[])
193{
194 int i = 1;
195
196 if (argc >= 1)
197 prog = argv[0];
198 else
199 prog = "unknown";
200
201 while(i < argc) { /* consider argument i */
202 if (argv[i][0] == '-') { /* it's an option argument */
203 char *p = argv[i] + 1;
204 while(*p) {
205 switch (*p) {
206 case 'v': /* verbosity */
207 ++ verbosity;
208 break;
209 case 'p': /* progress */
210 progress = TRUE;
211 break;
212 case 'r': /* rebuild */
213 rebuild = TRUE;
214 break;
215 case 'd': /* rebuild */
216 deleteDatabase = TRUE;
217 break;
218 case 'f': /* force */
219 force = TRUE;
220 break;
221 case 't': /* run tests */
222 runTests = TRUE;
223 break;
224 case 'i': /* input (log file) name */
225 if (p[1] == '\0') { /* last character in this arg; name is next arg */
226 logFileName = argv[i+1];
227 ++ i;
228 } else { /* not last character in arg; name is rest of arg */
229 logFileName = p+1;
230 }
231 continue;
232 case 'o': /* output (database file) name */
233 if (p[1] == '\0') { /* last character in this arg; name is next arg */
234 databaseName = argv[i+1];
235 ++ i;
236 } else { /* not last character in arg; name is rest of arg */
237 databaseName = p+1;
238 }
239 continue;
240 case 'h':
241 usage();
242 exit(EXIT_SUCCESS);
243 default:
244 usageError();
245 }
246 ++ p;
247 }
248 } else { /* not an option argument */
249 usageError();
250 }
251 ++ i;
252 }
253 if (verbosity > LOG_ALWAYS)
254 progress = TRUE;
255}
256
257/* openDatabase(p) opens the database file and returns a SQLite 3
258 * database connection object. */
259
260static sqlite3 *openDatabase(void)
261{
262 sqlite3 *db;
263 int res;
264
265 if (!databaseName) {
266 databaseName = getenv(DATABASE_NAME_ENVAR);
267 if(!databaseName)
268 databaseName = DEFAULT_DATABASE_NAME;
269 }
270
271 if (deleteDatabase) {
272 res = remove(databaseName);
273 if (res)
274 evlog(LOG_ALWAYS, "Could not remove database file %s", databaseName);
275 else
276 evlog(LOG_OFTEN, "Removed database file %s", databaseName);
277 }
278
279 res = sqlite3_open_v2(databaseName,
280 &db,
281 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
282 NULL); /* use default sqlite_vfs object */
283
284 if (res != SQLITE_OK)
285 sqlite_error(res, db, "Opening %s failed", databaseName);
286
287 evlog(LOG_OFTEN, "Writing to %s.",databaseName);
288
289 return db;
290}
291
292/* closeDatabase(db) closes the database opened by openDatabase(). */
293
294static void closeDatabase(sqlite3 *db)
295{
296 int res = sqlite3_close(db);
297 if (res != SQLITE_OK)
298 sqlite_error(res, db, "Closing database failed");
299 evlog(LOG_SOMETIMES, "Closed %s.", databaseName);
300}
301
302/* Utility functions for SQLite statements. */
303
304static sqlite3_stmt *prepareStatement(sqlite3 *db,
305 const char *sql)
306{
307 int res;
308 sqlite3_stmt *statement;
309 evlog(LOG_SELDOM, "Preparing statement %s", sql);
310 res = sqlite3_prepare_v2(db, sql,
311 -1, /* prepare whole string as statement */
312 &statement,
313 NULL);
314 if (res != SQLITE_OK)
315 sqlite_error(res, db, "statement preparation failed: %s", sql);
316 return statement;
317}
318
319static void finalizeStatement(sqlite3 *db,
320 sqlite3_stmt *statement)
321{
322 int res;
323 res = sqlite3_finalize(statement);
324 if (res != SQLITE_OK)
325 sqlite_error(res, db, "statement finalize failed");
326}
327
328static void runStatement(sqlite3 *db,
329 const char *sql,
330 const char *description)
331{
332 int res;
333 evlog(LOG_SELDOM, "%s: %s", description, sql);
334 res = sqlite3_exec(db,
335 sql,
336 NULL, /* No callback */
337 NULL, /* No callback closure */
338 NULL); /* error messages handled by sqlite_error */
339 if (res != SQLITE_OK)
340 sqlite_error(res, db, "%s failed - statement %s", description, sql);
341}
342
343/* Test for the existence of a table using sqlite_master table.
344 */
345
346static int tableExists(sqlite3* db, const char *tableName)
347{
348 int res;
349 int exists = 0;
350 sqlite3_stmt *statement = NULL;
351
352 statement = prepareStatement(db,
353 "SELECT 1 FROM sqlite_master WHERE type='table' AND name=?");
354 res = sqlite3_bind_text(statement, 1, tableName, -1, SQLITE_STATIC);
355 if (res != SQLITE_OK)
356 sqlite_error(res, db, "table existence bind of name failed.");
357 res = sqlite3_step(statement);
358 switch(res) {
359 case SQLITE_DONE:
360 exists = 0;
361 break;
362 case SQLITE_ROW:
363 exists = 1;
364 break;
365 default:
366 sqlite_error(res, db, "select from sqlite_master failed.");
367 }
368 finalizeStatement(db, statement);
369 return exists;
370}
371
372/* Unit test for tableExists() */
373
374static struct {
375 const char* name;
376 int exists;
377} tableTests[] = {
378 {"event_kind", TRUE},
379 {"spong", FALSE},
380 {"EVENT_SegSplit", TRUE}
381};
382
383static void testTableExists(sqlite3 *db)
384{
385 size_t i;
386 int defects = 0;
387 int tests = 0;
388 for (i=0; i < (sizeof(tableTests)/sizeof(tableTests[0])); ++i) {
389 const char *name = tableTests[i].name;
390 int exists = tableExists(db, name);
391 if (exists)
392 evlog(LOG_OFTEN, "Table exists: %s", name);
393 else
394 evlog(LOG_OFTEN, "Table does not exist: %s", name);
395 if (exists != tableTests[i].exists) {
396 evlog(LOG_ALWAYS, "tableExists test failed on table %s", name);
397 ++ defects;
398 }
399 ++ tests;
400 }
401 evlog(LOG_ALWAYS, "%d tests, %d defects found.", tests, defects);
402}
403
404/* Every time we put events from a log file into a database file, we
405 * add the log file to the event_log table, and get a serial number
406 * from SQL which is then attached to all event rows from that log.
407 * We use this to record overall SQL activity, to deter mistaken
408 * attempts to add the same log file twice, and to allow events from
409 * several different log files to share the same SQL file.
410 *
411 * When reading events from stdin, we can't so easily avoid the
412 * duplication (unless we, e.g., take a hash of the event set); we
413 * have to assume that the user is smart enough not to do that.
414 */
415
416static int64 logSerial = 0;
417
418static void registerLogFile(sqlite3 *db,
419 const char *filename)
420{
421 sqlite3_stmt *statement;
422 int res;
423 const unsigned char *name;
424 int64 completed;
425 int64 file_size;
426 int64 file_modtime;
427
428 if (filename) {
429 struct stat st;
430 res = stat(filename, &st);
431 if (res != 0)
432 error("Couldn't stat() %s", filename);
433 file_size = st.st_size;
434 file_modtime = st.st_mtime;
435
436 statement = prepareStatement(db,
437 "SELECT name, serial, completed FROM event_log"
438 " WHERE size = ? AND modtime = ?");
439 res = sqlite3_bind_int64(statement, 1, file_size);
440 if (res != SQLITE_OK)
441 sqlite_error(res, db, "event_log bind of size failed.");
442 res = sqlite3_bind_int64(statement, 2, file_modtime);
443 if (res != SQLITE_OK)
444 sqlite_error(res, db, "event_log bind of modtime failed.");
445 res = sqlite3_step(statement);
446 switch(res) {
447 case SQLITE_DONE:
448 evlog(LOG_SOMETIMES, "No log file matching '%s' found in database.", filename);
449 break;
450 case SQLITE_ROW:
451 name = sqlite3_column_text(statement, 0);
452 logSerial = sqlite3_column_int64(statement, 1);
453 completed = sqlite3_column_int64(statement, 2);
454 evlog(force ? LOG_OFTEN : LOG_ALWAYS, "Log file matching '%s' already in event_log, named \"%s\" (serial %lu, completed %lu).",
455 filename, name, logSerial, completed);
456 if (force) {
457 evlog(LOG_OFTEN, "Continuing anyway because -f specified.");
458 } else {
459 evlog(LOG_ALWAYS, "Exiting. Specify -f to force events into SQL anyway.");
460 exit(0);
461 }
462 break;
463 default:
464 sqlite_error(res, db, "select from event_log failed.");
465 }
466 finalizeStatement(db, statement);
467 } else { /* stdin */
468 filename = "<stdin>";
469 file_size = 0;
470 file_modtime = 0;
471 }
472 statement = prepareStatement(db,
473 "INSERT into event_log (name, size, modtime, completed)"
474 " VALUES (?, ?, ?, 0)");
475 res = sqlite3_bind_text(statement, 1, filename, -1, SQLITE_STATIC);
476 if (res != SQLITE_OK)
477 sqlite_error(res, db, "event_log insert bind of name failed.");
478 res = sqlite3_bind_int64(statement, 2, file_size);
479 if (res != SQLITE_OK)
480 sqlite_error(res, db, "event_log insert bind of size failed.");
481 res = sqlite3_bind_int64(statement, 3, file_modtime);
482 if (res != SQLITE_OK)
483 sqlite_error(res, db, "event_log insert bind of modtime failed.");
484 res = sqlite3_step(statement);
485 if (res != SQLITE_DONE)
486 sqlite_error(res, db, "insert into event_log failed.");
487 logSerial = sqlite3_last_insert_rowid(db);
488 evlog(LOG_SOMETIMES, "Log file %s added to event_log with serial %lu",
489 filename, logSerial);
490 finalizeStatement(db, statement);
491}
492
493static void logFileCompleted(sqlite3 *db,
494 int64 completed)
495{
496 sqlite3_stmt *statement;
497 int res;
498
499 statement = prepareStatement(db,
500 "UPDATE event_log SET completed=? WHERE serial=?");
501 res = sqlite3_bind_int64(statement, 2, logSerial);
502 if (res != SQLITE_OK)
503 sqlite_error(res, db, "event_log update bind of serial failed.");
504 res = sqlite3_bind_int64(statement, 1, completed);
505 if (res != SQLITE_OK)
506 sqlite_error(res, db, "event_log update bind of completed failed.");
507 res = sqlite3_step(statement);
508 if (res != SQLITE_DONE)
509 sqlite_error(res, db, "insert into event_log failed.");
510 evlog(LOG_SOMETIMES, "Marked in event_log: %lu events", completed);
511 finalizeStatement(db, statement);
512}
513
514/* Macro magic to make a CREATE TABLE statement for each event type. */
515
516#define EVENT_PARAM_SQL_TYPE_A "INTEGER"
517#define EVENT_PARAM_SQL_TYPE_P "INTEGER"
518#define EVENT_PARAM_SQL_TYPE_U "INTEGER"
519#define EVENT_PARAM_SQL_TYPE_W "INTEGER"
520#define EVENT_PARAM_SQL_TYPE_D "REAL "
521#define EVENT_PARAM_SQL_TYPE_S "TEXT "
522#define EVENT_PARAM_SQL_TYPE_B "INTEGER"
523
524#define EVENT_PARAM_SQL_COLUMN(X, index, sort, ident) \
525 "\"" #ident "\" " EVENT_PARAM_SQL_TYPE_##sort ", "
526
527#define EVENT_TABLE_CREATE(X, name, code, always, kind) \
528 "CREATE TABLE IF NOT EXISTS EVENT_" #name " ( " \
529 EVENT_##name##_PARAMS(EVENT_PARAM_SQL_COLUMN, X) \
530 "time INTEGER, " \
531 "log_serial INTEGER)",
532
533/* An array of table-creation statement strings. */
534
535const char *createStatements[] = {
536 "CREATE TABLE IF NOT EXISTS event_kind (name TEXT,"
537 " description TEXT,"
538 " enum INTEGER PRIMARY KEY)",
539
540 "CREATE TABLE IF NOT EXISTS event_type (name TEXT,"
541 " code INTEGER PRIMARY KEY,"
542 " always INTEGER,"
543 " kind INTEGER,"
544 " FOREIGN KEY (kind) REFERENCES event_kind(enum));",
545
546 "CREATE TABLE IF NOT EXISTS event_param (type INTEGER,"
547 " param_index INTEGER,"
548 " sort TEXT,"
549 " ident TEXT,"
550 " FOREIGN KEY (type) REFERENCES event_type(code));",
551
552 "CREATE TABLE IF NOT EXISTS event_log (name TEXT,"
553 " size INTEGER,"
554 " modtime INTEGER,"
555 " completed INTEGER,"
556 " serial INTEGER PRIMARY KEY AUTOINCREMENT)",
557
558 EVENT_LIST(EVENT_TABLE_CREATE, X)
559};
560
561/* makeTables makes all the tables. */
562
563static void makeTables(sqlite3 *db)
564{
565 size_t i;
566 evlog(LOG_SOMETIMES, "Creating tables.");
567
568 for (i=0; i < (sizeof(createStatements)/sizeof(createStatements[0])); ++i) {
569 runStatement(db, createStatements[i], "Table creation");
570 }
571}
572
573const char *glueTables[] = {
574 "event_kind",
575 "event_type",
576 "event_param",
577};
578
579static void dropGlueTables(sqlite3 *db)
580{
581 size_t i;
582 int res;
583 char sql[1024];
584
585 evlog(LOG_ALWAYS, "Dropping glue tables so they are rebuilt.");
586
587 for (i=0; i < (sizeof(glueTables)/sizeof(glueTables[0])); ++i) {
588 evlog(LOG_SOMETIMES, "Dropping table %s", glueTables[i]);
589 sprintf(sql, "DROP TABLE %s", glueTables[i]);
590 res = sqlite3_exec(db,
591 sql,
592 NULL, /* No callback */
593 NULL, /* No callback closure */
594 NULL); /* error messages handled by sqlite_error */
595 /* Don't check for errors. */
596 (void)res;
597 }
598}
599
600/* Populate the metadata "glue" tables event_kind, event_type, and
601 * event_param. */
602
603#define EVENT_KIND_DO_INSERT(X, name, description) \
604 res = sqlite3_bind_text(statement, 1, #name, -1, SQLITE_STATIC); \
605 if (res != SQLITE_OK) \
606 sqlite_error(res, db, "event_kind bind of name \"" #name "\" failed."); \
607 res = sqlite3_bind_text(statement, 2, description, -1, SQLITE_STATIC); \
608 if (res != SQLITE_OK) \
609 sqlite_error(res, db, "event_kind bind of description \"" description "\" failed."); \
610 res = sqlite3_bind_int(statement, 3, i); \
611 if (res != SQLITE_OK) \
612 sqlite_error(res, db, "event_kind bind of enum %d failed.", i); \
613 ++i; \
614 res = sqlite3_step(statement); \
615 if (res != SQLITE_DONE) \
616 sqlite_error(res, db, "event_kind insert of name \"" #name "\" failed."); \
617 if (sqlite3_changes(db) != 0) \
618 evlog(LOG_SOMETIMES, "Insert of event_kind row for \"" #name "\" affected %d rows.", sqlite3_changes(db)); \
619 res = sqlite3_reset(statement); \
620 if (res != SQLITE_OK) \
621 sqlite_error(res, db, "Couldn't reset event_kind insert statement.");
622
623#define EVENT_TYPE_DO_INSERT(X, name, code, always, kind) \
624 res = sqlite3_bind_text(statement, 1, #name, -1, SQLITE_STATIC); \
625 if (res != SQLITE_OK) \
626 sqlite_error(res, db, "event_type bind of name \"" #name "\" failed."); \
627 res = sqlite3_bind_int(statement, 2, code); \
628 if (res != SQLITE_OK) \
629 sqlite_error(res, db, "event_type bind of code %d failed.", code); \
630 res = sqlite3_bind_int(statement, 3, always); \
631 if (res != SQLITE_OK) \
632 sqlite_error(res, db, "event_type bind of always for name \"" #name "\" failed."); \
633 res = sqlite3_bind_int(statement, 4, EventKind##kind); \
634 if (res != SQLITE_OK) \
635 sqlite_error(res, db, "event_type bind of kind for name \"" #name "\" failed."); \
636 res = sqlite3_step(statement); \
637 if (res != SQLITE_DONE) \
638 sqlite_error(res, db, "event_type insert of name \"" #name "\" failed."); \
639 if (sqlite3_changes(db) != 0) \
640 evlog(LOG_SOMETIMES, "Insert of event_type row for \"" #name "\" affected %d rows.", sqlite3_changes(db)); \
641 res = sqlite3_reset(statement); \
642 if (res != SQLITE_OK) \
643 sqlite_error(res, db, "Couldn't reset event_type insert statement.");
644
645#define EVENT_PARAM_DO_INSERT(code, index, sort, ident) \
646 res = sqlite3_bind_int(statement, 1, code); \
647 if (res != SQLITE_OK) \
648 sqlite_error(res, db, "event_param bind of code %d failed.", code); \
649 res = sqlite3_bind_int(statement, 2, index); \
650 if (res != SQLITE_OK) \
651 sqlite_error(res, db, "event_param bind of index %d failed.", index); \
652 res = sqlite3_bind_text(statement, 3, #sort, -1, SQLITE_STATIC); \
653 if (res != SQLITE_OK) \
654 sqlite_error(res, db, "event_type bind of sort \"" #sort "\" failed."); \
655 res = sqlite3_bind_text(statement, 4, #ident, -1, SQLITE_STATIC); \
656 if (res != SQLITE_OK) \
657 sqlite_error(res, db, "event_type bind of ident \"" #ident "\" failed."); \
658 res = sqlite3_step(statement); \
659 if (res != SQLITE_DONE) \
660 sqlite_error(res, db, "event_param insert of ident \"" #ident "\" for code %d failed.", code); \
661 if (sqlite3_changes(db) != 0) \
662 evlog(LOG_SOMETIMES, "Insert of event_param row for code %d, ident \"" #ident "\" affected %d rows.", code, sqlite3_changes(db)); \
663 res = sqlite3_reset(statement); \
664 if (res != SQLITE_OK) \
665 sqlite_error(res, db, "Couldn't reset event_param insert statement.");
666
667#define EVENT_TYPE_INSERT_PARAMS(X, name, code, always, kind) \
668 EVENT_##name##_PARAMS(EVENT_PARAM_DO_INSERT, code)
669
670static void fillGlueTables(sqlite3 *db)
671{
672 int i;
673 sqlite3_stmt *statement;
674 int res;
675
676 statement = prepareStatement(db,
677 "INSERT OR IGNORE INTO event_kind (name, description, enum)"
678 "VALUES (?, ?, ?)");
679
680 i = 0;
681 EventKindENUM(EVENT_KIND_DO_INSERT, X);
682
683 finalizeStatement(db, statement);
684
685 statement = prepareStatement(db,
686 "INSERT OR IGNORE INTO event_type (name, code, always, kind)"
687 "VALUES (?, ?, ?, ?)");
688 EVENT_LIST(EVENT_TYPE_DO_INSERT, X);
689
690 finalizeStatement(db, statement);
691
692 statement = prepareStatement(db,
693 "INSERT OR IGNORE INTO event_param (type, param_index, sort, ident)"
694 "VALUES (?, ?, ?, ?)");
695 EVENT_LIST(EVENT_TYPE_INSERT_PARAMS, X);
696
697 finalizeStatement(db, statement);
698}
699
700/* Populate the actual event tables. */
701
702#define EVENT_TYPE_DECLARE_STATEMENT(X, name, code, always, kind) \
703 sqlite3_stmt *stmt_##name;
704
705#define EVENT_PARAM_PREPARE_IDENT(X, index, sort, ident) "\"" #ident "\", "
706
707#define EVENT_PARAM_PREPARE_PLACE(X, index, sort, ident) "?, "
708
709#define EVENT_TYPE_PREPARE_STATEMENT(X, name, code, always, kind) \
710 stmt_##name = \
711 prepareStatement(db, \
712 "INSERT INTO EVENT_" #name " (" \
713 EVENT_##name##_PARAMS(EVENT_PARAM_PREPARE_IDENT, X) \
714 "log_serial, time) VALUES (" \
715 EVENT_##name##_PARAMS(EVENT_PARAM_PREPARE_PLACE,X) \
716 "?, ?)");
717
718#define EVENT_TYPE_FINALIZE_STATEMENT(X, name, code, always, kind) \
719 finalizeStatement(db, stmt_##name);
720
721#define EVENT_PARAM_BIND_A bind_int
722#define EVENT_PARAM_BIND_P bind_int
723#define EVENT_PARAM_BIND_U bind_int
724#define EVENT_PARAM_BIND_W bind_int
725#define EVENT_PARAM_BIND_D bind_real
726#define EVENT_PARAM_BIND_S bind_text
727#define EVENT_PARAM_BIND_B bind_int
728
729#define EVENT_PARAM_BIND(X, index, sort, ident) \
730 p = EVENT_PARAM_BIND_##sort (db, statement, eventCount, index+1, p); \
731 last_index = index+1;
732
733#define EVENT_TYPE_WRITE_SQL(X, name, code, always, kind) \
734 case code: \
735 statement = stmt_##name; \
736 /* bind all the parameters of this particular event with macro magic. */ \
737 EVENT_##name##_PARAMS(EVENT_PARAM_BIND, X) \
738 break;
739
740static char *bind_int(sqlite3 *db, sqlite3_stmt *stmt, int64 count, int field, char *p)
741{
742 char *q;
743 long long val;
744 int res;
745
746 while(*p == ' ')
747 ++p;
748
749 val = strtoll(p, &q, 16);
750 if (q == p)
751 error("event %llu field %d not an integer: %s",
752 count, field, p);
753
754 res = sqlite3_bind_int64(stmt, field, val);
755 if (res != SQLITE_OK)
756 sqlite_error(res, db, "event %llu field %d bind failed", count, field);
757 return q;
758}
759
760static char *bind_real(sqlite3 *db, sqlite3_stmt *stmt, int64 count, int field, char *p)
761{
762 char *q;
763 double val;
764 int res;
765
766 while(*p == ' ')
767 ++p;
768
769 val = strtod(p, &q);
770 if (q == p)
771 error("event %llu field %d not a floating-point value: %s",
772 count, field, p);
773
774 res = sqlite3_bind_double(stmt, field, val);
775 if (res != SQLITE_OK)
776 sqlite_error(res, db, "event %llu field %d bind failed", count, field);
777 return q;
778}
779
780static char *bind_text(sqlite3 *db, sqlite3_stmt *stmt, int64 count, int field, char *p)
781{
782 char *q;
783 int res;
784
785 while(*p == ' ')
786 ++p;
787
788 q = p;
789 while((*q != '\n') && (*q != '\0')) {
790 ++ q;
791 }
792 if ((q == p) || (q[-1] != '"'))
793 error("event %llu string field %d has no closing quote mark.",
794 count, field);
795
796 res = sqlite3_bind_text(stmt, field, p, (int)(q-p-1), SQLITE_STATIC);
797 if (res != SQLITE_OK)
798 sqlite_error(res, db, "event %llu field %d bind failed", count, field);
799 return q;
800}
801
802/* this is overkill, at present. */
803
804#define MAX_LOG_LINE_LENGTH 1024
805
806/* readLog -- read and parse log. Returns the number of events written.
807 */
808
809static int64 readLog(FILE *input,
810 sqlite3 *db)
811{
812 int64 eventCount = 0;
813
814 /* declare statements for every event type */
815 EVENT_LIST(EVENT_TYPE_DECLARE_STATEMENT, X);
816
817 /* prepare statements for every event type */
818 EVENT_LIST(EVENT_TYPE_PREPARE_STATEMENT, X);
819
820 runStatement(db, "BEGIN", "Transaction start");
821
822 while (TRUE) { /* loop for each event */
823 char line[MAX_LOG_LINE_LENGTH];
824 char *p;
825 char *q;
826 int last_index=0;
827 sqlite3_stmt *statement = NULL;
828 int res;
829 int64 clock_field;
830 long code;
831
832 p = fgets(line, MAX_LOG_LINE_LENGTH, input);
833 if (!p) {
834 if (feof(input))
835 break;
836 else
837 error("Couldn't read line after event %llu", eventCount);
838 }
839
840 eventCount++;
841
842 clock_field = strtoll(p, &q, 16);
843
844 if (q == p)
845 error("event %llu clock field not a hex integer: %s",
846 eventCount, p);
847
848 if (*q != ' ')
849 error("event %llu code field not preceded by ' ': %s",
850 eventCount, q);
851 while(*q == ' ')
852 ++q;
853
854 p = q;
855 code = strtol(p, &q, 16);
856 if (q == p)
857 error("event %llu code field not an integer: %s",
858 eventCount, p);
859 p = q;
860
861 /* Write event to SQLite. */
862 switch (code) {
863 /* this macro sets statement and last_index */
864 EVENT_LIST(EVENT_TYPE_WRITE_SQL, X);
865 default:
866 error("Event %llu has Unknown event code %d", eventCount, code);
867 }
868 /* bind the fields we store for every event */ \
869 res = sqlite3_bind_int64(statement, last_index+1, logSerial);
870 if (res != SQLITE_OK)
871 sqlite_error(res, db, "Event %llu bind of log_serial failed.", eventCount);
872 res = sqlite3_bind_int64(statement, last_index+2, clock_field);
873 if (res != SQLITE_OK)
874 sqlite_error(res, db, "Event %llu bind of clock failed.", eventCount);
875 res = sqlite3_step(statement);
876 if (res != SQLITE_DONE)
877 sqlite_error(res, db, "insert of event %llu failed.", eventCount);
878 res = sqlite3_reset(statement);
879 if (res != SQLITE_OK)
880 sqlite_error(res, db, "Couldn't reset insert statement of event %llu", eventCount);
881
882 if (progress) {
883 if ((eventCount % SMALL_TICK) == 0) {
884 printf(".");
885 fflush(stdout);
886 if (((eventCount / SMALL_TICK) % BIG_TICK) == 0) {
887 printf("\n");
888 fflush(stdout);
889 evlog(LOG_SOMETIMES, "%lu events.", (unsigned long)eventCount);
890 }
891 }
892 }
893 }
894 if (progress) {
895 printf("\n");
896 fflush(stdout);
897 }
898 runStatement(db, "COMMIT", "Transaction finish");
899 logFileCompleted(db, eventCount);
900
901 /* finalize all the statements */
902 EVENT_LIST(EVENT_TYPE_FINALIZE_STATEMENT, X);
903
904 return eventCount;
905}
906
907/* openLog -- open the log file doors, HAL */
908
909static FILE *openLog(sqlite3 *db)
910{
911 FILE *input;
912
913 registerLogFile(db, logFileName);
914 if (!logFileName) {
915 input = stdin;
916 logFileName = "<stdin>";
917 } else {
918 input = fopen(logFileName, "r");
919 if (input == NULL)
920 error("unable to open %s", logFileName);
921 }
922
923 evlog(LOG_OFTEN, "Reading %s.", logFileName ? logFileName : "standard input");
924
925 return input;
926}
927
928static int64 writeEventsToSQL(sqlite3 *db)
929{
930 FILE *input;
931 int64 count;
932 input = openLog(db);
933 count = readLog(input, db);
934 (void)fclose(input);
935 return count;
936}
937
938
939int main(int argc, char *argv[])
940{
941 sqlite3 *db;
942 int64 count;
943
944 parseArgs(argc, argv);
945
946 db = openDatabase();
947 if (rebuild) {
948 dropGlueTables(db);
949 }
950 makeTables(db);
951 fillGlueTables(db);
952 count = writeEventsToSQL(db);
953 evlog(LOG_ALWAYS, "Imported %llu events from %s to %s, serial %lu.",
954 count, logFileName, databaseName, logSerial);
955
956 if (runTests) {
957 /* TODO: more unit tests in here */
958 testTableExists(db);
959 }
960
961 closeDatabase(db);
962 return 0;
963}
964
965/* COPYRIGHT AND LICENSE
966 *
967 * Copyright (C) 2012 Ravenbrook Limited <http://www.ravenbrook.com/>.
968 * All rights reserved. This is an open source license. Contact
969 * Ravenbrook for commercial licensing options.
970 *
971 * Redistribution and use in source and binary forms, with or without
972 * modification, are permitted provided that the following conditions are
973 * met:
974 *
975 * 1. Redistributions of source code must retain the above copyright
976 * notice, this list of conditions and the following disclaimer.
977 *
978 * 2. Redistributions in binary form must reproduce the above copyright
979 * notice, this list of conditions and the following disclaimer in the
980 * documentation and/or other materials provided with the distribution.
981 *
982 * 3. Redistributions in any form must be accompanied by information on how
983 * to obtain complete source code for this software and any accompanying
984 * software that uses this software. The source code must either be
985 * included in the distribution or be available for no more than the cost
986 * of distribution plus a nominal fee, and must be freely redistributable
987 * under reasonable conditions. For an executable file, complete source
988 * code means the source code for all modules it contains. It does not
989 * include source code for modules or files that typically accompany the
990 * major components of the operating system on which the executable file
991 * runs.
992 *
993 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
994 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
995 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
996 * PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
997 * COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
998 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
999 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
1000 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
1001 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1002 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
1003 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1004 */
diff --git a/mps/code/eventtxt.c b/mps/code/eventtxt.c
new file mode 100644
index 00000000000..77c3100131a
--- /dev/null
+++ b/mps/code/eventtxt.c
@@ -0,0 +1,540 @@
1/* eventtxt.c: event text log to human-friendly format.
2 *
3 * $Id$
4 *
5 * Copyright (c) 2012 Ravenbrook Limited. See end of file for license.
6 *
7 * This is a command-line tool that converts events from a text-format
8 * MPS telemetry file into a more human-readable format.
9 *
10 * The default MPS library will write a binary-format telemetry file
11 * which can be converted into a text-format file using the eventcnv
12 * program (q.v.).
13 *
14 * For efficiency, eventcnv writes all event times, codes, and
15 * parameters (apart from EventFS - strings - and EventFD -
16 * floating-point) as hexadecimal strings, separated by single spaces.
17 * For human-readable purposes, we'd prefer a format in which
18 * parameters are named; event codes are converted to event type
19 * names; integers are in decimal; booleans are 'True ' or 'False';
20 * pointers, addresses, and words are in hex; and labelled addresses
21 * are shown with their label strings. This program performs that
22 * conversion.
23 *
24 * Options:
25 *
26 * -l <logfile>: Import events from the named logfile. Defaults to
27 * stdin.
28 *
29 * $Id$
30 */
31
32#include "config.h"
33#include "eventdef.h"
34#include "eventcom.h"
35#include "table.h"
36#include "testlib.h" /* for ulongest_t and associated print formats */
37
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41
42#ifdef MPS_BUILD_MV
43/* MSVC warning 4996 = stdio / C runtime 'unsafe' */
44/* Objects to: strncpy, sscanf, fopen. See job001934. */
45#pragma warning( disable : 4996 )
46#endif
47
48static char *prog; /* program name */
49static char *logFileName = NULL;
50
51/* everror -- error signalling */
52
53static void everror(const char *format, ...)
54{
55 va_list args;
56
57 fflush(stdout); /* sync */
58 fprintf(stderr, "%s: ", prog);
59 va_start(args, format);
60 vfprintf(stderr, format, args);
61 fprintf(stderr, "\n");
62 va_end(args);
63 exit(EXIT_FAILURE);
64}
65
66static void usage(void)
67{
68 fprintf(stderr,
69 "Usage: %s [-l <logfile>]\n",
70 prog);
71}
72
73static void usageError(void)
74{
75 usage();
76 everror("Bad usage");
77}
78
79/* parseArgs -- parse command line arguments */
80
81static void parseArgs(int argc, char *argv[])
82{
83 int i = 1;
84
85 if (argc >= 1)
86 prog = argv[0];
87 else
88 prog = "unknown";
89
90 while (i < argc) { /* consider argument i */
91 if (argv[i][0] == '-') { /* it's an option argument */
92 switch (argv[i][1]) {
93 case 'l': /* log file name */
94 ++ i;
95 if (i == argc)
96 usageError();
97 else
98 logFileName = argv[i];
99 break;
100 case '?': case 'h': /* help */
101 usage();
102 exit(EXIT_SUCCESS);
103 default:
104 usageError();
105 }
106 } /* if option */
107 ++ i;
108 }
109}
110
111/* table methods for a table of interned strings, and another of
112 * labelled addresses. */
113
114static void *tableAlloc(void *closure, size_t size)
115{
116 UNUSED(closure);
117 return malloc(size);
118}
119
120static void tableFree(void *closure, void *p, size_t size)
121{
122 UNUSED(closure);
123 UNUSED(size);
124 free(p);
125}
126
127/* Printing routines */
128
129/* printStr -- print an EventString */
130
131static void printStr(const char *str)
132{
133 size_t i;
134
135 putchar('"');
136 for (i = 0; str[i] != '\0'; ++i) {
137 char c = str[i];
138 if (c == '"' || c == '\\') putchar('\\');
139 putchar(c);
140 }
141 putchar('"');
142}
143
144
145/* Reading hex numbers, and doubles, and quoted-and-escaped
146 * strings. */
147
148static ulongest_t parseHex(char **pInOut)
149{
150 ulongest_t val;
151 int i, l;
152 char *p = *pInOut;
153
154 i = sscanf(p, "%" SCNXLONGEST "%n", &val, &l);
155 if (i != 1)
156 everror("Couldn't read a hex number from '%s'", p);
157 *pInOut = p + l;
158 return val;
159}
160
161static double parseDouble(char **pInOut)
162{
163 double val;
164 int i, l;
165 char *p = *pInOut;
166
167 i = sscanf(p, "%lg%n", &val, &l);
168 if (i != 1)
169 everror("Couldn't read a float from '%s'", p);
170 *pInOut = p + l;
171 return val;
172}
173
174/* parseString checks string syntax (opening and closing quotation
175 * marks) and takes a copy (stripping escaping backslashes) into a
176 * static buffer (callers must "use it or lose it"; the next
177 * invocation will over-write it). Probably not bullet-proof. */
178
179#define MAX_STRING_LENGTH 1024
180
181char strBuf[MAX_STRING_LENGTH];
182
183static char *parseString(char **pInOut)
184{
185 char *p = *pInOut;
186 char *q = strBuf;
187 while(*p == ' ')
188 ++p;
189
190 if (*p != '"')
191 everror("String has no opening quotation mark: '%s'", p);
192 ++p;
193
194 while(1) {
195 if (q - strBuf >= MAX_STRING_LENGTH) {
196 everror("String length exceeds %d", MAX_STRING_LENGTH);
197 }
198 if (*p == '\\') { /* escaped character */
199 ++p;
200 if (*p == '\0')
201 everror("Closing NUL byte escaped by backslash.");
202 *q++ = *p++;
203 } else if (*p == '"') { /* end of string */
204 *q = '\0';
205 ++p;
206 *pInOut = p;
207 return strBuf;
208 } else if (*p == '\0')
209 everror("Unexpected closing NUL byte.");
210 else
211 *q++ = *p++;
212 }
213}
214
215/* Event logs have interned strings (i.e. they construct a partial
216 * function from non-negatie integer IDs to strings), and can label
217 * addresses with intern string IDs (i.e. they construct a partial
218 * function from address to string ID). We need two tables to keep
219 * track of these. */
220
221static Table internTable; /* dictionary of intern ids to strings */
222
223static Table labelTable; /* dictionary of addrs to intern ids */
224
225static void createTables(void)
226{
227 Res res;
228 /* MPS intern IDs are serials from zero up, so we can use -1
229 * and -2 as specials. */
230 res = TableCreate(&internTable,
231 (size_t)1<<4,
232 tableAlloc, tableFree, NULL,
233 (Word)-1, (Word)-2);
234 if (res != ResOK)
235 everror("Couldn't make intern table.");
236
237 /* We assume that 0 and 1 are invalid as Addrs. */
238 res = TableCreate(&labelTable, (size_t)1<<7,
239 tableAlloc, tableFree, NULL,
240 0, 1);
241 if (res != ResOK)
242 everror("Couldn't make label table.");
243}
244
245/* recordIntern -- record an interned string in the table. a copy of
246* the string from the parsed buffer into a newly-allocated block. */
247
248static void recordIntern(char *p)
249{
250 ulongest_t stringId;
251 char *string;
252 char *copy;
253 size_t len;
254 Res res;
255
256 stringId = parseHex(&p);
257 string = parseString(&p);
258 len = strlen(string);
259 copy = malloc(len+1);
260 if (copy == NULL)
261 everror("Couldn't allocate space for a string.");
262 (void)strcpy(copy, string);
263 res = TableDefine(internTable, (Word)stringId, (void *)copy);
264 if (res != ResOK)
265 everror("Couldn't create an intern mapping.");
266}
267
268/* recordLabel records a label (an association between an address and
269 * a string ID). Note that the event log may have been generated on a
270 * platform with addresses larger than Word on the current platform.
271 * If that happens then we are scuppered because our Table code uses
272 * Word as the key type: there's nothing we can do except detect this
273 * bad case (see also the EventInit handling and warning code).
274 *
275 * We can and do handle the case where string IDs (which are Words on
276 * the MPS platform) are larger than void* on the current platform.
277 * This is probably in fact the same case, because Word should be the
278 * same size as void*. In practice, trying to analyse a log from a
279 * wide platform on a narrow one (e.g. - the only case which is likely
280 * to occur this decade - from a 64-bit platform on a 32-bit one) is
281 * probably a bad idea and maybe doomed to failure.
282 */
283
284static void recordLabel(char *p)
285{
286 ulongest_t address;
287 ulongest_t *stringIdP;
288 Res res;
289
290 address = parseHex(&p);
291 if (address > (Word)-1) {
292 printf("label address too large!");
293 return;
294 }
295
296 stringIdP = malloc(sizeof(ulongest_t));
297 if (stringIdP == NULL)
298 everror("Can't allocate space for a string's ID");
299 *stringIdP = parseHex(&p);
300 res = TableDefine(labelTable, (Word)address, (void *)stringIdP);
301 if (res != ResOK)
302 everror("Couldn't create an intern mapping.");
303}
304
305/* output code */
306
307/* hexWordWidth is the number of characters used to output a Word
308 * value in hexadecimal. Note that what we really care about is the
309 * width of a Word on the source platform, not here. So when we see
310 * an EventInit event, we update this variable to the necessary
311 * width. */
312
313static int hexWordWidth = (MPS_WORD_WIDTH+3)/4;
314
315/* printAddr -- output a ulongest_t in hex, with the interned string
316 * if the value is in the label table */
317
318static void printAddr(ulongest_t addr, const char *ident)
319{
320 ulongest_t label;
321 void *alias;
322
323 printf("%s:%0*" PRIXLONGEST, ident, hexWordWidth, addr);
324 if (TableLookup(&alias, labelTable, addr)) {
325 label = *(ulongest_t*)alias;
326 putchar('[');
327 if (TableLookup(&alias, internTable, label))
328 printStr((char *)alias);
329 else
330 printf("unknown label %" PRIuLONGEST, label);
331 putchar(']');
332 }
333 putchar(' ');
334}
335
336/* parameter processing. For each parameter we parse it and then
337 * print it, preceded by its name and a colon and followed by a
338 * space. */
339
340#define processParamA(ident) \
341 val_hex = parseHex(&p); \
342 printAddr(val_hex, #ident);
343
344#define processParamP processParamA
345#define processParamW processParamA
346
347#define processParamU(ident) \
348 val_hex = parseHex(&p); \
349 printf(#ident ":%" PRIuLONGEST " ", val_hex);
350
351#define processParamD(ident) \
352 val_float = parseDouble(&p); \
353 printf(#ident ":%#8.3g ", val_float);
354
355#define processParamS(ident) \
356 val_string = parseString(&p); \
357 printf(#ident ":"); \
358 printStr(val_string); \
359 putchar(' ');
360
361#define processParamB(ident) \
362 val_hex = parseHex(&p); \
363 printf(#ident ":%s ", val_hex ? "True" : "False");
364
365#define EVENT_PROCESS_PARAM(X, index, sort, ident) processParam##sort(ident);
366
367#define EVENT_PROCESS(X, name, code, always, kind) \
368 case code: \
369 EVENT_##name##_PARAMS(EVENT_PROCESS_PARAM, X) \
370 break;
371
372/* a table of the event names */
373
374static const char *eventName[EventCodeMAX+EventCodeMAX];
375
376#define EVENT_SET_NAME(X, name, code, always, kind) \
377 eventName[code] = #name;
378
379/* this is overkill, at present. */
380
381#define MAX_LOG_LINE_LENGTH 1024
382
383/* readLog -- read and parse log. Returns the number of events written. */
384
385static void readLog(FILE *input)
386{
387 int i;
388
389 for (i=0; i <= EventCodeMAX; ++i)
390 eventName[i] = NULL;
391
392 EVENT_LIST(EVENT_SET_NAME, X);
393
394 while (TRUE) { /* loop for each event */
395 char line[MAX_LOG_LINE_LENGTH];
396 char *p, *q;
397 ulongest_t clock;
398 int code;
399 ulongest_t val_hex;
400 double val_float;
401 const char *val_string;
402
403 p = fgets(line, MAX_LOG_LINE_LENGTH, input);
404 if (!p) {
405 if (feof(input))
406 break;
407 else
408 everror("Couldn't read line from input.");
409 }
410
411 clock = parseHex(&p);
412 code = (int)parseHex(&p);
413
414 if (eventName[code])
415 printf("%0*" PRIXLONGEST " %04X %-19s ", hexWordWidth, clock, code,
416 eventName[code]);
417 else
418 printf("%0*" PRIXLONGEST " %04X %-19s ", hexWordWidth, clock, code,
419 "[Unknown]");
420
421 q = p;
422
423 /* for a few particular codes, we do local processing. */
424 if (code == EventInternCode) {
425 recordIntern(q);
426 } else if (code == EventLabelCode) {
427 recordLabel(q);
428 } else if (code == EventEventInitCode) {
429 ulongest_t major, median, minor, maxCode, maxNameLen, wordWidth, clocksPerSec;
430 major = parseHex(&q); /* EVENT_VERSION_MAJOR */
431 median = parseHex(&q); /* EVENT_VERSION_MEDIAN */
432 minor = parseHex(&q); /* EVENT_VERSION_MINOR */
433 maxCode = parseHex(&q); /* EventCodeMAX */
434 maxNameLen = parseHex(&q); /* EventNameMAX */
435 wordWidth = parseHex(&q); /* MPS_WORD_WIDTH */
436 clocksPerSec = parseHex(&q); /* mps_clocks_per_sec() */
437 UNUSED(clocksPerSec);
438 UNUSED(maxNameLen);
439
440 if ((major != EVENT_VERSION_MAJOR) ||
441 (median != EVENT_VERSION_MEDIAN) ||
442 (minor != EVENT_VERSION_MINOR)) {
443 fprintf(stderr, "Event log version does not match: %d.%d.%d vs %d.%d.%d\n",
444 (int)major, (int)median, (int)minor,
445 EVENT_VERSION_MAJOR,
446 EVENT_VERSION_MEDIAN,
447 EVENT_VERSION_MINOR);
448 }
449
450 if (maxCode > EventCodeMAX) {
451 fprintf(stderr, "Event log may contain unknown events with codes from %d to %d\n",
452 EventCodeMAX+1, (int)maxCode);
453 }
454
455 if (wordWidth > MPS_WORD_WIDTH) {
456 int newHexWordWidth = (int)((wordWidth + 3) / 4);
457 if (newHexWordWidth > hexWordWidth) {
458 fprintf(stderr,
459 "Event log word width is greater than on current platform;"
460 "previous values may be printed too narrowly.\n");
461 }
462 hexWordWidth = newHexWordWidth;
463 }
464
465 if (wordWidth > sizeof(ulongest_t) * CHAR_BIT) {
466 everror("Event log word width %d is too wide for the current platform.",
467 (int)wordWidth);
468 }
469 }
470
471 switch(code) {
472 EVENT_LIST(EVENT_PROCESS, X);
473 default:
474 printf("Unknown event.");
475 }
476 putchar('\n');
477
478 }
479}
480
481int main(int argc, char *argv[])
482{
483 FILE *input;
484
485 parseArgs(argc, argv);
486 if (!logFileName) {
487 input = stdin;
488 logFileName = "<stdin>";
489 } else {
490 input = fopen(logFileName, "r");
491 if (input == NULL)
492 everror("unable to open %s", logFileName);
493 }
494
495 createTables();
496 readLog(input);
497 (void)fclose(input);
498 return 0;
499}
500
501/* C. COPYRIGHT AND LICENSE
502 *
503 * Copyright (C) 2012 Ravenbrook Limited <http://www.ravenbrook.com/>.
504 * All rights reserved. This is an open source license. Contact
505 * Ravenbrook for commercial licensing options.
506 *
507 * Redistribution and use in source and binary forms, with or without
508 * modification, are permitted provided that the following conditions are
509 * met:
510 *
511 * 1. Redistributions of source code must retain the above copyright
512 * notice, this list of conditions and the following disclaimer.
513 *
514 * 2. Redistributions in binary form must reproduce the above copyright
515 * notice, this list of conditions and the following disclaimer in the
516 * documentation and/or other materials provided with the distribution.
517 *
518 * 3. Redistributions in any form must be accompanied by information on how
519 * to obtain complete source code for this software and any accompanying
520 * software that uses this software. The source code must either be
521 * included in the distribution or be available for no more than the cost
522 * of distribution plus a nominal fee, and must be freely redistributable
523 * under reasonable conditions. For an executable file, complete source
524 * code means the source code for all modules it contains. It does not
525 * include source code for modules or files that typically accompany the
526 * major components of the operating system on which the executable file
527 * runs.
528 *
529 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
530 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
531 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
532 * PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
533 * COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
534 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
535 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
536 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
537 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
538 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
539 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
540 */
diff --git a/mps/code/fri3gc.gmk b/mps/code/fri3gc.gmk
index f2895c00404..12f0d3e7b01 100644
--- a/mps/code/fri3gc.gmk
+++ b/mps/code/fri3gc.gmk
@@ -9,12 +9,13 @@ MPMPF = lockix.c thix.c pthrdext.c vmix.c \
9 protix.c protsgix.c prmcan.c prmci3fr.c ssixi3.c span.c 9 protix.c protsgix.c prmcan.c prmci3fr.c ssixi3.c span.c
10 10
11LIBS = -lm -pthread 11LIBS = -lm -pthread
12LINKFLAGS = -L/usr/local/lib
12 13
13include gc.gmk 14include gc.gmk
14 15
15# FIXME: We pun types through the MPS interface, setting off this warning. 16# FIXME: We pun types through the MPS interface, setting off this warning.
16# Can we avoid this? The puns might indeed be dangerous. 17# Can we avoid this? The puns might indeed be dangerous.
17CFLAGSCOMPILER := $(CFLAGSCOMPILER) -Wno-strict-aliasing 18CFLAGSCOMPILER := $(CFLAGSCOMPILER) -Wno-strict-aliasing -I/usr/local/include
18 19
19CC = cc 20CC = cc
20 21
diff --git a/mps/code/gc.gmk b/mps/code/gc.gmk
index 3de47e908b0..695455dbd0a 100644
--- a/mps/code/gc.gmk
+++ b/mps/code/gc.gmk
@@ -8,13 +8,18 @@
8# common makefile fragment (<code/comm.gmk>) requires. 8# common makefile fragment (<code/comm.gmk>) requires.
9 9
10CC = gcc 10CC = gcc
11CFLAGSCOMPILER := \ 11CFLAGSDEBUG = -O -g3
12 -ansi -pedantic -Wall -Werror -Wpointer-arith \ 12CFLAGSOPT = -O2 -g3
13CFLAGSCOMPILER := -Wall -Werror -Wpointer-arith \
13 -Wstrict-prototypes -Wmissing-prototypes \ 14 -Wstrict-prototypes -Wmissing-prototypes \
14 -Winline -Waggregate-return -Wnested-externs \ 15 -Winline -Waggregate-return -Wnested-externs \
15 -Wcast-qual -Wshadow -Wstrict-aliasing=2 16 -Wcast-qual -Wshadow -Wstrict-aliasing=2
16CFLAGSDEBUG = -O -g3 17CFLAGSCOMPILERSTRICT := -ansi -pedantic -Wshadow
17CFLAGSOPT = -O2 -g3 18
19# A different set of compiler flags for less strict compilation, for
20# instance when we need to #include a third-party header file that
21# won't fly with -ansi -pedantic. Use sparingly!
22CFLAGSCOMPILERLAX :=
18 23
19# gcc -MM generates a dependency line of the form: 24# gcc -MM generates a dependency line of the form:
20# thing.o : thing.c ... 25# thing.o : thing.c ...
diff --git a/mps/code/global.c b/mps/code/global.c
index 0f16c5e4475..ed297978d64 100644
--- a/mps/code/global.c
+++ b/mps/code/global.c
@@ -584,6 +584,7 @@ MutatorFaultContext mps_exception_info = NULL;
584 584
585Bool ArenaAccess(Addr addr, AccessSet mode, MutatorFaultContext context) 585Bool ArenaAccess(Addr addr, AccessSet mode, MutatorFaultContext context)
586{ 586{
587 static Count count = 0; /* used to match up ArenaAccess events */
587 Seg seg; 588 Seg seg;
588 Ring node, nextNode; 589 Ring node, nextNode;
589 Res res; 590 Res res;
@@ -598,6 +599,8 @@ Bool ArenaAccess(Addr addr, AccessSet mode, MutatorFaultContext context)
598 Root root; 599 Root root;
599 600
600 ArenaEnter(arena); /* <design/arena/#lock.arena> */ 601 ArenaEnter(arena); /* <design/arena/#lock.arena> */
602 EVENT4(ArenaAccess, arena, ++count, addr, mode);
603
601 /* @@@@ The code below assumes that Roots and Segs are disjoint. */ 604 /* @@@@ The code below assumes that Roots and Segs are disjoint. */
602 /* It will fall over (in TraceSegAccess probably) if there is a */ 605 /* It will fall over (in TraceSegAccess probably) if there is a */
603 /* protected root on a segment. */ 606 /* protected root on a segment. */
@@ -613,6 +616,7 @@ Bool ArenaAccess(Addr addr, AccessSet mode, MutatorFaultContext context)
613 res = PoolAccess(SegPool(seg), seg, addr, mode, context); 616 res = PoolAccess(SegPool(seg), seg, addr, mode, context);
614 AVER(res == ResOK); /* Mutator can't continue unless this succeeds */ 617 AVER(res == ResOK); /* Mutator can't continue unless this succeeds */
615 } 618 }
619 EVENT4(ArenaAccess, arena, count, addr, mode);
616 ArenaLeave(arena); 620 ArenaLeave(arena);
617 return TRUE; 621 return TRUE;
618 } else if (RootOfAddr(&root, arena, addr)) { 622 } else if (RootOfAddr(&root, arena, addr)) {
@@ -621,6 +625,7 @@ Bool ArenaAccess(Addr addr, AccessSet mode, MutatorFaultContext context)
621 mode &= RootPM(root); 625 mode &= RootPM(root);
622 if (mode != AccessSetEMPTY) 626 if (mode != AccessSetEMPTY)
623 RootAccess(root, mode); 627 RootAccess(root, mode);
628 EVENT4(ArenaAccess, arena, count, addr, mode);
624 ArenaLeave(arena); 629 ArenaLeave(arena);
625 return TRUE; 630 return TRUE;
626 } 631 }
@@ -680,6 +685,9 @@ void ArenaPoll(Globals globals)
680 arena = GlobalsArena(globals); 685 arena = GlobalsArena(globals);
681 start = ClockNow(); 686 start = ClockNow();
682 quanta = 0; 687 quanta = 0;
688
689 EVENT3(ArenaPoll, arena, start, 0);
690
683 while(globals->pollThreshold <= globals->fillMutatorSize) { 691 while(globals->pollThreshold <= globals->fillMutatorSize) {
684 tracedSize = TracePoll(globals); 692 tracedSize = TracePoll(globals);
685 693
@@ -705,6 +713,8 @@ void ArenaPoll(Globals globals)
705 713
706 AVER(globals->fillMutatorSize < globals->pollThreshold); 714 AVER(globals->fillMutatorSize < globals->pollThreshold);
707 715
716 EVENT3(ArenaPoll, arena, start, quanta);
717
708 globals->insidePoll = FALSE; 718 globals->insidePoll = FALSE;
709} 719}
710#endif 720#endif
@@ -1066,7 +1076,8 @@ void ArenaSetEmergency(Arena arena, Bool emergency)
1066 1076
1067 DIAG_SINGLEF(( "ArenaSetEmergency", 1077 DIAG_SINGLEF(( "ArenaSetEmergency",
1068 "emergency: $U", (WriteFU)emergency, NULL )); 1078 "emergency: $U", (WriteFU)emergency, NULL ));
1069 1079 EVENT2(ArenaSetEmergency, arena, emergency);
1080
1070 arena->emergency = emergency; 1081 arena->emergency = emergency;
1071} 1082}
1072 1083
diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h
index 984790baf56..f7cf9a023ea 100644
--- a/mps/code/mpmtypes.h
+++ b/mps/code/mpmtypes.h
@@ -41,7 +41,7 @@ typedef unsigned Shift; /* <design/type/#shift> */
41typedef unsigned Serial; /* <design/type/#serial> */ 41typedef unsigned Serial; /* <design/type/#serial> */
42typedef Addr Ref; /* <design/type/#ref> */ 42typedef Addr Ref; /* <design/type/#ref> */
43typedef void *Pointer; /* <design/type/#pointer> */ 43typedef void *Pointer; /* <design/type/#pointer> */
44typedef unsigned long Clock; /* processor time */ 44typedef Word Clock; /* processor time */
45typedef MPS_T_ULONGEST ULongest; /* <design/type/#ulongest> */ 45typedef MPS_T_ULONGEST ULongest; /* <design/type/#ulongest> */
46 46
47typedef Word RefSet; /* design.mps.refset */ 47typedef Word RefSet; /* design.mps.refset */
diff --git a/mps/code/mps.h b/mps/code/mps.h
index 6d0edbb75d2..e47a4ca8e34 100644
--- a/mps/code/mps.h
+++ b/mps/code/mps.h
@@ -70,13 +70,13 @@ typedef struct mps_frame_s
70typedef MPS_T_WORD mps_word_t; /* pointer-sized word */ 70typedef MPS_T_WORD mps_word_t; /* pointer-sized word */
71typedef int mps_bool_t; /* boolean (int) */ 71typedef int mps_bool_t; /* boolean (int) */
72typedef int mps_res_t; /* result code (int) */ 72typedef int mps_res_t; /* result code (int) */
73typedef unsigned mps_shift_t; /* shift amount (unsigned int) */
74typedef void *mps_addr_t; /* managed address (void *) */ 73typedef void *mps_addr_t; /* managed address (void *) */
75typedef size_t mps_align_t; /* alignment (size_t) */ 74typedef size_t mps_align_t; /* alignment (size_t) */
76typedef unsigned mps_rm_t; /* root mode (unsigned) */ 75typedef unsigned mps_rm_t; /* root mode (unsigned) */
77typedef unsigned mps_rank_t; /* ranks (unsigned) */ 76typedef unsigned mps_rank_t; /* ranks (unsigned) */
78typedef unsigned mps_message_type_t; /* message type (unsigned) */ 77typedef unsigned mps_message_type_t; /* message type (unsigned) */
79typedef unsigned long mps_clock_t; /* processor time */ 78typedef mps_word_t mps_clock_t; /* processor time */
79typedef mps_word_t mps_label_t; /* telemetry label */
80 80
81/* Result Codes */ 81/* Result Codes */
82/* .result-codes: Keep in sync with <code/mpmtypes.h#result-codes> */ 82/* .result-codes: Keep in sync with <code/mpmtypes.h#result-codes> */
@@ -584,8 +584,11 @@ enum {
584/* Telemetry */ 584/* Telemetry */
585 585
586extern mps_word_t mps_telemetry_control(mps_word_t, mps_word_t); 586extern mps_word_t mps_telemetry_control(mps_word_t, mps_word_t);
587extern mps_word_t mps_telemetry_intern(const char *); 587extern void mps_telemetry_set(mps_word_t);
588extern void mps_telemetry_label(mps_addr_t, mps_word_t); 588extern void mps_telemetry_reset(mps_word_t);
589extern mps_word_t mps_telemetry_get(void);
590extern mps_label_t mps_telemetry_intern(const char *);
591extern void mps_telemetry_label(mps_addr_t, mps_label_t);
589extern void mps_telemetry_flush(void); 592extern void mps_telemetry_flush(void);
590 593
591 594
diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj
index 207e50660e4..1b5d7700d4b 100644
--- a/mps/code/mps.xcodeproj/project.pbxproj
+++ b/mps/code/mps.xcodeproj/project.pbxproj
@@ -15,6 +15,8 @@
15 dependencies = ( 15 dependencies = (
16 3104AFF6156D37BC000A585A /* PBXTargetDependency */, 16 3104AFF6156D37BC000A585A /* PBXTargetDependency */,
17 3114A6D5156E9839001E0AA3 /* PBXTargetDependency */, 17 3114A6D5156E9839001E0AA3 /* PBXTargetDependency */,
18 2D07B9791636FCBD00DB751B /* PBXTargetDependency */,
19 2275798916C5422900B662B0 /* PBXTargetDependency */,
18 3114A6B9156E9763001E0AA3 /* PBXTargetDependency */, 20 3114A6B9156E9763001E0AA3 /* PBXTargetDependency */,
19 3114A6A7156E9739001E0AA3 /* PBXTargetDependency */, 21 3114A6A7156E9739001E0AA3 /* PBXTargetDependency */,
20 3114A68D156E9686001E0AA3 /* PBXTargetDependency */, 22 3114A68D156E9686001E0AA3 /* PBXTargetDependency */,
@@ -51,6 +53,10 @@
51/* End PBXAggregateTarget section */ 53/* End PBXAggregateTarget section */
52 54
53/* Begin PBXBuildFile section */ 55/* Begin PBXBuildFile section */
56 2D07B97A1636FCCE00DB751B /* eventsql.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D07B96C1636FC7200DB751B /* eventsql.c */; };
57 2D07B97C163705E400DB751B /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D07B97B163705E400DB751B /* libsqlite3.dylib */; };
58 2D53F2E716515A63009A1829 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; };
59 2D604BA516514C4F003AAF46 /* eventtxt.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D604BA416514C4F003AAF46 /* eventtxt.c */; };
54 3104AFBF156D3591000A585A /* apss.c in Sources */ = {isa = PBXBuildFile; fileRef = 3104AFBE156D3591000A585A /* apss.c */; }; 60 3104AFBF156D3591000A585A /* apss.c in Sources */ = {isa = PBXBuildFile; fileRef = 3104AFBE156D3591000A585A /* apss.c */; };
55 3104AFC2156D35B2000A585A /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; }; 61 3104AFC2156D35B2000A585A /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; };
56 3104AFC3156D35C3000A585A /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; }; 62 3104AFC3156D35C3000A585A /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; };
@@ -196,6 +202,20 @@
196/* End PBXBuildFile section */ 202/* End PBXBuildFile section */
197 203
198/* Begin PBXContainerItemProxy section */ 204/* Begin PBXContainerItemProxy section */
205 2275798816C5422900B662B0 /* PBXContainerItemProxy */ = {
206 isa = PBXContainerItemProxy;
207 containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */;
208 proxyType = 1;
209 remoteGlobalIDString = 2D604B9B16514B1A003AAF46;
210 remoteInfo = mpseventtxt;
211 };
212 2D07B9781636FCBD00DB751B /* PBXContainerItemProxy */ = {
213 isa = PBXContainerItemProxy;
214 containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */;
215 proxyType = 1;
216 remoteGlobalIDString = 2D07B9701636FC9900DB751B;
217 remoteInfo = mpseventsql;
218 };
199 3104AFC0156D35AE000A585A /* PBXContainerItemProxy */ = { 219 3104AFC0156D35AE000A585A /* PBXContainerItemProxy */ = {
200 isa = PBXContainerItemProxy; 220 isa = PBXContainerItemProxy;
201 containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; 221 containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */;
@@ -509,7 +529,7 @@
509 containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */; 529 containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */;
510 proxyType = 1; 530 proxyType = 1;
511 remoteGlobalIDString = 3114A6C5156E9815001E0AA3; 531 remoteGlobalIDString = 3114A6C5156E9815001E0AA3;
512 remoteInfo = eventcnv; 532 remoteInfo = mpseventcnv;
513 }; 533 };
514 31A47BA9156C210D0039B1C2 /* PBXContainerItemProxy */ = { 534 31A47BA9156C210D0039B1C2 /* PBXContainerItemProxy */ = {
515 isa = PBXContainerItemProxy; 535 isa = PBXContainerItemProxy;
@@ -626,6 +646,24 @@
626/* End PBXContainerItemProxy section */ 646/* End PBXContainerItemProxy section */
627 647
628/* Begin PBXCopyFilesBuildPhase section */ 648/* Begin PBXCopyFilesBuildPhase section */
649 2D07B96F1636FC9900DB751B /* CopyFiles */ = {
650 isa = PBXCopyFilesBuildPhase;
651 buildActionMask = 2147483647;
652 dstPath = /usr/share/man/man1/;
653 dstSubfolderSpec = 0;
654 files = (
655 );
656 runOnlyForDeploymentPostprocessing = 1;
657 };
658 2D604B9A16514B1A003AAF46 /* CopyFiles */ = {
659 isa = PBXCopyFilesBuildPhase;
660 buildActionMask = 2147483647;
661 dstPath = /usr/share/man/man1/;
662 dstSubfolderSpec = 0;
663 files = (
664 );
665 runOnlyForDeploymentPostprocessing = 1;
666 };
629 3104AFB1156D357B000A585A /* CopyFiles */ = { 667 3104AFB1156D357B000A585A /* CopyFiles */ = {
630 isa = PBXCopyFilesBuildPhase; 668 isa = PBXCopyFilesBuildPhase;
631 buildActionMask = 2147483647; 669 buildActionMask = 2147483647;
@@ -899,6 +937,11 @@
899/* End PBXCopyFilesBuildPhase section */ 937/* End PBXCopyFilesBuildPhase section */
900 938
901/* Begin PBXFileReference section */ 939/* Begin PBXFileReference section */
940 2D07B96C1636FC7200DB751B /* eventsql.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = eventsql.c; sourceTree = "<group>"; };
941 2D07B9711636FC9900DB751B /* mpseventsql */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mpseventsql; sourceTree = BUILT_PRODUCTS_DIR; };
942 2D07B97B163705E400DB751B /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; };
943 2D604B9C16514B1A003AAF46 /* mpseventtxt */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mpseventtxt; sourceTree = BUILT_PRODUCTS_DIR; };
944 2D604BA416514C4F003AAF46 /* eventtxt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eventtxt.c; sourceTree = "<group>"; };
902 3104AFA5156D27E7000A585A /* ssixi6.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ssixi6.c; sourceTree = "<group>"; }; 945 3104AFA5156D27E7000A585A /* ssixi6.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ssixi6.c; sourceTree = "<group>"; };
903 3104AFB3156D357B000A585A /* apss */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = apss; sourceTree = BUILT_PRODUCTS_DIR; }; 946 3104AFB3156D357B000A585A /* apss */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = apss; sourceTree = BUILT_PRODUCTS_DIR; };
904 3104AFBE156D3591000A585A /* apss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = apss.c; sourceTree = "<group>"; }; 947 3104AFBE156D3591000A585A /* apss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = apss.c; sourceTree = "<group>"; };
@@ -939,7 +982,7 @@
939 3114A69F156E9725001E0AA3 /* messtest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = messtest.c; sourceTree = "<group>"; }; 982 3114A69F156E9725001E0AA3 /* messtest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = messtest.c; sourceTree = "<group>"; };
940 3114A6AC156E9759001E0AA3 /* walkt0 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = walkt0; sourceTree = BUILT_PRODUCTS_DIR; }; 983 3114A6AC156E9759001E0AA3 /* walkt0 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = walkt0; sourceTree = BUILT_PRODUCTS_DIR; };
941 3114A6BA156E9768001E0AA3 /* walkt0.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = walkt0.c; sourceTree = "<group>"; }; 984 3114A6BA156E9768001E0AA3 /* walkt0.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = walkt0.c; sourceTree = "<group>"; };
942 3114A6C6156E9815001E0AA3 /* eventcnv */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = eventcnv; sourceTree = BUILT_PRODUCTS_DIR; }; 985 3114A6C6156E9815001E0AA3 /* mpseventcnv */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mpseventcnv; sourceTree = BUILT_PRODUCTS_DIR; };
943 3114A6D0156E9829001E0AA3 /* eventcnv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eventcnv.c; sourceTree = "<group>"; }; 986 3114A6D0156E9829001E0AA3 /* eventcnv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eventcnv.c; sourceTree = "<group>"; };
944 3114A6D9156E9950001E0AA3 /* eventpro.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eventpro.c; sourceTree = "<group>"; }; 987 3114A6D9156E9950001E0AA3 /* eventpro.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eventpro.c; sourceTree = "<group>"; };
945 3124CAB8156BE3EC00753214 /* awlut */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = awlut; sourceTree = BUILT_PRODUCTS_DIR; }; 988 3124CAB8156BE3EC00753214 /* awlut */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = awlut; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -1026,6 +1069,22 @@
1026/* End PBXFileReference section */ 1069/* End PBXFileReference section */
1027 1070
1028/* Begin PBXFrameworksBuildPhase section */ 1071/* Begin PBXFrameworksBuildPhase section */
1072 2D07B96E1636FC9900DB751B /* Frameworks */ = {
1073 isa = PBXFrameworksBuildPhase;
1074 buildActionMask = 2147483647;
1075 files = (
1076 2D07B97C163705E400DB751B /* libsqlite3.dylib in Frameworks */,
1077 );
1078 runOnlyForDeploymentPostprocessing = 0;
1079 };
1080 2D604B9916514B1A003AAF46 /* Frameworks */ = {
1081 isa = PBXFrameworksBuildPhase;
1082 buildActionMask = 2147483647;
1083 files = (
1084 2D53F2E716515A63009A1829 /* libmps.a in Frameworks */,
1085 );
1086 runOnlyForDeploymentPostprocessing = 0;
1087 };
1029 3104AFB0156D357B000A585A /* Frameworks */ = { 1088 3104AFB0156D357B000A585A /* Frameworks */ = {
1030 isa = PBXFrameworksBuildPhase; 1089 isa = PBXFrameworksBuildPhase;
1031 buildActionMask = 2147483647; 1090 buildActionMask = 2147483647;
@@ -1276,6 +1335,22 @@
1276/* End PBXFrameworksBuildPhase section */ 1335/* End PBXFrameworksBuildPhase section */
1277 1336
1278/* Begin PBXGroup section */ 1337/* Begin PBXGroup section */
1338 2D07B96A1636FC4C00DB751B /* mpseventsql */ = {
1339 isa = PBXGroup;
1340 children = (
1341 2D07B96C1636FC7200DB751B /* eventsql.c */,
1342 );
1343 name = mpseventsql;
1344 sourceTree = "<group>";
1345 };
1346 2D604B971651433C003AAF46 /* mpseventtxt */ = {
1347 isa = PBXGroup;
1348 children = (
1349 2D604BA416514C4F003AAF46 /* eventtxt.c */,
1350 );
1351 name = mpseventtxt;
1352 sourceTree = "<group>";
1353 };
1279 3114A647156E956C001E0AA3 /* Mysterious */ = { 1354 3114A647156E956C001E0AA3 /* Mysterious */ = {
1280 isa = PBXGroup; 1355 isa = PBXGroup;
1281 children = ( 1356 children = (
@@ -1288,18 +1363,20 @@
1288 3114A6D6156E9846001E0AA3 /* Tools */ = { 1363 3114A6D6156E9846001E0AA3 /* Tools */ = {
1289 isa = PBXGroup; 1364 isa = PBXGroup;
1290 children = ( 1365 children = (
1291 3114A6D8156E9942001E0AA3 /* eventcnv */, 1366 2D604B971651433C003AAF46 /* mpseventtxt */,
1367 2D07B96A1636FC4C00DB751B /* mpseventsql */,
1368 3114A6D8156E9942001E0AA3 /* mpseventcnv */,
1292 ); 1369 );
1293 name = Tools; 1370 name = Tools;
1294 sourceTree = "<group>"; 1371 sourceTree = "<group>";
1295 }; 1372 };
1296 3114A6D8156E9942001E0AA3 /* eventcnv */ = { 1373 3114A6D8156E9942001E0AA3 /* mpseventcnv */ = {
1297 isa = PBXGroup; 1374 isa = PBXGroup;
1298 children = ( 1375 children = (
1299 3114A6D9156E9950001E0AA3 /* eventpro.c */, 1376 3114A6D9156E9950001E0AA3 /* eventpro.c */,
1300 3114A6D0156E9829001E0AA3 /* eventcnv.c */, 1377 3114A6D0156E9829001E0AA3 /* eventcnv.c */,
1301 ); 1378 );
1302 name = eventcnv; 1379 name = mpseventcnv;
1303 sourceTree = "<group>"; 1380 sourceTree = "<group>";
1304 }; 1381 };
1305 3124CAB3156BE1B700753214 /* Tests */ = { 1382 3124CAB3156BE1B700753214 /* Tests */ = {
@@ -1374,6 +1451,7 @@
1374 31EEABD8156AAE9E00714D05 = { 1451 31EEABD8156AAE9E00714D05 = {
1375 isa = PBXGroup; 1452 isa = PBXGroup;
1376 children = ( 1453 children = (
1454 2D07B97B163705E400DB751B /* libsqlite3.dylib */,
1377 3114A6D6156E9846001E0AA3 /* Tools */, 1455 3114A6D6156E9846001E0AA3 /* Tools */,
1378 3114A647156E956C001E0AA3 /* Mysterious */, 1456 3114A647156E956C001E0AA3 /* Mysterious */,
1379 31A47BA8156C1E930039B1C2 /* MPS */, 1457 31A47BA8156C1E930039B1C2 /* MPS */,
@@ -1415,7 +1493,9 @@
1415 3114A67C156E9668001E0AA3 /* mv2test */, 1493 3114A67C156E9668001E0AA3 /* mv2test */,
1416 3114A695156E971B001E0AA3 /* messtest */, 1494 3114A695156E971B001E0AA3 /* messtest */,
1417 3114A6AC156E9759001E0AA3 /* walkt0 */, 1495 3114A6AC156E9759001E0AA3 /* walkt0 */,
1418 3114A6C6156E9815001E0AA3 /* eventcnv */, 1496 3114A6C6156E9815001E0AA3 /* mpseventcnv */,
1497 2D07B9711636FC9900DB751B /* mpseventsql */,
1498 2D604B9C16514B1A003AAF46 /* mpseventtxt */,
1419 ); 1499 );
1420 name = Products; 1500 name = Products;
1421 sourceTree = "<group>"; 1501 sourceTree = "<group>";
@@ -1515,6 +1595,40 @@
1515/* End PBXHeadersBuildPhase section */ 1595/* End PBXHeadersBuildPhase section */
1516 1596
1517/* Begin PBXNativeTarget section */ 1597/* Begin PBXNativeTarget section */
1598 2D07B9701636FC9900DB751B /* mpseventsql */ = {
1599 isa = PBXNativeTarget;
1600 buildConfigurationList = 2D07B9741636FC9900DB751B /* Build configuration list for PBXNativeTarget "mpseventsql" */;
1601 buildPhases = (
1602 2D07B96D1636FC9900DB751B /* Sources */,
1603 2D07B96E1636FC9900DB751B /* Frameworks */,
1604 2D07B96F1636FC9900DB751B /* CopyFiles */,
1605 );
1606 buildRules = (
1607 );
1608 dependencies = (
1609 );
1610 name = mpseventsql;
1611 productName = mpseventsql;
1612 productReference = 2D07B9711636FC9900DB751B /* mpseventsql */;
1613 productType = "com.apple.product-type.tool";
1614 };
1615 2D604B9B16514B1A003AAF46 /* mpseventtxt */ = {
1616 isa = PBXNativeTarget;
1617 buildConfigurationList = 2D604BA216514B59003AAF46 /* Build configuration list for PBXNativeTarget "mpseventtxt" */;
1618 buildPhases = (
1619 2D604B9816514B1A003AAF46 /* Sources */,
1620 2D604B9916514B1A003AAF46 /* Frameworks */,
1621 2D604B9A16514B1A003AAF46 /* CopyFiles */,
1622 );
1623 buildRules = (
1624 );
1625 dependencies = (
1626 );
1627 name = mpseventtxt;
1628 productName = mpseventtxt;
1629 productReference = 2D604B9C16514B1A003AAF46 /* mpseventtxt */;
1630 productType = "com.apple.product-type.tool";
1631 };
1518 3104AFB2156D357B000A585A /* apss */ = { 1632 3104AFB2156D357B000A585A /* apss */ = {
1519 isa = PBXNativeTarget; 1633 isa = PBXNativeTarget;
1520 buildConfigurationList = 3104AFBC156D357B000A585A /* Build configuration list for PBXNativeTarget "apss" */; 1634 buildConfigurationList = 3104AFBC156D357B000A585A /* Build configuration list for PBXNativeTarget "apss" */;
@@ -1857,9 +1971,9 @@
1857 productReference = 3114A6AC156E9759001E0AA3 /* walkt0 */; 1971 productReference = 3114A6AC156E9759001E0AA3 /* walkt0 */;
1858 productType = "com.apple.product-type.tool"; 1972 productType = "com.apple.product-type.tool";
1859 }; 1973 };
1860 3114A6C5156E9815001E0AA3 /* eventcnv */ = { 1974 3114A6C5156E9815001E0AA3 /* mpseventcnv */ = {
1861 isa = PBXNativeTarget; 1975 isa = PBXNativeTarget;
1862 buildConfigurationList = 3114A6CD156E9815001E0AA3 /* Build configuration list for PBXNativeTarget "eventcnv" */; 1976 buildConfigurationList = 3114A6CD156E9815001E0AA3 /* Build configuration list for PBXNativeTarget "mpseventcnv" */;
1863 buildPhases = ( 1977 buildPhases = (
1864 3114A6C2156E9815001E0AA3 /* Sources */, 1978 3114A6C2156E9815001E0AA3 /* Sources */,
1865 3114A6C3156E9815001E0AA3 /* Frameworks */, 1979 3114A6C3156E9815001E0AA3 /* Frameworks */,
@@ -1870,9 +1984,9 @@
1870 dependencies = ( 1984 dependencies = (
1871 3114A6D3156E9834001E0AA3 /* PBXTargetDependency */, 1985 3114A6D3156E9834001E0AA3 /* PBXTargetDependency */,
1872 ); 1986 );
1873 name = eventcnv; 1987 name = mpseventcnv;
1874 productName = eventcnv; 1988 productName = mpseventcnv;
1875 productReference = 3114A6C6156E9815001E0AA3 /* eventcnv */; 1989 productReference = 3114A6C6156E9815001E0AA3 /* mpseventcnv */;
1876 productType = "com.apple.product-type.tool"; 1990 productType = "com.apple.product-type.tool";
1877 }; 1991 };
1878 3124CAB7156BE3EC00753214 /* awlut */ = { 1992 3124CAB7156BE3EC00753214 /* awlut */ = {
@@ -2123,12 +2237,30 @@
2123 3114A67B156E9668001E0AA3 /* mv2test */, 2237 3114A67B156E9668001E0AA3 /* mv2test */,
2124 3114A694156E971B001E0AA3 /* messtest */, 2238 3114A694156E971B001E0AA3 /* messtest */,
2125 3114A6AB156E9759001E0AA3 /* walkt0 */, 2239 3114A6AB156E9759001E0AA3 /* walkt0 */,
2126 3114A6C5156E9815001E0AA3 /* eventcnv */, 2240 3114A6C5156E9815001E0AA3 /* mpseventcnv */,
2241 2D07B9701636FC9900DB751B /* mpseventsql */,
2242 2D604B9B16514B1A003AAF46 /* mpseventtxt */,
2127 ); 2243 );
2128 }; 2244 };
2129/* End PBXProject section */ 2245/* End PBXProject section */
2130 2246
2131/* Begin PBXSourcesBuildPhase section */ 2247/* Begin PBXSourcesBuildPhase section */
2248 2D07B96D1636FC9900DB751B /* Sources */ = {
2249 isa = PBXSourcesBuildPhase;
2250 buildActionMask = 2147483647;
2251 files = (
2252 2D07B97A1636FCCE00DB751B /* eventsql.c in Sources */,
2253 );
2254 runOnlyForDeploymentPostprocessing = 0;
2255 };
2256 2D604B9816514B1A003AAF46 /* Sources */ = {
2257 isa = PBXSourcesBuildPhase;
2258 buildActionMask = 2147483647;
2259 files = (
2260 2D604BA516514C4F003AAF46 /* eventtxt.c in Sources */,
2261 );
2262 runOnlyForDeploymentPostprocessing = 0;
2263 };
2132 3104AFAF156D357B000A585A /* Sources */ = { 2264 3104AFAF156D357B000A585A /* Sources */ = {
2133 isa = PBXSourcesBuildPhase; 2265 isa = PBXSourcesBuildPhase;
2134 buildActionMask = 2147483647; 2266 buildActionMask = 2147483647;
@@ -2461,6 +2593,16 @@
2461/* End PBXSourcesBuildPhase section */ 2593/* End PBXSourcesBuildPhase section */
2462 2594
2463/* Begin PBXTargetDependency section */ 2595/* Begin PBXTargetDependency section */
2596 2275798916C5422900B662B0 /* PBXTargetDependency */ = {
2597 isa = PBXTargetDependency;
2598 target = 2D604B9B16514B1A003AAF46 /* mpseventtxt */;
2599 targetProxy = 2275798816C5422900B662B0 /* PBXContainerItemProxy */;
2600 };
2601 2D07B9791636FCBD00DB751B /* PBXTargetDependency */ = {
2602 isa = PBXTargetDependency;
2603 target = 2D07B9701636FC9900DB751B /* mpseventsql */;
2604 targetProxy = 2D07B9781636FCBD00DB751B /* PBXContainerItemProxy */;
2605 };
2464 3104AFC1156D35AE000A585A /* PBXTargetDependency */ = { 2606 3104AFC1156D35AE000A585A /* PBXTargetDependency */ = {
2465 isa = PBXTargetDependency; 2607 isa = PBXTargetDependency;
2466 target = 31EEABFA156AAF9D00714D05 /* mps */; 2608 target = 31EEABFA156AAF9D00714D05 /* mps */;
@@ -2683,7 +2825,7 @@
2683 }; 2825 };
2684 3114A6D5156E9839001E0AA3 /* PBXTargetDependency */ = { 2826 3114A6D5156E9839001E0AA3 /* PBXTargetDependency */ = {
2685 isa = PBXTargetDependency; 2827 isa = PBXTargetDependency;
2686 target = 3114A6C5156E9815001E0AA3 /* eventcnv */; 2828 target = 3114A6C5156E9815001E0AA3 /* mpseventcnv */;
2687 targetProxy = 3114A6D4156E9839001E0AA3 /* PBXContainerItemProxy */; 2829 targetProxy = 3114A6D4156E9839001E0AA3 /* PBXContainerItemProxy */;
2688 }; 2830 };
2689 31A47BAA156C210D0039B1C2 /* PBXTargetDependency */ = { 2831 31A47BAA156C210D0039B1C2 /* PBXTargetDependency */ = {
@@ -2769,6 +2911,51 @@
2769/* End PBXTargetDependency section */ 2911/* End PBXTargetDependency section */
2770 2912
2771/* Begin XCBuildConfiguration section */ 2913/* Begin XCBuildConfiguration section */
2914 2D07B9751636FC9900DB751B /* Debug */ = {
2915 isa = XCBuildConfiguration;
2916 buildSettings = {
2917 GCC_C_LANGUAGE_STANDARD = c99;
2918 PRODUCT_NAME = "$(TARGET_NAME)";
2919 };
2920 name = Debug;
2921 };
2922 2D07B9761636FC9900DB751B /* Release */ = {
2923 isa = XCBuildConfiguration;
2924 buildSettings = {
2925 GCC_C_LANGUAGE_STANDARD = c99;
2926 PRODUCT_NAME = "$(TARGET_NAME)";
2927 };
2928 name = Release;
2929 };
2930 2D07B9771636FC9900DB751B /* WE */ = {
2931 isa = XCBuildConfiguration;
2932 buildSettings = {
2933 GCC_C_LANGUAGE_STANDARD = c99;
2934 PRODUCT_NAME = "$(TARGET_NAME)";
2935 };
2936 name = WE;
2937 };
2938 2D604B9F16514B1A003AAF46 /* Debug */ = {
2939 isa = XCBuildConfiguration;
2940 buildSettings = {
2941 PRODUCT_NAME = "$(TARGET_NAME)";
2942 };
2943 name = Debug;
2944 };
2945 2D604BA016514B1A003AAF46 /* Release */ = {
2946 isa = XCBuildConfiguration;
2947 buildSettings = {
2948 PRODUCT_NAME = "$(TARGET_NAME)";
2949 };
2950 name = Release;
2951 };
2952 2D604BA116514B1A003AAF46 /* WE */ = {
2953 isa = XCBuildConfiguration;
2954 buildSettings = {
2955 PRODUCT_NAME = "$(TARGET_NAME)";
2956 };
2957 name = WE;
2958 };
2772 3104AFBA156D357B000A585A /* Debug */ = { 2959 3104AFBA156D357B000A585A /* Debug */ = {
2773 isa = XCBuildConfiguration; 2960 isa = XCBuildConfiguration;
2774 buildSettings = { 2961 buildSettings = {
@@ -3616,6 +3803,26 @@
3616/* End XCBuildConfiguration section */ 3803/* End XCBuildConfiguration section */
3617 3804
3618/* Begin XCConfigurationList section */ 3805/* Begin XCConfigurationList section */
3806 2D07B9741636FC9900DB751B /* Build configuration list for PBXNativeTarget "mpseventsql" */ = {
3807 isa = XCConfigurationList;
3808 buildConfigurations = (
3809 2D07B9751636FC9900DB751B /* Debug */,
3810 2D07B9761636FC9900DB751B /* Release */,
3811 2D07B9771636FC9900DB751B /* WE */,
3812 );
3813 defaultConfigurationIsVisible = 0;
3814 defaultConfigurationName = Release;
3815 };
3816 2D604BA216514B59003AAF46 /* Build configuration list for PBXNativeTarget "mpseventtxt" */ = {
3817 isa = XCConfigurationList;
3818 buildConfigurations = (
3819 2D604B9F16514B1A003AAF46 /* Debug */,
3820 2D604BA016514B1A003AAF46 /* Release */,
3821 2D604BA116514B1A003AAF46 /* WE */,
3822 );
3823 defaultConfigurationIsVisible = 0;
3824 defaultConfigurationName = Release;
3825 };
3619 3104AFBC156D357B000A585A /* Build configuration list for PBXNativeTarget "apss" */ = { 3826 3104AFBC156D357B000A585A /* Build configuration list for PBXNativeTarget "apss" */ = {
3620 isa = XCConfigurationList; 3827 isa = XCConfigurationList;
3621 buildConfigurations = ( 3828 buildConfigurations = (
@@ -3816,7 +4023,7 @@
3816 defaultConfigurationIsVisible = 0; 4023 defaultConfigurationIsVisible = 0;
3817 defaultConfigurationName = Release; 4024 defaultConfigurationName = Release;
3818 }; 4025 };
3819 3114A6CD156E9815001E0AA3 /* Build configuration list for PBXNativeTarget "eventcnv" */ = { 4026 3114A6CD156E9815001E0AA3 /* Build configuration list for PBXNativeTarget "mpseventcnv" */ = {
3820 isa = XCConfigurationList; 4027 isa = XCConfigurationList;
3821 buildConfigurations = ( 4028 buildConfigurations = (
3822 3114A6CE156E9815001E0AA3 /* Debug */, 4029 3114A6CE156E9815001E0AA3 /* Debug */,
diff --git a/mps/code/mpscamc.h b/mps/code/mpscamc.h
index 8d33ee4bb6a..710eea2f261 100644
--- a/mps/code/mpscamc.h
+++ b/mps/code/mpscamc.h
@@ -12,8 +12,8 @@
12extern mps_class_t mps_class_amc(void); 12extern mps_class_t mps_class_amc(void);
13extern mps_class_t mps_class_amcz(void); 13extern mps_class_t mps_class_amcz(void);
14 14
15extern void mps_amc_apply(mps_pool_t, 15typedef void (*mps_amc_apply_stepper_t)(mps_addr_t, void *, size_t);
16 void (*)(mps_addr_t, void *, size_t), 16extern void mps_amc_apply(mps_pool_t, mps_amc_apply_stepper_t,
17 void *, size_t); 17 void *, size_t);
18 18
19#endif /* mpscamc_h */ 19#endif /* mpscamc_h */
diff --git a/mps/code/mpscmfs.h b/mps/code/mpscmfs.h
new file mode 100644
index 00000000000..4a46e10a84b
--- /dev/null
+++ b/mps/code/mpscmfs.h
@@ -0,0 +1,56 @@
1/* mpscamfs.h: MEMORY POOL SYSTEM CLASS "MFS"
2 *
3 * $Id$
4 * Copyright (c) 2001-2012 Ravenbrook Limited. See end of file for license.
5 */
6
7#ifndef mpscmfs_h
8#define mpscmfs_h
9
10#include "mps.h"
11
12extern mps_class_t mps_class_mfs(void);
13
14#endif /* mpscmfs_h */
15
16
17/* C. COPYRIGHT AND LICENSE
18 *
19 * Copyright (C) 2001-2012 Ravenbrook Limited <http://www.ravenbrook.com/>.
20 * All rights reserved. This is an open source license. Contact
21 * Ravenbrook for commercial licensing options.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions are
25 * met:
26 *
27 * 1. Redistributions of source code must retain the above copyright
28 * notice, this list of conditions and the following disclaimer.
29 *
30 * 2. Redistributions in binary form must reproduce the above copyright
31 * notice, this list of conditions and the following disclaimer in the
32 * documentation and/or other materials provided with the distribution.
33 *
34 * 3. Redistributions in any form must be accompanied by information on how
35 * to obtain complete source code for this software and any accompanying
36 * software that uses this software. The source code must either be
37 * included in the distribution or be available for no more than the cost
38 * of distribution plus a nominal fee, and must be freely redistributable
39 * under reasonable conditions. For an executable file, complete source
40 * code means the source code for all modules it contains. It does not
41 * include source code for modules or files that typically accompany the
42 * major components of the operating system on which the executable file
43 * runs.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
46 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
47 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
48 * PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
49 * COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
50 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
51 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
52 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
53 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
54 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
55 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 */
diff --git a/mps/code/mpscmvt.h b/mps/code/mpscmvt.h
new file mode 100644
index 00000000000..be273177304
--- /dev/null
+++ b/mps/code/mpscmvt.h
@@ -0,0 +1,77 @@
1/* mpscmvt.h: MEMORY POOL SYSTEM CLASS "MVT"
2 *
3 * $Id$
4 * Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
5 */
6
7#ifndef mpscmvt_h
8#define mpscmvt_h
9
10#include "mps.h"
11
12/* The mvt pool class has five extra parameters to mps_pool_create:
13 * mps_res_t mps_pool_create(mps_pool_t * pool, mps_arena_t arena,
14 * mps_class_t mvt_class,
15 * size_t minimum_size,
16 * size_t mean_size,
17 * size_t maximum_size,
18 * mps_count_t reserve_depth
19 * mps_count_t fragmentation_limit);
20 * minimum_, mean_, and maximum_size are the mimimum, mean, and
21 * maximum (typical) size of objects expected to be allocated in the
22 * pool. reserve_depth is a measure of the expected hysteresis of the
23 * object population. fragmentation_limit is a percentage (between 0
24 * and 100): if the free space managed by the pool exceeds the
25 * specified percentage, the pool will resort to a "first fit"
26 * allocation policy.
27 */
28extern mps_class_t mps_class_mvt(void);
29
30/* The mvt pool class supports two extensions to the pool protocol:
31 size and free_size. */
32extern size_t mps_mvt_free_size(mps_pool_t mps_pool);
33extern size_t mps_mvt_size(mps_pool_t mps_pool);
34
35#endif /* mpscmvt_h */
36
37
38/* C. COPYRIGHT AND LICENSE
39 *
40 * Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
41 * All rights reserved. This is an open source license. Contact
42 * Ravenbrook for commercial licensing options.
43 *
44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted provided that the following conditions are
46 * met:
47 *
48 * 1. Redistributions of source code must retain the above copyright
49 * notice, this list of conditions and the following disclaimer.
50 *
51 * 2. Redistributions in binary form must reproduce the above copyright
52 * notice, this list of conditions and the following disclaimer in the
53 * documentation and/or other materials provided with the distribution.
54 *
55 * 3. Redistributions in any form must be accompanied by information on how
56 * to obtain complete source code for this software and any accompanying
57 * software that uses this software. The source code must either be
58 * included in the distribution or be available for no more than the cost
59 * of distribution plus a nominal fee, and must be freely redistributable
60 * under reasonable conditions. For an executable file, complete source
61 * code means the source code for all modules it contains. It does not
62 * include source code for modules or files that typically accompany the
63 * major components of the operating system on which the executable file
64 * runs.
65 *
66 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
67 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
68 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
69 * PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
70 * COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
71 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
72 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
73 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
74 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
75 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
76 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
77 */
diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c
index 15bc692ee00..86855d5c606 100644
--- a/mps/code/mpsi.c
+++ b/mps/code/mpsi.c
@@ -49,7 +49,6 @@
49 49
50#include "mpm.h" 50#include "mpm.h"
51#include "mps.h" 51#include "mps.h"
52#include "mpsavm.h" /* only for mps_space_create */
53#include "sac.h" 52#include "sac.h"
54#include "chain.h" 53#include "chain.h"
55 54
@@ -941,8 +940,9 @@ mps_res_t (mps_ap_frame_pop)(mps_ap_t mps_ap, mps_frame_t frame)
941 940
942/* mps_ap_fill -- called by mps_reserve when an AP hasn't enough arena 941/* mps_ap_fill -- called by mps_reserve when an AP hasn't enough arena
943 * 942 *
944 * .ap.fill.internal: Note that mps_ap_fill should never be "called" 943 * .ap.fill.internal: mps_ap_fill is normally invoked by the
945 * directly by the client code. It is invoked by the mps_reserve macro. */ 944 * mps_reserve macro, but may be "called" directly by the client code
945 * if necessary. See <manual/topic/allocation> */
946 946
947mps_res_t mps_ap_fill(mps_addr_t *p_o, mps_ap_t mps_ap, size_t size) 947mps_res_t mps_ap_fill(mps_addr_t *p_o, mps_ap_t mps_ap, size_t size)
948{ 948{
@@ -1007,8 +1007,9 @@ mps_res_t mps_ap_fill_with_reservoir_permit(mps_addr_t *p_o, mps_ap_t mps_ap,
1007 1007
1008/* mps_ap_trip -- called by mps_commit when an AP is tripped 1008/* mps_ap_trip -- called by mps_commit when an AP is tripped
1009 * 1009 *
1010 * .ap.trip.internal: Note that mps_ap_trip should never be "called" 1010 * .ap.trip.internal: mps_ap_trip is normally invoked by the
1011 * directly by the client code. It is invoked by the mps_commit macro. */ 1011 * mps_commit macro, but may be "called" directly by the client code
1012 * if necessary. See <manual/topic/allocation> */
1012 1013
1013mps_bool_t mps_ap_trip(mps_ap_t mps_ap, mps_addr_t p, size_t size) 1014mps_bool_t mps_ap_trip(mps_ap_t mps_ap, mps_addr_t p, size_t size)
1014{ 1015{
@@ -1687,19 +1688,35 @@ mps_res_t mps_alert_collection_set(mps_arena_t arena,
1687 1688
1688/* Telemetry */ 1689/* Telemetry */
1689 1690
1691/* TODO: need to consider locking. See job003387, job003388. */
1692
1690mps_word_t mps_telemetry_control(mps_word_t resetMask, mps_word_t flipMask) 1693mps_word_t mps_telemetry_control(mps_word_t resetMask, mps_word_t flipMask)
1691{ 1694{
1692 /* Doesn't require locking and isn't arena-specific. */
1693 return EventControl((Word)resetMask, (Word)flipMask); 1695 return EventControl((Word)resetMask, (Word)flipMask);
1694} 1696}
1695 1697
1696mps_word_t mps_telemetry_intern(const char *label) 1698void mps_telemetry_set(mps_word_t setMask)
1699{
1700 EventControl((Word)setMask, (Word)setMask);
1701}
1702
1703void mps_telemetry_reset(mps_word_t resetMask)
1704{
1705 EventControl((Word)resetMask, 0);
1706}
1707
1708mps_word_t mps_telemetry_get(void)
1709{
1710 return EventControl(0, 0);
1711}
1712
1713mps_label_t mps_telemetry_intern(const char *label)
1697{ 1714{
1698 AVER(label != NULL); 1715 AVER(label != NULL);
1699 return (mps_word_t)EventInternString(label); 1716 return (mps_label_t)EventInternString(label);
1700} 1717}
1701 1718
1702void mps_telemetry_label(mps_addr_t addr, mps_word_t intern_id) 1719void mps_telemetry_label(mps_addr_t addr, mps_label_t intern_id)
1703{ 1720{
1704 EventLabelAddr((Addr)addr, (Word)intern_id); 1721 EventLabelAddr((Addr)addr, (Word)intern_id);
1705} 1722}
diff --git a/mps/code/mpsliban.c b/mps/code/mpsliban.c
index 8abab586319..deca56d630f 100644
--- a/mps/code/mpsliban.c
+++ b/mps/code/mpsliban.c
@@ -36,6 +36,8 @@
36#include <stdlib.h> 36#include <stdlib.h>
37#include <stdio.h> 37#include <stdio.h>
38#include <string.h> 38#include <string.h>
39#include <ctype.h>
40#include <assert.h>
39 41
40 42
41int mps_lib_get_EOF(void) 43int mps_lib_get_EOF(void)
@@ -92,15 +94,35 @@ int (mps_lib_memcmp)(const void *s1, const void *s2, size_t n)
92 94
93/* @@@@ Platform specific conversion? */ 95/* @@@@ Platform specific conversion? */
94/* See http://devworld.apple.com/dev/techsupport/insidemac/OSUtilities/OSUtilities-94.html#MARKER-9-32 */ 96/* See http://devworld.apple.com/dev/techsupport/insidemac/OSUtilities/OSUtilities-94.html#MARKER-9-32 */
97
98/* If your platform has a low-resolution clock(), and there are
99 * higher-resolution clocks readily available, then using one of those
100 * will improve MPS scheduling decisions and the quality of telemetry
101 * output. For instance, with getrusage():
102 *
103 * #include <sys/resource.h>
104 * struct rusage s;
105 * int res = getrusage(RUSAGE_SELF, &s);
106 * if (res != 0) {
107 * ...
108 * }
109 * return ((mps_clock_t)s.ru_utime.tv_sec) * 1000000 + s.ru_utime.tv_usec;
110 */
111
95mps_clock_t mps_clock(void) 112mps_clock_t mps_clock(void)
96{ 113{
97 return (unsigned long)clock(); 114 /* The clock values need to fit in mps_clock_t. If your platform
115 has a very wide clock type, trim or truncate it. */
116 assert(sizeof(mps_clock_t) >= sizeof(clock_t));
117
118 return (mps_clock_t)clock();
98} 119}
99 120
100 121
101mps_clock_t mps_clocks_per_sec(void) 122mps_clock_t mps_clocks_per_sec(void)
102{ 123{
103 return (unsigned long)CLOCKS_PER_SEC; 124 /* must correspond to whatever mps_clock() does */
125 return (mps_clock_t)CLOCKS_PER_SEC;
104} 126}
105 127
106 128
@@ -112,6 +134,20 @@ mps_clock_t mps_clocks_per_sec(void)
112#pragma warning( disable : 4996 ) 134#pragma warning( disable : 4996 )
113#endif 135#endif
114 136
137/* Simple case-insensitive string comparison */
138static int striequal(const char *s0, const char *s1)
139{
140 int c;
141 do {
142 c = *s0;
143 if (tolower(c) != tolower(*s1)) /* note: works for '\0' */
144 return 0;
145 ++s0;
146 ++s1;
147 } while (c != '\0');
148 return 1;
149}
150
115unsigned long mps_lib_telemetry_control(void) 151unsigned long mps_lib_telemetry_control(void)
116{ 152{
117 char *s; 153 char *s;
@@ -130,14 +166,20 @@ unsigned long mps_lib_telemetry_control(void)
130 if (mask != 0) 166 if (mask != 0)
131 return mask; 167 return mask;
132 168
133 /* Split the value at spaces and try to patch the words against the names 169 /* copy the envar to a buffer so we can mess with it. */
134 of event kinds, enabling them if there's a match. */
135 strncpy(buf, s, sizeof(buf) - 1); 170 strncpy(buf, s, sizeof(buf) - 1);
136 buf[sizeof(buf) - 1] = '\0'; 171 buf[sizeof(buf) - 1] = '\0';
172
173 /* Split the value at spaces and try to match the words against the names
174 of event kinds, enabling them if there's a match. */
137 for (word = strtok(buf, sep); word != NULL; word = strtok(NULL, sep)) { 175 for (word = strtok(buf, sep); word != NULL; word = strtok(NULL, sep)) {
138#define TELEMATCH(X, rowName, rowDoc) \ 176 if (striequal(word, "all")) {
139 if (strcmp(word, #rowName) == 0) \ 177 mask = (unsigned long)-1;
140 mask |= (1ul << EventKind##rowName); 178 return mask;
179 }
180#define TELEMATCH(X, name, rowDoc) \
181 if (striequal(word, #name)) \
182 mask |= (1ul << EventKind##name);
141 EventKindENUM(TELEMATCH, X) 183 EventKindENUM(TELEMATCH, X)
142 } 184 }
143 185
diff --git a/mps/code/mpstd.h b/mps/code/mpstd.h
index 0345810b723..ad695bc23a9 100644
--- a/mps/code/mpstd.h
+++ b/mps/code/mpstd.h
@@ -97,7 +97,6 @@
97#define MPS_ARCH_I6 97#define MPS_ARCH_I6
98#define MPS_BUILD_MV 98#define MPS_BUILD_MV
99#define MPS_T_WORD unsigned __int64 99#define MPS_T_WORD unsigned __int64
100#define MPS_T_LONGEST __int64
101#define MPS_T_ULONGEST unsigned __int64 100#define MPS_T_ULONGEST unsigned __int64
102#define MPS_WORD_WIDTH 64 101#define MPS_WORD_WIDTH 64
103#define MPS_WORD_SHIFT 6 102#define MPS_WORD_SHIFT 6
diff --git a/mps/code/mv2test.c b/mps/code/mv2test.c
index d8c80ba0d6a..5568f9dc713 100644
--- a/mps/code/mv2test.c
+++ b/mps/code/mv2test.c
@@ -10,7 +10,7 @@
10#include "mpstd.h" 10#include "mpstd.h"
11#include <time.h> 11#include <time.h>
12 12
13#include "mpscmv2.h" 13#include "mpscmvt.h"
14#include "mps.h" 14#include "mps.h"
15 15
16typedef MPS_T_WORD mps_count_t; /* machine word (target dep.) */ 16typedef MPS_T_WORD mps_count_t; /* machine word (target dep.) */
diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c
index 1617c2e4f0a..71f7f8f6fe6 100644
--- a/mps/code/poolamc.c
+++ b/mps/code/poolamc.c
@@ -1,7 +1,7 @@
1/* poolamc.c: AUTOMATIC MOSTLY-COPYING MEMORY POOL CLASS 1/* poolamc.c: AUTOMATIC MOSTLY-COPYING MEMORY POOL CLASS
2 * 2 *
3 * $Id$ 3 * $Id$
4 * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. 4 * Copyright (c) 2001-2012 Ravenbrook Limited. See end of file for license.
5 * Portions copyright (C) 2002 Global Graphics Software. 5 * Portions copyright (C) 2002 Global Graphics Software.
6 * 6 *
7 * .sources: <design/poolamc/>. 7 * .sources: <design/poolamc/>.
@@ -1672,7 +1672,10 @@ static void amcFixInPlace(Pool pool, Seg seg, ScanState ss, Ref *refIO)
1672 return; 1672 return;
1673 } 1673 }
1674 SegSetNailed(seg, TraceSetUnion(SegNailed(seg), ss->traces)); 1674 SegSetNailed(seg, TraceSetUnion(SegNailed(seg), ss->traces));
1675 SegSetGrey(seg, TraceSetUnion(SegGrey(seg), ss->traces)); 1675 /* AMCZ segments don't contain references and so don't need to */
1676 /* become grey */
1677 if(SegRankSet(seg) != RankSetEMPTY)
1678 SegSetGrey(seg, TraceSetUnion(SegGrey(seg), ss->traces));
1676} 1679}
1677 1680
1678 1681
@@ -1792,7 +1795,8 @@ Res AMCFix(Pool pool, ScanState ss, Seg seg, Ref *refIO)
1792 /* Segment only needs greying if there are new traces for */ 1795 /* Segment only needs greying if there are new traces for */
1793 /* which we are nailing. */ 1796 /* which we are nailing. */
1794 if(!TraceSetSub(ss->traces, SegNailed(seg))) { 1797 if(!TraceSetSub(ss->traces, SegNailed(seg))) {
1795 SegSetGrey(seg, TraceSetUnion(SegGrey(seg), ss->traces)); 1798 if(SegRankSet(seg) != RankSetEMPTY) /* not for AMCZ */
1799 SegSetGrey(seg, TraceSetUnion(SegGrey(seg), ss->traces));
1796 SegSetNailed(seg, TraceSetUnion(SegNailed(seg), ss->traces)); 1800 SegSetNailed(seg, TraceSetUnion(SegNailed(seg), ss->traces));
1797 } 1801 }
1798 res = ResOK; 1802 res = ResOK;
@@ -1826,7 +1830,9 @@ Res AMCFix(Pool pool, ScanState ss, Seg seg, Ref *refIO)
1826 1830
1827 /* Since we're moving an object from one segment to another, */ 1831 /* Since we're moving an object from one segment to another, */
1828 /* union the greyness and the summaries together. */ 1832 /* union the greyness and the summaries together. */
1829 grey = TraceSetUnion(ss->traces, SegGrey(seg)); 1833 grey = SegGrey(seg);
1834 if(SegRankSet(seg) != RankSetEMPTY) /* not for AMCZ */
1835 grey = TraceSetUnion(grey, ss->traces);
1830 SegSetGrey(toSeg, TraceSetUnion(SegGrey(toSeg), grey)); 1836 SegSetGrey(toSeg, TraceSetUnion(SegGrey(toSeg), grey));
1831 SegSetSummary(toSeg, RefSetUnion(SegSummary(toSeg), SegSummary(seg))); 1837 SegSetSummary(toSeg, RefSetUnion(SegSummary(toSeg), SegSummary(seg)));
1832 1838
@@ -1930,7 +1936,8 @@ static Res AMCHeaderFix(Pool pool, ScanState ss, Seg seg, Ref *refIO)
1930 /* Segment only needs greying if there are new traces for */ 1936 /* Segment only needs greying if there are new traces for */
1931 /* which we are nailing. */ 1937 /* which we are nailing. */
1932 if(!TraceSetSub(ss->traces, SegNailed(seg))) { 1938 if(!TraceSetSub(ss->traces, SegNailed(seg))) {
1933 SegSetGrey(seg, TraceSetUnion(SegGrey(seg), ss->traces)); 1939 if(SegRankSet(seg) != RankSetEMPTY) /* not for AMCZ */
1940 SegSetGrey(seg, TraceSetUnion(SegGrey(seg), ss->traces));
1934 SegSetNailed(seg, TraceSetUnion(SegNailed(seg), ss->traces)); 1941 SegSetNailed(seg, TraceSetUnion(SegNailed(seg), ss->traces));
1935 } 1942 }
1936 res = ResOK; 1943 res = ResOK;
@@ -1967,7 +1974,9 @@ static Res AMCHeaderFix(Pool pool, ScanState ss, Seg seg, Ref *refIO)
1967 1974
1968 /* Since we're moving an object from one segment to another, */ 1975 /* Since we're moving an object from one segment to another, */
1969 /* union the greyness and the summaries together. */ 1976 /* union the greyness and the summaries together. */
1970 grey = TraceSetUnion(ss->traces, SegGrey(seg)); 1977 grey = SegGrey(seg);
1978 if(SegRankSet(seg) != RankSetEMPTY) /* not for AMCZ */
1979 grey = TraceSetUnion(grey, ss->traces);
1971 SegSetGrey(toSeg, TraceSetUnion(SegGrey(toSeg), grey)); 1980 SegSetGrey(toSeg, TraceSetUnion(SegGrey(toSeg), grey));
1972 SegSetSummary(toSeg, RefSetUnion(SegSummary(toSeg), SegSummary(seg))); 1981 SegSetSummary(toSeg, RefSetUnion(SegSummary(toSeg), SegSummary(seg)));
1973 1982
@@ -2429,7 +2438,7 @@ mps_class_t mps_class_amcz(void)
2429*/ 2438*/
2430 2439
2431typedef struct mps_amc_apply_closure_s { 2440typedef struct mps_amc_apply_closure_s {
2432 void (*f)(mps_addr_t object, void *p, size_t s); 2441 mps_amc_apply_stepper_t f;
2433 void *p; 2442 void *p;
2434 size_t s; 2443 size_t s;
2435} mps_amc_apply_closure_s; 2444} mps_amc_apply_closure_s;
@@ -2449,7 +2458,7 @@ static void mps_amc_apply_iter(Addr addr, Format format, Pool pool,
2449} 2458}
2450 2459
2451void mps_amc_apply(mps_pool_t mps_pool, 2460void mps_amc_apply(mps_pool_t mps_pool,
2452 void (*f)(mps_addr_t object, void *p, size_t s), 2461 mps_amc_apply_stepper_t f,
2453 void *p, size_t s) 2462 void *p, size_t s)
2454{ 2463{
2455 Pool pool = (Pool)mps_pool; 2464 Pool pool = (Pool)mps_pool;
@@ -2499,7 +2508,7 @@ static Bool AMCCheck(AMC amc)
2499 2508
2500/* C. COPYRIGHT AND LICENSE 2509/* C. COPYRIGHT AND LICENSE
2501 * 2510 *
2502 * Copyright (C) 2001-2002, 2008 Ravenbrook Limited <http://www.ravenbrook.com/>. 2511 * Copyright (C) 2001-2012 Ravenbrook Limited <http://www.ravenbrook.com/>.
2503 * All rights reserved. This is an open source license. Contact 2512 * All rights reserved. This is an open source license. Contact
2504 * Ravenbrook for commercial licensing options. 2513 * Ravenbrook for commercial licensing options.
2505 * 2514 *
diff --git a/mps/code/poolmfs.c b/mps/code/poolmfs.c
index 82044e37589..ad4140a4479 100644
--- a/mps/code/poolmfs.c
+++ b/mps/code/poolmfs.c
@@ -1,7 +1,7 @@
1/* poolmfs.c: MANUAL FIXED SMALL UNIT POOL 1/* poolmfs.c: MANUAL FIXED SMALL UNIT POOL
2 * 2 *
3 * $Id$ 3 * $Id$
4 * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. 4 * Copyright (c) 2001-2012 Ravenbrook Limited. See end of file for license.
5 * 5 *
6 * This is the implementation of the MFS pool class. 6 * This is the implementation of the MFS pool class.
7 * 7 *
@@ -32,6 +32,7 @@
32 */ 32 */
33 33
34 34
35#include "mpscmfs.h"
35#include "poolmfs.h" 36#include "poolmfs.h"
36#include "mpm.h" 37#include "mpm.h"
37 38
@@ -282,6 +283,12 @@ PoolClass PoolClassMFS(void)
282} 283}
283 284
284 285
286mps_class_t mps_class_mfs(void)
287{
288 return (mps_class_t)PoolClassMFS();
289}
290
291
285Bool MFSCheck(MFS mfs) 292Bool MFSCheck(MFS mfs)
286{ 293{
287 Arena arena; 294 Arena arena;
@@ -305,7 +312,7 @@ Bool MFSCheck(MFS mfs)
305 312
306/* C. COPYRIGHT AND LICENSE 313/* C. COPYRIGHT AND LICENSE
307 * 314 *
308 * Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>. 315 * Copyright (C) 2001-2012 Ravenbrook Limited <http://www.ravenbrook.com/>.
309 * All rights reserved. This is an open source license. Contact 316 * All rights reserved. This is an open source license. Contact
310 * Ravenbrook for commercial licensing options. 317 * Ravenbrook for commercial licensing options.
311 * 318 *
diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c
index 9401f568b03..dc10ce990a8 100644
--- a/mps/code/poolmv2.c
+++ b/mps/code/poolmv2.c
@@ -11,7 +11,7 @@
11 11
12#include "mpm.h" 12#include "mpm.h"
13#include "poolmv2.h" 13#include "poolmv2.h"
14#include "mpscmv2.h" 14#include "mpscmvt.h"
15#include "abq.h" 15#include "abq.h"
16#include "cbs.h" 16#include "cbs.h"
17#include "meter.h" 17#include "meter.h"
diff --git a/mps/code/seg.c b/mps/code/seg.c
index f12b9fdcbc8..c544a8063e0 100644
--- a/mps/code/seg.c
+++ b/mps/code/seg.c
@@ -267,7 +267,7 @@ void SegSetGrey(Seg seg, TraceSet grey)
267{ 267{
268 AVERT(Seg, seg); 268 AVERT(Seg, seg);
269 AVER(TraceSetCheck(grey)); 269 AVER(TraceSetCheck(grey));
270 AVER(SegRankSet(seg) != RankSetEMPTY); 270 AVER(grey == TraceSetEMPTY || SegRankSet(seg) != RankSetEMPTY);
271 271
272 /* Don't dispatch to the class method if there's no actual change in 272 /* Don't dispatch to the class method if there's no actual change in
273 greyness, or if the segment doesn't contain any references. */ 273 greyness, or if the segment doesn't contain any references. */
diff --git a/mps/code/testlib.h b/mps/code/testlib.h
index 2bcd50e7c18..e3a11c34139 100644
--- a/mps/code/testlib.h
+++ b/mps/code/testlib.h
@@ -74,31 +74,41 @@
74 74
75/* ulongest_t -- longest unsigned integer type 75/* ulongest_t -- longest unsigned integer type
76 * 76 *
77 * Define a longest unsigned integer type for testing and printing. We'd 77 * Define a longest unsigned integer type for testing, scanning, and
78 * like to use C99's uintmax_t and PRIuMAX here, but the MPS is in C89 78 * printing. We'd like to use C99's uintmax_t and PRIuMAX here, but
79 * and C99 isn't supported by Microsoft. 79 * the MPS is in C89 and C99 isn't supported by Microsoft.
80 * 80 *
81 * We avoid using the ones defined in mpstd.h because we want the tests to 81 * We avoid using the types defined in mpstd.h because we want the
82 * root out any incompatible assumptions by breaking. 82 * tests to root out any incompatible assumptions by breaking.
83 */ 83 */
84 84
85#if defined(MPS_ARCH_I6)
86#define PRIwWORD "16"
87#elif defined(MPS_ARCH_I3)
88#define PRIwWORD "8"
89#else
90#error "How many beans make five?"
91#endif
92
85#ifdef MPS_PF_W3I6MV 93#ifdef MPS_PF_W3I6MV
86#define PRIuLONGEST "llu" 94#define PRIuLONGEST "llu"
87#define SCNuLONGEST "llu" 95#define SCNuLONGEST "llu"
96#define SCNXLONGEST "llX"
88#define PRIXLONGEST "llX" 97#define PRIXLONGEST "llX"
89#define PRIwWORD "16"
90typedef unsigned long long ulongest_t; 98typedef unsigned long long ulongest_t;
91typedef long long longest_t; 99typedef long long longest_t;
92#define MPS_WORD_CONST(n) (n##ull) 100#define MPS_WORD_CONST(n) (n##ull)
93#else 101#else
94#define PRIuLONGEST "lu" 102#define PRIuLONGEST "lu"
95#define SCNuLONGEST "lu" 103#define SCNuLONGEST "lu"
104#define SCNXLONGEST "lX"
96#define PRIXLONGEST "lX" 105#define PRIXLONGEST "lX"
97#define PRIwWORD "8"
98typedef unsigned long ulongest_t; 106typedef unsigned long ulongest_t;
99typedef long longest_t; 107typedef long longest_t;
100#define MPS_WORD_CONST(n) (n##ul) 108#define MPS_WORD_CONST(n) (n##ul)
101#endif 109#endif
110
111
102#define PRIXPTR "0"PRIwWORD PRIXLONGEST 112#define PRIXPTR "0"PRIwWORD PRIXLONGEST
103 113
104 114
diff --git a/mps/code/w3i3mv.nmk b/mps/code/w3i3mv.nmk
index ebe971e1626..671b1b5847f 100644
--- a/mps/code/w3i3mv.nmk
+++ b/mps/code/w3i3mv.nmk
@@ -50,6 +50,7 @@ TESTLIB = <testlib>
50 50
51!IF "$(VARIETY)" == "hot" 51!IF "$(VARIETY)" == "hot"
52CFLAGS=$(CFLAGSCOMMONPRE) $(CFHOT) $(CFLAGSCOMMONPOST) 52CFLAGS=$(CFLAGSCOMMONPRE) $(CFHOT) $(CFLAGSCOMMONPOST)
53CFLAGSSQL=$(CFLAGSSQLPRE) $(CFHOT) $(CFLAGSSQLPOST)
53LINKFLAGS=$(LINKFLAGSCOMMON) $(LFHOT) 54LINKFLAGS=$(LINKFLAGSCOMMON) $(LFHOT)
54LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSHOT) 55LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSHOT)
55MPMOBJ0 = $(MPM:<=w3i3mv\hot\) 56MPMOBJ0 = $(MPM:<=w3i3mv\hot\)
@@ -67,6 +68,7 @@ TESTLIBOBJ0 = $(TESTLIB:<=w3i3mv\hot\)
67 68
68!ELSEIF "$(VARIETY)" == "di" 69!ELSEIF "$(VARIETY)" == "di"
69CFLAGS=$(CFLAGSCOMMONPRE) $(CFDI) $(CFLAGSCOMMONPOST) 70CFLAGS=$(CFLAGSCOMMONPRE) $(CFDI) $(CFLAGSCOMMONPOST)
71CFLAGSSQL=$(CFLAGSSQLPRE) $(CFDI) $(CFLAGSSQLPOST)
70LINKFLAGS=$(LINKFLAGSCOMMON) $(LFDI) 72LINKFLAGS=$(LINKFLAGSCOMMON) $(LFDI)
71LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSDI) 73LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSDI)
72MPMOBJ0 = $(MPM:<=w3i3mv\di\) 74MPMOBJ0 = $(MPM:<=w3i3mv\di\)
@@ -84,6 +86,7 @@ TESTLIBOBJ0 = $(TESTLIB:<=w3i3mv\di\)
84 86
85!ELSEIF "$(VARIETY)" == "cool" 87!ELSEIF "$(VARIETY)" == "cool"
86CFLAGS=$(CFLAGSCOMMONPRE) $(CFCOOL) $(CFLAGSCOMMONPOST) 88CFLAGS=$(CFLAGSCOMMONPRE) $(CFCOOL) $(CFLAGSCOMMONPOST)
89CFLAGSSQL=$(CFLAGSSQLPRE) $(CFCOOL) $(CFLAGSSQLPOST)
87LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCOOL) 90LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCOOL)
88LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCOOL) 91LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCOOL)
89MPMOBJ0 = $(MPM:<=w3i3mv\cool\) 92MPMOBJ0 = $(MPM:<=w3i3mv\cool\)
@@ -101,6 +104,7 @@ TESTLIBOBJ0 = $(TESTLIB:<=w3i3mv\cool\)
101 104
102!ELSEIF "$(VARIETY)" == "ti" 105!ELSEIF "$(VARIETY)" == "ti"
103CFLAGS=$(CFLAGSCOMMONPRE) $(CFTI) $(CFLAGSCOMMONPOST) 106CFLAGS=$(CFLAGSCOMMONPRE) $(CFTI) $(CFLAGSCOMMONPOST)
107CFLAGSSQL=$(CFLAGSSQLPRE) $(CFTI) $(CFLAGSSQLPOST)
104LINKFLAGS=$(LINKFLAGSCOMMON) $(LFTI) 108LINKFLAGS=$(LINKFLAGSCOMMON) $(LFTI)
105LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSTI) 109LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSTI)
106MPMOBJ0 = $(MPM:<=w3i3mv\ti\) 110MPMOBJ0 = $(MPM:<=w3i3mv\ti\)
@@ -118,6 +122,7 @@ TESTLIBOBJ0 = $(TESTLIB:<=w3i3mv\ti\)
118 122
119!ELSEIF "$(VARIETY)" == "rash" 123!ELSEIF "$(VARIETY)" == "rash"
120CFLAGS=$(CFLAGSCOMMONPRE) $(CFRASH) $(CFLAGSCOMMONPOST) 124CFLAGS=$(CFLAGSCOMMONPRE) $(CFRASH) $(CFLAGSCOMMONPOST)
125CFLAGSSQL=$(CFLAGSSQLPRE) $(CFRASH) $(CFLAGSSQLPOST)
121LINKFLAGS=$(LINKFLAGSCOMMON) $(LFRASH) 126LINKFLAGS=$(LINKFLAGSCOMMON) $(LFRASH)
122LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSRASH) 127LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSRASH)
123MPMOBJ0 = $(MPM:<=w3i3mv\rash\) 128MPMOBJ0 = $(MPM:<=w3i3mv\rash\)
diff --git a/mps/code/w3i6mv.nmk b/mps/code/w3i6mv.nmk
index 729509f05dc..75aae0aaa4d 100644
--- a/mps/code/w3i6mv.nmk
+++ b/mps/code/w3i6mv.nmk
@@ -50,6 +50,7 @@ TESTLIB = <testlib>
50 50
51!IF "$(VARIETY)" == "hot" 51!IF "$(VARIETY)" == "hot"
52CFLAGS=$(CFLAGSCOMMONPRE) $(CFHOT) $(CFLAGSCOMMONPOST) 52CFLAGS=$(CFLAGSCOMMONPRE) $(CFHOT) $(CFLAGSCOMMONPOST)
53CFLAGSSQL=$(CFLAGSSQLPRE) $(CFHOT) $(CFLAGSSQLPOST)
53LINKFLAGS=$(LINKFLAGSCOMMON) $(LFHOT) 54LINKFLAGS=$(LINKFLAGSCOMMON) $(LFHOT)
54LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSHOT) 55LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSHOT)
55MPMOBJ0 = $(MPM:<=w3i6mv\hot\) 56MPMOBJ0 = $(MPM:<=w3i6mv\hot\)
@@ -67,6 +68,7 @@ TESTLIBOBJ0 = $(TESTLIB:<=w3i6mv\hot\)
67 68
68!ELSEIF "$(VARIETY)" == "di" 69!ELSEIF "$(VARIETY)" == "di"
69CFLAGS=$(CFLAGSCOMMONPRE) $(CFDI) $(CFLAGSCOMMONPOST) 70CFLAGS=$(CFLAGSCOMMONPRE) $(CFDI) $(CFLAGSCOMMONPOST)
71CFLAGSSQL=$(CFLAGSSQLPRE) $(CFDI) $(CFLAGSSQLPOST)
70LINKFLAGS=$(LINKFLAGSCOMMON) $(LFDI) 72LINKFLAGS=$(LINKFLAGSCOMMON) $(LFDI)
71LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSDI) 73LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSDI)
72MPMOBJ0 = $(MPM:<=w3i6mv\di\) 74MPMOBJ0 = $(MPM:<=w3i6mv\di\)
@@ -84,6 +86,7 @@ TESTLIBOBJ0 = $(TESTLIB:<=w3i6mv\di\)
84 86
85!ELSEIF "$(VARIETY)" == "cool" 87!ELSEIF "$(VARIETY)" == "cool"
86CFLAGS=$(CFLAGSCOMMONPRE) $(CFCOOL) $(CFLAGSCOMMONPOST) 88CFLAGS=$(CFLAGSCOMMONPRE) $(CFCOOL) $(CFLAGSCOMMONPOST)
89CFLAGSSQL=$(CFLAGSSQLPRE) $(CFCOOL) $(CFLAGSSQLPOST)
87LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCOOL) 90LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCOOL)
88LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCOOL) 91LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCOOL)
89MPMOBJ0 = $(MPM:<=w3i6mv\cool\) 92MPMOBJ0 = $(MPM:<=w3i6mv\cool\)
@@ -101,6 +104,7 @@ TESTLIBOBJ0 = $(TESTLIB:<=w3i6mv\cool\)
101 104
102!ELSEIF "$(VARIETY)" == "ti" 105!ELSEIF "$(VARIETY)" == "ti"
103CFLAGS=$(CFLAGSCOMMONPRE) $(CFTI) $(CFLAGSCOMMONPOST) 106CFLAGS=$(CFLAGSCOMMONPRE) $(CFTI) $(CFLAGSCOMMONPOST)
107CFLAGSSQL=$(CFLAGSSQLPRE) $(CFCOOL) $(CFLAGSSQLPOST)
104LINKFLAGS=$(LINKFLAGSCOMMON) $(LFTI) 108LINKFLAGS=$(LINKFLAGSCOMMON) $(LFTI)
105LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSTI) 109LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSTI)
106MPMOBJ0 = $(MPM:<=w3i6mv\ti\) 110MPMOBJ0 = $(MPM:<=w3i6mv\ti\)
@@ -118,6 +122,7 @@ TESTLIBOBJ0 = $(TESTLIB:<=w3i6mv\ti\)
118 122
119!ELSEIF "$(VARIETY)" == "rash" 123!ELSEIF "$(VARIETY)" == "rash"
120CFLAGS=$(CFLAGSCOMMONPRE) $(CFRASH) $(CFLAGSCOMMONPOST) 124CFLAGS=$(CFLAGSCOMMONPRE) $(CFRASH) $(CFLAGSCOMMONPOST)
125CFLAGSSQL=$(CFLAGSSQLPRE) $(CFRASH) $(CFLAGSSQLPOST)
121LINKFLAGS=$(LINKFLAGSCOMMON) $(LFRASH) 126LINKFLAGS=$(LINKFLAGSCOMMON) $(LFRASH)
122LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSRASH) 127LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSRASH)
123MPMOBJ0 = $(MPM:<=w3i6mv\rash\) 128MPMOBJ0 = $(MPM:<=w3i6mv\rash\)