[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
5.1 Hello World in STELLA | ||
5.2 Incrementally Developing STELLA Code | ||
5.3 Performance Hints |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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")) |
5.1.1 Hello World in Lisp | ||
5.1.2 Hello World in C++ | ||
5.1.3 Hello World in Java |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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
:
defun
used to define STELLA functions.
stella::defun
that resides in the STELLA
Lisp package and is only available for convenience in Lisp versions of
STELLA.
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] | [ ? ] |
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.
5.3.1 Lisp Performance Hints |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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
CONS
es. 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.