Changed byte array in Memory to char array (+60% performance improvement)

This commit is contained in:
simon 2017-11-18 22:23:32 -05:00
parent d004386b7b
commit 12db25e726
10 changed files with 102 additions and 55 deletions

View File

@ -187,6 +187,13 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit {
@Override @Override
public Memory getFloppyData() { public Memory getFloppyData() {
return ((CubotFloppyDrive) getParent().getCpu().getHardware(CubotFloppyDrive.DEFAULT_ADDRESS)).getFloppy().getMemory();
CubotFloppyDrive drive = ((CubotFloppyDrive) getParent().getCpu().getHardware(CubotFloppyDrive.DEFAULT_ADDRESS));
if (drive.getFloppy() != null) {
return drive.getFloppy().getMemory();
} else {
return null;
}
} }
} }

View File

@ -23,6 +23,8 @@ public class CubotFloppyDrive extends CpuHardware {
public CubotFloppyDrive(Cubot cubot) { public CubotFloppyDrive(Cubot cubot) {
this.cubot = cubot; this.cubot = cubot;
floppyDisk = new FloppyDisk();
} }
@Override @Override
@ -94,8 +96,6 @@ public class CubotFloppyDrive extends CpuHardware {
if (hwJSON.containsKey("floppy")) { if (hwJSON.containsKey("floppy")) {
drive.floppyDisk = FloppyDisk.deserialise((JSONObject) hwJSON.get("floppy")); drive.floppyDisk = FloppyDisk.deserialise((JSONObject) hwJSON.get("floppy"));
} else {
drive.floppyDisk = new FloppyDisk();
} }
return drive; return drive;

View File

@ -25,7 +25,7 @@ public class FloppyDisk implements JSONSerialisable {
public FloppyDisk() { public FloppyDisk() {
this.memory = new Memory(1024 * 1440); this.memory = new Memory(512 * 1440);
} }
/** /**
@ -39,7 +39,7 @@ public class FloppyDisk implements JSONSerialisable {
public boolean readSector(int sector, Memory cpuMemory, int ramAddress) { public boolean readSector(int sector, Memory cpuMemory, int ramAddress) {
if (sector <= 1440) { if (sector <= 1440) {
cpuMemory.write(ramAddress, memory.getBytes(), sector * 1024, 1024); cpuMemory.write(ramAddress, memory.getWords(), sector * 512, 512);
//Calculate seek time //Calculate seek time
int deltaTrack = (sector / 80) - rwHeadTrack; int deltaTrack = (sector / 80) - rwHeadTrack;
@ -66,7 +66,7 @@ public class FloppyDisk implements JSONSerialisable {
public boolean writeSector(int sector, Memory cpuMemory, int ramAddress) { public boolean writeSector(int sector, Memory cpuMemory, int ramAddress) {
if (sector <= 1440) { if (sector <= 1440) {
memory.write(sector * 512, cpuMemory.getBytes(), ramAddress * 2, 1024); memory.write(sector * 512, cpuMemory.getWords(), ramAddress, 512);
//Calculate seek time //Calculate seek time
int deltaTrack = (sector / 80) - rwHeadTrack; int deltaTrack = (sector / 80) - rwHeadTrack;

View File

@ -5,6 +5,8 @@ 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 net.simon987.server.logging.LogManager;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -30,7 +32,7 @@ public class AssemblyResult {
/** /**
* Offset of the code segment * Offset of the code segment
*/ */
public int codeSegmentOffset; private int codeSegmentOffset;
/** /**
* Line of the code segment definition (for editor icons) * Line of the code segment definition (for editor icons)
*/ */
@ -104,4 +106,20 @@ public class AssemblyResult {
} }
public char[] getWords() {
char[] assembledCode = new char[bytes.length / 2];
ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).asCharBuffer().get(assembledCode);
return assembledCode;
}
public int getCodeSegmentOffset() {
if (codeSegmentSet) {
return codeSegmentOffset;
} else {
return origin;
}
}
} }

View File

