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

Sjsonnet performance improvements #117

Merged
merged 52 commits into from
Apr 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
d61fdfe
jsonnet
ahirreddy Mar 10, 2021
6d31126
loop
ahirreddy Mar 11, 2021
5238163
faster bitset
ahirreddy Mar 11, 2021
b7298d5
remove vecotr builder
ahirreddy Mar 11, 2021
6831465
remove builder
ahirreddy Mar 11, 2021
5f9072d
cut allocations
ahirreddy Mar 11, 2021
9b18abd
remove more loops
ahirreddy Mar 11, 2021
c9e24f1
eliminate more allocations
ahirreddy Mar 11, 2021
e8ed484
Fix BitSet size bug
szeiger Mar 25, 2021
a33f10f
Add sbt build
szeiger Mar 25, 2021
9f9e128
Add simple benchmark using JMH
szeiger Mar 25, 2021
7df7e75
Remove unnecessary abstractions/wrapping/boxing related to Func/Apply
szeiger Mar 26, 2021
e95bc0c
Improve position handling
szeiger Mar 26, 2021
8fbb8b1
Further Val optimization
szeiger Mar 26, 2021
4919adc
Scopes with arrays
szeiger Mar 26, 2021
ffa3d9c
Unwrap scope Options
szeiger Mar 26, 2021
bc1a833
Remove more Options
szeiger Mar 26, 2021
872514b
Lazy SAM
szeiger Mar 26, 2021
29b29a7
Use Array in Arr
szeiger Mar 26, 2021
f07fa51
Improve scope handling
szeiger Mar 26, 2021
72d475c
Remove FileScope threading
szeiger Mar 26, 2021
11e1a49
simplify
szeiger Mar 26, 2021
0a3b97f
Disable acyclic because of binary incompatibility with 2.13.4
szeiger Mar 27, 2021
398869a
Val$Obj optimization
szeiger Mar 27, 2021
69f1f92
Stricter Val$Func + Fast path for simple function calls
szeiger Mar 27, 2021
791c98e
Cache visible keys
szeiger Mar 27, 2021
7238c24
Option-free bindings lookup
szeiger Mar 27, 2021
a397ba2
Some simplifications
szeiger Mar 27, 2021
535a153
Simplify scope handling
szeiger Mar 27, 2021
a748001
Optimistic function parameter validation
szeiger Mar 27, 2021
eb14cc2
Remove empty trigger asserts
szeiger Mar 27, 2021
4226744
Val literals
szeiger Mar 27, 2021
17ffad1
Remove Parened
szeiger Mar 28, 2021
39ac310
Use Java LinkedHashMap
szeiger Mar 28, 2021
2d8183a
Improved BinaryOp handling
szeiger Mar 28, 2021
8c510b6
Remove more Options
szeiger Mar 28, 2021
2f62e22
Improve Std
szeiger Mar 28, 2021
c729f79
Equality checks without Materializer
szeiger Mar 29, 2021
68d687f
More std improvements
szeiger Mar 29, 2021
c70635b
Improve pos handling
szeiger Mar 30, 2021
3a83606
Simplify Obj.value
szeiger Mar 30, 2021
f1928fb
Simplify member handling
szeiger Mar 30, 2021
a292189
Allow null bindings in locals
szeiger Apr 1, 2021
e6b876b
Remove Expr.Obj
szeiger Apr 1, 2021
e6df7d9
Clean up visible keys handling
szeiger Apr 1, 2021
8d12f17
Improved equality
szeiger Apr 2, 2021
2d2e8cb
Optimize super handling
szeiger Apr 2, 2021
4979ac6
wip: static objects
szeiger Apr 2, 2021
a270482
Clean up and make all versions compile again
szeiger Apr 6, 2021
8537f0e
Fix parse cache
szeiger Apr 6, 2021
7abb425
Fix std.join bug
szeiger Apr 7, 2021
147d85c
Enable optimizer in the Mill build
szeiger Apr 7, 2021
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
44 changes: 44 additions & 0 deletions bench/src/main/scala/sjsonnet/MainBenchmark.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package sjsonnet

import java.io.{OutputStream, PrintStream}
import java.util.concurrent.TimeUnit

import org.openjdk.jmh.annotations._
import org.openjdk.jmh.infra._

import scala.collection.mutable.ArrayBuffer

