
I have a Brainfuck program translated into Racket program instruction by instruction. Can someone confirm that this is the optimal solution? Or there is still overhead that can be reduced. https://gist.github.com/sleepnova/241c524a3311390ba9e2ff5aed93cbff\|https://gist.github.com/sleepnova/241c524a3311390ba9e2ff5aed93cbff

@wanpeebaw I observe several inc
instructions in a row. You could make a peep-hole optimizer that rewrites to (inc n)
. One way to do this, is to expand to (peephole
(inc)
(inc)
(inc)
(inc)
(inc)
(inc)
(until
(zero? (current-byte))
(dec)
(ptr++)
...)
and let peephole me a macro that rewrites its input.
Similar optimizations can be done for repeated occurrences of dec, ptr++, ptr--
. Handling mixed sequences of inc
and dec
would be even better :wink:

@sorawee @343519265 thanks for the workaround.. In my case switching to the base language worked, too, but should I open an issue on GitHub?

I see several uses if (current-byte)
which expands to (bytes-ref arr ptr)
. If the current byte is read more often than it is written to, you could make a “cache”.
Simply store the current byte in a variable: (define current 0)
The price is that set-current-byte!
must update the both the variable as well as the array arr
.

Is it possible to write a macro (count-me)
that • Associates a different counter to each syntactic call site (possibly using syntax-line
and syntax-source-path-string
) • The counter is in a struct field such as (struct count (n))
• A struct instance is initialized on the first call to the corresponding (count-me)
call site • Subsequent calls at the same call site do not use a condition to check if the struct has been initialized, and instead does the minimum possible work such as (set-count-n! the-counter (+ (count-n the-counter)))

My current solution uses a hash-ref
at each call, but this is very costly. The ultimate purpose is to count the time and the number of calls at different sites, for debugging/optimization purposes. (raco profile --use-errortrace
is pretty good, but sometimes not precise enough)

FYI, incidentally, I also need to gather the struct instances to display the stats when the program exists.

Yes, please do!

Do you need this to work with compilation to “.zo” form? If not, you can use the 3-D macro approach, where the macro expands to a quoted mutable object. As long as the ojbect isn’t something the expander recognizes, like a box or vector, it will be left alone by further expansion and compilation.

I would not expect most of Racket Mode to work.
Using racket-mode
buffers to edit files: yes.
Using racket-xp-mode
or racket-repl-mode
: no. They need to run a Racket “back end”, which assumes it’s running where your source files are.

Can you report a bug?

Since I do have racket
installed where my source files are (the remote machine), can I force Racket Mode to start up a backend on the remote? i.e. allow Racket Mode to make backends on the remote machine somehow

Interesting. Would you happen to have a pointer that would put me on the right track? (I’m not “seeing it” currently).


Woah, thanks!
The “3d” part is because the compiler is going to keep #,c
as a single struct instance rather than generating something like (begin (set-counter-n! '#s((counter #(0 1)) 0 (* x x))
(add1 (counter-n '#s((counter #(0 1)) 0 (* x x)))))
(* x x))
which would of course not work?
Also, I’m stumped by these last 3 lines :smile:

Yes. The last three lines are there to report all of the generated counters, transporting them from the compile-time list to a run-time list.

It seems @hoshom is going to do this. By looking at the expand observer, this bug results from add-annotations
in “class-prims.rkt”, which calls method-procedure?
to expand the rhs of definitions before the class environment setup.

I see, thank you, that’s quite instructive

Just to be clear, we normally discourage 3-D macros, because they break the phase separation and tend not to play well with compilation to “.zo” form. This kind of instrumentation task is the one use I know that seems possibly ok.

Makes sense.

There are some strange effects indeed. After turning this into a module, it seems that the counters
are not shared by different require
s from different modules, correct?

That doesn’t sound right. Are you using something like (define counters (done))
to have the list of counters, and then looking at them after all modules run?

In main.rkt (riskily simplified from real working case): (module+ main
(require "a.rkt"
"counters.rkt")
(count (fun-from-a))
(#%expression (done)))
where a.rkt also requires “counters.rkt” and uses count
. Then the results shows only the count
of “main.rkt”

Oh, I see what you mean. Yes, the counters
variable will be specific to a module. You need to use something like (done)
in each module to collect the counters for that module.

Ok, that works indeed

@robby (cc: @samth) It turns out that some tests rely on the old keybindings. At least, the frame.rkt
test in frameworks/test
does around line 184. I guess the tests should just change?

Yeah, I’ve changed one so far

I’m happy with just changing the tests but haven’t been proactive about finding them and fixing them

I’ve opened a bug in the typed racket repo