CPU execution time costs energy #16

This commit is contained in:
simon 2017-11-15 12:24:01 -05:00
parent 8701007ad9
commit c703dec3cf
10 changed files with 58 additions and 19 deletions

View File

@ -29,6 +29,8 @@ public class GameServer implements Runnable {
private SocketServer socketServer; private SocketServer socketServer;
private int maxExecutionTime;
public GameServer() { public GameServer() {
this.config = new ServerConfiguration(new File("config.properties")); this.config = new ServerConfiguration(new File("config.properties"));
@ -36,6 +38,8 @@ public class GameServer implements Runnable {
gameUniverse = new GameUniverse(config); gameUniverse = new GameUniverse(config);
pluginManager = new PluginManager(); pluginManager = new PluginManager();
maxExecutionTime = config.getInt("user_timeout");
//Load all plugins in plugins folder, if it doesn't exist, create it //Load all plugins in plugins folder, if it doesn't exist, create it
File pluginDir = new File("plugins/"); File pluginDir = new File("plugins/");
File[] pluginDirListing = pluginDir.listFiles(); File[] pluginDirListing = pluginDir.listFiles();
@ -109,8 +113,13 @@ public class GameServer implements Runnable {
if(user.getCpu() != null){ if(user.getCpu() != null){
try { try {
int timeout = Math.min(user.getControlledUnit().getEnergy(), maxExecutionTime);
user.getCpu().reset(); user.getCpu().reset();
user.getCpu().execute(); int cost = user.getCpu().execute(timeout);
user.getControlledUnit().spendEnergy(cost);
} catch (Exception e) { } catch (Exception e) {
LogManager.LOGGER.severe("Error executing " + user.getUsername() + "'s code"); LogManager.LOGGER.severe("Error executing " + user.getUsername() + "'s code");
e.printStackTrace(); e.printStackTrace();

View File

@ -253,6 +253,8 @@ public class Assembler {
} else if (tokens[0].toUpperCase().equals(".DATA")) { } else if (tokens[0].toUpperCase().equals(".DATA")) {
LogManager.LOGGER.fine("DEBUG: .data @" + currentLine);
result.defineSegment(Segment.DATA, currentLine, currentOffset); result.defineSegment(Segment.DATA, currentLine, currentOffset);
throw new PseudoInstructionException(currentLine); throw new PseudoInstructionException(currentLine);
} }

View File

@ -3,6 +3,7 @@ package net.simon987.server.assembly;
import net.simon987.server.ServerConfiguration; import net.simon987.server.ServerConfiguration;
import net.simon987.server.assembly.exception.AssemblyException; import net.simon987.server.assembly.exception.AssemblyException;
import net.simon987.server.assembly.exception.DuplicateSegmentException; import net.simon987.server.assembly.exception.DuplicateSegmentException;
import net.simon987.server.logging.LogManager;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -29,7 +30,7 @@ public class AssemblyResult {
/** /**
* Offset of the code segment * Offset of the code segment
*/ */
private int codeSegmentOffset; public int codeSegmentOffset;
/** /**
* Line of the code segment definition (for editor icons) * Line of the code segment definition (for editor icons)
*/ */
@ -77,6 +78,10 @@ public class AssemblyResult {
if (!codeSegmentSet) { if (!codeSegmentSet) {
codeSegmentOffset = origin + currentOffset; codeSegmentOffset = origin + currentOffset;
codeSegmentLine = currentLine; codeSegmentLine = currentLine;
LogManager.LOGGER.fine("DEBUG: .text offset @" + codeSegmentOffset);
codeSegmentSet = true; codeSegmentSet = true;
} else { } else {
throw new DuplicateSegmentException(currentLine); throw new DuplicateSegmentException(currentLine);
@ -87,6 +92,9 @@ public class AssemblyResult {
if (!dataSegmentSet) { if (!dataSegmentSet) {
dataSegmentOffset = origin + currentOffset; dataSegmentOffset = origin + currentOffset;
dataSegmentLine = currentLine; dataSegmentLine = currentLine;
LogManager.LOGGER.fine("DEBUG: .data offset @" + dataSegmentOffset);
dataSegmentSet = true; dataSegmentSet = true;
} else { } else {
throw new DuplicateSegmentException(currentLine); throw new DuplicateSegmentException(currentLine);

View File

@ -60,10 +60,11 @@ public class CPU implements JSONSerialisable{
private ServerConfiguration config; private ServerConfiguration config;
private long timeout;
private int registerSetSize; private int registerSetSize;
private static final char EXECUTION_COST_ADDR = 0x0300;
private static final char EXECUTED_INS_ADDR = 0x0301;
/** /**
* Creates a new CPU * Creates a new CPU
*/ */
@ -74,8 +75,6 @@ public class CPU implements JSONSerialisable{
attachedHardware = new HashMap<>(); attachedHardware = new HashMap<>();
codeSegmentOffset = config.getInt("org_offset"); codeSegmentOffset = config.getInt("org_offset");
timeout = config.getInt("user_timeout");
instructionSet.add(new JmpInstruction(this)); instructionSet.add(new JmpInstruction(this));
instructionSet.add(new JnzInstruction(this)); instructionSet.add(new JnzInstruction(this));
instructionSet.add(new JzInstruction(this)); instructionSet.add(new JzInstruction(this));
@ -116,7 +115,7 @@ public class CPU implements JSONSerialisable{
ip = codeSegmentOffset; ip = codeSegmentOffset;
} }
public void execute() { public int execute(int timeout) {
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
int counter = 0; int counter = 0;
@ -128,10 +127,16 @@ public class CPU implements JSONSerialisable{
while (!status.isBreakFlag()) { while (!status.isBreakFlag()) {
counter++; counter++;
if(counter % 1000 == 0){ if (counter % 10000 == 0) {
if (System.currentTimeMillis() >= (startTime + timeout)) { if (System.currentTimeMillis() >= (startTime + timeout)) {
LogManager.LOGGER.fine("CPU Timeout " + this + " after " + counter + "instructions (" + timeout + "ms): " + (double) counter / ((double) timeout / 1000) / 1000000 + "MHz"); LogManager.LOGGER.fine("CPU Timeout " + this + " after " + counter + "instructions (" + timeout + "ms): " + (double) counter / ((double) timeout / 1000) / 1000000 + "MHz");
return;
//Write execution cost and instruction count to memory
memory.set(EXECUTION_COST_ADDR, timeout);
memory.set(EXECUTED_INS_ADDR, Util.getHigherWord(counter));
memory.set(EXECUTED_INS_ADDR, Util.getLowerWord(counter));
return timeout;
} }
} }
@ -151,8 +156,17 @@ public class CPU implements JSONSerialisable{
executeInstruction(instruction, source, destination); executeInstruction(instruction, source, destination);
// LogManager.LOGGER.info(instruction.getMnemonic()); // LogManager.LOGGER.info(instruction.getMnemonic());
} }
double elapsed = (System.currentTimeMillis() - startTime); int elapsed = (int) (System.currentTimeMillis() - startTime);
LogManager.LOGGER.fine(counter + " instruction in " + elapsed + "ms : " + (double) counter / (elapsed / 1000) / 1000000 + "MHz"); LogManager.LOGGER.fine(counter + " instruction in " + elapsed + "ms : " + (double) counter / (elapsed / 1000) / 1000000 + "MHz");
//Write execution cost and instruction count to memory
memory.set(EXECUTION_COST_ADDR, elapsed);
memory.set(EXECUTED_INS_ADDR, Util.getHigherWord(counter));
memory.set(EXECUTED_INS_ADDR, Util.getLowerWord(counter));
return elapsed;
} }
public void executeInstruction(Instruction instruction, int source, int destination) { public void executeInstruction(Instruction instruction, int source, int destination) {

View File

@ -42,14 +42,14 @@ public class Memory implements Target, JSONSerialisable {
*/ */
@Override @Override
public int get(int address) { public int get(int address) {
address = (char)address * 2; //Because our Memory is only divisible by 16bits address = address * 2; //Because our Memory is only divisible by 16bits
if (address < 0 || address + 2 > bytes.length) { if (address + 2 > bytes.length) {
LogManager.LOGGER.info("DEBUG: Trying to get memory out of bounds " + address); LogManager.LOGGER.info("DEBUG: Trying to get memory out of bounds " + address);
return 0; return 0;
} }
return (((bytes[address] & 0xFF) << 8) | (bytes[address + 1] & 0xFF)); return ((bytes[address] & 0xFF) << 8) | (bytes[address + 1] & 0xFF);
} }
/** /**
@ -60,7 +60,7 @@ public class Memory implements Target, JSONSerialisable {
offset = (char)offset * 2; offset = (char)offset * 2;
if (offset + count > this.bytes.length || count < 0 || offset < 0 || srcOffset >= bytes.length) { if (offset + count > this.bytes.length || srcOffset >= bytes.length || count < 0 || offset < 0) {
return false; return false;
} }
@ -80,12 +80,12 @@ public class Memory implements Target, JSONSerialisable {
address = (char)address * 2; address = (char)address * 2;
if (address < 0 || address + 2 > bytes.length) { if (address + 2 > bytes.length) {
LogManager.LOGGER.info("DEBUG: Trying to set memory out of bounds: " + address); LogManager.LOGGER.info("DEBUG: Trying to set memory out of bounds: " + address);
return; return;
} }
bytes[address] = (byte) ((value >> 8) & 0xFF); bytes[address] = (byte) ((value >> 8));
bytes[address + 1] = (byte) (value & 0xFF); bytes[address + 1] = (byte) (value & 0xFF);
} }

View File

@ -17,4 +17,8 @@ public interface ControllableUnit {
Memory getFloppyData(); Memory getFloppyData();
boolean spendEnergy(int energy);
int getEnergy();
} }

View File

@ -114,7 +114,7 @@ public class GameUniverse implements JSONSerialisable{
//Write assembled code to mem //Write assembled code to mem
user.getCpu().getMemory().write((short) ar.origin, ar.bytes, 0, ar.bytes.length); user.getCpu().getMemory().write((short) ar.origin, ar.bytes, 0, ar.bytes.length);
user.getCpu().setCodeSegmentOffset(ar.origin); user.getCpu().setCodeSegmentOffset(ar.codeSegmentOffset);
//Init //Init

View File

@ -29,7 +29,7 @@ public class CodeUploadHandler implements MessageHandler {
//Write assembled code to mem //Write assembled code to mem
user.getUser().getCpu().getMemory().write((char) ar.origin, ar.bytes, 0, ar.bytes.length); user.getUser().getCpu().getMemory().write((char) ar.origin, ar.bytes, 0, ar.bytes.length);
user.getUser().getCpu().setCodeSegmentOffset(ar.origin); user.getUser().getCpu().setCodeSegmentOffset(ar.codeSegmentOffset);
JSONObject response = new JSONObject(); JSONObject response = new JSONObject();
response.put("t", "codeResponse"); response.put("t", "codeResponse");

View File

@ -60,4 +60,6 @@ wg_minCopperCount=0
wg_maxCopperCount=2 wg_maxCopperCount=2
# ---------------------------------------------- # ----------------------------------------------
# Maximum execution time of user code in ms # Maximum execution time of user code in ms
user_timeout=40 user_timeout=500
# Free CPU execution time in ms
user_free_execution_time=2

Binary file not shown.