summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xlib/protocol_benchmarks.py1225
1 files changed, 1225 insertions, 0 deletions
diff --git a/lib/protocol_benchmarks.py b/lib/protocol_benchmarks.py
new file mode 100755
index 0000000..f1f0f7c
--- /dev/null
+++ b/lib/protocol_benchmarks.py
@@ -0,0 +1,1225 @@
+import bson
+import cbor
+import json
+import msgpack
+import ubjson
+
+import os
+from filelock import FileLock
+
+class DummyProtocol:
+ def __init__(self):
+ self.max_serialized_bytes = None
+ self.enc_buf = ''
+ self.dec_buf = ''
+ self.dec_buf0 = ''
+ self.dec_buf1 = ''
+ self.dec_buf2 = ''
+ self.dec_index = 0
+
+ def assign_and_kout(self, signature, assignment):
+ self.new_var(signature)
+ self.assign_var(assignment)
+ self.kout_var()
+
+ def new_var(self, signature):
+ self.dec_index += 1
+ self.dec_buf0 += '{} dec_{:d};\n'.format(signature, self.dec_index)
+
+ def assign_var(self, assignment):
+ self.dec_buf1 += 'dec_{:d} = {};\n'.format(self.dec_index, assignment)
+
+ def get_var(self):
+ return 'dec_{:d}'.format(self.dec_index)
+
+ def kout_var(self):
+ self.dec_buf2 += 'kout << dec_{:d};\n'.format(self.dec_index)
+
+ def note_unsupported(self, value):
+ note = '// value {} has unsupported type {}\n'.format(value, type(value))
+ self.enc_buf += note
+ self.dec_buf += note
+ self.dec_buf1 += note
+
+ def is_ascii(self):
+ return True
+
+ def get_encode(self):
+ return ''
+
+ def get_buffer_declaration(self):
+ return ''
+
+ def get_serialize(self):
+ return ''
+
+ def get_deserialize(self):
+ return ''
+
+ def get_decode_and_output(self):
+ return ''
+
+ def get_decode_vars(self):
+ return ''
+
+ def get_decode(self):
+ return ''
+
+ def get_decode_output(self):
+ return ''
+
+ def get_extra_files(self):
+ return dict()
+
+class ArduinoJSON(DummyProtocol):
+
+ def __init__(self, data, bufsize = 255, int_type = 'uint16_t', float_type = 'float'):
+ super().__init__()
+ self.data = data
+ self.max_serialized_bytes = self.get_serialized_length() + 2
+ self.children = set()
+ self.bufsize = bufsize
+ self.int_type = int_type
+ self.float_type = float_type
+ self.enc_buf += 'ArduinoJson::StaticJsonBuffer<{:d}> jsonBuffer;\n'.format(bufsize)
+ self.enc_buf += 'ArduinoJson::JsonObject& root = jsonBuffer.createObject();\n'
+ self.from_json(data, 'root')
+
+ def get_serialized_length(self):
+ return len(json.dumps(self.data))
+
+ def get_encode(self):
+ return self.enc_buf
+
+ def get_buffer_declaration(self):
+ return 'char buf[{:d}];\n'.format(self.max_serialized_bytes)
+
+ def get_buffer_name(self):
+ return 'buf'
+
+ def get_length_var(self):
+ return 'serialized_size'
+
+ def get_serialize(self):
+ return 'uint16_t serialized_size = root.printTo(buf);\n'
+
+ def get_deserialize(self):
+ ret = 'ArduinoJson::StaticJsonBuffer<{:d}> jsonBuffer;\n'.format(self.bufsize)
+ ret += 'ArduinoJson::JsonObject& root = jsonBuffer.parseObject(buf);\n'
+ return ret
+
+ def get_decode_and_output(self):
+ return 'kout << dec << "dec:";\n' + self.dec_buf + 'kout << endl;\n';
+
+ def get_decode_vars(self):
+ return self.dec_buf0
+
+ def get_decode(self):
+ return self.dec_buf1
+
+ def get_decode_output(self):
+ return 'kout << dec << "dec:";\n' + self.dec_buf2 + 'kout << endl;\n';
+
+ def add_to_list(self, enc_node, dec_node, offset, value):
+ if type(value) == str:
+ if len(value) and value[0] == '$':
+ self.enc_buf += '{}.add({});\n'.format(enc_node, value[1:])
+ self.dec_buf += 'kout << {}[{:d}].as<{}>();\n'.format(dec_node, offset, self.int_type)
+ self.assign_and_kout(self.int_type, '{}[{:d}].as<{}>()'.format(dec_node, offset, self.int_type))
+ else:
+ self.enc_buf += '{}.add("{}");\n'.format(enc_node, value)
+ self.dec_buf += 'kout << {}[{:d}].as<const char *>();\n'.format(dec_node, offset)
+ self.assign_and_kout('char const*', '{}[{:d}].as<char const *>()'.format(dec_node, offset))
+
+ elif type(value) == list:
+ child = enc_node + 'l'
+ while child in self.children:
+ child += '_'
+ self.enc_buf += 'ArduinoJson::JsonArray& {} = {}.createNestedArray();\n'.format(
+ child, enc_node)
+ self.children.add(child)
+ self.from_json(value, child)
+
+ elif type(value) == dict:
+ child = enc_node + 'o'
+ while child in self.children:
+ child += '_'
+ self.enc_buf += 'ArduinoJson::JsonObject& {} = {}.createNestedObject();\n'.format(
+ child, enc_node)
+ self.children.add(child)
+ self.from_json(value, child)
+
+ elif type(value) == float:
+ self.enc_buf += '{}.add({});\n'.format(enc_node, value)
+ self.dec_buf += 'kout << {}[{:d}].as<{}>();\n'.format(dec_node, offset, self.float_type)
+ self.assign_and_kout(self.float_type, '{}[{:d}].as<{}>()'.format(dec_node, offset, self.float_type))
+
+ elif type(value) == int:
+ self.enc_buf += '{}.add({});\n'.format(enc_node, value)
+ self.dec_buf += 'kout << {}[{:d}].as<{}>();\n'.format(dec_node, offset, self.int_type)
+ self.assign_and_kout(self.int_type, '{}[{:d}].as<{}>()'.format(dec_node, offset, self.int_type))
+
+ else:
+ self.note_unsupported(value)
+
+ def add_to_dict(self, enc_node, dec_node, key, value):
+ if type(value) == str:
+ if len(value) and value[0] == '$':
+ self.enc_buf += '{}["{}"] = {};\n'.format(enc_node, key, value[1:])
+ self.dec_buf += 'kout << {}["{}"].as<{}>();\n'.format(dec_node, key, self.int_type)
+ self.assign_and_kout(self.int_type, '{}["{}"].as<{}>()'.format(dec_node, key, self.int_type))
+ else:
+ self.enc_buf += '{}["{}"] = "{}";\n'.format(enc_node, key, value)
+ self.dec_buf += 'kout << {}["{}"].as<const char *>();\n'.format(dec_node, key)
+ self.assign_and_kout('char const*', '{}["{}"].as<const char *>()'.format(dec_node, key))
+
+ elif type(value) == list:
+ child = enc_node + 'l'
+ while child in self.children:
+ child += '_'
+ self.enc_buf += 'ArduinoJson::JsonArray& {} = {}.createNestedArray("{}");\n'.format(
+ child, enc_node, key)
+ self.children.add(child)
+ self.from_json(value, child, '{}["{}"]'.format(dec_node, key))
+
+ elif type(value) == dict:
+ child = enc_node + 'o'
+ while child in self.children:
+ child += '_'
+ self.enc_buf += 'ArduinoJson::JsonObject& {} = {}.createNestedObject("{}");\n'.format(
+ child, enc_node, key)
+ self.children.add(child)
+ self.from_json(value, child, '{}["{}"]'.format(dec_node, key))
+
+ elif type(value) == float:
+ self.enc_buf += '{}["{}"] = {};\n'.format(enc_node, key, value)
+ self.dec_buf += 'kout << {}["{}"].as<{}>();\n'.format(dec_node, key, self.float_type)
+ self.assign_and_kout(self.float_type, '{}["{}"].as<{}>()'.format(dec_node, key, self.float_type))
+
+ elif type(value) == int:
+ self.enc_buf += '{}["{}"] = {};\n'.format(enc_node, key, value)
+ self.dec_buf += 'kout << {}["{}"].as<{}>();\n'.format(dec_node, key, self.int_type)
+ self.assign_and_kout(self.int_type, '{}["{}"].as<{}>()'.format(dec_node, key, self.int_type))
+
+ else:
+ self.note_unsupported(tvalue)
+
+ def from_json(self, data, enc_node = 'root', dec_node = 'root'):
+ if type(data) == dict:
+ for key in sorted(data.keys()):
+ self.add_to_dict(enc_node, dec_node, key, data[key])
+ elif type(data) == list:
+ for i, elem in enumerate(data):
+ self.add_to_list(enc_node, dec_node, i, elem)
+
+
+class CapnProtoC(DummyProtocol):
+
+ def __init__(self, data, max_serialized_bytes = 128, packed = False, trail = ['benchmark'], int_type = 'uint16_t', float_type = 'float', dec_index = 0):
+ super().__init__()
+ self.data = data
+ self.max_serialized_bytes = max_serialized_bytes
+ self.packed = packed
+ self.name = trail[-1]
+ self.trail = trail
+ self.int_type = int_type
+ self.proto_int_type = self.int_type_to_proto_type(int_type)
+ self.float_type = float_type
+ self.proto_float_type = self.float_type_to_proto_type(float_type)
+ self.dec_index = dec_index
+ self.trail_name = '_'.join(map(lambda x: x.capitalize(), trail))
+ self.proto_buf = ''
+ self.enc_buf += 'struct {} {};\n'.format(self.trail_name, self.name)
+ self.cc_tail = ''
+ self.key_counter = 0
+ self.from_json(data)
+
+ def int_type_to_proto_type(self, int_type):
+ sign = ''
+ if int_type[0] == 'u':
+ sign = 'U'
+ if '8' in int_type:
+ self.int_bits = 8
+ return sign + 'Int8'
+ if '16' in int_type:
+ self.int_bits = 16
+ return sign + 'Int16'
+ if '32' in int_type:
+ self.int_bits = 32
+ return sign + 'Int32'
+ self.int_bits = 64
+ return sign + 'Int64'
+
+ def float_type_to_proto_type(self, float_type):
+ if float_type == 'float':
+ self.float_bits = 32
+ return 'Float32'
+ self.float_bits = 64
+ return 'Float64'
+
+ def is_ascii(self):
+ return False
+
+ def get_proto(self):
+ return '@0xad5b236043de2389;\n\n' + self.proto_buf
+
+ def get_extra_files(self):
+ return {
+ 'capnp_c_bench.capnp' : self.get_proto()
+ }
+
+ def get_buffer_declaration(self):
+ ret = 'uint8_t buf[{:d}];\n'.format(self.max_serialized_bytes)
+ ret += 'uint16_t serialized_size;\n'
+ return ret
+
+ def get_buffer_name(self):
+ return 'buf'
+
+ def get_encode(self):
+ ret = 'struct capn c;\n'
+ ret += 'capn_init_malloc(&c);\n'
+ ret += 'capn_ptr cr = capn_root(&c);\n'
+ ret += 'struct capn_segment *cs = cr.seg;\n\n'
+ ret += '{}_ptr {}_ptr = new_{}(cs);\n'.format(
+ self.trail_name, self.name, self.trail_name)
+
+ tail = 'write_{}(&{}, {}_ptr);\n'.format(
+ self.trail_name, self.name, self.name)
+ tail += 'capn_setp(cr, 0, {}_ptr.p);\n'.format(self.name)
+
+ return ret + self.enc_buf + self.cc_tail + tail
+
+ def get_serialize(self):
+ ret = 'serialized_size = capn_write_mem(&c, buf, sizeof(buf), {:d});\n'.format(self.packed)
+ ret += 'capn_free(&c);\n'
+ return ret
+
+ def get_deserialize(self):
+ ret = 'struct capn c;\n'
+ ret += 'capn_init_mem(&c, buf, serialized_size, 0);\n'
+ return ret
+
+ def get_decode_and_output(self):
+ ret = '{}_ptr {}_ptr;\n'.format(self.trail_name, self.name)
+ ret += '{}_ptr.p = capn_getp(capn_root(&c), 0, 1);\n'.format(self.name)
+ ret += 'struct {} {};\n'.format(self.trail_name, self.name)
+ ret += 'kout << dec << "dec:";\n'
+ ret += self.dec_buf
+ ret += 'kout << endl;\n'
+ ret += 'capn_free(&c);\n'
+ return ret
+
+ def get_decode_vars(self):
+ return self.dec_buf0
+
+ def get_decode(self):
+ ret = '{}_ptr {}_ptr;\n'.format(self.trail_name, self.name)
+ ret += '{}_ptr.p = capn_getp(capn_root(&c), 0, 1);\n'.format(self.name)
+ ret += 'struct {} {};\n'.format(self.trail_name, self.name)
+ ret += self.dec_buf1
+ ret += 'capn_free(&c);\n'
+ return ret
+
+ def get_decode_output(self):
+ return 'kout << dec << "dec:";\n' + self.dec_buf2 + 'kout << endl;\n';
+
+ def get_length_var(self):
+ return 'serialized_size'
+
+ def add_field(self, fieldtype, key, value):
+ extra = ''
+ texttype = self.proto_int_type
+
+ if fieldtype == str:
+ texttype = 'Text'
+ elif fieldtype == float:
+ texttype = self.proto_float_type
+ elif fieldtype == dict:
+ texttype = key.capitalize()
+
+ if type(value) == list:
+ texttype = 'List({})'.format(texttype)
+
+ self.proto_buf += '{} @{:d} :{};\n'.format(
+ key, self.key_counter, texttype)
+ self.key_counter += 1
+
+ if fieldtype == str:
+ self.enc_buf += 'capn_text {}_text;\n'.format(key)
+ self.enc_buf += '{}_text.len = {:d};\n'.format(key, len(value))
+ self.enc_buf += '{}_text.str = "{}";\n'.format(key, value)
+ self.enc_buf += '{}_text.seg = NULL;\n'.format(key)
+ self.enc_buf += '{}.{} = {}_text;\n\n'.format(self.name, key, key)
+ self.dec_buf += 'kout << {}.{}.str;\n'.format(self.name, key)
+ self.assign_and_kout('char const *', '{}.{}.str'.format(self.name, key))
+ elif fieldtype == dict:
+ pass # content is handled recursively in add_to_dict
+ elif type(value) == list:
+ if type(value[0]) == float:
+ self.enc_buf += '{}.{} = capn_new_list{:d}(cs, {:d});\n'.format(
+ self.name, key, self.float_bits, len(value))
+ for i, elem in enumerate(value):
+ self.enc_buf += 'capn_set{:d}({}.{}, {:d}, capn_from_f{:d}({:f}));\n'.format(
+ self.float_bits, self.name, key, i, self.float_bits, elem)
+ self.dec_buf += 'kout << capn_to_f{:d}(capn_get{:d}({}.{}, {:d}));\n'.format(
+ self.float_bits, self.float_bits, self.name, key, i)
+ self.assign_and_kout(self.float_type, 'capn_to_f{:d}(capn_get{:d}({}.{}, {:d}))'.format(self.float_bits, self.float_bits, self.name, key, i))
+ else:
+ self.enc_buf += '{}.{} = capn_new_list{:d}(cs, {:d});\n'.format(
+ self.name, key, self.int_bits, len(value))
+ for i, elem in enumerate(value):
+ self.enc_buf += 'capn_set{:d}({}.{}, {:d}, {:d});\n'.format(
+ self.int_bits, self.name, key, i, elem)
+ self.dec_buf += 'kout << capn_get{:d}({}.{}, {:d});\n'.format(
+ self.int_bits, self.name, key, i)
+ self.assign_and_kout(self.int_type, 'capn_get{:d}({}.{}, {:d})'.format(self.int_bits, self.name, key, i))
+ elif fieldtype == float:
+ self.enc_buf += '{}.{} = {};\n\n'.format(self.name, key, value)
+ self.dec_buf += 'kout << {}.{};\n'.format(self.name, key)
+ self.assign_and_kout(self.float_type, '{}.{}'.format(self.name, key))
+
+ elif fieldtype == int:
+ self.enc_buf += '{}.{} = {};\n\n'.format(self.name, key, value)
+ self.dec_buf += 'kout << {}.{};\n'.format(self.name, key)
+ self.assign_and_kout(self.int_type, '{}.{}'.format(self.name, key))
+
+ else:
+ self.note_unsupported(value)
+
+ def add_to_dict(self, key, value):
+ if type(value) == str:
+ if len(value) and value[0] == '$':
+ self.add_field(int, key, value[1:])
+ else:
+ self.add_field(str, key, value)
+ elif type(value) == list:
+ self.add_field(type(value[0]), key, value)
+ elif type(value) == dict:
+ trail = list(self.trail)
+ trail.append(key)
+ nested = CapnProtoC(value, trail = trail, int_type = self.int_type, float_type = self.float_type, dec_index = self.dec_index)
+ self.add_field(dict, key, value)
+ self.enc_buf += '{}.{} = new_{}_{}(cs);\n'.format(
+ self.name, key, self.trail_name, key.capitalize())
+ self.enc_buf += nested.enc_buf
+ self.enc_buf += 'write_{}_{}(&{}, {}.{});\n'.format(
+ self.trail_name, key.capitalize(), key, self.name, key)
+ self.dec_buf += 'struct {}_{} {};\n'.format(self.trail_name, key.capitalize(), key)
+ self.dec_buf += 'read_{}_{}(&{}, {}.{});\n'.format(self.trail_name, key.capitalize(), key, self.name, key)
+ self.dec_buf += nested.dec_buf
+ self.dec_buf0 += nested.dec_buf0
+ self.dec_buf1 += 'struct {}_{} {};\n'.format(self.trail_name, key.capitalize(), key)
+ self.dec_buf1 += 'read_{}_{}(&{}, {}.{});\n'.format(self.trail_name, key.capitalize(), key, self.name, key)
+ self.dec_buf1 += nested.dec_buf1
+ self.dec_buf2 += nested.dec_buf2
+ self.dec_index = nested.dec_index
+ self.proto_buf += nested.proto_buf
+ else:
+ self.add_field(type(value), key, value)
+
+ def from_json(self, data):
+ self.proto_buf += 'struct {} {{\n'.format(self.name.capitalize())
+ if type(data) == dict:
+ for key in sorted(data.keys()):
+ self.add_to_dict(key, data[key])
+ self.proto_buf += '}\n'
+
+class ManualJSON(DummyProtocol):
+
+ def __init__(self, data):
+ super().__init__()
+ self.data = data
+ self.max_serialized_bytes = self.get_serialized_length() + 2
+ self.buf = 'BufferOutput<> bout(buf);\n'
+ self.buf += 'bout << "{";\n'
+ self.from_json(data)
+ self.buf += 'bout << "}";\n'
+
+ def get_serialized_length(self):
+ return len(json.dumps(self.data))
+
+ def is_ascii(self):
+ return True
+
+ def get_buffer_declaration(self):
+ return 'char buf[{:d}];\n'.format(self.max_serialized_bytes);
+
+ def get_buffer_name(self):
+ return 'buf'
+
+ def get_encode(self):
+ return self.buf
+
+ def get_length_var(self):
+ return 'bout.size()'
+
+ def add_to_list(self, value, is_last):
+ if type(value) == str:
+ if len(value) and value[0] == '$':
+ self.buf += 'bout << dec << {}'.format(value[1:])
+ else:
+ self.buf += 'bout << "\"{}\""'.format(value)
+
+ elif type(value) == list:
+ self.buf += 'bout << "[";\n'
+ self.from_json(value)
+ self.buf += 'bout << "]"'
+
+ elif type(value) == dict:
+ self.buf += 'bout << "{";\n'
+ self.from_json(value)
+ self.buf += 'bout << "}"'
+
+ else:
+ self.buf += 'bout << "{}"'.format(value)
+
+ if is_last:
+ self.buf += ';\n';
+ else:
+ self.buf += ' << ",";\n'
+
+ def add_to_dict(self, key, value, is_last):
+ if type(value) == str:
+ if len(value) and value[0] == '$':
+ self.buf += 'bout << "\\"{}\\":" << dec << {}'.format(key, value[1:])
+ else:
+ self.buf += 'bout << "\\"{}\\":\\"{}\\""'.format(key, value)
+
+ elif type(value) == list:
+ self.buf += 'bout << "\\"{}\\":[";\n'.format(key)
+ self.from_json(value)
+ self.buf += 'bout << "]"'
+
+ elif type(value) == dict:
+ # '{{' is an escaped '{' character
+ self.buf += 'bout << "\\"{}\\":{{";\n'.format(key)
+ self.from_json(value)
+ self.buf += 'bout << "}"'
+
+ else:
+ self.buf += 'bout << "\\"{}\\":{}"'.format(key, value)
+
+ if is_last:
+ self.buf += ';\n'
+ else:
+ self.buf += ' << ",";\n'
+
+ def from_json(self, data):
+ if type(data) == dict:
+ keys = sorted(data.keys())
+ for key in keys:
+ self.add_to_dict(key, data[key], key == keys[-1])
+ elif type(data) == list:
+ for i, elem in enumerate(data):
+ self.add_to_list(elem, i == len(data) - 1)
+
+class ModernJSON(DummyProtocol):
+
+ def __init__(self, data, output_format = 'json'):
+ super().__init__()
+ self.data = data
+ self.output_format = output_format
+ self.buf = 'nlohmann::json js;\n'
+ self.from_json(data)
+
+ def is_ascii(self):
+ if self.output_format == 'json':
+ return True
+ return False
+
+ def get_buffer_name(self):
+ return 'out'
+
+ def get_encode(self):
+ return self.buf
+
+ def get_serialize(self):
+ if self.output_format == 'json':
+ return 'std::string out = js.dump();\n'
+ elif self.output_format == 'bson':
+ return 'std::vector<std::uint8_t> out = nlohmann::json::to_bson(js);\n'
+ elif self.output_format == 'cbor':
+ return 'std::vector<std::uint8_t> out = nlohmann::json::to_cbor(js);\n'
+ elif self.output_format == 'msgpack':
+ return 'std::vector<std::uint8_t> out = nlohmann::json::to_msgpack(js);\n'
+ elif self.output_format == 'ubjson':
+ return 'std::vector<std::uint8_t> out = nlohmann::json::to_ubjson(js);\n'
+ else:
+ raise ValueError('invalid output format {}'.format(self.output_format))
+
+ def get_length_var(self):
+ return 'out.size()'
+
+ def add_to_list(self, prefix, index, value):
+ if type(value) == str:
+ if len(value) and value[0] == '$':
+ self.buf += value[1:]
+ self.buf += '{}[{:d}] = {};\n'.format(prefix, index, value[1:])
+ else:
+ self.buf += '{}[{:d}] = "{}";\n'.format(prefix, index, value)
+
+ else:
+ self.buf += '{}[{:d}] = {};\n'.format(prefix, index, value)
+
+ def add_to_dict(self, prefix, key, value):
+ if type(value) == str:
+ if len(value) and value[0] == '$':
+ self.buf += '{}["{}"] = {};\n'.format(prefix, key, value[1:])
+ else:
+ self.buf += '{}["{}"] = "{}";\n'.format(prefix, key, value)
+
+ elif type(value) == list:
+ self.from_json(value, '{}["{}"]'.format(prefix, key))
+
+ elif type(value) == dict:
+ self.from_json(value, '{}["{}"]'.format(prefix, key))
+
+ else:
+ self.buf += '{}["{}"] = {};\n'.format(prefix, key, value)
+
+ def from_json(self, data, prefix = 'js'):
+ if type(data) == dict:
+ for key in sorted(data.keys()):
+ self.add_to_dict(prefix, key, data[key])
+ elif type(data) == list:
+ for i, elem in enumerate(data):
+ self.add_to_list(prefix, i, elem)
+
+class MPack(DummyProtocol):
+
+ def __init__(self, data, int_type = 'uint16_t', float_type = 'float'):
+ super().__init__()
+ self.data = data
+ self.max_serialized_bytes = self.get_serialized_length() + 2
+ self.int_type = int_type
+ self.float_type = float_type
+ self.enc_buf += 'mpack_writer_t writer;\n'
+ self.enc_buf += 'mpack_writer_init(&writer, buf, sizeof(buf));\n'
+ self.dec_buf0 += 'char strbuf[16];\n'
+ self.from_json(data)
+
+ def get_serialized_length(self):
+ return len(msgpack.dumps(self.data))
+
+ def is_ascii(self):
+ return False
+
+ def get_buffer_declaration(self):
+ ret = 'char buf[{:d}];\n'.format(self.max_serialized_bytes)
+ ret += 'uint16_t serialized_size;\n'
+ return ret
+
+ def get_buffer_name(self):
+ return 'buf'
+
+ def get_encode(self):
+ return self.enc_buf
+
+ def get_serialize(self):
+ ret = 'serialized_size = mpack_writer_buffer_used(&writer);\n'
+ ret += 'if (mpack_writer_destroy(&writer) != mpack_ok) {\n'
+ ret += 'kout << "Encoding failed" << endl;\n'
+ ret += '}\n'
+ return ret
+
+ def get_deserialize(self):
+ ret = 'mpack_reader_t reader;\n'
+ ret += 'mpack_reader_init_data(&reader, buf, serialized_size);\n'
+ return ret
+
+ def get_decode_and_output(self):
+ ret = 'kout << dec << "dec:";\n'
+ ret += 'char strbuf[16];\n'
+ return ret + self.dec_buf + 'kout << endl;\n'
+
+ def get_decode_vars(self):
+ return self.dec_buf0
+
+ def get_decode(self):
+ return self.dec_buf1
+
+ def get_decode_output(self):
+ return 'kout << dec << "dec:";\n' + self.dec_buf2 + 'kout << endl;\n';
+
+ def get_length_var(self):
+ return 'serialized_size'
+
+ def add_value(self, value):
+ if type(value) == str:
+ if len(value) and value[0] == '$':
+ self.enc_buf += 'mpack_write(&writer, {});\n'.format(value[1:])
+ self.dec_buf += 'kout << mpack_expect_uint(&reader);\n'
+ self.assign_and_kout(self.int_type, 'mpack_expect_uint(&reader)')
+ else:
+ self.enc_buf += 'mpack_write_cstr_or_nil(&writer, "{}");\n'.format(value)
+ self.dec_buf += 'mpack_expect_cstr(&reader, strbuf, sizeof(strbuf));\n'
+ self.dec_buf += 'kout << strbuf;\n'
+ self.dec_buf1 += 'mpack_expect_cstr(&reader, strbuf, sizeof(strbuf));\n'
+ self.dec_buf2 += 'kout << strbuf;\n'
+ elif type(value) == list:
+ self.from_json(value)
+ elif type(value) == dict:
+ self.from_json(value)
+ elif type(value) == int:
+ self.enc_buf += 'mpack_write(&writer, ({}){:d});\n'.format(self.int_type, value)
+ self.dec_buf += 'kout << mpack_expect_uint(&reader);\n'
+ self.assign_and_kout(self.int_type, 'mpack_expect_uint(&reader)')
+ elif type(value) == float:
+ self.enc_buf += 'mpack_write(&writer, ({}){:f});\n'.format(self.float_type, value)
+ self.dec_buf += 'kout << mpack_expect_float(&reader);\n'
+ self.assign_and_kout(self.float_type, 'mpack_expect_float(&reader)')
+ else:
+ self.note_unsupported(value)
+
+ def from_json(self, data):
+ if type(data) == dict:
+ self.enc_buf += 'mpack_start_map(&writer, {:d});\n'.format(len(data))
+ self.dec_buf += 'mpack_expect_map_max(&reader, {:d});\n'.format(len(data))
+ self.dec_buf1 += 'mpack_expect_map_max(&reader, {:d});\n'.format(len(data))
+ for key in sorted(data.keys()):
+ self.enc_buf += 'mpack_write_cstr(&writer, "{}");\n'.format(key)
+ self.dec_buf += 'mpack_expect_cstr(&reader, strbuf, sizeof(strbuf));\n'
+ self.dec_buf1 += 'mpack_expect_cstr(&reader, strbuf, sizeof(strbuf));\n'
+ self.add_value(data[key])
+ self.enc_buf += 'mpack_finish_map(&writer);\n'
+ self.dec_buf += 'mpack_done_map(&reader);\n'
+ self.dec_buf1 += 'mpack_done_map(&reader);\n'
+ if type(data) == list:
+ self.enc_buf += 'mpack_start_array(&writer, {:d});\n'.format(len(data))
+ self.dec_buf += 'mpack_expect_array_max(&reader, {:d});\n'.format(len(data))
+ self.dec_buf1 += 'mpack_expect_array_max(&reader, {:d});\n'.format(len(data))
+ for elem in data:
+ self.add_value(elem);
+ self.enc_buf += 'mpack_finish_array(&writer);\n'
+ self.dec_buf += 'mpack_done_array(&reader);\n'
+ self.dec_buf1 += 'mpack_done_array(&reader);\n'
+
+class NanoPB(DummyProtocol):
+
+ def __init__(self, data, max_serialized_bytes = 256, cardinality = 'required', use_maps = False, max_string_length = None, cc_prefix = '', name = 'Benchmark',
+ int_type = 'uint16_t', float_type = 'float', dec_index = 0):
+ super().__init__()
+ self.data = data
+ self.max_serialized_bytes = max_serialized_bytes
+ self.cardinality = cardinality
+ self.use_maps = use_maps
+ self.max_strlen = max_string_length
+ self.cc_prefix = cc_prefix
+ self.name = name
+ self.int_type = int_type
+ self.proto_int_type = self.int_type_to_proto_type(int_type)
+ self.float_type = float_type
+ self.proto_float_type = self.float_type_to_proto_type(float_type)
+ self.dec_index = dec_index
+ self.fieldnum = 1
+ self.proto_head = 'syntax = "proto2";\nimport "src/app/prototest/nanopb.proto";\n\n'
+ self.proto_fields = ''
+ self.proto_options = ''
+ self.sub_protos = []
+ self.cc_encoders = ''
+ self.from_json(data)
+
+ def is_ascii(self):
+ return False
+
+ def int_type_to_proto_type(self, int_type):
+ sign = 'u'
+ if int_type[0] != 'u':
+ sign = ''
+ if '64' in int_type:
+ self.int_bits = 64
+ return sign + 'int64'
+ # Protocol Buffers only have 32 and 64 bit integers, so we default to 32
+ self.int_bits = 32
+ return sign + 'int32'
+
+ def float_type_to_proto_type(self, float_type):
+ if float_type == 'float':
+ self.float_bits = 32
+ else:
+ self.float_bits = 64
+ return float_type
+
+ def get_buffer_declaration(self):
+ ret = 'uint8_t buf[{:d}];\n'.format(self.max_serialized_bytes)
+ ret += 'uint16_t serialized_size;\n'
+ return ret + self.get_cc_functions()
+
+ def get_buffer_name(self):
+ return 'buf'
+
+ def get_serialize(self):
+ ret = 'pb_ostream_t stream = pb_ostream_from_buffer(buf, sizeof(buf));\n'
+ ret += 'pb_encode(&stream, Benchmark_fields, &msg);\n'
+ ret += 'serialized_size = stream.bytes_written;\n'
+ return ret
+
+ def get_deserialize(self):
+ ret = 'Benchmark msg = Benchmark_init_zero;\n'
+ ret += 'pb_istream_t stream = pb_istream_from_buffer(buf, serialized_size);\n'
+ ret += 'if (pb_decode(&stream, Benchmark_fields, &msg) == false) {\n'
+ ret += 'kout << "deserialized failed" << endl;\n'
+ ret += '}\n'
+ return ret
+
+ def get_decode_and_output(self):
+ return 'kout << dec << "dec:";\n' + self.dec_buf + 'kout << endl;\n'
+
+ def get_decode_vars(self):
+ return self.dec_buf0
+
+ def get_decode(self):
+ return self.dec_buf1
+
+ def get_decode_output(self):
+ return 'kout << dec << "dec:";\n' + self.dec_buf2 + 'kout << endl;\n';
+
+ def get_length_var(self):
+ return 'serialized_size'
+
+ def add_field(self, cardinality, fieldtype, key, value):
+ extra = ''
+ texttype = self.proto_int_type
+ dectype = self.int_type
+ if fieldtype == str:
+ texttype = 'string'
+ elif fieldtype == float:
+ texttype = self.proto_float_type
+ dectype = self.float_type
+ elif fieldtype == dict:
+ texttype = key.capitalize()
+ if type(value) == list:
+ extra = '[(nanopb).max_count = {:d}]'.format(len(value))
+ self.enc_buf += 'msg.{}{}_count = {:d};\n'.format(self.cc_prefix, key, len(value))
+ self.proto_fields += '{} {} {} = {:d} {};\n'.format(
+ cardinality, texttype, key, self.fieldnum, extra)
+ self.fieldnum += 1
+ if fieldtype == str:
+ if cardinality == 'optional':
+ self.enc_buf += 'msg.{}has_{} = true;\n'.format(self.cc_prefix, key)
+ if self.max_strlen:
+ self.proto_options += '{}.{} max_size:{:d}\n'.format(self.name, key, self.max_strlen)
+ i = -1
+ for i, character in enumerate(value):
+ self.enc_buf += '''msg.{}{}[{:d}] = '{}';\n'''.format(self.cc_prefix, key, i, character)
+ self.enc_buf += 'msg.{}{}[{:d}] = 0;\n'.format(self.cc_prefix, key, i+1)
+ self.dec_buf += 'kout << msg.{}{};\n'.format(self.cc_prefix, key)
+ self.assign_and_kout('char *', 'msg.{}{}'.format(self.cc_prefix, key))
+ else:
+ self.cc_encoders += 'bool encode_{}(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)\n'.format(key)
+ self.cc_encoders += '{\n'
+ self.cc_encoders += 'if (!pb_encode_tag_for_field(stream, field)) return false;\n'
+ self.cc_encoders += 'return pb_encode_string(stream, (uint8_t*)"{}", {:d});\n'.format(value, len(value))
+ self.cc_encoders += '}\n'
+ self.enc_buf += 'msg.{}{}.funcs.encode = encode_{};\n'.format(self.cc_prefix, key, key)
+ self.dec_buf += '// TODO decode string {}{} via callback\n'.format(self.cc_prefix, key)
+ self.dec_buf1 += '// TODO decode string {}{} via callback\n'.format(self.cc_prefix, key)
+ elif fieldtype == dict:
+ if cardinality == 'optional':
+ self.enc_buf += 'msg.{}has_{} = true;\n'.format(self.cc_prefix, key)
+ # The rest is handled recursively in add_to_dict
+ elif type(value) == list:
+ for i, elem in enumerate(value):
+ self.enc_buf += 'msg.{}{}[{:d}] = {};\n'.format(self.cc_prefix, key, i, elem)
+ self.dec_buf += 'kout << msg.{}{}[{:d}];\n'.format(self.cc_prefix, key, i)
+ if fieldtype == float:
+ self.assign_and_kout(self.float_type, 'msg.{}{}[{:d}]'.format(self.cc_prefix, key, i))
+ elif fieldtype == int:
+ self.assign_and_kout(self.int_type, 'msg.{}{}[{:d}]'.format(self.cc_prefix, key, i))
+ elif fieldtype == int:
+ if cardinality == 'optional':
+ self.enc_buf += 'msg.{}has_{} = true;\n'.format(self.cc_prefix, key)
+ self.enc_buf += 'msg.{}{} = {};\n'.format(self.cc_prefix, key, value)
+ self.dec_buf += 'kout << msg.{}{};\n'.format(self.cc_prefix, key)
+ self.assign_and_kout(self.int_type, 'msg.{}{}'.format(self.cc_prefix, key))
+ elif fieldtype == dict:
+ if cardinality == 'optional':
+ self.enc_buf += 'msg.{}has_{} = true;\n'.format(self.cc_prefix, key)
+ self.enc_buf += 'msg.{}{} = {};\n'.format(self.cc_prefix, key, value)
+ self.dec_buf += 'kout << msg.{}{};\n'.format(self.cc_prefix, key)
+ self.assign_and_kout(self.float_type, 'msg.{}{}'.format(self.cc_prefix, key))
+ else:
+ self.note_unsupported(value)
+
+ def get_proto(self):
+ return self.proto_head + '\n\n'.join(self.get_message_definitions('Benchmark'))
+
+ def get_proto_options(self):
+ return self.proto_options
+
+ def get_extra_files(self):
+ return {
+ 'nanopbbench.proto' : self.get_proto(),
+ 'nanopbbench.options' : self.get_proto_options()
+ }
+
+ def get_message_definitions(self, msgname):
+ ret = list(self.sub_protos)
+ ret.append('message {} {{\n'.format(msgname) + self.proto_fields + '}\n')
+ return ret
+
+ def get_encode(self):
+ ret = 'Benchmark msg = Benchmark_init_zero;\n'
+ return ret + self.enc_buf
+
+ def get_cc_functions(self):
+ return self.cc_encoders
+
+ def add_to_dict(self, key, value):
+ if type(value) == str:
+ if len(value) and value[0] == '$':
+ self.add_field(self.cardinality, int, key, value[1:])
+ else:
+ self.add_field(self.cardinality, str, key, value)
+ elif type(value) == list:
+ self.add_field('repeated', type(value[0]), key, value)
+ elif type(value) == dict:
+ nested_proto = NanoPB(
+ value, max_string_length = self.max_strlen, cardinality = self.cardinality, use_maps = self.use_maps, cc_prefix =
+ '{}{}.'.format(self.cc_prefix, key), name = key.capitalize(),
+ int_type = self.int_type, float_type = self.float_type,
+ dec_index = self.dec_index)
+ self.sub_protos.extend(nested_proto.get_message_definitions(key.capitalize()))
+ self.proto_options += nested_proto.proto_options
+ self.cc_encoders += nested_proto.cc_encoders
+ self.add_field(self.cardinality, dict, key, value)
+ self.enc_buf += nested_proto.enc_buf
+ self.dec_buf += nested_proto.dec_buf
+ self.dec_buf0 += nested_proto.dec_buf0
+ self.dec_buf1 += nested_proto.dec_buf1
+ self.dec_buf2 += nested_proto.dec_buf2
+ self.dec_index = nested_proto.dec_index
+ else:
+ self.add_field(self.cardinality, type(value), key, value)
+
+ def from_json(self, data):
+ if type(data) == dict:
+ for key in sorted(data.keys()):
+ self.add_to_dict(key, data[key])
+
+
+
+class UBJ(DummyProtocol):
+
+ def __init__(self, data, max_serialized_bytes = 255, int_type = 'uint16_t', float_type = 'float'):
+ super().__init__()
+ self.data = data
+ self.max_serialized_bytes = self.get_serialized_length() + 2
+ self.int_type = int_type
+ self.float_type = self.parse_float_type(float_type)
+ self.enc_buf += 'ubjw_context_t* ctx = ubjw_open_memory(buf, buf + sizeof(buf));\n'
+ self.enc_buf += 'ubjw_begin_object(ctx, UBJ_MIXED, 0);\n'
+ self.from_json('root', data)
+ self.enc_buf += 'ubjw_end(ctx);\n'
+
+ def get_serialized_length(self):
+ return len(ubjson.dumpb(self.data))
+
+ def is_ascii(self):
+ return False
+
+ def parse_float_type(self, float_type):
+ if float_type == 'float':
+ self.float_bits = 32
+ else:
+ self.float_bits = 64
+ return float_type
+
+ def get_buffer_declaration(self):
+ ret = 'uint8_t buf[{:d}];\n'.format(self.max_serialized_bytes)
+ ret += 'uint16_t serialized_size;\n'
+ return ret
+
+ def get_buffer_name(self):
+ return 'buf'
+
+ def get_length_var(self):
+ return 'serialized_size'
+
+ def get_serialize(self):
+ return 'serialized_size = ubjw_close_context(ctx);\n'
+
+ def get_encode(self):
+ return self.enc_buf
+
+ def get_deserialize(self):
+ ret = 'ubjr_context_t* ctx = ubjr_open_memory(buf, buf + serialized_size);\n'
+ ret += 'ubjr_dynamic_t dynamic_root = ubjr_read_dynamic(ctx);\n'
+ ret += 'ubjr_dynamic_t* root_values = (ubjr_dynamic_t*)dynamic_root.container_object.values;\n'
+ return ret
+
+ def get_decode_and_output(self):
+ ret = 'kout << dec << "dec:";\n'
+ ret += self.dec_buf
+ ret += 'kout << endl;\n'
+ ret += 'ubjr_cleanup_dynamic(&dynamic_root);\n' # This causes the data (including all strings) to be free'd
+ ret += 'ubjr_close_context(ctx);\n'
+ return ret
+
+ def get_decode_vars(self):
+ return self.dec_buf0
+
+ def get_decode(self):
+ return self.dec_buf1
+
+ def get_decode_output(self):
+ ret = 'kout << dec << "dec:";\n' + self.dec_buf2 + 'kout << endl;\n'
+ ret += 'ubjr_cleanup_dynamic(&dynamic_root);\n'
+ ret += 'ubjr_close_context(ctx);\n'
+ return ret
+
+ def add_to_list(self, root, index, value):
+ if type(value) == str:
+ if len(value) and value[0] == '$':
+ self.enc_buf += 'ubjw_write_integer(ctx, {});\n'.format(value[1:])
+ self.dec_buf += 'kout << {}_values[{:d}].integer;\n'.format(root, index)
+ self.assign_and_kout(self.int_type, '{}_values[{:d}].integer'.format(root, index))
+ else:
+ self.enc_buf += 'ubjw_write_string(ctx, "{}");\n'.format(value)
+ self.dec_buf += 'kout << {}_values[{:d}].string;\n'.format(root, index)
+ self.assign_and_kout('char *', '{}_values[{:d}].string'.format(root, index))
+
+ elif type(value) == list:
+ self.enc_buf += 'ubjw_begin_array(ctx, UBJ_MIXED, 0);\n'.format(value)
+ self.dec_buf += '// decoding nested lists is not supported\n'
+ self.dec_buf1 += '// decoding nested lists is not supported\n'
+ self.from_json(root, value)
+ self.enc_buf += 'ubjw_end(ctx);\n'
+
+ elif type(value) == dict:
+ self.enc_buf += 'ubjw_begin_object(ctx, UBJ_MIXED, 0);\n'.format(value)
+ self.dec_buf += '// decoding objects in lists is not supported\n'
+ self.dec_buf1 += '// decoding objects in lists is not supported\n'
+ self.from_json(root, value)
+ self.enc_buf += 'ubjw_end(ctx);\n'
+
+ elif type(value) == float:
+ self.enc_buf += 'ubjw_write_float{:d}(ctx, {});\n'.format(self.float_bits, value)
+ self.dec_buf += 'kout << {}_values[{:d}].real;\n'.format(root, index)
+ self.assign_and_kout(self.float_type, '{}_values[{:d}].real'.format(root, index))
+
+ elif type(value) == int:
+ self.enc_buf += 'ubjw_write_integer(ctx, {});\n'.format(value)
+ self.dec_buf += 'kout << {}_values[{:d}].integer;\n'.format(root, index)
+ self.assign_and_kout(self.int_type, '{}_values[{:d}].integer'.format(root, index))
+
+ else:
+ raise TypeError('Cannot handle {} of type {}'.format(value, type(value)))
+
+ def add_to_dict(self, root, index, key, value):
+ if type(value) == str:
+ if len(value) and value[0] == '$':
+ self.enc_buf += 'ubjw_write_key(ctx, "{}"); ubjw_write_integer(ctx, {});\n'.format(key, value[1:])
+ self.dec_buf += 'kout << {}_values[{:d}].integer;\n'.format(root, index)
+ self.assign_and_kout(self.int_type, '{}_values[{:d}].integer'.format(root, index))
+ else:
+ self.enc_buf += 'ubjw_write_key(ctx, "{}"); ubjw_write_string(ctx, "{}");\n'.format(key, value)
+ self.dec_buf += 'kout << {}_values[{:d}].string;\n'.format(root, index)
+ self.assign_and_kout('char *', '{}_values[{:d}].string'.format(root, index))
+
+ elif type(value) == list:
+ self.enc_buf += 'ubjw_write_key(ctx, "{}"); ubjw_begin_array(ctx, UBJ_MIXED, 0);\n'.format(key)
+ self.dec_buf += 'ubjr_dynamic_t *{}_values = (ubjr_dynamic_t*){}_values[{:d}].container_array.values;\n'.format(
+ key, root, index)
+ self.dec_buf1 += 'ubjr_dynamic_t *{}_values = (ubjr_dynamic_t*){}_values[{:d}].container_array.values;\n'.format(
+ key, root, index)
+ self.from_json(key, value)
+ self.enc_buf += 'ubjw_end(ctx);\n'
+
+ elif type(value) == dict:
+ self.enc_buf += 'ubjw_write_key(ctx, "{}"); ubjw_begin_object(ctx, UBJ_MIXED, 0);\n'.format(key)
+ self.dec_buf += 'ubjr_dynamic_t *{}_values = (ubjr_dynamic_t*){}_values[{:d}].container_object.values;\n'.format(
+ key, root, index)
+ self.dec_buf1 += 'ubjr_dynamic_t *{}_values = (ubjr_dynamic_t*){}_values[{:d}].container_object.values;\n'.format(
+ key, root, index)
+ self.from_json(key, value)
+ self.enc_buf += 'ubjw_end(ctx);\n'
+
+ elif type(value) == float:
+ self.enc_buf += 'ubjw_write_key(ctx, "{}"); ubjw_write_float{:d}(ctx, {});\n'.format(key, self.float_bits, value)
+ self.dec_buf += 'kout << {}_values[{:d}].real;\n'.format(root, index)
+ self.assign_and_kout(self.float_type, '{}_values[{:d}].real'.format(root, index))
+
+ elif type(value) == int:
+ self.enc_buf += 'ubjw_write_key(ctx, "{}"); ubjw_write_integer(ctx, {});\n'.format(key, value)
+ self.dec_buf += 'kout << {}_values[{:d}].integer;\n'.format(root, index)
+ self.assign_and_kout(self.int_type, '{}_values[{:d}].integer'.format(root, index))
+
+ else:
+ raise TypeError('Cannot handle {} of type {}'.format(value, type(value)))
+
+ def from_json(self, root, data):
+ if type(data) == dict:
+ keys = sorted(data.keys())
+ for i, key in enumerate(keys):
+ self.add_to_dict(root, i, key, data[key])
+ elif type(data) == list:
+ for i, elem in enumerate(data):
+ self.add_to_list(root, i, elem)
+
+
+class XDR(DummyProtocol):
+
+ def __init__(self, data, max_serialized_bytes = 256, int_type = 'uint16_t', float_type = 'float'):
+ super().__init__()
+ self.data = data
+ self.max_serialized_bytes = 256
+ self.enc_int_type = int_type
+ self.dec_int_type = self.parse_int_type(int_type)
+ self.float_type = self.parse_float_type(float_type)
+ self.enc_buf += 'BufferOutput<XDRStream> xdrstream(buf);\n'
+ self.dec_buf += 'XDRInput xdrinput(buf);\n'
+ self.dec_buf0 += 'XDRInput xdrinput(buf);\n'
+ # By default, XDR does not even include a version / protocol specifier.
+ # This seems rather impractical -> emulate that here.
+ self.enc_buf += 'xdrstream << (uint32_t)22075;\n'
+ self.dec_buf += 'char strbuf[16];\n'
+ self.dec_buf += 'xdrinput.get_uint32();\n'
+ self.dec_buf0 += 'char strbuf[16];\n'
+ self.dec_buf0 += 'xdrinput.get_uint32();\n'
+ self.from_json(data)
+
+ def is_ascii(self):
+ return False
+
+ def parse_int_type(self, int_type):
+ sign = ''
+ if int_type[0] == 'u':
+ sign = 'u'
+ if '64' in int_type:
+ self.int_bits = 64
+ return sign + 'int64'
+ else:
+ self.int_bits = 32
+ return sign + 'int32'
+
+ def parse_float_type(self, float_type):
+ if float_type == 'float':
+ self.float_bits = 32
+ else:
+ self.float_bits = 64
+ return float_type
+
+ def get_buffer_declaration(self):
+ ret = 'uint16_t serialized_size;\n'
+ ret += 'char buf[{:d}];\n'.format(self.max_serialized_bytes)
+ return ret
+
+ def get_buffer_name(self):
+ return 'buf'
+
+ def get_length_var(self):
+ return 'xdrstream.size()'
+
+ def get_encode(self):
+ return self.enc_buf
+
+ def get_decode_and_output(self):
+ return 'kout << dec << "dec:";\n' + self.dec_buf + 'kout << endl;\n'
+
+ def get_decode_vars(self):
+ return self.dec_buf0
+
+ def get_decode(self):
+ return self.dec_buf1
+
+ def get_decode_output(self):
+ return 'kout << dec << "dec:";\n' + self.dec_buf2 + 'kout << endl;\n';
+
+ def from_json(self, data):
+ if type(data) == dict:
+ for key in sorted(data.keys()):
+ self.from_json(data[key])
+ elif type(data) == list:
+ #self.enc_buf += 'xdrstream.setNextArrayLen({});\n'.format(len(data))
+ #self.enc_buf += 'xdrstream << variable;\n'
+ self.enc_buf += 'xdrstream << (uint32_t){:d};\n'.format(len(data))
+ self.dec_buf += 'xdrinput.get_uint32();\n'
+ self.dec_buf1 += 'xdrinput.get_uint32();\n'
+ for elem in data:
+ self.from_json(elem)
+ elif type(data) == str:
+ if len(data) and data[0] == '$':
+ self.enc_buf += 'xdrstream << ({}){};\n'.format(self.enc_int_type, data[1:])
+ self.dec_buf += 'kout << xdrinput.get_{}();\n'.format(self.dec_int_type)
+ self.dec_buf0 += '{} dec_{};\n'.format(self.enc_int_type, self.dec_index)
+ self.dec_buf1 += 'dec_{} = xdrinput.get_{}();;\n'.format(self.dec_index, self.dec_int_type)
+ self.dec_buf2 += 'kout << dec_{};\n'.format(self.dec_index)
+ else:
+ # Kodierte Strings haben nicht immer ein Nullbyte am Ende
+ self.enc_buf += 'xdrstream.setNextArrayLen({});\n'.format(len(data))
+ self.enc_buf += 'xdrstream << variable << "{}";\n'.format(data)
+ self.dec_buf += 'xdrinput.get_string(strbuf);\n'
+ self.dec_buf += 'kout << strbuf;\n'
+ self.dec_buf1 += 'xdrinput.get_string(strbuf);\n'.format(self.dec_index)
+ self.dec_buf2 += 'kout << strbuf;\n'.format(self.dec_index)
+ elif type(data) == float:
+ self.enc_buf += 'xdrstream << ({}){};\n'.format(self.float_type, data)
+ self.dec_buf += 'kout << xdrinput.get_{}();\n'.format(self.float_type)
+ self.dec_buf0 += '{} dec_{};\n'.format(self.float_type, self.dec_index)
+ self.dec_buf1 += 'dec_{} = xdrinput.get_{}();\n'.format(self.dec_index, self.float_type)
+ self.dec_buf2 += 'kout << dec_{};\n'.format(self.dec_index)
+ elif type(data) == int:
+ self.enc_buf += 'xdrstream << ({}){};\n'.format(self.enc_int_type, data)
+ self.dec_buf += 'kout << xdrinput.get_{}();\n'.format(self.dec_int_type)
+ self.dec_buf0 += '{} dec_{};\n'.format(self.enc_int_type, self.dec_index)
+ self.dec_buf1 += 'dec_{} = xdrinput.get_{}();\n'.format(self.dec_index, self.dec_int_type)
+ self.dec_buf2 += 'kout << dec_{};\n'.format(self.dec_index)
+ else:
+ self.enc_buf += 'xdrstream << {};\n'.format(data)
+ self.dec_buf += '// unsupported type {} of {}\n'.format(type(data), data)
+ self.dec_buf1 += '// unsupported type {} of {}\n'.format(type(data), data)
+ self.dec_index += 1;
+
+class Benchmark:
+
+ def __init__(self, logfile):
+ self.logfile = logfile
+
+ def log(self, arch, library, library_options, bench_name, bench_index, data, key, value = None, error = None):
+ if not library_options:
+ library_options = []
+ libkey = '{}:{}:{}'.format(arch, library, ','.join(library_options))
+ # JSON does not differentiate between int and str keys -> always use
+ # str(bench_index)
+ bench_index = str(bench_index)
+ with FileLock(self.logfile + '.lock'):
+ if os.path.exists(self.logfile):
+ with open(self.logfile, 'rb') as f:
+ benchmark_data = ubjson.load(f)
+ else:
+ benchmark_data = {}
+ if not libkey in benchmark_data:
+ benchmark_data[libkey] = dict()
+ if not bench_name in benchmark_data[libkey]:
+ benchmark_data[libkey][bench_name] = dict()
+ if not bench_index in benchmark_data[libkey][bench_name]:
+ benchmark_data[libkey][bench_name][bench_index] = dict()
+ this_result = benchmark_data[libkey][bench_name][bench_index]
+ # data is unset for log(...) calls from postprocessing
+ if data != None:
+ this_result['data'] = data
+ if value != None:
+ this_result[key] = {
+ 'v' : value
+ }
+ print('{} {} {} ({}) :: {} -> {}'.format(
+ libkey, bench_name, bench_index, data, key, value))
+ else:
+ this_result[key] = {
+ 'e' : error
+ }
+ print('{} {} {} ({}) :: {} -> [E] {}'.format(
+ libkey, bench_name, bench_index, data, key, error))
+ with open(self.logfile, 'wb') as f:
+ ubjson.dump(benchmark_data, f)
+
+ def get_snapshot(self):
+ with FileLock(self.logfile + '.lock'):
+ if os.path.exists(self.logfile):
+ with open(self.logfile, 'rb') as f:
+ benchmark_data = ubjson.load(f)
+ else:
+ benchmark_data = {}
+ return benchmark_data