Allegro CL 9.0 and SMP: an introduction

Allegro CL 9.0 on Windows, Linux, and the Mac comes with a version which supports Symmetric Multiprocessing (SMP), which means that it can utilize more than one hardware processor at the same time. (On all supported platforms, a non-SMP version of Allegro CL 9.0 is also available.)

Using multiple processors means that programs can run significantly faster -- in theory almost as many times faster as there are processors (two processors, nearly twice as fast; eight processors, nearly eight times as fast) but in practice the actual speedups, while significant, are not so dramatic.

Here is an example where SMP will produce speed ups which come as close as can be to number-of-processors-times speedup: matrix multiplication. If you have two large matrices you wish to multiple together, divide the result matrix rows by the likely number of processors and spawn a process to calculate the values for those sets of rows. Because the input data is fixed, any process can read it safely -- there is no danger that another process is modifying the values. Because each process deals with specific result locations and values of one result location are unaffected by values in others, each process can store safely -- there is no danger that two processes will try to store in the same location simultaneously. And the result is there much sooner!

But in general, to use multiple processors, your program must ensure that instructions being executed on one processor do not interfere with instructions being executed on another. This can be difficult. Multiple processes within a single Lisp image have been supported for a long time in Allegro CL. But only one of these processes was running at any instant, and by telling the system not to switch processes, you could guarantee that code run by one process was not affected adversely by code run by another. (Thus you could wrap sensitive code with the without-interrupts macro, which would prevent process switching while its body was executed. without-interrupts does not work that way in an SMP image.)

Perhaps the most significant problem with SMP has to do with modifying stored values. Consider a program designed to record orders for goods, where each sales person is handled by a different process. There is a variable *order-number* and each salesperson, when starting to process an order, gets the order number by evaluating (incf *order-number*).

The instructions associated with incf are roughly:

Fetch the symbol value of *order-number*
Add 1 to that value
Store the new value as the symbol-value of *order-number*

It is clear that that code is dangerous when multiple processes are executing it. Suppose at the start the value of *order-number* is 12345, and two sales orders are started at the same time in different processes. Then we might get the following:

Salesperson 1                 Salesperson 2
Fetches the value 12345       Fetches the value 12345
Adds 1                        Adds 1
Stores 12346                  Stores 12346

We now have two orders numbered 12346. Note that this can occur even in a non-SMP Lisp using multiple processes. But in a non-SMP Lisp, such errors are in fact likely to be rare since each process that has code to run executes many thousands of instructions before it is switched out (fetch-add 1-store is generally less than 10 machine instructions, so the chance of a process switch breaking in is less tha 1/1000 if at least 10,000 instructions are run between process switches). Further, most programs will protect against interference by evaluating (without-interrupts (incf *order-number*)), which in a non-SMP Lisp guarantees that there will not be interference.

In an SMP Lisp, interference is neither unlikely nor protected by without-interrupts. (without-interrupts still exists but its use is deprecated. It still ensures interrupts are not processed while code is being run, but that says nothing in an SMP Lisp about what other processes are doing. It is only in a non-SMP Lisp that not handling interrupts also means other processes will not run.)

To handle situations like this, the SMP Lisp is provided with additional macros which ensure integrity of such code. The macro incf-atomic, for example, if used in place of incf, ensure that each process will see a unique value of *order-number* and no numbers will be missed (every value up to the current value will correspond to an actual order). incf-atomic is just one of many new operators defined for SMP. All are discussed in smp.htm, which is the main document discussing SMP.

Many situations are more complex and cannot be handled just with a specialized macro variant. These situations often require communication between processes, using locks, queues, and similar objects which can indicate whether it is safe to modify data (or whether data is in a consistent state and can be safely used). These are also discussed in smp.htm and we will be giving examples in future Tech Corner articles.

Copyright © 2023 Franz Inc., All Rights Reserved | Privacy Statement Twitter