boinkmarks outage...

Still in Cambridge, “sharing” connectivity on a wireless access point kindly provided by security-unaware residents, so just a short update on the boinkmarks thing: something on this machine is making the linux OOM killer go mad (both in linux 2.6.16 and 2.6.18, running on amd64). It will kill perfectly well-behaved processes although there seem to always be hundreds of megabytes of real RAM (not to mention swap) available. Then, some time later, it will start complaining on the console about running out of memory while oomkilling, in an endless loop.

Thank god this machine has a remote admin interface. I’ll try to fix the real problem when I am back home.

A silly CL-PPCRE performance test

I read “Regular Expression Matching can be Simple and Fast” today (via DF), and I immediately had to try its test for exponential-ness with Edi Weitz’s excellent cl-ppcre.

Here’s a little benchmark thing (as noted in the article, “a?nan” translates to e.g. “a?a?a?aaa” for n=3):

(defun match-n (n) 
  (let* ((as (make-list n :initial-element #\a))
         (regex (format nil "~{~A?~}~{~A~}" as as))
         (string (make-string n :initial-element #\a))) 
    (time (cl-ppcre:scan regex string))))

which gives me (on an intel iMac):

CL-USER> (match-n 100)
Evaluation took:
  0.008 seconds of real time
  0.007047 seconds of user run time
  9.4e-5 seconds of system run time
  0 calls to %EVAL
  0 page faults and
  4,562,912 bytes consed.
0
100
#()
#()

Tee hee. Perl 5.8.8 has been sitting on the same regex for the last few minutes; according to the article, it’ll take 1015 years. ^C!

Why is this blog-worthy? Regex benchmarks on bodies of #\a characters aren’t very interesting, after all (even if CL-PPCRE defeats Ruby, Perl and pcre, according to the graph). One reason: I really like how easy it was to format the regex from a list of #\as.

(Update: Sure enough, there’s a reddit discussion on the same topic. Note that this post’s purpose is to praise format, not cl-ppcre (-;)

Unintended consequences

asdf-dependency-grovel seems to be more of a hit than I’d anticipated. Not only have I received great feedback from several people, ignas on #lisp already found the first a use case for it that I hadn’t anticipated.

* ignas loves asdf-dependency-grovel
<antifuchs> ignas: it works for you? (:
<antifuchs> cool!
* antifuchs happy
* ignas just finished stripping closure's sgml parser of all the unnecessary stuff by using it

So, it turns out that not only can you use adg to merge two large systems into one, it’s possible to split one system into smaller components, as well! Not too bad for a tool that makes use of (hopefully) unintended consequences in the CL specification.

Explaining some features of asdf-dependency-grovel

Some people asked me why asdf-dependency-grovel (abbreviated adg, to save my fingers) merges systems. Since I wrote it, a few more questions came up, and so I’ll try to answer them.

Why does adg merge systems?

ASDF has a useful dependency-tracking mechanism: if a component changes, it automatically rebuilds that component and all components that depend on it. But what happens to dependencies between systems? They are problematic for ASDF, as it doesn’t track the need to recompile components across system boundaries. For example:

(defsystem foo
   :components ((:file "a")))

(defsystem bar
   :depends-on (:foo)
   :components ((:file "b")))

Suppose that file “a” in system FOO changes; if you load system BAR, file “a” will be recompiled; but file “b” will not! If file “b” uses a macro from file “a”, you will load the old version of that macro from FASLs, and things will break. Ow.

There are two solutions for this problem:

  • Make ASDF track compilation across system boundaries - expensive, as every user would need to update asdf, and now every user would have to sit through endless recompilation sessions if only a comment in a low-level system changes.
  • Merge systems where it makes sense. adg ensures that dependencies are kept up-to-date and minimal: only those things that are actual compile-time (or load-time) dependencies are recorded.

This exact problem is what bit us in mcclim once. I spent a long time thinking about it and came up with adg in the end. So there.

How does it merge systems?

It merges systems in the same way it operates when not merging systems, really: asdf recursively propagates an instrumened load-op (which translates to a compile-op for uncompiled sources) down the tree of dependencies, which ensures that adg can collect references and definitions. When a definition or a dependency is recorded, adg checks whether it’s in a list of “interesting” systems and omits those components and dependencies that are not interesting.

Why not just use XREF?

XREF is a mechanism provided by many CL implementations which allows queries like who-calls and who-macroexpands. who-macroexpands would cover a good part of compile-time dependencies, but there are many more types of compile-time dependencies! For example:

  • Definition of a method that uses a class defined in another file
  • Definition of a package that uses another package
  • Use of a symbol interned in a package defined in another file
  • Calling (at compile or load time) a function defined in another file
  • many more…

I do not know a single XREF mechanism that has queries for all these things, and so adg has to grovel to the compiler for them. Thanks to macroexpand-hook, they are pretty easy to find out (-:

Can I have a simple example for using adg?

Sure thing. Assuming you have one (or more) horribly long :serial t system(s):

 (defsystem something-awful
   :serial t
   :components ((:module "foo" :components (#| lots #| )))

You rename the system to indicate that it’s the serial one, then add this argument to the defsystem form: :default-component-type asdf-dependency-grovel:instrumented-cl-source-file, and replace occurrences of :module with asdf-dependency-grovel:instrumented-module. The result would look like this:

 (defsystem something-awful/serial
   :serial t
   :default-component-class asdf-dependency-grovel:instrumented-cl-source-file
   :components ((asdf-dependency-grovel:instrumented-module "foo" :components (#| lots #| )))

(If it’s more than one system, you have to do the previous step for all the systems that are involved.) Then you define a second system that discovers the dependencies:

 (defsystem something-awful/dependencies
   :components ((component-file "something-awful"
                :output-file #p"something-awful-components.lisp-expr"
                :load-system something-awful/serial ; the system to load. should depend-on all the merged systems.
                :merge-systems (something-awful/serial) ; if you have more than one system, list them here
                :cull-redundant t ; remove unnecessary dependencies? Makes for easier-to-read component files
                :verbose nil ; silly debugging output
 )))

I suggest you put the definitions for the /dependencies system and the /serial system(s) in a separate file, and then, in the original system definition file, define your new something-awful system like this:

 (defsystem something-awful
   :components
   #.(let ((component-file (make-pathname :name "something-awful-components"
                                          :type "lisp-expr"
                                          :defaults *load-truename*)))
       (when (probe-file component-file)
         (with-open-file (f component-file :direction :input)
           (read f)))))

And that’s it. You can now load the separate file, run (asdf:oos 'asdf:dependency-op :something-awful/dependencies) and have it emit the component information into something-awful-components.lisp-expr. Done! Your users can now load the new system and hack on it, and ASDF can rely on the dependency information in that file.

You should re-generate the component file (using the :dependency-op) in these cases:

  • After hacking on something and incrementally compiling, the system breaks. This probably means that a compile/load-time dependency was introduced somewhere down the line.
  • After adding a new file. This requires that you find a sensible place for it in the serial order of the /serial system, then have adg re-generate component info.

"make depend" for lisp

As the software-publishing planet.lisp.org crowd probably knows, writing simple defsystems with ASDF is pretty easy. Dependencies are not hard to find (and to specify), if you have up to 10 or 20 components. Beyond that, though, it becomes pretty painful to maintain a system definition file that doesn’t result in a compilation error. After that, it’s easier to use a serial system definition: just find a defined order to compile and load the files.

There’s a tradeoff, though: Serial system definitions are a pain for users who want to hack on your code. If someone changes a file (e.g. one close to the start of the series of components), every single component after it in the series must be recompiled. Dependencies would help, but we already established that they’re too hard to maintain by hand in a large system. What’s a system definition maintainer to do?

Have the computer do the dirty work, of course (-:

A few months ago, I had a pretty neat idea: To find out the compile-time dependencies in a system, you’d have to hook into the compiler. And the compiler provides one such hook: macroexpand-hook - of course, all the operators that can construct a compile-time dependency must be macros - and all the standard operators are!

So, I wrote a program called asdf-dependency-grovel that compiles a serial asdf system (or an asdf system that just so happens to be in working order), and extracts components with dependency information.

Here’s an outline of what it does for the prime example of a compile-time dependency: a file uses a macro that is defined in another file:

    (defmethod asdf:perform :around ((op asdf:compile-op) (comp asdf:cl-source-file))
      (let* ((old-hook *macroexpand-hook*)
             (*macroexpand-hook*
              (lambda (fun form env)
                 (when (listp form)
                   (case (first form)
                     ((defmacro)
                      (signal-macroexpansion 'provides (second form) (first form) comp))
                      ;; many many more form types cut
                     (t (signal-macroexpansion 'uses (second form) (first form) comp))))
                 (funcall old-hook fun form env))))
        (call-next-method)))

And all that signal-macroexpansion does is send a little notice to the function that keeps track of dependencies (i.e. it invokes a closure on a hook) to tell it that there’s either a use of a previously defined macro from the current component, or a new definition from from the current component.

It has additional handlers for:

  • defclass and define-condition (“use” of superclasses, and definition of classes for use by defmethod and other defclass forms)
  • defpackage and in-package.
  • defun - it rewrites the function’s macroexpansion into code that signals a compile-time use.
  • defmethod and defgeneric (“use” of generic functions and classes on which a method specializes),
  • defconstant - makes the constant a symbol-macro signals the variable was used and the constant’s value.

This code managed to automatically generate a working dependency graph for mcclim, even merging 8 pretty large systems into one in the process. The resulting system now contains a total of 168 components with 192 non-redundant dependencies!

If you want to try your luck with asdf-dependency-grovel, check out the cliki page.

Also, here are two graphs of the new McCLIM system’s dependencies and the CLX system’s dependencies.

McCLIM 0.9.4 "Orthodox New Year" released!

We released McCLIM 0.9.4 today. You may be wondering what’s so cool about it this time, so here’s a short list:

  • A new input editor and editing substrate called DREI (covered here before),
  • several great improvements to gtkairo (see lisp porn here), and
  • many cool new features and bug fixes, including a few clim 2.2 functions.

(Of course, there are probably lots of new bugs in there, too. Please let us know about them at mcclim-devel at common-lisp.net!)

(And of course, the release announcement has the obligatory editing-under-stress error. You will get the following reward for finding it:
)

Threads for SBCL on FreeBSD

I don’t use FreeBSD anymore, but for some reason, this topic still interests me.

So it brings me great joy to see that NIIMI Satoshi has a patch that adds threading support to SBCL on FreeBSD! I tested it on FreeBSD 6.1-RELEASE running in Parallels Desktop for Mac, and all tests passed 2 of 3 times. I think this would be a good time for all FreeBSD-using lispers (especially those running it natively) to help us test this change.

Good hunting!

An unexpected optimization (also, archiving IMAP mail with mel-base)

As I own my own mail server, my mail setup is very much engineered to fit my own needs. This means everything works as I think it should, but it also means I have to hack things myself if I need them. This time, I needed a program that can move IMAP mails to archive mailboxes.

(Side note: My IMAP mail server is dovecot, which supports keeping mail in different namespaces in separate storage system. For current mail, Maildir is handy: needs no locking, and it’s hard to corrupt a mailbox. For archiving, mbox is better, because one mailbox takes up only one file.)

The plan was this: For every mail in “mail.lisp.sbcl.arch”, I want it to move the mail to the mail box “archive.<year>.lisp.sbcl.arch”. This would have been a tedious mark&drag operation in any gui-based mailer, and hopelessly slow in the emacs-based mailers (which support this operation) like wanderlust. Mel-base to the rescue!

I’ll keep it short: This code was the result. It requires mel-base (obviously), and I only tested it on sbcl.

So, this is how you use it:

  1. Install mel-base.
  2. Create a file passwords.lisp in the same directory as message-archiver.lisp, with contents like these:

        (setf *me* "username")
        (setf *my-pass* "password")
        (setf *my-host* "imap-server")
    
  3. load message-archiver.lisp.
  4. run (imap-archiver:archive-messages "lisp.phemlock") ; and it will move all mails in the mailbox “mail.lisp.phemlock” to the mailbox “archive.<year>.lisp.phemlock”, with <year> being the year in the message’s Date: header field.

But wait! This is very slow on current versions of mel-base (0.7-2)! Why? The code that copies a message from one folder to another works the same for all folder types: it reads the entire message from the server and sends it back again. As a side effect, this removes all marks. Ow. But we’re lucky that Jochen Schmidt is a good hacker and designed mel such that this is easily fixed.

Like everything else in mel-base, operations on a folder have their own protocol, and copying messages from a folder to another has its own generic function, copy-message-using-folders:

    (defgeneric COPY-MESSAGE-USING-FOLDERS (message message-folder sink-folder))

As it is, we can easily make a method that specializes on the case where we copy a message from an imap folder to another imap folder. We only need to check that they’re on the same server (for that, I assume they’re the same if the server name, port, user name and password are the same), and issue the correct UID COPY command to the imap server, and we’re good to go:

    (in-package :mel.folders.imap)
    (defmethod copy-message-using-folders :around ((message message) (message-folder imap-folder) (sink-folder imap-folder))
      "Copy a message between two imap folders. We can optimize this case if the folders are on the same server."
      (if (and (equal (host message-folder) (host sink-folder))
               (equal (username message-folder) (username sink-folder))
               (equal (password message-folder) (password sink-folder))
               (equal (imap-port message-folder) (imap-port sink-folder)))
          (progn
            (send-command message-folder "~A uid copy ~A ~A" "UID" (uid message) (mailbox sink-folder))
            (process-response message-folder :on-uid (lambda (m) m)))
          ;; if we're not using the same server, play it safe
          (call-next-method)))

Evaluate this, and suddenly everything is 10 times as fast, and marks are preserved after moving the message.

The lesson for today: Good libraries provide functionality that works well enough for the typical use case. Great libraries let you extend them to support your own use cases.

CLISP git repository available

As a pleasant side-effect from CLISP boinkmarks availability, I can now make available a git-ified clone of CLISP’s CVS repository that is synced once every hour.

To use it, point your git or cogito client at git://sbcl.boinkor.net/clisp. If you want to browse the commits, tags and branches, you can get a gitweb summary (with rss!) here.

Of course, tips I posted about the git-ified SBCL on this blog before (like the one about finding bugs by using git bisect) apply to the git-ified CLISP as well!

Three useful .emacs hacks for lispers

I gave in and updated my lisp hacking-related emacs configuration today. These three snippets make my life easier now:

  • Turning off the “unsafe local variable” warning for common lisp source files. Several packages use the -*- convention to set the major mode; some also set variables like Package, Base and Syntax. Emacs 22 doesn’t know that they’re harmless and prompts almost every time I open a new lisp file. Ugh. Use this:

    (put 'package 'safe-local-variable 'symbolp)
    (put 'Package 'safe-local-variable 'symbolp)
    (put 'syntax 'safe-local-variable 'symbolp)
    (put 'Syntax 'safe-local-variable 'symbolp)
    (put 'Base 'safe-local-variable 'integerp)
    (put 'base 'safe-local-variable 'integerp)
    

    and remove all those unnecessary safe-local-variable-values customizations.

  • Wrapping the current defun in (eval-when (:compile-toplevel :load-toplevel :execute) …): I always misspell at least one of the keywords, so I bound C-c e to wrap the current defun (or the current + prefix-arg - 1 next defuns) in an eval-when:

    (defun asf-eval-whenify (&optional n)
      (interactive "*p")
      (save-excursion
        (if (and (boundp 'slime-repl-input-start-mark)
                 slime-repl-input-start-mark)
            (slime-repl-beginning-of-defun)
            (beginning-of-defun))
        (paredit-wrap-sexp n)
        (insert "eval-when (:compile-toplevel :load-toplevel :execute)\n")
        (slime-reindent-defun)))
    (define-key lisp-mode-map [(control c) ?e] 'asf-eval-whenify)
    

    (this requires both Slime and Paredit)

  • Fixing Command-left in Aquamacs: A-left (a.k.a. Command-left) goes to the beginning of the line. This is useful (and consistent with OS X) everywhere but in slime REPL mode. Unfortunately, shadowing the binding in the repl mode map isn’t possible, as macosx-mode-map’s A-left overrules that of the slime repl mode. Here’s a piece of advice to work around that:

    (when (fboundp 'beginning-of-visual-line)
      (defadvice beginning-of-visual-line (around slime-repl-bol first () activate)
        (if (eq major-mode 'slime-repl-mode)
            (call-interactively 'slime-repl-bol)
            ad-do-it)))
    

    Update: In Aquamacs 1.0b, you have to use:

    (when (fboundp 'visual-line-down)
      (defadvice beginning-of-line (around slime-repl-bol first () activate)
        (if (eq major-mode 'slime-repl-mode)
            (call-interactively 'slime-repl-bol)
            ad-do-it)))
    

Some UI improvements to boinkmarks

I’ve spent the last few hours adding a bit of javascript/araneida magick to the boinkmarks web interface. If you have javascript enabled, and your browser is supported by dojo, it’s possible to select the hosts, implementations, releases that you want in a matter of seconds (and not in 2-3 minutes). Yay!

Also, that taught me some useful lessons:

  • I’m not cut out for web development. Seriously, ew.
  • Parenscript is nice. But then you find out you can’t write something.innerHTML = ..., because there is no way for it to emit a variable name that consists only in part of capital letters — and javascript is case-sensitive! Argh! You can get innerHTML by using (in lisp) something.inner-h-t-m-l. (thanks to Marco Baringer and Ivan Toshov)

In other news, Postgresql = love. It’s really a joy to search for performance problems with it. The last one I weeded out was this:

When you join a small table to a big table in order to limit the number of resulting rows to ones matched in a big table, don’t use JOIN, use WHERE EXISTS.

For example, if you want smalltable’s foo column for rows that are related to those rows in bigtable that match bigtable.condition=’something’, don’t use

select smalltable.id, smalltable.foo from smalltable join bigtable on bigtable.id=smalltable.id where bigtable.condition = 'something'

, use:

select id, foo from smalltable where exists (select * from bigtable where bigtable.id = smalltable.id and bigtable.condition = 'something' limit 1).

(And don’t forget to keep an index on (bigtable.id, bigtable.condition)!) Rewriting sql statements like this (and using an index) gave the queries in the boinkmarks web app a speed boost of anything between 30x and 200x.

It’s still slow, but at least now I can’t do anything obvious about it anymore. (-:

CLISP boinkmarks available

Here’s the explanation of yesterday’s cryptic announcement:

Prompted by a late-night discussion on #lisp, I added build/benchmark support for CLISP to autobench. It’s currently churning away at early releases, but some numbers are already in.

Graphs are available for AMD64 in 32-bit mode and AMD64 in native mode.

When everything is working correctly, I’ll start benchmarking CVS commits as they trickle in (just like I do for SBCL). If any volunteers want to dedicate hard disk space (the git tree is 186 MB, plus 1.5MB for every revision in the build archive) and processing power (building one revision takes around 10 minutes, 3 benchmark runs take 27 minutes), that would be much appreciated. See the updated autobench setup guide for details; if you need more convincing, I have a flyer that highlights the advantages of running boinkmarks for you.

This will probably mean nothing to you...

…But to me, it spells “success”:

#<CLISP 2.41-2006-10-13-gea222e0>/(:ARCH :EMULATED-X86): Build:OK BM3:012

Results soon.

DREI Raises Engineer's Interest

Troels Henriksen has made available his modifications to McCLIM: He added an input editor (named “DREI”) that is based on climacs. The greater plan seems to be to make Climacs use that input editor for all its editing panes.

Apart from less code duplication and embeddability of a really nice emacs in every clim application that uses a text-editor gadget, this adds a few cool things to the input editing in current clim applications. This screen shot

A clim listener with an active DREI input editor

shows:

  • Lisp syntax highlighting,
  • (almost) correct indentation of forms, and
  • nicely formatted “noise” strings: (pathname).

Using git bisect to locate bugs in sbcl

I’ve announced the git repository a few weeks ago. Here’s something very nice you can do with it: Run a binary search on revisions to find out the version of SBCL that caused a bug. This helps enormously when searching for the cause of bugs.

You can use the CVS repository for this, too, but it doesn’t include any of the nice functions I mention in this tutorial; you need a start time and an end time, and do month/day/hour/minute calculations yourself. Git allows you to bisect based on changesets, and it includes a nice graphical representation of bisection progress.

Here’s how you do it:

  1. Make an automated test case that you can run from a script. This may seem optional, but it gets tiresome (and error-prone) if you test manually.

  2. Check out the sbcl tree: git clone git://sbcl.boinkor.net/sbcl

  3. Change to the directory, look at the revision log: git log

    The lines starting with “commit” contain sha-1 commit IDs. A few lines after that, you see the log summary containing the sbcl revision number.

  4. Find the version that you know is broken, and a version that you know works and copy their commit IDs. I’ll call the good version’s commit ID 6584a2c88efaa6931083721adae2f9f10e0fefd5 and the bad one’s commit ID 1de12891f900d156ed035a097561ecd7755a256a.

  5. start bisection search: git bisect start

  6. Now mark the good and bad revision:

    • git bisect good 6584a2c88efaa6931083721adae2f9f10e0fefd5
    • git bisect bad 1de12891f900d156ed035a097561ecd7755a256a

    This will give you output similar to:

    Bisecting:        9 revisions left to test after this
    [90a83478829f33b91f6300c183b374a968bc13c6] 0.9.18.20: correct step-frame logic on non-x86oids

    From now on, after every step, you can look at a first bisection history in gitk: git bisect visualize

  7. Start the actual bisection: git bisect next

    This gives you:

    Bisecting:        9 revisions left to test after this
    [90a83478829f33b91f6300c183b374a968bc13c6] 0.9.18.20: correct step-frame logic on non-x86oids
    $ cat version.lisp-expr
    [...]
    "0.9.18.20"
  8. Run the test script.

    • If it fails, use git bisect bad to mark the current revision as bad,
    • if it succeeds, use git bisect good to mark it as good.

    You’ll get something like:

    Bisecting:        5 revisions left to test after this
    [7bad074650949dc5427711b93ff615d9c17308d9] 0.9.18.25:

    As mentioned above, you can always view the bisection history using git bisect visualize.

  9. Repeat steps 7 and 8, until there are no more versions to bisect. After running the final test and marking the version with git bisect good or git bisect bad, You’ll get something like the following output:

    a30a3d82293eca3eb036ea0c713b0da31c0467dc is first bad commit
    commit a30a3d82293eca3eb036ea0c713b0da31c0467dc
    Author: Nikodemus Siivola <nikodemus@random-state.net>
    Date:   Thu Nov 2 15:11:25 2006 +0000
    0.9.18.27: fix darwin build
     [...]

And that’s it! You identified the broken revision. When reporting bugs to the sbcl mailing list, please include the version number (in the example above, that would be 0.9.18.27).

If you want to cancel or pause bisection at any time, you can use the following commands:

  • git bisect log > bisection-logfile # (optionally) save the current progress
  • git bisect reset # reset bisection to the revision where you started

To resume bisection from a log file, use git bisect replay bisection-logfile.

I hope this guide helps you identify bugs quickly. Good hunting!

McCLIM 0.9.3 "All Souls' Day" released!

We released McCLIM 0.9.3, code-named “All Souls’ Day” today. Most prominently, this release:

  • Plugs a horrible memory leak in incremental redisplay, along with a few optimizations.
  • Has a new backend, gtkairo (uses GTK for gadgets, and Cairo for rendering)
  • Includes lots and lots of bug fixes and new features.

The “haha, this is embarrassing” department mentions that my brain misfired while sending the release announcement. I wrote “All Saints’ Day” instead of “All Souls’ Day”. This is now corrected.

McCLIM frozen. Again.

Two days ago, I announced the freeze of the current code base of mcclim. All in all, that doesn’t sound like it’s much different from the previous freeze (which failed), but this time:

  • The freeze period is much shorter - projected release date is November 2nd;
  • Both the test status as well as the release notes are on the mcclim cliki, and visible to all.
  • I actually have the time and the energy to take care of these things.

I hope that this time, it will work out.

If you want to test mcclim before we release, feel free to report your results on IRC, on the test status page, or on the mcclim-devel mailing list.

Six-word stories about programming languages

This made me laugh:

COBOL: Without me there wouldn’t be PCs.

FORTRAN: Without me there wouldn’t be H-Bombs.

Oh, and the lisp story in Pupeno’s comment is way better than the one in the original article.

SBCL cvs->arch service turned off: use git.

As mentioned on the sbcl-devel mailing list, I have turned off syncing between the SBCL CVS repository and the SBCL Arch archive.

The arch archive is still reachable, it just won’t show any new patches in future. If you would like to volunteer to continue the repository syncing service for the cvs->arch, I’ll happily turn over my hacked tla and cscvs source trees, database, and conversion scripts.

If you still used the Arch archive and would like to continue using a patchset-ified full history of the SBCL repository, I suggest you try out the SBCL git repository (get it via git clone git://sbcl.boinkor.net/sbcl.git/). It’s both faster and more functional than the arch archive, and has conversion tools that work really well.

Update: the git repository url was wrong. Please use git://sbcl.boinkor.net/sbcl.git/ or http://sbcl.boinkor.net/git/sbcl-beta.git/ if you tried to download from the old url before.

How I found free time and what I did to it when I found it

Busy busy! (This post contains references to at least three things related to lisp, so into this category it goes)

It’s been several months since the last post. Since then, I was in Hamburg, St. Petersburg, and Helsinki. I hacked on a few lisp projects (an asdf dependency groveller of which I’m proud, and a new cl pathname system of which I’m planning to be proud), and rotated jobs. I am a consultant in lispy things now. Yay! That doesn’t mean I get to hack only on lisp code, though.

Read two or three dozen books. Highlights: lots of stuff by Charles Stross, The Lost Cosmonaut and Warren Ellis’s Fell (issue one available for free here). Promised a mcclim release and promptly missed the deadline. Got a Mac. Am now installing grml in Parallels on it. Went to a funeral and missed a wedding. Am enthusiastic about metalab. Read lots of irrelevant stuff on the internet (like the entry you’re reading now).

Promise less disinformation density soon.

McCLIM 0.9.2 out-of-the-box demo application available

Following Christophe’s suggestion, I have put up a binary of McCLIM 0.9.2, its demos, and the Inspector, Debugger and Listener applications.

As stated on the mailing list, it’s based on a threaded SBCL 0.9.11 and requires Linux 2.6.x on an i386 machine. If you are on debian, it needs libfreetype6-dev installed, as well.

Get it at http://boinkor.net/lisp/mcclim-listener-0.9.2.tar.bz2.

To try out McCLIM’s applications, download the file (14MB), unpack it, and run the mcclim-listener-0.9.2/mcclim binary. It doesn’t get much easier than that. (:

Some fun things to try:

on the Listener prompt, enter

    (/ 1 0)  ; to open the clim debugger

or activate the menu item “Demos -> Plot Fishes using Functional Geometry” to see a nice “Escher” style plot.

McCLIM 0.9.2 released

McCLIM 0.9.2 was released today, just in (CEST) time to be called Laetare Sunday. (-:

Lots and lots of things are new and cool in this release. See the release notes for details.

Kudos go to the whole McCLIM crowd for making this release happen!

MUCH MORE BEIRC

While several others are busy porting sbcl to platforms that God itself hates, I’ve been hacking on something much more trivial, but much more fun (and rewarding, in the short term): beirc.

Some recent changes:

  • Multi-server support! You can now be connected to more than one server at the same time, and be in many channels (with the same names, even) on every one of them, all in one beirc instance.
  • Query renaming: If a user changes his or her nick, and you have a query window open, that query window will be renamed and messages to that user will go to their new nickname. Note: due limitations in the irc protocol, this will only work if you are in at least one common channel with that user.
  • Keyboard shortcuts to switch tabs: ctrl-pgdown/ctrl-pgup switch to the next/previous tab and ctrl-tab and ctrl-shift-tab switch to the next/previous unread tab with unread content.
  • Better Tab highlighting: Tabs now highlight only if there is genuinely interesting content (messages, operator actions or messages mentioning you) happening in the window while you’re not watching.
  • Generally Better Code (I think), which can deal with more of the stuff that cl-irc throws at it.

So, I think you definitely should have a look at beirc. Outside of work (where I have to use irssi in a screen instance), I use it exclusively now. It really is that good. I’m an IRC addict, you can trust me. (-:

Starting daemonized lisp images in debian

On baker, I’m running two lisp images: autobench’s web interface, and a chavatar instance for my girlfriend who is currently in St. Petersburg.

Starting these lisp images manually using detachtty is somewhat tedious, so I wrote/modified two scripts to aid me with starting/attaching to/starting swank in/stopping these images. lisp-images is an init.d script that starts one or all lisp images that are defined in /etc/lisp-start.d/ and the other, start-stop-lisp-image does the actual work. Note that they need start-stop-daemon to work; I’ve tested them on debian, and I’m not sure about availability of start-stop-daemon on other distributions, so you may need a debian-based distribution to run them.

To install the scripts, put start-stop-lisp-image into /usr/local/sbin and lisp-images into /etc/init.d, with appropriate permissions.

Also, you need a patched detachtty. Marco Baringer’s patch for the —eval option is on the detachtty bug page. apt-get source detachtty, patch, fakeroot debian/rules binary and dpkg -i ../detachtty*.deb was all I had to do on my machine.

Defining a lisp image to run is pretty easy: You drop a file into /etc/lisp-start.d/ that is sourced by the lisp image control shell script.

A typical lisp image definition (for my chavatar instance) looks like this:

# The user to whom to switch before running the lisp image
RUN_AS="asf"

# these paths must be absolute:
# Base directory; we chdir to it before running the lisp
ABROOT="/home/asf/dl/svn/chavatar"
# Directory where detachtty places its pipe and pid file
VARROOT=$ABROOT/+var
# Directory where detachtty dribble output goes
LOGROOT=$ABROOT/+log

# The command that we use to run the lisp.
LISP_LOAD="/home/asf/bin/sbcl --noinform --userinit $ABROOT/+web-userinit.lisp"

# The port where we start swank on demand.
SWANKPORT=4008

Give it a descriptive name, and you’re ready to roll. run /etc/init.d/lisp-images start image-name and you should see:

Starting Lisp images: image-name.

To attach to the lisp, run /etc/init.d/lisp-images attach image-name.

Init.d operation is easy, too: /etc/init.d/lisp-images operates on all lisp images, if no images are given on the command line. This means that you can create symlinks in /etc/rc*.d/ and the images will be automatically started on startup and stopped on shutdown.

If you want more information on how to use this setup, once it’s working, see Bill Clementson’s summary of nice things to do with lisp webapps.

Credits for these scripts go to Marco Baringer who wrote the attachtty patch and the original ucwctl, from which most of start-stop-lisp-image’s meat is copied; and to Helmut Eller, not only for the awesome SLIME, but also for figuring out that sbcl in detachtty has no *debug-io*, which prevented the scripts’ swank functionality from working.

What's so sexy about boinkmarks?

Xach on #lisp asked me why people would want to run autobench to repeatedly build & benchmark sbcl. That’s a good question, and I think I found a few answers:

  • It gives you a build archive of previously built SBCL implementations, which you can use to run historical regression tests on. This is pretty nice to have: Autobench works using changesets, so you can often pinpoint exactly between which changes a feature that you want to use broke. I have been thinking about automating this process: pass it a test, and two revisions between which you suspect the test broke and it’ll run the test for every revision in between.
  • Autobench doesn’t exclusively work when benchmarking sbcl. While it was developed specifically for sbcl, it’s pretty easy to extend it to autobuild/benchmark your favourite lisp implementation. An incomplete port to CMUCL (no autobuilding) is already done. CLisp and ABCL would be interesting targets, as they’re easy to build automatically, and they’re not based on python.
  • It gives you a chance to see how well your lisp/os/machine performs relative to mine (baker is an amd64 running linux) (:
  • You don’t want to have your sexy new machine (maybe even a rare architecture running a strange OS) sit around with a 0.x system load while it could do something useful instead.

SBCL autobenching (a.k.a. "boinkmarking") HOWTO

Finally! A life sign! And it’s a lisp post, too!

I’ve been promising to do this for a long time now. So, without further ado, here’s the

Setting up an SBCL benchmark host HOWTO

You, too, can run regular SBCL benchmarks (a.k.a boinkmarks) with the “Autobench” software package. It’s similar in spirit to buildbot, but it is focused at benchmarking cl implementations, so the abstractions are a bit different.

Getting the software

Autobench requires a recent SBCL release. I’ve built and tested it with 0.9.8. It also requires git and cogito.

Also, it requires a strong cpu, lots of diskspace for the build archive (around 8.7 GB if you build & benchmark all sbcl 0.8 and 0.9 revisions), and a good stomach that doesn’t hurt when you run into one of my stupid bugs.

If you have all that,

  • Get&install the latest git distribution. Any build (I tested debian packages and macports) should work fine.

  • Get the sources and link them to your ~/.sbcl/systems/:

    • $ cg clone http://sbcl.boinkor.net/git/boinkmarks.git/ autobench
    • $ ln -sf $(pwd)/autobench/lisp/autobench.asd ~/.sbcl/systems/
  • Get its dependencies:

Great! You’re almost ready to go. If you try loading the autobench system with asdf now, it will give you an error message telling you to customize your ~/.autobench.lisp file. And that’s just what we’re going to do now.

Customizing ~/.autobench.lisp for your machine

As I mentioned, we’re going to create an .autobench.lisp file now. Here’s a sample customisation file for an x86-64 machine:

 ;;; SIMPLE (important) CUSTOMIZABLE VARIABLES.
 ;; The directory where you checked out the autobench source.
 (setf *base-dir* #p"/home/sbcl-arch/autobench/")


 ;;; BUILD STRATEGIES
 (defstrategy +sbcl-64+ sbcl (:mode (:arch :x86_64 :features ())))
 (defstrategy +sbcl-32+ sbcl (:mode (:arch :emulated-x86 :features ())))

 (defstrategy +sbcl-64-threaded+ sbcl (:mode (:arch :x86_64 :features (:sb-thread)))
              :build-p (every-nth-revision 4))
 (defstrategy +sbcl-32-threaded+ sbcl (:mode (:arch :emulated-x86 :features (:sb-thread)))
              :build-p (every-nth-revision 4))


 ;;; implementations that should be automatically built. supports only sbcl right now.
 (setq *implementations-to-build* `((sbcl :directory #p"/home/sbcl-arch/space/autobench/+newest-64/"
                                          :strategies (,+sbcl-32+ ,+sbcl-32-threaded+
                                          ,+sbcl-64+ ,+sbcl-64-threaded+))))


 ;;; POSTGRES DB SSH TUNNEL VARIABLES
 ;; The function used to ensure the database connection can be established.
 ;; This is different from actually establishing the db connection:
 ;; Think of it as a cheap :before method/hook (:
 (setf *db-connection-setup-function* #'ensure-ssh-tunnel-connected)

 ;; The user name to use for connections to the data base.
 (setf *db-default-user-name* "test-db-user")

 ;; The default port for ssh forwards is 5096.
 ;; Uncomment if this port is in use on your autobuild machine.
 ;; (setf *ssh-port* 5096)

 ;; The user name to use for the ssh connection that establishes the tunnel
 ;; to the boinkmarks DB host.
 (setf *ssh-remote-username* *db-default-user-name*) ; typically the same. customize if they're not.

While this may look like a lot at first reading, it’s nothing compared to, say, sendmail.cf (-:

The one really important variable is *base-dir*. if you fail to set it correctly, autobench will autobelch directories left and right. Try the pathname with probe-file first. (:

I’ll cover the build strategies in the next section, and the postgres DB ssh tunnel variables in the one titled “connecting to the boinkmarks db”.

Build Strategies

The things that control how SBCL is built are called build strategies. They’re defined via defstrategy like so:

 (defstrategy +strategy-name+ implementation-name
              (;; initargs, for example:
               :mode (:arch architecture :features (:sb-thread))
              [:build-p build-p])

This defines a variable bound to a strategy object, which you can then use on implementations-to-build.

Valid names for implementation-name (which isn’t evaluated, btw) are SBCL only at the moment.

The :mode init argument is pretty interesting. Let’s have a closer look at it. Architecture says which arch to build for. SBCL needs a bit of hand-holding to build in the x86 emulation on amd64 machines. See sbcl.lisp, build-in-directory/arch methods for details. Features are the features that should be put into customize-target-features.lisp during the build process.

Finally, build-p is a function that is called with a version number and returns t or nil, indicating that the release should be built and benchmarked or not. The function (every-nth-release n) returns a test function that returns T for every sbcl release and for every n-th cvs version of SBCL.

Note that you shouldn’t change the strategies, once you ran builds and benchmarks with them, and imported the results into a database.

Connecting to the Boinkmarks DB

You do that by sending me a signed e-mail stating:

  • Your desired username

  • An SSH public key (the private key should have no password and should be installed in the autobenching user’s home directory)

  • The output of (machine-instance) and (machine-type), when run on an SBCL 0.9.8 (or later) prompt.

  • The DEFSTRATEGY forms in your ~/.autobench.lisp (alternatively, you state that you don’t know what you should put there and then we can discuss them (-:)

When you sent me all that, I’ll create your account. (For ssh tunnels only. No shells from me. If you want one, ask the cl.net or tech.coop guys.) Also, I’ll perform the required foreign keys voodoo with your build strategies so that you can import the build results.

When I’ve created your account, I’ll send you an acknowledgement, and you can start…

Auto-Building SBCL

The SBCL autobuilder uses the sbcl git repository as a changeset source. Good thing you got git in the previous steps, right?

  • check out (e.g. the first sbcl 0.9.0 revision):

    • $ git clone http://sbcl.boinkor.net/git/sbcl-beta.git /wherever/sbcl
    • $ cd /wherever/sbcl && cg seek sbcl.0.9.0
  • Use /wherever/sbcl/ as the directory on implementations-to-build in your ~/.autobench.lisp.

  • Try to build a few revisions on the command line:

    • $ /autobench-base-dir/scripts/cron-run-benchmarks
    • Hit ctrl-c if it works. If not, see /autobench-base-dir/+log/ for logs of every command that failed (i.e. returned non-0 exit status).
  • Set up a cron job to execute base-dir“/scripts/cron-run-benchmarks” every day on 0:00:

    • $ crontab -e
    • add the line @daily wherever/scripts/cron-run-benchmarks

You’re done! Now you can watch your build archive grow and (hopefully) pretty graphs on http://sbcl-test.boinkor.net/bench/!

UPDATE: The arch archive is defunct; this guide now uses the git repository.

SBCL in Git

(If you were redirected here while looking for SBCL in Arch, my apologies. It has been turned off.)

This page describes the current state of the SBCL Git repository.

There is a gitweb presentation of the repostitory here: gitweb for SBCL.

You can clone a full copy of the SBCL repository with this command line: git clone git://git.boinkor.net/sbcl

Administrative details

The repository is synchronized with upstream CVS through the Sourceforge rsync service. This means that commit propagation will be delayed by up to ~1 hour. The archive contains all commits on all branches in SBCL’s past. A partially unpacked repository is 68MB in size. Typically, cloned repositories will be 47 or so MB in size.

Some useful commands

  • To create a branch (off the current branch’s head revision) to which you can commit, use git branch your-branch-name HEAD
  • To update your tree, use git pull
  • To commit to your repository, use git commit

All the git commands have a switch —help.

Steel Bank Common Lisp

The host on which this web site is running also provides a few services for the community of SBCL developers and users:

More hacking on beirc

There was a lot of progress in the development of Beirc since my last entry. We (splittist, mgr and I) fixed the three most annoying things so far:

  • You no longer have to hit the “/” key to be able to click on presentations. It’s funny how before, everybody said that they don’t mind hitting “/” before reaching for the mouse; but now, I don’t think anybody would want to go back.
  • Hitting RET in the middle of a line doesn’t land you in the debugger, and
  • Tab completion now works.

Then, there are dozens of little things that we improved (better message display, useful customizations and defaults, timestamps in columns, more presentations and more clickable things). And of course, there’s mgr’s wonderful new tab-layout-pane code (lisp porn here).

So, beirc is rapidly becoming an IRC client that I really enjoy using (and, of course, hacking on). Join in the fun on #beirc!

Hacking on beirc

I’ve spent some time lately hacking on beirc, the McCLIM-optimized CLIM IRC client by Gilbert Baumann. The version you find in the CVS repository at common-lisp.net comes with a neat channel selector that may remind you of xchat. Channels are shown red if there was activity on the channel that you didn’t see yet and blue if there were messages on the channel that contained your nickname.

You can see it in action in this screenshot.

I really like how easy CLIM makes adding new features like this channel selector. The code for the actual selector, including the activity indicator is only a few tens of lines. (the new channel selection mechanism I had to implement is a bit more than that, but that’s GUI toolkit independent)

More Amsterdam

Time to write up how I experienced the Amsterdam Lisp meeting. Summary: had a great time. The combination of gorgeous weather, lots of interesting people, good food, and lisp content might have helped there, I guess.

  • Friday was weird. Airports, planes, trains and a hotel that, despite having confirmed my reservation for a room, had to relocate me to another hotel because they were full. After the initial shock of suddenly having a 1/2 hour’s commute to the city center, I spent some time wandering around there and meeting up with a few people (Juho, Antonio Martinez, Tim Daly Jr. and quite a few others) in a cute cafe that happens to serve belgian beer. I had to go back to my room and fall into bed way too early, though. (Hours before midnight!)

  • On Saturday, I met up with a few of last night’s lispers to visit the Heineken Museum. That exhibitions reminded me a bit of Duff Gardens, except that it was indoors and lacked the quality of being an intentional parody. Did you know that Heineken engineers once tried to make a brick-shaped beer bottle, so that it could be used as a building block for houses in development countries? Turns out that in the countries they targeted, the sun is so hot that you can’t live in a house made of glass. Their beer trivia terminals tell you that.

    Later, we went to the Van Gogh Museum and looked at the Egon Schiele (gallery) exhibition there (as well as a few pictures by Van Gogh in the main exhibition hall). After that, fetched my digicam and walked from Stadhouderskade to the Kantjil & de Tijger, photographing everything that caught my eye. Had great dinner there (the entire table was covered by plates full of extremely tasty food!) and then went to Robert Strandh’s (and others’, in fact) Hotel to talk about CLIM stuff in the hotel bar. There we heard what I think is the best explanation of incremental redisplay yet. Physical presence of people who understand a concept really helps. (-:

  • Sunday was Lispmeet day. I had thought that the people I had seen at saturday’s dinner were the most lispers I had ever met. Imagine my surprise when I wandered into the meeting room. Here’s a list of the most important notes I took during the talks:

    • During the LispWorks talk, I had a few ideas for a CLIM frontend to ASDF defsystems. The first of these ideas is ripping off Lispworks’ defsystem browser. (-:
    • The SLIME talk made me realize (again) how few functions I use in slime. M-x slime-edit-variable and the package apropos function are way cool. Must practice using them.
    • For the sake of our children, I will continue to pronounce climacs as “klee-macs”.
    • Had lunch at a small place called “Lust” with Robert, Kathleen and David Lichteblau. They serve pretty good food and mint tea with real mint. I can’t remember the street name, though. Might have been Runstraat (first crossroad south of the Felix Meritis). Recommended if you’re in Amsterdam. Update (and note to self): Turns out it is Rumstraat. They have a web site, too.
    • I was very impressed by the Linj talk held by Antonio Menezes Leitao. A friend said that compiling a subset of idiomatic lisp to human-readable idiomatic java only makes sense in a world that is very weird already. It is, and so I’m very happy that this project is around to save me from writing java the next time I would normally have to. (-:
    • I won one of the 19 (18?) Practical Common Lisp books that Peter Seibel brought to Amsterdam and signed there! Spent the entire monday afternoon (well, the parts of the afternoon that I didn’t spend sleeping) blissfully reading it.
  • Monday was planes and airports again and reading PCL, interrupted by irregular sleeping.

So, yours truly had a very fine weekend just like all the other europlanet.lispers. The only thing I missed was more time to talk to all the extremely interesting people that I met there. I do hope there is going to be another lisp meeting next year! (-:

An interactive Lisp tutorial

I just rediscovered a pretty good Lisp tutorial - ELM-ART (german version, english version). My first contact was sometime early in 2003, when somebody else (could have been Rainer Joswig) gave me the link and I tried it out.

The whole tutorial is very well presented, and it includes exercises which you can solve interactively. The system also gives you feedback on errors in your code.

I found the whole ELM-ART (Episodic Learner Model / Adaptive Remote Tutor) concept pretty interesting, and found that the Uni Trier’s ELM group published a few papers on it. In case you’re interested, here are links to the papers that I could dig up:

  • 1996: “ELM-ART: An Intelligent Tutoring System on World Wide Web” (html)
  • 2001: “ELM-ART: An Adaptive Versatile System for Web-based Instruction” (pdf html)

Anyway. Don’t mind the underlying technology. It’s a pretty good low-level tutorial. Still, for a more extensive treatment of Common Lisp, you should get Peter Seibel’s Practical Common Lisp or Peter Norvig’s PAIP.

New boinkmarks feature: syndication

I just finished hacking up a new feature to boinkmarks. It now has an atom feed that reports significant changes (that is, more than 2s) in SBCL benchmarks. It should be on planet.sbcl.org soon. If you want to watch SBCL performance yourself, subscribe to http://sbcl.boinkor.net/bench/atom/ with your favorite RSS/Atom feed reader.

McCLIM 0.9.1 - Mothering Sunday released!

McCLIM 0.9.1 was released today. I have hopes that the next (time-boxed) releases will work as well as this one.

That means it is time for you, dear reader/hacker, to write neat McCLIM-using applications. Making one that does useful things is really easy.

Kevin Rosenberg is orphaning 100 Debian Common Lisp packages

Kevin Rosenberg is putting 100 debian packages up for adoption. That means that, among other packages, these are now without an official debian maintainer:

  • cl-asdf
  • cl-interpol
  • cl-irc
  • cl-pdf
  • cl-ppcre
  • langband
  • sbcl

You can get a full list of packages in his weblog entry. If you are a debian maintainer or you plan on becoming one, there’s a lot of (high-quality, and high-profile) stuff available for you to take on.

50!

I’m registered for the Amsterdam Lisp Meeting . You should come, too.

Autobench released at last

At last I managed to release Autobench, the incremental benchmark runner that powers http://sbcl.boinkor.net/bench/. Get it at http://boinkor.net/lisp/autobench/autobench-0.4.tar.gz. This version includes support for benchmarking CMUCL and SBCL. The README should tell you most of what you need to know.

By the way, it’s nice to know that the protocol I mentioned in the 2004-11-22 entry is sustainable. The implementation of the benchmark protocol for cmucl snapshots is about 90 lines of lisp code (which unfortunately is pretty ugly, due to some suboptimalities in cmucl snapshot packages).

Now somebody really should add support for CLisp. Hey look, it’s open source. (-;

Incremental-developmentification of McCLIM

Upgrading McCLIM (or even hacking on it) is hard work for your computer. That’s due to the use of :serial t in the system definition that manages to be compatible to ASDF (which has an idea of “real” dependencies) and other defsystems (for example, MK:DEFSYSTEM and the ones in LispWorks and Allegro CL) because of this.

So whenever you update a file, your defsystem must recompile all the files that are listed after it in the McCLIM system definition. This can result in 20 files that need to be recompiled for changes to a file that only 6 files actually depend on.

This has resulted in lots of gnashing of teeth from people who want to spend their time hacking cool stuff with McCLIM, and less time waiting for it to finish compiling.

(Here’s the bragging part. Skip below for actual code.) So I sat down and wrote a bit of awful code, which essentially does this:

  • Find out which “interesting” symbols a defsystem’s components use
  • Find out which components use which symbols (establishing file->symbols and symbol->files mappings)
  • Order the components according to the existing :serial definition and use the first component for group of files as the dependency target for the others.

This (and the symbol finder, which really wants to be an XREF thing) is a bit conservative, in that it generates dependencies when in doubt - if a file uses CLIMI::Q and another file uses CLIMI::Q as a temporary variable, the code emits a dependency. But then, the resulting system definition works as good as the original mcclim/system.lisp file worked for me.

(Skip to this point to escape the bragging part.) You can get the ASDF system definition that i tested from lisppaste, at. Just replace mcclim’s system.lisp file with it and load the components as you normally would. I would like to hear from you if it works or breaks for you. Tell me at #lisp / irc.freenode.net. I’m “antifuchs”.

Things to test:

  • Building “from scratch”: remove all .fasl files and rebuild with the new system definition in place
  • reloading a system after files have changed: touch random .lisp files and (asdf:oos 'asdf:load-op :clim) ; for example

Security considerations when using Lisp features

Today, Kevin Rosenberg asked on IRC how to prevent code insertion when READing data from a string. A solution to that problem is binding *READ-EVAL* to NIL in code using READ.

Now, that got me wondering: which other security pitfalls are there in lisp? These are the other READ-related ones that came up in the discussion that followed:

  • READ can intern symbols in packages other than the one you want it to (could lead to bugs further down in the application)

  • READ (again) can produce self-referential objects (via #n=) that can make your application go into endless loops/recursion

  • And of course, EVALing code that you get from the outside world is always a bad idea. As is writing it to a file and using COMPILE/LOAD.

So, any others? I’m sure there are. Having them collected in a central place would be a really good thing. Improved awareness of security problems might help prevent stuff like this bug in an intrusion detection system that did not set *READ-EVAL*.

Yet another benchmark entry

A few months ago, Christophe suggested that autobuilding/autobenchmarking of CLisp would be nice to have in Boinkmarks. I tried, but couldn’t make it fit into the ugly bunch of shell scripts. This was when I decided to rewrite them in Common Lisp, and to add a nice web interface using araneida.

That is now finished. See the results at [[http://sbcl.boinkor.net/benchmark/]] old version, for contrast].

So, was it worth it? The rewrite doesn’t bring me that much closer to my goal of actually benchmarking CLisp; but adding that functionality is now much easier with the new CLOS-based protocol for building/caching/benchmarking implementation binaries (especially when compared to these ugly shell constructs). Another great advantage is that I now have a chance of understanding what I have written when I have to fix it in a few months.

Watch this space, there are a few benchmarking-related announcements waiting to be made in the near future (the release of the benchmarking tool, for one) (-:

Yay Open Source!

My workplace just gave me permission to open-source two projects I did for them. One is screen-scraper, a rudimentary (but extensible) vt100 terminal emulator for lisp (BSD licence, sans advertising). The other is debian-security-updates, a netsaint/nagios plugin and debian security update SNMP agent adaptor (GPL).

Wow. Lots of nouns in that last sentence.

Last update using muse, probably

Lisp content first: I added a few features to the SBCL auto-benchmarker: When it encounters compile errors in the last revision, it sends an irritating mail to sbcl-devel (currently, to me, so that I can test and extend the auto-irritation levels a bit more).

Right. And now for some real-world stuff. There is now a Picture album online, which is semi-automatically updated from my digicam. Included are a few shots of our mouldy toilet. Apparently, our neighbor’s toilet’s water pipe broke. 5. weeks. ago. We noticed the mould last wednesday. You can see the result in The “schimmel” section of the album. I wonder whose fault it was that repairing the broken pipe took so long. Anyway, As soon as we called the property manager (to whom the toilet belongs - for various reasons), they sent a plumber over who fixed it; of course, there is still the slightly mouldy wall to be fixed. Ah well, some people had better not pass me by in the next few days, lest they risk hearing my opinion, which might not please them very much.

In other news, this is probably the last update to this journal with Muse; I think I’ll switch to Chandler’s neat blogging engine.

Hi from Bordeaux

Greetings from room TD11 at ENSERB at Bordeaux University. currently discussing possible buffer abstractions for a properly protocolized cl-emacs. More details later (and pictures, I forgot my camera in my hotel room today).

SBCL manual now auto-built

See The SBCL pages (you might also notice the link in the top navigation bar). The Benchmark runner needs to automatically build every SBCL revision, anyway. It could build the manual, as well. And so it does.

CL tutorial google juicification

A google search for Lisp tutorials often doesn’t yield a useful result for a newbie: Lots of Tutorials from the late 90s and 80s. Most call it “LISP” (in capitals), and refer to “the interpreter”. This does not reflect reality any more. Here are some more useful introductions to Common Lisp:

Hope this helps direct the google juice into more modern channels.

New Iterate release

I released a new version of iterate today. It fixes a bug in synonym code, removes spurious WARNINGs on perfectly good code, and adds a README (the same as the iterate page) and a BUGS file (find the current version on the iterate bugs page). Get it at http://boinkor.net/lisp/iterate/iterate-current.tar.gz. The signature is at http://boinkor.net/lisp/iterate/iterate-current.tar.gz.asc.

aliens are taking over SB-GROVEL!

I spent the last few months of my spare time hacking on SB-GROVEL, trying to port its structure types from the C-like simplicity (and simple-mindedness that comes with non-typechecked data) to SB-ALIEN. There are a few memory leaks in other contribs, now. (The previous SB-GROVEL used lisp objects that are garbage collected, the new one doesn’t. Choose your poison!)

I think it was worth the effort. Foreign Function definitions can now use the neat alien types, and don’t have to rely on (* t) types where they’d expect a structure. And application programmers now get usable alien objects back, without having to frob them through SB-INT::FOREIGN-ARRAY or whatever. Yay!