Typed Racket segmentation fault

59 views
Skip to first unread message

James Geddes

unread,
Jun 5, 2019, 10:42:31 AM6/5/19
to racket...@googlegroups.com
Dear All,

The following Typed Racket program is intended to produce an image of the Mandelbrot set (but it doesn't bother actually displaying the image).

Running the program using command-line Racket causes a crash. Specifically, Racket terminates with the error message:

Segmentation fault: 11

However,

1. The program runs successfully in DrRacket;

2. Reducing the size of the image to, say, 200 x 200 (by changing the last arguments in the calls to `make-ticks`) also results in successful termination, without a segmentation fault.

Any advice appreciated!

(PS: I'm not actually that interested in making pictures. I'm trying to do some speed benchmarks to show my colleagues, particularly those who argue that Python is faster, and this example happened to be on hand.)


James




#lang typed/racket

;; Generate an image of the Mandelbrot set (https://en.wikipedia.org/wiki/Mandelbrot_set)

(define *iteration-limit* : Integer 50)

(: mandel (-> Float-Complex Integer))
;; Given c, iterate z <- z^2 + c starting from z = 0 until either |z| > 2 or the number of iterations
;; exceeds *iteration-limit*. Returns the number of iterations required.
(define (mandel c)
(let mandel-iter ([z 0.0+0.0i]
[i 0])
(if (or (>= i *iteration-limit*) (> (magnitude z) 2.0))
i
(mandel-iter (+ c (sqr z)) (+ i 1)))))

(: brot ((Listof Float) (Listof Float) -> (Listof Integer)))
;; Apply mandel to a rectangular grid of complex numbers
(define (brot xs ys)
(for*/list : [Listof Integer]
([y (in-list ys)]
[x (in-list xs)])
(mandel (make-rectangular x y))))

(: make-ticks (-> Float Float Integer (Listof Float)))
(define (make-ticks min max resolution)
(range min max (/ (- max min) resolution)))

(define *xs* (make-ticks -1.5 0.5 300))
(define *ys* (make-ticks -1.0 1.0 300))

;; Compute a Mandelbrot image (but then discard it)
(void (brot *xs* *ys*))


Philip McGrath

unread,
Jun 5, 2019, 10:47:19 AM6/5/19
to James Geddes, Racket Users
What version of Racket are you using? I get a segfault in 7.2, but 7.3 works for me.
-Philip


--
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/194F0EE9-0B9E-412B-A2C0-BCE51CD0AA75%40gmail.com.
For more options, visit https://groups.google.com/d/optout.

James Geddes

unread,
Jun 5, 2019, 10:48:28 AM6/5/19
to Philip McGrath, Racket Users
I'm using version 7.3, amusingly.

James

Paulo Matos

unread,
Jun 5, 2019, 11:02:24 AM6/5/19
to racket...@googlegroups.com

On 05/06/2019 16:47, Philip McGrath wrote:
> What version of Racket are you using? I get a segfault in 7.2, but 7.3
> works for me.

I see the segfault in 7.1 but not in 7.2 or 7.3. Then I run it under
valgrind and I see it in all the versions. :)
It's there, but sometimes hiding.

Will take a look.
> <mailto:racket-users%2Bunsu...@googlegroups.com>.
> --
> 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
> <mailto:racket-users...@googlegroups.com>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/racket-users/CAH3z3gY4Cte5p0ZuY6yCmjAc1jjebZQ6GTaQQZJXQxdoqaop2Q%40mail.gmail.com
> <https://groups.google.com/d/msgid/racket-users/CAH3z3gY4Cte5p0ZuY6yCmjAc1jjebZQ6GTaQQZJXQxdoqaop2Q%40mail.gmail.com?utm_medium=email&utm_source=footer>.
> For more options, visit https://groups.google.com/d/optout.

--
Paulo Matos

Sam Tobin-Hochstadt

unread,
Jun 5, 2019, 11:40:55 AM6/5/19
to Paulo Matos, Racket Users
I think this is a miscompilation of `unsafe-make-flrectangular` by the
underlying Racket compiler.
The below program is a plain racket version of the code, with just one
use of unsafe, a call to `unsafe-make-flrectangular`. If that's
replaced with `make-flrectangular`, then the program works propetly.
Furthermore, if we add a print statement that requires the argument to
`unsafe-make-flrectangular`, then the program also works correctly.
The program also works correctly with the JIT off, and under RacketCS.
https://gist.github.com/samth/683042c4754c1c5ce284794b19dd37e3
> 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/cea3ba1c-64fe-2d39-a8ed-98570751fb3e%40linki.tools.

Matthew Flatt

unread,
Jun 5, 2019, 11:46:03 AM6/5/19
to Sam Tobin-Hochstadt, Paulo Matos, Racket Users
I had just reached the same conclusion. Specifically, it looks like a
missing runstack sync in the JIT-inlined `unsafe-make-flrectangular`.

Thanks!
> https://groups.google.com/d/msgid/racket-users/CAK%3DHD%2BaX%2Bh4%3DEAOt4qYC8dB
> 8JfPCRUfHvo0C8C-BnbzAfdfuqw%40mail.gmail.com.

Philip McGrath

unread,
Jun 5, 2019, 12:08:30 PM6/5/19
to Matthew Flatt, Sam Tobin-Hochstadt, Paulo Matos, Racket Users
In case it's helpful as a workaround, changing the #lang line to:
#lang typed/racket #:no-optimize
will disable the type-based optimizations, so the problematic `unsafe-make-flrectangular` isn't introduced and the segfault is avoided. You presumably loose some performance, though, and "use this flag to work around a compiler bug" may not be the first example you want to show your colleagues—but, even without the type-based optimizations, Racket is probably still faster than Python.

In case it's helpful for your colleagues, someone recently brought up this direct comparison of speed benchmarks for Racket and Python 3: https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/racket-python3.html

-Philip


Matthew Flatt

unread,
Jun 5, 2019, 12:09:23 PM6/5/19
to Racket Users

James Geddes

unread,
Jun 5, 2019, 12:26:58 PM6/5/19
to Philip McGrath, Matthew Flatt, Sam Tobin-Hochstadt, Paulo Matos, Racket Users
This is very helpful, thank you.

In fact, my "naive" version (in untyped Racket) was about the same speed as my colleague's naive Python version. Switching to fl+, fl-, etc bought me a 10x improvement (I presume from the JIT compiler avoiding boxing and unboxing?). Annoyingly, my colleague had got the same speedup by using Numpy, but that does require a change to the way one arranges the calculation (and the change is unnatural, to my eye).

Simply switching to Racket on Chez improved the naive version by a factor of 5x, which was very nice to see.

However, I'm now unsure how to continue. How should I think about making speed improvements? There are flvectors, for example: under what circumstances would these help? Should I expect more gains from TR above this, or do the gains only come from TR figuring out that it can use fl+ rather than me doing so?

Many thanks again,

James
> To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/CAH3z3gb1hoEKSU4ygZLghPZN%3Daz3J5MANZAJzxA6i2X9dM3ztg%40mail.gmail.com.

Philip McGrath

unread,
Jun 5, 2019, 1:10:59 PM6/5/19
to James Geddes, Matthew Flatt, Sam Tobin-Hochstadt, Paulo Matos, Racket Users
On Wed, Jun 5, 2019 at 12:26 PM James Geddes <james....@gmail.com> wrote:
Annoyingly, my colleague had got the same speedup by using Numpy, but that does require a change to the way one arranges the calculation (and the change is unnatural, to my eye).

Also, that's cheating! Numpy is mostly written in C, with all of the safety issues that entails. Numpy is a great, well-maintained library, but these issues came up with a library I depend on just this week.

The JSON parser and writer in Python's standard library are not especially fast,* so there are a lot of JSON packages that do what you need to do to write fast Python modules: write them in C. At Digital Ricouer, we are using spaCy, a Python NLP library. They've vendored a fork of one of these C-level JSON libraries and some similar libraries with the goal of making maintenance easier. This week, someone found some memory leaks, because manual memory management is hard. The reporter said, "Days were spent on this issue, because I would never suspect the JSON library to be at fault, but it is." It turns out the upstream library has had an open PR to patch these leaks since June 2017. The creator of spaCy commented:
I have to say, I feel pretty sheepish about this. The fact that ujson had that PR open for a while was one of the things that made us think that vendoring our own fork might not be such a bad idea. But...then I got started doing srsly, and I forgot all about that PR :(. So I never ended up actually integrating the patch!
 
With Racket, you are getting this speed while working in a safe language, with C-level bits only where they really do make sense.

*I'd love to see benchmarks of Python's stock JSON parser vs. Racket's, especially since Matthew's optimizations in Racket 7.3.

On your broader questions:
However, I'm now unsure how to continue. How should I think about making speed improvements?

If you want to optimize Mandelbrot, it happens to be worked through as an example in The Racket Guide section on parallelism with futures: https://docs.racket-lang.org/guide/parallelism.html

In general, though, I think a the fundamental question is what kind of programs you're going to write and where the hot spots are likely to be. I personally don't do much pure number-crunching, but I think that is an area where Typed Racket can help: it can effectively translate `+` into `unsafe-fl+` because the type-checker has proven the arguments are correct. For more general advice, the Guide has a section on performance: https://docs.racket-lang.org/guide/performance.html

Two other miscellaneous points that come to mind:
  • `match` does some similar optimizations to Typed Racket, so that it can use e.g. `unsafe-car` and `unsafe-cdr` if it knows it's already done a `pair?` check.
  • Many sequence constructors like `in-list` document that they "can provide better performance for … iteration when [they] appear[] directly in a `for` clause." The difference is significant: with `in-list`, `in-vector`, etc., the `for`-like forms are generally as fast as hand-written loops. I'm in the habit of using these constructors all the time.
-Philip

Reply all
Reply to author
Forward
0 new messages