Skip to content

Commit

Permalink
Update to latest version and some cleanups. (#8)
Browse files Browse the repository at this point in the history
* Update to latest version and some cleanups.

- Update to latest versions of dependencies
- Add upickle to benchmarks
- Some tweaks to proto serialization (caching size, utf8, etc.)

* Regenerate automated files/headers

* bump to working versions of temurin

* Actually regnereate gha files
  • Loading branch information
jsuereth committed May 20, 2023
1 parent e4e794b commit b112203
Show file tree
Hide file tree
Showing 27 changed files with 451 additions and 72 deletions.
46 changes: 32 additions & 14 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ name: Continuous Integration

on:
pull_request:
branches: ['*']
branches: ['**']
push:
branches: ['*']
branches: ['**']

env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -22,19 +22,28 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
scala: [3.0.0]
java: [adopt@1.8, adopt@1.11]
scala: [3.2.2]
java: [temurin@17.0, temurin@11.0]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout current branch (full)
uses: actions/checkout@v2
with:
fetch-depth: 0

- name: Setup Java and Scala
uses: olafurpg/setup-scala@v10
- name: Setup Java (temurin@17.0)
if: matrix.java == 'temurin@17.0'
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java }}
distribution: temurin
java-version: 17.0

- name: Setup Java (temurin@11.0)
if: matrix.java == 'temurin@11.0'
uses: actions/setup-java@v2
with:
distribution: temurin
java-version: 11.0

- name: Cache sbt
uses: actions/cache@v2
Expand All @@ -57,23 +66,32 @@ jobs:
publish:
name: Publish Artifacts
needs: [build]
if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/master')
if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/main')
strategy:
matrix:
os: [ubuntu-latest]
scala: [3.0.0]
java: [adopt@1.8]
scala: [3.2.2]
java: [temurin@17.0]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout current branch (full)
uses: actions/checkout@v2
with:
fetch-depth: 0

- name: Setup Java and Scala
uses: olafurpg/setup-scala@v10
- name: Setup Java (temurin@17.0)
if: matrix.java == 'temurin@17.0'
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java }}
distribution: temurin
java-version: 17.0

- name: Setup Java (temurin@11.0)
if: matrix.java == 'temurin@11.0'
uses: actions/setup-java@v2
with:
distribution: temurin
java-version: 11.0

- name: Cache sbt
uses: actions/cache@v2
Expand All @@ -85,4 +103,4 @@ jobs:
~/.cache/coursier/v1
~/AppData/Local/Coursier/Cache/v1
~/Library/Caches/Coursier/v1
key: ${{ runner.os }}-sbt-cache-v2-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }}
key: ${{ runner.os }}-sbt-cache-v2-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }}
2 changes: 1 addition & 1 deletion .github/workflows/clean.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,4 @@ jobs:
printf "Deleting '%s' #%d, %'d bytes\n" $name ${ARTCOUNT[$name]} $size
ghapi -X DELETE $REPO/actions/artifacts/$id
done
done
done
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
target/
.bloop/
.metals/
_site/
.idea/
.bsp/
_site/
.vscode/
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ Latest status/analysis can be found in the [benchmarks directory](benchmarks/lat
- [X] Kryo
- [ ] Thrift
- [ ] Circe
- [ ] uPickle
- [X] uPickle
- [ ] Automatic well-formatted graph dump in Markdown of results.


Expand Down
32 changes: 30 additions & 2 deletions benchmarks/latest-results.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Our goal is to:
code generation for Java *and* conventional/common
usage does not match Java's usage.


## Full Results (2020-03-05)

*Test #1 - Nested messages + primitive collections*
Expand Down Expand Up @@ -49,7 +50,7 @@ numbers from the naive implementation into something ready-for-production.
- [X] Split apart `RawBinaryPickleReader.push` (7.4%)
- [ ] Attempt to remove the crazy amount of boxing/unboxing we have w/ Primitives (2.5%)
- [ ] Erase PrimitiveBuilders in codegen of `Buildable.derived[T]`
- [ ] Add direct un-boxed signatures for putPrimitive.
- [X] Add direct un-boxed signatures for putPrimitive.
- [ ] Figure out if `Mirror.ProductOf[T]#fromProduct` could be more efficient. (2.9%)
- [X] Support compressed repeated fields in PB format
- [ ] Add size-hint to `CollectionBuilder`
Expand Down Expand Up @@ -260,4 +261,31 @@ of fields on a given structure. Additionally, we see a lot of overhead on boxin
[info] 1.4% 2.9% scala.deriving$.productElement
[info] 1.1% 2.3% sauerkraut.benchmarks.generated.RawBinaryBenchmarks_writeAndReadSimpleMessage_jmhTest.writeAndReadSimpleMessage_avgt_jmhStub
[info] 7.7% 15.4% <other>
```
```

## Write Results (2023-05-19)

Test - Sauerkraut vs. upickle

| Framework | Format | ByteSize | Write (ns / op) | Read ( ns / op) |
| --------- | --------- | -------- | ----------------- | ---------------- |
| Sauerkraut | proto | 165 | 1258.493 | |
| Sauerkraut | json | 5875 | 3538.085 | |
| upickle | msgpack | 4775 | 832.646 | |
| upickle | json | 6075 | 2803.192 | |

A few notes:

- upickle JSON uses MORE bytes than sauerkraut, need to investigate what these are used for.
- upickle JSON vendors jackson-fast for rendering JSON more efficiently
- Sauerkraut collection "visiting" appears to be a major slowdown.
upickle directly models Array[Byte] and uses while loops for collection looping.
- upickle msgpack (binary) serializes very quickly, but is almost as large as sauerkraut JSON.
- This includes some optimisations in proto to memoize size calculations and String->UTF-8 byte conversion.

Areas to investigate:

- [ ] Vendor some better JSON serialization code from faster-json, like upickle does
- [ ] Model particularly slow (but important) types directly in visitors
- [ ] Look at some byte / charset conversion shenanigans in upickle
- [ ] Add msgpack as viable format in Sauerkraut
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ import scala.collection.mutable.ArrayBuffer

// -- Saurkraut Classes --
case class SimpleMessage(value: Int @Field(2), message: String @Field(1))
derives Writer, Buildable
derives Writer, Buildable, upickle.default.ReadWriter
case class LargerMessage(
messages: ArrayBuffer[SimpleMessage] @Field(1),
otherNums: ArrayBuffer[Double] @Field(2),
ints: ArrayBuffer[Long] @Field(3)
) derives Writer, Buildable
) derives Writer, Buildable, upickle.default.ReadWriter

