Thread: [tcljava-dev] Prototype Jacl Runtime Compiler
Brought to you by:
mdejong
|
From: Bruce J. <nm...@ma...> - 2005-09-19 02:35:02
|
Dear Jacl folk,
I've been doing some work recently to prototype some methods for
increasing the performance of Jacl. Originally I did a protoype
that focussed on actually compiling Jacl code to Java byte codes.
While this looked feasible it was quite complicated and looked
like it would take quite a bit of effort to complete. I've spent
some time recently looking at a different approach. This consists
of compiling Jacl code to a series of Instruction objects
which are then executed by iterating through the list of
instructions and calling the "exec" method for each. The code is
relatively simple and at present simple, artificial benchmarks are
sped up by about 2-10x.
For example:
proc tproc {} {
string length abc
string length abc
... repeat to a total of 30 lines
}
is sped up 10x, with a StringInstruction that explicitly executes
the "string length" command.
proc tproc {} {
set a1 duck
set a2 $a1
set a3 $a2
set a4 $a3
set a5 $a4
set a6 $a5
set a7 $a6
set a8 $a7
set a9 $a8
set a10 $a9
}
is sped up about 3x, and is ultimately limited by the lack of
explicit optimization of local variable lookup. Implementation
of a local variable table should substantially increase this
performance.
Note that these calculations are done after first executing the
procedure multiple times. The initial speed increase is lower.
I'm guessing this is an effect of the Java Hot Spot compiler.
My company has some money available to fund some work on Jacl
optimization and am currently considering the best way to proceed. The
protoype work I describe here may not be the best solution and may not
be developed beyond this stage. There are certainly alternative
approaches.
I thought I'd make this code available and get some feedback on it.
I'd welcome opinions on whether people think this approach is
reasonable.
Note that the code is written simply to get a quick idea of the value
in this
approach and could be substantially rewritten. Also note that only the
"if" and
"for" flow instructions are implemented. Jacl code within loops such
as the "foreach"
command is not yet compiled so no performance increase will be seen.
Running the test suite (with certain tests disabled) gives the
following results:
all.tcl: Total 4912 Passed 4565 Skipped 294 Failed
53
I disabled about 5 test files that caused the testing to crash and have
not yet
investigated the source of these problems.
Note: running the code gives the following message when procedures are
created:
WARNING: This code running with experimental Jacl runtime compiler
support!
It is not now ready, and may never be ready, for production use!
I'll be posting the code shortly at my web site, but if anyone would
like it sooner just email me
and I'll send you a copy (the compressed code is only 46Kb).
It consists of 11 modified or new Java source files that can just be
copied into
the Jacl 1.3.2 distribution that Mo recently released.
best regards,
Bruce
Bruce A. Johnson
One Moon Scientific, Inc.
EDC III
211 Warren St
Newark, NJ 07103
Phone 908 517-5105
Fax 908 517-5107
Email br...@on...
Web www.onemoonscientific.com
More details on the methodology follow:
Compilation proceedes by parsing Jacl scripts using code translated
from the C version of Tcl.
During compilation, instructions are added to a list of instructions.
Instructions consist of
Java objects that are instances of classes that extend an abstract
Instruction class:
static public abstract class Instruction {
private String name = null;
private int stackEffect = 0;
Instruction(String name,int stackEffect) {
this.name = name;
this.stackEffect = stackEffect;
}
public String toString() {return name;}
abstract int exec(CompileEnv env,Object instructions[], int iC)
throws TclException;
}
Each Instruction class provides a concrete implementation of the "exec"
method.
For example, the PUSH Instruction:
public static final Instruction PUSH = new
Instruction("push", 1) {
int exec(CompileEnv env,Object instructions[],int iC) {
int index = ((Integer) instructions[iC+1]).intValue();
env.stack.push(env.literalsArray[index]);
return 1;
}
};
More complicated instructions, for example, those that implement flow
control extend the
Instruction class.
For example, the If instruction is implemented as follows (note that at
present the expressions in the If command
are not compiled, though the execution bodies are:
class IfInstruction extends Instruction {
IfInstruction(String name,int stackEffect) {
super(name,stackEffect);
}
ArrayList branches = new ArrayList();
ArrayList expressions = new ArrayList();
void addInstructionBranch(ArrayList branch) {
branches.add(branch);
}
void addExpression(String expression) {
expressions.add(expression);
}
int exec(CompileEnv env,Object instructions[],int iC) throws
TclException {
int i = 0;
for (i=0;i<expressions.size();i++) {
boolean value = interp.expr.evalBoolean(interp,(String)
expressions.get(i));
if (value) {
break;
}
}
if (i < branches.size()) {
Object myInstructions[] = ((ArrayList)
branches.get(i)).toArray();
execInstructionList(interp,myInstructions, false);
} else {
}
return 1;
}
}
At present there are only about 16 instructions implemented.
Execution of a compiled script proceeds by incrementing through the
list of instructions and calling
the "exec" method of each. This relies on the simple use of Javas
intrinsic method dispatch capabilities, rather
than complicated if/then or switch statements.
Actual Java source files used to implement the compiler/execution
system are described below:
src/jacl/tcl/lang/Procedure.java
Modified to call compiler when procedure is created.
If global Tcl variable CompileProc(procedureName) is present and
set to false
then the procedure will not be compiled.
If procedure has been compiled, then when it is executed the
compiled instructions will be executed.
src/jacl/tcl/lang/VarType.java
Used by compiler in managing variables, Note: there is no
optimized support yet for local variables
src/jacl/tcl/lang/Compiler.java
Compiles procedures
src/jacl/tcl/lang/CompileEnvjava
Compilation environemnt.
Containts subclasses for an Execution stack and Instructions to
execute.
Current instructions are:
Instructions for manipulating objects on stack
PUSH, DISCARD, POP, DUP, CONCAT,
Instructions for invoking execution
INVOKE,
Instructions for moving stack elements between stack and
variables
LOAD_SCALAR_STK, STORE_SCALAR_STK, STORE_ARRAY_STK,
LOAD_ARRAY_STK, LOAD_SCALAR, LOAD_ARRAY
Prototype of a math instruction:
MULT
Flow control execution
IfInstruction, ForInstruction
Compiled Tcl commands
StringInstruction (only implements "string length" at
present
src/jacl/tcl/lang/CTclParse.java
Modified version of TclParse for use with Compiler
src/jacl/tcl/lang/CParser.java
Translation of Parser for C version to parse scripts prior to
compilation
the following are present, but not complete, functional or used yet
src/jacl/tcl/lang/OperatorDesc.java
Math and Boolean operators for compiling expressions
src/jacl/tcl/lang/MathFunc.java
Math functions for compiling expressions
src/jacl/tcl/lang/ParseExpr.java
Used to parse expressions
src/jacl/tcl/lang/ParseExpr.java
Used to compile expressions
src/jacl/tcl/lang/CompCommand.java
Interface for commands that are compiled (this is not now used, and
may not be used)
|
|
From: Tom P. <tpo...@ny...> - 2005-09-19 15:06:46
|
On Sun, Sep 18, 2005 at 10:34:58PM -0400, Bruce Johnson wrote: > I'll be posting the code shortly at my web site, but if anyone would > like it sooner just email me > and I'll send you a copy (the compressed code is only 46Kb). > It consists of 11 modified or new Java source files that can just be Bruce, this looks cool! Please send me a copy. I started a small 'performance' project, trying to cache the parsed TclParse objects per each Procedure, mapping them to the character offset in each proc body. This turned out not to have a great performance impact, only about 1.3 - 1.5 increase. There's still quite a bit of overhead in Parser.evalTokens(). Oh well, nice experiment anyway. -- Tom Poindexter tpo...@ny... http://www.nyx.net/~tpoindex/ |
|
From: Mo D. <md...@un...> - 2005-09-19 18:30:05
|
On Mon, 19 Sep 2005 09:06:33 -0600
Tom Poindexter <tpo...@ny...> wrote:
> On Sun, Sep 18, 2005 at 10:34:58PM -0400, Bruce Johnson wrote:
>
> > I'll be posting the code shortly at my web site, but if anyone would
> > like it sooner just email me
> > and I'll send you a copy (the compressed code is only 46Kb).
> > It consists of 11 modified or new Java source files that can just be
>
>
> Bruce, this looks cool! Please send me a copy.
>
> I started a small 'performance' project, trying to cache the parsed TclParse
> objects per each Procedure, mapping them to the character offset in each
> proc body. This turned out not to have a great performance impact, only
> about 1.3 - 1.5 increase. There's still quite a bit of overhead in
> Parser.evalTokens(). Oh well, nice experiment anyway.
Tom, what kind of scripts/tools were you using to measure this 1.3 -> 1.5
speed improvement? I have not found much "demo code" that was easy
to use with Jacl for the testing runtime performance issues. One could always
write a small loop and use time {...} to measure it, but that does not really
work like "real world" Jacl code. I guess what I am really looking for is some
number of Jacl examples that do more than just a simple loop and yet can
easily be used outside of other code to test the Jacl runtime impl.
Mo DeJong
|
|
From: Tom P. <tpo...@ny...> - 2005-09-19 20:30:49
|
On Mon, Sep 19, 2005 at 11:32:15AM -0700, Mo DeJong wrote:
> Tom, what kind of scripts/tools were you using to measure this 1.3 -> 1.5
> speed improvement? I have not found much "demo code" that was easy
> to use with Jacl for the testing runtime performance issues. One could always
> write a small loop and use time {...} to measure it, but that does not really
I must confess, most of my timings were mostly artificial. Since my goal
was to cache TclParse (and thus TclToken) objects per proc, the tests that
I used defined one or more procs and invoked those procs in for loops.
Certainly not real world examples, but good enough to get some preliminary
results.
I did use a Java profiler, JMP, to get the idea of caching TclParse. I ran
the Jacl test suite, some of my real code, and some of my contrived
examples under the profiler. This gave me the idea for caching TclParse
objects.
Perhaps TclBench has some tests we can use?
--
Tom Poindexter
tpo...@ny...
http://www.nyx.net/~tpoindex/
|
|
From: Bruce J. <nm...@ma...> - 2005-09-20 11:32:53
|
I've found that when developing the code I just released that I had to rely on "artificial" benchmarks. Because most of my real code uses constructs such as "foreach", for which the body is not yet compiled, I wouldn't see any performance change in "real" code. Though ultimately any performance optimization scheme is irrelevant if it doesn't work well on real code, I'm not sure one can make substantial progress if one doesn't use simple benchmarks to understand where the performance bottlenecks are. As with Tom, I found a Java profiler useful The goal wasn't to try to eke out every bit of performance, but just to get some sense of which parts of the code were most important to worry about. I found the new profiler in NetBeans ( http://profiler.netbeans.org ) to work well. Bruce On Sep 19, 2005, at 4:30 PM, Tom Poindexter wrote: > On Mon, Sep 19, 2005 at 11:32:15AM -0700, Mo DeJong wrote: > >> Tom, what kind of scripts/tools were you using to measure this 1.3 -> >> 1.5 >> speed improvement? I have not found much "demo code" that was easy >> to use with Jacl for the testing runtime performance issues. One >> could always >> write a small loop and use time {...} to measure it, but that does >> not really > > > I must confess, most of my timings were mostly artificial. Since my > goal > was to cache TclParse (and thus TclToken) objects per proc, the tests > that > I used defined one or more procs and invoked those procs in for loops. > Certainly not real world examples, but good enough to get some > preliminary > results. > > I did use a Java profiler, JMP, to get the idea of caching TclParse. > I ran > the Jacl test suite, some of my real code, and some of my contrived > examples under the profiler. This gave me the idea for caching > TclParse > objects. > > Perhaps TclBench has some tests we can use? > > > -- > Tom Poindexter > tpo...@ny... > http://www.nyx.net/~tpoindex/ > > > ------------------------------------------------------- > SF.Net email is sponsored by: > Tame your development challenges with Apache's Geronimo App Server. > Download it for free - -and be entered to win a 42" plasma tv or your > very > own Sony(tm)PSP. Click here to play: > http://sourceforge.net/geronimo.php > _______________________________________________ > tcljava-dev mailing list > tcl...@li... > https://lists.sourceforge.net/lists/listinfo/tcljava-dev > Bruce A. Johnson, President One Moon Scientific, Inc. EDC III 211 Warren St Newark, NJ 07103 Phone 908 517-5105 Fax 908 517-5107 Email br...@on... Web www.onemoonscientific.com |
|
From: Bruce J. <nm...@ma...> - 2005-09-19 15:15:47
Attachments:
compiler.tar.gz
|
cheers, Bruce On Sep 19, 2005, at 11:06 AM, Tom Poindexter wrote: > On Sun, Sep 18, 2005 at 10:34:58PM -0400, Bruce Johnson wrote: > >> I'll be posting the code shortly at my web site, but if anyone would >> like it sooner just email me >> and I'll send you a copy (the compressed code is only 46Kb). >> It consists of 11 modified or new Java source files that can just be > > > Bruce, this looks cool! Please send me a copy. > > I started a small 'performance' project, trying to cache the parsed > TclParse > objects per each Procedure, mapping them to the character offset in > each > proc body. This turned out not to have a great performance impact, > only > about 1.3 - 1.5 increase. There's still quite a bit of overhead in > Parser.evalTokens(). Oh well, nice experiment anyway. > > -- > Tom Poindexter > tpo...@ny... > http://www.nyx.net/~tpoindex/ > > > ------------------------------------------------------- > SF.Net email is sponsored by: > Tame your development challenges with Apache's Geronimo App Server. > Download it for free - -and be entered to win a 42" plasma tv or your > very > own Sony(tm)PSP. Click here to play: > http://sourceforge.net/geronimo.php > _______________________________________________ > tcljava-dev mailing list > tcl...@li... > https://lists.sourceforge.net/lists/listinfo/tcljava-dev > Bruce A. Johnson, President One Moon Scientific, Inc. EDC III 211 Warren St Newark, NJ 07103 Phone 908 517-5105 Fax 908 517-5107 Email br...@on... Web www.onemoonscientific.com |