6 ms·
Optimizing Guile Scheme
- anthk 2y agoI prefer Common Lisp with SBCL and Lem, but this is good too. On SICP, Guile badly needs a module for the picture language from the book (and srfi-203 + srfi-216).
- orliesaurus 2y agoAs soon as I saw the title, I thought of the streetfighter character, but this was actually an interesting read on a programming language, I had never heard of before
- abound 2y agoA prominent use of Guile is as the configuration language for Guix, GNU's version of Nix
- pxc 2y agoIt's the official GNU extension language, so it's fairly widely used in the GNU world I think. It's also the language of the init system/service manager on GuixSD (the full OS distribution based on Guix), GNU Shepherd (a.k.a. dmd), and IIRC their initrd runs a Guile program instead of a shell script.
- deleted 2y ago[deleted]
- bitwize 2y agoThe slogan I've proposed for the language is "Guile goes with everything." Because Guile was designed from the outset to run embedded or standalone, and to transpile other extension languages to Scheme or a Scheme-compatible representation, I think that fitting. See: https://knowyourmeme.com/memes/guiles-theme-goes-with-everything https://knowyourmeme.com/memes/guiles-theme-goes-with-everyt...
- davexunit 2y agoI think the Guile community of yore would have no idea what Street Fighter was but now we should embrace it as long as Capcom doesn't get mad.
- bitwize 2y agoThe other Scheme environment I use regularly is Gambit. So, reppin both Marvel and Capcom.
- masfoobar 2y agoOriginally, it was called GEL (GNU Extension Language) but was later renamed to GUILE. https://wingolog.org/archives/2009/01/07/a-brief-history-of-guile https://wingolog.org/archives/2009/01/07/a-brief-history-of-... There was a forum where Tom Lord, the creator of GEL talked about the early history from his perspective. Unfortunately I cannot remember where it is. Sadly, Tom Lord passed away in 2022.
- fwip 2y agoShould it be "Guile Scheme goes with everything" for the rhyme?
- pjmlp 2y agoGreat overview on how to approach improving code performance, without going down the usual route of rewriting into something else.
- throwaway17_17 2y agoSolid blog overall and I think it is pitched at the right level of granularity for the topic. However, if I were offering criticism, the place I think more detail would be super interesting is the 'Please Inline' section. In particular, I would really be interested in a slightly more detailed description of the optimizer's algorithm for inlining. I think the "define_inlinable" macro is a great example of macro usage, but it is clearly a way to circumvent the inliner's apparent short comings. I would like to be able to understand what heuristic the optimizer is using to see if there is a sensible default function construction style/idiom that is more appealing to the optimizer for inlining. However, I am reminded of the inlining discussion in Chandler Carruth's talk (Understanding Compiler Optimization) from a few years ago where he discusses how obscure and seemingly arbitrary, in general, inlining heuristics and their optimization passes are in practice. [1] 1 - https://youtu.be/FnGCDLhaxKU?si=J3MhvJ-BmX5SG2N6&t=1550 https://youtu.be/FnGCDLhaxKU?si=J3MhvJ-BmX5SG2N6&t=1550
- davexunit 2y agoA walkthrough of Guile's optimization passes and the inlining heuristics would be great. I've been meaning to do a "part two" here but you know how these things go.
- atemerev 2y agoThese sorts of optimizations can and should be handled by a (sufficiently smart (tm)) compiler. Common Lisp/SBCL is usually sufficiently smart. I know not everyone likes Common Lisp, but at least I would have tested it with something more performant that Guile, like Chicken Scheme (my favorite!), Chez Scheme, etc. I like Guile and its purpose as a universal scripting language. However, its performance issues are well known. Even compared to other scripting-first languages (Lua, Perl, Python etc).
- throwaway17_17 2y agoI think that is why this blog is particularly interesting to me. As one of the other comments to this posting said, it is nice to see an analysis/detailed description of working to optimize code where the first step is not to rewrite in a language with a presumed better performance baseline. Also, I think there is also some props to be given for continuing to work within Guile's somewhat spartan tooling to do the optimization work, instead of switching to a language that may have more/better tooling for the task. Not to take away from the general comparisons between various Lisp flavors and between various scripting languages (an activity I engage in quite often), but your lead off line is more prescriptive than I find advisable. I don't think a blanket statement that optimizations of runtime behavior of code "should" only be done via a compiler. Some devs enjoy the work, others have varied reasons for doing performance sensitive work in a given language/environment. But at the end of day, doing optimization is a valid usage of developer effort and time if that developer judges it so.
- eru 2y agoIsn't Racket the 'default' Scheme? (Even though it's no longer called Scheme.)
- medo-bear 2y agoNo
- School-Cotton 2y agoExtremely easy interop with native code is the main selling point of guile IMO. You just link in guile as a library and can have C code call scheme code and vice versa. Makes it great for any native program that needs an embedded scripting language (much like Lua). Does Racket support that use-case?
- munificent 2y agoI have such mixed feelings about dynamically typed languages. I've designed a whole pile of hobby programming languages, and dynamically typed languages are at least an order of magnitude simpler to design and for users to learn and start using. At the same time, they inevitably seem to lead to user stories like this where a user really does know exactly what types they're working with and wants the language to know that too (for performance or correctness), and they end up jumping through all sorts of insane hoops to get the optimizer to do exactly what they want.
- sctb 2y agoI like dynamic languages too. But I don't like the idea of "optimization", and I would be super interested in a dynamic language that didn't attempt to divorce performance from correctness. The worst part about jumping through insane hoops to enchant the optimizer is that it can all go wrong with the tiniest change--a flag here, a different usage pattern there, a new version, etc., and suddenly your program doesn't do what you need it to, as though an operation taking 1000x longer is just a matter of degree.
- munificent 2y agoI agree completely. At the same time, no one wants their code to run 100x slower than it would in any typical statically typed language. Unoptimized dynamic languages are sloooooow.
- 082349872349872 2y agoRpython and Graal (and what else?) provide JIT-for-free (or at least cheap). Of course, this really only works for code that is (a) statically polymorphic but dynamically monomorphic, and (b) has hot loops, but qualitatively that conjunction does seem like it ought to cover a lot of low-hanging fruit. Anyone have quantitative measures?
- noelwelsh 2y agoThere aren't many people looking at these JITs at the moment. Stefan Marr[1]'s group[2] is, I believe, the where most of the research is currently done. A recent paper[3] compares performance of interpreters in RPython and Graal. Their baseline performance is Java, and they achieve performance close to V8, which itself is about 2x slower than Java. My summary is you can write fast interpreters + get JIT for free, but fast JIT for dynamic languages still means 2x slower than JIT for statically typed languages (and Java definitely leaves some performance on the table due to how it represents data). [1]: https://stefan-marr.de/ https://stefan-marr.de/ [2]: https://research.kent.ac.uk/programming-languages-systems/ https://research.kent.ac.uk/programming-languages-systems/ [3]: https://dl.acm.org/doi/10.1145/3622808 https://dl.acm.org/doi/10.1145/3622808
- samatman 2y agoIf you want to read just an enormous amount of well-written bloggage about optimizing Guile Scheme, this is the spot: https://wingolog.org https://wingolog.org Andy Wingo is the maintainer and I get a kick out of everything he posts.
- davexunit 2y agoAndy's blog is on another level. He's also leading the Hoot project to compile Guile to WebAssembly and I work with him on that and try to absorb whatever compiler knowledge I can while doing so.
- exitb 2y agoYou probably shouldn’t do those things. The point of a high level language is to not have to think about such details. If you can’t get the performance you need, you should use a different tool, instead of trying to circumvent implicit limitations.
- gus_massa 2y agoSometimes you can write mostly high level code and only add trick and annotations for speed to very hot loops.
- exitb 2y agoThere are two major problems with this approach. First of all, the intent is implicit, so it won't be clear for a new set of eyes. Second, by peeking behind the curtain you can get some gains, but only as long as everything behind this curtain stays the same. Author written about Guile 3, but is it also true of Guile 2 or 1? Will it hold true for Guile 4? Anybody's guess really. In contrast to this approach, I'd point at Numpy. It optimises specific cases in Python code, but does so in an explicit way and its interface is even sufficiently high level to match Python well.
- gus_massa 2y agoEarly this year, I've been suffering with @guvectorize in Python, so I don't disagree completely... Anyway: > First of all, the intent is implicit, so it won't be clear for a new set of eyes. Yep. Many times the change is obvious, like changing + to fx+ But if the change needs a big rewrite, it probably needs a good comment explaining the simple versions and the tricks to make it faster. Even better, have the functions `something` and also `something_slow` with the simple slow implementation so you can make a few test and check they give the same result. I've used that for big refactoring/rewriting, in the moment I run the two functions and the results differ by more than 1E-10, I made a mistake and I have to revert the last change (hopefully). > Author written about Guile 3, but is it also true of Guile 2 or 1? Will it hold true for Guile 4? I don't know about the details of Guile, but I know about Racket. (I guess Guile has a similar culture.) It the code is fast in the current version 8, then nobody is sure if it's also fast in the previous versions 7 or 6 or ... The compiler get a lot of tiny invisible improvements and perhaps one of them made your code fast. It's difficult to know. About version 9 ... There is an informal implicit promise to make idiomatic code faster. So I expect fast idiomatic code in version 8 to be fast in version 9. Moreover, I'd classify a big slowdown as a almost-bug and hope it's fixed for next edition. (It happened in the 7 -> 8 transition when the back end was changed completely, but the problems were rare.) Non idiomatic code is more problematic, for example if you use too many `set!` to make the code faster. I don't expect that code with `set!` to be slower in version 9, but perhaps the version without `set!` may be faster in the new release. About the changes proposed in the article, I don't expect them to cause problems in the future. Perhaps the Guile compiler will be improved to make them unnecessary, but they don't look problematic.
- pmkary 2y agoMakes me happy when I see Guile is alive and going.
- ristos 2y agoThe monomorphic vs polymorphic argument is an interesting one. I think that you could explicitly get unboxing if you used something like CLOS style multimethods to dispatch based on the type, so that (add <float> <float>) would dispatch to the function that uses fadd on those operands. I never realized that you could use this kind functionality, multimethods or free monad interpreters, to write in-code optimizations that are conveniently abstracted away in actual code usage. Edit: nevermind, that's also dynamic dispatch. You'd have to add static dispatch via macros or some external transpilation step.
- bjoli 2y agoThe guile source->source Optimizer is such a nice tool to see what is going on. Especially when writing macros. I really recommend Kent Dybvig's "the macro writer's bill of rights" to see how useful it can be.
- tightbookkeeper 2y agoThe full numeric tower sounds like a great idea. But in retrospect you almost never want uint32 silently converting to bignum, or ending up with a low precision float. Has anyone had a positive experience?
- davexunit 2y agoI love the numeric tower most of the time. Not having to worry about integer overflow bugs is great. I like that I can express the fraction 1/3 exactly rather than approximately with a float. It's only in the cases of very sensitive code that I have to worry about the details of how numbers are represented at runtime.
- tmtvl 2y agoThat's funny, my impression was the opposite: that you'd almost always want a fixed-width integer to promote to bignum when it transcends the limit. It's a lot more sensible than adding a bunch of integers together and ending up with one which is smaller than any of the ones in the input.
- pkkm 2y agoI would say the opposite: In a high-level language for "everyday programming", as opposed to systems programming or high-performance programming, arbitrary precision signed integers are the right choice. They let you do math on things like a large file size in bytes, or a nanosecond-precision timestamp, without having to think about integer widths. You only need to think about "is this an integer or is this floating-point", which takes less mental effort than using a language like C with its large selection of integer types.