[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5. Programming in STELLA


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.1 Hello World in STELLA

Included with the STELLA distribution is a simple Hello World application that shows you how to organize your own STELLA code and build a working STELLA application. The sources for the Hello World system consist of the following files:

 
sources/systems/hello-world-system.ste
sources/hello-world/file-a.ste
sources/hello-world/file-b.ste

STELLA organizes code modules with a simple system facility. Translation always operates on a complete system, so you always need to create a system definition for the STELLA files comprising your application (somewhat similar to what you would put in a Unix Makefile).

For the Hello World system the system definition already exists and resides in the file ‘sources/systems/hello-world-system.ste’. By default, STELLA looks in the directory ‘sources/systems’ to find the definition of a particular system. ‘hello-world-system.ste’ defines two things:

(1) The HELLO-WORLD module which defines a namespace for all objects in the Hello World systems. STELLA modules are mapped onto corresponding native namespace constructs, i.e., Lisp packages, C++ namespaces or Java packages. The exact mapping for each language can be defined via the keyword options :lisp-package, :cpp-package and :java-package in the module definition, for example:

 
(defmodule "HELLO-WORLD"
  :lisp-package "STELLA"
  :cpp-package "hello_world"
  :java-package "edu.isi.hello_world"
  :uses ("STELLA"))

The :uses directive tells STELLA from what other modules this one inherits.

(2) The actual system definitions defining what source files comprise the system, and what parent systems this one depends on, plus a variety of other options:

 
(defsystem HELLO-WORLD
  :directory "hello-world"
  :required-systems ("stella")
  :cardinal-module "HELLO-WORLD"
  :production-settings (1 0 3 3)
  :development-settings (3 2 3 3)
  :files ("file-a"
          "file-b"))

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.1.1 Hello World in Lisp

To generate a Lisp translation of Hello World you can use either the Lisp, C++ or Java version of STELLA. Before you can translate you have to make sure the following native directories exist:

 
native/lisp/hello-world/
bin/acl7.0/hello-world/

The directory ‘native/lisp/hello-world/’ will hold the Lisp translations of the corresponding STELLA source files. The directory ‘bin/acl7.0/hello-world/’ will hold the compiled Lisp files if you are using Allegro CL 7.0. If you are using a different Lisp, one of the other binary directories as defined in the top-level file ‘translations.lisp’ will be used. The directory ‘bin/lisp/hello-world/’ will be used as a fall-back if your version of Lisp is not yet handled in ‘translations.lisp’.

If you create your own system, you will need to create those directories by hand (future versions of STELLA might do that automatically). For the Hello World system these directories already exist.

To generate a Lisp translation of Hello World using Lisp startup a Lisp version of STELLA (see Lisp Installation). The following idiom will then translate the system into Lisp and also Lisp-compile and load it. The first argument to make-system is the name of the system, and the second argument indicates into what language it should be translated:

 
STELLA(3): (make-system "hello-world" :common-lisp)
Processing `/tmp/stella-3.1.0/sources/hello-world/file-a.ste':
*** Pass 1, generating objects...
Processing `/tmp/stella-3.1.0/sources/hello-world/file-b.ste':
*** Pass 1, generating objects...
   .........................................
;;; Writing fasl file
;;;   /tmp/stella-3.1.0/native/lisp/bin/acl7.0/hello-world/startup-system.fasl
;;; Fasl write complete
; Fast loading
;    /tmp/stella-3.1.0/native/lisp/bin/acl7.0/hello-world/startup-system.fasl
CL:T
STELLA(4): 

After the system is loaded you can call its main function:

 
STELLA(10): (main)
Hello World A
Hello World B
bye
()
STELLA(11): 

Using main in the Lisp version will not always make sense, since you can call any function directly at the Lisp top level, but both C++ and Java always need a main function as a top-level entry point.

While this would be somewhat unusual, you could also generate the Lisp translation using the C++ or Java version of STELLA. The easiest way to do that is to run the stella script in the STELLA directory like this:

 
% ./stella -e '(make-system "hello-world" :common-lisp)'
Running C++ version of STELLA...
Welcome to STELLA 3.4.0
Processing `sources/hello-world/file-a.ste':
*** Pass 1, generating objects...
Processing `sources/hello-world/file-b.ste':
*** Pass 1, generating objects...
  ...............................................
Translating `sources/hello-world/file-a.ste' to `Common Lisp'...
Writing `native/lisp/hello-world/file-a.lisp'...
Translating `sources/hello-world/startup-system.ste' to `Common Lisp'...
Writing `native/lisp/hello-world/startup-system.lisp'...

The -e command line option is used to evaluate an evaluable STELLA command. Conveniently, make-system is such a command, so you can supply a make-system form to the C++ or Java version of STELLA just as you would do in Lisp. Note the extra quotes around the expression to protect the characters from interpretation by the Unix shell.

To compile and load the translated Lisp files into Lisp you then have to startup a Lisp version of STELLA and call make-system again which now will only compile and load the necessary files, since the translations have already been generated in the previous step.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.1.2 Hello World in C++

To generate a C++ translation of Hello World you can use either the Lisp, C++ or Java version of STELLA. Before you can translate you have to make sure the following native directory exists:

 
native/cpp/hello-world/

The directory ‘native/cpp/hello-world/’ will hold the C++ translations of the corresponding STELLA source files. If you create your own system, you will need to create this directory by hand (future versions of STELLA might do that automatically). For the Hello World system the directory already exist.

To generate a C++ translation of Hello World using Lisp startup a Lisp version of STELLA (see Lisp Installation). The following idiom will then translate the system into C++. The first argument to make-system is the name of the system, and the second argument indicates into what language it should be translated:

 
STELLA(4): (make-system "hello-world" :cpp)
Processing `/tmp/stella-3.1.0/sources/hello-world/file-a.ste':
*** Pass 1, generating objects...
Processing `/tmp/stella-3.1.0/sources/hello-world/file-b.ste':
*** Pass 1, generating objects...
  ...............................................
Writing `/tmp/stella-3.1.0/native/cpp/hello-world/file-b.hh'...
Writing `/tmp/stella-3.1.0/native/cpp/hello-world/file-b.cc'...
Translating `/tmp/stella-3.1.0/sources/hello-world/startup-system.ste'.
Writing `/tmp/stella-3.1.0/native/cpp/hello-world/startup-system.hh'...
Writing `/tmp/stella-3.1.0/native/cpp/hello-world/startup-system.cc'...
:VOID
STELLA(5): 

Alternatively, you can generate the translation using the C++ or Java version of STELLA. The easiest way to do that is to run the stella script in the STELLA directory like this:

 
% ./stella -e '(make-system "hello-world" :cpp)'
Running C++ version of STELLA...
Welcome to STELLA 3.4.0
Processing `sources/hello-world/file-a.ste':
*** Pass 1, generating objects...
Processing `sources/hello-world/file-b.ste':
*** Pass 1, generating objects...
  ...............................................
Writing `native/cpp/hello-world/file-b.hh'...
Writing `native/cpp/hello-world/file-b.cc'...
Translating `sources/hello-world/startup-system.ste'.
Writing `native/cpp/hello-world/startup-system.hh'...
Writing `native/cpp/hello-world/startup-system.cc'...

The -e command line option is used to evaluate an evaluable STELLA command. Conveniently, make-system is such a command, so you can supply a make-system form to the C++ or Java version of STELLA just as you would do in Lisp. Note the extra quotes around the expression to protect the characters from interpretation by the Unix shell.

Different from Lisp, neither of the above idioms will compile and load the generated C++ code. Instead you have to use the Unix ‘make’ facility to compile and link the C++ sources. First change into the native ‘hello-world’ directory and then call make (important: the generated Makefiles currently require the GNU version of make):

 
% cd native/cpp/hello-world/
% make
g++ -w -g -O2  -DSTELLA_USE_GC -I../stella/cpp-lib/gc/include \ 
    -c -I.. main.cc
g++ -w -g -O2  -DSTELLA_USE_GC -I../stella/cpp-lib/gc/include \ 
    -c -I.. file-a.cc
g++ -w -g -O2  -DSTELLA_USE_GC -I../stella/cpp-lib/gc/include \ 
    -c -I.. file-b.cc
g++ -w -g -O2  -DSTELLA_USE_GC -I../stella/cpp-lib/gc/include \ 
    -c -I.. startup-system.cc
  ..................................
g++ -dynamic  -L../stella/cpp-lib/gc -Xlinker -rpath -Xlinker \
       '../lib:/tmp/stella-3.1.0/native/cpp/lib' \
       main.o -o hello-world \
       -L../lib -lhello-world -L../lib -lstella -lgc -lm

The first time around this will also compile the C++ version of STELLA and the C++ garbage collector and create a STELLA library file. Future builds of the Hello World and other systems will use the STELLA library file directly. To run the Hello World system simply run the ‘hello-world’ executable that was built in the previous step:

 
% ./hello-world
Hello World A
Hello World B
bye

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.1.3 Hello World in Java

To generate a Java translation of Hello World you can use either the Lisp, C++ or Java version of STELLA. Before you can translate you have to make sure the following native directory exists:

 
native/java/edu/isi/hello-world/

The directory ‘native/java/edu/isi/hello-world/’ will hold the Java translations of the corresponding STELLA source files. If you create your own system, you will need to create this directory by hand (future versions of STELLA might do that automatically). For the Hello World system the directory already exist.

Note that following Java convention we use the package edu.isi.hello_world to hold the Hello World system. This was specified via the :java-package option in the definition of the HELLO-WORLD module. Also note that we use hello_world instead of hello-world as the package name, since a dash cannot legally appear as part of a Java identifier.

To generate a Java translation of Hello World using Lisp startup a Lisp version of STELLA (see Lisp Installation). The following idiom will then translate the system into Java. The first argument to make-system is the name of the system, and the second argument indicates into what language it should be translated:

 
STELLA(5): (make-system "hello-world" :java)
Processing `/tmp/stella-3.1.0/sources/hello-world/file-a.ste':
*** Pass 1, generating objects...
   ..............................................
Writing `/tmp/stella-3.1.0/native/java/hello_world/Startup_Hello_...
:VOID
STELLA(6): 

Alternatively, you can generate the translation using the C++ or Java version of STELLA. The easiest way to do that is to run the stella script in the STELLA directory like this:

 
% ./stella -e '(make-system "hello-world" :java)'
Running C++ version of STELLA...
Welcome to STELLA 3.4.0
Processing `sources/hello-world/file-a.ste':
*** Pass 1, generating objects...
Processing `sources/hello-world/file-b.ste':
*** Pass 1, generating objects...
  ...............................................
Writing `native/java/edu/isi/hello_world/HelloWorld.java'...
Writing `native/java/edu/isi/hello_world/StartupFileA.java'...
Writing `native/java/edu/isi/hello_world/StartupFileB.java'...
Writing `native/java/edu/isi/hello_world/StartupHelloWorldSystem.java'...

The -e command line option is used to evaluate an evaluable STELLA command. Conveniently, make-system is such a command, so you can supply a make-system form to the C++ or Java version of STELLA just as you would do in Lisp. Note the extra quotes around the expression to protect the characters from interpretation by the Unix shell.

Different from Lisp, neither of the above idioms will compile and load the generated C++ code. Instead you have to use the Java compiler to compile and Java to run the compiled Java sources. First change into the top-level native Java directory ‘native/java’ and then compile and run the Hello World system like this:

 
% cd native/java/
% javac edu/isi/hello_world/*.java
% java edu.isi.hello_world.HelloWorld
Hello World A
Hello World B
bye

It is not necessary to Java-compile STELLA first, since STELLA already ships with a Java compilation of the STELLA system.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2 Incrementally Developing STELLA Code

The preferred method of STELLA code development is to use a Lisp-based version of STELLA for all the prototyping and testing, since that allows you to exploit most (or all) of the rapid-prototyping advantages of Lisp. Once a system has reached a certain point of stability, it can be translated into C++ or Java for delivery or to interface it with other C++ or Java code.

In the following, we assume an X/Emacs-based Lisp development environment such as the Allegro CL Emacs interface, where Lisp is run in an Emacs subprocess, and Lisp source can be compiled and evaluated directly from the source buffers. By "Lisp buffer" we mean the listener buffer in which Lisp is actually running, and by "source buffer" we mean a buffer that is used to edit a file that contains STELLA source.

Included in the distribution is the Hello World system comprised of the files

 
sources/systems/hello-world-system.ste
sources/hello-world/file-a.ste
sources/hello-world/file-b.ste

To get started, simply add your code to either ‘file-a.ste’ or ‘file-b.ste’, since all the necessary definitions and directories for these files are already set up properly. See section ??? on how to setup your own system.

Make sure the Hello World system is loaded into Lisp by doing the following:

 
(make-system "hello-world" :common-lisp)

This will make sure that the system definition is loaded and the necessary module definition is evaluated.

Now suppose you add the following function to ‘file-a.ste’:

 
(defun (factorial INTEGER) ((n INTEGER))
  (if (eql? n 0)
      (return 1)
    (return (* n (factorial (1- n))))))

There are various options for translating and evaluating this definition. For example, you can simply remake the complete system similar to what you would do for a C++ or Java program:

 
(make-system "hello-world" :common-lisp)

This will retranslate the modified files, recompile them and reload them into your Lisp image.

Instead of retranslating and recompiling everything, you can incrementally evaluate the definition of factorial from your Emacs-to-Lisp interface. Simply put your cursor somewhere inside the definition in the source buffer and evaluate it by typing M-C-x. This translates the STELLA code into Lisp and compiles (or evaluates) the resulting Lisp code. Now you can actually try it out in the Lisp buffer, for example:

 
STELLA(4): (factorial 6)
720

Finally, instead of evaluating the definition in the source buffer, you can also enter it directly at the Lisp prompt with the same effect.

The way this works is that the Lisp symbol stella::defun is actually bound to a Lisp macro that calls all the necessary translation machinery to convert the STELLA defun into Lisp code. Look at the file ‘sources/stella/cl-lib/stella-to-cl.ste’ for the complete set of such macros. This might be a bit confusing, since there are now three different bindings (or meanings) of defun:

  1. The STELLA operator defun used to define STELLA functions.
  2. The Lisp macro stella::defun that resides in the STELLA Lisp package and is only available for convenience in Lisp versions of STELLA.
  3. The Lisp macro CL:defun which is the standard Common Lisp macro used to define Lisp functions.

We’ll try to explicitly qualify which meaning is used wherever there might be some doubt which one is meant. In general, every unqualified symbol mentioned below is either part of the STELLA language or resides in the STELLA Lisp package.

Since a newly-written STELLA function might have errors, it is prudent to first only translate it without actually executing the result of the translation. In the source buffer you can do that by macro-expanding the defun. For example, if you use the Allegro CL interface you would position the cursor on the opening parenthesis of the defun and then type M-M. Any errors discovered by the STELLA translator are reported in the Lisp buffer window. The expansion will be a CL:progn that contains the translated definition as the first element plus various startup-time (initialization) code following it.

In the Lisp buffer you can achieve a similar effect with the lptrans macro. For example, executing

 
(lptrans
 (defun (factorial INTEGER) ((n INTEGER))
   (if (eql? n 0)
       (return 1)
     (return (* n (factorial (1- n)))))))

in the Lisp buffer first Lisp-translates the definition, and then prints the translation. To see the C++ translation you can use cpptrans, calling jptrans will generate the Java translation.

You can also use lptrans/cpptrans/jptrans to translate code fragments that are not top-level definitions such as defun and its friends. For example:

 
STELLA(8): (lptrans
            (foreach element in (list 1 2 3)
                do (print element EOL)))

(CL:LET* ((ELEMENT NULL)
          (ITER-003
           (%THE-CONS-LIST (LIST (WRAP-INTEGER 1) (WRAP-INTEGER 2)
                                 (WRAP-INTEGER 3)))))
  (CL:LOOP WHILE (CL:NOT (CL:EQ ITER-003 NIL)) DO
           (CL:PROGN (SETQ ELEMENT (%%VALUE ITER-003))
                     (SETQ ITER-003 (%%REST ITER-003)))
           (%%PRINT-STREAM (%NATIVE-STREAM STANDARD-OUTPUT) 
                           ELEMENT EOL)))
()
STELLA(9): (cpptrans
            (foreach element in (list 1 2 3)
                do (print element EOL)))
{ Object* element = NULL;
  Cons* iter004 = list(3, wrapInteger(1), wrapInteger(2),
                          wrapInteger(3))-> theConsList;

  while (!(iter004 == NIL)) {
    element = iter004->value;
    iter004 = iter004->rest;
    cout << element << endl;
  }
}
:VOID
STELLA(10): (jptrans
             (foreach element in (list 1 2 3)
                 do (print element EOL)))
{ Stella_Object element = null;
  Cons iter005 = Stella.list
                  (Stella_Object.cons
                    (IntegerWrapper.wrapInteger(1), 
                     Stella_Object.cons
                      (IntegerWrapper.wrapInteger(2), 
                       Stella_Object.cons
                        (IntegerWrapper.wrapInteger(3), 
                         Stella.NIL)))).theConsList;

  while (!(iter005 == Stella.NIL)) {
    {
      element = iter005.value;
      iter005 = iter005.rest;
    }
    java.lang.System.out.println(element);
  }
}
:VOID

The use of lptrans is really necessary here, since there is no Lisp macro foreach that knows how to translate STELLA foreach loops (those Lisp macros only exist for top-level definition commands such as defun). In order to translate such code fragments without error messages, they need to be self-contained, i.e., all referenced variables have to be either bound by a surrounding let, or they must be globally defined variables. Otherwise, the STELLA translator will generate various "undefined variable" error messages.

You can use the STELLA Lisp macro eval (i.e., stella::eval not CL:eval) to actually execute such a code fragment. For example:

 
STELLA(11): (eval
             (foreach element in (list 1 2 3)
                 do (print element EOL)))
|L|1
|L|2
|L|3
()

This translates the loop and executes the result, which prints the wrapped numbers (hence, the |L| prefix) to standard output. The () at the end is the resulting Lisp value returned by the loop (in Lisp everything returns a value, even though for STELLA foreach is a statement, not an expression).

Make it a habit to wrap eval around any STELLA code you incrementally evaluate in the Lips buffer. This makes sure that all the arguments to a function, etc., are translated into the appropriate STELLA objects. For example, evaluating

 
(eval (list :a :b :c))

in the Lisp buffer generates a STELLA list that points to the STELLA keywords :a, :b and :c. If you don’t use eval, for example,

 
(list :a :b :c)

a STELLA list containing the Lisp keywords ‘:a’, ‘:b’ and ‘:c’ will be created. Lisp keywords are a completely different data structure than STELLA keywords, and any STELLA code expecting a STELLA keyword but finding a Lisp keyword will break, since Lisp keywords are not a legal STELLA data structure. Unfortunately, such cases can be very confusing, since Lisp and STELLA keywords look/print exactly alike.

eval is also necessary to access STELLA symbols and surrogates in the Lisp buffer. For example, to access a STELLA symbol, you can use quote (again, this is the STELLA quote not CL:quote):

 
(eval (quote foo))

This returns the STELLA symbol foo. We explicitly used quote here, since code typed at the Lisp prompt is first passed through the Lisp reader before the STELLA translator sees it, and the default Lisp reader interprets the ' character differently than the STELLA reader. Within a STELLA file you can use the syntax 'foo, since it will be read directly by the STELLA reader that knows how to interpret it correctly.

lptrans, cpptrans and jptrans are evaluable STELLA commands that can also be evaluated by the C++ and Java version of STELLA. For example, to generate a Java translation of a little STELLA code fragment you could run the stella script in the STELLA directory like this (the output below has been additionally indented by hand for clarity):

 
% ./stella -e '(jptrans\
                 (foreach element in (list 1 2 3)\
                    do (print element EOL)))'
Running C++ version of STELLA...
Welcome to STELLA 3.4.0
{ Stella_Object element = null;
  Cons iter001 = Stella.list
                  (Stella_Object.cons
                    (IntegerWrapper.wrapInteger(1), 
                     Stella_Object.cons
                      (IntegerWrapper.wrapInteger(2), 
                       Stella_Object.cons
                        (IntegerWrapper.wrapInteger(3), 
                         Stella.NIL)))).theConsList;

  while (!(iter001 == Stella.NIL)) {
    {
      element = iter001.value;
      iter001 = iter001.rest;
    }
    java.lang.System.out.println(element);
  }
}

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.3 Performance Hints

Here are a few things to watch out for once you get serious about the performance of your translated STELLA programs:

Safety checks: The STELLA variable *safety* controls whether certain safety code is added to your translated STELLA program. For Lisp translations it also controls whether cast’s will be translated into run-time type checks or not. There is no run-time type checking performed in C++. In Java native casts will always perform runtime type tests. The default *safety* level is 3 which enables the translation of all safety clauses with level 3 or lower. A safety level of 1 or lower disables the generation of calls to the cast function in Lisp. cast performs run-time type checks which are somewhat expensive. However, you should not disable run-time type checking in Lisp until you have fully debugged your program. Once you are confident that your program works correctly, you can set *safety* to 0 before you translate it. That way you will avoid the generation and execution of any safety code at all. All of the core STELLA system was translated with *safety* set to 1.

Quoted cons trees: Access to quoted constants that are not symbols is somewhat slow, since it currently uses hashing to find them in a table. Hence, access to quoted constants such as (quote (foo bar fum)) should be avoided in inner loops. Access to quoted symbols such as (quote foo) is fast and does not cause any performance problems. The use of quote for constant cons trees is rare in STELLA (and somewhat deprecated), which is the reason why this mechanism is not all that well supported. Future versions of STELLA might re-implement the handling of constants and alleviate this performance problem.

Equality tests: The standard equality test in STELLA is eql?, which the translator will translate into the most efficient equality test for the particular types of operands (eql? is somewhat similar to the Lisp function CL:eql with the exception of comparing strings). If the translator can determine that at least one of the operands is a subtype of STANDARD-OBJECT, it will translate the test into a fast pointer comparison with the Lisp function CL:eq or the C++/Java == operator. However, if both operands are of type OBJECT, they might be wrapped literals such as wrapped integers or strings. In that case the equality test translates into a call to the function eql? which in turn uses method calls to handle comparison of different types of wrapped literals (two wrapped literals are equal if their wrapped content is equal). This is of course a lot less efficient than a simple pointer comparison. It also means that if you can restrict the type of a variable that will be tested with eql? to STANDARD-OBJECT, you probably should do so for performance reasons.

Type tests: Run-time type tests as used implicitly within a typecase or explicitly with functions such as cons? have to use a call to the method primary-type. Hence, in performance-critical portions of your code you should try to keep the number of such tests as small as possible.

Wrapping and unwrapping literals: The STELLA translator automatically wraps (or objectifies) literals such as numbers or strings when they are stored in a variable or slot of type OBJECT. Similarly, it unwraps wrapped literals automatically to operate on the literal directly. This is very convenient, since it relieves the programmer from having to perform these conversions by hand and makes the code less cluttered. For example, consider the following code fragment:

 
(let ((l (cons "foo" nil))
      (x (concatenate "bar" (first l))))
  (print x EOL)))

Here is its C++ translation:

 
{ Cons* l = cons(wrapString("foo"), NIL);
   char* x = stringConcatenate
              ("bar", ((StringWrapper*)(l->value))->wrapperValue, 0);

  std::cout << x << std::endl;
}

Notice how the string literal "foo" is first wrapped so it can be inserted into the CONS list l and then automatically unwrapped in the call to concatenate. While this is very convenient, it does cause a certain overhead that should be avoided in performance critical loops, etc. In such situations, it often helps to use auxiliary variables of the appropriate literal type to avoid unnecessary wrap/unwrap operations.

Lisp-style property lists: Lisp programs often use property lists for fast retrieval of information that is linked to symbols. To support the easy translation of existing Lisp programs that use this paradigm into STELLA, a similar mechanism implemented by the functions symbol-value, symbol-plist, and symbol-property is available that preserves the performance benefits of this storage scheme (see the file sources/stella/symbols.ste). However, property lists do not fit the object-oriented programming paradigm supported by STELLA, and, hence, are frowned upon.

Compiler optimization: The optimization settings used with the native Lisp or C++ compiler can greatly influence performance results. In particular, using high optimization settings with the Lisp compiler can greatly improve slot access time on STELLA objects.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.3.1 Lisp Performance Hints

The standard Lisp implementation for STELLA objects are CLOS objects, since CLOS provides the most natural Lisp implementation for the STELLA object system. However, there is a price to pay, since in Lisp slot access on CLOS objects is a lot slower than slot access on structs. For example, in Allegro CL 4.3, the access to the value slot of a STELLA CONS cell takes about 4 times longer on a CLOS object implementation of CONS than on a struct implementation. Unfortunately, the struct implementation itself takes about 3 times longer than calling CL:car on a Lisp cons, which is why we are actually using Lisp conses as the Lisp implementation for STELLA CONSes. Note, that in the C++ and Java translation these slot-access performance problems are nonexistent.

In order to get the maximum performance out of the Lisp version of STELLA, you can tell the translator to use structs as the implementation for STELLA objects. It does so by using CL:defstruct instead of CL:defclass and dispatches methods directly on the structure object.

To use the struct translation scheme evaluate

 
(set-stella-feature :use-common-lisp-structs)

before you translate a STELLA system. This will generate translated files with a .slisp extension. Make sure that after you translated all the files you are interested in, you disable the above feature with

 
(unset-stella-feature :use-common-lisp-structs)

Otherwise, subsequent incremental translations in that Lisp image might fail, since different translation schemes cannot be mixed. If you already are using the struct version of STELLA, all systems will be translated in struct mode by default.

To use the struct translation of your system you have to use the struct version of STELLA. To do so do the following:

 
(CL:setq cl-user::*load-cl-struct-stella?* CL:t)
(CL:load "load-stella.lisp")

Alternatively, you can edit the initial value of the variable *load-cl-struct-stella?* in the file ‘load-stella.lisp’ (see also Lisp Installation).

The reasons why the struct translation scheme is not enabled by default are the following:


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Hans Chalupsky on January 5, 2023 using texi2html 1.82.