thread ring benchmark and related bug fixes (non null array creation and wrong signature of enclosing class)
This commit is contained in:
@@ -10,7 +10,6 @@ import org.jetbrains.jet.lang.descriptors.*;
|
|||||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.JetDeclarationWithBody;
|
import org.jetbrains.jet.lang.psi.JetDeclarationWithBody;
|
||||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||||
import org.jetbrains.jet.lang.psi.JetFunctionLiteral;
|
|
||||||
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
|
import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||||
@@ -100,7 +99,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
|
|||||||
generateBridge(name, funDescriptor, fun, cv);
|
generateBridge(name, funDescriptor, fun, cv);
|
||||||
captureThis = generateBody(funDescriptor, cv, fun.getFunctionLiteral());
|
captureThis = generateBody(funDescriptor, cv, fun.getFunctionLiteral());
|
||||||
ClassDescriptor thisDescriptor = context.getThisDescriptor();
|
ClassDescriptor thisDescriptor = context.getThisDescriptor();
|
||||||
final Type enclosingType = thisDescriptor == null ? null : Type.getObjectType(thisDescriptor.getName());
|
final Type enclosingType = thisDescriptor == null ? null : state.getTypeMapper().mapType(thisDescriptor.getDefaultType());
|
||||||
if (enclosingType == null)
|
if (enclosingType == null)
|
||||||
captureThis = false;
|
captureThis = false;
|
||||||
|
|
||||||
@@ -164,7 +163,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
|
|||||||
Collections.<TypeParameterDescriptor>emptyList(),
|
Collections.<TypeParameterDescriptor>emptyList(),
|
||||||
Collections.singleton((funDescriptor.getReceiverParameter().exists() ? JetStandardClasses.getReceiverFunction(arity) : JetStandardClasses.getFunction(arity)).getDefaultType()), JetScope.EMPTY, Collections.<ConstructorDescriptor>emptySet(), null);
|
Collections.singleton((funDescriptor.getReceiverParameter().exists() ? JetStandardClasses.getReceiverFunction(arity) : JetStandardClasses.getFunction(arity)).getDefaultType()), JetScope.EMPTY, Collections.<ConstructorDescriptor>emptySet(), null);
|
||||||
|
|
||||||
final CodegenContext.ClosureContext closureContext = context.intoClosure(funDescriptor, function, name, this);
|
final CodegenContext.ClosureContext closureContext = context.intoClosure(funDescriptor, function, name, this, state.getTypeMapper());
|
||||||
FunctionCodegen fc = new FunctionCodegen(closureContext, cv, state);
|
FunctionCodegen fc = new FunctionCodegen(closureContext, cv, state);
|
||||||
fc.generateMethod(body, invokeSignature(funDescriptor), funDescriptor);
|
fc.generateMethod(body, invokeSignature(funDescriptor), funDescriptor);
|
||||||
return closureContext.outerWasUsed;
|
return closureContext.outerWasUsed;
|
||||||
|
|||||||
@@ -104,24 +104,24 @@ public abstract class CodegenContext {
|
|||||||
return new ClassContext(descriptor, kind, this, typeMapper);
|
return new ClassContext(descriptor, kind, this, typeMapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CodegenContext intoAnonymousClass(@NotNull ObjectOrClosureCodegen closure, ClassDescriptor descriptor, OwnerKind kind) {
|
public CodegenContext intoAnonymousClass(@NotNull ObjectOrClosureCodegen closure, ClassDescriptor descriptor, OwnerKind kind, JetTypeMapper typeMapper) {
|
||||||
return new AnonymousClassContext(descriptor, kind, this, closure);
|
return new AnonymousClassContext(descriptor, kind, this, closure, typeMapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodContext intoFunction(FunctionDescriptor descriptor) {
|
public MethodContext intoFunction(FunctionDescriptor descriptor) {
|
||||||
return new MethodContext(descriptor, getContextKind(), this);
|
return new MethodContext(descriptor, getContextKind(), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConstructorContext intoConstructor(ConstructorDescriptor descriptor) {
|
public ConstructorContext intoConstructor(ConstructorDescriptor descriptor, JetTypeMapper typeMapper) {
|
||||||
if(descriptor == null) {
|
if(descriptor == null) {
|
||||||
descriptor = new ConstructorDescriptorImpl(getThisDescriptor(), Collections.<AnnotationDescriptor>emptyList(), true)
|
descriptor = new ConstructorDescriptorImpl(getThisDescriptor(), Collections.<AnnotationDescriptor>emptyList(), true)
|
||||||
.initialize(Collections.<TypeParameterDescriptor>emptyList(), Collections.<ValueParameterDescriptor>emptyList(), Modality.OPEN, Visibility.PUBLIC);
|
.initialize(Collections.<TypeParameterDescriptor>emptyList(), Collections.<ValueParameterDescriptor>emptyList(), Modality.OPEN, Visibility.PUBLIC);
|
||||||
}
|
}
|
||||||
return new ConstructorContext(descriptor, getContextKind(), this);
|
return new ConstructorContext(descriptor, getContextKind(), this, typeMapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClosureContext intoClosure(FunctionDescriptor funDescriptor, ClassDescriptor classDescriptor, String internalClassName, ClosureCodegen closureCodegen) {
|
public ClosureContext intoClosure(FunctionDescriptor funDescriptor, ClassDescriptor classDescriptor, String internalClassName, ClosureCodegen closureCodegen, JetTypeMapper typeMapper) {
|
||||||
return new ClosureContext(funDescriptor, classDescriptor, this, closureCodegen, internalClassName);
|
return new ClosureContext(funDescriptor, classDescriptor, this, closureCodegen, internalClassName, typeMapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FrameMap prepareFrame(JetTypeMapper mapper) {
|
public FrameMap prepareFrame(JetTypeMapper mapper) {
|
||||||
@@ -170,12 +170,12 @@ public abstract class CodegenContext {
|
|||||||
return parentContext != null ? parentContext.lookupInContext(d, v, result) : null;
|
return parentContext != null ? parentContext.lookupInContext(d, v, result) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type enclosingClassType() {
|
public Type enclosingClassType(JetTypeMapper typeMapper) {
|
||||||
CodegenContext cur = getParentContext();
|
CodegenContext cur = getParentContext();
|
||||||
while(cur != null && !(cur.getContextDescriptor() instanceof ClassDescriptor))
|
while(cur != null && !(cur.getContextDescriptor() instanceof ClassDescriptor))
|
||||||
cur = cur.getParentContext();
|
cur = cur.getParentContext();
|
||||||
|
|
||||||
return cur == null ? null : Type.getObjectType(cur.getContextDescriptor().getName());
|
return cur == null ? null : typeMapper.mapType(((ClassDescriptor)cur.getContextDescriptor()).getDefaultType());
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTypeInfoConstantIndex(JetType type) {
|
public int getTypeInfoConstantIndex(JetType type) {
|
||||||
@@ -290,8 +290,8 @@ public abstract class CodegenContext {
|
|||||||
return getParentContext().lookupInContext(d, v, result);
|
return getParentContext().lookupInContext(d, v, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type enclosingClassType() {
|
public Type enclosingClassType(JetTypeMapper typeMapper) {
|
||||||
return getParentContext().enclosingClassType();
|
return getParentContext().enclosingClassType(typeMapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -305,10 +305,10 @@ public abstract class CodegenContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class ConstructorContext extends MethodContext {
|
public static class ConstructorContext extends MethodContext {
|
||||||
public ConstructorContext(ConstructorDescriptor contextType, OwnerKind kind, CodegenContext parent) {
|
public ConstructorContext(ConstructorDescriptor contextType, OwnerKind kind, CodegenContext parent, JetTypeMapper typeMapper) {
|
||||||
super(contextType, kind, parent);
|
super(contextType, kind, parent);
|
||||||
|
|
||||||
final Type type = enclosingClassType();
|
final Type type = enclosingClassType(typeMapper);
|
||||||
outerExpression = type != null
|
outerExpression = type != null
|
||||||
? local1
|
? local1
|
||||||
: null;
|
: null;
|
||||||
@@ -323,7 +323,7 @@ public abstract class CodegenContext {
|
|||||||
public ClassContext(ClassDescriptor contextType, OwnerKind contextKind, CodegenContext parentContext, JetTypeMapper typeMapper) {
|
public ClassContext(ClassDescriptor contextType, OwnerKind contextKind, CodegenContext parentContext, JetTypeMapper typeMapper) {
|
||||||
super(contextType, contextKind, parentContext, null);
|
super(contextType, contextKind, parentContext, null);
|
||||||
|
|
||||||
final Type type = enclosingClassType();
|
final Type type = enclosingClassType(typeMapper);
|
||||||
outerExpression = type != null
|
outerExpression = type != null
|
||||||
? StackValue.field(type, typeMapper.getFQName(contextType), "this$0", false)
|
? StackValue.field(type, typeMapper.getFQName(contextType), "this$0", false)
|
||||||
: null;
|
: null;
|
||||||
@@ -341,10 +341,10 @@ public abstract class CodegenContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class AnonymousClassContext extends CodegenContext {
|
public static class AnonymousClassContext extends CodegenContext {
|
||||||
public AnonymousClassContext(ClassDescriptor contextType, OwnerKind contextKind, CodegenContext parentContext, @NotNull ObjectOrClosureCodegen closure) {
|
public AnonymousClassContext(ClassDescriptor contextType, OwnerKind contextKind, CodegenContext parentContext, @NotNull ObjectOrClosureCodegen closure, JetTypeMapper typeMapper) {
|
||||||
super(contextType, contextKind, parentContext, closure);
|
super(contextType, contextKind, parentContext, closure);
|
||||||
|
|
||||||
final Type type = enclosingClassType();
|
final Type type = enclosingClassType(typeMapper);
|
||||||
outerExpression = type != null
|
outerExpression = type != null
|
||||||
? StackValue.field(type, closure.state.getTypeMapper().mapType(contextType.getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName(), "this$0", false)
|
? StackValue.field(type, closure.state.getTypeMapper().mapType(contextType.getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName(), "this$0", false)
|
||||||
: null;
|
: null;
|
||||||
@@ -364,11 +364,11 @@ public abstract class CodegenContext {
|
|||||||
public static class ClosureContext extends ReceiverContext {
|
public static class ClosureContext extends ReceiverContext {
|
||||||
private ClassDescriptor classDescriptor;
|
private ClassDescriptor classDescriptor;
|
||||||
|
|
||||||
public ClosureContext(FunctionDescriptor contextType, ClassDescriptor classDescriptor, CodegenContext parentContext, @NotNull ObjectOrClosureCodegen closureCodegen, String internalClassName) {
|
public ClosureContext(FunctionDescriptor contextType, ClassDescriptor classDescriptor, CodegenContext parentContext, @NotNull ObjectOrClosureCodegen closureCodegen, String internalClassName, JetTypeMapper typeMapper) {
|
||||||
super(contextType, OwnerKind.IMPLEMENTATION, parentContext, closureCodegen);
|
super(contextType, OwnerKind.IMPLEMENTATION, parentContext, closureCodegen);
|
||||||
this.classDescriptor = classDescriptor;
|
this.classDescriptor = classDescriptor;
|
||||||
|
|
||||||
final Type type = enclosingClassType();
|
final Type type = enclosingClassType(typeMapper);
|
||||||
outerExpression = type != null
|
outerExpression = type != null
|
||||||
? StackValue.field(type, internalClassName, "this$0", false)
|
? StackValue.field(type, internalClassName, "this$0", false)
|
||||||
: null;
|
: null;
|
||||||
|
|||||||
@@ -1958,26 +1958,13 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
|||||||
} else {
|
} else {
|
||||||
ClassDescriptor classDecl = (ClassDescriptor) constructorDescriptor.getContainingDeclaration();
|
ClassDescriptor classDecl = (ClassDescriptor) constructorDescriptor.getContainingDeclaration();
|
||||||
|
|
||||||
receiver.put(receiver.type, v);
|
|
||||||
v.anew(type);
|
v.anew(type);
|
||||||
|
v.dup();
|
||||||
|
|
||||||
// TODO typechecker must verify that we're the outer class of the instance being created
|
// TODO typechecker must verify that we're the outer class of the instance being created
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
if (classDecl.getContainingDeclaration() instanceof ClassDescriptor) {
|
if(!receiver.type.equals(Type.VOID_TYPE)) {
|
||||||
if(!receiver.type.equals(Type.VOID_TYPE)) {
|
receiver.put(receiver.type, v);
|
||||||
// class object is in receiver
|
|
||||||
v.dupX1();
|
|
||||||
v.swap();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// this$0 need to be put on stack
|
|
||||||
v.dup();
|
|
||||||
v.load(0, typeMapper.mapType(classDecl.getDefaultType(), OwnerKind.IMPLEMENTATION));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// regular case
|
|
||||||
v.dup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CallableMethod method = typeMapper.mapToCallableMethod((ConstructorDescriptor) constructorDescriptor, OwnerKind.IMPLEMENTATION);
|
CallableMethod method = typeMapper.mapToCallableMethod((ConstructorDescriptor) constructorDescriptor, OwnerKind.IMPLEMENTATION);
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ public class GenerationState {
|
|||||||
|
|
||||||
closure.cv = nameAndVisitor.getSecond();
|
closure.cv = nameAndVisitor.getSecond();
|
||||||
closure.name = nameAndVisitor.getFirst();
|
closure.name = nameAndVisitor.getFirst();
|
||||||
final CodegenContext objectContext = closure.context.intoAnonymousClass(closure, getBindingContext().get(BindingContext.CLASS, objectDeclaration), OwnerKind.IMPLEMENTATION);
|
final CodegenContext objectContext = closure.context.intoAnonymousClass(closure, getBindingContext().get(BindingContext.CLASS, objectDeclaration), OwnerKind.IMPLEMENTATION, typeMapper);
|
||||||
|
|
||||||
new ImplementationBodyCodegen(objectDeclaration, objectContext, nameAndVisitor.getSecond(), this).generate(null);
|
new ImplementationBodyCodegen(objectDeclaration, objectContext, nameAndVisitor.getSecond(), this).generate(null);
|
||||||
|
|
||||||
|
|||||||
@@ -267,7 +267,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
|
|
||||||
ConstructorDescriptor constructorDescriptor = bindingContext.get(BindingContext.CONSTRUCTOR, myClass);
|
ConstructorDescriptor constructorDescriptor = bindingContext.get(BindingContext.CONSTRUCTOR, myClass);
|
||||||
|
|
||||||
CodegenContext.ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor);
|
CodegenContext.ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor, typeMapper);
|
||||||
|
|
||||||
Method constructorMethod;
|
Method constructorMethod;
|
||||||
CallableMethod callableMethod;
|
CallableMethod callableMethod;
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
class A() {
|
||||||
|
class B(val i: Int) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test() = Array<B> (10, { B(it) })
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() = if(A().test()[5].i == 5) "OK" else "fail"
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace org2
|
||||||
|
|
||||||
|
enum class Test {
|
||||||
|
A
|
||||||
|
B
|
||||||
|
C
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() = Test.A.toString()
|
||||||
@@ -286,4 +286,9 @@ public class ArrayGenTest extends CodegenTestCase {
|
|||||||
// System.out.println(generateToText());
|
// System.out.println(generateToText());
|
||||||
blackBox();
|
blackBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testNonNullArray() throws Exception {
|
||||||
|
blackBoxFile("classes/nonnullarray.jet");
|
||||||
|
System.out.println(generateToText());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package org.jetbrains.jet.codegen;
|
package org.jetbrains.jet.codegen;
|
||||||
|
|
||||||
|
import org.jetbrains.jet.lang.psi.JetNamespace;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
@@ -216,6 +218,10 @@ public class ClassGenTest extends CodegenTestCase {
|
|||||||
blackBoxFile("regressions/kt500.jet");
|
blackBoxFile("regressions/kt500.jet");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testKt694 () throws Exception {
|
||||||
|
blackBoxFile("regressions/kt694.jet");
|
||||||
|
}
|
||||||
|
|
||||||
public void testKt285 () throws Exception {
|
public void testKt285 () throws Exception {
|
||||||
// blackBoxFile("regressions/kt285.jet");
|
// blackBoxFile("regressions/kt285.jet");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,137 @@
|
|||||||
|
/**
|
||||||
|
* The Computer Language Benchmarks Game
|
||||||
|
* http://shootout.alioth.debian.org/
|
||||||
|
*
|
||||||
|
* contributed by Fabien Le Floc'h
|
||||||
|
*
|
||||||
|
* Java implementation of thread-ring benchmark. Best performance is achieved with
|
||||||
|
* MAX_THREAD=1 as the thread-ring test is bested with only 1 os thread.
|
||||||
|
* This implementation shows using a simple thread pool solves the thread context
|
||||||
|
* switch issue.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
public class ThreadRing {
|
||||||
|
private static final int MAX_NODES = 503;
|
||||||
|
private static final int MAX_THREADS = 503;
|
||||||
|
|
||||||
|
private ExecutorService executor;
|
||||||
|
private final int N;
|
||||||
|
|
||||||
|
static final CountDownLatch cdl = new CountDownLatch(1);
|
||||||
|
|
||||||
|
public static void main(String[] args) throws InterruptedException {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
int n = 5000000;
|
||||||
|
try {
|
||||||
|
n = Integer.parseInt(args[0]);
|
||||||
|
} catch (Exception e) {}
|
||||||
|
ThreadRing ring = new ThreadRing(n);
|
||||||
|
Node node = ring.start(MAX_NODES);
|
||||||
|
node.sendMessage(new TokenMessage(1,0));
|
||||||
|
cdl.await();
|
||||||
|
|
||||||
|
long total = System.currentTimeMillis() - start;
|
||||||
|
System.out.println("[ThreadRing-" + System.getProperty("project.name")+ " Benchmark Result: " + total + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
public ThreadRing(int n) {
|
||||||
|
N = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node start(int n) {
|
||||||
|
Node[] nodes = spawnNodes(n);
|
||||||
|
connectNodes(n, nodes);
|
||||||
|
return nodes[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
private Node[] spawnNodes(int n) {
|
||||||
|
executor = Executors.newFixedThreadPool(MAX_THREADS);
|
||||||
|
Node[] nodes = new Node[n+1];
|
||||||
|
for (int i = 0; i < n ; i++) {
|
||||||
|
nodes[i] = new Node(i+1, null);
|
||||||
|
}
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connectNodes(int n, Node[] nodes) {
|
||||||
|
nodes[n] = nodes[0];
|
||||||
|
for (int i=0; i<n; i++) {
|
||||||
|
nodes[i].connect(nodes[i+1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TokenMessage {
|
||||||
|
private int nodeId;
|
||||||
|
private volatile int value;
|
||||||
|
private boolean isStop;
|
||||||
|
|
||||||
|
public TokenMessage(int nodeId, int value) {
|
||||||
|
this.nodeId = nodeId;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TokenMessage(int nodeId, int value, boolean isStop) {
|
||||||
|
this.nodeId = nodeId;
|
||||||
|
this.value = value;
|
||||||
|
this.isStop = isStop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Node implements Runnable {
|
||||||
|
private int nodeId;
|
||||||
|
private Node nextNode;
|
||||||
|
private BlockingQueue<TokenMessage> queue = new LinkedBlockingQueue<TokenMessage>();
|
||||||
|
private boolean isActive = false;
|
||||||
|
private int counter;
|
||||||
|
|
||||||
|
public Node(int id, Node nextNode) {
|
||||||
|
this.nodeId = id;
|
||||||
|
this.nextNode = nextNode;
|
||||||
|
this.counter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connect(Node node) {
|
||||||
|
this.nextNode = node;
|
||||||
|
isActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendMessage(TokenMessage m) {
|
||||||
|
queue.add(m);
|
||||||
|
executor.execute(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
if (isActive) {
|
||||||
|
try {
|
||||||
|
TokenMessage m = queue.take();
|
||||||
|
if (m.isStop) {
|
||||||
|
int nextValue = m.value+1;
|
||||||
|
if (nextValue == MAX_NODES) {
|
||||||
|
// System.out.println("last one");
|
||||||
|
executor.shutdown();
|
||||||
|
cdl.countDown();
|
||||||
|
} else {
|
||||||
|
m.value = nextValue;
|
||||||
|
nextNode.sendMessage(m);
|
||||||
|
}
|
||||||
|
isActive = false;
|
||||||
|
// System.out.println("ending node "+nodeId);
|
||||||
|
} else {
|
||||||
|
if (m.value == N) {
|
||||||
|
System.out.println(nodeId);
|
||||||
|
nextNode.sendMessage(new TokenMessage(nodeId, 0, true));
|
||||||
|
} else {
|
||||||
|
m.value = m.value + 1;
|
||||||
|
nextNode.sendMessage(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InterruptedException ie) {
|
||||||
|
ie.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
namespace threadring
|
||||||
|
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.concurrent.atomic.*;
|
||||||
|
|
||||||
|
val MAX_NODES = 503
|
||||||
|
val MAX_THREADS = 503
|
||||||
|
|
||||||
|
val cdl = CountDownLatch(1)
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val start = System.currentTimeMillis()
|
||||||
|
var n = 5000000;
|
||||||
|
try {
|
||||||
|
n = Integer.parseInt(args[0]);
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
}
|
||||||
|
|
||||||
|
val ring = ThreadRing(n)
|
||||||
|
ring.sendMessage(TokenMessage(1,0,false))
|
||||||
|
cdl.await();
|
||||||
|
|
||||||
|
val total = System.currentTimeMillis() - start
|
||||||
|
System.out?.println("[ThreadRing-" + System.getProperty("project.name")+ " Benchmark Result: " + total + "]")
|
||||||
|
}
|
||||||
|
|
||||||
|
class TokenMessage(val nodeId : Int, value: Int, val isStop: Boolean) : AtomicInteger(value){
|
||||||
|
}
|
||||||
|
|
||||||
|
class ThreadRing(val N: Int) {
|
||||||
|
val executor = Executors.newFixedThreadPool(MAX_THREADS).sure()
|
||||||
|
|
||||||
|
val nodes : Array<Node> = Array<Node>(MAX_NODES+1, { Node(it+1) })
|
||||||
|
|
||||||
|
{
|
||||||
|
connectNodes()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun connectNodes() {
|
||||||
|
nodes[nodes.size-1] = nodes[0]
|
||||||
|
for (i in 0..nodes.size-2) {
|
||||||
|
nodes[i].connect(nodes[i+1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sendMessage(m : TokenMessage) {
|
||||||
|
nodes[0].sendMessage(m)
|
||||||
|
}
|
||||||
|
class Node(val nodeId : Int) : Runnable {
|
||||||
|
val queue = LinkedBlockingQueue<TokenMessage>()
|
||||||
|
var isActive = false
|
||||||
|
var nextNode : Node? = null
|
||||||
|
|
||||||
|
fun sendMessage(m: TokenMessage) {
|
||||||
|
queue.add(m)
|
||||||
|
executor.execute(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun connect(next: Node) {
|
||||||
|
nextNode = next
|
||||||
|
isActive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun run() {
|
||||||
|
if(isActive) {
|
||||||
|
try {
|
||||||
|
val m = queue.take()
|
||||||
|
if(m.isStop) {
|
||||||
|
val nextValue = m.get()+1
|
||||||
|
if (nextValue == MAX_NODES) {
|
||||||
|
executor.shutdown()
|
||||||
|
cdl.countDown()
|
||||||
|
} else {
|
||||||
|
m.set(nextValue)
|
||||||
|
nextNode.sure().sendMessage(m)
|
||||||
|
}
|
||||||
|
isActive = false
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (m.get() == N) {
|
||||||
|
System.out?.println(nodeId);
|
||||||
|
nextNode.sure().sendMessage(TokenMessage(nodeId, 0, true));
|
||||||
|
} else {
|
||||||
|
m.incrementAndGet()
|
||||||
|
nextNode.sure().sendMessage(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(e: InterruptedException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user