From 12db25e726bae373dc2eec3870120912ec50688f Mon Sep 17 00:00:00 2001 From: simon Date: Sat, 18 Nov 2017 22:23:32 -0500 Subject: [PATCH] Changed byte array in Memory to char array (+60% performance improvement) --- .../src/net/simon987/cubotplugin/Cubot.java | 9 ++- .../cubotplugin/CubotFloppyDrive.java | 4 +- .../net/simon987/cubotplugin/FloppyDisk.java | 6 +- .../server/assembly/AssemblyResult.java | 20 ++++- .../net/simon987/server/assembly/Memory.java | 75 +++++++++++-------- .../simon987/server/game/GameUniverse.java | 7 +- .../server/webserver/CodeUploadHandler.java | 6 +- .../server/webserver/FloppyHandler.java | 10 ++- .../simon987/server/assembly/MemoryTest.java | 14 ++-- .../instruction/AddInstructionTest.java | 6 +- 10 files changed, 102 insertions(+), 55 deletions(-) diff --git a/Plugin Cubot/src/net/simon987/cubotplugin/Cubot.java b/Plugin Cubot/src/net/simon987/cubotplugin/Cubot.java index e6a87c6..0fb9890 100644 --- a/Plugin Cubot/src/net/simon987/cubotplugin/Cubot.java +++ b/Plugin Cubot/src/net/simon987/cubotplugin/Cubot.java @@ -187,6 +187,13 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit { @Override 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; + } } } diff --git a/Plugin Cubot/src/net/simon987/cubotplugin/CubotFloppyDrive.java b/Plugin Cubot/src/net/simon987/cubotplugin/CubotFloppyDrive.java index 4e4c656..efa609e 100644 --- a/Plugin Cubot/src/net/simon987/cubotplugin/CubotFloppyDrive.java +++ b/Plugin Cubot/src/net/simon987/cubotplugin/CubotFloppyDrive.java @@ -23,6 +23,8 @@ public class CubotFloppyDrive extends CpuHardware { public CubotFloppyDrive(Cubot cubot) { this.cubot = cubot; + + floppyDisk = new FloppyDisk(); } @Override @@ -94,8 +96,6 @@ public class CubotFloppyDrive extends CpuHardware { if (hwJSON.containsKey("floppy")) { drive.floppyDisk = FloppyDisk.deserialise((JSONObject) hwJSON.get("floppy")); - } else { - drive.floppyDisk = new FloppyDisk(); } return drive; diff --git a/Plugin Cubot/src/net/simon987/cubotplugin/FloppyDisk.java b/Plugin Cubot/src/net/simon987/cubotplugin/FloppyDisk.java index 0b54718..b13abdd 100644 --- a/Plugin Cubot/src/net/simon987/cubotplugin/FloppyDisk.java +++ b/Plugin Cubot/src/net/simon987/cubotplugin/FloppyDisk.java @@ -25,7 +25,7 @@ public class FloppyDisk implements JSONSerialisable { 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) { if (sector <= 1440) { - cpuMemory.write(ramAddress, memory.getBytes(), sector * 1024, 1024); + cpuMemory.write(ramAddress, memory.getWords(), sector * 512, 512); //Calculate seek time int deltaTrack = (sector / 80) - rwHeadTrack; @@ -66,7 +66,7 @@ public class FloppyDisk implements JSONSerialisable { public boolean writeSector(int sector, Memory cpuMemory, int ramAddress) { if (sector <= 1440) { - memory.write(sector * 512, cpuMemory.getBytes(), ramAddress * 2, 1024); + memory.write(sector * 512, cpuMemory.getWords(), ramAddress, 512); //Calculate seek time int deltaTrack = (sector / 80) - rwHeadTrack; diff --git a/Server/src/net/simon987/server/assembly/AssemblyResult.java b/Server/src/net/simon987/server/assembly/AssemblyResult.java index 9cc8f97..bc0a0ce 100755 --- a/Server/src/net/simon987/server/assembly/AssemblyResult.java +++ b/Server/src/net/simon987/server/assembly/AssemblyResult.java @@ -5,6 +5,8 @@ import net.simon987.server.assembly.exception.AssemblyException; import net.simon987.server.assembly.exception.DuplicateSegmentException; import net.simon987.server.logging.LogManager; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.util.ArrayList; import java.util.HashMap; @@ -30,7 +32,7 @@ public class AssemblyResult { /** * Offset of the code segment */ - public int codeSegmentOffset; + private int codeSegmentOffset; /** * 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; + } + } + } diff --git a/Server/src/net/simon987/server/assembly/Memory.java b/Server/src/net/simon987/server/assembly/Memory.java index ef12420..2f91889 100755 --- a/Server/src/net/simon987/server/assembly/Memory.java +++ b/Server/src/net/simon987/server/assembly/Memory.java @@ -1,12 +1,15 @@ package net.simon987.server.assembly; +import net.simon987.server.GameServer; import net.simon987.server.io.JSONSerialisable; import net.simon987.server.logging.LogManager; import org.json.simple.JSONObject; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.util.Arrays; import java.util.Base64; import java.util.zip.Deflater; @@ -23,7 +26,7 @@ public class Memory implements Target, JSONSerialisable { /** * Contents of the memory */ - private byte[] bytes; + private char[] words; /** * Create an empty Memory object @@ -31,7 +34,7 @@ public class Memory implements Target, JSONSerialisable { * @param size Size of the memory, in words */ public Memory(int size) { - bytes = new byte[size]; + words = new char[size]; } /** @@ -42,29 +45,26 @@ public class Memory implements Target, JSONSerialisable { */ @Override 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); return 0; } - return ((bytes[address] & 0xFF) << 8) | (bytes[address + 1] & 0xFF); + return words[address]; } /** * 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.bytes.length || srcOffset >= bytes.length || count < 0 || offset < 0) { + if (offset + count > this.words.length || srcOffset >= src.length || count < 0 || offset < 0) { return false; } - System.arraycopy(bytes, srcOffset, this.bytes, offset, count); + System.arraycopy(src, srcOffset, this.words, offset, count); return true; } @@ -76,30 +76,31 @@ public class Memory implements Target, JSONSerialisable { */ @Override public void set(int address, int value) { + address = (char) address; - address = (char)address * 2; - - - if (address + 2 > bytes.length) { + if (address >= words.length) { LogManager.LOGGER.info("DEBUG: Trying to set memory out of bounds: " + address); return; } - bytes[address] = (byte) ((value >> 8)); - bytes[address + 1] = (byte) (value & 0xFF); + words[address] = (char) value; } /** * Fill the memory with 0s */ public void clear() { - Arrays.fill(bytes, (byte) 0); + Arrays.fill(words, (char) 0); } /** * Get byte array of the Memory object */ public byte[] getBytes() { + + byte[] bytes = new byte[words.length * 2]; + ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).asCharBuffer().put(words); + return bytes; } @@ -112,7 +113,7 @@ public class Memory implements Target, JSONSerialisable { ByteArrayOutputStream stream = new ByteArrayOutputStream(); Deflater compressor = new Deflater(Deflater.BEST_COMPRESSION, true); DeflaterOutputStream deflaterOutputStream = new DeflaterOutputStream(stream, compressor); - deflaterOutputStream.write(bytes); + deflaterOutputStream.write(getBytes()); deflaterOutputStream.close(); byte[] compressedBytes = stream.toByteArray(); @@ -128,25 +129,39 @@ public class Memory implements Target, JSONSerialisable { public static Memory deserialize(JSONObject json){ Memory memory = new Memory(0); - byte[] compressedBytes = Base64.getDecoder().decode((String)json.get("zipBytes")); - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - Inflater decompressor = new Inflater(true); - InflaterOutputStream inflaterOutputStream = new InflaterOutputStream(baos, decompressor); - inflaterOutputStream.write(compressedBytes); - inflaterOutputStream.close(); + String zipBytesStr = (String) json.get("zipBytes"); - memory.bytes = baos.toByteArray(); + if (zipBytesStr != null) { + byte[] compressedBytes = Base64.getDecoder().decode((String) json.get("zipBytes")); - } catch (IOException e) { - e.printStackTrace(); + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Inflater decompressor = new Inflater(true); + InflaterOutputStream inflaterOutputStream = new InflaterOutputStream(baos, decompressor); + inflaterOutputStream.write(compressedBytes); + inflaterOutputStream.close(); + + memory.setBytes(baos.toByteArray()); + + } catch (IOException e) { + e.printStackTrace(); + } + } else { + LogManager.LOGGER.severe("Memory was manually deleted"); + memory = new Memory(GameServer.INSTANCE.getConfig().getInt("memory_size")); } + return memory; } 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; } } diff --git a/Server/src/net/simon987/server/game/GameUniverse.java b/Server/src/net/simon987/server/game/GameUniverse.java index bf5c39f..9767f6e 100644 --- a/Server/src/net/simon987/server/game/GameUniverse.java +++ b/Server/src/net/simon987/server/game/GameUniverse.java @@ -113,10 +113,11 @@ public class GameUniverse implements JSONSerialisable{ user.getCpu().getMemory().clear(); //Write assembled code to mem - user.getCpu().getMemory().write((short) ar.origin, ar.bytes, 0, ar.bytes.length); - user.getCpu().setCodeSegmentOffset(ar.codeSegmentOffset); + char[] assembledCode = ar.getWords(); + + user.getCpu().getMemory().write((char) ar.origin, assembledCode, 0, assembledCode.length); + user.getCpu().setCodeSegmentOffset(ar.getCodeSegmentOffset()); - //Init } else { user = new User(null); diff --git a/Server/src/net/simon987/server/webserver/CodeUploadHandler.java b/Server/src/net/simon987/server/webserver/CodeUploadHandler.java index 8cec247..2898ad6 100644 --- a/Server/src/net/simon987/server/webserver/CodeUploadHandler.java +++ b/Server/src/net/simon987/server/webserver/CodeUploadHandler.java @@ -28,8 +28,10 @@ public class CodeUploadHandler implements MessageHandler { user.getUser().getCpu().getMemory().clear(); //Write assembled code to mem - user.getUser().getCpu().getMemory().write((char) ar.origin, ar.bytes, 0, ar.bytes.length); - user.getUser().getCpu().setCodeSegmentOffset(ar.codeSegmentOffset); + char[] assembledCode = ar.getWords(); + + user.getUser().getCpu().getMemory().write((char) ar.origin, assembledCode, 0, assembledCode.length); + user.getUser().getCpu().setCodeSegmentOffset(ar.getCodeSegmentOffset()); JSONObject response = new JSONObject(); response.put("t", "codeResponse"); diff --git a/Server/src/net/simon987/server/webserver/FloppyHandler.java b/Server/src/net/simon987/server/webserver/FloppyHandler.java index f6d8d03..115d929 100644 --- a/Server/src/net/simon987/server/webserver/FloppyHandler.java +++ b/Server/src/net/simon987/server/webserver/FloppyHandler.java @@ -15,11 +15,15 @@ public class FloppyHandler implements MessageHandler { LogManager.LOGGER.info("(WS) Floppy download request from " + user.getUser().getUsername()); + if (user.isGuest()) { + return; + } - //floppy - byte[] bytes = user.getUser().getControlledUnit().getFloppyData().getBytes(); + if (user.getUser().getControlledUnit().getFloppyData() != null) { + byte[] bytes = user.getUser().getControlledUnit().getFloppyData().getBytes(); + user.getWebSocket().send(bytes); + } - user.getWebSocket().send(bytes); } else if (json.get("t").equals("floppyUp")) { diff --git a/Server/test/net/simon987/server/assembly/MemoryTest.java b/Server/test/net/simon987/server/assembly/MemoryTest.java index 22b1877..ea2bdf9 100644 --- a/Server/test/net/simon987/server/assembly/MemoryTest.java +++ b/Server/test/net/simon987/server/assembly/MemoryTest.java @@ -36,14 +36,14 @@ public class MemoryTest { Memory memory = new Memory(memorySize); - assertTrue(memory.write(0, new byte[memorySize], 0, memorySize)); - assertFalse(memory.write(0, new byte[memorySize], 0, memorySize + 1)); - assertFalse(memory.write(0, new byte[memorySize], 0, -1)); - assertFalse(memory.write(-1, new byte[memorySize], 0, 10)); + assertTrue(memory.write(0, new char[memorySize], 0, memorySize)); + assertFalse(memory.write(0, new char[memorySize], 0, memorySize + 1)); + assertFalse(memory.write(0, new char[memorySize], 0, -1)); + assertFalse(memory.write(-1, new char[memorySize], 0, 10)); - assertFalse(memory.write(memorySize / 2, new byte[15], 0, 1)); - assertFalse(memory.write((memorySize / 2) - 5, new byte[11], 0, 11)); - assertTrue(memory.write((memorySize / 2) - 5, new byte[11], 0, 10)); + assertFalse(memory.write(memorySize, new char[15], 0, 1)); + assertFalse(memory.write((memorySize) - 5, new char[11], 0, 6)); + assertTrue(memory.write((memorySize) - 5, new char[11], 0, 5)); } diff --git a/Server/test/net/simon987/server/assembly/instruction/AddInstructionTest.java b/Server/test/net/simon987/server/assembly/instruction/AddInstructionTest.java index e0a89df..2195ece 100644 --- a/Server/test/net/simon987/server/assembly/instruction/AddInstructionTest.java +++ b/Server/test/net/simon987/server/assembly/instruction/AddInstructionTest.java @@ -55,10 +55,10 @@ public class AddInstructionTest { assertFalse(status.isBreakFlag()); memory.clear(); - memory.set(memorySize, 10); + memory.set(memorySize - 1, 10); memory.set(1, 10); - addInstruction.execute(memory, memorySize, memory, 1, status); - assertEquals(20, memory.get(memorySize)); + addInstruction.execute(memory, memorySize - 1, memory, 1, status); + assertEquals(20, memory.get(memorySize - 1)); assertEquals(10, memory.get(1)); //FLAGS Should be CF=0 ZF=0 SF=0 OF=0 assertFalse(status.isSignFlag());