|
| 1 | +package dotty.tools.dotc.profile |
| 2 | + |
| 3 | +import java.io.* |
| 4 | + |
| 5 | +import org.junit.Assert.* |
| 6 | +import org.junit.* |
| 7 | +import java.nio.file.Files |
| 8 | +import java.nio.charset.StandardCharsets |
| 9 | +import java.util.concurrent.locks.LockSupport |
| 10 | +import scala.concurrent.duration.* |
| 11 | + |
| 12 | +class ChromeTraceTest: |
| 13 | + private def testTraceOutputs(generator: ChromeTrace => Unit)(checkContent: String => Unit): Unit = { |
| 14 | + val outfile = Files.createTempFile("trace-", ".json").nn |
| 15 | + val tracer = new ChromeTrace(outfile) |
| 16 | + try generator(tracer) |
| 17 | + finally tracer.close() |
| 18 | + val content = scala.io.Source.fromFile(outfile.toFile().nn).mkString |
| 19 | + checkContent(content) |
| 20 | + } |
| 21 | + |
| 22 | + @Test def traceCounterEvent(): Unit = testTraceOutputs{ tracer => |
| 23 | + tracer.traceCounterEvent("foo", "counter1", 42, processWide = true) |
| 24 | + tracer.traceCounterEvent("bar", "counter2", 21, processWide = false) |
| 25 | + }{ |
| 26 | + case s"""{"traceEvents":[ |
| 27 | +{"cat":"scalac","name":"foo","ph":"C","tid":"${tid1}","pid":"${pid1}","ts":${ts1},"args":{"counter1":42}} |
| 28 | +,{"cat":"scalac","name":"bar","ph":"C","tid":"${tid2}","pid":"${pid2}","ts":${ts2},"args":{"counter2":21}} |
| 29 | +]}""" => |
| 30 | + assertEquals(tid1, tid2) |
| 31 | + assertTrue(tid1.toIntOption.isDefined) |
| 32 | + assertNotEquals(pid1, pid2) |
| 33 | + assertTrue(pid1.toIntOption.isDefined) |
| 34 | + assertEquals(s"$pid1-$tid1", pid2) |
| 35 | + assertTrue(ts1.toLong < ts2.toLong) |
| 36 | + } |
| 37 | + |
| 38 | + @Test def traceDurationEvent(): Unit = testTraceOutputs{ tracer => |
| 39 | + tracer.traceDurationEvent(name = "name1", startNanos = 1000L, durationNanos = 2500L, tid = "this-thread") |
| 40 | + tracer.traceDurationEvent(name = "name2", startNanos = 1000L, durationNanos = 5000L, tid = "this-thread", pidSuffix = "pidSuffix") |
| 41 | + }{ |
| 42 | + case s"""{"traceEvents":[ |
| 43 | +{"cat":"scalac","name":"name1","ph":"X","tid":"this-thread","pid":"${pid1}","ts":1,"dur":2} |
| 44 | +,{"cat":"scalac","name":"name2","ph":"X","tid":"this-thread","pid":"${pid2}","ts":1,"dur":5} |
| 45 | +]}""" => |
| 46 | + assertTrue(pid1.toIntOption.isDefined) |
| 47 | + assertEquals(s"$pid1-pidSuffix", pid2) |
| 48 | + } |
| 49 | + |
| 50 | + @Test def traceDurationEvents(): Unit = { |
| 51 | + val testStart = System.nanoTime() |
| 52 | + testTraceOutputs{ tracer => |
| 53 | + tracer.traceDurationEventStart(cat = "test1", name = "event1") |
| 54 | + LockSupport.parkNanos(2.millis.toNanos) |
| 55 | + tracer.traceDurationEventStart(cat = "test2", name = "event2", colour = "RED", pidSuffix = "pid-suffix") |
| 56 | + LockSupport.parkNanos(4.millis.toNanos) |
| 57 | + tracer.traceDurationEventEnd(cat = "test2", name = "event2") |
| 58 | + LockSupport.parkNanos(8.millis.toNanos) |
| 59 | + tracer.traceDurationEventEnd(cat = "test1", name = "event1", colour = "RED", pidSuffix = "pid-suffix") |
| 60 | + }{ |
| 61 | + case s"""{"traceEvents":[ |
| 62 | +{"cat":"test1","name":"event1","ph":"B","pid":"${pid1}","tid":"${tid1}","ts":${ts1}} |
| 63 | +,{"cat":"test2","name":"event2","ph":"B","pid":"${pid2}","tid":"${tid2}","ts":${ts2},"cname":"RED"} |
| 64 | +,{"cat":"test2","name":"event2","ph":"E","pid":"${pid3}","tid":"${tid3}","ts":${ts3}} |
| 65 | +,{"cat":"test1","name":"event1","ph":"E","pid":"${pid4}","tid":"${tid4}","ts":${ts4},"cname":"RED"} |
| 66 | +]}""" => |
| 67 | + val traceEnd = System.nanoTime() |
| 68 | + assertTrue(tid1.toIntOption.isDefined) |
| 69 | + assertEquals(pid1, pid3) |
| 70 | + assertTrue(pid1.endsWith(s"-$tid1")) |
| 71 | + assertEquals(pid2, pid4) |
| 72 | + assertTrue(pid2.endsWith("-pid-suffix")) |
| 73 | + List(tid1, tid2, tid3).foreach: tid => |
| 74 | + assertEquals(tid4, tid) |
| 75 | + List(pid1, pid2, pid3, pid4).foreach: pid => |
| 76 | + assertTrue(pid.takeWhile(_ != '-').toIntOption.isDefined) |
| 77 | + |
| 78 | + List(ts1, ts2, ts3, ts4).map(_.toLong) match { |
| 79 | + case all @ List(ts1, ts2, ts3, ts4) => |
| 80 | + all.foreach: ts => |
| 81 | + // Timestamps are presented using Epoch microsecondos |
| 82 | + assertTrue(ts >= testStart / 1000) |
| 83 | + assertTrue(ts <= traceEnd / 1000) |
| 84 | + assertTrue(ts2 >= ts1 + 2.millis.toMicros) |
| 85 | + assertTrue(ts3 >= ts2 + 4.millis.toMicros) |
| 86 | + assertTrue(ts4 >= ts3 + 8.millis.toMicros) |
| 87 | + case _ => fail("unreachable") |
| 88 | + } |
| 89 | + } |
| 90 | +} |
0 commit comments