= Move benchmark core to fit existing standard
This commit is contained in:
@@ -2,11 +2,11 @@ package commands.benchmark;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import core.benchmark.BenchmarkCommand;
|
||||
import core.benchmark.BenchmarkEntry;
|
||||
import core.benchmark.BenchmarkFormattable;
|
||||
import core.benchmark.BenchmarkInput;
|
||||
import core.benchmark.BenchmarkManager;
|
||||
import commands.benchmark.core.BenchmarkCommand;
|
||||
import commands.benchmark.core.BenchmarkEntry;
|
||||
import commands.benchmark.core.BenchmarkFormattable;
|
||||
import commands.benchmark.core.BenchmarkInput;
|
||||
import commands.benchmark.core.BenchmarkManager;
|
||||
|
||||
public class BenchmarkCommandCompare extends BenchmarkCommand
|
||||
{
|
||||
|
||||
@@ -2,7 +2,11 @@ package commands.benchmark;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import core.benchmark.*;
|
||||
import commands.benchmark.core.BenchmarkCommand;
|
||||
import commands.benchmark.core.BenchmarkEntry;
|
||||
import commands.benchmark.core.BenchmarkFormattable;
|
||||
import commands.benchmark.core.BenchmarkInput;
|
||||
import commands.benchmark.core.BenchmarkManager;
|
||||
|
||||
public class BenchmarkCommandFind extends BenchmarkCommand
|
||||
{
|
||||
|
||||
@@ -2,11 +2,11 @@ package commands.benchmark;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import core.benchmark.BenchmarkCommand;
|
||||
import core.benchmark.BenchmarkEntry;
|
||||
import core.benchmark.BenchmarkFormattable;
|
||||
import core.benchmark.BenchmarkInput;
|
||||
import core.benchmark.BenchmarkManager;
|
||||
import commands.benchmark.core.BenchmarkCommand;
|
||||
import commands.benchmark.core.BenchmarkEntry;
|
||||
import commands.benchmark.core.BenchmarkFormattable;
|
||||
import commands.benchmark.core.BenchmarkInput;
|
||||
import commands.benchmark.core.BenchmarkManager;
|
||||
import dataStructures.KittyEmbed;
|
||||
import java.awt.Color;
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package commands.benchmark;
|
||||
|
||||
import commands.benchmark.core.BenchmarkFormattable;
|
||||
import commands.benchmark.core.BenchmarkFramework;
|
||||
import core.Command;
|
||||
import core.LocStrings;
|
||||
import core.benchmark.BenchmarkFormattable;
|
||||
import core.benchmark.BenchmarkFramework;
|
||||
import dataStructures.KittyChannel;
|
||||
import dataStructures.KittyGuild;
|
||||
import dataStructures.KittyRating;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package commands.benchmark.core;
|
||||
|
||||
public abstract class BenchmarkCommand
|
||||
{
|
||||
public BenchmarkCommand()
|
||||
{ }
|
||||
|
||||
// OVERRIDE ME
|
||||
public abstract BenchmarkFormattable onRun(BenchmarkManager manager, BenchmarkInput input);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package commands.benchmark.core;
|
||||
|
||||
public class BenchmarkEntry
|
||||
{
|
||||
public final BenchmarkType type;
|
||||
public final String partNumber;
|
||||
public final String brand;
|
||||
public final String model;
|
||||
public final int rank;
|
||||
public final float benchmark;
|
||||
public final int samples;
|
||||
public final String url;
|
||||
|
||||
BenchmarkEntry(String input)
|
||||
{
|
||||
String[] row = input.split(",");
|
||||
|
||||
type = BenchmarkType.valueOf(row[0]);
|
||||
partNumber = row[1];
|
||||
brand = row[2];
|
||||
model = row[3];
|
||||
rank = Integer.parseInt(row[4]);
|
||||
benchmark = Float.parseFloat(row[5]);
|
||||
samples = Integer.parseInt(row[6]);
|
||||
url = row[7];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package commands.benchmark.core;
|
||||
|
||||
import dataStructures.KittyEmbed;
|
||||
import dataStructures.Response;
|
||||
|
||||
// Only one isn't null!
|
||||
public class BenchmarkFormattable
|
||||
{
|
||||
public final KittyEmbed resEmbed;
|
||||
public final String resString;
|
||||
|
||||
// Default constructor is hidden and disabled.
|
||||
// If somehow it is called, defaults to an empty string and no embed.
|
||||
@SuppressWarnings("unused")
|
||||
private BenchmarkFormattable()
|
||||
{
|
||||
this.resEmbed = null;
|
||||
this.resString = "";
|
||||
}
|
||||
|
||||
public BenchmarkFormattable(String res)
|
||||
{
|
||||
this.resEmbed = null;
|
||||
this.resString = res;
|
||||
}
|
||||
|
||||
public BenchmarkFormattable(KittyEmbed embed)
|
||||
{
|
||||
this.resEmbed = embed;
|
||||
this.resString = null;
|
||||
}
|
||||
|
||||
public void call(Response res)
|
||||
{
|
||||
if(resEmbed == null)
|
||||
res.send(resString);
|
||||
else
|
||||
res.send(resEmbed);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package commands.benchmark.core;
|
||||
|
||||
import java.util.HashMap;
|
||||
import commands.benchmark.*;
|
||||
|
||||
// Based on general core structure, this registers sub-commands and keeps tabs on them.
|
||||
public class BenchmarkFramework
|
||||
{
|
||||
// Variables
|
||||
public HashMap<String, BenchmarkCommand> benchmarkCommand;
|
||||
public BenchmarkManager benchmarkManager;
|
||||
|
||||
// Constructor and command registration
|
||||
public BenchmarkFramework()
|
||||
{
|
||||
this.benchmarkManager = new BenchmarkManager();
|
||||
this.benchmarkCommand = new HashMap<String, BenchmarkCommand>();
|
||||
|
||||
registerCommand("find", new BenchmarkCommandFind());
|
||||
registerCommand("compare", new BenchmarkCommandCompare());
|
||||
registerCommand("info", new BenchmarkCommandInfo());
|
||||
}
|
||||
|
||||
// Runs a command if possible.
|
||||
public BenchmarkFormattable run(String args)
|
||||
{
|
||||
BenchmarkInput input = new BenchmarkInput(args);
|
||||
return executeCommand(input.key, input);
|
||||
}
|
||||
|
||||
public void update()
|
||||
{
|
||||
synchronized(benchmarkManager)
|
||||
{
|
||||
benchmarkManager.update();
|
||||
}
|
||||
}
|
||||
|
||||
// Registers a command
|
||||
private void registerCommand(String commandName, BenchmarkCommand command)
|
||||
{
|
||||
commandName = commandName.toLowerCase();
|
||||
if(benchmarkCommand.put(commandName, command) != null)
|
||||
BenchmarkLog.log("Multiple registration of a command with name '" + commandName + "'!");
|
||||
|
||||
BenchmarkLog.log("Registered " + commandName);
|
||||
}
|
||||
|
||||
// Executes a command with the specified name, and provides it with some extra input data.
|
||||
private BenchmarkFormattable executeCommand(String name, BenchmarkInput input)
|
||||
{
|
||||
BenchmarkCommand command = benchmarkCommand.get(name.toLowerCase());
|
||||
|
||||
if(command != null && benchmarkManager != null)
|
||||
return command.onRun(benchmarkManager, input);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package commands.benchmark.core;
|
||||
|
||||
import utils.StringUtils;
|
||||
|
||||
// Lifted from an early iteration of RPGInput
|
||||
public class BenchmarkInput
|
||||
{
|
||||
public String raw;
|
||||
public String key;
|
||||
public String value;
|
||||
|
||||
public BenchmarkInput(String raw)
|
||||
{
|
||||
this.raw = raw;
|
||||
this.key = "";
|
||||
this.value = "";
|
||||
|
||||
if(raw == null || raw.length() == 0)
|
||||
return;
|
||||
|
||||
raw = raw.trim();
|
||||
int whitespacePos = StringUtils.findFirstWhitespace(raw);
|
||||
|
||||
if(whitespacePos == -1)
|
||||
{
|
||||
key = raw;
|
||||
return;
|
||||
}
|
||||
|
||||
key = raw.substring(0, whitespacePos).trim();
|
||||
value = raw.substring(whitespacePos).trim();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package commands.benchmark.core;
|
||||
|
||||
import utils.GlobalLog;
|
||||
|
||||
//Logging shim
|
||||
public class BenchmarkLog
|
||||
{
|
||||
public static void log(String str) { GlobalLog.log("[Benchmark] " + str); }
|
||||
public static void warn(String str) { GlobalLog.warn("[Benchmark] " + str); }
|
||||
public static void error(String str) { GlobalLog.error(" [Benchmark] " + str); }
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
package commands.benchmark.core;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import core.Constants;
|
||||
import dataStructures.Pair;
|
||||
import utils.io.DirectoryMonitor;
|
||||
import utils.io.FileUtils;
|
||||
import utils.io.MonitoredFile;
|
||||
|
||||
// All things considered, this doesn't need to be particularly efficient since anything
|
||||
// less than 10ms of search time won't be noticable to an end user really, not for
|
||||
// a networked application that's not performance bound.
|
||||
public class BenchmarkManager
|
||||
{
|
||||
// Variables
|
||||
public final String directory = Constants.AssetDirectory + "userbench/";
|
||||
public final String extension = ".csv";
|
||||
public final String lineDelimiter = "\n";
|
||||
|
||||
private List<BenchmarkEntry> raw;
|
||||
private DirectoryMonitor directoryMonitor;
|
||||
private boolean needsUpdate;
|
||||
|
||||
// Read in all extensions
|
||||
public BenchmarkManager()
|
||||
{
|
||||
long start = Instant.now().toEpochMilli();
|
||||
|
||||
raw = new ArrayList<BenchmarkEntry>();
|
||||
directoryMonitor = new DirectoryMonitor(directory);
|
||||
needsUpdate = false;
|
||||
|
||||
rebuildLookup();
|
||||
|
||||
BenchmarkLog.log("Took " + (Instant.now().toEpochMilli() - start) + " ms to load " + raw.size() + " entries from " + directoryMonitor.getCurrentFiles().size() + " file" + (raw.size() > 1 ? "s" : ""));
|
||||
}
|
||||
|
||||
// Rebuilds the files being monitored
|
||||
public void rebuildLookup()
|
||||
{
|
||||
long start = Instant.now().toEpochMilli();
|
||||
|
||||
synchronized(raw)
|
||||
{
|
||||
raw.clear();
|
||||
List<MonitoredFile> files;
|
||||
|
||||
synchronized(directoryMonitor)
|
||||
{
|
||||
files = directoryMonitor.getCurrentFiles();
|
||||
}
|
||||
|
||||
if(files != null)
|
||||
{
|
||||
for(MonitoredFile mf : files)
|
||||
{
|
||||
String contents = FileUtils.readContent(mf.path);
|
||||
String[] lines = contents.split(lineDelimiter);
|
||||
|
||||
for(int i = 1; i < lines.length; ++i)
|
||||
raw.add(new BenchmarkEntry(lines[i]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BenchmarkLog.warn("No " + extension + " files where found in " + directory);
|
||||
}
|
||||
}
|
||||
|
||||
long end = Instant.now().toEpochMilli();
|
||||
BenchmarkLog.log("Rebuilt data in " + (end - start) + "ms");
|
||||
}
|
||||
|
||||
// Re-evaluates and re-orders the input list based on the Levenshtein distance of the
|
||||
// original search and the contents of the provided list of benchmark entries.
|
||||
public List<BenchmarkEntry> evaluateLevenshteinDistance(List<BenchmarkEntry> entries, String search)
|
||||
{
|
||||
// Populate cost list with heuristic results
|
||||
List<Pair<BenchmarkEntry, Integer>> cost = new ArrayList<Pair<BenchmarkEntry, Integer>>();
|
||||
int bestSoFar = Integer.MAX_VALUE;
|
||||
for(int i = 0; i < entries.size(); ++i)
|
||||
{
|
||||
BenchmarkEntry entry = entries.get(i);
|
||||
String entryString = entry.brand + " " + entry.model;
|
||||
|
||||
int heuristic = levenshteinHeuristic(entryString, search, bestSoFar);
|
||||
if(heuristic < bestSoFar)
|
||||
bestSoFar = heuristic;
|
||||
|
||||
cost.add(new Pair<BenchmarkEntry, Integer>(entry, heuristic));
|
||||
}
|
||||
|
||||
// Sort list
|
||||
Collections.sort(cost, (i1, i2) -> i1.Second.compareTo(i2.Second));
|
||||
|
||||
// Build new output list
|
||||
List<BenchmarkEntry> sortedEntries = new ArrayList<BenchmarkEntry>();
|
||||
for(int i = 0; i < cost.size(); ++i)
|
||||
sortedEntries.add(cost.get(i).First);
|
||||
|
||||
return sortedEntries;
|
||||
}
|
||||
|
||||
// Finds the minimum integer in an array of ints and returns it.
|
||||
private int min(int[] arr)
|
||||
{
|
||||
int min = Integer.MAX_VALUE;
|
||||
for(int i = 0; i < arr.length; ++i)
|
||||
{
|
||||
if(arr[i] < min)
|
||||
min = arr[i];
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
// Returns cost based on distance of characters from string. This is a kinda sloppy way
|
||||
// to do it, but because I keep tabs on the best result so far, it could be much worse.
|
||||
// Still chucks a lot - a non-recursive result w/ memoization would be best but this will do.
|
||||
private int levenshteinHeuristic(String str1, String str2, int bestSoFar)
|
||||
{
|
||||
int cost;
|
||||
|
||||
if(str1.length() <= 0)
|
||||
return str2.length();
|
||||
|
||||
if(str2.length() <= 0)
|
||||
return str1.length();
|
||||
|
||||
if(str1.charAt(0) == str2.charAt(0))
|
||||
cost = 0;
|
||||
else
|
||||
cost = 1;
|
||||
|
||||
int distance = Math.abs(str1.length() - str2.length());
|
||||
if(distance > bestSoFar)
|
||||
return distance;
|
||||
|
||||
int s1 = levenshteinHeuristic(str1.substring(1), str2, bestSoFar) + 1;
|
||||
int s2 = levenshteinHeuristic(str1, str2.substring(1), bestSoFar) + 1;
|
||||
int s3 = levenshteinHeuristic(str1.substring(1), str2.substring(1), bestSoFar) + cost;
|
||||
|
||||
return min(new int[] {s1, s2, s3 });
|
||||
}
|
||||
|
||||
// Search for a substring in the model name
|
||||
public List<BenchmarkEntry> findModel(String modelSubstr)
|
||||
{
|
||||
long start = Instant.now().toEpochMilli();
|
||||
List<BenchmarkEntry> matching = new ArrayList<BenchmarkEntry>();
|
||||
String searchSubstr = modelSubstr.toLowerCase();
|
||||
|
||||
for(BenchmarkEntry e : raw)
|
||||
{
|
||||
String model = e.model.toLowerCase().trim();
|
||||
|
||||
if(model.contains(searchSubstr))
|
||||
matching.add(e);
|
||||
}
|
||||
|
||||
BenchmarkLog.log("Searched for '" + searchSubstr + "' for "+ (Instant.now().toEpochMilli() - start) + "ms and found " + matching.size() + " entries.");
|
||||
return matching;
|
||||
}
|
||||
|
||||
// Keeps tabs on any changes of the files.
|
||||
public void update()
|
||||
{
|
||||
needsUpdate = false;
|
||||
directoryMonitor.update(this::onRescan, this::onRescan, this::onRescan);
|
||||
|
||||
if(needsUpdate)
|
||||
rebuildLookup();
|
||||
}
|
||||
|
||||
// When a file is changed, handle it.
|
||||
private void onRescan(MonitoredFile file)
|
||||
{
|
||||
// For now, all we need is to note that something was adjusted.
|
||||
if(file.path.toString().contains(extension))
|
||||
{
|
||||
BenchmarkLog.log("File status changed: " + file.path);
|
||||
needsUpdate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package commands.benchmark.core;
|
||||
|
||||
public enum BenchmarkType
|
||||
{
|
||||
CPU(0), GPU(1), SSD(2), HDD(4), RAM(8), USB(16);
|
||||
|
||||
private final int value;
|
||||
private BenchmarkType(int value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user