Optimizations aswell as the option to disable section verification

This commit is contained in:
mcrcortex
2024-08-07 00:06:02 +10:00
parent ee5bca7db5
commit 6eed71656d
6 changed files with 69 additions and 46 deletions

View File

@@ -20,20 +20,17 @@ public class ZSTDCompressor implements StorageCompressor {
} }
@Override @Override
public ByteBuffer compress(ByteBuffer saveData) { public MemoryBuffer compress(MemoryBuffer saveData) {
ByteBuffer compressedData = MemoryUtil.memAlloc((int)ZSTD_COMPRESSBOUND(saveData.remaining())); MemoryBuffer compressedData = new MemoryBuffer((int)ZSTD_COMPRESSBOUND(saveData.size));
long compressedSize = ZSTD_compress(compressedData, saveData, this.level); long compressedSize = nZSTD_compress(compressedData.address, compressedData.size, saveData.address, saveData.size, this.level);
compressedData.limit((int) compressedSize); return compressedData.subSize(compressedSize);
compressedData.rewind();
return compressedData;
} }
@Override @Override
public MemoryBuffer decompress(MemoryBuffer saveData) { public MemoryBuffer decompress(MemoryBuffer saveData) {
var decompressed = new MemoryBuffer(SaveLoadSystem.BIGGEST_SERIALIZED_SECTION_SIZE); var decompressed = new MemoryBuffer(SaveLoadSystem.BIGGEST_SERIALIZED_SECTION_SIZE);
//TODO: mark the size of the decompressed data to verify its length later
long size = nZSTD_decompress(decompressed.address, decompressed.size, saveData.address, saveData.size); long size = nZSTD_decompress(decompressed.address, decompressed.size, saveData.address, saveData.size);
return decompressed; return decompressed.subSize(size);
} }
@Override @Override

View File

@@ -11,6 +11,11 @@ public class MemoryBuffer extends TrackedObject {
this.address = MemoryUtil.nmemAlloc(size); this.address = MemoryUtil.nmemAlloc(size);
} }
private MemoryBuffer(long address, long size) {
this.size = size;
this.address = address;
}
public void cpyTo(long dst) { public void cpyTo(long dst) {
super.assertNotFreed(); super.assertNotFreed();
UnsafeUtil.memcpy(this.address, dst, this.size); UnsafeUtil.memcpy(this.address, dst, this.size);
@@ -27,4 +32,15 @@ public class MemoryBuffer extends TrackedObject {
this.cpyTo(copy.address); this.cpyTo(copy.address);
return copy; return copy;
} }
//Creates a new MemoryBuffer, defunking this buffer and sets the size to be a subsize of the current size
public MemoryBuffer subSize(long size) {
if (size > this.size) {
throw new IllegalArgumentException("Requested size larger than current size");
}
//Free the current object, but not the memory associated with it
super.free0();
return new MemoryBuffer(this.address, size);
}
} }

View File

