Permalink
Browse files

Fixed race condition. Worker thread always uses its own runQ, and loa…

…ds it from scheduler when empty.

Updated manual.
Some changes are cosmetic: changing tabs to spaces
	modified:   README.txt
	modified:   bench/kilim/bench/LotsOfTasks.java
	modified:   docs/manual.html
	deleted:    docs/manual.txt
	modified:   src/kilim/Cell.java
	modified:   src/kilim/Mailbox.java
	modified:   src/kilim/RingQueue.java
	modified:   src/kilim/Scheduler.java
	new file:   src/kilim/ShutdownException.java
	modified:   src/kilim/Task.java
	modified:   src/kilim/WorkerThread.java
	modified:   src/kilim/YieldReason.java
  • Loading branch information...
1 parent 8fdb99a commit 8ee45f749545ac430f385654f7a3be56de38140b @sriram-srinivasan sriram-srinivasan committed Mar 17, 2010
View
@@ -1,4 +1,4 @@
-Kilim v0.5
+Kilim v0.7
Copyright (c) 2006 Sriram Srinivasan.
(kilim _at_ malhar.net)
======================================================================
@@ -9,7 +9,7 @@ License file).
Please see docs/manual.txt and docs/kilim_ecoop08.pdf for a brief
introduction.
-This software depends on the ASM bytecode library (v 3.0).
+This software depends on the ASM bytecode library (v 2.2.3).
To build, you can either run "build.sh" on Unix or ant from the top
directory. Run "test.sh" or "ant test" to test.
@@ -8,54 +8,81 @@
import kilim.*;
+// Usage: java kilim.bench.LotsOfTasks -ntasks
+// creates ntasks and waits for them to finish
+// Or
+//Usage: java kilim.bench.LotsOfTasks ntasks pause
+// creates ntasks, which in turn block indefinitely on their mailboxes.
public class LotsOfTasks {
static boolean block;
+ static int nTasks = 100000;
+ static int nRounds = 10;
+
public static void main(String[] args) throws Exception {
- // Usage: java kilim.bench.LotsOfTasks [ntasks] [pause]
- // pause will tell each task to wait on its mailbox
-
- final int numTasks = (args.length > 0) ? Integer.parseInt(args[0]) : 100000;
- final boolean block = (args.length > 1) ? true : false;
- final Stopwatch s = new Stopwatch("Tasks(" + numTasks + ")");
- for (int round = 0; round < 10; round++) {
+ try {
+ for (int i = 0; i < args.length; i++) {
+ String arg = args[i];
+ if (arg.equalsIgnoreCase("-nRounds")) {
+ nRounds = Integer.parseInt(args[++i]);
+ } else if (arg.equalsIgnoreCase("-nTasks")) {
+ nTasks = Integer.parseInt(args[++i]);
+ } else if (arg.equalsIgnoreCase("-block")) {
+ block = true;
+ }
+ }
+ } catch (NumberFormatException e) {
+ e.printStackTrace();
+ System.exit(0);
+ }
+ System.out.println("kilim.bench.LotsOfTasks -nTasks " + nTasks + (block ? " -block": "") + " -nRounds " + nRounds);
+
+ final Stopwatch s = new Stopwatch("Tasks(" + nTasks + ")");
+ for (int round = 1; round <= nRounds; round++) {
+ System.out.println("Round #" + round + " ================= ");
s.tick();
final Mailbox<ExitMsg> exitmb = new Mailbox<ExitMsg>();
-
- System.out.println("Creating " + numTasks + (block ? " blocking tasks" : " tasks"));
- for (int i = 1; i <= numTasks; i++) {
+
+ System.out.println("Creating " + nTasks + (block ? " blocking tasks" : " tasks"));
+ for (int i = 1; i <= nTasks; i++) {
Task t = new LTask();
t.informOnExit(exitmb);
t.start();
if (i % 100000 == 0) {
- System.out.println("Created " + i + " tasks .... (contd.)");
+ System.out.println(" created " + i + " tasks .... (contd.)");
}
}
-
- if (block) {
- for (int i = 1; i <= numTasks; i++) {
+ profilerMark(); // dummy method to study memory consumption at this stage
+ if (!block) {
+ System.out.println("Waiting for completion");
+ for (int i = 1; i <= nTasks; i++) {
exitmb.getb();
if (i % 100000 == 0) {
- System.out.println("Created " + i + " tasks .... (contd.)");
+ System.out.println(" " + i + " tasks finished.... (contd.)");
}
- };
- }
- System.out.println("Round #" + round + " done. " + numTasks + " created in " + s.tick() + " ms");
- s.tickPrint(numTasks);
+ }
+ ;
+ }
+ System.out.println("Round #" + round + " done:");
+ System.out.print(" ");
+ s.tickPrint(nTasks);
System.gc();
- Thread.sleep(1000); // give the GC a chance.
+ Thread.sleep(100); // give the GC a chance.
}
System.exit(0);
}
+ public static void profilerMark() {
+ // dummy method to help as a profiler breakpoint in JProfiler.
+ }
}
class LTask extends Task {
Mailbox<String> mymb = new Mailbox<String>();
-
+
public void execute() throws Pausable {
if (LotsOfTasks.block) {
mymb.get();
}
}
-
+
}
View
@@ -5,11 +5,12 @@
</head>
<body>
-<h1>Kilim. Release 0.5</h1>
-<p>Last updated: May 24, 2008.
+
+<h1>Kilim v0.7</h1>
+<p>Last updated: March 17, 2010
+
<p>by Sriram Srinivasan
-<p>University of Cambridge.
<p>Please send comments, encouragements, money, cakes, code fixes to
<b>kilim@malhar.net</b>. Thank you.
@@ -84,28 +85,33 @@
new MyThread().start();
</pre>
<p>Now, if you replace the words "Thread" with "Task", "run" with
-"execute" and add an <code>@pausable</code> annotation to <code>execute()</code>, you have a
+"execute" and add an exception called <code>Pausable</code> to <code>execute()</code>, you have a
Kilim Task. Simple.
<pre>
import kilim.*;
public class MyTask extends Task {
- @pausable
- public void execute() {
+ public void execute() throws Pausable{
}
}
</pre>
and to start it, you say <code>new MyTask().start()</code>
-<p>A method marked pausable is one that calls another pausable method; the
-built-in ones are Task.yield() and Task.sleep() (mailbox.get() calls
-Task.yield()).
-<p>The only difference is that you can spawn a million of these
-without turning your computer into a room heater. These tasks
-get executed on a thread pool.
+<p>The "Pausable" exception is used as an annotation, and is never actually thrown (it replaces
+@pausable from earlier versions). A method with such an annotation is deemed "pausable". Pausing refers to
+voluntarily yielding control to the scheduler so that another task may run. For example,
+Task.sleep() is a pausable method that pauses a task
+for a give time. Another example is Mailbox.get(), which pauses a task until a mailbox is
+non-empty.
+
+<p>A pausbale method is similar to blocking calls such as InputStream.read() and
+Thread.wait(), except that it makes its intention clear in its signature with
+the Pausable annotation. This annotation is used by the Kilim weaver to rewrite the bytecode
+of all pausable methods to incorporate the voluntary yielding logic. One important property
+of this scheme is that a pausable method can only be called by another pausable method.
<h1>Communication</h1>
@@ -128,12 +134,9 @@
mb.put("hello");
String s = mb.get();
</pre>
-<p>These two methods block the task (not the java Thread) when they are
-unable to perform the operation. How does one know ? They are marked
-<code>@pausable</code>.
+<p>These two methods pause the task when they are unable to perform the operation.
-<p><code>mailbox.getnb()</code> and <code>putnb()</code> are the non-blocking versions: they are
-not pausable, and they return quickly.
+<p><code>mailbox.getnb()</code> and <code>putnb()</code> are variants that neither pause the task, nor block the thread. They return immediately indicating whether they were able to dequeue (respectively enqueue) an object from the mailbox.
<p><code>mailbox.getb()</code> and putb are the *thread*-blocking versions. Use them if you want to wait for a message but cannot make the calling method
pausable (like <code>main()</code>, for example). You shouldn't be using these
@@ -145,10 +148,9 @@
<p>This package comes with a bytecode transformation tool called Weaver
(package: kilim.tools.Weaver) that post-processes .class files
-looking for the @pausable annotation.
+looking for the "throws Pausable" annotation.
-<p>When a task needs to block (or "pause", calling <code>Task.sleep()</code>, for
-example), the task unwinds its stack, squirrels away all state that
+<p>When a task needs to pause, it unwinds its stack, squirrels away all state that
it'll need later on resumption. This unwinding and rewinding the
stack is automatically performed by the code introduced by the Weaver.
(Debug information is adjusted so that the transformed code can be
@@ -159,7 +161,6 @@
the Workshop on New Horizons in Compilers (2006). A simple introduction
to CPS is in the accompanying IFAQ.txt.
-
<h1>Building, running the examples</h1>
<p>Build the sources by running ant (or build.sh) at the topmost
@@ -179,12 +180,11 @@
<pre> java -cp ./classes kilim.examples.SimpleTask</pre>
<p>Create a million tasks just for the heck of it.
-<p> Try <code>java kilim.bench.LotsOfTasks 1000000</code>
-<p> (Notice the JIT's effect after the first round)
+<p> Try <code>java kilim.bench.LotsOfTasks -ntasks 300000</code>
<p>You can supply a different directory for the weaver's output, but
remember to include that directory in the classpath before the
-original, otherwise you will "class not woven" errors at run time.
+original, otherwise you will see "class not woven" errors at run time.
<p>NOTE: It is safer (and convenient) to supply the entire directory to
weave, like this:
Oops, something went wrong. Retry.

0 comments on commit 8ee45f7

Please sign in to comment.