@BenchmarkMode(Array(Mode.AverageTime))
@Fork(4)
@Threads(1)
@Warmup(iterations = 30)
@Measurement(iterations = 40)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Benchmark)
class MainBenchmark {

val mainArgs = Array[String](
"../../universe2/rulemanager/deploy/rulemanager.jsonnet",
"-J", "../../universe2",
"-J", "../../universe2/mt-shards/dev/az-westus-c2",
)

val dummyOut = new PrintStream(new OutputStream {
def write(b: Int): Unit = ()
override def write(b: Array[Byte]): Unit = ()
override def write(b: Array[Byte], off: Int, len: Int): Unit = ()
})

@Benchmark
def main(bh: Blackhole): Unit = {
bh.consume(SjsonnetMain.main0(
mainArgs,
collection.mutable.HashMap.empty,
System.in,
dummyOut,
System.err,
os.pwd,
None
))
}
}
55 changes: 55 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
val sjsonnetVersion = "0.3.3"

scalaVersion in Global := "2.13.4"

cancelable in Global := true

lazy val main = (project in file("sjsonnet"))
.settings(
scalacOptions in Compile ++= Seq("-opt:l:inline", "-opt-inline-from:sjsonnet.**"),
fork in Test := true,
baseDirectory in Test := (baseDirectory in ThisBuild).value,
libraryDependencies ++= Seq(
"com.lihaoyi" %% "fastparse" % "2.3.1",
"com.lihaoyi" %% "pprint" % "0.6.1",
"com.lihaoyi" %% "ujson" % "1.3.7",
"com.lihaoyi" %% "scalatags" % "0.9.3",
"com.lihaoyi" %% "os-lib" % "0.7.2",
"com.lihaoyi" %% "mainargs" % "0.2.0",
"org.scala-lang.modules" %% "scala-collection-compat" % "2.4.0",
"org.tukaani" % "xz" % "1.8",
),
libraryDependencies ++= Seq(
"com.lihaoyi" %% "utest" % "0.7.7",
).map(_ % "test"),
testFrameworks += new TestFramework("utest.runner.Framework"),
(unmanagedSourceDirectories in Compile) := Seq(
baseDirectory.value / "src",
baseDirectory.value / "src-jvm",
baseDirectory.value / "src-jvm-native",
),
(unmanagedSourceDirectories in Test) := Seq(
baseDirectory.value / "test/src",
baseDirectory.value / "test/src-jvm",
baseDirectory.value / "test/src-jvm-native",
),
(unmanagedResourceDirectories in Test) := Seq(
baseDirectory.value / "test/resources",
),
(sourceGenerators in Compile) += Def.task {
val file = (Compile / sourceManaged).value / "jsonnet" / "Version.scala"
IO.write(file,
s"""package sjsonnet
|object Version{
| val version = "${sjsonnetVersion}"
|}
|""".stripMargin)
Seq(file)
}.taskValue
)

