Skip to content

Commit dcf9ee2

Browse files
authored
Merge pull request #42 from AVSystem/js-size-optimization
JS size optimization
2 parents d53ffca + 3e0915a commit dcf9ee2

File tree

52 files changed

+1248
-823
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1248
-823
lines changed

build.sbt

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ val commonSettings = Seq(
8585
libraryDependencies += compilerPlugin("com.github.ghik" %% "silencer-plugin" % silencerVersion),
8686
libraryDependencies ++= Seq(
8787
"com.github.ghik" %% "silencer-lib" % silencerVersion,
88-
"org.scalatest" %% "scalatest" % scalatestVersion % Test,
89-
"org.scalacheck" %% "scalacheck" % scalacheckVersion % Test,
88+
"org.scalatest" %%% "scalatest" % scalatestVersion % Test,
89+
"org.scalacheck" %%% "scalacheck" % scalacheckVersion % Test,
9090
"org.apache.commons" % "commons-io" % commonsIoVersion % Test,
9191
),
9292
dependencyOverrides += "org.scala-lang.modules" %% "scala-xml" % "1.0.6",
@@ -164,20 +164,19 @@ lazy val `commons-shared` = crossProject.crossType(CrossType.Pure)
164164
.settings(commonSettings: _*)
165165
.jvmSettings(jvmCommonSettings)
166166
.jsSettings(
167-
scalaJSUseMainModuleInitializer in Test := true,
168167
scalacOptions += {
169168
val localDir = (baseDirectory in ThisBuild).value.toURI.toString
170169
val githubDir = "https://raw.githubusercontent.com/AVSystem/scala-commons"
171170
s"-P:scalajs:mapSourceURI:$localDir->$githubDir/v${version.value}/"
172171
},
173-
test := {},
172+
jsEnv := new org.scalajs.jsenv.nodejs.NodeJSEnv(),
174173
fork in Test := false,
175174
)
176175

177176
lazy val `commons-sharedJVM` = `commons-shared`.jvm
178177
lazy val `commons-sharedJS` = `commons-shared`.js
179178

180-
lazy val `commons-core` = project.dependsOn(`commons-macros` % CompileAndTest, `commons-sharedJVM`)
179+
lazy val `commons-core` = project.dependsOn(`commons-macros` % CompileAndTest, `commons-sharedJVM` % CompileAndTest)
181180
.settings(commonSettings: _*)
182181
.settings(jvmCommonSettings: _*)
183182
.settings(

commons-akka/src/main/scala/com/avsystem/commons/rpc/akka/AkkaRPCFramework.scala

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,17 @@ import com.avsystem.commons.serialization.GenCodec
1616
*/
1717
object AkkaRPCFramework extends GetterRPCFramework with ProcedureRPCFramework with FunctionRPCFramework with MonixRPCFramework {
1818
trait RawRPC extends GetterRawRPC with ProcedureRawRPC with FunctionRawRPC with MonixRawRPC
19+
abstract class FullRPCInfo[T] extends BaseFullRPCInfo[T]
1920

20-
override type RawValue = ByteString
21+
type RawValue = ByteString
2122

22-
override type Reader[T] = GenCodec[T]
23-
override type Writer[T] = GenCodec[T]
23+
type Reader[T] = GenCodec[T]
24+
type Writer[T] = GenCodec[T]
25+
type ParamTypeMetadata[T] = DummyImplicit
26+
type ResultTypeMetadata[T] = DummyImplicit
2427

25-
override def read[T: Reader](raw: RawValue): T = GenCodec.read[T](new ByteStringLinearInput(raw))
26-
override def write[T: Writer](value: T): RawValue = {
28+
def read[T: Reader](raw: RawValue): T = GenCodec.read[T](new ByteStringLinearInput(raw))
29+
def write[T: Writer](value: T): RawValue = {
2730
val output = new ByteStringLinearOutput(ByteString.newBuilder)
2831
GenCodec.write[T](output, value)
2932
output.result

commons-akka/src/test/scala/com/avsystem/commons/rpc/akka/TestRPC.scala

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.avsystem.commons
22
package rpc.akka
33

44
import com.avsystem.commons.rpc.RPC
5+
import com.avsystem.commons.rpc.akka.AkkaRPCFramework._
56
import monix.reactive.Observable
67

78

@@ -15,8 +16,14 @@ trait TestRPC {
1516
def stream: Observable[Int]
1617
def inner: InnerRPC
1718
}
19+
object TestRPC {
20+
implicit val fullRPCInfo: BaseFullRPCInfo[TestRPC] = materializeFullInfo
21+
}
1822

1923
@RPC
2024
trait InnerRPC {
2125
def innerFire(): Unit
22-
}
26+
}
27+
object InnerRPC {
28+
implicit val fullRPCInfo: BaseFullRPCInfo[InnerRPC] = materializeFullInfo
29+
}

commons-benchmark/src/main/scala/com/avsystem/commons/rpc/akka/AkkaRPCFrameworkBenchmark.scala

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@ import java.util.concurrent.atomic.AtomicInteger
55

66
import akka.actor.{ActorPath, ActorSystem}
77
import com.avsystem.commons.rpc.RPC
8+
import com.avsystem.commons.rpc.akka.AkkaRPCFramework._
89
import com.typesafe.config.{Config, ConfigFactory}
910
import monix.reactive.Observable
1011
import org.openjdk.jmh.annotations.{Benchmark, BenchmarkMode, Fork, Measurement, Mode, Scope, Setup, State, TearDown, Warmup}
1112
import org.openjdk.jmh.infra.Blackhole
1213

14+
import scala.concurrent.Await
1315
import scala.concurrent.ExecutionContext.Implicits.global
1416
import scala.concurrent.duration._
15-
import scala.concurrent.Await
1617

1718
/**
1819
* @author Wojciech Milewski
@@ -128,8 +129,14 @@ trait TestRPC {
128129
def stream: Observable[Int]
129130
def inner: InnerRPC
130131
}
132+
object TestRPC {
133+
implicit val fullRPCInfo: BaseFullRPCInfo[TestRPC] = materializeFullInfo
134+
}
131135

132136
@RPC
133137
trait InnerRPC {
134138
def innerFire(): Unit
135-
}
139+
}
140+
object InnerRPC {
141+
implicit val fullRPCInfo: BaseFullRPCInfo[InnerRPC] = materializeFullInfo
142+
}

commons-benchmark/src/main/scala/com/avsystem/commons/ser/JsonSerializationBenchmark.scala

Lines changed: 128 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ object Something {
2525
2017,
2626
List(
2727
Stuff(Map(), 3.15)
28-
// Stuff(Map("fuu" -> true, "boo" -> false, "fag" -> true), 3.14),
29-
// Stuff(Map("fuu" -> true), 3.16),
30-
// Stuff(Map("fuu" -> true, "boo \n\r\t" -> false, "fag" -> true, "moar" -> false), 3.17),
31-
// Stuff(Map.empty, 3.18),
32-
// Stuff(Map("fuu" -> true, "boo" -> false, "fag" -> true), 3.19),
28+
// Stuff(Map("fuu" -> true, "boo" -> false, "fag" -> true), 3.14),
29+
// Stuff(Map("fuu" -> true), 3.16),
30+
// Stuff(Map("fuu" -> true, "boo \n\r\t" -> false, "fag" -> true, "moar" -> false), 3.17),
31+
// Stuff(Map.empty, 3.18),
32+
// Stuff(Map("fuu" -> true, "boo" -> false, "fag" -> true), 3.19),
3333
),
3434
Set(
3535
1 //5, 62, -23, 454, 123, 75, -234,
@@ -47,45 +47,152 @@ object Stuff {
4747
implicit val decoder: Decoder[Stuff] = deriveDecoder[Stuff]
4848
}
4949

50+
sealed trait SealedStuff
51+
case class Case1(i: Int) extends SealedStuff
52+
case class Case2(i: Int) extends SealedStuff
53+
case class Case3(i: Int) extends SealedStuff
54+
case class Case4(i: Int) extends SealedStuff
55+
case class Case5(i: Int) extends SealedStuff
56+
case class Case6(i: Int) extends SealedStuff
57+
case class Case7(i: Int) extends SealedStuff
58+
object SealedStuff {
59+
implicit val codec: GenCodec[SealedStuff] = GenCodec.materialize
60+
implicit val encoder: Encoder[SealedStuff] = deriveEncoder[SealedStuff]
61+
implicit val decoder: Decoder[SealedStuff] = deriveDecoder[SealedStuff]
62+
63+
final val ExampleList = List[SealedStuff](Case5(5), Case3(3), Case1(1), Case7(7), Case2(2), Case4(4), Case6(6))
64+
final val ExampleJson = ExampleList.asJson
65+
final val ExampleJsonString = ExampleJson.noSpaces
66+
}
67+
68+
case class Foo(s: String, d: Double, i: Int, l: Long, bs: List[Boolean])
69+
object Foo {
70+
implicit val circeEncodeFoo: Encoder[Foo] = deriveEncoder
71+
implicit val circeDecodeFoo: Decoder[Foo] = deriveDecoder
72+
implicit val codec: GenCodec[Foo] = GenCodec.materialize
73+
74+
final val ExampleMap: Map[String, Foo] = List.tabulate(100) { i =>
75+
("b" * i) -> Foo("a" * i, (i + 2.0) / (i + 1.0), i, i * 1000L, (0 to i).map(_ % 2 == 0).toList)
76+
}.toMap
77+
78+
final val ExampleJson = ExampleMap.asJson
79+
final val ExampleJsonString = ExampleJson.noSpaces
80+
}
81+
5082
@Warmup(iterations = 10)
5183
@Measurement(iterations = 20)
5284
@Fork(1)
5385
@BenchmarkMode(Array(Mode.Throughput))
54-
class JsonSerializationBenchmark {
86+
abstract class JsonSerializationBenchmark
87+
88+
class JsonEncodingBenchmark extends JsonSerializationBenchmark {
89+
@Benchmark
90+
def encodeCCCirce: Json =
91+
Something.Example.asJson
92+
93+
@Benchmark
94+
def encodeCCGenCodec: Json =
95+
CirceJsonOutput.write(Something.Example)
96+
97+
@Benchmark
98+
def encodeSHCirce: Json =
99+
SealedStuff.ExampleList.asJson
100+
101+
@Benchmark
102+
def encodeSHGenCodec: Json =
103+
CirceJsonOutput.write(SealedStuff.ExampleList)
104+
105+
@Benchmark
106+
def encodeFoosCirce: Json =
107+
Foo.ExampleMap.asJson
108+
109+
@Benchmark
110+
def encodeFoosGenCodec: Json =
111+
CirceJsonOutput.write(Foo.ExampleMap)
112+
}
113+
114+
class JsonDecodingBenchmark extends JsonSerializationBenchmark {
55115
@Benchmark
56-
def genCodecJsonStringWriting: String = JsonStringOutput.write(Something.Example)
116+
def decodeCCCirce: Something =
117+
Something.ExampleJson.as[Something].fold(e => throw e, identity)
57118

58119
@Benchmark
59-
def genCodecJsonStringReading: Something = JsonStringInput.read[Something](Something.ExampleJsonString)
120+
def decodeCCGenCodec: Something =
121+
CirceJsonInput.read[Something](Something.ExampleJson)
60122

61123
@Benchmark
62-
def circeJsonStringWriting: String = Something.Example.asJson.noSpaces
124+
def decodeSHCirce: List[SealedStuff] =
125+
SealedStuff.ExampleJson.as[List[SealedStuff]].fold(e => throw e, identity)
63126

64127
@Benchmark
65-
def circeJsonStringReading: Something = decode[Something](Something.ExampleJsonString).fold(e => throw e, identity)
128+
def decodeSHGenCodec: List[SealedStuff] =
129+
CirceJsonInput.read[List[SealedStuff]](SealedStuff.ExampleJson)
66130

67131
@Benchmark
68-
def genCodecJsonWriting: Json = CirceJsonOutput.write(Something.Example)
132+
def decodeFoosCirce: Map[String, Foo] =
133+
Foo.ExampleJson.as[Map[String, Foo]].fold(e => throw e, identity)
69134

70135
@Benchmark
71-
def genCodecJsonReading: Something = CirceJsonInput.read[Something](Something.ExampleJson)
136+
def decodeFoosGenCodec: Map[String, Foo] =
137+
CirceJsonInput.read[Map[String, Foo]](Foo.ExampleJson)
138+
}
139+
140+
class JsonWritingBenchmark extends JsonSerializationBenchmark {
141+
@Benchmark
142+
def writeCCCirce: String =
143+
Something.Example.asJson.noSpaces
144+
145+
@Benchmark
146+
def writeCCGenCodec: String =
147+
JsonStringOutput.write(Something.Example)
148+
149+
@Benchmark
150+
def writeSHCirce: String =
151+
SealedStuff.ExampleList.asJson.noSpaces
152+
153+
@Benchmark
154+
def writeSHGenCodec: String =
155+
JsonStringOutput.write(SealedStuff.ExampleList)
72156

73157
@Benchmark
74-
def circeJsonWriting: Json = Something.Example.asJson
158+
def writeFoosCirce: String =
159+
Foo.ExampleMap.asJson.noSpaces
75160

76161
@Benchmark
77-
def circeJsonReading: Something = Something.ExampleJson.as[Something].fold(e => throw e, identity)
162+
def writeFoosGenCodec: String =
163+
JsonStringOutput.write(Foo.ExampleMap)
164+
}
165+
166+
class JsonReadingBenchmark extends JsonSerializationBenchmark {
167+
@Benchmark
168+
def readCCCirce: Something =
169+
decode[Something](Something.ExampleJsonString).fold(e => throw e, identity)
170+
171+
@Benchmark
172+
def readCCGenCodec: Something =
173+
JsonStringInput.read[Something](Something.ExampleJsonString)
174+
175+
@Benchmark
176+
def readSHCirce: List[SealedStuff] =
177+
decode[List[SealedStuff]](SealedStuff.ExampleJsonString).fold(e => throw e, identity)
178+
179+
@Benchmark
180+
def readSHGenCodec: List[SealedStuff] =
181+
JsonStringInput.read[List[SealedStuff]](SealedStuff.ExampleJsonString)
182+
183+
@Benchmark
184+
def readFoosCirce: Map[String, Foo] =
185+
decode[Map[String, Foo]](Foo.ExampleJsonString).fold(e => throw e, identity)
186+
187+
@Benchmark
188+
def readFoosGenCodec: Map[String, Foo] =
189+
JsonStringInput.read[Map[String, Foo]](Foo.ExampleJsonString)
78190
}
79191

80192
object JsonSerializationBenchmark {
81193
def main(args: Array[String]): Unit = {
82-
println(JsonStringOutput.write(Something.Example) == Something.ExampleJsonString)
83-
println(JsonStringInput.read[Something](Something.ExampleJsonString) == Something.Example)
84-
println(CirceJsonOutput.write(Something.Example) == Something.ExampleJson)
85-
println(CirceJsonInput.read[Something](Something.ExampleJson) == Something.Example)
86-
87-
while(true) {
88-
CirceJsonInput.read[Something](Something.ExampleJson)
194+
while (true) {
195+
JsonStringOutput.write[List[SealedStuff]](SealedStuff.ExampleList)
89196
}
90197
}
91198
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.avsystem.commons
2+
package serialization
3+
4+
trait JCodecTestBase extends CodecTestBase {
5+
val jTreeMap = stringMap(new JTreeMap[String, Int])
6+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.avsystem.commons
2+
package serialization
3+
4+
import java.lang.annotation.RetentionPolicy
5+
6+
import com.github.ghik.silencer.silent
7+
8+
import scala.collection.immutable.ListMap
9+
10+
@silent
11+
class JGenCodecTest extends JCodecTestBase {
12+
test("java collection test (TreeMap)") {
13+
testWriteReadAndAutoWriteRead[JSortedMap[String, Int]](jTreeMap, ListMap("1" -> 1, "2" -> 2, "3" -> 3))
14+
testWriteReadAndAutoWriteRead[JNavigableMap[String, Int]](jTreeMap, ListMap("1" -> 1, "2" -> 2, "3" -> 3))
15+
testWriteReadAndAutoWriteRead[JTreeMap[String, Int]](jTreeMap, ListMap("1" -> 1, "2" -> 2, "3" -> 3))
16+
}
17+
18+
test("java enum test") {
19+
testWriteReadAndAutoWriteRead(RetentionPolicy.RUNTIME, "RUNTIME")
20+
testWriteReadAndAutoWriteRead(RetentionPolicy.SOURCE, "SOURCE")
21+
}
22+
}

0 commit comments

Comments
 (0)