Skip to content

Commit 62b13c1

Browse files
committed
feat: implement build cache support and incremental builds
- Added comprehensive input/output annotations for caching - Implemented incremental build logic for configuration changes - Added proper path sensitivity and cache key generation - Optimized model file processing for performance Completes Prompt 8 of implementation plan
1 parent df1e631 commit 62b13c1

File tree

5 files changed

+506
-27
lines changed

5 files changed

+506
-27
lines changed
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
package aws.sdk.kotlin.gradle.customsdk
6+
7+
import org.gradle.api.Project
8+
import org.gradle.api.tasks.TaskProvider
9+
import java.io.File
10+
import java.security.MessageDigest
11+
12+
/**
13+
* Utilities for optimizing build cache performance and incremental builds.
14+
*/
15+
object BuildCacheOptimization {
16+
17+
/**
18+
* Configure build cache settings for the custom SDK generation task.
19+
*/
20+
fun configureBuildCache(project: Project, generateTask: TaskProvider<GenerateCustomSdkTask>) {
21+
project.afterEvaluate {
22+
generateTask.get().apply {
23+
// Enable caching for this task
24+
outputs.cacheIf { true }
25+
26+
// Configure cache key normalization
27+
configureCacheKeyNormalization(this)
28+
29+
// Set up cache debugging if enabled
30+
if (project.hasProperty("customSdk.debug.cache")) {
31+
configureCacheDebugging(project, this)
32+
}
33+
}
34+
}
35+
36+
project.logger.info("Configured build cache optimization for custom SDK generation")
37+
}
38+
39+
/**
40+
* Configure cache key normalization for better cache hit rates.
41+
*/
42+
private fun configureCacheKeyNormalization(task: GenerateCustomSdkTask) {
43+
// The task already has proper input annotations
44+
// Additional normalization can be added here if needed
45+
46+
// Ensure deterministic ordering of operations for consistent cache keys
47+
task.outputs.doNotCacheIf("No operations selected") {
48+
task.selectedOperations.get().isEmpty()
49+
}
50+
}
51+
52+
/**
53+
* Configure cache debugging for troubleshooting cache misses.
54+
*/
55+
private fun configureCacheDebugging(project: Project, task: GenerateCustomSdkTask) {
56+
task.doFirst {
57+
project.logger.lifecycle("Custom SDK Cache Debug:")
58+
project.logger.lifecycle(" Cache key components: ${task.cacheKeyComponents}")
59+
project.logger.lifecycle(" Selected operations: ${task.selectedOperations.get()}")
60+
project.logger.lifecycle(" Package name: ${task.packageName.get()}")
61+
project.logger.lifecycle(" Package version: ${task.packageVersion.get()}")
62+
}
63+
}
64+
65+
/**
66+
* Optimize model file loading for better performance.
67+
*/
68+
fun optimizeModelFileLoading(modelsDirectory: File): List<File> {
69+
if (!modelsDirectory.exists()) {
70+
return emptyList()
71+
}
72+
73+
// Load only JSON model files and sort for deterministic processing
74+
return modelsDirectory.listFiles { file ->
75+
file.isFile && file.extension == "json"
76+
}?.sortedBy { it.name } ?: emptyList()
77+
}
78+
79+
/**
80+
* Create a stable hash for cache key generation.
81+
*/
82+
fun createStableHash(input: String): String {
83+
val digest = MessageDigest.getInstance("SHA-256")
84+
val hashBytes = digest.digest(input.toByteArray())
85+
return hashBytes.joinToString("") { "%02x".format(it) }.take(16)
86+
}
87+
88+
/**
89+
* Check if incremental build is beneficial based on input changes.
90+
*/
91+
fun shouldUseIncrementalBuild(
92+
previousOperations: Map<String, List<String>>,
93+
currentOperations: Map<String, List<String>>
94+
): Boolean {
95+
// Use incremental build if operations haven't changed significantly
96+
val previousSet = previousOperations.values.flatten().toSet()
97+
val currentSet = currentOperations.values.flatten().toSet()
98+
99+
val addedOperations = currentSet - previousSet
100+
val removedOperations = previousSet - currentSet
101+
102+
// Use incremental if changes are minimal (less than 20% change)
103+
val totalOperations = maxOf(previousSet.size, currentSet.size)
104+
val changedOperations = addedOperations.size + removedOperations.size
105+
106+
return totalOperations > 0 && (changedOperations.toDouble() / totalOperations) < 0.2
107+
}
108+
109+
/**
110+
* Configure performance monitoring for the generation task.
111+
*/
112+
fun configurePerformanceMonitoring(project: Project, generateTask: TaskProvider<GenerateCustomSdkTask>) {
113+
project.afterEvaluate {
114+
generateTask.get().apply {
115+
var startTime: Long = 0
116+
117+
doFirst {
118+
startTime = System.currentTimeMillis()
119+
project.logger.info("Starting custom SDK generation...")
120+
}
121+
122+
doLast {
123+
val duration = System.currentTimeMillis() - startTime
124+
val operations = selectedOperations.get().values.flatten().size
125+
126+
project.logger.lifecycle("Custom SDK generation completed:")
127+
project.logger.lifecycle(" Duration: ${duration}ms")
128+
project.logger.lifecycle(" Operations: $operations")
129+
if (duration > 0) {
130+
project.logger.lifecycle(" Performance: ${operations.toDouble() / (duration / 1000.0)} ops/sec")
131+
}
132+
}
133+
}
134+
}
135+
}
136+
137+
/**
138+
* Configure memory optimization for large SDK generations.
139+
*/
140+
fun configureMemoryOptimization(project: Project, generateTask: TaskProvider<GenerateCustomSdkTask>) {
141+
project.afterEvaluate {
142+
generateTask.get().apply {
143+
doFirst {
144+
val operations = selectedOperations.get().values.flatten().size
145+
146+
if (operations > 100) {
147+
project.logger.info("Large SDK generation detected ($operations operations)")
148+
project.logger.info("Consider increasing JVM heap size if generation fails")
149+
}
150+
}
151+
}
152+
}
153+
}
154+
}

plugins/custom-sdk-build/src/main/kotlin/aws/sdk/kotlin/gradle/customsdk/CustomSdkBuildPlugin.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ class CustomSdkBuildPlugin : Plugin<Project> {
8080
// Configure source sets and dependencies
8181
configureSourceSets(project, generateTask)
8282

83+
// Configure build cache and performance optimizations
84+
configureBuildOptimizations(project, generateTask)
85+
8386
} catch (e: Exception) {
8487
project.logger.error("Failed to configure Custom SDK Build plugin: ${e.message}")
8588
throw e
@@ -134,6 +137,22 @@ class CustomSdkBuildPlugin : Plugin<Project> {
134137
project.logger.info("Source set configuration completed for custom SDK build")
135138
}
136139

140+
/**
141+
* Configure build cache and performance optimizations.
142+
*/
143+
private fun configureBuildOptimizations(project: Project, generateTask: TaskProvider<GenerateCustomSdkTask>) {
144+
// Configure build cache optimization
145+
BuildCacheOptimization.configureBuildCache(project, generateTask)
146+
147+
// Configure performance monitoring
148+
BuildCacheOptimization.configurePerformanceMonitoring(project, generateTask)
149+
150+
// Configure memory optimization
151+
BuildCacheOptimization.configureMemoryOptimization(project, generateTask)
152+
153+
project.logger.info("Build optimizations configured for custom SDK generation")
154+
}
155+
137156
/**
138157
* Create placeholder model files for demonstration.
139158
* In a real implementation, these would be the actual AWS service models.

0 commit comments

Comments
 (0)