Marc:
macro-read-char is a fair amount of code to inline at each site of read-char. We have with the original
-rw-r--r-- 1 lucier pfaculty 107585 Feb 10 12:47 bewig2.c -rwxr-xr-x 1 lucier pfaculty 52001 Feb 10 12:47 bewig2.o1* -rw-r--r-- 1 lucier pfaculty 10799 Feb 10 11:36 bewig2.scm
If we replace all 16 instances of read-char with macro-read-char, we get
-rw-r--r-- 1 lucier pfaculty 175125 Feb 10 13:38 bewig2+macro-read- char.c -rwxr-xr-x 1 lucier pfaculty 71575 Feb 10 13:38 bewig2+macro-read- char.o2* -rw-r--r-- 1 lucier pfaculty 10925 Feb 10 13:38 bewig2+macro-read- char.scm
Part of the problem here is that, if function A calls function B, Gambit's inlining heuristic looks at the size of the macro-expanded function A before deciding whether to inline function B into A; if macro-expansion increases the size of A a lot (say, by expanding macro-read-char ;-), then B is more likely to be inlined into A. This happened with two of the state-machine functions in read-csv- record.
If, instead, we add a simple function my-read-char
(define (my-read-char port) (macro-read-char port))
and then replace calls to read-char by calls to my-read-char, we get
-rw-r--r-- 1 lucier pfaculty 134833 Feb 11 11:50 bewig3.c -rwxr-xr-x 1 lucier pfaculty 59349 Feb 11 11:50 bewig3.o1* -rw-r--r-- 1 lucier pfaculty 10929 Feb 11 11:50 bewig3.scm
and the times are almost as good as when macro-read-char is inlined at all call sites of read-char, 113ms on Philip's benchmark instead of 111ms. Recall that the time for using read-char is 435ms, so we're about four times as fast.
So perhaps you should add another compilation strategy---for files that have calls to read-char (or to any functions that are big enough, or have a big enough fast path, that you don't want to inline them into each call site), put in a local function that has the code for macro-read-char, and redirect calls to read-char to this local function (under suitable circumstances, of course).
Brad