From a55449ee5fe9d4fad1b7de30520260d8785a2e8b Mon Sep 17 00:00:00 2001 From: Kresten Krab Thorup Date: Thu, 3 Dec 2009 16:10:23 +0100 Subject: [PATCH] fiber optimization --- pom.xml | 10 ++- src/kilim/java/kilim/Fiber.java | 90 +++++++++++-------- src/kilim/java/kilim/State.java | 11 +-- src/kilim/java/kilim/analysis/CallWeaver.java | 70 +++++++++++---- .../java/kilim/analysis/ClassWeaver.java | 6 -- src/main/erl/fib.erl | 69 ++++++++++++++ src/main/java/erjang/ERT.java | 2 +- src/main/java/erjang/Erj.java | 1 + 8 files changed, 187 insertions(+), 72 deletions(-) create mode 100644 src/main/erl/fib.erl diff --git a/pom.xml b/pom.xml index 1f0a6c29..1ddd1813 100644 --- a/pom.xml +++ b/pom.xml @@ -23,6 +23,14 @@ + + org.apache.maven.plugins + maven-compiler-plugin + + 1.5 + 1.5 + + @@ -52,4 +60,4 @@ 3.2 - \ No newline at end of file + diff --git a/src/kilim/java/kilim/Fiber.java b/src/kilim/java/kilim/Fiber.java index 92a8dee4..ca3a8b38 100755 --- a/src/kilim/java/kilim/Fiber.java +++ b/src/kilim/java/kilim/Fiber.java @@ -42,7 +42,9 @@ public final class Fiber { * One State object for each activation frame in the call hierarchy. */ private State[] stateStack = new State[10]; - + private Object[] selfStack = new Object[10]; + private int[] pcStack = new int[10]; + /* * Index into stateStack and equal to depth of call hierarchy - 1 */ @@ -60,7 +62,9 @@ public final class Fiber { /* * Special marker state used by pause */ + private static final int PAUSE_STATE_PC = 1; private static final State PAUSE_STATE = new State(); + private static final State EMPTY_STATE = new State(); /* * Status indicators returned by down() @@ -85,10 +89,6 @@ public final class Fiber { */ private static final int PAUSING__HAS_STATE = 3; - static { - PAUSE_STATE.pc = 1; - } - public Fiber(Task t) { task = t; } @@ -152,33 +152,14 @@ public int up() { return NOT_PAUSING__NO_STATE; } else { stack[d] = null; // clean up - pc = cs.pc; + pc = pcStack[d]; // if (debug) System.out.println("\nup(not pausing)" + this);; // if (debug) ds(); - cs.releaseTo(this); return NOT_PAUSING__HAS_STATE; } } } - private static final int STATE_POOL_SIZE = 10; - int pool_count = 0; - State[] pool = new State[STATE_POOL_SIZE]; - - public final State allocState() - { - if (pool_count==0) return new State(); - return pool[--pool_count]; - } - - final void release(State s) { - if (pool_count != STATE_POOL_SIZE) { - pool[pool_count++] = s; - s.self = null; - } - } - - public final Fiber begin() { return down(); } @@ -219,7 +200,7 @@ public Fiber down() { } else { State s = stateStack[d]; curState = s; - pc = (s == null) ? 0 : s.pc; + pc = (s == null) ? 0 : pcStack[d]; } // if (debug) System.out.println("down:\n" + this); // if (debug) ds(); @@ -262,16 +243,17 @@ static void ds() { */ public int upEx() { // compute new iStack. - int is = task.getStackDepth() - 2; // remove upEx and convert to 0-based index. + final int is = task.getStackDepth() - 2; // remove upEx and convert to 0-based index. State cs = stateStack[is]; for (int i = iStack; i >= is; i--) { stateStack[i] = null; // release state + selfStack[i] = null; // release state } iStack = is; curState = cs; - return (cs == null) ? 0 : cs.pc; + return (cs == null) ? 0 : pcStack[is]; } /** @@ -282,16 +264,25 @@ public int upEx() { public Object getCallee() { assert stateStack[iStack] != PAUSE_STATE : "No callee: this state is the pause state"; assert stateStack[iStack] != null : "Callee is null"; - return stateStack[iStack + 1].self; + return selfStack[iStack + 1]; } - private State[] ensureSize(int newsize) { + private void ensureSize(int newsize) { // System.out.println("ENSURE SIZE = " + newsize); + int len = stateStack.length; + State[] newStack = new State[newsize]; - System.arraycopy(stateStack, 0, newStack, 0, stateStack.length); + System.arraycopy(stateStack, 0, newStack, 0, len); stateStack = newStack; - return newStack; - } + + Object[] newSelfStack = new Object[newsize]; + System.arraycopy(selfStack, 0, newSelfStack, 0, len); + selfStack = newSelfStack; + + int[] newPCStack = new int[newsize]; + System.arraycopy(pcStack, 0, newPCStack, 0, len); + pcStack = newPCStack; +} /** * Called by the generated code before pausing and unwinding its stack @@ -299,8 +290,34 @@ private State[] ensureSize(int newsize) { * * @param state */ - public void setState(State state) { + public void setState(State state, Object self, int pc) { stateStack[iStack] = state; + selfStack[iStack] = self; + pcStack[iStack] = pc; + isPausing = true; +// System.out.println("setState[" + + iStack + "] = " + this); + } + + public void setState(State state, int pc) { + stateStack[iStack] = state; + selfStack[iStack] = null; + pcStack[iStack] = pc; + isPausing = true; +// System.out.println("setState[" + + iStack + "] = " + this); + } + + public void setState(Object self, int pc) { + stateStack[iStack] = EMPTY_STATE; + selfStack[iStack] = self; + pcStack[iStack] = pc; + isPausing = true; +// System.out.println("setState[" + + iStack + "] = " + this); + } + + public void setState(int pc) { + stateStack[iStack] = EMPTY_STATE; + selfStack[iStack] = null; + pcStack[iStack] = pc; isPausing = true; // System.out.println("setState[" + + iStack + "] = " + this); } @@ -311,9 +328,10 @@ void togglePause() { // upto date. if (curState == null) { - setState(PAUSE_STATE); + setState(PAUSE_STATE, PAUSE_STATE_PC); } else { - assert curState == PAUSE_STATE : "togglePause: Expected PAUSE_STATE, instead got: iStack == " + iStack + ", state = " + curState; + assert curState == PAUSE_STATE : + "togglePause: Expected PAUSE_STATE, instead got: iStack == " + iStack + ", state = " + curState; stateStack[iStack] = null; isPausing = false; } diff --git a/src/kilim/java/kilim/State.java b/src/kilim/java/kilim/State.java index b14a006b..27f45da3 100755 --- a/src/kilim/java/kilim/State.java +++ b/src/kilim/java/kilim/State.java @@ -25,13 +25,6 @@ */ public class State { - public int pc; - public Object self; - - /** - * @param fiber - */ - void releaseTo(Fiber fiber) { - fiber.release(this); - } + //public int pc; + //public Object self; } diff --git a/src/kilim/java/kilim/analysis/CallWeaver.java b/src/kilim/java/kilim/analysis/CallWeaver.java index b6422868..7ca29ba4 100755 --- a/src/kilim/java/kilim/analysis/CallWeaver.java +++ b/src/kilim/java/kilim/analysis/CallWeaver.java @@ -516,32 +516,41 @@ private void genSave(MethodVisitor mv, Label saveLabel) { * the method weaver's list. This allows us to do a switch in the * method's entry. */ - if (stateClassName.equals(STATE_CLASS)) { + boolean is_simple_state = stateClassName.equals(STATE_CLASS); + + if (is_simple_state) { + loadVar(mv, TOBJECT, methodWeaver.getFiberVar()); - mv.visitMethodInsn(INVOKEVIRTUAL, FIBER_CLASS, "allocState", "()" + D_STATE); + + if (!bb.flow.isStatic()) { + mv.visitInsn(ALOAD_0); // for state.self == this + } + + int pc = methodWeaver.getPC(this); + if (pc < 6) { + mv.visitInsn(ICONST_0 + pc); + } else { + mv.visitIntInsn(BIPUSH, pc); + } + + if (!bb.flow.isStatic()) { + methodWeaver.ensureMaxStack(3); + mv.visitMethodInsn(INVOKEVIRTUAL, FIBER_CLASS, "setState", "(Ljava/lang/Object;I)V"); + } else { + methodWeaver.ensureMaxStack(2); + mv.visitMethodInsn(INVOKEVIRTUAL, FIBER_CLASS, "setState", "(I)V"); + } + + } else { mv.visitTypeInsn(NEW, stateClassName); mv.visitInsn(DUP); // // call constructor mv.visitMethodInsn(INVOKESPECIAL, stateClassName, "", "()V"); - } + // save state in register int stateVar = allocVar(1); storeVar(mv, TOBJECT, stateVar); - // state.self = this if the current executing method isn't static - if (!bb.flow.isStatic()) { - loadVar(mv, TOBJECT, stateVar); - mv.visitInsn(ALOAD_0); // for state.self == this - mv.visitFieldInsn(PUTFIELD, STATE_CLASS, "self", D_OBJECT); - } - int pc = methodWeaver.getPC(this); - loadVar(mv, TOBJECT, stateVar); // state.pc - if (pc < 6) { - mv.visitInsn(ICONST_0 + pc); - } else { - mv.visitIntInsn(BIPUSH, pc); - } - mv.visitFieldInsn(PUTFIELD, STATE_CLASS, "pc", D_INT); // First save bottom stack into state int i = getNumBottom() - 1; @@ -585,9 +594,32 @@ private void genSave(MethodVisitor mv, Label saveLabel) { // Fiber.setState(state); loadVar(mv, TOBJECT, methodWeaver.getFiberVar()); loadVar(mv, TOBJECT, stateVar); - mv.visitMethodInsn(INVOKEVIRTUAL, FIBER_CLASS, "setState", "(" - + D_STATE + ")V"); + + if (!bb.flow.isStatic()) { + mv.visitInsn(ALOAD_0); // for state.self == this + } + + int pc = methodWeaver.getPC(this); + if (pc < 6) { + mv.visitInsn(ICONST_0 + pc); + } else { + mv.visitIntInsn(BIPUSH, pc); + } + + if (!bb.flow.isStatic()) { + methodWeaver.ensureMaxStack(4); + mv.visitMethodInsn(INVOKEVIRTUAL, FIBER_CLASS, "setState", "(" + + D_STATE + "Ljava/lang/Object;I)V"); + } else { + methodWeaver.ensureMaxStack(3); + mv.visitMethodInsn(INVOKEVIRTUAL, FIBER_CLASS, "setState", "(" + + D_STATE + "I)V"); + } + releaseVar(stateVar, 1); + } + + // Figure out the return type of the calling method and issue the // appropriate xRETURN instruction retType = TypeDesc.getReturnTypeDesc(bb.flow.desc); diff --git a/src/kilim/java/kilim/analysis/ClassWeaver.java b/src/kilim/java/kilim/analysis/ClassWeaver.java index c8dbc466..5e6c17ca 100755 --- a/src/kilim/java/kilim/analysis/ClassWeaver.java +++ b/src/kilim/java/kilim/analysis/ClassWeaver.java @@ -190,12 +190,6 @@ String createStateClass(ValInfoList valInfoList) { ClassWriter cw = new ClassWriter(0); cw.visit(V1_1, ACC_PUBLIC | ACC_FINAL, className, null, "kilim/State", null); - MethodVisitor mv = cw.visitMethod(0, "releaseTo", "(Lkilim/Fiber;)V" , null, null); - mv.visitCode(); - mv.visitInsn(RETURN); - mv.visitMaxs(1, 2); - mv.visitEnd(); - // Create default constructor // () { // super(); // call java/lang/Object.() diff --git a/src/main/erl/fib.erl b/src/main/erl/fib.erl new file mode 100644 index 00000000..2d00adcb --- /dev/null +++ b/src/main/erl/fib.erl @@ -0,0 +1,69 @@ +-module(fib). +-export([fibo/1, fibo2/1, fibo3/1, print_nfibos/2, main/0, runLength/2, main2/0]). + +%% print fibo arg. and result, with function as parameter + +print_nfibos( N, FiboFunc) -> printfibos( N, FiboFunc, 0). + +printfibos( 0, FiboFunc, N) -> %% last recursion + Res = FiboFunc(N), + io:format("~w ~w~n", [N, Res]) ; + +printfibos( Iter, FiboFunc, N) when Iter > 0 -> + Res = FiboFunc(N), + io:format("~w ~w~n", [N, Res]), + printfibos( Iter -1, FiboFunc, N +1). + + + +fibo(0) -> 0 ; +fibo(1) -> 1 ; +fibo(N) when N > 0 -> fibo(N-1) + fibo(N-2) . + + +fibo2_tr( 0, Result, _Next) -> Result ; %% last recursion output + +fibo2_tr( Iter, Result, Next) when Iter > 0 -> fibo2_tr( Iter -1, Next, Result + Next) . + +fibo2( N) -> fibo2_tr( N, 0, 1) . + + +fibo3(N) -> + {Fib, _} = fibo3(N, {1, 1}, {0, 1}), + Fib. + +fibo3(0, _, Pair) -> Pair; +fibo3(N, {Fib1, Fib2}, Pair) when N rem 2 == 0 -> + SquareFib1 = Fib1*Fib1, + fibo3(N div 2, {2*Fib1*Fib2 - SquareFib1, SquareFib1 + Fib2*Fib2}, Pair); +fibo3(N, {FibA1, FibA2}=Pair, {FibB1, FibB2}) -> + fibo3(N-1, Pair, {FibA1*FibB2 + FibB1*(FibA2 - FibA1), FibA1*FibB1 + FibA2*FibB2}). + + +time(F,N) -> + {Time,_Res} = timer:tc(fib,F,[N]), + io:format("~w,~w,~w~n", [F,N,Time]). + +tlength(L) -> tlength(L,0). +tlength([_|T],Acc) -> tlength(T,Acc+1); +tlength([],Acc) -> Acc. + +makeList(N) when N==0 -> []; +makeList(N) -> [N,makeList(N-1)]. + +runLength(_,N) when N==0 -> done; +runLength(L,N) -> tlength(L), runLength(L,N-1). + +main() -> + List = makeList(2000), + io:format("time=~w~n", [timer:tc(fib,runLength,[List,1000000])]). + +main2() -> + time(fibo3,10), + time(fibo3,100), + time(fibo3,1000), + time(fibo3,10000), + time(fibo3,100000), + time(fibo3,1000000). + + \ No newline at end of file diff --git a/src/main/java/erjang/ERT.java b/src/main/java/erjang/ERT.java index 7fdbbe31..83109997 100644 --- a/src/main/java/erjang/ERT.java +++ b/src/main/java/erjang/ERT.java @@ -348,7 +348,7 @@ public static EObject apply(EProc proc, EObject mod, EObject fun) throws Pausabl if (m==null||f==null) throw ERT.badarg(mod, fun); EFun efun = EModule.resolve(new FunID(m,f,0)); - return efun.invoke(proc, new EObject[] { }); + return efun.invoke(proc, new EObject[0]); } public static EObject apply$last(EProc proc, EObject arg1, EObject mod, EObject fun) diff --git a/src/main/java/erjang/Erj.java b/src/main/java/erjang/Erj.java index 9c1b1e05..06e866a2 100644 --- a/src/main/java/erjang/Erj.java +++ b/src/main/java/erjang/Erj.java @@ -62,6 +62,7 @@ public static void main(String[] args) throws ClassNotFoundException, MalformedU } EModule.load_module(EAtom.intern("io"), new File("target/classes").toURL()); + EModule.load_module(EAtom.intern("timer"), new File("target/classes").toURL()); load(new File("src/main/erl/" + m + ".classes"), m);