lazy val bench = (project in file("bench"))
.dependsOn(main)
.enablePlugins(JmhPlugin)
.settings(
)
13 changes: 7 additions & 6 deletions build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,14 @@ class SjsonnetModule(val crossScalaVersion: String) extends Module {
def ivyDeps = super.ivyDeps() ++ Agg(
ivy"org.tukaani:xz::1.8"
)
def compileIvyDeps = Agg( ivy"com.lihaoyi::acyclic:0.2.0")
def scalacOptions = Seq("-P:acyclic:force")
def scalacPluginIvyDeps = Agg( ivy"com.lihaoyi::acyclic:0.2.0")
def scalacOptions = Seq("-opt:l:inline", "-opt-inline-from:sjsonnet.**")
//def compileIvyDeps = Agg( ivy"com.lihaoyi::acyclic:0.2.0")
//def scalacOptions = Seq("-P:acyclic:force")
//def scalacPluginIvyDeps = Agg( ivy"com.lihaoyi::acyclic:0.2.0")
object test extends Tests with CrossTests{
def compileIvyDeps = Agg( ivy"com.lihaoyi::acyclic:0.2.0")
def scalacOptions = Seq("-P:acyclic:force")
def scalacPluginIvyDeps = Agg( ivy"com.lihaoyi::acyclic:0.2.0")
//def compileIvyDeps = Agg( ivy"com.lihaoyi::acyclic:0.2.0")
//def scalacOptions = Seq("-P:acyclic:force")
//def scalacPluginIvyDeps = Agg( ivy"com.lihaoyi::acyclic:0.2.0")
def forkOptions = Seq("-Xss100m")
def sources = T.sources(
millSourcePath / "src",
Expand Down
1 change: 1 addition & 0 deletions project/build.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sbt.version=1.3.10
2 changes: 2 additions & 0 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
//addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.3.7")
addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.3.3")
6 changes: 3 additions & 3 deletions sjsonnet/server/src/sjsonnet/SjsonnetServerMain.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ trait SjsonnetServerMain[T]{
wd: os.Path): (Boolean, Option[T])
}

object SjsonnetServerMain extends SjsonnetServerMain[collection.mutable.Map[String, fastparse.Parsed[(Expr, Map[String, Int])]]]{
object SjsonnetServerMain extends SjsonnetServerMain[collection.mutable.HashMap[(Path, String), fastparse.Parsed[(Expr, FileScope)]]]{
def main(args0: Array[String]): Unit = {
// Disable SIGINT interrupt signal in the Mill server.
//
Expand All @@ -45,7 +45,7 @@ object SjsonnetServerMain extends SjsonnetServerMain[collection.mutable.Map[Stri
).run()
}
def main0(args: Array[String],
stateCache: Option[collection.mutable.Map[String, fastparse.Parsed[(Expr, Map[String, Int])]]],
stateCache: Option[collection.mutable.HashMap[(Path, String), fastparse.Parsed[(Expr, FileScope)]]],
mainInteractive: Boolean,
stdin: InputStream,
stdout: PrintStream,
Expand All @@ -55,7 +55,7 @@ object SjsonnetServerMain extends SjsonnetServerMain[collection.mutable.Map[Stri
wd: os.Path) = {

val stateCache2 = stateCache.getOrElse{
val p = collection.mutable.Map[String, fastparse.Parsed[(Expr, Map[String, Int])]]()
val p = collection.mutable.HashMap[(Path, String), fastparse.Parsed[(Expr, FileScope)]]()
this.stateCache = Some(p)
p
}
Expand Down
18 changes: 18 additions & 0 deletions sjsonnet/src-js/java/util/BitSet.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package java.util

import java.util.stream.IntStream

import scala.collection.mutable.{BitSet => SBitSet}
import scala.collection.JavaConverters._

class BitSet(_initialSizeDummy: Int) extends java.lang.Cloneable {
val bs: SBitSet = SBitSet.empty
def isEmpty: Boolean = bs.isEmpty
override def clone(): AnyRef = super.clone()
def cardinality(): Int = bs.size
def stream(): IntStream = IntStream.of(bs.toArray: _*)
def get(i: Int): Boolean = bs.apply(i)
def set(i: Int): Unit = bs += i
def clear(): Unit = bs.clear()
def andNot(other: BitSet): Unit = bs.&~=(other.bs)
}
7 changes: 7 additions & 0 deletions sjsonnet/src-js/sjsonnet/BitSetUtils.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package sjsonnet

import java.util.BitSet

object BitSetUtils {
def iterator(bs: BitSet): Iterator[Int] = bs.bs.iterator
}
6 changes: 3 additions & 3 deletions sjsonnet/src-js/sjsonnet/SjsonnetMain.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import scala.scalajs.js.annotation.{JSExport, JSExportTopLevel}

@JSExportTopLevel("SjsonnetMain")
object SjsonnetMain {
def createParseCache() = collection.mutable.Map[String, fastparse.Parsed[(Expr, Map[String, Int])]]()
def createParseCache() = collection.mutable.HashMap[(Path, String), fastparse.Parsed[(Expr, FileScope)]]()
@JSExport
def interpret(text: String,
extVars: js.Any,
Expand All @@ -15,7 +15,7 @@ object SjsonnetMain {
importer: js.Function2[String, String, js.Array[String]],
preserveOrder: Boolean = false): js.Any = {
val interp = new Interpreter(
mutable.Map.empty,
mutable.HashMap.empty,
ujson.WebJson.transform(extVars, ujson.Value).obj.toMap,
ujson.WebJson.transform(tlaVars, ujson.Value).obj.toMap,
JsVirtualPath(wd0),
Expand Down Expand Up @@ -51,7 +51,7 @@ case class JsVirtualPath(path: String) extends Path{

def /(s: String): Path = JsVirtualPath(path + "/" + s)

def renderOffsetStr(offset: Int, loadedFileContents: mutable.Map[Path, Array[Int]]): String = {
def renderOffsetStr(offset: Int, loadedFileContents: mutable.HashMap[Path, Array[Int]]): String = {
path + ":" + offset
}
}
8 changes: 7 additions & 1 deletion sjsonnet/src-jvm-native/sjsonnet/OsPath.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,14 @@ case class OsPath(p: os.Path) extends Path{
def last: String = p.last
def /(s: String): Path = OsPath(p / s)

override def equals(other: Any): Boolean = other match {
case OsPath(p2) => p == p2
case _ => false
}

override def hashCode: Int = p.hashCode()

def renderOffsetStr(offset: Int, loadedFileContents: mutable.Map[Path, Array[Int]]): String = {
def renderOffsetStr(offset: Int, loadedFileContents: mutable.HashMap[Path, Array[Int]]): String = {
val offsetStr =
if (p.toString.contains("(materialize)")) ""
else {
Expand Down
10 changes: 5 additions & 5 deletions sjsonnet/src-jvm-native/sjsonnet/SjsonnetMain.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import scala.util.Try
import scala.util.control.NonFatal

object SjsonnetMain {
def createParseCache() = collection.mutable.Map[String, fastparse.Parsed[(Expr, Map[String, Int])]]()
def createParseCache() = collection.mutable.HashMap[(Path, String), fastparse.Parsed[(Expr, FileScope)]]()
def resolveImport(searchRoots0: Seq[Path], allowedInputs: Option[Set[os.Path]] = None)(wd: Path, str: String) = {
(wd +: searchRoots0)
.flatMap(base => os.FilePath(str) match {
Expand All @@ -25,12 +25,12 @@ object SjsonnetMain {
.flatMap(p => try Some((OsPath(p), os.read(p))) catch{case NonFatal(_) => None})
}
def main(args: Array[String]): Unit = {
val exitCode = main0(
var exitCode = main0(
args match {
case Array(s, _*) if s == "-i" || s == "--interactive" => args.tail
case _ => args
},
collection.mutable.Map.empty,
collection.mutable.HashMap.empty,
System.in,
System.out,
System.err,
Expand All @@ -41,7 +41,7 @@ object SjsonnetMain {
}

def main0(args: Array[String],
parseCache: collection.mutable.Map[String, fastparse.Parsed[(Expr, Map[String, Int])]],
parseCache: collection.mutable.HashMap[(Path, String), fastparse.Parsed[(Expr, FileScope)]],
stdin: InputStream,
stdout: PrintStream,
stderr: PrintStream,
Expand Down Expand Up @@ -124,7 +124,7 @@ object SjsonnetMain {

def mainConfigured(file: String,
config: Config,
parseCache: collection.mutable.Map[String, fastparse.Parsed[(Expr, Map[String, Int])]],
parseCache: collection.mutable.HashMap[(Path, String), fastparse.Parsed[(Expr, FileScope)]],
wd: os.Path,
allowedInputs: Option[Set[os.Path]] = None,
importer: Option[(Path, String) => Option[os.Path]] = None): Either[String, String] = {
Expand Down
17 changes: 17 additions & 0 deletions sjsonnet/src-jvm/sjsonnet/BitSetUtils.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package sjsonnet

import java.util.BitSet

import scala.collection.mutable.ArrayBuffer

object BitSetUtils {
def iterator(bs: BitSet): Iterator[Int] = {
val b = ArrayBuffer.empty[Int]
var i = bs.nextSetBit(0)
while(i > 0) {
b += i
i = bs.nextSetBit(i+1)
}
b.iterator
}
}
18 changes: 18 additions & 0 deletions sjsonnet/src-native/java/util/BitSet.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package java.util

import java.util.stream.IntStream

import scala.collection.mutable.{BitSet => SBitSet}
import scala.collection.JavaConverters._

class BitSet(_initialSizeDummy: Int) extends java.lang.Cloneable {
val bs: SBitSet = SBitSet.empty
def isEmpty: Boolean = bs.isEmpty
override def clone(): AnyRef = super.clone()
def cardinality(): Int = bs.size
def stream(): IntStream = IntStream.of(bs.toArray: _*)
def get(i: Int): Boolean = bs.apply(i)
def set(i: Int): Unit = bs += i
def clear(): Unit = bs.clear()
def andNot(other: BitSet): Unit = bs.&~=(other.bs)
}
7 changes: 7 additions & 0 deletions sjsonnet/src-native/sjsonnet/BitSetUtils.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package sjsonnet

import java.util.BitSet

object BitSetUtils {
def iterator(bs: BitSet): Iterator[Int] = bs.bs.iterator
}
Loading