Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package gov.nasa.jpl.aerie.banananation;

import gov.nasa.jpl.aerie.banananation.generated.ActivityTypes;
import org.junit.jupiter.api.Test;

import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;

public class ActivityTypesPerformanceTest {

@Test
public void testActivityTypesLoadTime() {
// Warm up JVM
System.gc();

long startTime = System.nanoTime();
var directiveTypes = ActivityTypes.directiveTypes;
long endTime = System.nanoTime();

long durationMs = (endTime - startTime) / 1_000_000;

System.out.println("=== ActivityTypes Load Performance ===");
System.out.println("Time to load directiveTypes: " + durationMs + " ms");
System.out.println("Number of activities loaded: " + directiveTypes.size());
System.out.println("Average time per activity: " + (durationMs / (double) directiveTypes.size()) + " ms");

// Verify it actually works
assert directiveTypes.size() > 0 : "No activities loaded!";
assert directiveTypes.containsKey("BiteBanana") : "BiteBanana not found!";

// Test subsequent access (should be instant)
startTime = System.nanoTime();
var directiveTypes2 = ActivityTypes.directiveTypes;
endTime = System.nanoTime();
long subsequentAccessNs = endTime - startTime;

System.out.println("Subsequent access time: " + subsequentAccessNs + " ns (< 1 microsecond)");

// Memory usage
MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
System.out.println("Heap memory used: " + (heapUsage.getUsed() / 1024 / 1024) + " MB");
}

@Test
public void testDirectiveTypesAccess() {
// Test that normal access patterns are unaffected
long startTime = System.nanoTime();

for (int i = 0; i < 10000; i++) {
var mapper = ActivityTypes.directiveTypes.get("BiteBanana");
assert mapper != null;
}

long endTime = System.nanoTime();
long totalTimeMs = (endTime - startTime) / 1_000_000;

System.out.println("=== Map Access Performance ===");
System.out.println("10,000 Map lookups took: " + totalTimeMs + " ms");
System.out.println("Average per lookup: " + (totalTimeMs / 10000.0) + " ms");
}

@Test
public void testReflectionOverhead() {
// Measure just the reflection cost by timing class load
long startTime = System.nanoTime();

try {
for (int i = 0; i < 100; i++) {
Class<?> clazz = Class.forName("gov.nasa.jpl.aerie.banananation.generated.ActivityTypes_BiteBanana");
var field = clazz.getField("directiveTypes");
var value = field.get(null);
}
} catch (Exception e) {
throw new RuntimeException(e);
}

long endTime = System.nanoTime();
double avgTimeMs = (endTime - startTime) / 1_000_000.0 / 100.0;

System.out.println("=== Reflection Overhead ===");
System.out.println("Average reflection cost per activity: " + avgTimeMs + " ms");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,17 @@ public final class MissionModelProcessor implements Processor {

@Override
public Set<String> getSupportedOptions() {
return Set.of();
// Enable Gradle incremental annotation processing
// This processor generates both:
// 1. Individual Mappers (isolating - each depends on one activity)
// 2. Registry files (aggregating - depend on all activities)
// We use "isolating" and rely on originating elements to express the aggregating dependencies.
// Gradle will figure out that ActivityActions/ActivityTypes depend on all activities from the
// originating elements we register in MissionModelGenerator.
// See: https://docs.gradle.org/current/userguide/java_plugin.html#sec:incremental_annotation_processing
return Set.of(
"org.gradle.annotation.processing.isolating"
);
}

/** Elements marked by these annotations will be treated as processing roots. */
Expand Down Expand Up @@ -125,9 +135,10 @@ public boolean process(final Set<? extends TypeElement> annotations, final Round
generatedFiles.addAll(List.of(
missionModelGen.generateModelType(missionModelRecord),
missionModelGen.generateSchedulerModel(missionModelRecord),
missionModelGen.generateActivityActions(missionModelRecord),
missionModelGen.generateActivityTypes(missionModelRecord)
missionModelGen.generateActivityActions(missionModelRecord)
));
// Add all ActivityTypes files (one per activity plus master)
generatedFiles.addAll(missionModelGen.generateActivityTypes(missionModelRecord));

final var autoValueMappers = AutoValueMappers.generateAutoValueMappers(
missionModelRecord,
Expand Down
Loading
Loading