Skip to content

Commit

Permalink
perf(java): optimize pojo copy performance (#1739)
Browse files Browse the repository at this point in the history
## What does this PR do?
 optimize pojo copy performance by 1~4X and add copy benchmark

## Related issues

<!--
Is there any related issue? Please attach here.

- #xxxx0
- #xxxx1
- #xxxx2
-->


## Does this PR introduce any user-facing change?

<!--
If any user-facing interface changes, please [open an
issue](https://github.com/apache/fury/issues/new/choose) describing the
need to do so and update the document if necessary.
-->

- [ ] Does this PR introduce any public API change?
- [ ] Does this PR introduce any binary protocol compatibility change?


## Benchmark

Before:
```java
Benchmark                (bufferType)   (objectType)  (references)   Mode  Cnt        Score         Error  Units
CopyBenchmark.fury_copy         array  MEDIA_CONTENT         false  thrpt    3  1294614.644 ± 2103796.392  ops/s
CopyBenchmark.fury_copy         array         SAMPLE         false  thrpt    3  1909071.799 ± 2343118.356  ops/s
CopyBenchmark.fury_copy         array         STRUCT         false  thrpt    3  1220680.635 ± 1019806.837  ops/s
CopyBenchmark.fury_copy         array        STRUCT2         false  thrpt    3   584429.541 ±  111229.502  ops/s
CopyBenchmark.kryo_copy         array  MEDIA_CONTENT         false  thrpt    3  1008490.635 ±  309047.316  ops/s
CopyBenchmark.kryo_copy         array         SAMPLE         false  thrpt    3   921863.274 ± 1082442.180  ops/s
CopyBenchmark.kryo_copy         array         STRUCT         false  thrpt    3  1336939.990 ±  795836.830  ops/s
CopyBenchmark.kryo_copy         array        STRUCT2         false  thrpt    3   168367.000 ±  236966.711  ops/s
```

Java
```java
Benchmark                (bufferType)   (objectType)  (references)   Mode  Cnt        Score         Error  Units
CopyBenchmark.fury_copy         array  MEDIA_CONTENT         false  thrpt    3  2201830.808 ± 4640532.805  ops/s
CopyBenchmark.fury_copy         array         SAMPLE         false  thrpt    3  4945272.027 ± 5429361.187  ops/s
CopyBenchmark.fury_copy         array         STRUCT         false  thrpt    3  4809373.970 ± 6803285.896  ops/s
CopyBenchmark.fury_copy         array        STRUCT2         false  thrpt    3  2577391.052 ± 6682601.210  ops/s
CopyBenchmark.kryo_copy         array  MEDIA_CONTENT         false  thrpt    3   830059.189 ± 2509547.599  ops/s
CopyBenchmark.kryo_copy         array         SAMPLE         false  thrpt    3   696901.072 ±  525070.309  ops/s
CopyBenchmark.kryo_copy         array         STRUCT         false  thrpt    3   980635.311 ± 2495689.418  ops/s
CopyBenchmark.kryo_copy         array        STRUCT2         false  thrpt    3   141996.627 ±  343339.930  ops/s
```
  • Loading branch information
chaokunyang authored Jul 20, 2024
1 parent 64c995d commit 5e0b8a9
Show file tree
Hide file tree
Showing 6 changed files with 396 additions and 207 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.fury.benchmark;

import java.io.IOException;
import org.apache.fury.benchmark.state.FuryState;
import org.apache.fury.benchmark.state.KryoState;
import org.openjdk.jmh.Main;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.CompilerControl;
import org.openjdk.jmh.annotations.Mode;

@BenchmarkMode(Mode.Throughput)
@CompilerControl(value = CompilerControl.Mode.INLINE)
public class CopyBenchmark {

@Benchmark
public Object fury_copy(FuryState.FuryUserTypeState state) {
return state.fury.copy(state.object);
}

@Benchmark
public Object kryo_copy(KryoState.KryoUserTypeState state) {
return state.kryo.copy(state.object);
}

public static void main(String[] args) throws IOException {
if (args.length == 0) {
String commandLine =
"org.apache.fury.*CopyBenchmark.* -f 1 -wi 3 -i 3 -t 1 -w 2s -r 2s -rf csv "
+ "-p bufferType=array -p references=false";
System.out.println(commandLine);
args = commandLine.split(" ");
}
Main.main(args);
}
}
49 changes: 38 additions & 11 deletions java/fury-core/src/main/java/org/apache/fury/Fury.java
Original file line number Diff line number Diff line change
Expand Up @@ -1273,14 +1273,6 @@ public <T> T copyObject(T obj) {
Object copy;
ClassInfo classInfo = classResolver.getOrUpdateClassInfo(obj.getClass());
switch (classInfo.getClassId()) {
case ClassResolver.BOOLEAN_CLASS_ID:
case ClassResolver.BYTE_CLASS_ID:
case ClassResolver.CHAR_CLASS_ID:
case ClassResolver.SHORT_CLASS_ID:
case ClassResolver.INTEGER_CLASS_ID:
case ClassResolver.FLOAT_CLASS_ID:
case ClassResolver.LONG_CLASS_ID:
case ClassResolver.DOUBLE_CLASS_ID:
case ClassResolver.PRIMITIVE_BOOLEAN_CLASS_ID:
case ClassResolver.PRIMITIVE_BYTE_CLASS_ID:
case ClassResolver.PRIMITIVE_CHAR_CLASS_ID:
Expand All @@ -1289,6 +1281,14 @@ public <T> T copyObject(T obj) {
case ClassResolver.PRIMITIVE_FLOAT_CLASS_ID:
case ClassResolver.PRIMITIVE_LONG_CLASS_ID:
case ClassResolver.PRIMITIVE_DOUBLE_CLASS_ID:
case ClassResolver.BOOLEAN_CLASS_ID:
case ClassResolver.BYTE_CLASS_ID:
case ClassResolver.CHAR_CLASS_ID:
case ClassResolver.SHORT_CLASS_ID:
case ClassResolver.INTEGER_CLASS_ID:
case ClassResolver.FLOAT_CLASS_ID:
case ClassResolver.LONG_CLASS_ID:
case ClassResolver.DOUBLE_CLASS_ID:
case ClassResolver.STRING_CLASS_ID:
return obj;
case ClassResolver.PRIMITIVE_BOOLEAN_ARRAY_CLASS_ID:
Expand Down Expand Up @@ -1319,22 +1319,49 @@ public <T> T copyObject(T obj) {
String[] stringArr = (String[]) obj;
return (T) Arrays.copyOf(stringArr, stringArr.length);
case ClassResolver.ARRAYLIST_CLASS_ID:
copyDepth++;
copy = arrayListSerializer.copy((ArrayList) obj);
break;
case ClassResolver.HASHMAP_CLASS_ID:
copyDepth++;
copy = hashMapSerializer.copy((HashMap) obj);
break;
// todo: add fastpath for other types.
default:
copyDepth++;
copy = classInfo.getSerializer().copy(obj);
copyDepth--;
}
copyDepth--;
return (T) copy;
}

public <T> T copyObject(T obj, int classId) {
if (obj == null) {
return null;
}
// Fast path to avoid cost of query class map.
switch (classId) {
case ClassResolver.PRIMITIVE_BOOLEAN_CLASS_ID:
case ClassResolver.PRIMITIVE_BYTE_CLASS_ID:
case ClassResolver.PRIMITIVE_CHAR_CLASS_ID:
case ClassResolver.PRIMITIVE_SHORT_CLASS_ID:
case ClassResolver.PRIMITIVE_INT_CLASS_ID:
case ClassResolver.PRIMITIVE_FLOAT_CLASS_ID:
case ClassResolver.PRIMITIVE_LONG_CLASS_ID:
case ClassResolver.PRIMITIVE_DOUBLE_CLASS_ID:
case ClassResolver.BOOLEAN_CLASS_ID:
case ClassResolver.BYTE_CLASS_ID:
case ClassResolver.CHAR_CLASS_ID:
case ClassResolver.SHORT_CLASS_ID:
case ClassResolver.INTEGER_CLASS_ID:
case ClassResolver.FLOAT_CLASS_ID:
case ClassResolver.LONG_CLASS_ID:
case ClassResolver.DOUBLE_CLASS_ID:
case ClassResolver.STRING_CLASS_ID:
return obj;
default:
return (T) classResolver.getOrUpdateClassInfo(obj.getClass()).getSerializer().copy(obj);
}
}

/**
* Track ref for copy.
*
Expand Down
Loading

0 comments on commit 5e0b8a9

Please sign in to comment.