@ -1,12 +1,15 @@
package net.simon987.server.assembly; package net.simon987.server.assembly;
import net.simon987.server.GameServer;
import net.simon987.server.io.JSONSerialisable; import net.simon987.server.io.JSONSerialisable;
import net.simon987.server.logging.LogManager; import net.simon987.server.logging.LogManager;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays; import java.util.Arrays;
import java.util.Base64; import java.util.Base64;
import java.util.zip.Deflater; import java.util.zip.Deflater;
@ -23,7 +26,7 @@ public class Memory implements Target, JSONSerialisable {
/** /**
* Contents of the memory * Contents of the memory
*/ */
private byte[] bytes; private char[] words;
/** /**
* Create an empty Memory object * Create an empty Memory object
@ -31,7 +34,7 @@ public class Memory implements Target, JSONSerialisable {
* @param size Size of the memory, in words * @param size Size of the memory, in words
*/ */
public Memory(int size) { public Memory(int size) {
bytes = new byte[size]; words = new char[size];
} }
/** /**
@ -42,29 +45,26 @@ public class Memory implements Target, JSONSerialisable {
*/ */
@Override @Override
public int get(int address) { public int get(int address) {
address = address * 2; //Because our Memory is only divisible by 16bits address = (char) address;
if (address + 2 > bytes.length) { if (address >= words.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 words[address];
} }
/** /**
* Write x words from an array at an offset * Write x words from an array at an offset
*/ */
public boolean write(int offset, byte[] bytes, int srcOffset, int count) { public boolean write(int offset, char[] src, int srcOffset, int count) {
offset = (char)offset * 2; if (offset + count > this.words.length || srcOffset >= src.length || count < 0 || offset < 0) {
if (offset + count > this.bytes.length || srcOffset >= bytes.length || count < 0 || offset < 0) {
return false; return false;
} }
System.arraycopy(bytes, srcOffset, this.bytes, offset, count); System.arraycopy(src, srcOffset, this.words, offset, count);
return true; return true;
} }
@ -76,30 +76,31 @@ public class Memory implements Target, JSONSerialisable {
*/ */
@Override @Override
public void set(int address, int value) { public void set(int address, int value) {
address = (char) address;
address = (char)address * 2; if (address >= words.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)); words[address] = (char) value;
bytes[address + 1] = (byte) (value & 0xFF);
} }
/** /**
* Fill the memory with 0s * Fill the memory with 0s
*/ */
public void clear() { public void clear() {
Arrays.fill(bytes, (byte) 0); Arrays.fill(words, (char) 0);
} }
/** /**
* Get byte array of the Memory object * Get byte array of the Memory object
*/ */
public byte[] getBytes() { public byte[] getBytes() {
byte[] bytes = new byte[words.length * 2];
ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).asCharBuffer().put(words);
return bytes; return bytes;
} }
@ -112,7 +113,7 @@ public class Memory implements Target, JSONSerialisable {
ByteArrayOutputStream stream = new ByteArrayOutputStream(); ByteArrayOutputStream stream = new ByteArrayOutputStream();
Deflater compressor = new Deflater(Deflater.BEST_COMPRESSION, true); Deflater compressor = new Deflater(Deflater.BEST_COMPRESSION, true);
DeflaterOutputStream deflaterOutputStream = new DeflaterOutputStream(stream, compressor); DeflaterOutputStream deflaterOutputStream = new DeflaterOutputStream(stream, compressor);
deflaterOutputStream.write(bytes); deflaterOutputStream.write(getBytes());
deflaterOutputStream.close(); deflaterOutputStream.close();
byte[] compressedBytes = stream.toByteArray(); byte[] compressedBytes = stream.toByteArray();
@ -128,7 +129,11 @@ public class Memory implements Target, JSONSerialisable {
public static Memory deserialize(JSONObject json){ public static Memory deserialize(JSONObject json){
Memory memory = new Memory(0); Memory memory = new Memory(0);
byte[] compressedBytes = Base64.getDecoder().decode((String)json.get("zipBytes"));
String zipBytesStr = (String) json.get("zipBytes");
if (zipBytesStr != null) {
byte[] compressedBytes = Base64.getDecoder().decode((String) json.get("zipBytes"));
try { try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
@ -137,16 +142,26 @@ public class Memory implements Target, JSONSerialisable {
inflaterOutputStream.write(compressedBytes); inflaterOutputStream.write(compressedBytes);
inflaterOutputStream.close(); inflaterOutputStream.close();
memory.bytes = baos.toByteArray(); memory.setBytes(baos.toByteArray());
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
} else {
LogManager.LOGGER.severe("Memory was manually deleted");
memory = new Memory(GameServer.INSTANCE.getConfig().getInt("memory_size"));
}
return memory; return memory;
} }
public void setBytes(byte[] bytes) { public void setBytes(byte[] bytes) {
this.bytes = bytes; this.words = new char[bytes.length / 2];
ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).asCharBuffer().get(this.words);
}
public char[] getWords() {
return words;
} }
} }

View File

@ -113,10 +113,11 @@ public class GameUniverse implements JSONSerialisable{
user.getCpu().getMemory().clear(); user.getCpu().getMemory().clear();
//Write assembled code to mem //Write assembled code to mem
user.getCpu().getMemory().write((short) ar.origin, ar.bytes, 0, ar.bytes.length); char[] assembledCode = ar.getWords();
user.getCpu().setCodeSegmentOffset(ar.codeSegmentOffset);
user.getCpu().getMemory().write((char) ar.origin, assembledCode, 0, assembledCode.length);
user.getCpu().setCodeSegmentOffset(ar.getCodeSegmentOffset());
//Init
} else { } else {
user = new User(null); user = new User(null);

View File

@ -28,8 +28,10 @@ public class CodeUploadHandler implements MessageHandler {
user.getUser().getCpu().getMemory().clear(); user.getUser().getCpu().getMemory().clear();
//Write assembled code to mem //Write assembled code to mem
user.getUser().getCpu().getMemory().write((char) ar.origin, ar.bytes, 0, ar.bytes.length); char[] assembledCode = ar.getWords();
user.getUser().getCpu().setCodeSegmentOffset(ar.codeSegmentOffset);
user.getUser().getCpu().getMemory().write((char) ar.origin, assembledCode, 0, assembledCode.length);
user.getUser().getCpu().setCodeSegmentOffset(ar.getCodeSegmentOffset());
JSONObject response = new JSONObject(); JSONObject response = new JSONObject();
response.put("t", "codeResponse"); response.put("t", "codeResponse");

View File

@ -15,11 +15,15 @@ public class FloppyHandler implements MessageHandler {
LogManager.LOGGER.info("(WS) Floppy download request from " + user.getUser().getUsername()); LogManager.LOGGER.info("(WS) Floppy download request from " + user.getUser().getUsername());
if (user.isGuest()) {
return;
}
//floppy if (user.getUser().getControlledUnit().getFloppyData() != null) {
byte[] bytes = user.getUser().getControlledUnit().getFloppyData().getBytes(); byte[] bytes = user.getUser().getControlledUnit().getFloppyData().getBytes();
user.getWebSocket().send(bytes); user.getWebSocket().send(bytes);
}
} else if (json.get("t").equals("floppyUp")) { } else if (json.get("t").equals("floppyUp")) {

View File

@ -36,14 +36,14 @@ public class MemoryTest {
Memory memory = new Memory(memorySize); Memory memory = new Memory(memorySize);
assertTrue(memory.write(0, new byte[memorySize], 0, memorySize)); assertTrue(memory.write(0, new char[memorySize], 0, memorySize));
assertFalse(memory.write(0, new byte[memorySize], 0, memorySize + 1)); assertFalse(memory.write(0, new char[memorySize], 0, memorySize + 1));
assertFalse(memory.write(0, new byte[memorySize], 0, -1)); assertFalse(memory.write(0, new char[memorySize], 0, -1));
assertFalse(memory.write(-1, new byte[memorySize], 0, 10)); assertFalse(memory.write(-1, new char[memorySize], 0, 10));
assertFalse(memory.write(memorySize / 2, new byte[15], 0, 1)); assertFalse(memory.write(memorySize, new char[15], 0, 1));
assertFalse(memory.write((memorySize / 2) - 5, new byte[11], 0, 11)); assertFalse(memory.write((memorySize) - 5, new char[11], 0, 6));
assertTrue(memory.write((memorySize / 2) - 5, new byte[11], 0, 10)); assertTrue(memory.write((memorySize) - 5, new char[11], 0, 5));
} }

View File

@ -55,10 +55,10 @@ public class AddInstructionTest {
assertFalse(status.isBreakFlag()); assertFalse(status.isBreakFlag());
memory.clear(); memory.clear();
memory.set(memorySize, 10); memory.set(memorySize - 1, 10);
memory.set(1, 10); memory.set(1, 10);
addInstruction.execute(memory, memorySize, memory, 1, status); addInstruction.execute(memory, memorySize - 1, memory, 1, status);
assertEquals(20, memory.get(memorySize)); assertEquals(20, memory.get(memorySize - 1));
assertEquals(10, memory.get(1)); assertEquals(10, memory.get(1));
//FLAGS Should be CF=0 ZF=0 SF=0 OF=0 //FLAGS Should be CF=0 ZF=0 SF=0 OF=0
assertFalse(status.isSignFlag()); assertFalse(status.isSignFlag());