There is also interesting CL implementation that is based on the LLVM framework - Clasp[1]. It can be natively compiled and designed for performance. [1] https://github.com/clasp-developers/clasp
CLASP is a really interesting project. For one, it's created and written by a Chemistry PhD researcher (Christian Schafmeister), not someone with a traditional CS background. For another, it's one of the few languages that has ever attempted to interface with C++ at the template level - you can instantiate C++ template classes from CL, and catch C++ exceptions etc. For yet another, he does compacting garbage collecti…
Carp – A statically typed Lisp, without a GC, for real-time applications
81–90 of 139 posts
Re: Carp – A statically typed Lisp, without a GC, for real-time applications
#82There is also interesting CL implementation that is based on the LLVM framework - Clasp[1]. It can be natively compiled and designed for performance. [1] https://github.com/clasp-developers/clasp
Last I checked SBCL and CCL (both open source native compiled CL implementations) are quite a bit faster than Clasp. However, if you are primarily e.g. calling computational chemistry libraries written in C++, Clasp is the way to go. It's the only non-C++ language implementation I know of with actually usable C++ support.
Re: Carp – A statically typed Lisp, without a GC, for real-time applications
#83Earlier quoted context omitted.
> A non-blocking write should just copy the data to the socket buffer, definitely not taking milliseconds. That's the theory, right? It could be I measured something wrong, but sometimes dozens of ms is what I got, and I concluded that non-blocking I/O avoids indeterminate blocking (such as reading from a TCP socket until the sender sent N bytes) but does it completely avoid taking in-kernel locks etc? Probably not.…
>I didn't find any other measurements on the internet, please point me to them if you find them. It has been years since I have written thousands sockets servers (used in forex), yet even a couple milliseconds per write would have made the entire operation useless. >another explanation could be false sharing effects that I didn't know well at the time. False sharing sucks, of course, but milliseconds seems way way to…
Including ones with soft real time GC for performance critical deployments like PTC and Aicas.
https://www.ptc.com/en/products/developer-tools/perc
https://www.aicas.com/wp/products-services/jamaicavm
Anyone picking a traditional JVM for such workloads is doing it wrong.
Re: Carp – A statically typed Lisp, without a GC, for real-time applications
#84Re: Carp – A statically typed Lisp, without a GC, for real-time applications
#85This is interesting, but I believe a big point of LISP is actually having a live system that can be introspected, and GC is part of making that work. In the end isn’t this just but with s-expressions?
Re: Carp – A statically typed Lisp, without a GC, for real-time applications
#86It uses a "linear" (actually affine) type system for memory management, with borrowed refs similar to Rust, but evidently without tracking mutability: https://github.com/carp-lang/Carp/blob/master/docs/Memory.md
The omission of the kind of mutability tracking that eases multithreading seems like a significant drawback for its target application domain.
Re: Carp – A statically typed Lisp, without a GC, for real-time applications
#87Earlier quoted context omitted.
>I didn't find any other measurements on the internet, please point me to them if you find them. It has been years since I have written thousands sockets servers (used in forex), yet even a couple milliseconds per write would have made the entire operation useless. >another explanation could be false sharing effects that I didn't know well at the time. False sharing sucks, of course, but milliseconds seems way way to…
Correction, one of Hotspot's GC implementations, there are plenty of Java implementations to chose from. Including ones with soft real time GC for performance critical deployments like PTC and Aicas. https://www.ptc.com/en/products/developer-tools/perc https://www.aicas.com/wp/products-services/jamaicavm Anyone picking a traditional JVM for such workloads is doing it wrong.
Re: Carp – A statically typed Lisp, without a GC, for real-time applications
#88For the history buffs: Pre-Scheme: A Scheme Dialect for Systems Programming Richard A. Kelsey, 1997 Abstract Pre-Scheme is a statically typed dialect of Scheme that gives the programmer the eciency and low-level machine access of C while retaining many of the desirable features of Scheme. The PreScheme compiler makes use of type inference, partial evaluation and Scheme and Lisp compiler technology to compile the pro…
The letter combination "fi" seems to have been deleted throughout your quote, there. Perhaps it was a ligature in the original.
Re: Carp – A statically typed Lisp, without a GC, for real-time applications
#89This is interesting, but I believe a big point of LISP is actually having a live system that can be introspected, and GC is part of making that work. In the end isn’t this just but with s-expressions?
S-expressions also enable proper macros, as long as it has them, it's already ahead of .
Re: Carp – A statically typed Lisp, without a GC, for real-time applications
#90Earlier quoted context omitted.
As long as you forbid or mark cycles (…or ignore the problem) lifetime analysis can be done statically. Which is better anyway. Automatic memory management doesn't need a GC.
It's really surprising that it's rare in functional languages. Immutability seems like it should guarantee no cycles (?), so reference counting could be used.
Without reference counting, here's the end of a hairy function scope that deallocates 15 local variables and restores two callee-saved registers:
11a6: 48 83 c4 78 add $0x78,%rsp
11aa: 5b pop %rbx
11ab: 41 5e pop %r14
11ad: c3 retq
Now imagine looping over 15 local variables to decrement each reference count, test it, and do a conditional jump based on the result; if that's open-coded, your epilogue is humongous, and if it's in a reference-count-decrementing subroutine, it's going to have mispredicted branches all over the place, costing you maybe 15 cycles each, a total of about 100 cycles for this function. We're talking about adding an order of magnitude of cost to subroutine call, or more. (I think this function doesn't really need 15 local variables; that's the compiler's fault.)This gets worse with multithreading, because writing to the same reference count on different cores would even in the best case require one core stealing the cache line from another in order to modify it, which may stall the core; but often even an atomic reference count increment is more expensive even than that because it involves a memory barrier.
Reference counting can become reasonably cheap if it's done at large granularity (filesystem files or COM objects, not conses); if you can elide almost all of the reference-count updates, as in Rust; or if your language runtime is just so dog-slow at everything that the extra cost of reference counting isn't that important, like CPython.
30 years ago or more, before generational GC had gone mainstream, reference counting was a more reasonable choice, because GC was going to be very slow in any case, and ref counting at least used less memory—especially important on machines without cache or virtual memory.
(Purely immutable (applicative) languages like Haskell and Miranda are usually lazy, since that's the payoff for completely abjuring side effects. But lazy evaluation is implemented at the machine level by mutation.)