From 0ca6faea011a5bb8b456fd2f87651132392bea37 Mon Sep 17 00:00:00 2001 From: goyuken Date: Mon, 18 May 2015 22:18:09 +0000 Subject: [PATCH] AppleII: squeeze a bit of speed out of binary states, still way too slow --- .../Computers/AppleII/AppleII.IStatable.cs | 25 +- .../Computers/AppleII/LBSON.cs | 327 +++++++++--------- 2 files changed, 185 insertions(+), 167 deletions(-) diff --git a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IStatable.cs b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IStatable.cs index 75ad89043f..75df894756 100644 --- a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IStatable.cs +++ b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IStatable.cs @@ -32,7 +32,7 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII } } - public bool BinarySaveStatesPreferred { get { return false; } } + public bool BinarySaveStatesPreferred { get { return true; } } private void SerializeEverything(JsonWriter w) { @@ -103,7 +103,7 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII DeserializeEverything(new BsonReader(reader)); } */ - + /* public void SaveStateBinary(BinaryWriter writer) { var tw = new StreamWriter(writer.BaseStream, new System.Text.UTF8Encoding(false)); @@ -115,23 +115,24 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII { var tr = new StreamReader(reader.BaseStream, System.Text.Encoding.UTF8); LoadStateText(tr); - } + }*/ - /* - * This naive attempt at making my own kind of BSON writer/reader is slow, probably because - * everything has to be popped out to a full JToken graph to use it. A real competing solution - * would inherit JsonWriter\JsonReader, if that's even possible + // these homemade classes edge out the stock ones slightly, but need BufferedStream to not be bad public void SaveStateBinary(BinaryWriter writer) { - var j = new JTokenWriter(); - SerializeEverything(j); - new LBSONWriter(writer).Write(j.Token); + var buffer = new BufferedStream(writer.BaseStream, 16384); + var bw2 = new BinaryWriter(buffer); + SerializeEverything(new LBW(bw2)); + bw2.Flush(); + buffer.Flush(); } public void LoadStateBinary(BinaryReader reader) { - DeserializeEverything(new JTokenReader(new LBSONReader(reader).Read())); - }*/ + var buffer = new BufferedStream(reader.BaseStream, 16384); + var br2 = new BinaryReader(buffer); + DeserializeEverything(new LBR(br2)); + } public byte[] SaveStateBinary() { diff --git a/BizHawk.Emulation.Cores/Computers/AppleII/LBSON.cs b/BizHawk.Emulation.Cores/Computers/AppleII/LBSON.cs index 6540af6fee..76df21fa69 100644 --- a/BizHawk.Emulation.Cores/Computers/AppleII/LBSON.cs +++ b/BizHawk.Emulation.Cores/Computers/AppleII/LBSON.cs @@ -9,197 +9,214 @@ using Newtonsoft.Json.Linq; namespace BizHawk.Emulation.Cores.Computers.AppleII { - // test classes to see if our own lightweight BSON can be fast - // these don't derive JsonReader and JsonWriter because those classes are difficult to derive from, - // so unfortunately everything has to be loaded into memory. + // barebones classes for writing and reading a simple bson-like format, used to gain a bit of speed in Apple II savestates - public class LBSONReader + internal enum LBTOK : byte { - private enum LToken : byte - { - Null, - Array, - Object, - S8, - U8, - S16, - U16, - S32, - U32, - S64, - U64, - False, - True, - String, - F32, - F64 - } + Null, + Undefined, + StartArray, + EndArray, + StartObject, + EndObject, + Property, + S8, + U8, + S16, + U16, + S32, + U32, + S64, + U64, + False, + True, + String, + F32, + F64, + } - private LToken ReadToken() - { - return (LToken)r.ReadByte(); - } - - public LBSONReader(BinaryReader r) + public class LBR : JsonReader + { + public LBR(BinaryReader r) { this.r = r; } - private BinaryReader r; - - public JToken Read() + public override void Close() { - var t = ReadToken(); + } + // as best as I can tell, the serializers refer to depth, but don't actually need to work except when doing certain error recovery + public override int Depth { get { return 0; } } + public override string Path { get { throw new NotImplementedException(); } } + public override Type ValueType { get { return v != null ? v.GetType() : null; } } + public override JsonToken TokenType { get { return t; } } + public override object Value { get { return v; } } + private object v; + private JsonToken t; + + public override bool Read() + { + LBTOK l = (LBTOK)r.ReadByte(); + switch (l) + { + case LBTOK.StartArray: t = JsonToken.StartArray; v = null; break; + case LBTOK.EndArray: t = JsonToken.EndArray; v = null; break; + case LBTOK.StartObject: t = JsonToken.StartObject; v = null; break; + case LBTOK.EndObject: t = JsonToken.EndObject; v = null; break; + case LBTOK.Null: t = JsonToken.Null; v = null; break; + case LBTOK.False: t = JsonToken.Boolean; v = false; break; + case LBTOK.True: t = JsonToken.Boolean; v = true; break; + case LBTOK.Property: t = JsonToken.PropertyName; v = r.ReadString(); break; + case LBTOK.Undefined: t = JsonToken.Undefined; v = null; break; + case LBTOK.S8: t = JsonToken.Integer; v = r.ReadSByte(); break; + case LBTOK.U8: t = JsonToken.Integer; v = r.ReadByte(); break; + case LBTOK.S16: t = JsonToken.Integer; v = r.ReadInt16(); break; + case LBTOK.U16: t = JsonToken.Integer; v = r.ReadUInt16(); break; + case LBTOK.S32: t = JsonToken.Integer; v = r.ReadInt32(); break; + case LBTOK.U32: t = JsonToken.Integer; v = r.ReadUInt32(); break; + case LBTOK.S64: t = JsonToken.Integer; v = r.ReadInt64(); break; + case LBTOK.U64: t = JsonToken.Integer; v = r.ReadUInt64(); break; + case LBTOK.String: t = JsonToken.String; v = r.ReadString(); break; + case LBTOK.F32: t = JsonToken.Float; v = r.ReadSingle(); break; + case LBTOK.F64: t = JsonToken.Float; v = r.ReadDouble(); break; + + default: + throw new InvalidOperationException(); + } + return true; + } + + public override byte[] ReadAsBytes() + { + throw new NotImplementedException(); + } + + public override DateTime? ReadAsDateTime() + { + throw new NotImplementedException(); + } + + public override DateTimeOffset? ReadAsDateTimeOffset() + { + throw new NotImplementedException(); + } + + public override decimal? ReadAsDecimal() + { + throw new NotImplementedException(); + } + + public override int? ReadAsInt32() + { + // TODO: speed this up if needed + if (!Read()) + return null; + switch (t) { - case LToken.Null: return JValue.CreateNull(); - case LToken.Array: return ReadArray(); - case LToken.Object: return ReadObject(); - case LToken.S8: return new JValue(r.ReadSByte()); - case LToken.U8: return new JValue(r.ReadByte()); - case LToken.S16: return new JValue(r.ReadInt16()); - case LToken.U16: return new JValue(r.ReadUInt16()); - case LToken.S32: return new JValue(r.ReadInt32()); - case LToken.U32: return new JValue(r.ReadUInt32()); - case LToken.S64: return new JValue(r.ReadInt64()); - case LToken.U64: return new JValue(r.ReadUInt64()); - case LToken.False: return new JValue(false); - case LToken.True: return new JValue(true); - case LToken.String: return new JValue(r.ReadString()); - case LToken.F32: return new JValue(r.ReadSingle()); - case LToken.F64: return new JValue(r.ReadDouble()); - default: throw new InvalidOperationException(); + case JsonToken.Null: + return null; + case JsonToken.Integer: + case JsonToken.Float: + return Convert.ToInt32(v); + case JsonToken.String: + int i; + if (int.TryParse(v.ToString(), out i)) + return i; + else + return null; + default: + return null; } } - private JArray ReadArray() + public override string ReadAsString() { - int l = r.ReadInt32(); - var ret = new JArray(); - for (int i = 0; i < l; i++) - { - ret.Add(Read()); - } - return ret; - } + if (!Read()) + return null; - private JObject ReadObject() - { - int l = r.ReadInt32(); - var ret = new JObject(); - for (int i = 0; i < l; i++) + switch (t) { - ret.Add(r.ReadString(), Read()); + case JsonToken.Null: + return null; + case JsonToken.Float: + case JsonToken.Integer: + case JsonToken.Boolean: + case JsonToken.String: + return v.ToString(); + default: + return null; } - return ret; } } - public class LBSONWriter + public class LBW : JsonWriter { - private enum LToken : byte - { - Null, - Array, - Object, - S8, - U8, - S16, - U16, - S32, - U32, - S64, - U64, - False, - True, - String, - F32, - F64 - } - private void WriteToken(LToken t) + private void WT(LBTOK t) { w.Write((byte)t); } - public LBSONWriter(BinaryWriter w) + public LBW(BinaryWriter w) { this.w = w; } - private BinaryWriter w; - private void WriteArray(JArray j) + public override void Flush() { - WriteToken(LToken.Array); - w.Write(j.Count); - foreach (var jj in j) - { - Write(jj); - } - } - private void WriteObject(JObject j) - { - WriteToken(LToken.Object); - w.Write(j.Count); - foreach (var jj in j) - { - w.Write(jj.Key); - Write(jj.Value); - } + w.Flush(); } - private void WriteValue(object o) + public override void Close() { - switch (o.GetType().ToString()) - { - case "System.SByte": WriteToken(LToken.S8); w.Write((sbyte)o); return; - case "System.Byte": WriteToken(LToken.U8); w.Write((byte)o); return; - case "System.Int16": WriteToken(LToken.S16); w.Write((short)o); return; - case "System.UInt16": WriteToken(LToken.U16); w.Write((ushort)o); return; - case "System.Int32": WriteToken(LToken.S32); w.Write((int)o); return; - case "System.UInt32": WriteToken(LToken.U32); w.Write((uint)o); return; - case "System.Int64": WriteToken(LToken.S64); w.Write((long)o); return; - case "System.UInt64": WriteToken(LToken.U64); w.Write((ulong)o); return; - - case "System.Boolean": WriteToken((bool)o ? LToken.True : LToken.False); return; - - case "System.Single": WriteToken(LToken.F32); w.Write((float)o); return; - case "System.Double": WriteToken(LToken.F64); w.Write((double)o); return; - - case "System.String": WriteToken(LToken.String); w.Write((string)o); return; - - default: - throw new NotImplementedException(); - } } - public void Write(JToken j) - { - switch (j.Type) - { - case JTokenType.Array: - WriteArray((JArray)j); - return; - case JTokenType.Object: - WriteObject((JObject)j); - return; - case JTokenType.Boolean: - case JTokenType.Bytes: - case JTokenType.Date: - case JTokenType.Float: - case JTokenType.Guid: - case JTokenType.Integer: - case JTokenType.String: - WriteValue(((JValue)j).Value); - return; - - case JTokenType.Null: - WriteToken(LToken.Null); - return; + public override void WriteValue(bool value) { WT(value ? LBTOK.True : LBTOK.False); } - default: - throw new NotImplementedException(); - } - } + public override void WriteValue(sbyte value) { WT(LBTOK.S8); w.Write(value); } + public override void WriteValue(byte value) { WT(LBTOK.U8); w.Write(value); } + public override void WriteValue(short value) { WT(LBTOK.S16); w.Write(value); } + public override void WriteValue(ushort value) { WT(LBTOK.U16); w.Write(value); } + public override void WriteValue(int value) { WT(LBTOK.S32); w.Write(value); } + public override void WriteValue(uint value) { WT(LBTOK.U32); w.Write(value); } + public override void WriteValue(long value) { WT(LBTOK.S64); w.Write(value); } + public override void WriteValue(ulong value) { WT(LBTOK.U64); w.Write(value); } + + public override void WriteStartArray() { WT(LBTOK.StartArray); } + public override void WriteEndArray() { WT(LBTOK.EndArray); } + public override void WriteStartObject() { WT(LBTOK.StartObject); } + public override void WriteEndObject() { WT(LBTOK.EndObject); } + public override void WriteNull() { WT(LBTOK.Null); } + public override void WriteUndefined() { WT(LBTOK.Undefined); } + + public override void WriteValue(float value) { WT(LBTOK.F32); w.Write(value); } + public override void WriteValue(double value) { WT(LBTOK.F64); w.Write(value); } + + public override void WriteComment(string text) { throw new NotImplementedException(); } + public override void WriteWhitespace(string ws) { throw new NotImplementedException(); } + protected override void WriteIndent() { throw new NotImplementedException(); } + protected override void WriteIndentSpace() { throw new NotImplementedException(); } + public override void WriteEnd() { throw new NotImplementedException(); } + protected override void WriteEnd(JsonToken token) { throw new NotImplementedException(); } + public override void WriteRaw(string json) { throw new NotImplementedException(); } + public override void WriteRawValue(string json) { throw new NotImplementedException(); } + public override void WriteStartConstructor(string name) { throw new NotImplementedException(); } + public override void WriteEndConstructor() { throw new NotImplementedException(); } + protected override void WriteValueDelimiter() { throw new NotImplementedException(); } + + public override void WritePropertyName(string name) { WT(LBTOK.Property); w.Write(name); } + public override void WriteValue(string value) { WT(LBTOK.String); w.Write(value); } + public override void WritePropertyName(string name, bool escape) { WT(LBTOK.Property); w.Write(name); } // no escaping required + + public override void WriteValue(byte[] value) { throw new NotImplementedException(); } + public override void WriteValue(char value) { throw new NotImplementedException(); } + public override void WriteValue(DateTime value) { throw new NotImplementedException(); } + public override void WriteValue(DateTimeOffset value) { throw new NotImplementedException(); } + public override void WriteValue(decimal value) { throw new NotImplementedException(); } + public override void WriteValue(Guid value) { throw new NotImplementedException(); } + public override void WriteValue(TimeSpan value) { throw new NotImplementedException(); } + public override void WriteValue(Uri value) { throw new NotImplementedException(); } } + }