import java.text.DecimalFormat
import java.text.SimpleDateFormat
task generateProfilerReport {
group = "Verification"
description = "Aggregates profiler data with configurable latency flags, coverage, and time range."
def csvFile = file("$buildDir/profiler-results/profiler_combined_report.csv")
def targetsFile = file("${projectDir}/profiler_targets.txt")
def reportFile = file("$buildDir/profiler-results/performance_summary.txt")
doLast {
def thresholdStr = project.findProperty("threshold") ?: "100"
double threshold = thresholdStr.toDouble()
def sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
String startTime = null
String endTime = null
if (!targetsFile.exists()) {
throw new GradleException("Target list not found at ${targetsFile.absolutePath}")
}
def aggregated = [:]
targetsFile.eachLine { line ->
def trimmed = line.trim()
if (!trimmed.isEmpty() && !trimmed.startsWith("#")) {
aggregated[trimmed] = [0L, 0.0d]
}
}
if (csvFile.exists()) {
csvFile.eachLine { line, index ->
if (index <= 1 || line.trim().isEmpty()) return
def parts = line.split(',')
if (parts.length >= 5) {
def timestamp = parts[0]
if (startTime == null) startTime = timestamp
endTime = timestamp
def methodWithClass = parts[1]
def calls = parts[2].toLong()
def totalMs = parts[4].toDouble()
if (aggregated.containsKey(methodWithClass)) {
def current = aggregated[methodWithClass]
aggregated[methodWithClass] = [current[0] + calls, current[1] + totalMs]
} else {
aggregated[methodWithClass] = [calls, totalMs]
}
}
}
}
// --- FIXED DURATION LOGIC ---
String durationStr = "0m 0s"
if (startTime && endTime) {
long diff = sdf.parse(endTime).time - sdf.parse(startTime).time
if (diff > 0) {
long totalSeconds = (diff / 1000) as long
long mins = totalSeconds.intdiv(60)
long secs = totalSeconds % 60
durationStr = "${mins}m ${secs}s"
} else if (startTime == endTime && startTime != null) {
durationStr = "0m 0s (Single Snapshot)"
}
}
int totalTargets = aggregated.size()
int executedTargets = aggregated.values().count { it[0] > 0 }
double coveragePercent = totalTargets > 0 ? (executedTargets / (double)totalTargets) * 100 : 0
def sortedResults = aggregated.entrySet().sort { a, b ->
b.value[1] <=> a.value[1] ?: b.value[0] <=> a.value[0] ?: a.key <=> b.key
}
def thickDivider = "=" * 110
def thinDivider = "-" * 110
def reportHeader = """
${thickDivider}
PROFILER FULL REPORT: ${new Date().format('yyyy-MM-dd HH:mm:ss')}
Time Range: [${startTime ?: 'N/A'}] to [${endTime ?: 'N/A'}] (Duration: ${durationStr})
Threshold: > ${threshold}ms | Source: ${csvFile.exists() ? csvFile.name : "NO DATA FOUND"}
${thickDivider}
${String.format("%-55s | %8s | %10s | %10s | %s", "Method Name", "Calls", "Total MS", "Avg MS", "Flag")}
${thinDivider}"""
StringBuilder reportBody = new StringBuilder()
sortedResults.each { entry ->
def method = entry.key
def calls = entry.value[0]
def totalMs = entry.value[1]
def avgMs = (calls > 0) ? (totalMs / calls) : 0.0d
def flag = (avgMs > threshold) ? "⚠️ SLOW" : ""
reportBody.append(String.format("%-55s | %8d | %10.2f | %10.4f | %s\n",
method, calls, totalMs, avgMs, flag))
}
def summaryFooter = """
${thinDivider}
COVERAGE SUMMARY:
Total Methods Tracked: ${totalTargets}
Methods Executed: ${executedTargets}
Coverage Percentage: ${String.format("%.2f", coveragePercent)}%
${thickDivider}"""
def finalReport = reportHeader + "\n" + reportBody.toString() + summaryFooter
println finalReport
reportFile.parentFile.mkdirs()
reportFile.text = finalReport
println "\n[REPORT]: Saved to ${reportFile.absolutePath}"
}
}
For further actions, you may consider blocking this person and/or reporting abuse
Top comments (0)