blob: 90c0281eb4efc07c87a3f156be0cf37aa72a3a7d [file] [log] [blame]
/*
* Copyright 2018 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Notes
*
* TODO (chriswailes): Support JSON output
*/
/*
* Imports
*/
import java.io.File
import trebuchet.model.Model
import trebuchet.extras.parseTrace
import trebuchet.util.time.*
/*
* Constants
*/
/*
* Class Definition
*/
/*
* Class Extensions
*/
/*
* Helper Functions
*/
fun measureStartup(model: Model) {
val startupEvents = model.getStartupEvents()
println("Found ${startupEvents.count()} startup events.")
startupEvents.forEach { startupEvent ->
println()
println("App Startup summary for ${startupEvent.name} (${startupEvent.proc.id}):")
println("\tStart offset: ${(startupEvent.startTime - model.beginTimestamp).secondValueToMillisecondString()}")
println("\tLaunch duration: ${(startupEvent.endTime - startupEvent.startTime).secondValueToMillisecondString()}")
if (startupEvent.reportFullyDrawnTime == null) {
println("\tRFD duration: N/A")
} else {
println("\tRFD duration: ${(startupEvent.reportFullyDrawnTime!! - startupEvent.startTime).secondValueToMillisecondString()}")
}
println("\tServer fork time: ${startupEvent.serverSideForkTime.secondValueToMillisecondString()}")
println("\tTime to first slice: ${(startupEvent.firstSliceTime - startupEvent.startTime).secondValueToMillisecondString()}")
println("\tUndifferentiated time: ${startupEvent.undifferentiatedTime.secondValueToMillisecondString()}")
println()
println("\tScheduling timings:")
startupEvent.schedTimings.toSortedMap().forEach { schedState, timing ->
println("\t\t${schedState.friendlyName}: ${timing.secondValueToMillisecondString()}")
}
println()
println("\tTop-level slice information:")
startupEvent.topLevelSliceInfo.toSortedMap(java.lang.String.CASE_INSENSITIVE_ORDER).forEach { sliceName, aggInfo ->
println("\t\t$sliceName")
println("\t\t\tEvent count: ${aggInfo.count}")
println("\t\t\tTotal duration: ${aggInfo.totalTime.secondValueToMillisecondString()}")
}
println()
println("\tAll slice information:")
startupEvent.allSlicesInfo.toSortedMap(java.lang.String.CASE_INSENSITIVE_ORDER).forEach { sliceName, aggInfo->
println("\t\t$sliceName")
println("\t\t\tEvent count: ${aggInfo.count}")
println("\t\t\tTotal duration: ${aggInfo.totalTime.secondValueToMillisecondString()}")
if (aggInfo.values.count() > 0) {
println("\t\t\tEvent details:")
aggInfo.values.toSortedMap(java.lang.String.CASE_INSENSITIVE_ORDER).forEach { value, (count, duration) ->
println("\t\t\t\t$value ${if (count > 1) "x $count " else ""}@ ${duration.secondValueToMillisecondString()}")
}
}
}
println()
}
}
/*
* Main Function
*/
fun main(args: Array<String>) {
if (args.isEmpty()) {
println("Usage: StartAnalyzerKt <trace filename>")
return
}
val filename = args[0]
println("Opening `$filename`")
val trace = parseTrace(File(filename), verbose = false)
measureStartup(trace)
}