// -- Java framework classes --
class JavaSimpleMessage {
Expand Down Expand Up @@ -150,6 +150,22 @@ object JavaSerializationBenchmarks extends SauerkrautBenchmarkConfig:
out.writeObject(value)
out.flush()

/** Uses UPickle -> msgpack serialization. */
object UPickleBinarySerializationBenchmarks extends SauerkrautBenchmarkConfig:
override val name: String = "upickle_binary_msgpack"
override def load(store: ByteBuffer): LargerMessage =
upickle.default.readBinary[LargerMessage](store.in)
override def save(value: LargerMessage, store: ByteBuffer): Unit =
upickle.default.writeBinaryTo(value, store.out)

/** Uses UPickle -> json serialization. */
object UPickleJsonSerializationBenchmarks extends SauerkrautBenchmarkConfig:
override val name: String = "upickle_json"
override def load(store: ByteBuffer): LargerMessage =
upickle.default.read[LargerMessage](ujson.Readable.fromByteBuffer(store))
override def save(value: LargerMessage, store: ByteBuffer): Unit =
upickle.default.writeJs(value).writeBytesTo(store.out)

object KryoSerializationBenchmarks extends BenchmarkConfig[JavaLargerMessage]:
private val kryo = com.esotericsoftware.kryo.Kryo()
kryo.setRegistrationRequired(false)
Expand Down Expand Up @@ -196,6 +212,8 @@ val benchmarkConfigs = Set(
SauerkrautNbtBenchmarkConfig,
SauerkrautProtoBenchmarkConfig,
// Competitor frameworks
UPickleBinarySerializationBenchmarks,
UPickleJsonSerializationBenchmarks,
JavaSerializationBenchmarks,
ProtocolBufferBenchmarkConfig,
KryoSerializationBenchmarks)
Expand All @@ -206,7 +224,8 @@ val benchmarkConfigs = Set(
class ReadBenchmarks:
private var config: BenchmarkConfig[?] = null
private var buffer = ByteBuffer.allocate(1024*1024)
@Param(Array("proto", "nbt", "json", "xml", "java_pb", "java_ser", "java_kryo"))
// @Param(Array("proto", "nbt", "json", "xml", "java_pb", "java_ser", "java_kryo"))
@Param(Array("proto", "json", "upickle_binary_msgpack", "upickle_json"))
var configName: String = null;
@Setup(Level.Invocation) def setUp(): Unit =
config = benchmarkConfigs.find(_.name == configName).get
Expand All @@ -223,7 +242,8 @@ class ReadBenchmarks:
class WriteBenchmarks:
private var config: BenchmarkConfig[?] = null
private var buffer = ByteBuffer.allocate(1024*1024)
@Param(Array("proto", "nbt", "json", "xml", "java_pb", "java_ser", "java_kryo"))
// @Param(Array("proto", "nbt", "json", "xml", "java_pb", "java_ser", "java_kryo"))
@Param(Array("proto", "json", "upickle_binary_msgpack", "upickle_json"))
var configName: String = null;
@Setup(Level.Invocation) def setUp(): Unit =
config = benchmarkConfigs.find(_.name == configName).get
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Google
* Copyright 2019 Google
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
16 changes: 9 additions & 7 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import com.typesafe.sbt.license.{DepModuleInfo}
import sbtlicensereport.license.{DepModuleInfo}
import sbtghactions.JavaSpec


val Deps = new {
val protobufJava = "com.google.protobuf" % "protobuf-java" % "3.17.1"
val jawnAst = "org.typelevel" %% "jawn-ast" % "1.1.2"
val junit = "junit" % "junit" % "4.11"
val easyMock = "org.easymock" % "easymock" % "4.3"
val protobufJava = "com.google.protobuf" % "protobuf-java" % "3.23.1"
val jawnAst = "org.typelevel" %% "jawn-ast" % "1.4.0"
val junit = "junit" % "junit" % "4.13.2"
val easyMock = "org.easymock" % "easymock" % "5.1.0"
}

val commonSettings: Seq[Setting[_]] = Seq(
Expand All @@ -32,8 +33,8 @@ val commonSettings: Seq[Setting[_]] = Seq(
ThisBuild / githubWorkflowPublish := Nil
ThisBuild / githubWorkflowArtifactUpload := false
// ThisBuild / githubWorkflowScalaVersions := Seq(dottyVersion)
ThisBuild / githubWorkflowJavaVersions := Seq("adopt@1.8", "adopt@1.11")
ThisBuild / scalaVersion := "3.0.0"
ThisBuild / githubWorkflowJavaVersions := Seq(JavaSpec.temurin("17.0"), JavaSpec.temurin("11.0"))
ThisBuild / scalaVersion := "3.2.2"
ThisBuild / crossScalaVersions := Seq((ThisBuild / scalaVersion).value)
ThisBuild / version := "0.1.0-SNAPSHOT"
ThisBuild / organization := "com.jsuereth.sauerkraut"
Expand Down Expand Up @@ -101,6 +102,7 @@ val benchmarks = project
run / javaOptions += "-Xmx6G",
libraryDependencies += "org.openjdk.jmh" % "jmh-core" % "1.23",
libraryDependencies += "com.esotericsoftware" % "kryo" % "5.0.3",
libraryDependencies += "com.lihaoyi" %% "upickle" % "3.1.0",
ProtobufConfig / protobufRunProtoc := { args =>
com.github.os72.protocjar.Protoc.runProtoc("-v370" +: args.toArray)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ trait ComplianceTests
with PrimitiveComplianceTests
with StructureComplianceTests
with ChoiceComplianceTests
with FieldTests

// TODO - evolution compliance tests
// 1. Field => Option[Field]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2019 Google
*
* Licensed 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 sauerkraut
package format
package testing

import org.junit.Test
import sauerkraut.core.{Buildable, Writer, given}
import scala.collection.mutable.ArrayBuffer

object FieldTests:
// Nested structures with non-standard field numbers
case class SimpleMessage(value: Int @Field(2), message: String @Field(1))
derives Writer, Buildable
case class LargerMessage(
messages: ArrayBuffer[SimpleMessage] @Field(1),
otherNums: ArrayBuffer[Double] @Field(2),
ints: ArrayBuffer[Long] @Field(3)
) derives Writer, Buildable

/** Compliance tests that check serialization using @Field annotation. */
trait FieldTests extends ComplianceTestBase:
@Test def testFieldOutOfOrder(): Unit =
import FieldTests.SimpleMessage
roundTrip(SimpleMessage(231415325, "A test of out of order"))
@Test def testNestedStructureWithFieldNumbers(): Unit =
import FieldTests.{LargerMessage, SimpleMessage}
roundTrip(
LargerMessage(
messages = ArrayBuffer(
SimpleMessage(1124312542, "This is a test of simple byte serialization for us all"),
SimpleMessage(0, ""),
SimpleMessage(-1, "ANother string")),
otherNums = ArrayBuffer(1.0, -0.000001, 1000000000000000.0101010),
ints = ArrayBuffer(1,2,3,4,5,-1,-2,-4,1425,0)
)
)
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,5 @@ trait PrimitiveComplianceTests extends ComplianceTestBase:
@Test def writeString(): Unit =
roundTrip("")
roundTrip("testing")
roundTrip("This is a test of simple byte serialization for us all")

Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ case class StructureOfCollections(
z: List[String]
) derives Writer, Buildable

case class StructureOfPrimitiveCollections(
a: Int,
z: List[Int]
) derives Writer, Buildable

case class Simple(x: String) derives Writer, Buildable

case class StructureOfCollectionOfStructures(
Expand Down Expand Up @@ -81,5 +86,10 @@ trait StructureComplianceTests extends ComplianceTestBase:
4,
List("one", "two", "three")
))
@Test def testStructureOfPrimitiveCollections(): Unit =
roundTrip(StructureOfPrimitiveCollections(
4,
List(1,2,3)
))
@Test def testStructureOfCollectionOfStructures(): Unit =
roundTrip(StructureOfCollectionOfStructures(4, List(Simple("Hi"), Simple("You"))))
2 changes: 1 addition & 1 deletion core/src/main/scala/sauerkraut/annotations.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2021 Google
* Copyright 2019 Google
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
Loading

0 comments on commit b112203

Please sign in to comment.