Browse Source

updated garbage collection

Snej69420 5 months ago
parent
commit
f506e38c5d

+ 34 - 5
benchmarks/Agents/main.jl

@@ -1,3 +1,5 @@
+using SQLite
+using DataFrames
 using ArgParse
 using Profile
 using PProf
@@ -52,6 +54,29 @@ function create_graph(file_path::String, title::String="")
     end
 end
 
+function normalize_simulation_data(db_path)
+    db = SQLite.DB(db_path)
+
+    SQLite.transaction(db) do
+        # preserve original data
+        try SQLite.execute(db, "ALTER TABLE record ADD COLUMN raw_rss INTEGER") catch end
+        SQLite.execute(db, "UPDATE record SET raw_rss = stat_rss")
+
+        # Subtract the FIRST entry from EVERY entry for each PID
+        # This makes every process in the graph start at 0
+        SQLite.execute(db, """
+            UPDATE record
+            SET stat_rss = raw_rss - (
+                SELECT r2.raw_rss
+                FROM record r2
+                WHERE r2.stat_pid = record.stat_pid
+                ORDER BY r2.record_id ASC LIMIT 1
+            )
+        """)
+    end
+    println("Database normalized. All processes now start at 0 (Net Growth).")
+end
+
 function build_environment(type::Structure, devstone_model::CoupledDEVS, gen_period::Float64)
     env = CoupledDEVS("DEVStoneEnvironment")
     add_submodel!(env, :generator, Generator;
@@ -139,7 +164,7 @@ function run_single_simulation(topology_type::Structure, depth::Int, width::Int,
     end
     type_str = enum_to_string(topology_type)
 
-    GC.gc() # clear the heap before the next run
+    GC.gc(true) # clear the heap before the next run
     pp_proc = nothing
     if memory != ""
         my_pid = getpid()
@@ -185,6 +210,8 @@ function run_single_simulation(topology_type::Structure, depth::Int, width::Int,
         else
             @warn "Memory file $memory is empty after simulation."
         end
+#         println("Pure Model Memory: $(Base.summarysize(model) / 1024^2)")
+        normalize_simulation_data(memory)
     end
 
     t_creation = model_created_time - start_time
@@ -226,16 +253,15 @@ function main()
         topology_type = string_to_enum(Structure, model_str)
         suffix = args["filename"] == "" ? "" : "_$(args["filename"])"
 
-        if output
-            println("Warming up JIT for $model_str...")
-        end
-
         if memory
             mem_file = joinpath(mem_dir, "$(model_str)$(suffix).sqlite")
 
             if !args["append"] && isfile(mem_file)
                 rm(mem_file)
             end
+            if output
+                println("Warming up JIT for $model_str (D:$max_depth, W:$max_width)")
+            end
             run_single_simulation(topology_type, max_depth, max_width, false, false, false, "", interval)
 
             println("Measuring memory (Timing results will not be saved)...")
@@ -260,6 +286,9 @@ function main()
 
                 for depth in ds:ds:max_depth
                     for width in ws:ws:max_width
+                        if output
+                            println("Warming up JIT for $model_str (D:$depth, W:$width)")
+                        end
                         run_single_simulation(topology_type, depth, width, false, false, false, "", interval)
                         for run in 0:(repetitions - 1)
                             if output || stats

+ 293 - 0
benchmarks/xdevs-java/src/main/java/DEVStoneSimulation.java

@@ -0,0 +1,293 @@
+package xdevs.core.examples.devstone;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import xdevs.core.modeling.Coupled;
+import xdevs.core.simulation.Coordinator;
+import xdevs.core.util.DevsLogger;
+
+public class Main {
+    private static final Logger LOGGER = Logger.getLogger(Main.class.getName());
+
+    private static final int MAX_EVENTS = 1;
+    private static final double PREPARATION_TIME = 0.0;
+    private static final double PERIOD = 1;
+
+    public static enum BenchmarkType {
+        LI, HI, HO, HOmem, HOmod
+    }
+
+-    private String path = "../Results/Agents";
+    private String filename = "";
+    private boolean append = false;
+    private int maxDepth = 8;
+    private int depthStepsize = 0;
+    private int maxWidth = 8;
+    private int widthStepsize = 0;
+    private int repetitions = 1;
+    private boolean output = false;
+    private boolean stats = false;
+    private boolean profile = false; // Note: JVM profiling usually requires external agents
+    private boolean logging = false;
+    private List<String> modelStructure = new ArrayList<>(Arrays.asList("LI", "HI", "HO", "HOmod"));
+    private boolean memory = false;
+    private double interval = 1.0;
+
+    public static void main(String[] args) {
+        Main orchestrator = new Main();
+        orchestrator.parseArguments(args);
+        orchestrator.runOrchestrator();
+    }
+
+    private void runOrchestrator() {
+        int ds = (depthStepsize > 0 && !memory) ? depthStepsize : maxDepth;
+        int ws = (widthStepsize > 0 && !memory) ? widthStepsize : maxWidth;
+        int reps = memory ? 1 : repetitions;
+
+        File timeDir = new File(path, "Time");
+        timeDir.mkdirs();
+
+        File memDir = new File(path, "Memory");
+        memDir.mkdirs();
+
+        for (String modelStr : modelStructure) {
+            BenchmarkType topologyType;
+            try {
+                topologyType = BenchmarkType.valueOf(modelStr);
+            } catch (IllegalArgumentException e) {
+                LOGGER.severe("Invalid model structure: " + modelStr);
+                continue;
+            }
+
+            String suffix = filename.isEmpty() ? "" : "_" + filename;
+
+            if (memory) {
+                String memFile = new File(memDir, modelStr + suffix + ".sqlite").getAbsolutePath();
+
+                if (!append && new File(memFile).exists()) {
+                    new File(memFile).delete();
+                }
+
+                if (output) {
+                    System.out.println("Warming up JIT for " + modelStr + " (D:" + maxDepth + ", W:" + maxWidth + ")");
+                }
+                // Warmup run
+                runSingleSimulation(topologyType, maxDepth, maxWidth, false, false, false, "", interval);
+
+                System.out.println("Measuring memory (Timing results will not be saved)...");
+                double[] times = runSingleSimulation(topologyType, maxDepth, maxWidth, stats, logging, profile, memFile, interval);
+
+                if (output || stats) {
+                    System.out.printf("  Creation: %.4fs | Setup: %.4fs | Sim: %.4fs\n", times[0], times[1], times[2]);
+                }
+                System.out.println("Saved memory database to " + memFile);
+                normalizeSimulationData(memFile); // Will need SQLite JDBC or system call
+
+            } else {
+                File timeFile = new File(timeDir, modelStr + suffix + ".csv");
+                boolean fileExists = timeFile.exists() && timeFile.length() > 0;
+
+                try (BufferedWriter writer = new BufferedWriter(new FileWriter(timeFile, append))) {
+                    if (!append || !fileExists) {
+                        writer.write("simulator,model_type,depth,width,run,creation_time,setup_time,simulation_time\n");
+                    }
+
+                    for (int depth = ds; depth <= maxDepth; depth += ds) {
+                        for (int width = ws; width <= maxWidth; width += ws) {
+
+                            if (output) {
+                                System.out.println("Warming up JIT for " + modelStr + " (D:" + depth + ", W:" + width + ")");
+                            }
+                            // Warmup
+                            runSingleSimulation(topologyType, depth, width, false, false, false, "", interval);
+
+                            for (int run = 0; run < reps; run++) {
+                                if (output || stats) {
+                                    System.out.println("Running " + modelStr + " (D:" + depth + ", W:" + width + ") - Repetition " + run + "...");
+                                }
+
+                                double[] times = runSingleSimulation(topologyType, depth, width, stats, logging, profile, "", interval);
+
+                                writer.write(String.format("java_xdevs,%s,%d,%d,%d,%f,%f,%f\n",
+                                        modelStr, depth, width, run, times[0], times[1], times[2]));
+                                writer.flush();
+
+                                if (output || stats) {
+                                    System.out.printf("\tCreation: %.4fs | Setup: %.4fs | Sim: %.4fs\n", times[0], times[1], times[2]);
+                                }
+                            }
+                        }
+                    }
+                } catch (IOException e) {
+                    LOGGER.severe(e.getLocalizedMessage());
+                }
+                System.out.println("Saved timing results to " + timeFile.getAbsolutePath());
+            }
+        }
+    }
+
+    private double[] runSingleSimulation(BenchmarkType modelType, int depth, int width,
+                                         boolean stats, boolean logging, boolean profile,
+                                         String memoryDb, double interval) {
+        System.gc();
+
+        Process ppProc = null;
+        if (memoryDb != null && !memoryDb.isEmpty()) {
+            try {
+                long myPid = ProcessHandle.current().pid();
+                String procpathQuery = "$..children[?(@.stat.pid == " + myPid + ")]";
+                ProcessBuilder pb = new ProcessBuilder(
+                        "uv", "run", "-m", "procpath", "record",
+                        "-i", String.valueOf(interval), "-f", "stat",
+                        "-d", memoryDb, procpathQuery
+                );
+                ppProc = pb.start();
+            } catch (IOException e) {
+                LOGGER.warning("Could not start procpath: " + e.getMessage());
+            }
+        }
+
+        long startModel = System.nanoTime();
+        Coupled framework = buildFramework(modelType, width, depth);
+        long endModel = System.nanoTime();
+
+        long startSetup = System.nanoTime();
+        Coordinator coordinator = new Coordinator(framework); // Simplified to standard coordinator
+        coordinator.initialize();
+        long endSetup = System.nanoTime();
+
+        long startSim = System.nanoTime();
+        coordinator.simulate(Long.MAX_VALUE);
+        coordinator.exit();
+        long endSim = System.nanoTime();
+
+        if (memoryDb != null && !memoryDb.isEmpty() && ppProc != null) {
+            ppProc.destroy(); // Base.kill(ppProc, 2) in Julia
+            try {
+                ppProc.waitFor();
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+            }
+        }
+
+        double tCreation = (endModel - startModel) / 1e9;
+        double tSetup = (endSetup - startSetup) / 1e9;
+        double tSim = (endSim - startSim) / 1e9;
+
+        return new double[]{tCreation, tSetup, tSim};
+    }
+
+    private Coupled buildFramework(BenchmarkType modelType, int width, int depth) {
+        Coupled framework = new Coupled("DevStone" + modelType.toString());
+        DevStoneGenerator generator = new DevStoneGenerator("Generator", PREPARATION_TIME, PERIOD, MAX_EVENTS);
+        framework.addComponent(generator);
+
+        DevStone stone = null;
+        // Setting delays as 0.0 constant to match Julia benchmark parameters
+        switch (modelType) {
+            case LI:
+                stone = new DevStoneCoupledLI("C", width, depth, PREPARATION_TIME, 0.0, 0.0);
+                break;
+            case HI:
+                stone = new DevStoneCoupledHI("C", width, depth, PREPARATION_TIME, 0.0, 0.0);
+                break;
+            case HO:
+                stone = new DevStoneCoupledHO("C", width, depth, PREPARATION_TIME, 0.0, 0.0);
+                break;
+            case HOmod:
+                stone = new DevStoneCoupledHOmod("C", width, depth, PREPARATION_TIME, 0.0, 0.0);
+                break;
+            default:
+                break;
+        }
+
+        framework.addComponent(stone);
+        framework.addCoupling(generator.oOut, stone.iIn);
+
+        if (modelType == BenchmarkType.HO || modelType == BenchmarkType.HOmod || modelType == BenchmarkType.HOmem) {
+            if (stone instanceof DevStoneCoupledHO) framework.addCoupling(generator.oOut, ((DevStoneCoupledHO) stone).iInAux);
+            if (stone instanceof DevStoneCoupledHOmod) framework.addCoupling(generator.oOut, ((DevStoneCoupledHOmod) stone).iInAux);
+        }
+        return framework;
+    }
+
+    private void normalizeSimulationData(String dbPath) {
+        try {
+            System.out.println("Normalizing database. All processes now start at 0 (Net Growth).");
+            String[] cmd = {
+                    "sqlite3", dbPath,
+                    "ALTER TABLE record ADD COLUMN raw_rss INTEGER;" +
+                            "UPDATE record SET raw_rss = stat_rss;" +
+                            "UPDATE record SET stat_rss = raw_rss - (SELECT r2.raw_rss FROM record r2 WHERE r2.stat_pid = record.stat_pid ORDER BY r2.record_id ASC LIMIT 1);"
+            };
+            ProcessBuilder pb = new ProcessBuilder(cmd);
+            Process p = pb.start();
+            p.waitFor();
+        } catch (Exception e) {
+            LOGGER.warning("Could not normalize sqlite database using CLI sqlite3: " + e.getMessage());
+        }
+    }
+
+    private void parseArguments(String[] args) {
+        for (int i = 0; i < args.length; i++) {
+            String arg = args[i];
+
+            // Handles both -flag value AND --flag=value formats
+            String value = "";
+            if (arg.contains("=")) {
+                String[] parts = arg.split("=", 2);
+                arg = parts[0];
+                value = parts[1];
+            } else if (i + 1 < args.length && !args[i+1].startsWith("-")) {
+                value = args[i+1];
+            }
+
+            switch (arg) {
+                case "--path": case "-p":
+                    this.path = value; break;
+                case "--filename": case "-f":
+                    this.filename = value; break;
+                case "--append": case "-a":
+                    this.append = true; break;
+                case "--max-depth": case "-D":
+                    this.maxDepth = Integer.parseInt(value); break;
+                case "--depth-stepsize": case "--ds":
+                    this.depthStepsize = Integer.parseInt(value); break;
+                case "--max-width": case "-W":
+                    this.maxWidth = Integer.parseInt(value); break;
+                case "--width-stepsize": case "--ws":
+                    this.widthStepsize = Integer.parseInt(value); break;
+                case "--repetitions": case "-r":
+                    this.repetitions = Integer.parseInt(value); break;
+                case "--output": case "-O":
+                    this.output = true; break;
+                case "--stats": case "-s":
+                    this.stats = true; break;
+                case "--profile": case "-P":
+                    this.profile = true; break;
+                case "--logging": case "-L":
+                    this.logging = true; break;
+                case "--model-structure": case "--ms":
+                    // Consume multiple arguments until the next flag
+                    this.modelStructure.clear();
+                    if (!value.isEmpty()) this.modelStructure.add(value);
+                    while (i + 1 < args.length && !args[i+1].startsWith("-")) {
+                        this.modelStructure.add(args[++i]);
+                    }
+                    break;
+                case "--memory": case "-M":
+                    this.memory = true; break;
+                case "--interval": case "-i":
+                    this.interval = Double.parseDouble(value); break;
+            }
+        }
+    }
+}

+ 0 - 0
benchmarks/xdevs-java/src/main/java/Main.java