Skip to content

Commit

Permalink
[Java] speed test codegen speed by avoid duplicate codegen (apache#929)
Browse files Browse the repository at this point in the history
* speed test codegen speed by avoid duplicate codegen

* fix cache

* fix cllass gc

* use a standalone lock for every key

* refine gc trigger

* skip cache for furyGC tests

* fix gc tests

* lint code
  • Loading branch information
chaokunyang committed Oct 3, 2023
1 parent d4cbbe1 commit a1598b8
Show file tree
Hide file tree
Showing 13 changed files with 212 additions and 126 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,9 @@ public void testRecordCompatible(boolean codegen) throws Throwable {
String code1 =
"import java.util.*;"
+ "public record TestRecord(int f1, String f2, List<String> f3, char f4, Map<String, Integer> f5) {}";
Class<?> cls1 = Struct.createStructClass("TestRecord", code1);
Class<?> cls1 =
Struct.createStructClass(
"TestRecord", code1, RecordSerializersTest.class + "testRecordCompatible_1");
Object record1 =
RecordUtils.getRecordConstructor(cls1)
.f1
Expand All @@ -114,7 +116,9 @@ public void testRecordCompatible(boolean codegen) throws Throwable {
String code2 =
"import java.util.*;"
+ "public record TestRecord(int f1, String f2, char f4, Map<String, Integer> f5) {}";
Class<?> cls2 = Struct.createStructClass("TestRecord", code2);
Class<?> cls2 =
Struct.createStructClass(
"TestRecord", code2, RecordSerializersTest.class + "testRecordCompatible_2");
Object record2 =
RecordUtils.getRecordConstructor(cls2).f1.invoke(1, "abc", 'a', ofHashMap("a", 1));
Fury fury2 =
Expand All @@ -134,7 +138,9 @@ public void testRecordMetaShare(boolean codegen) throws Throwable {
String code1 =
"import java.util.*;"
+ "public record TestRecord(int f1, String f2, List<String> f3, char f4, Map<String, Integer> f5) {}";
Class<?> cls1 = Struct.createStructClass("TestRecord", code1);
Class<?> cls1 =
Struct.createStructClass(
"TestRecord", code1, RecordSerializersTest.class + "testRecordMetaShare_1");
Object record1 =
RecordUtils.getRecordConstructor(cls1)
.f1
Expand All @@ -150,7 +156,9 @@ public void testRecordMetaShare(boolean codegen) throws Throwable {
String code2 =
"import java.util.*;"
+ "public record TestRecord(String f2, char f4, Map<String, Integer> f5) {}";
Class<?> cls2 = Struct.createStructClass("TestRecord", code2);
Class<?> cls2 =
Struct.createStructClass(
"TestRecord", code2, RecordSerializersTest.class + "testRecordMetaShare_2");
Object record2 =
RecordUtils.getRecordConstructor(cls2).f1.invoke("abc", 'a', ofHashMap("a", 1));
Fury fury2 =
Expand Down
4 changes: 2 additions & 2 deletions java/fury-core/src/test/java/io/fury/FuryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -441,14 +441,14 @@ public void testClassGC() {
TestUtils.triggerOOMForSoftGC(
() -> {
System.out.printf("Wait map keys %s gc.\n", map.keySet());
return map.size() > 0;
return !map.isEmpty();
});
Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
}

private void furyGC(WeakHashMap<Object, Boolean> map) {
Fury fury = Fury.builder().requireClassRegistration(false).build();
Class<?> structClass1 = Struct.createStructClass("TestClassGC", 1);
Class<?> structClass1 = Struct.createStructClass("TestClassGC", 1, false);
System.out.println(structClass1.hashCode());
Object struct1 = Struct.createPOJO(structClass1);
serDe(fury, struct1);
Expand Down
26 changes: 17 additions & 9 deletions java/fury-core/src/test/java/io/fury/TestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,24 +45,32 @@ public static <K, V> ImmutableMap<K, V> mapOf(K k1, V v1) {
* @param predicate whether stop Trigger OOM.
*/
public static void triggerOOMForSoftGC(Supplier<Boolean> predicate) {
System.gc();
while (predicate.get()) {
// Force an OoM
triggerOOM();
System.gc();
System.out.printf("Wait gc.");
try {
Thread.sleep(50);
} catch (InterruptedException e1) {
throw new RuntimeException(e1);
}
}
}

private static void triggerOOM() {
while (true) {
// Force an OOM
try {
final ArrayList<Object[]> allocations = new ArrayList<>();
int size;
while ((size =
Math.min(Math.abs((int) Runtime.getRuntime().freeMemory()), Integer.MAX_VALUE))
> 0) allocations.add(new Object[size]);
} catch (OutOfMemoryError e) {
System.out.println("Trigger OOM to clear LoaderBinding.furySoftMap soft references.");
System.out.println("Met OOM.");
break;
}
System.gc();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.printf("Wait gc.");
}
}
}
29 changes: 11 additions & 18 deletions java/fury-core/src/test/java/io/fury/ThreadSafeFuryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import io.fury.test.bean.BeanA;
import io.fury.test.bean.Struct;
import io.fury.util.LoaderBinding.StagingType;
import java.util.ArrayList;
import java.util.WeakHashMap;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
Expand Down Expand Up @@ -224,29 +223,23 @@ public void testClassDuplicateName(StagingType staging) {
public void testClassGC() throws Exception {
// Can't inline `generateClassForGC` in current method, generated classes won't be gc.
WeakHashMap<Class<?>, Boolean> map = generateClassForGC();
while (map.size() > 0) {
// Force an OoM
try {
final ArrayList<Object[]> allocations = new ArrayList<>();
int size;
while ((size =
Math.min(Math.abs((int) Runtime.getRuntime().freeMemory()), Integer.MAX_VALUE))
> 0) allocations.add(new Object[size]);
} catch (OutOfMemoryError e) {
System.out.println("Trigger OOM to clear LoaderBinding.furySoftMap soft references.");
}
System.gc();
Thread.sleep(1000);
System.out.printf("Wait classes %s gc.\n", map.keySet());
}
TestUtils.triggerOOMForSoftGC(
() -> {
if (!map.isEmpty()) {
System.out.printf("Wait classes %s gc.\n", map.keySet());
return true;
} else {
return false;
}
});
}

private WeakHashMap<Class<?>, Boolean> generateClassForGC() {
ThreadSafeFury fury = Fury.builder().requireClassRegistration(false).buildThreadSafeFury();
String className = "DuplicateStruct";
WeakHashMap<Class<?>, Boolean> map = new WeakHashMap<>();
{
Class<?> structClass1 = Struct.createStructClass(className, 1);
Class<?> structClass1 = Struct.createStructClass(className, 1, false);
Object struct1 = Struct.createPOJO(structClass1);
byte[] bytes = fury.serialize(struct1);
Assert.assertEquals(fury.deserialize(bytes), struct1);
Expand All @@ -256,7 +249,7 @@ private WeakHashMap<Class<?>, Boolean> generateClassForGC() {
structClass1.hashCode(), structClass1.getClassLoader().hashCode());
}
{
Class<?> structClass2 = Struct.createStructClass(className, 2);
Class<?> structClass2 = Struct.createStructClass(className, 2, false);
map.put(structClass2, true);
System.out.printf(
"structClass2 %s %s\n ",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ public void genCode(boolean compressNumber) {
// System.out.println(code);
new ObjectCodecBuilder(BeanA.class, fury).genCode();
new ObjectCodecBuilder(BeanB.class, fury).genCode();
new ObjectCodecBuilder(Struct.createStructClass("", 1), fury).genCode();
new ObjectCodecBuilder(Struct.createStructClass("ObjectCodecBuilderTestStruct", 1), fury)
.genCode();
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ public void testJaninoCompiler() throws Exception {
WeakReference<? extends Class<?>> clsRef = new WeakReference<>(compileClassByJaninoCompiler());
while (clsRef.get() != null) {
System.gc();
Thread.sleep(1000);
Thread.sleep(50);
System.out.printf("Wait cls %s gc.\n", clsRef.get());
}
}
Expand Down Expand Up @@ -212,10 +212,10 @@ public Class<?> compileClassByJaninoCompiler() throws Exception {
@Test
public void testJaninoCompileDependentClass() throws Exception {
WeakReference<? extends Class<?>> clsRef =
janinoCompileDependentClass(Struct.createStructClass("A", 1));
janinoCompileDependentClass(Struct.createStructClass("A", 1, false));
while (clsRef.get() != null) {
System.gc();
Thread.sleep(1000);
Thread.sleep(10);
System.out.printf("Wait cls %s gc.\n", clsRef.get());
}
}
Expand Down Expand Up @@ -287,10 +287,9 @@ public void testGetClassStats() {
@Test(timeOut = 60000)
public void testJaninoGeneratedClassGC() throws InterruptedException {
WeakReference<Class<?>> clsRef = janinoGenerateClass();
;
while (clsRef.get() != null) {
System.gc();
Thread.sleep(1000);
Thread.sleep(10);
System.out.printf("Wait cls %s gc.\n", clsRef.get());
}
}
Expand Down Expand Up @@ -322,13 +321,13 @@ public void testJDKGeneratedClassGC() throws InterruptedException {
WeakReference<Class<?>> clsRef = jdkGenerateClass();
while (clsRef.get() != null) {
System.gc();
Thread.sleep(1000);
Thread.sleep(10);
System.out.printf("Wait cls %s gc.\n", clsRef.get());
}
}

private WeakReference<Class<?>> jdkGenerateClass() {
Class<?> cls = Struct.createStructClass("TestGeneratedClassGC", 1);
Class<?> cls = Struct.createStructClass("TestGeneratedClassGC", 1, false);
return new WeakReference<>(cls);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public void testMap() throws Exception {
referencesField.setAccessible(true);
Set<Reference<?>> references = (Set<Reference<?>>) referencesField.get(null);
System.gc();
Thread.sleep(1000);
Thread.sleep(50);
LOG.info("Before references: {}", references);
int size = references.size();
Object o1 = new Object();
Expand All @@ -47,7 +47,7 @@ public void testMap() throws Exception {

// `references` is global and may contain references put by others.
while (references.size() != size) {
Thread.sleep(1000);
Thread.sleep(10);
System.gc();
LOG.info("wait object gc, references: {}", references);
}
Expand Down
12 changes: 8 additions & 4 deletions java/fury-core/src/test/java/io/fury/serializer/ClassUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public static Class<?> createCompatibleClass1() {
+ " private int[][] int2DArray;\n"
+ " private int[][] int2DArray_added;\n"
+ "}";
return loadClass(BeanA.class, code);
return loadClass(BeanA.class, code, ClassUtils.class + "createCompatibleClass1");
}

public static Class<?> createCompatibleClass2() {
Expand All @@ -89,7 +89,7 @@ public static Class<?> createCompatibleClass2() {
+ " public Map<String, String> map2;\n"
+ " public SortedMap<Integer, Integer> sortedMap3;"
+ "}";
return loadClass(CollectionFields.class, code);
return loadClass(CollectionFields.class, code, ClassUtils.class + "createCompatibleClass2");
}

public static Class<?> createCompatibleClass3() {
Expand Down Expand Up @@ -120,10 +120,14 @@ public static Class<?> createCompatibleClass3() {
+ " public Map singletonMap;\n"
+ " public Map<String, Integer> singletonMap2;\n"
+ "}";
return loadClass(MapFields.class, code);
return loadClass(MapFields.class, code, ClassUtils.class + "createCompatibleClass3");
}

static Class<?> loadClass(Class<?> cls, String code) {
static Class<?> loadClass(Class<?> cls, String code, Object cacheKey) {
return Struct.loadClass(cacheKey, () -> compileClass(cls, code));
}

private static Class<?> compileClass(Class<?> cls, String code) {
String pkg = ReflectionUtils.getPackage(cls);
Path path = Paths.get(pkg.replace(".", "/") + "/" + cls.getSimpleName() + ".java");
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,11 @@ public void testWriteCompatibleCollectionBasic(boolean referenceTracking, boolea
+ " private Iterable<BeanB> beanBIterable;\n"
+ " private List<BeanB> beanBList;\n"
+ "}";
Class<?> cls1 = loadClass(BeanA.class, code);
Class<?> cls1 =
loadClass(
BeanA.class,
code,
CodegenCompatibleSerializerTest.class + "testWriteCompatibleCollectionBasic_1");
Fury fury1 =
Fury.builder()
.withLanguage(Language.JAVA)
Expand All @@ -165,7 +169,11 @@ public void testWriteCompatibleCollectionBasic(boolean referenceTracking, boolea
+ " private List<Double> doubleList;\n"
+ " private Iterable<BeanB> beanBIterable;\n"
+ "}";
Class<?> cls2 = loadClass(BeanA.class, code);
Class<?> cls2 =
loadClass(
BeanA.class,
code,
CodegenCompatibleSerializerTest.class + "testWriteCompatibleCollectionBasic_2");
Object newBeanA = cls2.newInstance();
ReflectionUtils.unsafeCopy(beanA, newBeanA);
Fury fury2 =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,8 @@ public static Class<?> createCompatibleClass1() {
+ " private int[][] int2DArray;\n"
+ " private int[][] int2DArray_added;\n"
+ "}";
return ClassUtils.loadClass(BeanA.class, code);
return ClassUtils.loadClass(
BeanA.class, code, CompatibleSerializerTest.class + "createCompatibleClass1");
}

@Test(dataProvider = "referenceTrackingConfig")
Expand Down Expand Up @@ -304,7 +305,8 @@ public static Class<?> createCompatibleClass2() {
+ " public Map<String, String> map2;\n"
+ " public SortedMap<Integer, Integer> sortedMap3;"
+ "}";
return ClassUtils.loadClass(CollectionFields.class, code);
return ClassUtils.loadClass(
CollectionFields.class, code, CompatibleSerializerTest.class + "createCompatibleClass2");
}

@Test(dataProvider = "referenceTrackingConfig")
Expand Down Expand Up @@ -380,7 +382,8 @@ public static Class<?> createCompatibleClass3() {
+ " public Map singletonMap;\n"
+ " public Map<String, Integer> singletonMap2;\n"
+ "}";
return ClassUtils.loadClass(MapFields.class, code);
return ClassUtils.loadClass(
MapFields.class, code, CompatibleSerializerTest.class + "createCompatibleClass3");
}

@Test(dataProvider = "compressNumber")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,11 @@ public void testWriteCompatibleCollectionBasic(
+ " private Iterable<BeanB> beanBIterable;\n"
+ " private List<BeanB> beanBList;\n"
+ "}";
Class<?> cls1 = loadClass(BeanA.class, code);
Class<?> cls1 =
loadClass(
BeanA.class,
code,
MetaSharedCompatibleTest.class + "testWriteCompatibleCollectionBasic_1");
Fury fury1 =
Fury.builder()
.withLanguage(Language.JAVA)
Expand All @@ -237,7 +241,11 @@ public void testWriteCompatibleCollectionBasic(
+ " private List<Double> doubleList;\n"
+ " private Iterable<BeanB> beanBIterable;\n"
+ "}";
Class<?> cls2 = loadClass(BeanA.class, code);
Class<?> cls2 =
loadClass(
BeanA.class,
code,
MetaSharedCompatibleTest.class + "testWriteCompatibleCollectionBasic_2");
Object o2 = cls2.newInstance();
ReflectionUtils.unsafeCopy(beanA, o2);
Fury fury2 =
Expand Down
Loading

0 comments on commit a1598b8

Please sign in to comment.