Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions codegen/codegen-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import java.io.Serializable

plugins {
id("smithy-java.codegen-plugin-conventions")
id("smithy-java.publishing-conventions")
Expand Down Expand Up @@ -96,3 +98,63 @@ tasks.test {
configureIntegTests {
awsModelTests = true
}

val artifactStatsDir = project.layout.buildDirectory.dir("reports/artifact-stats")

class PrintArtifactSizeStats(
private val statsPath: String,
) : Action<Task>,
Serializable {
override fun execute(task: Task) {
val statsFile = File(statsPath, "artifact-size-stats.tsv")
if (!statsFile.exists()) {
return
}

val entries =
statsFile
.readLines()
.filter { it.isNotBlank() }
.map { line ->
val (name, size) = line.split('\t')
name to size.toLong()
}.sortedBy { it.second }

if (entries.isEmpty()) {
return
}

val total = entries.sumOf { it.second }
val avg = total / entries.size
val (minName, minSize) = entries.first()
val (maxName, maxSize) = entries.last()

fun humanReadable(bytes: Long): String =
when {
bytes < 1024 -> "$bytes B"
bytes < 1024 * 1024 -> "%.1f KB".format(bytes / 1024.0)
else -> "%.1f MB".format(bytes / (1024.0 * 1024.0))
}

println()
println("========== Compiled Artifact Size Statistics ==========")
println(" SDKs processed: ${entries.size}")
println(" Average size: ${humanReadable(avg)} (%,d bytes)".format(avg))
println(" Min size: ${humanReadable(minSize)} (%,d bytes) -> $minName".format(minSize))
println(" Max size: ${humanReadable(maxSize)} (%,d bytes) -> $maxName".format(maxSize))
println(" Total: ${humanReadable(total)} (%,d bytes)".format(total))
println("=======================================================")
println()
println("Top 5 largest SDKs:")
for ((name, size) in entries.takeLast(5).reversed()) {
println(" %-50s %s".format(name, humanReadable(size)))
}
}
}

tasks.named<Test>("integ") {
val statsPath = artifactStatsDir.get().asFile.absolutePath
systemProperty("artifactStatsDir", statsPath)
outputs.dir(artifactStatsDir)
doLast(PrintArtifactSizeStats(statsPath))
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.tools.Diagnostic;
Expand All @@ -33,6 +36,7 @@
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Named;
import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
import org.junit.jupiter.api.parallel.Execution;
Expand All @@ -57,11 +61,26 @@
@EnabledIfSystemProperty(named = "awsModelsTests", matches = "true")
class AwsModelCodegenCompilationTest {

private static final Map<String, Long> artifactSizes = new ConcurrentHashMap<>();

private static final Set<String> IGNORED_SDK_IDS = Set.of(
"timestream-write",
"timestream-query",
"clouddirectory");

@AfterAll
static void writeArtifactSizeStatistics() throws IOException {
var sb = new StringBuilder();
artifactSizes.forEach((key, value) -> sb.append(key)
.append('\t')
.append(value)
.append('\n'));

Path outputDir = Path.of(System.getProperty("artifactStatsDir", "build"));
Files.createDirectories(outputDir);
Files.writeString(outputDir.resolve("artifact-size-stats.tsv"), sb.toString());
}

static Stream<Named<URL>> awsModels() {
return ModelDiscovery.findModels()
.stream()
Expand Down Expand Up @@ -148,6 +167,7 @@ private void generateAndCompile(URL modelUrl, String... modes) {
fail(Arrays.toString(modes) + " compilation failed for " + service.getId()
+ ". Generated sources dumped to: " + dumpFile + "\n" + errors);
}
artifactSizes.put(artifactName(modelUrl), fm.getTotalBytesWritten());
}
}
} catch (Throwable t) {
Expand Down Expand Up @@ -201,13 +221,19 @@ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
}

/**
* In-memory output manager — discards .class bytes.
* In-memory output manager — captures .class byte counts.
*/
private static class InMemoryFileManager extends ForwardingJavaFileManager<StandardJavaFileManager> {
private final AtomicLong totalBytesWritten = new AtomicLong();

InMemoryFileManager(StandardJavaFileManager delegate) {
super(delegate);
}

long getTotalBytesWritten() {
return totalBytesWritten.get();
}

@Override
public JavaFileObject getJavaFileForOutput(
JavaFileManager.Location location,
Expand All @@ -220,7 +246,13 @@ public JavaFileObject getJavaFileForOutput(
kind) {
@Override
public OutputStream openOutputStream() {
return new ByteArrayOutputStream();
return new ByteArrayOutputStream() {
@Override
public void close() throws IOException {
super.close();
totalBytesWritten.addAndGet(size());
}
};
}
};
}
Expand Down