Prime Mover is a modern, high-performance discrete event simulation framework for Java. It uses bytecode transformation to convert regular Java code into event-driven simulations, with native support for blocking operations via Java virtual threads (Project Loom).
First, configure access to GitHub Packages in your ~/.m2/settings.xml:
<settings>
<servers>
<server>
<id>github</id>
<username>YOUR_GITHUB_USERNAME</username>
<password>YOUR_GITHUB_TOKEN</password>
</server>
</servers>
</settings>Note: Generate a GitHub Personal Access Token with
read:packagesscope at https://github.com/settings/tokens
Then add the repository and dependencies to your pom.xml:
<repositories>
<repository>
<id>github</id>
<url>https://maven.pkg.github.com/Hellblazer/Prime-Mover</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>github</id>
<url>https://maven.pkg.github.com/Hellblazer/Prime-Mover</url>
</pluginRepository>
</pluginRepositories>
<dependencies>
<!-- API for @Entity, Kronos, etc. -->
<dependency>
<groupId>com.hellblazer.primeMover</groupId>
<artifactId>api</artifactId>
<version>1.0.5-SNAPSHOT</version>
</dependency>
<!-- Runtime (needed for test/runtime) -->
<dependency>
<groupId>com.hellblazer.primeMover</groupId>
<artifactId>runtime</artifactId>
<version>1.0.5-SNAPSHOT</version>
<scope>test</scope> <!-- or compile if needed -->
</dependency>
</dependencies>Choose one of three transformation methods:
Option A: IntelliJ IDEA Plugin (Recommended for IDE users)
- Install from Settings > Plugins > Search "Prime Mover"
- Automatically transforms classes on build
- See primemover-intellij-plugin/README.md
Option B: Maven Plugin (Recommended for CI/CD)
<build>
<plugins>
<plugin>
<groupId>com.hellblazer.primeMover</groupId>
<artifactId>primemover-maven-plugin</artifactId>
<version>1.0.5-SNAPSHOT</version>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>transform</goal>
<goal>transform-test</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>Option C: Runtime Java Agent (For testing/prototyping)
java -javaagent:path/to/sim-agent.jar -cp ... YourSimulationimport com.hellblazer.primeMover.annotations.Entity;
import com.hellblazer.primeMover.api.Kronos;
import com.hellblazer.primeMover.controllers.SimulationController;
@Entity
public class HelloWorld {
public static void main(String[] args) {
// Create simulation controller
SimulationController controller = new SimulationController();
Kronos.setController(controller);
// Schedule initial event
new HelloWorld().event1();
// Run simulation
controller.eventLoop();
}
public void event1() {
Kronos.sleep(1); // Advance time by 1 unit
event1(); // Schedule next occurrence
System.out.println("Hello @ " + Kronos.currentTime());
}
}./mvnw clean package
java -cp target/classes:... HelloWorldMark any class as a simulation entity - its methods become simulation events:
@Entity
public class Bank {
public void openAccount(String name) {
System.out.println("Opening: " + name);
Kronos.sleep(100); // Advance simulation time
System.out.println("Account opened");
}
}When called, methods don't execute directly - they're scheduled as time-ordered events.
The static API for simulation code:
Kronos.sleep(duration) // Non-blocking time advance
Kronos.blockingSleep(duration) // Blocking time advance
Kronos.currentTime() // Query simulation time
Kronos.getController() // Access the controller
Kronos.createChannel() // Create inter-entity communicationAll these calls are rewritten during transformation to use the actual runtime implementation.
Mark methods that need to suspend execution:
@Entity
public class Task {
@Blocking
public void longOperation() {
Kronos.blockingSleep(1000); // Suspends using virtual thread continuation
System.out.println("Done");
}
}Blocking uses Java virtual threads - no threads actually block, just virtual continuations.
The simulation engine that processes events:
// Standard discrete event simulation
SimulationController controller = new SimulationController();
controller.eventLoop();
// Step through events for debugging
SteppingController controller = new SteppingController();
while (controller.hasEvents()) {
controller.processOneEvent();
}
// Real-time paced simulation
RealTimeController controller = new RealTimeController();
controller.eventLoop();api/ - Public API (@Entity, Kronos, Controller)
|
framework/ (runtime) - Runtime implementation (Kairos, SimulationController)
|
transform/ - Bytecode transformation engine
|
primemover-maven-plugin/ - Build-time transformation (Maven)
|
primemover-intellij-plugin/ - IDE integration (IntelliJ IDEA)
|
sim-agent/ - Runtime transformation (Java agent)
|
demo/ - Example simulations
|
janus/ - Composite/mixin pattern support
|
space-ghost/ - Example application using Janus
|
desmoj-ish/ - DESMOJ-compatible simulation framework
|
maven-testing/ - Plugin testing infrastructure
Original Java Code (@Entity classes)
|
v
Bytecode Transformation (ClassFile API)
- Identify event methods
- Rewrite method calls to event scheduling
- Generate EntityReference for dispatch
- Rewrite Kronos -> Kairos
|
v
Transformed Bytecode
|
v
Execution (Virtual Threads + Priority Queue)
- Events execute in time order
- Blocking suspends/resumes continuations
- Concurrent entities at same time
|
v
Simulation Results
Measured Performance (Java 25, GraalVM, Apple Silicon M1):
- Event Throughput: ~120,000 non-blocking events per second
- Blocking Events: ~45,000 blocking events per second (using virtual thread continuations)
- Build-Time Transformation: <0.5 seconds for typical codebases
- Memory Efficiency: Minimal overhead with virtual threads (~1 KB per virtual thread vs ~1 MB per platform thread)
- Transformation Overhead: Zero at runtime (transformation happens at build time)
What "Zero-Overhead" Means: Prime Mover uses build-time bytecode transformation, so there is zero transformation overhead at runtime. The simulation framework itself has necessary costs for event scheduling and management, which are efficiently implemented using native Java features.
See PERFORMANCE.md for detailed benchmarks, methodology, and optimization guidelines.
- CONCEPTS.md - Deep-dive into DES theory, Kronos/Kairos design, event semantics, and virtual thread continuations
- PERFORMANCE.md - Validated performance measurements, overhead analysis, and optimization guidelines
- COMPATIBILITY.md - Version compatibility matrix, JDK requirements, and migration guides
Each module has detailed documentation:
- api/README.md - Public API and annotations
- framework/README.md - Runtime implementation and controllers
- transform/README.md - Bytecode transformation details
- primemover-maven-plugin/README.md - Build-time integration (Maven)
- primemover-intellij-plugin/README.md - IDE integration (IntelliJ IDEA)
- sim-agent/README.md - Runtime transformation via Java agent
- demo/README.md - Example programs and patterns
- janus/README.md - Composite/mixin pattern support
- desmoj-ish/README.md - DESMOJ-compatible simulation features
- CLASSFILE_API_ANALYSIS.md - Technical deep-dive on ClassFile API
Requirements: Java 25 or later (GraalVM recommended)
# Build entire project
./mvnw clean install
# Build specific module
./mvnw clean install -pl api
# Run tests
./mvnw test
# Run specific test
./mvnw test -pl demo -Dtest=TestClassName
# Build with verbose output
./mvnw clean install -XVersion: 1.0.5-SNAPSHOT
Recent Changes:
- IntelliJ IDEA plugin released for seamless IDE integration
- Migrated from ASM to Java 25 ClassFile API (complete)
- Removed external bytecode manipulation dependencies
- Full virtual thread (Project Loom) support
- Enhanced documentation and examples
- Published to GitHub Packages
Roadmap:
- Performance optimization
- More example simulations
- Advanced debugging tools
- Tutorial documentation
- Additional IDE integrations (Eclipse, VS Code)
Original Code:
@Entity
public class Account {
public void deposit(double amount) {
Kronos.sleep(50);
System.out.println("Deposited: " + amount);
}
}After Transformation (conceptual):
@Transformed
@Entity
public class Account implements EntityReference {
// Generated dispatch method - invoked by Controller
public Object __invoke(int eventIndex, Object[] args) throws Throwable {
return switch (eventIndex) {
case 0 -> { __event_deposit((Double) args[0]); yield null; }
default -> throw new IllegalArgumentException("Unknown event: " + eventIndex);
};
}
// Generated signature method - for debugging
public String __signatureFor(int eventIndex) {
return switch (eventIndex) {
case 0 -> "deposit(double)";
default -> throw new IllegalArgumentException("Unknown event: " + eventIndex);
};
}
// Original public method - now schedules event
public void deposit(double amount) {
Kairos.getController().postContinuingEvent(this, 0, amount);
}
// Original implementation renamed - executed by framework
public void __event_deposit(double amount) {
Kairos.sleep(50); // Rewritten from Kronos
System.out.println("Deposited: " + amount);
}
}The entity class becomes its own EntityReference implementation with __invoke() and __signatureFor() methods.
Use synchronous channels for safe communication:
@Entity
public class Producer {
public void produce(SynchronousQueue<String> channel) {
channel.put("item");
}
}
@Entity
public class Consumer {
public void consume(SynchronousQueue<String> channel) {
String item = channel.take(); // Blocks until item available
}
}Combine multiple behaviors using the Janus mixin system:
public interface ComplexAgent extends Movable, Communicative, Intelligent {
}
var assembler = Composite.instance();
ComplexAgent agent = assembler.assemble(ComplexAgent.class,
new Composite.CompositeClassLoader(getClass().getClassLoader()),
new MovementBehavior(),
new CommunicationBehavior(),
new DecisionMaking());For users familiar with DESMOJ, there's a compatibility layer with distributions, queues, and resources.
Prime-Mover/
├── README.md (this file)
├── CLAUDE.md (AI assistant guidance)
├── CLASSFILE_API_ANALYSIS.md (technical analysis)
├── CONCEPTS.md (conceptual deep-dive)
├── pom.xml (root Maven POM)
├── api/ (public API module)
├── framework/ (runtime module)
├── transform/ (transformation engine)
├── primemover-maven-plugin/ (Maven plugin)
├── primemover-intellij-plugin/ (IntelliJ IDEA plugin)
├── sim-agent/ (Java agent)
├── demo/ (examples)
├── janus/ (composite/mixin)
├── space-ghost/ (example app)
├── desmoj-ish/ (DESMOJ compatibility)
└── maven-testing/ (plugin testing)
Licensed under AGPL v3.0. See LICENSE for details.
Contributions welcome! Please ensure:
- Java 25+ code style (modern patterns,
var, virtual threads) - All tests pass (
./mvnw test) - Documentation updated
- Clear commit messages
UnsupportedOperationException when calling Kronos methods
- Cause: Code is not transformed. Kronos methods throw by default and are rewritten to Kairos during transformation.
- Fix: Ensure transformation is configured (Maven plugin, IntelliJ plugin, or sim-agent).
Classes not being transformed
- Cause: Missing
@Entityannotation or wrong import. - Fix: Verify
import com.hellblazer.primeMover.annotations.Entity(not javax.persistence.Entity).
NoClassDefFoundError for Kairos
- Cause: Runtime dependency missing.
- Fix: Add
runtimeartifact to dependencies with appropriate scope.
Events executing in unexpected order
- Cause: Misunderstanding event scheduling vs direct execution.
- Fix: Remember that method calls on
@Entityclasses schedule events at the current simulation time. UseKronos.sleep()to advance time between events.
Blocking method not suspending
- Cause: Missing
@Blockingannotation or not usingblockingSleep(). - Fix: Mark method with
@Blockingand useKronos.blockingSleep()instead ofsleep().
- Use
SteppingControllerto step through events one at a time - Check
controller.getTotalEvents()to verify events are being scheduled - Enable logging to see event posting and execution
- Verify transformation with
javap -c YourClassto inspect bytecode
- Read the module READMEs - Each module has detailed documentation
- Review examples - See
demo/module for usage patterns - Check CLASSFILE_API_ANALYSIS.md - Technical deep-dive on transformation
- Run demos - Execute example programs to understand concepts
For questions, issues, or suggestions:
- Open an issue on GitHub
- Visit the repository: https://github.com/hellblazer/Prime-Mover
Happy simulating!