Skip to content

Commit 1ce0c1f

Browse files
committed
Add host proxy benchmarks.
1 parent b224dfa commit 1ce0c1f

File tree

2 files changed

+417
-0
lines changed

2 files changed

+417
-0
lines changed
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package org.graalvm.truffle.benchmark.interop;
42+
43+
import org.graalvm.polyglot.Context;
44+
import org.graalvm.polyglot.Engine;
45+
import org.graalvm.polyglot.Value;
46+
import org.graalvm.polyglot.proxy.ProxyArray;
47+
import org.graalvm.polyglot.proxy.ProxyExecutable;
48+
import org.graalvm.polyglot.proxy.ProxyObject;
49+
import org.graalvm.truffle.benchmark.TruffleBenchmark;
50+
import org.openjdk.jmh.annotations.Benchmark;
51+
import org.openjdk.jmh.annotations.OperationsPerInvocation;
52+
import org.openjdk.jmh.annotations.Scope;
53+
import org.openjdk.jmh.annotations.State;
54+
import org.openjdk.jmh.annotations.TearDown;
55+
import org.openjdk.jmh.annotations.Warmup;
56+
57+
/**
58+
* Benchmark designed to measure the guest to host compiled performance for polyglot proxies.
59+
* Interpreter-only numbers are not useful for this benchmark as it uses the ReflectionLibrary to
60+
* call.
61+
*/
62+
@Warmup(iterations = 5, time = 1)
63+
public class HostProxyBenchmark extends TruffleBenchmark {
64+
65+
public static final String TEST_LANGUAGE = HostProxyBenchmarkLanguage.ID;
66+
public static final int INNER_LOOP = 100;
67+
68+
@Benchmark
69+
@OperationsPerInvocation(INNER_LOOP)
70+
public void arrayRead(ProxyArrayState state) {
71+
state.arrayRead.executeVoid();
72+
}
73+
74+
@Benchmark
75+
@OperationsPerInvocation(INNER_LOOP)
76+
public void arrayWrite(ProxyArrayState state) {
77+
state.arrayWrite.executeVoid();
78+
}
79+
80+
@Benchmark
81+
@OperationsPerInvocation(INNER_LOOP)
82+
public void arrayGetSize(ProxyArrayState state) {
83+
state.arrayGetSize.executeVoid();
84+
}
85+
86+
@Benchmark
87+
@OperationsPerInvocation(INNER_LOOP)
88+
public void executableExecute(ProxyArrayState state) {
89+
state.executableExecute.executeVoid();
90+
}
91+
92+
@Benchmark
93+
@OperationsPerInvocation(INNER_LOOP)
94+
public void objectPutMember(ProxyArrayState state) {
95+
state.objectPutMember.executeVoid();
96+
}
97+
98+
@Benchmark
99+
@OperationsPerInvocation(INNER_LOOP)
100+
public void objectHasMember(ProxyArrayState state) {
101+
state.objectHasMember.executeVoid();
102+
}
103+
104+
@Benchmark
105+
@OperationsPerInvocation(INNER_LOOP)
106+
public void objectGetKeys(ProxyArrayState state) {
107+
state.objectGetMemberKeys.executeVoid();
108+
}
109+
110+
@Benchmark
111+
@OperationsPerInvocation(INNER_LOOP)
112+
public void objectGetMember(ProxyArrayState state) {
113+
state.objectGetMember.executeVoid();
114+
}
115+
116+
static final class BenchmarkProxyObject implements ProxyObject {
117+
Object foo = "bar";
118+
Object bar = "baz";
119+
120+
public void putMember(String key, Value value) {
121+
switch (key) {
122+
case "foo":
123+
this.foo = value;
124+
return;
125+
case "bar":
126+
this.bar = value;
127+
return;
128+
}
129+
throw new UnsupportedOperationException();
130+
}
131+
132+
public boolean hasMember(String key) {
133+
switch (key) {
134+
case "foo":
135+
case "bar":
136+
return true;
137+
}
138+
return false;
139+
}
140+
141+
public Object getMemberKeys() {
142+
return new ProxyArray() {
143+
private static final Object[] KEYS = new Object[]{"foo", "bar"};
144+
145+
public void set(long index, Value value) {
146+
throw new UnsupportedOperationException();
147+
}
148+
149+
public long getSize() {
150+
return KEYS.length;
151+
}
152+
153+
public Object get(long index) {
154+
if (index < 0 || index > Integer.MAX_VALUE) {
155+
throw new ArrayIndexOutOfBoundsException();
156+
}
157+
return KEYS[(int) index];
158+
}
159+
160+
};
161+
}
162+
163+
public Object getMember(String key) {
164+
switch (key) {
165+
case "foo":
166+
return this.foo;
167+
case "bar":
168+
return this.bar;
169+
}
170+
throw new UnsupportedOperationException();
171+
}
172+
173+
}
174+
175+
static final class BenchmarkProxyArray implements ProxyArray {
176+
177+
private final Object[] values;
178+
179+
BenchmarkProxyArray(Object[] values) {
180+
this.values = values;
181+
}
182+
183+
public Object get(long index) {
184+
int intIndex = coerceIndex(index);
185+
return values[intIndex];
186+
}
187+
188+
public void set(long index, Value value) {
189+
int intIndex = coerceIndex(index);
190+
values[intIndex] = value;
191+
}
192+
193+
private static int coerceIndex(long index) {
194+
int intIndex = (int) index;
195+
if (intIndex != index || intIndex < 0) {
196+
throw new ArrayIndexOutOfBoundsException("invalid index.");
197+
}
198+
return intIndex;
199+
}
200+
201+
public long getSize() {
202+
return values.length;
203+
}
204+
}
205+
206+
@State(Scope.Benchmark)
207+
public static class ProxyArrayState {
208+
final Context context;
209+
final Engine engine;
210+
211+
final Value arrayRead;
212+
final Value arrayWrite;
213+
final Value arrayGetSize;
214+
215+
final Value executableExecute;
216+
217+
final Value objectPutMember;
218+
final Value objectHasMember;
219+
final Value objectGetMemberKeys;
220+
final Value objectGetMember;
221+
222+
public ProxyArrayState() {
223+
engine = Engine.newBuilder(TEST_LANGUAGE).allowExperimentalOptions(true).build();
224+
context = Context.newBuilder(TEST_LANGUAGE).engine(engine).allowExperimentalOptions(true).build();
225+
context.enter();
226+
Value bind = context.eval(HostProxyBenchmarkLanguage.ID, "");
227+
ProxyArray proxyArray = new BenchmarkProxyArray(new Object[]{"0", "42", "1"});
228+
this.arrayRead = bind.execute(proxyArray, "readArrayElement", new Object[]{1L});
229+
this.arrayWrite = bind.execute(proxyArray, "writeArrayElement", new Object[]{1L, "42"});
230+
this.arrayGetSize = bind.execute(proxyArray, "getArraySize", new Object[]{});
231+
232+
ProxyExecutable executable = (arguments) -> arguments[1];
233+
this.executableExecute = bind.execute(executable, "execute", new Object[]{new Object[]{1L, "42"}});
234+
ProxyObject proxyObject = new BenchmarkProxyObject();
235+
236+
this.objectPutMember = bind.execute(proxyObject, "writeMember", new Object[]{"foo", "bar"});
237+
this.objectHasMember = bind.execute(proxyObject, "isMemberReadable", new Object[]{"bar"});
238+
this.objectGetMemberKeys = bind.execute(proxyObject, "getMembers", new Object[]{false});
239+
this.objectGetMember = bind.execute(proxyObject, "readMember", new Object[]{"bar"});
240+
}
241+
242+
@TearDown
243+
public void tearDown() {
244+
context.close();
245+
}
246+
}
247+
248+
}

0 commit comments

Comments
 (0)