From 3b29e991b9c53fe19b64aca4f43dff86abd17aed Mon Sep 17 00:00:00 2001 From: James Mark Chan Date: Sun, 14 Sep 2025 19:52:04 -0700 Subject: [PATCH 1/4] #73 initial datamodel refactor --- build.xml | 6 +- src/META-INF/persistence.xml | 6 +- src/jdiskmark/App.java | 30 +-- src/jdiskmark/Benchmark.java | 118 +++++------- src/jdiskmark/BenchmarkOperation.java | 257 ++++++++++++++++++++++++++ src/jdiskmark/BenchmarkPanel.form | 2 +- src/jdiskmark/BenchmarkPanel.java | 48 ++--- src/jdiskmark/BenchmarkWorker.java | 162 ++++++++-------- src/jdiskmark/Gui.java | 62 ++++--- src/jdiskmark/MainFrame.form | 26 +-- src/jdiskmark/MainFrame.java | 115 ++++++------ 11 files changed, 535 insertions(+), 297 deletions(-) create mode 100644 src/jdiskmark/BenchmarkOperation.java diff --git a/build.xml b/build.xml index 27c6d8d..e42c423 100644 --- a/build.xml +++ b/build.xml @@ -83,12 +83,12 @@ - + - + - + diff --git a/src/META-INF/persistence.xml b/src/META-INF/persistence.xml index da1ba85..569f2dd 100644 --- a/src/META-INF/persistence.xml +++ b/src/META-INF/persistence.xml @@ -7,7 +7,11 @@ - + + + + + diff --git a/src/jdiskmark/App.java b/src/jdiskmark/App.java index 878ae61..ddfb7e1 100644 --- a/src/jdiskmark/App.java +++ b/src/jdiskmark/App.java @@ -62,7 +62,7 @@ public static enum State { IDLE_STATE, DISK_TEST_STATE }; public static boolean writeSyncEnable = false; // run configuration - public static Benchmark.BlockSequence blockSequence = Benchmark.BlockSequence.SEQUENTIAL; + public static BenchmarkOperation.BlockSequence blockSequence = BenchmarkOperation.BlockSequence.SEQUENTIAL; public static int numOfSamples = 200; // desired number of samples public static int numOfBlocks = 32; // desired number of blocks public static int blockSizeKb = 512; // size of a block in KBs @@ -76,7 +76,9 @@ public static enum State { IDLE_STATE, DISK_TEST_STATE }; public static long rIops = -1; public static HashMap benchmarks = new HashMap<>(); - public static Benchmark.IOMode ioMode = Benchmark.IOMode.WRITE; + public static HashMap operations = new HashMap<>(); + public static Benchmark.BenchmarkType benchmarkType = Benchmark.BenchmarkType.WRITE; + public static BenchmarkOperation.IOMode ioMode = BenchmarkOperation.IOMode.WRITE; /** @@ -210,6 +212,9 @@ public static void loadConfig() { // configure settings from properties String value; + value = p.getProperty("benchmarkType", String.valueOf(benchmarkType)); + benchmarkType = Benchmark.BenchmarkType.valueOf(value.toUpperCase()); + value = p.getProperty("multiFile", String.valueOf(multiFile)); multiFile = Boolean.parseBoolean(value); @@ -220,10 +225,7 @@ public static void loadConfig() { autoReset = Boolean.parseBoolean(value); value = p.getProperty("blockSequence", String.valueOf(blockSequence)); - blockSequence = Benchmark.BlockSequence.valueOf(value.toUpperCase()); - - value = p.getProperty("ioMode", String.valueOf(ioMode)); - App.ioMode = Benchmark.IOMode.valueOf(value.toUpperCase()); + blockSequence = BenchmarkOperation.BlockSequence.valueOf(value.toUpperCase()); value = p.getProperty("showMaxMin", String.valueOf(showMaxMin)); showMaxMin = Boolean.parseBoolean(value); @@ -254,6 +256,7 @@ public static void saveConfig() { if (p == null) { p = new Properties(); } // configure properties + p.setProperty("benchmarkType", benchmarkType.name()); p.setProperty("multiFile", String.valueOf(multiFile)); p.setProperty("autoRemoveData", String.valueOf(autoRemoveData)); p.setProperty("autoReset", String.valueOf(autoReset)); @@ -266,7 +269,6 @@ public static void saveConfig() { p.setProperty("numOfThreads", String.valueOf(numOfThreads)); p.setProperty("writeSyncEnable", String.valueOf(writeSyncEnable)); p.setProperty("palette", Gui.palette.name()); - p.setProperty("ioMode", ioMode.name()); // write properties file try { @@ -278,13 +280,12 @@ public static void saveConfig() { } public static boolean isReadEnabled() { - return ioMode == Benchmark.IOMode.READ || ioMode == Benchmark.IOMode.READ_WRITE; -} + return benchmarkType == Benchmark.BenchmarkType.READ || benchmarkType == Benchmark.BenchmarkType.READ_WRITE; + } public static boolean isWriteEnabled() { - return ioMode == Benchmark.IOMode.WRITE || ioMode == Benchmark.IOMode.READ_WRITE; -} - + return benchmarkType == Benchmark.BenchmarkType.WRITE || benchmarkType == Benchmark.BenchmarkType.READ_WRITE; + } public static String getConfigString() { StringBuilder sb = new StringBuilder(); @@ -302,7 +303,7 @@ public static String getConfigString() { sb.append("blockSizeKb: ").append(blockSizeKb).append('\n'); sb.append("numOfThreads: ").append(numOfThreads).append('\n'); sb.append("palette: ").append(Gui.palette).append('\n'); - sb.append("ioMode: ").append(ioMode).append('\n'); + sb.append("ioMode: ").append(benchmarkType).append('\n'); return sb.toString(); } @@ -314,6 +315,9 @@ public static void loadBenchmarks() { Benchmark.findAll().stream().forEach((Benchmark run) -> { benchmarks.put(run.getStartTimeString(), run); Gui.runPanel.addRun(run); + for (BenchmarkOperation o : run.getOperations()) { + operations.put(o.getStartTimeString(), o); + } }); } diff --git a/src/jdiskmark/Benchmark.java b/src/jdiskmark/Benchmark.java index 4e2275d..6e5489e 100644 --- a/src/jdiskmark/Benchmark.java +++ b/src/jdiskmark/Benchmark.java @@ -1,6 +1,7 @@ package jdiskmark; +import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Convert; import jakarta.persistence.Entity; @@ -10,6 +11,7 @@ import jakarta.persistence.Id; import jakarta.persistence.NamedQueries; import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; import jakarta.persistence.Table; import java.io.Serializable; import java.text.DecimalFormat; @@ -26,7 +28,7 @@ @Table(name="Benchmark") @NamedQueries({ @NamedQuery(name="Benchmark.findAll", - query="SELECT d FROM Benchmark d") + query="SELECT b FROM Benchmark b JOIN FETCH b.operations") }) public class Benchmark implements Serializable { @@ -34,7 +36,7 @@ public class Benchmark implements Serializable { static final DecimalFormat DFT = new DecimalFormat("###"); static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - public enum IOMode { + public enum BenchmarkType { READ { @Override public String toString() { return "Read"; } @@ -48,18 +50,6 @@ public enum IOMode { public String toString() { return "Read & Write"; } } } - - public enum BlockSequence { - SEQUENTIAL { - @Override - public String toString() { return "Sequential"; } - }, - RANDOM { - @Override - public String toString() { return "Random"; } - } - } - // surrogate key @Column @@ -89,24 +79,8 @@ public enum BlockSequence { // benchmark parameters @Column - IOMode ioMode; - @Column - BlockSequence blockOrder; - @Column - int numBlocks = 0; - @Column - int blockSize = 0; - @Column - int numSamples = 0; - @Column - long txSize = 0; - @Column - int numThreads = 1; - - // NEW: whether write-sync was enabled for this run (only meaningful for WRITE; may be null for READ) - @Column - Boolean writeSyncEnabled; - + BenchmarkType benchmarkType; + // timestamps @Convert(converter = LocalDateTimeAttributeConverter.class) @Column(name = "startTime", columnDefinition = "TIMESTAMP") @@ -114,12 +88,7 @@ public enum BlockSequence { @Convert(converter = LocalDateTimeAttributeConverter.class) @Column LocalDateTime endTime = null; - - // sample data - @Column - @Convert(converter = SampleAttributeConverter.class) - ArrayList samples = new ArrayList<>(); - + // results @Column double bwAvg = 0; @@ -132,19 +101,35 @@ public enum BlockSequence { @Column long iops = 0; + @OneToMany(mappedBy = "benchmark", cascade = CascadeType.ALL, orphanRemoval = true) + private List operations = new ArrayList<>(); + + public List getOperations() { + return operations; + } + + // get the first operation of that type + public BenchmarkOperation getOperation(BenchmarkOperation.IOMode mode) { + for (BenchmarkOperation operation : operations) { + if (operation.ioMode == mode) { + return operation; + } + } + return null; + } + @Override public String toString() { - return "Benchmark(" + ioMode + "," + blockOrder + "): " + numSamples + " bw avg: " + bwAvg; + return "Benchmark(" + benchmarkType + "): bw: " + bwAvg; } public Benchmark() { startTime = LocalDateTime.now(); } - Benchmark(IOMode type, BlockSequence order) { + Benchmark(BenchmarkType type) { startTime = LocalDateTime.now(); - ioMode = type; - blockOrder = order; + benchmarkType = type; } // basic getters and setters @@ -165,25 +150,16 @@ public String getUsageColumnDisplay() { return percentUsed + "%"; } - public String getModeDisplay() { - // Show "Write*" when write-sync was enabled for a WRITE run - if (ioMode == IOMode.WRITE && Boolean.TRUE.equals(getWriteSyncEnabled())) { - return "Write*"; - } - return (ioMode == null) ? "" : ioMode.toString(); // "Read", "Write", "Read & Write" - } - - // GH-20 TODO: review should this be synchronized or redone to not be blocking? - public synchronized void add(Sample s) { - samples.add(s); - } +// public synchronized void add(Sample s) { +// samples.add(s); +// } // display friendly methods - public String getBlocksDisplay() { - return numBlocks + " (" + blockSize + ")"; - } +// public String getBlocksDisplay() { +// return numBlocks + " (" + blockSize + ")"; +// } public String getStartTimeString() { return startTime.format(DATE_FORMAT); @@ -228,16 +204,6 @@ public void setTotalOps(long totalOps) { iops = Math.round(iopsDouble); } } - - // NEW: getters/setters for writeSyncEnabled and iops (expose iops too if needed) - - public Boolean getWriteSyncEnabled() { - return writeSyncEnabled; - } - - public void setWriteSyncEnabled(Boolean writeSyncEnabled) { - this.writeSyncEnabled = writeSyncEnabled; - } public long getIops() { return iops; @@ -257,18 +223,28 @@ static List findAll() { static int deleteAll() { EntityManager em = EM.getEntityManager(); em.getTransaction().begin(); - int deletedCount = em.createQuery("DELETE FROM Benchmark").executeUpdate(); + int deletedOperationsCount = em.createQuery("DELETE FROM BenchmarkOperation").executeUpdate(); + int deletedBenchmarksCount = em.createQuery("DELETE FROM Benchmark").executeUpdate(); em.getTransaction().commit(); - return deletedCount; + return deletedBenchmarksCount; } static int delete(List benchmarkIds) { EntityManager em = EM.getEntityManager(); em.getTransaction().begin(); - String jpql = "DELETE FROM Benchmark b WHERE b.id IN :benchmarkIds"; - int deletedCount = em.createQuery(jpql) + + // delete the child BenchmarkOperation records. + String deleteOperationsJpql = "DELETE FROM BenchmarkOperation bo WHERE bo.benchmark.id IN :benchmarkIds"; + int deletedOpsCount = em.createQuery(deleteOperationsJpql) + .setParameter("benchmarkIds", benchmarkIds) + .executeUpdate(); + + // delete the parent BenchmarkOperation records + String deleteBenchmarksJpql = "DELETE FROM Benchmark b WHERE b.id IN :benchmarkIds"; + int deletedCount = em.createQuery(deleteBenchmarksJpql) .setParameter("benchmarkIds", benchmarkIds) .executeUpdate(); + em.getTransaction().commit(); return deletedCount; } diff --git a/src/jdiskmark/BenchmarkOperation.java b/src/jdiskmark/BenchmarkOperation.java new file mode 100644 index 0000000..11a87d8 --- /dev/null +++ b/src/jdiskmark/BenchmarkOperation.java @@ -0,0 +1,257 @@ + +package jdiskmark; + +import jakarta.persistence.Column; +import jakarta.persistence.Convert; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityManager; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import java.io.Serializable; +import java.text.DecimalFormat; +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; + +/** + * A read or write benchmark + */ +@Entity +@Table(name="BenchmarkOperation") +@NamedQueries({ +@NamedQuery(name="BenchmarkOperation.findAll", + query="SELECT d FROM BenchmarkOperation d") +}) +public class BenchmarkOperation implements Serializable { + + static final DecimalFormat DF = new DecimalFormat("###.##"); + static final DecimalFormat DFT = new DecimalFormat("###"); + static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + public enum IOMode { + READ { + @Override + public String toString() { return "Read"; } + }, + WRITE { + @Override + public String toString() { return "Write"; } + } + } + + public enum BlockSequence { + SEQUENTIAL { + @Override + public String toString() { return "Sequential"; } + }, + RANDOM { + @Override + public String toString() { return "Random"; } + } + } + + // surrogate key + @Column + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + long id; + + // This is the foreign key relationship + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "benchmark_id") // Specifies the foreign key column + private Benchmark benchmark; + + // benchmark parameters + @Column + IOMode ioMode; + @Column + BlockSequence blockOrder; + @Column + int numBlocks = 0; + @Column + int blockSize = 0; + @Column + int numSamples = 0; + @Column + long txSize = 0; + @Column + int numThreads = 1; + // NEW: whether write-sync was enabled for this run (only meaningful for WRITE; may be null for READ) + @Column + Boolean writeSyncEnabled; + + // timestamps + @Convert(converter = LocalDateTimeAttributeConverter.class) + @Column(name = "startTime", columnDefinition = "TIMESTAMP") + LocalDateTime startTime; + @Convert(converter = LocalDateTimeAttributeConverter.class) + @Column + LocalDateTime endTime = null; + + // sample data + @Column + @Convert(converter = SampleAttributeConverter.class) + ArrayList samples = new ArrayList<>(); + + // results + @Column + double bwAvg = 0; + @Column + double bwMax = 0; + @Column + double bwMin = 0; + @Column + double accAvg = 0; + @Column + long iops = 0; + + @Override + public String toString() { + return "BenchmarkOp(" + ioMode + "," + blockOrder + "): " + numSamples + " bw avg: " + bwAvg; + } + + public BenchmarkOperation() { + startTime = LocalDateTime.now(); + } + + BenchmarkOperation(IOMode type, BlockSequence order) { + startTime = LocalDateTime.now(); + ioMode = type; + blockOrder = order; + } + + // basic getters and setters + public Benchmark getBenchmark() { + return benchmark; + } + public void setBenchmark(Benchmark benchmark) { + this.benchmark = benchmark; + } + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + + public String getModeDisplay() { + // Show "Write*" when write-sync was enabled for a WRITE run + if (ioMode == IOMode.WRITE && Boolean.TRUE.equals(getWriteSyncEnabled())) { + return "Write*"; + } + return (ioMode == null) ? "" : ioMode.toString(); // "Read", "Write", "Read & Write" + } + + + // GH-20 TODO: review should this be synchronized or redone to not be blocking? + public synchronized void add(Sample s) { + samples.add(s); + } + + public synchronized ArrayList getSamples() { + return samples; + } + + // display friendly methods + + public String getBlocksDisplay() { + return numBlocks + " (" + blockSize + ")"; + } + + public String getStartTimeString() { + return startTime.format(DATE_FORMAT); + } + + public String getAccTimeDisplay() { + return accAvg == -1? "- -" : DF.format(accAvg); + } + + public String getBwMinDisplay() { + return bwMin == -1 ? "- -" : DF.format(bwMin); + } + + public String getBwMaxDisplay() { + return bwMax == -1 ? "- -" : DF.format(bwMax); + } + + public String getBwMinMaxDisplay() { + return bwMax == -1 ? "- -" : DFT.format(bwMin) + "/" + DFT.format(bwMax); + } + + public String getBwAvgDisplay() { + return bwAvg == -1 ? "- -" : DF.format(bwAvg); + } + + public String getDuration() { + if (endTime == null) { + return "unknown"; + } + long diffMs = Duration.between(startTime, endTime).toMillis(); + return String.valueOf(diffMs); + } + + public void setTotalOps(long totalOps) { + // iops = operations / sec = ops / (elapsed ms / 1,000ms) + // Multiply by 1_000_000 to convert milliseconds to seconds + System.err.println("startTime=" + startTime); + System.err.println("endTime=" + endTime); + long diffMs = Duration.between(startTime, endTime).toMillis(); + if (diffMs != 0) { + double iopsDouble = (double) (totalOps * 1_000_000) / (double) diffMs; + iops = Math.round(iopsDouble); + } + } + + // NEW: getters/setters for writeSyncEnabled and iops (expose iops too if needed) + + public Boolean getWriteSyncEnabled() { + return writeSyncEnabled; + } + + public void setWriteSyncEnabled(Boolean writeSyncEnabled) { + this.writeSyncEnabled = writeSyncEnabled; + } + + public long getIops() { + return iops; + } + + public void setIops(long iops) { + this.iops = iops; + } + + // utility methods for collection + + static List findAll() { + EntityManager em = EM.getEntityManager(); + return em.createNamedQuery("Benchmark.findAll", BenchmarkOperation.class).getResultList(); + } + + static int deleteAll() { + EntityManager em = EM.getEntityManager(); + em.getTransaction().begin(); + int deletedCount = em.createQuery("DELETE FROM Benchmark").executeUpdate(); + em.getTransaction().commit(); + return deletedCount; + } + + static int delete(List benchmarkIds) { + EntityManager em = EM.getEntityManager(); + em.getTransaction().begin(); + String jpql = "DELETE FROM Benchmark b WHERE b.id IN :benchmarkIds"; + int deletedCount = em.createQuery(jpql) + .setParameter("benchmarkIds", benchmarkIds) + .executeUpdate(); + em.getTransaction().commit(); + return deletedCount; + } +} \ No newline at end of file diff --git a/src/jdiskmark/BenchmarkPanel.form b/src/jdiskmark/BenchmarkPanel.form index 547a955..d6ea84a 100644 --- a/src/jdiskmark/BenchmarkPanel.form +++ b/src/jdiskmark/BenchmarkPanel.form @@ -48,7 +48,7 @@ - + diff --git a/src/jdiskmark/BenchmarkPanel.java b/src/jdiskmark/BenchmarkPanel.java index 92eb8c6..cc03323 100644 --- a/src/jdiskmark/BenchmarkPanel.java +++ b/src/jdiskmark/BenchmarkPanel.java @@ -62,7 +62,7 @@ private void initComponents() { }, new String [] { - "ID", "Drive Model", "Usage", "Mode", "Order", "Samples", "Blocks (Size)", "Thread", "Start Time", "Time (ms)", "Acc (ms)", "Min/Max (MB/s)", "IO (MB/s)" + "ID", "Drive Model", "Usage", "Type", "Order", "Samples", "Blocks (Size)", "Thread", "Start Time", "Time (ms)", "Acc (ms)", "Min/Max (MB/s)", "IO (MB/s)" } ) { boolean[] canEdit = new boolean [] { @@ -123,11 +123,10 @@ public void mouseClicked(java.awt.event.MouseEvent evt) { private void runTableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_runTableMouseClicked int sRow = runTable.getSelectedRow(); String timeString = (String) runTable.getValueAt(sRow, START_TIME_COLUMN); - System.out.println("timeString=" + timeString); - - Benchmark benchmark = App.benchmarks.get(timeString); - if (benchmark != null) { - Gui.loadBenchmark(benchmark); + System.out.println("selected operation starttime=" + timeString); + BenchmarkOperation operation = App.operations.get(timeString); + if (operation != null) { + Gui.loadOperation(operation); } }//GEN-LAST:event_runTableMouseClicked @@ -139,23 +138,28 @@ private void runTableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:ev public void addRun(Benchmark run) { + + List operations = run.getOperations(); + System.out.println("number of operations: " + operations.size()); DefaultTableModel model = (DefaultTableModel) this.runTable.getModel(); - model.addRow( - new Object[] { - run.id, - run.driveModel, - run.getUsageColumnDisplay(), - run.getModeDisplay(), - run.blockOrder, - run.numSamples, - run.getBlocksDisplay(), - run.numThreads, - run.getStartTimeString(), - run.getDuration(), - run.getAccTimeDisplay(), - run.getBwMinMaxDisplay(), - run.getBwAvgDisplay(), - }); + for (BenchmarkOperation o : operations) { + model.addRow( + new Object[] { + run.id, + run.driveModel, + run.getUsageColumnDisplay(), + o.getModeDisplay(), + o.blockOrder, + o.numSamples, + o.getBlocksDisplay(), + o.numThreads, + o.getStartTimeString(), + o.getDuration(), + o.getAccTimeDisplay(), + o.getBwMinMaxDisplay(), + o.getBwAvgDisplay(), + }); + } } public void hideFirstColumn() { diff --git a/src/jdiskmark/BenchmarkWorker.java b/src/jdiskmark/BenchmarkWorker.java index 95401f6..fc7d6f6 100644 --- a/src/jdiskmark/BenchmarkWorker.java +++ b/src/jdiskmark/BenchmarkWorker.java @@ -108,31 +108,35 @@ protected Boolean doInBackground() throws Exception { List> futures = new ArrayList<>(); + Benchmark run = new Benchmark(App.benchmarkType); + + // system info + run.processorName = App.processorName; + run.os = App.os; + run.arch = App.arch; + // drive information + run.driveModel = driveModel; + run.partitionId = partitionId; + run.percentUsed = usageInfo.percentUsed; + run.usedGb = usageInfo.usedGb; + run.totalGb = usageInfo.totalGb; + + Gui.chart.getTitle().setText(run.getDriveInfo()); + Gui.chart.getTitle().setVisible(true); + if (App.isWriteEnabled()) { - Benchmark run = new Benchmark(Benchmark.IOMode.WRITE, App.blockSequence); - - // system info - run.processorName = App.processorName; - run.os = App.os; - run.arch = App.arch; - // drive information - run.driveModel = driveModel; - run.partitionId = partitionId; - run.percentUsed = usageInfo.percentUsed; - run.usedGb = usageInfo.usedGb; - run.totalGb = usageInfo.totalGb; - // benchmark parameters - run.numSamples = App.numOfSamples; - run.numBlocks = App.numOfBlocks; - run.blockSize = App.blockSizeKb; - run.txSize = App.targetTxSizeKb(); - run.numThreads = App.numOfThreads; - + BenchmarkOperation wOperation = new BenchmarkOperation(); + wOperation.setBenchmark(run); + wOperation.ioMode = BenchmarkOperation.IOMode.WRITE; + wOperation.blockOrder = App.blockSequence; + wOperation.numSamples = App.numOfSamples; + wOperation.numBlocks = App.numOfSamples; + wOperation.blockSize = App.blockSizeKb; + wOperation.txSize = App.targetTxSizeKb(); + wOperation.numThreads = App.numOfThreads; // persist whether write sync was enabled for this run - run.setWriteSyncEnabled(App.writeSyncEnable); - - Gui.chart.getTitle().setText(run.getDriveInfo()); - Gui.chart.getTitle().setVisible(true); + wOperation.setWriteSyncEnabled(App.writeSyncEnable); + run.getOperations().add(wOperation); if (App.multiFile == false) { testFile = new File(dataDir.getAbsolutePath() + File.separator + "testdata.jdm"); @@ -161,7 +165,7 @@ protected Boolean doInBackground() throws Exception { try { try (RandomAccessFile rAccFile = new RandomAccessFile(testFile, mode)) { for (int b = 0; b < numOfBlocks; b++) { - if (App.blockSequence == Benchmark.BlockSequence.RANDOM) { + if (App.blockSequence == BenchmarkOperation.BlockSequence.RANDOM) { int rLoc = Util.randInt(0, numOfBlocks - 1); rAccFile.seek(rLoc * blockSize); } else { @@ -186,17 +190,17 @@ protected Boolean doInBackground() throws Exception { double sec = (double) elapsedTimeNs / 1_000_000_000d; double mbWritten = (double) totalBytesWrittenInSample / (double) MEGABYTE; sample.bwMbSec = mbWritten / sec; - msg("s:" + s + " write IO is " + sample.getBwMbSecDisplay() + " MB/s " - + "(" + Util.displayString(mbWritten) + "MB written in " - + Util.displayString(sec) + " sec) elapsedNs: " + elapsedTimeNs); +// msg("s:" + s + " write IO is " + sample.getBwMbSecDisplay() + " MB/s " +// + "(" + Util.displayString(mbWritten) + "MB written in " +// + Util.displayString(sec) + " sec) elapsedNs: " + elapsedTimeNs); App.updateMetrics(sample); publish(sample); - run.bwMax = sample.cumMax; - run.bwMin = sample.cumMin; - run.bwAvg = sample.cumAvg; - run.accAvg = sample.cumAccTimeMs; - run.add(sample); + wOperation.bwMax = sample.cumMax; + wOperation.bwMin = sample.cumMin; + wOperation.bwAvg = sample.cumAvg; + wOperation.accAvg = sample.cumAccTimeMs; + wOperation.add(sample); } })); } @@ -205,17 +209,10 @@ protected Boolean doInBackground() throws Exception { executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); // GH-10 file IOPS processing - run.endTime = LocalDateTime.now(); - run.setTotalOps(wUnitsComplete[0]); - App.wIops = run.iops; + wOperation.endTime = LocalDateTime.now(); + wOperation.setTotalOps(wUnitsComplete[0]); + App.wIops = wOperation.iops; Gui.mainFrame.refreshWriteMetrics(); - - EntityManager em = EM.getEntityManager(); - em.getTransaction().begin(); - em.persist(run); - em.getTransaction().commit(); - App.benchmarks.put(run.getStartTimeString(), run); - Gui.runPanel.addRun(run); } // try renaming all files to clear catch @@ -224,32 +221,19 @@ protected Boolean doInBackground() throws Exception { } if (App.isReadEnabled()) { - Benchmark run = new Benchmark(Benchmark.IOMode.READ, App.blockSequence); - - // system info - run.processorName = App.processorName; - run.os = App.os; - run.arch = App.arch; - - // drive information - run.driveModel = driveModel; - run.partitionId = partitionId; - run.percentUsed = usageInfo.percentUsed; - run.usedGb = usageInfo.usedGb; - run.totalGb = usageInfo.totalGb; - - // benchmark parameters - run.numSamples = App.numOfSamples; - run.numBlocks = App.numOfBlocks; - run.blockSize = App.blockSizeKb; - run.txSize = App.targetTxSizeKb(); - run.numThreads = App.numOfThreads; - + BenchmarkOperation rOperation = new BenchmarkOperation(); + rOperation.setBenchmark(run); + // operation parameters + rOperation.ioMode = BenchmarkOperation.IOMode.READ; + rOperation.blockOrder = App.blockSequence; + rOperation.numSamples = App.numOfSamples; + rOperation.numBlocks = App.numOfBlocks; + rOperation.blockSize = App.blockSizeKb; + rOperation.txSize = App.targetTxSizeKb(); + rOperation.numThreads = App.numOfThreads; // write sync does not apply to pure read benchmarks - run.setWriteSyncEnabled(null); - - Gui.chart.getTitle().setText(run.getDriveInfo()); - Gui.chart.getTitle().setVisible(true); + rOperation.setWriteSyncEnabled(null); + run.getOperations().add(rOperation); ExecutorService executorService = Executors.newFixedThreadPool(App.numOfThreads); @@ -271,7 +255,7 @@ protected Boolean doInBackground() throws Exception { try { try (RandomAccessFile rAccFile = new RandomAccessFile(testFile, "r")) { for (int b = 0; b < numOfBlocks; b++) { - if (App.blockSequence == Benchmark.BlockSequence.RANDOM) { + if (App.blockSequence == BenchmarkOperation.BlockSequence.RANDOM) { int rLoc = Util.randInt(0, numOfBlocks - 1); rAccFile.seek(rLoc * blockSize); } else { @@ -296,18 +280,16 @@ protected Boolean doInBackground() throws Exception { double sec = (double) elapsedTimeNs / 1_000_000_000d; double mbRead = (double) totalBytesReadInMark / (double) MEGABYTE; sample.bwMbSec = mbRead / sec; - msg("s:" + s + " read IO is " + sample.getBwMbSecDisplay() + " MB/s " - + "(" + Util.displayString(mbRead) + "MB read in " - + Util.displayString(sec) + " sec) elapsedNs: " + elapsedTimeNs); +// msg("s:" + s + " read IO is " + sample.getBwMbSecDisplay() + " MB/s " +// + "(" + Util.displayString(mbRead) + "MB read in " +// + Util.displayString(sec) + " sec) elapsedNs: " + elapsedTimeNs); App.updateMetrics(sample); publish(sample); - - run.bwMax = sample.cumMax; - run.bwMin = sample.cumMin; - run.bwAvg = sample.cumAvg; - run.accAvg = sample.cumAccTimeMs; - - run.add(sample); + rOperation.bwMax = sample.cumMax; + rOperation.bwMin = sample.cumMin; + rOperation.bwAvg = sample.cumAvg; + rOperation.accAvg = sample.cumAccTimeMs; + rOperation.add(sample); } })); } @@ -316,18 +298,22 @@ protected Boolean doInBackground() throws Exception { executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); // GH-10 file IOPS processing - run.endTime = LocalDateTime.now(); - run.setTotalOps(rUnitsComplete[0]); - App.rIops = run.iops; + rOperation.endTime = LocalDateTime.now(); + rOperation.setTotalOps(rUnitsComplete[0]); + App.rIops = rOperation.iops; Gui.mainFrame.refreshReadMetrics(); - - EntityManager em = EM.getEntityManager(); - em.getTransaction().begin(); - em.persist(run); - em.getTransaction().commit(); - App.benchmarks.put(run.getStartTimeString(), run); - Gui.runPanel.addRun(run); } + run.endTime = LocalDateTime.now(); + EntityManager em = EM.getEntityManager(); + em.getTransaction().begin(); + em.persist(run); + em.getTransaction().commit(); + App.benchmarks.put(run.getStartTimeString(), run); + for (BenchmarkOperation o : run.getOperations()) { + App.operations.put(o.getStartTimeString(), o); + } + Gui.runPanel.addRun(run); + App.nextSampleNumber += App.numOfSamples; return true; } diff --git a/src/jdiskmark/Gui.java b/src/jdiskmark/Gui.java index 244781c..6d58d61 100644 --- a/src/jdiskmark/Gui.java +++ b/src/jdiskmark/Gui.java @@ -224,7 +224,7 @@ public static void addWriteSample(Sample s) { wDrvAccess.add(s.sampleNum, s.accessTimeMs); } Gui.mainFrame.refreshWriteMetrics(); - System.out.println(s.toString()); + //System.out.println(s.toString()); } public static void addReadSample(Sample s) { rSeries.add(s.sampleNum, s.bwMbSec); @@ -237,7 +237,7 @@ public static void addReadSample(Sample s) { rDrvAccess.add(s.sampleNum, s.accessTimeMs); } Gui.mainFrame.refreshReadMetrics(); - System.out.println(s.toString()); + //System.out.println(s.toString()); } public static void resetBenchmarkData() { @@ -273,9 +273,9 @@ public static void updateLegendAndAxis() { msAxis.setVisible(App.showDriveAccess); } - public static void updateLegendAndAxis(Benchmark b) { - boolean isWriteTest = b.ioMode == Benchmark.IOMode.WRITE; - boolean isReadTest = b.ioMode == Benchmark.IOMode.READ; + public static void updateLegendAndAxis(BenchmarkOperation o) { + boolean isWriteTest = o.ioMode == BenchmarkOperation.IOMode.WRITE; + boolean isReadTest = o.ioMode == BenchmarkOperation.IOMode.READ; bwRenderer.setSeriesVisibleInLegend(0, isWriteTest); bwRenderer.setSeriesVisibleInLegend(1, isWriteTest); bwRenderer.setSeriesVisibleInLegend(2, isWriteTest && App.showMaxMin); @@ -400,41 +400,43 @@ static public void dropCache() { } } - static public void loadBenchmark(Benchmark benchmark) { + static public void loadOperation(BenchmarkOperation operation) { + Benchmark benchmark = operation.getBenchmark(); + System.out.println("benchmark type: " + benchmark.benchmarkType + " o: " + operation.ioMode); resetBenchmarkData(); - updateLegendAndAxis(benchmark); + updateLegendAndAxis(operation); chart.getTitle().setText(benchmark.getDriveInfo()); - ArrayList samples = benchmark.samples; + ArrayList samples = operation.getSamples(); System.out.println("samples=" + samples.size()); for (Sample s : samples) { - System.out.println(s); - if (benchmark.ioMode == Benchmark.IOMode.READ) { + if (operation.ioMode == BenchmarkOperation.IOMode.READ) { addReadSample(s); } else { addWriteSample(s); } } - - App.numOfBlocks = benchmark.numBlocks; - App.numOfSamples = benchmark.numSamples; - App.blockSizeKb = benchmark.blockSize; - App.blockSequence = benchmark.blockOrder; + App.numOfBlocks = operation.numBlocks; + App.numOfSamples = operation.numSamples; + App.blockSizeKb = operation.blockSize; + App.blockSequence = operation.blockOrder; Gui.mainFrame.loadSettings(); - - if (benchmark.ioMode == Benchmark.IOMode.READ) { - App.rAvg = benchmark.bwAvg; - App.rMax = benchmark.bwMax; - App.rMin = benchmark.bwMin; - App.rAcc = benchmark.accAvg; - App.rIops = benchmark.iops; - Gui.mainFrame.refreshReadMetrics(); - } else { - App.wAvg = benchmark.bwAvg; - App.wMax = benchmark.bwMax; - App.wMin = benchmark.bwMin; - App.wAcc = benchmark.accAvg; - App.wIops = benchmark.iops; - Gui.mainFrame.refreshWriteMetrics(); + switch (operation.ioMode) { + case BenchmarkOperation.IOMode.READ -> { + App.rAvg = operation.bwAvg; + App.rMax = operation.bwMax; + App.rMin = operation.bwMin; + App.rAcc = operation.accAvg; + App.rIops = operation.iops; + Gui.mainFrame.refreshReadMetrics(); + } + case BenchmarkOperation.IOMode.WRITE -> { + App.wAvg = operation.bwAvg; + App.wMax = operation.bwMax; + App.wMin = operation.bwMin; + App.wAcc = operation.accAvg; + App.wIops = operation.iops; + Gui.mainFrame.refreshWriteMetrics(); + } } } diff --git a/src/jdiskmark/MainFrame.form b/src/jdiskmark/MainFrame.form index 6bb40a0..d41a566 100644 --- a/src/jdiskmark/MainFrame.form +++ b/src/jdiskmark/MainFrame.form @@ -278,8 +278,8 @@ - - + + @@ -454,12 +454,12 @@ - + - + @@ -534,7 +534,7 @@ - + @@ -559,7 +559,7 @@ - + @@ -567,7 +567,7 @@ - + @@ -698,7 +698,7 @@ - + @@ -721,15 +721,15 @@ - + - + - + @@ -742,7 +742,7 @@ - + @@ -771,7 +771,7 @@ - + diff --git a/src/jdiskmark/MainFrame.java b/src/jdiskmark/MainFrame.java index b6ff526..ed6a178 100644 --- a/src/jdiskmark/MainFrame.java +++ b/src/jdiskmark/MainFrame.java @@ -33,9 +33,9 @@ public MainFrame() { //for diagnostics //controlsPanel.setBackground(Color.blue); - DefaultComboBoxModel ioModel - = new DefaultComboBoxModel<>(Benchmark.IOMode.values()); - modeCombo.setModel(ioModel); + DefaultComboBoxModel ioModel + = new DefaultComboBoxModel<>(Benchmark.BenchmarkType.values()); + typeCombo.setModel(ioModel); startButton.requestFocus(); Gui.createChartPanel(); @@ -73,8 +73,8 @@ public MainFrame() { caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE); // init order combo box - orderComboBox.addItem(Benchmark.BlockSequence.SEQUENTIAL); - orderComboBox.addItem(Benchmark.BlockSequence.RANDOM); + orderComboBox.addItem(BenchmarkOperation.BlockSequence.SEQUENTIAL); + orderComboBox.addItem(BenchmarkOperation.BlockSequence.RANDOM); } public JPanel getMountPanel() { @@ -117,17 +117,16 @@ public void loadConfig() { } public void initializeComboSettings() { - modeCombo.setSelectedItem(App.ioMode); + typeCombo.setSelectedItem(App.benchmarkType); loadSettings(); } public void loadSettings() { - //String blockOrderStr = App.randomEnable ? "random":"sequential"; + numThreadsCombo.setSelectedItem(String.valueOf(App.numOfThreads)); orderComboBox.setSelectedItem(App.blockSequence); - - numFilesCombo.setSelectedItem(String.valueOf(App.numOfSamples)); numBlocksCombo.setSelectedItem(String.valueOf(App.numOfBlocks)); - blockSizeCombo.setSelectedItem(String.valueOf(App.blockSizeKb)); + blockSizeCombo.setSelectedItem(String.valueOf(App.blockSizeKb)); + numSamplesCombo.setSelectedItem(String.valueOf(App.numOfSamples)); } @@ -158,9 +157,9 @@ private void initComponents() { jLabel6 = new javax.swing.JLabel(); blockSizeCombo = new javax.swing.JComboBox(); jLabel8 = new javax.swing.JLabel(); - numFilesCombo = new javax.swing.JComboBox(); + numSamplesCombo = new javax.swing.JComboBox(); jLabel4 = new javax.swing.JLabel(); - modeCombo = new javax.swing.JComboBox(); + typeCombo = new javax.swing.JComboBox(); jLabel9 = new javax.swing.JLabel(); sampleSizeLabel = new javax.swing.JLabel(); orderComboBox = new javax.swing.JComboBox<>(); @@ -223,7 +222,7 @@ private void initComponents() { setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); setTitle("JDiskMark"); - tabbedPane.addTab("Benchmarks", runPanel); + tabbedPane.addTab("Benchmark Operations", runPanel); msgTextArea.setEditable(false); msgTextArea.setColumns(20); @@ -330,23 +329,23 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { jLabel8.setText("No. Samples"); - numFilesCombo.setEditable(true); - numFilesCombo.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "50", "100", "200", "300", "500", "1000", "2000", "3000", "5000", "10000" })); - numFilesCombo.setSelectedIndex(2); - numFilesCombo.setPreferredSize(new java.awt.Dimension(72, 24)); - numFilesCombo.addActionListener(new java.awt.event.ActionListener() { + numSamplesCombo.setEditable(true); + numSamplesCombo.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "50", "100", "200", "300", "500", "1000", "2000", "3000", "5000", "10000" })); + numSamplesCombo.setSelectedIndex(2); + numSamplesCombo.setPreferredSize(new java.awt.Dimension(72, 24)); + numSamplesCombo.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - numFilesComboActionPerformed(evt); + numSamplesComboActionPerformed(evt); } }); - jLabel4.setText("IO Mode"); + jLabel4.setText("Benchmark Type"); - modeCombo.setModel(new javax.swing.DefaultComboBoxModel(new String[] { " ", " " })); - modeCombo.setPreferredSize(new java.awt.Dimension(60, 24)); - modeCombo.addActionListener(new java.awt.event.ActionListener() { + typeCombo.setModel(new javax.swing.DefaultComboBoxModel(new String[] { " ", " " })); + typeCombo.setPreferredSize(new java.awt.Dimension(60, 24)); + typeCombo.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - modeComboActionPerformed(evt); + typeComboActionPerformed(evt); } }); @@ -452,12 +451,12 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { .addComponent(jLabel21)) .addGap(18, 18, 18) .addGroup(controlsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(modeCombo, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(typeCombo, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(numThreadsCombo, 0, 100, Short.MAX_VALUE) .addComponent(orderComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(numBlocksCombo, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(blockSizeCombo, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(numFilesCombo, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addComponent(numSamplesCombo, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) .addGroup(controlsPanelLayout.createSequentialGroup() .addGroup(controlsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jLabel13) @@ -510,7 +509,7 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { .addGroup(controlsPanelLayout.createSequentialGroup() .addGroup(controlsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jLabel4) - .addComponent(modeCombo, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(typeCombo, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(controlsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(numThreadsCombo, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) @@ -530,13 +529,13 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(controlsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jLabel8) - .addComponent(numFilesCombo, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(numSamplesCombo, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(controlsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jLabel9) .addComponent(sampleSizeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(startButton, javax.swing.GroupLayout.DEFAULT_SIZE, 43, Short.MAX_VALUE) + .addComponent(startButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGap(18, 18, 18) .addGroup(controlsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jLabel20, javax.swing.GroupLayout.Alignment.TRAILING) @@ -833,6 +832,7 @@ private void startButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-F }//GEN-LAST:event_startButtonActionPerformed private void blockSizeComboActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_blockSizeComboActionPerformed + // NOTE: selecting a value from dropdown does not trigger the below if (blockSizeCombo.hasFocus()) { App.blockSizeKb = Integer.parseInt((String) blockSizeCombo.getSelectedItem()); sampleSizeLabel.setText(String.valueOf(App.targetMarkSizeKb())); @@ -842,6 +842,7 @@ private void blockSizeComboActionPerformed(java.awt.event.ActionEvent evt) {//GE }//GEN-LAST:event_blockSizeComboActionPerformed private void numBlocksComboActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_numBlocksComboActionPerformed + // NOTE: selecting a value from dropdown does not trigger the below if (numBlocksCombo.hasFocus()) { App.numOfBlocks = Integer.parseInt((String) numBlocksCombo.getSelectedItem()); sampleSizeLabel.setText(String.valueOf(App.targetMarkSizeKb())); @@ -850,23 +851,23 @@ private void numBlocksComboActionPerformed(java.awt.event.ActionEvent evt) {//GE } }//GEN-LAST:event_numBlocksComboActionPerformed - private void numFilesComboActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_numFilesComboActionPerformed - if (numFilesCombo.hasFocus()) { - App.numOfSamples = Integer.parseInt((String) numFilesCombo.getSelectedItem()); + private void numSamplesComboActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_numSamplesComboActionPerformed + // NOTE: selecting a value from dropdown does not trigger the below + if (numSamplesCombo.hasFocus()) { + App.numOfSamples = Integer.parseInt((String) numSamplesCombo.getSelectedItem()); sampleSizeLabel.setText(String.valueOf(App.targetMarkSizeKb())); totalTxProgBar.setString(String.valueOf(App.targetTxSizeKb())); App.saveConfig(); } - }//GEN-LAST:event_numFilesComboActionPerformed + }//GEN-LAST:event_numSamplesComboActionPerformed - private void modeComboActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_modeComboActionPerformed - if (modeCombo.hasFocus()) { - Benchmark.IOMode mode = (Benchmark.IOMode) modeCombo.getSelectedItem(); - App.ioMode = mode; + private void typeComboActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_typeComboActionPerformed + if (typeCombo.hasFocus()) { + Benchmark.BenchmarkType mode = (Benchmark.BenchmarkType) typeCombo.getSelectedItem(); + App.benchmarkType = mode; App.saveConfig(); - System.out.println("modeCombo changed to: " + mode); } - }//GEN-LAST:event_modeComboActionPerformed + }//GEN-LAST:event_typeComboActionPerformed private void exitMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitMenuItemActionPerformed System.exit(0); @@ -919,7 +920,7 @@ private void showMaxMinCheckBoxMenuItemActionPerformed(java.awt.event.ActionEven private void orderComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orderComboBoxActionPerformed if (orderComboBox.hasFocus()) { - App.blockSequence = (Benchmark.BlockSequence) orderComboBox.getSelectedItem(); + App.blockSequence = (BenchmarkOperation.BlockSequence) orderComboBox.getSelectedItem(); App.saveConfig(); } }//GEN-LAST:event_orderComboBoxActionPerformed @@ -986,6 +987,7 @@ private void resetBenchmarkItemActionPerformed(java.awt.event.ActionEvent evt) { }//GEN-LAST:event_resetBenchmarkItemActionPerformed private void numThreadsComboActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_numThreadsComboActionPerformed + // NOTE: selecting a value from dropdown does not trigger the below if (numThreadsCombo.hasFocus()) { App.numOfThreads = Integer.parseInt((String) numThreadsCombo.getSelectedItem()); App.saveConfig(); @@ -1041,16 +1043,15 @@ private void numThreadsComboActionPerformed(java.awt.event.ActionEvent evt) {//G private javax.swing.JPanel locationPanel; private javax.swing.JTextField locationText; private javax.swing.JMenuBar menuBar; - private javax.swing.JComboBox modeCombo; private javax.swing.JPanel mountPanel; private javax.swing.JTextArea msgTextArea; private javax.swing.JCheckBoxMenuItem multiFileCheckBoxMenuItem; private javax.swing.JComboBox numBlocksCombo; - private javax.swing.JComboBox numFilesCombo; + private javax.swing.JComboBox numSamplesCombo; private javax.swing.JComboBox numThreadsCombo; private javax.swing.JButton openLocButton; private javax.swing.JMenu optionMenu; - private javax.swing.JComboBox orderComboBox; + private javax.swing.JComboBox orderComboBox; private javax.swing.ButtonGroup palettebuttonGroup; private javax.swing.JPanel progressPanel; private javax.swing.JLabel rAccessLabel; @@ -1067,6 +1068,7 @@ private void numThreadsComboActionPerformed(java.awt.event.ActionEvent evt) {//G private javax.swing.JButton startButton; private javax.swing.JTabbedPane tabbedPane; private javax.swing.JProgressBar totalTxProgBar; + private javax.swing.JComboBox typeCombo; private javax.swing.JLabel wAccessLabel; private javax.swing.JLabel wAvgLabel; private javax.swing.JLabel wIopsLabel; @@ -1084,10 +1086,10 @@ public void msg(String message) { } public void applyTestParams() { - Benchmark.IOMode mode = (Benchmark.IOMode) modeCombo.getSelectedItem(); - App.ioMode = mode; - App.blockSequence = (Benchmark.BlockSequence) orderComboBox.getSelectedItem(); - App.numOfSamples = Integer.parseInt((String) numFilesCombo.getSelectedItem()); + Benchmark.BenchmarkType mode = (Benchmark.BenchmarkType) typeCombo.getSelectedItem(); + App.benchmarkType = mode; + App.blockSequence = (BenchmarkOperation.BlockSequence) orderComboBox.getSelectedItem(); + App.numOfSamples = Integer.parseInt((String) numSamplesCombo.getSelectedItem()); App.numOfBlocks = Integer.parseInt((String) numBlocksCombo.getSelectedItem()); App.blockSizeKb = Integer.parseInt((String) blockSizeCombo.getSelectedItem()); App.numOfThreads = Integer.parseInt((String) numThreadsCombo.getSelectedItem()); @@ -1138,8 +1140,8 @@ public void adjustSensitivity() { orderComboBox.setEnabled(false); blockSizeCombo.setEnabled(false); numBlocksCombo.setEnabled(false); - numFilesCombo.setEnabled(false); - modeCombo.setEnabled(false); + numSamplesCombo.setEnabled(false); + typeCombo.setEnabled(false); numThreadsCombo.setEnabled(false); resetBenchmarkItem.setEnabled(false); } @@ -1148,20 +1150,23 @@ public void adjustSensitivity() { orderComboBox.setEnabled(true); blockSizeCombo.setEnabled(true); numBlocksCombo.setEnabled(true); - numFilesCombo.setEnabled(true); - modeCombo.setEnabled(true); + numSamplesCombo.setEnabled(true); + typeCombo.setEnabled(true); numThreadsCombo.setEnabled(true); resetBenchmarkItem.setEnabled(true); } + + + } } // Replace lowercase mode options with proper casing @SuppressWarnings("unchecked") private void configureModeCombo() { - modeCombo.removeAllItems(); - modeCombo.addItem("Write"); - modeCombo.addItem("Read"); - modeCombo.addItem("Read & Write"); + typeCombo.removeAllItems(); + typeCombo.addItem("Write"); + typeCombo.addItem("Read"); + typeCombo.addItem("Read & Write"); } } From 03f33ebe4d21240c89fd1cfc506411e6d47265c3 Mon Sep 17 00:00:00 2001 From: James Mark Chan Date: Sun, 14 Sep 2025 21:04:43 -0700 Subject: [PATCH 2/4] #73 remove unused fields, update type and threads on load --- src/jdiskmark/Benchmark.java | 55 ++---------------------------------- src/jdiskmark/Gui.java | 2 ++ src/jdiskmark/MainFrame.java | 1 + 3 files changed, 5 insertions(+), 53 deletions(-) diff --git a/src/jdiskmark/Benchmark.java b/src/jdiskmark/Benchmark.java index 6e5489e..85b06c0 100644 --- a/src/jdiskmark/Benchmark.java +++ b/src/jdiskmark/Benchmark.java @@ -89,17 +89,6 @@ public enum BenchmarkType { @Column LocalDateTime endTime = null; - // results - @Column - double bwAvg = 0; - @Column - double bwMax = 0; - @Column - double bwMin = 0; - @Column - double accAvg = 0; - @Column - long iops = 0; @OneToMany(mappedBy = "benchmark", cascade = CascadeType.ALL, orphanRemoval = true) private List operations = new ArrayList<>(); @@ -120,7 +109,7 @@ public BenchmarkOperation getOperation(BenchmarkOperation.IOMode mode) { @Override public String toString() { - return "Benchmark(" + benchmarkType + "): bw: " + bwAvg; + return "Benchmark(" + benchmarkType + ") start=" + startTime + "numOps=" + operations.size(); } public Benchmark() { @@ -160,31 +149,11 @@ public String getUsageColumnDisplay() { // public String getBlocksDisplay() { // return numBlocks + " (" + blockSize + ")"; // } - + public String getStartTimeString() { return startTime.format(DATE_FORMAT); } - public String getAccTimeDisplay() { - return accAvg == -1? "- -" : DF.format(accAvg); - } - - public String getBwMinDisplay() { - return bwMin == -1 ? "- -" : DF.format(bwMin); - } - - public String getBwMaxDisplay() { - return bwMax == -1 ? "- -" : DF.format(bwMax); - } - - public String getBwMinMaxDisplay() { - return bwMax == -1 ? "- -" : DFT.format(bwMin) + "/" + DFT.format(bwMax); - } - - public String getBwAvgDisplay() { - return bwAvg == -1 ? "- -" : DF.format(bwAvg); - } - public String getDuration() { if (endTime == null) { return "unknown"; @@ -193,26 +162,6 @@ public String getDuration() { return String.valueOf(diffMs); } - public void setTotalOps(long totalOps) { - // iops = operations / sec = ops / (elapsed ms / 1,000ms) - // Multiply by 1_000_000 to convert milliseconds to seconds - System.err.println("startTime=" + startTime); - System.err.println("endTime=" + endTime); - long diffMs = Duration.between(startTime, endTime).toMillis(); - if (diffMs != 0) { - double iopsDouble = (double) (totalOps * 1_000_000) / (double) diffMs; - iops = Math.round(iopsDouble); - } - } - - public long getIops() { - return iops; - } - - public void setIops(long iops) { - this.iops = iops; - } - // utility methods for collection static List findAll() { diff --git a/src/jdiskmark/Gui.java b/src/jdiskmark/Gui.java index 6d58d61..081b599 100644 --- a/src/jdiskmark/Gui.java +++ b/src/jdiskmark/Gui.java @@ -415,10 +415,12 @@ static public void loadOperation(BenchmarkOperation operation) { addWriteSample(s); } } + App.benchmarkType = benchmark.benchmarkType; App.numOfBlocks = operation.numBlocks; App.numOfSamples = operation.numSamples; App.blockSizeKb = operation.blockSize; App.blockSequence = operation.blockOrder; + App.numOfThreads = operation.numThreads; Gui.mainFrame.loadSettings(); switch (operation.ioMode) { case BenchmarkOperation.IOMode.READ -> { diff --git a/src/jdiskmark/MainFrame.java b/src/jdiskmark/MainFrame.java index ed6a178..993ee8d 100644 --- a/src/jdiskmark/MainFrame.java +++ b/src/jdiskmark/MainFrame.java @@ -122,6 +122,7 @@ public void initializeComboSettings() { } public void loadSettings() { + typeCombo.setSelectedItem(App.benchmarkType); numThreadsCombo.setSelectedItem(String.valueOf(App.numOfThreads)); orderComboBox.setSelectedItem(App.blockSequence); numBlocksCombo.setSelectedItem(String.valueOf(App.numOfBlocks)); From f940a699c4d1b23856d6c0b3571a64daaff0d4f3 Mon Sep 17 00:00:00 2001 From: James Mark Chan Date: Sun, 14 Sep 2025 21:34:19 -0700 Subject: [PATCH 3/4] #73 load operation on selection, replaces mouse click listener --- src/jdiskmark/BenchmarkPanel.form | 3 -- src/jdiskmark/BenchmarkPanel.java | 24 +++----------- src/jdiskmark/MainFrame.java | 24 ++++++-------- .../OperationTableSelectionListener.java | 33 +++++++++++++++++++ 4 files changed, 47 insertions(+), 37 deletions(-) create mode 100644 src/jdiskmark/OperationTableSelectionListener.java diff --git a/src/jdiskmark/BenchmarkPanel.form b/src/jdiskmark/BenchmarkPanel.form index d6ea84a..1106ca9 100644 --- a/src/jdiskmark/BenchmarkPanel.form +++ b/src/jdiskmark/BenchmarkPanel.form @@ -136,9 +136,6 @@ - - - diff --git a/src/jdiskmark/BenchmarkPanel.java b/src/jdiskmark/BenchmarkPanel.java index cc03323..efc634e 100644 --- a/src/jdiskmark/BenchmarkPanel.java +++ b/src/jdiskmark/BenchmarkPanel.java @@ -9,9 +9,6 @@ import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; -/** - * @author James - */ public class BenchmarkPanel extends javax.swing.JPanel { /** @@ -23,6 +20,10 @@ public BenchmarkPanel() { // Tooltip only – keep it simple runTable.setToolTipText("Mode: Write* means Write Sync was enabled"); + + // #73 load new selected operation + OperationTableSelectionListener selectionListener = new OperationTableSelectionListener(runTable); + runTable.getSelectionModel().addListSelectionListener(selectionListener); // center align cells 2 - 11 for (int i = 2; i <= 11; i++) { @@ -74,11 +75,6 @@ public boolean isCellEditable(int rowIndex, int columnIndex) { } }); runTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); - runTable.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseClicked(java.awt.event.MouseEvent evt) { - runTableMouseClicked(evt); - } - }); jScrollPane1.setViewportView(runTable); if (runTable.getColumnModel().getColumnCount() > 0) { runTable.getColumnModel().getColumn(0).setPreferredWidth(10); @@ -119,17 +115,6 @@ public void mouseClicked(java.awt.event.MouseEvent evt) { }// //GEN-END:initComponents static final int START_TIME_COLUMN = 7; - - private void runTableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_runTableMouseClicked - int sRow = runTable.getSelectedRow(); - String timeString = (String) runTable.getValueAt(sRow, START_TIME_COLUMN); - System.out.println("selected operation starttime=" + timeString); - BenchmarkOperation operation = App.operations.get(timeString); - if (operation != null) { - Gui.loadOperation(operation); - } - }//GEN-LAST:event_runTableMouseClicked - // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JScrollPane jScrollPane1; @@ -140,7 +125,6 @@ private void runTableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:ev public void addRun(Benchmark run) { List operations = run.getOperations(); - System.out.println("number of operations: " + operations.size()); DefaultTableModel model = (DefaultTableModel) this.runTable.getModel(); for (BenchmarkOperation o : operations) { model.addRow( diff --git a/src/jdiskmark/MainFrame.java b/src/jdiskmark/MainFrame.java index 993ee8d..7a5a915 100644 --- a/src/jdiskmark/MainFrame.java +++ b/src/jdiskmark/MainFrame.java @@ -117,9 +117,9 @@ public void loadConfig() { } public void initializeComboSettings() { - typeCombo.setSelectedItem(App.benchmarkType); - loadSettings(); -} + typeCombo.setSelectedItem(App.benchmarkType); + loadSettings(); + } public void loadSettings() { typeCombo.setSelectedItem(App.benchmarkType); @@ -130,7 +130,6 @@ public void loadSettings() { numSamplesCombo.setSelectedItem(String.valueOf(App.numOfSamples)); } - /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -1156,18 +1155,15 @@ public void adjustSensitivity() { numThreadsCombo.setEnabled(true); resetBenchmarkItem.setEnabled(true); } - - - } } // Replace lowercase mode options with proper casing -@SuppressWarnings("unchecked") -private void configureModeCombo() { - typeCombo.removeAllItems(); - typeCombo.addItem("Write"); - typeCombo.addItem("Read"); - typeCombo.addItem("Read & Write"); -} + @SuppressWarnings("unchecked") + private void configureModeCombo() { + typeCombo.removeAllItems(); + typeCombo.addItem("Write"); + typeCombo.addItem("Read"); + typeCombo.addItem("Read & Write"); + } } diff --git a/src/jdiskmark/OperationTableSelectionListener.java b/src/jdiskmark/OperationTableSelectionListener.java new file mode 100644 index 0000000..a9b9143 --- /dev/null +++ b/src/jdiskmark/OperationTableSelectionListener.java @@ -0,0 +1,33 @@ + +package jdiskmark; + +import javax.swing.JTable; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import static jdiskmark.BenchmarkPanel.START_TIME_COLUMN; + +public class OperationTableSelectionListener implements ListSelectionListener { + final private JTable table; + + public OperationTableSelectionListener(JTable table) { + this.table = table; + } + + @Override + public void valueChanged(ListSelectionEvent e) { + // This prevents the event from firing twice (once for the old selection, once for the new) + if (e.getValueIsAdjusting()) { + return; + } + + int selectedRow = table.getSelectedRow(); + if (selectedRow != -1) { + String timeString = (String) table.getValueAt(selectedRow, START_TIME_COLUMN); + System.out.println("selected operation starttime=" + timeString); + BenchmarkOperation operation = App.operations.get(timeString); + if (operation != null) { + Gui.loadOperation(operation); + } + } + } +} From 8e1c291db2baed77453c66f2b7b67762b7a8157f Mon Sep 17 00:00:00 2001 From: James Mark Chan Date: Sun, 14 Sep 2025 21:48:44 -0700 Subject: [PATCH 4/4] #73 update readme, rename run to benchmark --- README.md | 3 ++- src/jdiskmark/Benchmark.java | 13 +--------- src/jdiskmark/BenchmarkWorker.java | 38 +++++++++++++++--------------- 3 files changed, 22 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index da7837b..0cdb973 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Java 21 needs to be installed to run jdiskmark. 3. Extract release zip archive into desired location. ``` Examples: - /Users/username/jdiskmark-v0.6.0 + /Users/username/jdiskmark-v0.6.0 /opt/jdiskmark-v0.6.0 ``` @@ -84,6 +84,7 @@ Source code is available on our [github repo](https://github.com/JDiskMark/jdm-j - TODO: #33 maven build - lane - TODO: #40 gui presentation issues - james - #84 processor info resolved for (sp) installs +- #73 refactor benchmark data model, keyboard op sel ### v0.6.2 linux optimized ui - #64 persist IOPS, write sync - val diff --git a/src/jdiskmark/Benchmark.java b/src/jdiskmark/Benchmark.java index 85b06c0..7ede76f 100644 --- a/src/jdiskmark/Benchmark.java +++ b/src/jdiskmark/Benchmark.java @@ -138,18 +138,7 @@ public String getUsageTitleDisplay() { public String getUsageColumnDisplay() { return percentUsed + "%"; } - - // GH-20 TODO: review should this be synchronized or redone to not be blocking? -// public synchronized void add(Sample s) { -// samples.add(s); -// } - - // display friendly methods - -// public String getBlocksDisplay() { -// return numBlocks + " (" + blockSize + ")"; -// } - + public String getStartTimeString() { return startTime.format(DATE_FORMAT); } diff --git a/src/jdiskmark/BenchmarkWorker.java b/src/jdiskmark/BenchmarkWorker.java index fc7d6f6..0de34b9 100644 --- a/src/jdiskmark/BenchmarkWorker.java +++ b/src/jdiskmark/BenchmarkWorker.java @@ -108,25 +108,25 @@ protected Boolean doInBackground() throws Exception { List> futures = new ArrayList<>(); - Benchmark run = new Benchmark(App.benchmarkType); + Benchmark benchmark = new Benchmark(App.benchmarkType); // system info - run.processorName = App.processorName; - run.os = App.os; - run.arch = App.arch; + benchmark.processorName = App.processorName; + benchmark.os = App.os; + benchmark.arch = App.arch; // drive information - run.driveModel = driveModel; - run.partitionId = partitionId; - run.percentUsed = usageInfo.percentUsed; - run.usedGb = usageInfo.usedGb; - run.totalGb = usageInfo.totalGb; + benchmark.driveModel = driveModel; + benchmark.partitionId = partitionId; + benchmark.percentUsed = usageInfo.percentUsed; + benchmark.usedGb = usageInfo.usedGb; + benchmark.totalGb = usageInfo.totalGb; - Gui.chart.getTitle().setText(run.getDriveInfo()); + Gui.chart.getTitle().setText(benchmark.getDriveInfo()); Gui.chart.getTitle().setVisible(true); if (App.isWriteEnabled()) { BenchmarkOperation wOperation = new BenchmarkOperation(); - wOperation.setBenchmark(run); + wOperation.setBenchmark(benchmark); wOperation.ioMode = BenchmarkOperation.IOMode.WRITE; wOperation.blockOrder = App.blockSequence; wOperation.numSamples = App.numOfSamples; @@ -136,7 +136,7 @@ protected Boolean doInBackground() throws Exception { wOperation.numThreads = App.numOfThreads; // persist whether write sync was enabled for this run wOperation.setWriteSyncEnabled(App.writeSyncEnable); - run.getOperations().add(wOperation); + benchmark.getOperations().add(wOperation); if (App.multiFile == false) { testFile = new File(dataDir.getAbsolutePath() + File.separator + "testdata.jdm"); @@ -222,7 +222,7 @@ protected Boolean doInBackground() throws Exception { if (App.isReadEnabled()) { BenchmarkOperation rOperation = new BenchmarkOperation(); - rOperation.setBenchmark(run); + rOperation.setBenchmark(benchmark); // operation parameters rOperation.ioMode = BenchmarkOperation.IOMode.READ; rOperation.blockOrder = App.blockSequence; @@ -233,7 +233,7 @@ protected Boolean doInBackground() throws Exception { rOperation.numThreads = App.numOfThreads; // write sync does not apply to pure read benchmarks rOperation.setWriteSyncEnabled(null); - run.getOperations().add(rOperation); + benchmark.getOperations().add(rOperation); ExecutorService executorService = Executors.newFixedThreadPool(App.numOfThreads); @@ -303,16 +303,16 @@ protected Boolean doInBackground() throws Exception { App.rIops = rOperation.iops; Gui.mainFrame.refreshReadMetrics(); } - run.endTime = LocalDateTime.now(); + benchmark.endTime = LocalDateTime.now(); EntityManager em = EM.getEntityManager(); em.getTransaction().begin(); - em.persist(run); + em.persist(benchmark); em.getTransaction().commit(); - App.benchmarks.put(run.getStartTimeString(), run); - for (BenchmarkOperation o : run.getOperations()) { + App.benchmarks.put(benchmark.getStartTimeString(), benchmark); + for (BenchmarkOperation o : benchmark.getOperations()) { App.operations.put(o.getStartTimeString(), o); } - Gui.runPanel.addRun(run); + Gui.runPanel.addRun(benchmark); App.nextSampleNumber += App.numOfSamples; return true;