Skip to content

Commit 57cfd18

Browse files
committed
Detect ecall inside loop
When an Ecall is inside a loop, there is an optimization chance to move the loop inside Ecall. This commit checks such chances and provide suggestions for user.
1 parent db9394a commit 57cfd18

File tree

6 files changed

+376
-0
lines changed

6 files changed

+376
-0
lines changed

sdk/optimizationDetector/pom.xml

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<!--
2+
Licensed to the Apache Software Foundation (ASF) under one or more
3+
contributor license agreements. See the NOTICE file distributed with
4+
this work for additional information regarding copyright ownership.
5+
The ASF licenses this file to You under the Apache License, Version 2.0
6+
(the "License"); you may not use this file except in compliance with
7+
the License. You may obtain a copy of the License at
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
-->
15+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
16+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
17+
<modelVersion>4.0.0</modelVersion>
18+
<parent>
19+
<groupId>org.apache.teaclave.javasdk</groupId>
20+
<artifactId>JavaEnclave</artifactId>
21+
<version>0.1.0</version>
22+
</parent>
23+
<artifactId>optimizationDetector</artifactId>
24+
<build>
25+
<plugins>
26+
<plugin>
27+
<groupId>org.apache.maven.plugins</groupId>
28+
<artifactId>maven-compiler-plugin</artifactId>
29+
<configuration>
30+
<compilerArgs>
31+
<arg>--add-modules</arg>
32+
<arg>jdk.internal.vm.ci,jdk.internal.vm.compiler</arg>
33+
<arg>--add-exports</arg>
34+
<arg>jdk.internal.vm.ci/jdk.vm.ci.meta=ALL-UNNAMED</arg>
35+
<arg>--add-exports</arg>
36+
<arg>jdk.internal.vm.ci/jdk.vm.ci.code=ALL-UNNAMED</arg>
37+
<arg>--add-exports</arg>
38+
<arg>jdk.internal.vm.ci/jdk.vm.ci.hotspot=ALL-UNNAMED</arg>
39+
<arg>--add-exports</arg>
40+
<arg>java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED</arg>
41+
<arg>--add-exports</arg>
42+
<arg>jdk.internal.vm.compiler/org.graalvm.compiler.options=ALL-UNNAMED</arg>
43+
<arg>--add-exports</arg>
44+
<arg>jdk.internal.vm.compiler/org.graalvm.compiler.debug=ALL-UNNAMED</arg>
45+
<arg>--add-exports</arg>
46+
<arg>jdk.internal.vm.compiler/org.graalvm.compiler.hotspot=ALL-UNNAMED</arg>
47+
<arg>--add-exports</arg>
48+
<arg>jdk.internal.vm.compiler/org.graalvm.compiler.nodes=ALL-UNNAMED</arg>
49+
<arg>--add-exports</arg>
50+
<arg>jdk.internal.vm.ci/jdk.vm.ci.runtime=ALL-UNNAMED</arg>
51+
<arg>--add-exports</arg>
52+
<arg>jdk.internal.vm.compiler/org.graalvm.compiler.printer=ALL-UNNAMED</arg>
53+
<arg>--add-exports</arg>
54+
<arg>jdk.internal.vm.compiler/org.graalvm.compiler.nodes.graphbuilderconf=ALL-UNNAMED</arg>
55+
<arg>--add-exports</arg>
56+
<arg>jdk.internal.vm.compiler/org.graalvm.compiler.phases=ALL-UNNAMED</arg>
57+
<arg>--add-exports</arg>
58+
<arg>jdk.internal.vm.compiler/org.graalvm.compiler.java=ALL-UNNAMED</arg>
59+
<arg>--add-exports</arg>
60+
<arg>jdk.internal.vm.compiler/org.graalvm.compiler.graph.iterators=ALL-UNNAMED</arg>
61+
<arg>--add-exports</arg>
62+
<arg>jdk.internal.vm.compiler/org.graalvm.compiler.graph=ALL-UNNAMED</arg>
63+
<arg>--add-exports</arg>
64+
<arg>jdk.internal.vm.compiler/org.graalvm.compiler.core.common=ALL-UNNAMED</arg>
65+
<arg>--add-exports</arg>
66+
<arg>jdk.internal.vm.compiler/org.graalvm.compiler.nodes.java=ALL-UNNAMED</arg>
67+
<arg>--add-exports</arg>
68+
<arg>jdk.internal.vm.compiler/org.graalvm.compiler.nodes.cfg=ALL-UNNAMED</arg>
69+
</compilerArgs>
70+
</configuration>
71+
</plugin>
72+
<plugin>
73+
<groupId>org.apache.maven.plugins</groupId>
74+
<artifactId>maven-surefire-plugin</artifactId>
75+
<configuration>
76+
<argLine>-XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI
77+
--add-modules jdk.internal.vm.ci
78+
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.hotspot=ALL-UNNAMED
79+
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.meta=ALL-UNNAMED
80+
--add-exports=jdk.internal.vm.compiler/org.graalvm.compiler.debug=ALL-UNNAMED
81+
--add-exports=jdk.internal.vm.compiler/org.graalvm.compiler.hotspot=ALL-UNNAMED
82+
--add-exports=jdk.internal.vm.compiler/org.graalvm.compiler.nodes=ALL-UNNAMED
83+
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.runtime=ALL-UNNAMED
84+
--add-exports=jdk.internal.vm.compiler/org.graalvm.compiler.nodes.graphbuilderconf=ALL-UNNAMED
85+
--add-exports=jdk.internal.vm.compiler/org.graalvm.compiler.phases=ALL-UNNAMED
86+
--add-exports=jdk.internal.vm.compiler/org.graalvm.compiler.java=ALL-UNNAMED
87+
--add-exports=jdk.internal.vm.compiler/org.graalvm.compiler.graph.iterators=ALL-UNNAMED
88+
--add-exports=jdk.internal.vm.compiler/org.graalvm.compiler.options=ALL-UNNAMED
89+
--add-exports=jdk.internal.vm.compiler/org.graalvm.compiler.graph=ALL-UNNAMED
90+
--add-exports=jdk.internal.vm.compiler/org.graalvm.compiler.core.common=ALL-UNNAMED
91+
--add-exports=jdk.internal.vm.compiler/org.graalvm.compiler.nodes.java=ALL-UNNAMED
92+
--add-exports=jdk.internal.vm.compiler/org.graalvm.compiler.nodes.cfg=ALL-UNNAMED
93+
</argLine>
94+
</configuration>
95+
96+
</plugin>
97+
</plugins>
98+
</build>
99+
<dependencies>
100+
<dependency>
101+
<groupId>org.apache.teaclave.javasdk</groupId>
102+
<artifactId>common</artifactId>
103+
</dependency>
104+
<dependency>
105+
<groupId>junit</groupId>
106+
<artifactId>junit</artifactId>
107+
<version>4.13.2</version>
108+
<scope>test</scope>
109+
</dependency>
110+
<dependency>
111+
<groupId>junit</groupId>
112+
<artifactId>junit</artifactId>
113+
<version>4.12</version>
114+
<scope>test</scope>
115+
</dependency>
116+
</dependencies>
117+
</project>
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.apache.teaclave.javasdk.tool.optimize;
19+
20+
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
21+
import jdk.vm.ci.meta.MetaAccessProvider;
22+
import jdk.vm.ci.meta.ResolvedJavaMethod;
23+
import jdk.vm.ci.meta.ResolvedJavaType;
24+
import org.apache.teaclave.javasdk.common.annotations.EnclaveService;
25+
import org.graalvm.collections.EconomicMap;
26+
import org.graalvm.compiler.core.common.CompilationIdentifier;
27+
import org.graalvm.compiler.debug.DebugContext;
28+
import org.graalvm.compiler.graph.NodeSourcePosition;
29+
import org.graalvm.compiler.hotspot.HotSpotGraalCompiler;
30+
import org.graalvm.compiler.java.GraphBuilderPhase;
31+
import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
32+
import org.graalvm.compiler.nodes.StructuredGraph;
33+
import org.graalvm.compiler.nodes.cfg.Block;
34+
import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
35+
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
36+
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
37+
import org.graalvm.compiler.options.OptionKey;
38+
import org.graalvm.compiler.options.OptionValues;
39+
import org.graalvm.compiler.phases.OptimisticOptimizations;
40+
41+
import java.lang.reflect.Method;
42+
import java.util.ArrayDeque;
43+
import java.util.ArrayList;
44+
import java.util.Deque;
45+
import java.util.List;
46+
47+
import static org.graalvm.compiler.debug.DebugOptions.Dump;
48+
49+
public class ECallInLoopDetector {
50+
51+
private static HotSpotGraalCompiler compiler;
52+
private static MetaAccessProvider accessProvider;
53+
private static final boolean DEBUG;
54+
private static OptionValues options;
55+
56+
static {
57+
DEBUG = Boolean.parseBoolean(System.getProperty("optimization.debug", "false"));
58+
HotSpotJVMCIRuntime jvmciRuntime = HotSpotJVMCIRuntime.runtime();
59+
compiler = (HotSpotGraalCompiler) jvmciRuntime.getCompiler();
60+
accessProvider = jvmciRuntime.getHostJVMCIBackend().getMetaAccess();
61+
options = compiler.getGraalRuntime().getOptions();
62+
if (DEBUG) {
63+
Dump.update((EconomicMap<OptionKey<?>, Object>) options.getMap(), ":3");
64+
}
65+
}
66+
67+
/**
68+
* Check if there is Ecall inside loop in the given method. See the test case {@code ECallInLoopDetectorTest} for
69+
* example illustration.
70+
*
71+
* @param m method to check
72+
* @return a list of inside-loop-Ecall positions in the method, empty if none.
73+
*/
74+
public static List<NodeSourcePosition> check(Method m) {
75+
StructuredGraph graph = getGraph(m);
76+
List<NodeSourcePosition> ret = new ArrayList<>();
77+
ControlFlowGraph cfg = ControlFlowGraph.computeForSchedule(graph);
78+
graph.getNodes(InvokeWithExceptionNode.TYPE).forEach(n -> {
79+
Block block = cfg.blockFor(n);
80+
if (block != null && block.getLoop() != null) {
81+
ResolvedJavaMethod method = n.getTargetMethod();
82+
if (isEnclaveService(method.getDeclaringClass())) {
83+
ret.add(n.getNodeSourcePosition());
84+
}
85+
}
86+
});
87+
if (!ret.isEmpty()) {
88+
int len = ret.size();
89+
System.out.println("Detected " + len + " enclave service calls inside loop.");
90+
for (int i = 0; i < len; i++) {
91+
System.out.println((i + 1) + ". " + ret.get(i));
92+
}
93+
}
94+
return ret;
95+
}
96+
97+
private static StructuredGraph getGraph(Method method) {
98+
ResolvedJavaMethod javaMethod = accessProvider.lookupJavaMethod(method);
99+
DebugContext debug = new DebugContext.Builder(options, compiler.getDebugHandlersFactories()).build();
100+
101+
StructuredGraph graph = compiler.createGraph(javaMethod, -1, null,
102+
CompilationIdentifier.INVALID_COMPILATION_ID, options, debug);
103+
try (DebugContext.Scope s = debug.scope("detectECallInLoop", graph)) {
104+
InvocationPlugins plugins = new InvocationPlugins();
105+
GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(new GraphBuilderConfiguration.Plugins(plugins))
106+
.withNodeSourcePosition(true)
107+
.withEagerResolving(true)
108+
.withRetainLocalVariables(true);
109+
110+
GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(compiler.getGraalRuntime().getHostProviders(), graphBuilderConfig, OptimisticOptimizations.NONE, null);
111+
graphBuilder.apply(graph);
112+
if (DEBUG) {
113+
debug.dump(3, graph, "");
114+
}
115+
} catch (Throwable throwable) {
116+
throwable.printStackTrace();
117+
}
118+
return graph;
119+
}
120+
121+
/**
122+
* Scan the entire class hierarchy tree to find if it implements any interface
123+
* annotated with @EnclaveService
124+
*/
125+
private static boolean isEnclaveService(ResolvedJavaType type) {
126+
Deque<ResolvedJavaType> workList = new ArrayDeque<>();
127+
workList.push(type);
128+
while (!workList.isEmpty()) {
129+
ResolvedJavaType top = workList.pop();
130+
if (top.getAnnotation(EnclaveService.class) != null) {
131+
return true;
132+
} else {
133+
for (ResolvedJavaType anInterface : top.getInterfaces()) {
134+
workList.push(anInterface);
135+
}
136+
}
137+
}
138+
return false;
139+
}
140+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.apache.teaclave.javasdk.tool.optimize;
19+
20+
import org.junit.Test;
21+
22+
import java.lang.reflect.Method;
23+
import java.util.List;
24+
25+
import static org.junit.Assert.assertEquals;
26+
27+
public class ECallInLoopDetectorTest {
28+
@Test
29+
public void testReport() throws NoSuchMethodException {
30+
Method m = LoopCase.class.getDeclaredMethod("foo");
31+
List ret = ECallInLoopDetector.check(m);
32+
assertEquals(1, ret.size());
33+
}
34+
35+
@Test
36+
public void testNotReport() throws NoSuchMethodException {
37+
Method m = LoopCase.class.getDeclaredMethod("doSomething");
38+
List ret = ECallInLoopDetector.check(m);
39+
assertEquals(0, ret.size());
40+
}
41+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.apache.teaclave.javasdk.tool.optimize;
19+
20+
import java.util.ServiceLoader;
21+
22+
public class LoopCase {
23+
public void foo() {
24+
ServiceLoader<TestServices.EnclaveServiceExample> exampleLoader = ServiceLoader.load(TestServices.EnclaveServiceExample.class);
25+
TestServices.EnclaveServiceExample example = exampleLoader.findFirst().get();
26+
int max = 100;
27+
int i = 0;
28+
while (i < max) {
29+
example.bar();
30+
i++;
31+
}
32+
}
33+
34+
public void doSomething(){
35+
ServiceLoader<TestServices.NormalServiceExample> exampleLoader = ServiceLoader.load(TestServices.NormalServiceExample.class);
36+
TestServices.NormalServiceExample example = exampleLoader.findFirst().get();
37+
int max = 100;
38+
int i = 0;
39+
while (i < max) {
40+
example.bar();
41+
i++;
42+
}
43+
}
44+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.apache.teaclave.javasdk.tool.optimize;
19+
20+
import org.apache.teaclave.javasdk.common.annotations.EnclaveService;
21+
22+
public class TestServices {
23+
24+
@EnclaveService
25+
public interface EnclaveServiceExample{
26+
void bar();
27+
}
28+
29+
public interface NormalServiceExample{
30+
void bar();
31+
}
32+
33+
}

sdk/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@
154154
<module>common</module>
155155
<module>enclave</module>
156156
<module>host</module>
157+
<module>optimizationDetector</module>
157158
</modules>
158159
<build>
159160
<pluginManagement>

0 commit comments

Comments
 (0)