Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to latest version and some cleanups. #8

Merged
merged 4 commits into from
May 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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