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

View File

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

View File

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

View File

@ -60,10 +60,11 @@ public class CPU implements JSONSerialisable{
private ServerConfiguration config;
private long timeout;
private int registerSetSize;
private static final char EXECUTION_COST_ADDR = 0x0300;
private static final char EXECUTED_INS_ADDR = 0x0301;
/**
* Creates a new CPU
*/
@ -74,8 +75,6 @@ public class CPU implements JSONSerialisable{
attachedHardware = new HashMap<>();
codeSegmentOffset = config.getInt("org_offset");
timeout = config.getInt("user_timeout");
instructionSet.add(new JmpInstruction(this));
instructionSet.add(new JnzInstruction(this));
instructionSet.add(new JzInstruction(this));
@ -116,7 +115,7 @@ public class CPU implements JSONSerialisable{
ip = codeSegmentOffset;
}
public void execute() {
public int execute(int timeout) {
long startTime = System.currentTimeMillis();
int counter = 0;
@ -128,10 +127,16 @@ public class CPU implements JSONSerialisable{
while (!status.isBreakFlag()) {
counter++;
if(counter % 1000 == 0){
if (counter % 10000 == 0) {
if (System.currentTimeMillis() >= (startTime + timeout)) {
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);
// 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");
//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) {

View File

@ -42,14 +42,14 @@ public class Memory implements Target, JSONSerialisable {
*/
@Override
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);
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;
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;
}
@ -80,12 +80,12 @@ public class Memory implements Target, JSONSerialisable {
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);
return;
}
bytes[address] = (byte) ((value >> 8) & 0xFF);
bytes[address] = (byte) ((value >> 8));
bytes[address + 1] = (byte) (value & 0xFF);
}

View File

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

View File

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

View File

@ -29,7 +29,7 @@ public class CodeUploadHandler implements MessageHandler {
//Write assembled code to mem
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();
response.put("t", "codeResponse");

View File

@ -60,4 +60,6 @@ wg_minCopperCount=0
wg_maxCopperCount=2
# ----------------------------------------------
# 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.