comparison truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/ThreadSafetyTest.java @ 22424:fec62e298245

Rename package truffle.api.test to truffle.api to enable package-protected API access for testing.
author Christian Humer <christian.humer@oracle.com>
date Wed, 02 Dec 2015 15:16:27 +0100
parents truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ThreadSafetyTest.java@dc83cc1f94f2
children b39b603e2a1e
comparison
equal deleted inserted replaced
22423:70a10a9f28ad 22424:fec62e298245
1 /*
2 * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23 package com.oracle.truffle.api;
24
25 import com.oracle.truffle.api.CallTarget;
26 import com.oracle.truffle.api.Truffle;
27 import com.oracle.truffle.api.TruffleRuntime;
28 import com.oracle.truffle.api.frame.VirtualFrame;
29 import com.oracle.truffle.api.nodes.DirectCallNode;
30 import com.oracle.truffle.api.nodes.Node;
31 import com.oracle.truffle.api.nodes.NodeUtil;
32 import com.oracle.truffle.api.nodes.RootNode;
33 import java.util.Random;
34 import java.util.concurrent.ExecutorService;
35 import java.util.concurrent.Executors;
36 import java.util.concurrent.TimeUnit;
37 import java.util.concurrent.atomic.AtomicInteger;
38 import static org.junit.Assert.assertEquals;
39 import static org.junit.Assert.assertTrue;
40 import org.junit.Ignore;
41 import org.junit.Test;
42
43 /**
44 * Test node rewriting in a tree shared across multiple threads (run with -ea).
45 */
46 public class ThreadSafetyTest {
47
48 @Test
49 @Ignore("sporadic failures with \"expected:<1000000> but was:<999999>\"")
50 public void test() throws InterruptedException {
51 TruffleRuntime runtime = Truffle.getRuntime();
52 TestRootNode rootNode1 = new TestRootNode(new RewritingNode(new RewritingNode(new RewritingNode(new RewritingNode(new RewritingNode(new ConstNode(42)))))));
53 final CallTarget target1 = runtime.createCallTarget(rootNode1);
54 NodeUtil.verify(rootNode1);
55
56 RecursiveCallNode callNode = new RecursiveCallNode(new ConstNode(42));
57 TestRootNode rootNode2 = new TestRootNode(new RewritingNode(new RewritingNode(new RewritingNode(new RewritingNode(new RewritingNode(callNode))))));
58 final CallTarget target2 = runtime.createCallTarget(rootNode2);
59 callNode.setCallNode(runtime.createDirectCallNode(target2));
60 NodeUtil.verify(rootNode2);
61
62 testTarget(target1, 47, 1_000_000);
63 testTarget(target2, 72, 1_000_000);
64 }
65
66 private static void testTarget(final CallTarget target, final int expectedResult, final int numberOfIterations) throws InterruptedException {
67 ExecutorService executorService = Executors.newFixedThreadPool(20);
68 final AtomicInteger ai = new AtomicInteger();
69 for (int i = 0; i < numberOfIterations; i++) {
70 executorService.submit(new Runnable() {
71 public void run() {
72 try {
73 Object result = target.call(new Object[]{5});
74 assertEquals(expectedResult, result);
75 ai.incrementAndGet();
76 } catch (Throwable t) {
77 t.printStackTrace(System.out);
78 }
79 }
80 });
81 }
82 executorService.shutdown();
83 executorService.awaitTermination(90, TimeUnit.SECONDS);
84 assertTrue("test did not terminate", executorService.isTerminated());
85 assertEquals(numberOfIterations, ai.get());
86 }
87
88 static class TestRootNode extends RootNode {
89
90 @Child private ValueNode child;
91
92 public TestRootNode(ValueNode child) {
93 super(TestingLanguage.class, null, null);
94 this.child = child;
95 }
96
97 @Override
98 public Object execute(VirtualFrame frame) {
99 return child.execute(frame);
100 }
101 }
102
103 abstract static class ValueNode extends Node {
104
105 public ValueNode() {
106 super(null);
107 }
108
109 abstract int execute(VirtualFrame frame);
110 }
111
112 static class RewritingNode extends ValueNode {
113
114 @Child private ValueNode child;
115 private final Random random;
116
117 public RewritingNode(ValueNode child) {
118 this(child, new Random());
119 }
120
121 public RewritingNode(ValueNode child, Random random) {
122 this.child = child;
123 this.random = random;
124 }
125
126 @Override
127 int execute(VirtualFrame frame) {
128 boolean replace = random.nextBoolean();
129 if (replace) {
130 ValueNode newNode = this.replace(new OtherRewritingNode(child, random));
131 return newNode.execute(frame);
132 }
133 return 1 + child.execute(frame);
134 }
135 }
136
137 static class OtherRewritingNode extends ValueNode {
138
139 @Child private ValueNode child;
140 private final Random random;
141
142 public OtherRewritingNode(ValueNode child, Random random) {
143 this.child = child;
144 this.random = random;
145 }
146
147 @Override
148 int execute(VirtualFrame frame) {
149 boolean replace = random.nextBoolean();
150 if (replace) {
151 ValueNode newNode = this.replace(new RewritingNode(child, random));
152 return newNode.execute(frame);
153 }
154 return 1 + child.execute(frame);
155 }
156 }
157
158 static class ConstNode extends ValueNode {
159
160 private final int value;
161
162 ConstNode(int value) {
163 this.value = value;
164 }
165
166 @Override
167 int execute(VirtualFrame frame) {
168 return value;
169 }
170 }
171
172 static class RecursiveCallNode extends ValueNode {
173 @Child DirectCallNode callNode;
174 @Child private ValueNode valueNode;
175
176 RecursiveCallNode(ValueNode value) {
177 this.valueNode = value;
178 }
179
180 @Override
181 int execute(VirtualFrame frame) {
182 int arg = (Integer) frame.getArguments()[0];
183 if (arg > 0) {
184 return (int) callNode.call(frame, new Object[]{(arg - 1)});
185 } else {
186 return valueNode.execute(frame);
187 }
188 }
189
190 void setCallNode(DirectCallNode callNode) {
191 this.callNode = insert(callNode);
192 }
193 }
194 }