How can I increase expansion+compilation speed?

54 views
Skip to first unread message

Ryan Kramer

unread,
Jul 19, 2020, 8:08:50 PM7/19/20
to Racket Users
Using DrRacket, the following file takes 18 seconds to compile without debugging, or about 40 seconds to compile with debugging: https://raw.githubusercontent.com/default-kramer/plisqin-tutorials/e844825b48137553246c64e73516d880b9068825/define-schema-answer-key/aw-schema.rkt

When I say "compile", I mean that I click "Run" in DrRacket and wait for it to give me REPL access. But that file just defines and provides a slew of functions, it doesn't really do anything at runtime.

(Using the command-line `racket that-file.rkt` takes only 7 seconds, which is OK. But many people, myself included, primarily use DrRacket.)

Admittedly, this is 612 dense lines of code. So it might just be a case of "yeah, that's about how long it takes." But it's also possible (or probable?) that I have some inefficient macros somewhere. Are there any tools/techniques I can use to help me reduce the compilation time?

Linus Björnstam

unread,
Jul 20, 2020, 3:53:29 AM7/20/20
to Ryan Kramer, Racket Users
40s to compile seems rather excessive, considering macros like match that also do a lot of work are instant, almost regardless of their size (I once managed to generate a 2000 line (match ...) and hardly noticed). Is there anything in define-schema that makes it non-linear? Do you process tables or columns over and over? How much code does it expand to?

I might have some computer time tonight, and will be able to test it out and explore the library you are using.

--
Linus Björnstam
> --
> You received this message because you are subscribed to the Google
> Groups "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to racket-users...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/racket-users/40e40eff-a0be-4850-9360-c9648cb5b8d9o%40googlegroups.com <https://groups.google.com/d/msgid/racket-users/40e40eff-a0be-4850-9360-c9648cb5b8d9o%40googlegroups.com?utm_medium=email&utm_source=footer>.

Ryan Culpepper

unread,
Jul 20, 2020, 9:42:57 AM7/20/20
to Ryan Kramer, Racket Users
One thing to check is the size of the resulting bytecode file. When I compiled it, I got a 911 KB .zo file. So the most likely reason is that your macros are just producing a lot of code.

You can run the macro profiler (eg, `raco macro-profiler aw-schema.rkt`) to get a summary of what macros contribute most to the compiled code size. See https://docs.racket-lang.org/macro-debugger/index.html#(part._.Macro_.Profiler) for more details. I also gave a talk about the macro profiler called "The Cost of Sugar" a few years ago at RacketCon. The slides are at http://www.ccs.neu.edu/home/ryanc/talks/racket18-sugar.pdf, and there should be a recording online somewhere.

The usual fix is to use helper functions. There are some examples in the slides.

Ryan


--
You received this message because you are subscribed to the Google Groups "Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to racket-users...@googlegroups.com.

Ryan Kramer

unread,
Jul 20, 2020, 10:59:01 AM7/20/20
to Racket Users
Thanks to both of you.

It does expand to a reasonably large amount of code, a small example is below. The processing that define-schema does shouldn't be worse than O(N*M) where N is the number of tables and M is the number of unique procedure names. Which is not linear, but also probably not large enough to be the main culprit. I added `(println stx-being-returned)` to define-schema and it gets printed relatively quickly. So probably the size of the generated code is the main culprit. I'll try Ryan C's tips as soon as I have time; they look promising.

(define-schema $$
  (table A
         #:property
         [foo (%%scalar "foo-given-A" this)])
  (table B
         #:property
         [foo (%%scalar "foo-given-B" this)]
         [bar (%%scalar "bar-given-B" this)]))

; Approximately expands to
#;(begin
    (define A (make-table 'A))
    (define B (make-table 'B))
    (define (foo x)
      (cond
        [((instanceof A) x)
         (%%scalar "foo-given-A" x)]
        [((instanceof B) x)
         (%%scalar "foo-given-B" x)]
        [else (error "expected instanceof A or B, got" x)]))
    (define (bar x)
      (cond
        [((instanceof B) x)
         (%%scalar "bar-given-B" x)]
        [else (error "expected instanceof B, got" x)])))

Ryan Kramer

unread,
Jul 20, 2020, 10:27:08 PM7/20/20
to Racket Users
Thanks Ryan, the macro profiler is great! It quickly identified a macro that I was able to convert to a procedure. (I'm not sure why I made it a macro in the first place.) And the .zo file decreased from about 910KB to 130KB, and the compilation speed went from 40 seconds to about 8 seconds (with debugging). I can probably do even better, but fixing this first big problem was quite a relief!
Reply all
Reply to author
Forward
0 new messages