Spritely Goblins v0.16.0 released!
Christine Lemmer-Webber —We are excited to announce Spritely Goblins v0.16.0! This release of Goblins is faster than ever, with two major core speedups benefiting all Goblins-using programs! Furthermore, we have a brand new Unix Domain Socket netlayer, which means our OCapN protocol is now usable for efficient machine-local inter-process communication!
A new Unix Domain Sockets netlayer
Another new netlayer has come to Goblins, this time one based on Unix Domain Sockets! Unix domain sockets are ideal for communication between multiple processes running on the same machine. We think being able to use Goblins and OCapN to wire together a kind of efficient local inter-process communication is pretty neat!
Many users might be familiar with using Unix domain sockets using file paths on the system, however since the file system on Unix(-like) systems use ACLs, this can lead to security vulnerabilities via confused deputy attacks.
Our implementation uses a feature of Unix domain sockets which allow sockets to be sent and received over other sockets. We built an introduction server which you run on your system. You can think of it as a little OCaps kernel in amongst the modern ACL sea that our systems are built on today! The Unix domain socket netlayer can connect to one or multiple of these introduction servers and so long as two netlayers share the same introduction server, they can securely communicate with one another.
We look forward to seeing what you all use this new netlayer for... we have several exciting uses planned ourselves we hope to show off soon!
Speeding, speeding, speeding ahead!
When we're talking speedups in this release, we're not talking in mere single digit percentage speed boosts. No, not even double digit... keep going! Each of our two core speed-boosts bring make Goblins each improve the speed of common Goblins operations 10-20x, benefiting all Goblins-using programs!
The short version is, spawn
has gotten faster, and bcom
and
promises have also gotten faster, all of which are core to all Goblins
programs. For the interested reader, we explain more in further detail
below. (This may go into more detail than many readers care for; feel
free to skip past!)
Speeding up spawn by bypassing the elfs
Once upon a time, when Goblins was being created, a decision was made: debugging programs is important, and so all objects shall carry a debug name, and that debug name shall be, by default, the name of the procedure that constructed the actor! This was a sensible decision, and we believe, generally the correct one: it has served us well.
This decision was made long ago, in early days when Goblins was a Racket library, and we began to focus on speed much more after the port to Guile. But unfortunately, in Guile, asking a procedure "what is your name?" resulted in a journey to the land of elfs.
Or rather, that is all to say, calling procedure-name
in Guile on
every spawn
, which we did for debuggability purposes, turns out to
be painfully slow. And the reason it is slow is that normally
procedure-name
is only called when experimenting at the REPL or when
printing a backtrace. While optimizing Goblins programs, we found that
tracing an ordinary spawn
(using Guile's lovely ,trace
tool) was
printing reams and reams of pages of lines of code. Guile's internal
object file format is (perhaps surprising to some readers!) the very
same ELF as, yes, the
Executable and Linkable Format
used by Linux executables! However, Guile uses this for different
purposes; it turns out this format is just very well thought through,
and Guile's lead dev Andy Wingo has a nice blogpost
explaining why ELF was chosen.
What this effectively meant is that ELF-parsing code would be executed
all the time when simply trying to grab the name of a procedure while
spawning an object.
What to do? Many paths were considered: We could try to optimize this code intended to be rarely-used in Guile itself, or cache the result and attach to the constructor somehow, or evaluate lazily. But each of these had problems: it was slow or otherwise complicated.
We could change spawn
to be a macro, and grab the name referred to
by the constructor at compile time. Alas, this had its own pitfall:
this would break any case where spawn
was already being used with
apply
.
The solution is to support both cases! Here is the new code for
spawn
:
;; When an actor is spawned and a name is not specified, we default to
;; the name of its constructor. However, 'procedure-name' is very
;; slow and can involve parsing ELF for compiled code. To speed
;; things up, we take advantage of the fact that actor constructors
;; are typically specified as identifiers in the source, so we can
;; simply use that identifier as the name. To preserve the illusion
;; that 'spawn' is just a regular ol' procedure, there is identifier
;; syntax.
(define-syntax spawn
(lambda (stx)
(syntax-case stx ()
((_ constructor arg ...) ; fast path
(identifier? #'constructor)
#'(spawn-named 'constructor constructor arg ...))
((_ constructor arg ...) ; slow path
#'(%spawn constructor arg ...))
(id ; identifier syntax; also slow
(identifier? #'id)
#'%spawn))))
What this means is that when a Goblins program is compiled, most
invocations of spawn
will cleverly use the name of the constructor
being passed in at compile time. But if this cannot be determined
simply at compile time, or if spawn
is to be invoked via apply
or
passed around as if it were a function, we fall back to using spawn
as an ordinary procedure (ie, fall back to the internal %spawn
procedure, which calls procedure-name
as normal).
We still love our friends the elfs, and upon occasion, some Goblins
programs might journey into elf
land, should they need their help to
provide a simple debugging name. But most of the time, we can be much
faster now, by looking around where we are at compile time!
Become your new you, faster than ever
Previously we discussed how Goblins actors got much faster with
spawn
, but this is only part of an actor's journey. First, we are
born, and then, we grow and change based upon experience. So it is too
with Goblins actors!
When an actor is spawn
ed, its constructor returns what will be its
first behavior. But actors may change their behavior based upon
experience: in response to a message, a Goblins actor may choose to
bcom
(pronounced "become") a new version of its behavior.
An actor having many experiences (receiving many messages) may
experience a large amount of change, and thus may invoke bcom
a lot.
The way bcom
was implemented used pretty much the same
sealers/unsealers technique
from the appendix of
The Heart of Spritely,
itself a technique borrowed from
W7,
the very security kernel from
A Security Kernel Based on the Lambda Calculus!
This is a cool technique, and takes advantage of being able to
construct new types at runtime. However, constructing new types at
runtime turns out to have some overhead. The details are unimportant,
but we moved to a new implementation of sealers which are functionally
equivalent but use an encapsulated "cookie" comparison, which turns
out to be dramatically faster... about as fast as two accessor calls
and an identity-comparison invocation of eq?
!
In other words, actors can now change their behavior with bcom
quite quickly! And several other aspects of Goblins have gotten faster
too with this new sealers technique, in particular several aspects of
promises! Zoom zoom!
Getting the release
This release includes all the features detailed above as well as many bug fixes. See the NEWS for more information.
As usual, if you're using Guix you can upgrade to 0.16 by using the following:
guix pull
guix install guile-goblins
Otherwise, you can find the tarball on our release page.
The above features and speedups spoken about in this blogpost refer to the Guile version of Goblins, which is nowadays the primary version of Spritely Goblins. However, we do maintain our older Racket version, which has now also gotten updated to maintain OCapN compatibility with Guile Goblins. Racket users can run the following:
raco pkg install goblins
If you're making something with Goblins or want to contribute to Goblins itself, be sure to join our community at community.spritely.institute! We also host regular office hours where you can come and ask questions or discuss our projects, you can find information about those on our community forum. Thanks for following along and hope to see you there!