diff --git a/compiler/src/dotty/tools/dotc/profile/FileUtils.scala b/compiler/src/dotty/tools/dotc/profile/FileUtils.scala index 97c2417d236b..4aec428c05bf 100644 --- a/compiler/src/dotty/tools/dotc/profile/FileUtils.scala +++ b/compiler/src/dotty/tools/dotc/profile/FileUtils.scala @@ -27,6 +27,7 @@ import java.util.concurrent.atomic.AtomicBoolean import scala.concurrent.duration.Duration import scala.concurrent.{Await, Promise} import scala.util.{Failure, Success} +import scala.annotation.internal.sharable object FileUtils { def newAsyncBufferedWriter(path: Path, charset: Charset = StandardCharsets.UTF_8.nn, options: Array[OpenOption] = NO_OPTIONS, threadsafe: Boolean = false): LineWriter = { @@ -72,8 +73,8 @@ object FileUtils { } private object AsyncBufferedWriter { - private val Close = CharBuffer.allocate(0) - private val Flush = CharBuffer.allocate(0) + @sharable private val Close = CharBuffer.allocate(0) + @sharable private val Flush = CharBuffer.allocate(0) } private class AsyncBufferedWriter(val underlying: Writer, bufferSize : Int = 4096) extends LineWriter { private var current: CharBuffer = allocate diff --git a/compiler/test/dotty/tools/dotc/profile/ChromeTraceTest.scala b/compiler/test/dotty/tools/dotc/profile/ChromeTraceTest.scala index 143c6b37dad5..1cd3bc498f38 100644 --- a/compiler/test/dotty/tools/dotc/profile/ChromeTraceTest.scala +++ b/compiler/test/dotty/tools/dotc/profile/ChromeTraceTest.scala @@ -10,41 +10,41 @@ import java.util.concurrent.locks.LockSupport import scala.concurrent.duration.* class ChromeTraceTest: - private def testTraceOutputs(generator: ChromeTrace => Unit)(checkContent: String => Unit): Unit = { + private def testTraceOutputs(generator: ChromeTrace => Unit)(checkContent: PartialFunction[List[String], Unit]): Unit = { val outfile = Files.createTempFile("trace-", ".json").nn val tracer = new ChromeTrace(outfile) try generator(tracer) finally tracer.close() - val content = scala.io.Source.fromFile(outfile.toFile().nn).mkString - checkContent(content) + val contentLines = scala.io.Source.fromFile(outfile.toFile().nn).getLines().toList + checkContent.applyOrElse(contentLines, content => fail(s"Invalid output lines: ${content.mkString(System.lineSeparator())}")) } @Test def traceCounterEvent(): Unit = testTraceOutputs{ tracer => tracer.traceCounterEvent("foo", "counter1", 42, processWide = true) tracer.traceCounterEvent("bar", "counter2", 21, processWide = false) }{ - case s"""{"traceEvents":[ -{"cat":"scalac","name":"foo","ph":"C","tid":"${tid1}","pid":"${pid1}","ts":${ts1},"args":{"counter1":42}} -,{"cat":"scalac","name":"bar","ph":"C","tid":"${tid2}","pid":"${pid2}","ts":${ts2},"args":{"counter2":21}} -]}""" => - assertEquals(tid1, tid2) - assertTrue(tid1.toIntOption.isDefined) - assertNotEquals(pid1, pid2) - assertTrue(pid1.toIntOption.isDefined) - assertEquals(s"$pid1-$tid1", pid2) - assertTrue(ts1.toLong < ts2.toLong) + case """{"traceEvents":[""" :: + s"""{"cat":"scalac","name":"foo","ph":"C","tid":"${tid1}","pid":"${pid1}","ts":${ts1},"args":{"counter1":42}}""" :: + s""",{"cat":"scalac","name":"bar","ph":"C","tid":"${tid2}","pid":"${pid2}","ts":${ts2},"args":{"counter2":21}}""" :: + "]}" :: Nil => + assertEquals(tid1, tid2) + assertTrue(tid1.toIntOption.isDefined) + assertNotEquals(pid1, pid2) + assertTrue(pid1.toIntOption.isDefined) + assertEquals(s"$pid1-$tid1", pid2) + assertTrue(ts1.toLong < ts2.toLong) } @Test def traceDurationEvent(): Unit = testTraceOutputs{ tracer => tracer.traceDurationEvent(name = "name1", startNanos = 1000L, durationNanos = 2500L, tid = "this-thread") tracer.traceDurationEvent(name = "name2", startNanos = 1000L, durationNanos = 5000L, tid = "this-thread", pidSuffix = "pidSuffix") }{ - case s"""{"traceEvents":[ -{"cat":"scalac","name":"name1","ph":"X","tid":"this-thread","pid":"${pid1}","ts":1,"dur":2} -,{"cat":"scalac","name":"name2","ph":"X","tid":"this-thread","pid":"${pid2}","ts":1,"dur":5} -]}""" => - assertTrue(pid1.toIntOption.isDefined) - assertEquals(s"$pid1-pidSuffix", pid2) + case """{"traceEvents":[""" :: + s"""{"cat":"scalac","name":"name1","ph":"X","tid":"this-thread","pid":"${pid1}","ts":1,"dur":2}""" :: + s""",{"cat":"scalac","name":"name2","ph":"X","tid":"this-thread","pid":"${pid2}","ts":1,"dur":5}""" :: + "]}" :: Nil => + assertTrue(pid1.toIntOption.isDefined) + assertEquals(s"$pid1-pidSuffix", pid2) } @Test def traceDurationEvents(): Unit = { @@ -58,33 +58,33 @@ class ChromeTraceTest: LockSupport.parkNanos(8.millis.toNanos) tracer.traceDurationEventEnd(cat = "test1", name = "event1", colour = "RED", pidSuffix = "pid-suffix") }{ - case s"""{"traceEvents":[ -{"cat":"test1","name":"event1","ph":"B","pid":"${pid1}","tid":"${tid1}","ts":${ts1}} -,{"cat":"test2","name":"event2","ph":"B","pid":"${pid2}","tid":"${tid2}","ts":${ts2},"cname":"RED"} -,{"cat":"test2","name":"event2","ph":"E","pid":"${pid3}","tid":"${tid3}","ts":${ts3}} -,{"cat":"test1","name":"event1","ph":"E","pid":"${pid4}","tid":"${tid4}","ts":${ts4},"cname":"RED"} -]}""" => - val traceEnd = System.nanoTime() - assertTrue(tid1.toIntOption.isDefined) - assertEquals(pid1, pid3) - assertTrue(pid1.endsWith(s"-$tid1")) - assertEquals(pid2, pid4) - assertTrue(pid2.endsWith("-pid-suffix")) - List(tid1, tid2, tid3).foreach: tid => - assertEquals(tid4, tid) - List(pid1, pid2, pid3, pid4).foreach: pid => - assertTrue(pid.takeWhile(_ != '-').toIntOption.isDefined) + case """{"traceEvents":[""" :: + s"""{"cat":"test1","name":"event1","ph":"B","pid":"${pid1}","tid":"${tid1}","ts":${ts1}}""" :: + s""",{"cat":"test2","name":"event2","ph":"B","pid":"${pid2}","tid":"${tid2}","ts":${ts2},"cname":"RED"}""" :: + s""",{"cat":"test2","name":"event2","ph":"E","pid":"${pid3}","tid":"${tid3}","ts":${ts3}}""" :: + s""",{"cat":"test1","name":"event1","ph":"E","pid":"${pid4}","tid":"${tid4}","ts":${ts4},"cname":"RED"}""" :: + "]}" :: Nil => + val traceEnd = System.nanoTime() + assertTrue(tid1.toIntOption.isDefined) + assertEquals(pid1, pid3) + assertTrue(pid1.endsWith(s"-$tid1")) + assertEquals(pid2, pid4) + assertTrue(pid2.endsWith("-pid-suffix")) + List(tid1, tid2, tid3).foreach: tid => + assertEquals(tid4, tid) + List(pid1, pid2, pid3, pid4).foreach: pid => + assertTrue(pid.takeWhile(_ != '-').toIntOption.isDefined) - List(ts1, ts2, ts3, ts4).map(_.toLong) match { - case all @ List(ts1, ts2, ts3, ts4) => - all.foreach: ts => - // Timestamps are presented using Epoch microsecondos - assertTrue(ts >= testStart / 1000) - assertTrue(ts <= traceEnd / 1000) - assertTrue(ts2 >= ts1 + 2.millis.toMicros) - assertTrue(ts3 >= ts2 + 4.millis.toMicros) - assertTrue(ts4 >= ts3 + 8.millis.toMicros) - case _ => fail("unreachable") - } + List(ts1, ts2, ts3, ts4).map(_.toLong) match { + case all @ List(ts1, ts2, ts3, ts4) => + all.foreach: ts => + // Timestamps are presented using Epoch microsecondos + assertTrue(ts >= testStart / 1000) + assertTrue(ts <= traceEnd / 1000) + assertTrue(ts2 >= ts1 + 2.millis.toMicros) + assertTrue(ts3 >= ts2 + 4.millis.toMicros) + assertTrue(ts4 >= ts3 + 8.millis.toMicros) + case _ => fail("unreachable") + } } }