diff --git a/.gitlab/fuzzing/.gitlab-ci.yml b/.gitlab/fuzzing/.gitlab-ci.yml index 8c03caac10..3e8078c077 100644 --- a/.gitlab/fuzzing/.gitlab-ci.yml +++ b/.gitlab/fuzzing/.gitlab-ci.yml @@ -8,7 +8,7 @@ fuzz_infra: image: registry.ddbuild.io/images/docker:27.3.1 tags: ["arch:amd64"] stage: fuzz - timeout: 30m + timeout: 1h30m allow_failure: true id_tokens: DDSIGN_ID_TOKEN: diff --git a/build-logic/conventions/src/main/kotlin/com/datadoghq/native/fuzz/FuzzTargetsPlugin.kt b/build-logic/conventions/src/main/kotlin/com/datadoghq/native/fuzz/FuzzTargetsPlugin.kt index c4a5477399..48dcca114c 100644 --- a/build-logic/conventions/src/main/kotlin/com/datadoghq/native/fuzz/FuzzTargetsPlugin.kt +++ b/build-logic/conventions/src/main/kotlin/com/datadoghq/native/fuzz/FuzzTargetsPlugin.kt @@ -108,6 +108,26 @@ class FuzzTargetsPlugin : Plugin { val crashDir = extension.crashDir.get().asFile val duration = extension.duration.get() + // Profiler sources are identical for every fuzz target (same compiler args and + // includes), so compile them once and share the resulting objects across targets + // instead of recompiling the whole profiler per target. + val sharedObjDir = project.file("${project.layout.buildDirectory.get()}/obj/fuzz/_profiler") + val compileProfilerTask = project.tasks.register("compileFuzzProfilerSources", NativeCompileTask::class.java) { + onlyIf { hasFuzzer && !project.hasProperty("skip-tests") && !project.hasProperty("skip-native") && !project.hasProperty("skip-fuzz") } + group = "build" + description = "Compile the profiler sources shared by all fuzz targets" + + this.compiler.set(compiler) + this.compilerArgs.set(compilerArgs) + sources.from( + extension.profilerSourceDir.map { dir -> + project.fileTree(dir) { include("**/*.cpp") } + } + ) + includes.from(includeFiles) + objectFileDir.set(sharedObjDir) + } + // Discover and create tasks for each fuzz target if (fuzzSourceDir.exists()) { fuzzSourceDir.listFiles()?.filter { file -> file.name.endsWith(".cpp") }?.forEach { fuzzFile -> @@ -119,7 +139,8 @@ class FuzzTargetsPlugin : Plugin { val binary = project.file("$binDir/$fuzzName") val targetCorpusDir = File(corpusBaseDir, fuzzName) - // Compile task + // Compile task - only compiles this target's own fuzz driver; profiler + // sources come from the shared compileFuzzProfilerSources task. val compileTask = project.tasks.register("compileFuzz_$fuzzName", NativeCompileTask::class.java) { onlyIf { hasFuzzer && !project.hasProperty("skip-tests") && !project.hasProperty("skip-native") && !project.hasProperty("skip-fuzz") } group = "build" @@ -127,12 +148,7 @@ class FuzzTargetsPlugin : Plugin { this.compiler.set(compiler) this.compilerArgs.set(compilerArgs) - sources.from( - extension.profilerSourceDir.map { dir -> - project.fileTree(dir) { include("**/*.cpp") } - }, - fuzzFile - ) + sources.from(fuzzFile) includes.from(includeFiles) objectFileDir.set(objDir) } @@ -140,13 +156,16 @@ class FuzzTargetsPlugin : Plugin { // Link task val linkTask = project.tasks.register("linkFuzz_$fuzzName", NativeLinkExecutableTask::class.java) { onlyIf { hasFuzzer && !project.hasProperty("skip-tests") && !project.hasProperty("skip-native") && !project.hasProperty("skip-fuzz") } - dependsOn(compileTask) + dependsOn(compileProfilerTask, compileTask) group = "build" description = "Link the fuzz target $fuzzName" linker.set(compiler) this.linkerArgs.set(linkerArgs) - objectFiles.from(project.fileTree(objDir) { include("*.o") }) + objectFiles.from( + project.fileTree(sharedObjDir) { include("*.o") }, + project.fileTree(objDir) { include("*.o") } + ) outputFile.set(binary) }