thread ring benchmark and related bug fixes (non null array creation and wrong signature of enclosing class)

This commit is contained in:
Alex Tkachman
2011-12-07 11:51:50 +02:00
parent bf54dc5453
commit d272979b09
11 changed files with 284 additions and 38 deletions
@@ -10,7 +10,6 @@ import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.psi.JetDeclarationWithBody;
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.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
@@ -100,7 +99,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
generateBridge(name, funDescriptor, fun, cv);
captureThis = generateBody(funDescriptor, cv, fun.getFunctionLiteral());
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)
captureThis = false;
@@ -164,7 +163,7 @@ public class ClosureCodegen extends ObjectOrClosureCodegen {
Collections.<TypeParameterDescriptor>emptyList(),
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);
fc.generateMethod(body, invokeSignature(funDescriptor), funDescriptor);
return closureContext.outerWasUsed;
@@ -104,24 +104,24 @@ public abstract class CodegenContext {
return new ClassContext(descriptor, kind, this, typeMapper);
}
public CodegenContext intoAnonymousClass(@NotNull ObjectOrClosureCodegen closure, ClassDescriptor descriptor, OwnerKind kind) {
return new AnonymousClassContext(descriptor, kind, this, closure);
public CodegenContext intoAnonymousClass(@NotNull ObjectOrClosureCodegen closure, ClassDescriptor descriptor, OwnerKind kind, JetTypeMapper typeMapper) {
return new AnonymousClassContext(descriptor, kind, this, closure, typeMapper);
}
public MethodContext intoFunction(FunctionDescriptor descriptor) {
return new MethodContext(descriptor, getContextKind(), this);
}
public ConstructorContext intoConstructor(ConstructorDescriptor descriptor) {
public ConstructorContext intoConstructor(ConstructorDescriptor descriptor, JetTypeMapper typeMapper) {
if(descriptor == null) {
descriptor = new ConstructorDescriptorImpl(getThisDescriptor(), Collections.<AnnotationDescriptor>emptyList(), true)
.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) {
return new ClosureContext(funDescriptor, classDescriptor, this, closureCodegen, internalClassName);
public ClosureContext intoClosure(FunctionDescriptor funDescriptor, ClassDescriptor classDescriptor, String internalClassName, ClosureCodegen closureCodegen, JetTypeMapper typeMapper) {
return new ClosureContext(funDescriptor, classDescriptor, this, closureCodegen, internalClassName, typeMapper);
}
public FrameMap prepareFrame(JetTypeMapper mapper) {
@@ -170,12 +170,12 @@ public abstract class CodegenContext {
return parentContext != null ? parentContext.lookupInContext(d, v, result) : null;
}
public Type enclosingClassType() {
public Type enclosingClassType(JetTypeMapper typeMapper) {
CodegenContext cur = getParentContext();
while(cur != null && !(cur.getContextDescriptor() instanceof ClassDescriptor))
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) {
@@ -290,8 +290,8 @@ public abstract class CodegenContext {
return getParentContext().lookupInContext(d, v, result);
}
public Type enclosingClassType() {
return getParentContext().enclosingClassType();
public Type enclosingClassType(JetTypeMapper typeMapper) {
return getParentContext().enclosingClassType(typeMapper);
}
@Override
@@ -305,10 +305,10 @@ public abstract class CodegenContext {
}
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);
final Type type = enclosingClassType();
final Type type = enclosingClassType(typeMapper);
outerExpression = type != null
? local1
: null;
@@ -323,7 +323,7 @@ public abstract class CodegenContext {
public ClassContext(ClassDescriptor contextType, OwnerKind contextKind, CodegenContext parentContext, JetTypeMapper typeMapper) {
super(contextType, contextKind, parentContext, null);
final Type type = enclosingClassType();
final Type type = enclosingClassType(typeMapper);
outerExpression = type != null
? StackValue.field(type, typeMapper.getFQName(contextType), "this$0", false)
: null;
@@ -341,10 +341,10 @@ public abstract class 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);
final Type type = enclosingClassType();
final Type type = enclosingClassType(typeMapper);
outerExpression = type != null
? StackValue.field(type, closure.state.getTypeMapper().mapType(contextType.getDefaultType(), OwnerKind.IMPLEMENTATION).getInternalName(), "this$0", false)
: null;
@@ -364,11 +364,11 @@ public abstract class CodegenContext {
public static class ClosureContext extends ReceiverContext {
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);
this.classDescriptor = classDescriptor;
final Type type = enclosingClassType();
final Type type = enclosingClassType(typeMapper);
outerExpression = type != null
? StackValue.field(type, internalClassName, "this$0", false)
: null;
@@ -1958,26 +1958,13 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
} else {
ClassDescriptor classDecl = (ClassDescriptor) constructorDescriptor.getContainingDeclaration();
receiver.put(receiver.type, v);
v.anew(type);
v.dup();
// TODO typechecker must verify that we're the outer class of the instance being created
//noinspection ConstantConditions
if (classDecl.getContainingDeclaration() instanceof ClassDescriptor) {
if(!receiver.type.equals(Type.VOID_TYPE)) {
// 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();
if(!receiver.type.equals(Type.VOID_TYPE)) {
receiver.put(receiver.type, v);
}
CallableMethod method = typeMapper.mapToCallableMethod((ConstructorDescriptor) constructorDescriptor, OwnerKind.IMPLEMENTATION);
@@ -140,7 +140,7 @@ public class GenerationState {
closure.cv = nameAndVisitor.getSecond();
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);
@@ -267,7 +267,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
ConstructorDescriptor constructorDescriptor = bindingContext.get(BindingContext.CONSTRUCTOR, myClass);
CodegenContext.ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor);
CodegenContext.ConstructorContext constructorContext = context.intoConstructor(constructorDescriptor, typeMapper);
Method constructorMethod;
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());
blackBox();
}
public void testNonNullArray() throws Exception {
blackBoxFile("classes/nonnullarray.jet");
System.out.println(generateToText());
}
}
@@ -1,5 +1,7 @@
package org.jetbrains.jet.codegen;
import org.jetbrains.jet.lang.psi.JetNamespace;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@@ -216,6 +218,10 @@ public class ClassGenTest extends CodegenTestCase {
blackBoxFile("regressions/kt500.jet");
}
public void testKt694 () throws Exception {
blackBoxFile("regressions/kt694.jet");
}
public void testKt285 () throws Exception {
// blackBoxFile("regressions/kt285.jet");
}
+137
View File
@@ -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();
}
}
}
}
}
+95
View File
@@ -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()
}
}
}
}
}