@@ -8,8 +8,12 @@ public abstract class TrackedObject {
public static final boolean TRACK_OBJECT_ALLOCATION_STACKS = System.getProperty("voxy.trackObjectAllocationStacks", "false").equals("true"); public static final boolean TRACK_OBJECT_ALLOCATION_STACKS = System.getProperty("voxy.trackObjectAllocationStacks", "false").equals("true");
private final Ref ref; private final Ref ref;
public TrackedObject() { protected TrackedObject() {
this.ref = register(this); this(true);
}
protected TrackedObject(boolean shouldTrack) {
this.ref = register(shouldTrack, this);
} }
protected void free0() { protected void free0() {
@@ -44,10 +48,10 @@ public abstract class TrackedObject {
cleaner = null; cleaner = null;
} }
} }
public static Ref register(Object obj) { public static Ref register(boolean track, Object obj) {
boolean[] freed = new boolean[1]; boolean[] freed = new boolean[1];
Cleaner.Cleanable cleanable = null; Cleaner.Cleanable cleanable = null;
if (TRACK_OBJECT_ALLOCATIONS) { if (TRACK_OBJECT_ALLOCATIONS && track) {
String clazz = obj.getClass().getName(); String clazz = obj.getClass().getName();
Throwable trace; Throwable trace;
if (TRACK_OBJECT_ALLOCATION_STACKS) { if (TRACK_OBJECT_ALLOCATION_STACKS) {

View File

@@ -15,6 +15,7 @@ public class UnsafeUtil {
} }
private static final long BYTE_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(byte[].class); private static final long BYTE_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(byte[].class);
private static final long SHORT_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(short[].class);
public static void memcpy(long src, long dst, long length) { public static void memcpy(long src, long dst, long length) {
UNSAFE.copyMemory(src, dst, length); UNSAFE.copyMemory(src, dst, length);
@@ -31,6 +32,9 @@ public class UnsafeUtil {
public static void memcpy(byte[] src, long dst) { public static void memcpy(byte[] src, long dst) {
UNSAFE.copyMemory(src, BYTE_ARRAY_BASE_OFFSET, null, dst, src.length); UNSAFE.copyMemory(src, BYTE_ARRAY_BASE_OFFSET, null, dst, src.length);
} }
public static void memcpy(short[] src, long dst) {
UNSAFE.copyMemory(src, SHORT_ARRAY_BASE_OFFSET, null, dst, (long) src.length <<1);
}
} }

View File

@@ -11,6 +11,7 @@ import java.nio.ByteBuffer;
import static org.lwjgl.util.zstd.Zstd.*; import static org.lwjgl.util.zstd.Zstd.*;
public class SaveLoadSystem { public class SaveLoadSystem {
public static final boolean VERIFY_HASH_ON_LOAD = System.getProperty("voxy.verifySectionOnLoad", "true").equals("true");
public static final int BIGGEST_SERIALIZED_SECTION_SIZE = 32 * 32 * 32 * 8 * 2; public static final int BIGGEST_SERIALIZED_SECTION_SIZE = 32 * 32 * 32 * 8 * 2;
public static int lin2z(int i) { public static int lin2z(int i) {
@@ -47,46 +48,46 @@ public class SaveLoadSystem {
pHash ^= block; pHash ^= block;
} }
long[] lut = LUTVAL.toLongArray(); long[] lut = LUTVAL.toLongArray();
ByteBuffer raw = MemoryUtil.memAlloc(compressed.length*2+lut.length*8+512); MemoryBuffer raw = new MemoryBuffer(compressed.length*2L+lut.length*8L+512);
long ptr = raw.address;
long hash = section.key^(lut.length*1293481298141L); long hash = section.key^(lut.length*1293481298141L);
raw.putLong(section.key); MemoryUtil.memPutLong(ptr, section.key); ptr += 8;
raw.putInt(lut.length); MemoryUtil.memPutInt(ptr, lut.length); ptr += 8;
for (long id : lut) { for (long id : lut) {
raw.putLong(id); MemoryUtil.memPutLong(ptr, id); ptr += 8;
hash *= 1230987149811L; hash *= 1230987149811L;
hash += 12831; hash += 12831;
hash ^= id; hash ^= id;
} }
hash ^= pHash; hash ^= pHash;
for (short block : compressed) { UnsafeUtil.memcpy(compressed, ptr); ptr += compressed.length*2L;
raw.putShort(block);
MemoryUtil.memPutLong(ptr, hash); ptr += 8;
return raw.subSize(ptr-raw.address);
} }
raw.putLong(hash); public static boolean deserialize(WorldSection section, MemoryBuffer data) {
//The amount of memory copies are not ideal
var out = new MemoryBuffer(raw.position());
UnsafeUtil.memcpy(MemoryUtil.memAddress(raw), out.address, out.size);
MemoryUtil.memFree(raw);
return out;
}
public static boolean deserialize(WorldSection section, MemoryBuffer data, boolean ignoreMismatchPosition) {
long ptr = data.address; long ptr = data.address;
long hash = 0; long hash = 0;
long key = MemoryUtil.memGetLong(ptr); ptr += 8; long key = MemoryUtil.memGetLong(ptr); ptr += 8;
int lutLen = MemoryUtil.memGetInt(ptr); ptr += 4; int lutLen = MemoryUtil.memGetInt(ptr); ptr += 4;
long[] lut = new long[lutLen]; long[] lut = new long[lutLen];
if (VERIFY_HASH_ON_LOAD) {
hash = key ^ (lut.length * 1293481298141L); hash = key ^ (lut.length * 1293481298141L);
}
for (int i = 0; i < lutLen; i++) { for (int i = 0; i < lutLen; i++) {
lut[i] = MemoryUtil.memGetLong(ptr); ptr += 8; lut[i] = MemoryUtil.memGetLong(ptr); ptr += 8;
if (VERIFY_HASH_ON_LOAD) {
hash *= 1230987149811L; hash *= 1230987149811L;
hash += 12831; hash += 12831;
hash ^= lut[i]; hash ^= lut[i];
} }
}
if ((!ignoreMismatchPosition) && section.key != key) { if (section.key != key) {
//throw new IllegalStateException("Decompressed section not the same as requested. got: " + key + " expected: " + section.key); //throw new IllegalStateException("Decompressed section not the same as requested. got: " + key + " expected: " + section.key);
System.err.println("Decompressed section not the same as requested. got: " + key + " expected: " + section.key); System.err.println("Decompressed section not the same as requested. got: " + key + " expected: " + section.key);
return false; return false;
@@ -96,6 +97,7 @@ public class SaveLoadSystem {
section.data[z2lin(i)] = lut[MemoryUtil.memGetShort(ptr)]; ptr += 2; section.data[z2lin(i)] = lut[MemoryUtil.memGetShort(ptr)]; ptr += 2;
} }
if (VERIFY_HASH_ON_LOAD) {
long pHash = 99; long pHash = 99;
for (long block : section.data) { for (long block : section.data) {
pHash *= 127817112311121L; pHash *= 127817112311121L;
@@ -111,7 +113,7 @@ public class SaveLoadSystem {
System.err.println("Hash mismatch got: " + hash + " expected: " + expectedHash + " removing region"); System.err.println("Hash mismatch got: " + hash + " expected: " + expectedHash + " removing region");
return false; return false;
} }
}
return true; return true;
} }
} }

View File

@@ -43,7 +43,7 @@ public class WorldEngine {
var data = this.storage.getSectionData(into.key); var data = this.storage.getSectionData(into.key);
if (data != null) { if (data != null) {
try { try {
if (!SaveLoadSystem.deserialize(into, data, true)) { if (!SaveLoadSystem.deserialize(into, data)) {
this.storage.deleteSectionData(into.key); this.storage.deleteSectionData(into.key);
//TODO: regenerate the section from children //TODO: regenerate the section from children
Arrays.fill(into.data, Mapper.AIR); Arrays.fill(into.data, Mapper.AIR);