Skip to content

Commit

Permalink
Add parseNumberCounter. numbersoup test fails
Browse files Browse the repository at this point in the history
  • Loading branch information
htmldoug committed Mar 9, 2022
1 parent a12c795 commit a3d913d
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 12 deletions.
22 changes: 13 additions & 9 deletions bench/src/main/scala/bench/JsoniterScalaBench.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package bench

import com.rallyhealth.weejson.v1.BufferedValue
import com.rallyhealth.weejson.v1.wee_jsoniter_scala.FromJsoniterScala
import com.rallyhealth.weepickle.v1.WeePickle.ToScala
import org.openjdk.jmh.annotations._

import java.util.concurrent.TimeUnit
Expand All @@ -10,17 +10,17 @@ import java.util.concurrent.TimeUnit
* Quick and dirty test to see how badly we're butchering performance of floats.
*
* ==Quick Run==
* bench / Jmh / run .*JsoniterScalabench
* bench / Jmh / run .*JsoniterScalaBench
*
* ==Profile with Flight Recorder==
* bench / Jmh / run -prof jfr .*JsoniterScalabench
* bench / Jmh / run -prof jfr .*JsoniterScalaBench
*
* ==Jmh Visualizer Report==
* bench / Jmh / run -prof gc -rf json -rff JsoniterScalabench-results.json .*JsoniterScalabench
* bench / Jmh / run -prof gc -rf json -rff JsoniterScalaBench-results.json .*JsoniterScalaBench
*
* @see https://github.com/ktoso/sbt-jmh
*/
@Warmup(iterations = 15, time = 1, timeUnit = TimeUnit.SECONDS)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 15, time = 1, timeUnit = TimeUnit.SECONDS)
@State(Scope.Benchmark)
@BenchmarkMode(Array(Mode.Throughput))
Expand All @@ -31,11 +31,15 @@ import java.util.concurrent.TimeUnit
value = 1
)
class JsoniterScalaBench {
private val input = "348249875e105".getBytes()

/**
* Values that end with a number throw an expensive exception internally when reaching EOF.
* The only time this would happen in the wild would be when parsing a JSON text of a single number.
* To make this more realistic, we're intentionally adding a whitespace suffix here.
*/
private val piBytes = "-3.14 ".getBytes()

@Benchmark
def parseDouble = {
FromJsoniterScala(input).transform(ToScala[Double])
}
def pi = FromJsoniterScala(piBytes).transform(BufferedValue.Builder)

}
12 changes: 12 additions & 0 deletions bench/src/test/scala/bench/JsoniterScalaBenchTests.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package bench

import com.rallyhealth.weejson.v1.BufferedValue._
import utest._

object JsoniterScalaBenchTests extends TestSuite {

val tests = Tests {
val bench = new JsoniterScalaBench()
test("pi")(bench.pi ==> Num("-3.14", 2, -1))
}
}
2 changes: 1 addition & 1 deletion project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.9.2")
addSbtPlugin("com.dwijnand" % "sbt-dynver" % "4.1.1")
addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.3.7")
addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.3")
addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.9.7")
addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.1.2")
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ object WeePickleJsonValueCodecs {
if (in.readBoolean()) v.visitTrue() else v.visitFalse()
} else if ((b >= '0' && b <= '9') || b == '-') {
in.rollbackToken()
parseNumber(in, v)
parseNumberCounter(in, v)
} else if (b == '[') {
val depthM1 = depth - 1
if (depthM1 < 0) in.decodeError("depth limit exceeded")
Expand Down Expand Up @@ -121,7 +121,69 @@ object WeePickleJsonValueCodecs {
}
}

private def parseNumber[J](
private def parseNumberCounter[J](
in: JsonReader,
v: Visitor[_, J]
): J = {
in.setMark()
var b = in.nextByte()
var digits, index = 0
var decIndex, expIndex = -1
if (b == '-') {
b = in.nextByte()
index += 1
}
try {
digits -= index
while (b >= '0' && b <= '9') {
b = in.nextByte()
index += 1
}
digits += index
if (b == '.') {
decIndex = index
b = in.nextByte()
index += 1
}
digits -= index
while (b >= '0' && b <= '9') {
b = in.nextByte()
index += 1
}
digits += index
if ((b | 0x20) == 'e') {
expIndex = index
b = in.nextByte()
index += 1
if (b == '-' || b == '+') {
b = in.nextByte()
index += 1
}
while (b >= '0' && b <= '9') {
b = in.nextByte()
index += 1
}
}
} catch {
case _: JsonReaderException =>
index += 1 // for length calcs, pretend that nextByte() didn't hit EOF
} finally in.rollbackToMark()
if ((decIndex & expIndex) == -1) {
if (digits < 19) v.visitInt64(in.readLong())
else {
val x = in.readBigInt(null)
if (x.bitLength < 64) v.visitInt64(x.longValue)
else v.visitFloat64StringParts(x.toString, -1, -1)
}
} else {
val cs = new String(in.readRawValAsBytes(), StandardCharsets.US_ASCII)
require(cs.length == index, "invalid number")
v.visitFloat64StringParts(cs, decIndex, expIndex)
}
}


private def parseNumberRegex[J](
in: JsonReader,
v: Visitor[_, J]
): J = {
Expand Down

0 comments on commit a3d913d

Please sign in to comment.