From c511f95d15644511d77b99e671989094b410602d Mon Sep 17 00:00:00 2001 From: Bruce Hamilton Date: Wed, 29 Nov 2023 12:53:50 +0100 Subject: [PATCH] fixup! Improvements for 3.0.0 --- allocation-benchmark/allocations/common.js | 20 +++++++ .../allocations/previewClasses.html | 41 +++++++------- .../allocations/previewSites.html | 40 +++++++------- allocation-benchmark/allocations/style.css | 6 +++ .../src/main/kotlin/benchmarks/Application.kt | 1 - .../main/kotlin/benchmarks/LocationInfo.kt | 5 -- .../main/kotlin/benchmarks/ReportServer.kt | 1 + .../test/kotlin/ServerCallAllocationTest.kt | 54 +++++++++++++------ .../src/test/kotlin/utils/ReportUtils.kt | 23 +++++--- 9 files changed, 122 insertions(+), 69 deletions(-) diff --git a/allocation-benchmark/allocations/common.js b/allocation-benchmark/allocations/common.js index e166833..e6cf4f7 100644 --- a/allocation-benchmark/allocations/common.js +++ b/allocation-benchmark/allocations/common.js @@ -30,4 +30,24 @@ export function displaySite(sites, item) { li.append("span").attr("class", "file").text(file) li.append("span").attr("class", "fun").text(fun) }) +} + +export function setupRenderControls(drawAllocations) { + const render = () => { + const engineName = document.querySelector("input[name='engine']:checked").value + const snapshotDir = document.querySelector("input[name='snapshot']:checked").value + const reportPath = `${snapshotDir}/testMemoryConsumptionIsSame[${engineName}].json`; + d3.json(reportPath).then(result => { + drawAllocations(result.data) + document.getElementById("info").innerText = "" + }, () => { + drawAllocations({}) + document.getElementById("info").innerText = `Nothing found for ${reportPath}` + }) + } + document.querySelectorAll("input[type='radio']").forEach(elem => { + elem.onchange = render + }) + + render() } \ No newline at end of file diff --git a/allocation-benchmark/allocations/previewClasses.html b/allocation-benchmark/allocations/previewClasses.html index b9ab7d0..9a7e26b 100644 --- a/allocation-benchmark/allocations/previewClasses.html +++ b/allocation-benchmark/allocations/previewClasses.html @@ -12,12 +12,25 @@
-
@@ -27,7 +40,7 @@ diff --git a/allocation-benchmark/allocations/previewSites.html b/allocation-benchmark/allocations/previewSites.html index f0a4d5b..5ed0890 100644 --- a/allocation-benchmark/allocations/previewSites.html +++ b/allocation-benchmark/allocations/previewSites.html @@ -12,12 +12,25 @@
-
@@ -27,7 +40,7 @@ diff --git a/allocation-benchmark/allocations/style.css b/allocation-benchmark/allocations/style.css index ebf61ba..71c5f6c 100644 --- a/allocation-benchmark/allocations/style.css +++ b/allocation-benchmark/allocations/style.css @@ -2,6 +2,12 @@ body { font-family: 'JetBrains Mono', monospace; font-size: 11pt; } +header { + display: flex; + gap: 1rem; + justify-content: space-evenly; + padding: 0 1rem 2rem 1rem; +} main { display: grid; grid-template-columns: 55% 45%; diff --git a/allocation-benchmark/src/main/kotlin/benchmarks/Application.kt b/allocation-benchmark/src/main/kotlin/benchmarks/Application.kt index 7953c04..9745754 100644 --- a/allocation-benchmark/src/main/kotlin/benchmarks/Application.kt +++ b/allocation-benchmark/src/main/kotlin/benchmarks/Application.kt @@ -1,7 +1,6 @@ package benchmarks import io.ktor.http.* -import io.ktor.http.content.* import io.ktor.server.application.* import io.ktor.server.cio.* import io.ktor.server.engine.* diff --git a/allocation-benchmark/src/main/kotlin/benchmarks/LocationInfo.kt b/allocation-benchmark/src/main/kotlin/benchmarks/LocationInfo.kt index b7e5ab1..152141c 100644 --- a/allocation-benchmark/src/main/kotlin/benchmarks/LocationInfo.kt +++ b/allocation-benchmark/src/main/kotlin/benchmarks/LocationInfo.kt @@ -19,11 +19,6 @@ class LocationInfo(val name: String) { } override fun toString(): String = buildString { - val instances = instanceIndex.values.sortedByDescending { it.totalSize } - appendLine("Location: $name. Size: ${locationSize.formatSize()}") -// instances.forEach { -// appendLine(it) -// } } } diff --git a/allocation-benchmark/src/main/kotlin/benchmarks/ReportServer.kt b/allocation-benchmark/src/main/kotlin/benchmarks/ReportServer.kt index 92e99ff..25fbd5c 100644 --- a/allocation-benchmark/src/main/kotlin/benchmarks/ReportServer.kt +++ b/allocation-benchmark/src/main/kotlin/benchmarks/ReportServer.kt @@ -11,6 +11,7 @@ fun main() { embeddedServer(Netty, port = port) { routing { staticFiles("/", File("allocations")) + staticFiles("/test_output", File("build/allocations")) } println(""" diff --git a/allocation-benchmark/src/test/kotlin/ServerCallAllocationTest.kt b/allocation-benchmark/src/test/kotlin/ServerCallAllocationTest.kt index ae36439..bac324e 100644 --- a/allocation-benchmark/src/test/kotlin/ServerCallAllocationTest.kt +++ b/allocation-benchmark/src/test/kotlin/ServerCallAllocationTest.kt @@ -1,13 +1,14 @@ package benchmarks -import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.ValueSource +import kotlin.math.absoluteValue const val TEST_SIZE = 1000 const val WARMUP_SIZE = 10 -const val ALLOWED_MEMORY_DIFFERENCE = 100 +const val ALLOWED_MEMORY_DIFFERENCE = 250L class ServerCallAllocationTest { @@ -16,35 +17,54 @@ class ServerCallAllocationTest { fun testMemoryConsumptionIsSame(engine: String) { val reportName = "testMemoryConsumptionIsSame[$engine]" - val memory = measureMemory(engine) { + val snapshot = measureMemory(engine) { repeat(TEST_SIZE) { makeRequest() } } - if (SAVE_REPORT) { - saveReport(reportName, memory) - saveSiteStatistics(reportName, memory) - println("Report updated: $reportName") - val consumedMemory = memory.totalSize() / TEST_SIZE - println("Request consumes ${consumedMemory.kb}") - return - } + saveReport(reportName, snapshot, replace = SAVE_REPORT) + saveSiteStatistics(reportName, snapshot, replace = SAVE_REPORT) - val consumedMemory = memory.totalSize() / TEST_SIZE - val expectedMemory = loadReport(reportName).totalSize() / TEST_SIZE + val previousSnapshot = loadReport(reportName) + val consumedMemory = snapshot.totalSize() / TEST_SIZE + val expectedMemory = previousSnapshot.totalSize() / TEST_SIZE val difference = consumedMemory - expectedMemory val message = """ Request consumes ${consumedMemory.kb}, expected ${expectedMemory.kb}. Difference: ${(consumedMemory - expectedMemory).kb} - Consumed ${consumedMemory.kb} on request - Expected ${expectedMemory.kb} on request - Extra consumed ${(consumedMemory - expectedMemory).kb} on request + Consumed ${consumedMemory.kb} on request + Expected ${expectedMemory.kb} on request + ${if (difference > 0L) "Extra " else "Saved "} ${difference.absoluteValue.kb} on request + (See stdout + build/allocations/* files for details) """.trimIndent().also(::println) - assertTrue(difference - ALLOWED_MEMORY_DIFFERENCE <= 0, message) + if (SAVE_REPORT) { + println("Report updated: $reportName") + return + } + + println("\nIncreased locations:") + snapshot.packages.mapNotNull { location -> + LocationDifference(previousSnapshot[location.name], location).takeIf { + it.difference() > 0 + } + }.sortedByDescending { it.difference() }.forEach { diff -> + val (previous, current) = diff + println("\t" + current.name.padEnd(40) + diff.difference().kb.padStart(10) + " (${(previous?.locationSize?.kb ?: "0").padEnd(12)} --> ${current.locationSize.kb.padStart(12)})") + } + + val increase = maxOf(difference - ALLOWED_MEMORY_DIFFERENCE, 0) + assertEquals(0L, increase, message) } private val Long.kb get() = "%.2f KB".format(toDouble() / 1024.0) + data class LocationDifference( + val previous: LocationInfo?, + val current: LocationInfo + ) { + fun difference() = previous?.let { current.locationSize - it.locationSize } ?: current.locationSize + } + } diff --git a/allocation-benchmark/src/test/kotlin/utils/ReportUtils.kt b/allocation-benchmark/src/test/kotlin/utils/ReportUtils.kt index 8e7fd22..3cb688b 100644 --- a/allocation-benchmark/src/test/kotlin/utils/ReportUtils.kt +++ b/allocation-benchmark/src/test/kotlin/utils/ReportUtils.kt @@ -1,7 +1,6 @@ package benchmarks import kotlinx.serialization.Serializable -import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import java.io.File @@ -10,11 +9,17 @@ private val serializer = Json { prettyPrint = true } -fun saveReport(name: String, report: AllocationData) { - val file = File("allocations/$name.json") - if (!file.exists()) { +fun saveReport(name: String, report: AllocationData, replace: Boolean = true) { + val file = if (replace) + File("allocations/$name.json") + else + File("build/allocations/$name.json") + + if (!file.parentFile.exists()) + file.parentFile.mkdirs() + + if (!file.exists()) file.createNewFile() - } val content = serializer.encodeToString(report) file.bufferedWriter().use { @@ -30,8 +35,12 @@ data class SiteWithName( var totalSize: Long ) -fun saveSiteStatistics(name: String, report: AllocationData) { - val file = File("allocations/sites_$name.json") +fun saveSiteStatistics(name: String, report: AllocationData, replace: Boolean) { + val file = if (replace) + File("allocations/sites_$name.json") + else + File("build/allocations/sites_$name.json") + if (!file.exists()) { file.createNewFile() }