Skip to content

Instantly share code, notes, and snippets.

@lawrenceching
Last active September 9, 2020 17:07
Show Gist options
  • Save lawrenceching/46e423dac385f22eceabc639dcbd8493 to your computer and use it in GitHub Desktop.
Save lawrenceching/46e423dac385f22eceabc639dcbd8493 to your computer and use it in GitHub Desktop.
A util class to measure how much a operation take
package me.imlc.example
import java.lang.StringBuilder
import java.util.*
class Tracker {
data class Tick(val name:String, val timeInMillis: Long)
companion object {
private val record = hashMapOf<String, ArrayList<Tick>>()
fun start(): String {
val uuid = UUID.randomUUID().toString()
record[uuid] = arrayListOf()
tick(uuid, "start")
return uuid
}
fun tick(id: String, name: String) {
record[id]?.add(Tick(name, System.currentTimeMillis()))
}
fun end(id: String) {
tick(id, "end")
}
fun clear(id: String) {
record.remove(id)
}
fun toFormattedString(id: String): String? {
if(record[id] == null) return null
val builder = StringBuilder()
val list = record[id]!!
val maxNameLength = list.map { it.name.length }.maxOrNull() ?: 0
val maxTimeLength = list.map { it.timeInMillis.toString().length }.maxOrNull() ?: 0
val format = "%-${maxNameLength+4}s%${maxTimeLength+4}s%16s%16s"
builder.append(String.format(format, "Name", "Time", "Used(ms)", "Passed(ms)")).append(System.lineSeparator())
var t = list.first().timeInMillis
val start = t
for (tick in list) {
builder.append(
String.format(format,
tick.name,
tick.timeInMillis,
tick.timeInMillis - t,
tick.timeInMillis - start),
)
.append(System.lineSeparator())
t = tick.timeInMillis
}
builder.append(System.lineSeparator())
builder.append("Total: ${list.last().timeInMillis - list.first().timeInMillis} ms").append(System.lineSeparator())
return builder.toString()
}
}
}
package me.imlc.example
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Test
import java.util.concurrent.CompletableFuture
internal class TrackerTest {
@Test
internal fun toFormattedString() {
val id = Tracker.start()
runBlocking {
Tracker.tick(id, "load configuration")
delay(200)
Tracker.tick(id, "connect to database")
delay(300)
Tracker.tick(id, "prepare documentation")
delay(400)
Tracker.tick(id, "ready for service")
}
Tracker.end(id)
println(Tracker.toFormattedString(id))
/*
Name Time Used(ms) Passed(ms)
start 1599671093021 0 0
load configuration 1599671093104 83 83
connect to database 1599671093315 211 294
prepare documentation 1599671093617 302 596
ready for service 1599671094018 401 997
end 1599671094019 1 998
Total: 998
*/
}
@Test
internal fun toFormattedString_MultipleThreads() {
val id = Tracker.start()
CompletableFuture.completedFuture(null)
.thenApply { sleep(); Tracker.tick(id , "Load Cache")}
.thenApply { sleep(); Tracker.tick(id , "HTTP GET")}
.thenApply { sleep(); Tracker.tick(id , "Write Database")}
.thenApply { Tracker.end(id) }
.thenApply { println(Tracker.toFormattedString(id)) }
.join()
}
fun sleep() {
Thread.sleep(100)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment