attempt at optimizing (535'000 -> 522'268 B)

This commit is contained in:
Samuel Sadok
2020-05-19 22:00:34 +02:00
parent 43a167f9fb
commit fbf5b29606
7 changed files with 109 additions and 67 deletions
+6 -4
View File
@@ -234,11 +234,12 @@ void ASCII_protocol_process_line(const uint8_t* buffer, size_t len, StreamSink&
respond(response_channel, use_checksum, "invalid command format");
} else {
Introspectable property = root_obj.get_child(name, sizeof(name));
if (!property.is_valid()) {
const StringConvertibleTypeInfo* type_info = dynamic_cast<const StringConvertibleTypeInfo*>(property.get_type_info());
if (!type_info) {
respond(response_channel, use_checksum, "invalid property");
} else {
char response[10];
bool success = property.get_string(response, sizeof(response));
bool success = type_info->get_string(property, response, sizeof(response));
if (!success)
respond(response_channel, use_checksum, "not implemented");
else
@@ -254,10 +255,11 @@ void ASCII_protocol_process_line(const uint8_t* buffer, size_t len, StreamSink&
respond(response_channel, use_checksum, "invalid command format");
} else {
Introspectable property = root_obj.get_child(name, sizeof(name));
if (!property.is_valid()) {
const StringConvertibleTypeInfo* type_info = dynamic_cast<const StringConvertibleTypeInfo*>(property.get_type_info());
if (!type_info) {
respond(response_channel, use_checksum, "invalid property");
} else {
bool success = property.set_string(value, sizeof(value));
bool success = type_info->set_string(property, value, sizeof(value));
if (!success)
respond(response_channel, use_checksum, "not implemented");
}
+26 -12
View File
@@ -15,6 +15,9 @@
#include <fibre/introspection.hpp>
#pragma GCC push_options
#pragma GCC optimize ("s")
namespace fibre {
const unsigned char embedded_json[] = [[embedded_endpoint_definitions | to_c_string]];
@@ -22,16 +25,36 @@ const size_t embedded_json_length = sizeof(embedded_json) - 1;
const uint16_t json_crc_ = calc_crc16<CANONICAL_CRC16_POLYNOMIAL>(PROTOCOL_VERSION, embedded_json, embedded_json_length);
const uint32_t json_version_id_ = (json_crc_ << 16) | calc_crc16<CANONICAL_CRC16_POLYNOMIAL>(json_crc_, embedded_json, embedded_json_length);
Introspectable get_property(size_t idx) {
switch (idx) {
[%- for endpoint in endpoints %]
[%- if endpoint.function.name == 'exchange' and endpoint.in_bindings | list == ['obj'] %]
case [[endpoint.id]]: return FibrePropertyTypeInfo<[[endpoint.function.in['obj'].type.c_type]]>::make_introspectable([[endpoint.in_bindings['obj']]]);
[%- endif %]
[%- endfor %]
default: return {};
}
}
// Note: with -Og this function reserves a huge amount of stack space because it
// reserves separate space for the stack frame of each of the inlined functions.
// The minimum known set of flags to prevent this is `-O1 -fipa-sra`.
// `-O2` is a superset of this so that's what we use here.
bool endpoint_handler(int idx, cbufptr_t* input_buffer, bufptr_t* output_buffer) __attribute__ ((optimize(2)));
//bool endpoint_handler(int idx, cbufptr_t* input_buffer, bufptr_t* output_buffer) __attribute__ ((optimize(2)));
bool endpoint_handler(int idx, cbufptr_t* input_buffer, bufptr_t* output_buffer) {
//Introspectable property = get_property(idx);
//if property.is_valid()
switch (idx) {
[%- for endpoint in endpoints %]
[%- if (endpoint.function.name == 'exchange' or endpoint.function.name == 'read') and endpoint.in_bindings | list == ['obj'] %]
//case [[endpoint.id]]: return FibrePropertyTypeInfo<[[endpoint.function.in['obj'].type.c_type]]>::make_introspectable([[endpoint.in_bindings['obj']]]);
case [[endpoint.id]]: { return [[endpoint.function.fullname | to_snake_case]]([% for k, arg in endpoint.function.in.items() %][% if k in endpoint.in_bindings %]static_cast<[[arg.type.c_type]]>([[endpoint.in_bindings[k]]])[% else %]std::nullopt[% endif %], [% endfor %][% for k, arg in endpoint.function.out.items() %][% if k in endpoint.out_bindings %]static_cast<[[arg.type.c_type]]*>([[endpoint.out_bindings[k]]])[% else %]nullptr[% endif %], [% endfor %]input_buffer, output_buffer); } break;
[%- else %]
case [[endpoint.id]]: { return [[endpoint.function.fullname | to_snake_case]]([% for k, arg in endpoint.function.in.items() %][% if k in endpoint.in_bindings %]static_cast<[[arg.type.c_type]]>([[endpoint.in_bindings[k]]])[% else %]std::nullopt[% endif %], [% endfor %][% for k, arg in endpoint.function.out.items() %][% if k in endpoint.out_bindings %]static_cast<[[arg.type.c_type]]*>([[endpoint.out_bindings[k]]])[% else %]nullptr[% endif %], [% endfor %]input_buffer, output_buffer); } break;
[%- endif %]
[%- endfor %]
default: return false;
}
@@ -50,17 +73,6 @@ bool is_endpoint_ref_valid(endpoint_ref_t endpoint_ref) {
}
}
Introspectable get_property(size_t idx) {
switch (idx) {
[%- for endpoint in endpoints %]
[%- if endpoint.function.name == 'exchange' and endpoint.in_bindings | list == ['obj'] %][# //case [[endpoint.id]]: *(decltype([[endpoint.in_bindings['obj']]])*)buf = [[endpoint.in_bindings['obj']]]; break;#]
case [[endpoint.id]]: return FibrePropertyTypeInfo<[[endpoint.function.in['obj'].type.c_type]]>::make_introspectable([[endpoint.in_bindings['obj']]]);
[%- endif %]
[%- endfor %]
default: return {};
}
}
bool set_endpoint_from_float(endpoint_ref_t endpoint_ref, float value) {
if (endpoint_ref.json_crc != json_crc_) {
return false;
@@ -73,4 +85,6 @@ bool set_endpoint_from_float(endpoint_ref_t endpoint_ref, float value) {
}
#pragma GCC pop_options
#endif // __FIBRE_INTERFACES_HPP
@@ -5,12 +5,15 @@
#include <algorithm>
#include <cstring>
#pragma GCC push_options
#pragma GCC optimize ("s")
class TypeInfo;
class Introspectable;
using introspectable_storage_t = std::aligned_storage<16, 4>::type;
struct PropertyInfo {
const char * name;
void(*getter)(Introspectable&);
const TypeInfo* type_info;
};
@@ -29,24 +32,16 @@ public:
TypeInfo(const PropertyInfo* property_table, size_t property_table_length)
: property_table_(property_table), property_table_length_(property_table_length) {}
const PropertyInfo* get_property_info(const char * name, size_t length) const {
for (const PropertyInfo* prop = property_table_; prop < (property_table_ + property_table_length_); ++prop) {
if (!strncmp(name, prop->name, length)) {
return prop;
}
}
return nullptr;
}
virtual introspectable_storage_t get_child(introspectable_storage_t obj, size_t idx) const = 0;
Introspectable get_child(const Introspectable& obj, const char * name, size_t length) const;
protected:
template<typename T> static T& as(Introspectable& obj);
template<typename T> static const T& as(const Introspectable& obj);
template<typename T> static Introspectable make_introspectable(T obj, const TypeInfo* type_info);
private:
virtual bool get_string(const Introspectable& obj, char* buffer, size_t length) const { return false; }
virtual bool set_string(const Introspectable& obj, char* buffer, size_t length) const { return false; }
const PropertyInfo* property_table_;
size_t property_table_length_;
};
@@ -83,13 +78,7 @@ public:
while ((begin < end) && current.type_info_) {
const char * end_of_token = std::find(begin, end, '.');
const PropertyInfo* prop_info = current.type_info_->get_property_info(begin, end_of_token - begin);
if (prop_info) {
(*prop_info->getter)(current);
current.type_info_ = prop_info->type_info;
} else {
current.type_info_ = nullptr;
}
current = current.get_direct_child(begin, end_of_token - begin);
begin = std::min(end, end_of_token + 1);
}
@@ -100,44 +89,38 @@ public:
return type_info_;
}
/**
* @brief Returns the underlying value as a string. This will only succeed
* if this Introspectable contains a Property<...> object.
*/
bool get_string(char* buffer, size_t length) {
return type_info_ && type_info_->get_string(*this, buffer, length);
}
/**
* @brief Sets the underlying value from a string. This will only succeed
* if this Introspectable contains a Property<...> object.
*/
bool set_string(char* buffer, size_t length) {
return type_info_ && type_info_->set_string(*this, buffer, length);
}
const TypeInfo* get_type_info() {
return type_info_;
}
private:
Introspectable get_direct_child(const char * name, size_t length) const {
for (size_t i = 0; i < type_info_->property_table_length_; ++i) {
if (!strncmp(name, type_info_->property_table_[i].name, length)) {
Introspectable result;
result.storage_ = type_info_->get_child(storage_, i);
result.type_info_ = type_info_->property_table_[i].type_info;
return result;
}
}
return {};
}
// We use this storage to hold generic small objects. Usually that's a pointer
// but sometimes it's an on-demand constructed Property<...>.
// Caution: only put objects in here which are trivially copyable, movable
// and destructible as any custom operation wouldn't be called.
unsigned char storage_[12];
introspectable_storage_t storage_;
const TypeInfo* type_info_ = nullptr;
};
template<typename T> T& TypeInfo::as(Introspectable& obj) {
static_assert(sizeof(T) <= sizeof(obj.storage_));
return *(T*)obj.storage_;
return *(T*)&obj.storage_;
}
template<typename T> const T& TypeInfo::as(const Introspectable& obj) {
static_assert(sizeof(T) <= sizeof(obj.storage_));
return *(const T*)obj.storage_;
return *(const T*)&obj.storage_;
}
template<typename T> Introspectable TypeInfo::make_introspectable(T obj, const TypeInfo* type_info) {
Introspectable introspectable;
@@ -154,8 +137,13 @@ template<typename T> struct maybe_underlying_type<T, false> { typedef T type; };
template<typename T> using maybe_underlying_type_t = typename maybe_underlying_type<T>::type;
struct StringConvertibleTypeInfo {
virtual bool get_string(const Introspectable& obj, char* buffer, size_t length) const { return false; }
virtual bool set_string(const Introspectable& obj, char* buffer, size_t length) const { return false; }
};
struct FloatSettableTypeInfo {
//virtual bool get_float(const Introspectable& obj, float* val) const { return false; }
virtual bool set_float(const Introspectable& obj, float val) const { return false; }
};
@@ -166,11 +154,15 @@ struct FibrePropertyTypeInfo;
// readonly property
template<typename T>
struct FibrePropertyTypeInfo<Property<const T>> : TypeInfo {
struct FibrePropertyTypeInfo<Property<const T>> : StringConvertibleTypeInfo, TypeInfo {
using TypeInfo::TypeInfo;
static const PropertyInfo property_table[];
static const FibrePropertyTypeInfo<Property<const T>> singleton;
introspectable_storage_t get_child(introspectable_storage_t obj, size_t idx) const override {
return {};
}
bool get_string(const Introspectable& obj, char* buffer, size_t length) const override {
return to_string(static_cast<maybe_underlying_type_t<T>>(as<const Property<const T>>(obj).read()), buffer, length, 0);
}
@@ -183,12 +175,16 @@ const FibrePropertyTypeInfo<Property<const T>> FibrePropertyTypeInfo<Property<co
// readwrite property
template<typename T>
struct FibrePropertyTypeInfo<Property<T>> : FloatSettableTypeInfo, TypeInfo {
struct FibrePropertyTypeInfo<Property<T>> : FloatSettableTypeInfo, StringConvertibleTypeInfo, TypeInfo {
using TypeInfo::TypeInfo;
static const PropertyInfo property_table[];
static const FibrePropertyTypeInfo<Property<T>> singleton;
static const Introspectable make_introspectable(Property<T> obj) { return TypeInfo::make_introspectable(obj, &singleton); }
introspectable_storage_t get_child(introspectable_storage_t obj, size_t idx) const override {
return {};
}
bool get_string(const Introspectable& obj, char* buffer, size_t length) const override {
return to_string(static_cast<maybe_underlying_type_t<T>>(as<const Property<T>>(obj).read()), buffer, length, 0);
}
@@ -217,4 +213,6 @@ const PropertyInfo FibrePropertyTypeInfo<Property<T>>::property_table[] = {};
template<typename T>
const FibrePropertyTypeInfo<Property<T>> FibrePropertyTypeInfo<Property<T>>::singleton{FibrePropertyTypeInfo<Property<T>>::property_table, sizeof(FibrePropertyTypeInfo<Property<T>>::property_table) / sizeof(FibrePropertyTypeInfo<Property<T>>::property_table[0])};
#pragma GCC pop_options
#endif // __FIBRE_INTROSPECTION_HPP
@@ -566,6 +566,8 @@ template<typename T>
struct Property {
Property(void* ctx, T(*getter)(void*), void(*setter)(void*, T))
: ctx_(ctx), getter_(getter), setter_(setter) {}
Property(T* ctx)
: ctx_(ctx), getter_([](void* ctx){ return *(T*)ctx; }), setter_([](void* ctx, T val){ *(T*)ctx = val; }) {}
Property& operator*() { return *this; }
Property* operator->() { return this; }
@@ -590,6 +592,8 @@ template<typename T>
struct Property<const T> {
Property(void* ctx, T(*getter)(void*))
: ctx_(ctx), getter_(getter) {}
Property(const T* ctx)
: ctx_(const_cast<T*>(ctx)), getter_([](void* ctx){ return *(const T*)ctx; }) {}
Property& operator*() { return *this; }
Property* operator->() { return this; }
+11 -4
View File
@@ -10,6 +10,9 @@
*
*/
#pragma GCC push_options
#pragma GCC optimize ("s")
[%- macro rettype(func) %]
[%- if not func.out -%]
void
@@ -36,13 +39,15 @@ public:
[%- for property in intf.attributes.values() %]
[%- if property.type.fullname.startswith("fibre.Property") %]
[%- if not property.c_setter %]
template<typename T> static auto get_[[property.name]](T* obj) { return [[property.type.c_type]]{obj, [](void* ctx){ return ([[property.type.value_type.c_type]])((T*)ctx)->[[property.c_getter]]; }}; }
[%- if not property.c_getter and not property.c_setter %]
template<typename T> static inline auto get_[[property.name]](T* obj) { return [[property.type.c_type]]{&obj->[[property.c_name]]}; }
[%- elif not property.c_setter %]
template<typename T> static inline auto get_[[property.name]](T* obj) { return [[property.type.c_type]]{obj, [](void* ctx){ return ([[property.type.value_type.c_type]])((T*)ctx)->[[property.c_getter]]; }}; }
[%- else %]
template<typename T> static auto get_[[property.name]](T* obj) { return [[property.type.c_type]]{obj, [](void* ctx){ return ([[property.type.value_type.c_type]])((T*)ctx)->[[property.c_getter]]; }, [](void* ctx, [[property.type.value_type.c_type]] value){ ((T*)ctx)->[[property.c_setter]](value); }}; }
template<typename T> static inline auto get_[[property.name]](T* obj) { return [[property.type.c_type]]{obj, [](void* ctx){ return ([[property.type.value_type.c_type]])((T*)ctx)->[[property.c_getter]]; }, [](void* ctx, [[property.type.value_type.c_type]] value){ ((T*)ctx)->[[property.c_setter]](value); }}; }
[%- endif %]
[%- else %]
template<typename T> static auto get_[[property.name]](T* obj) { return &obj->[[property.c_name]]; }
template<typename T> static inline auto get_[[property.name]](T* obj) { return &obj->[[property.c_name]]; }
[%- endif %]
[%- endfor %]
@@ -80,3 +85,5 @@ inline [[enum.c_type]] operator ~ ([[enum.c_type]] a) { return static_cast<[[enu
[%- endfor %]
#pragma GCC pop_options
+17 -1
View File
@@ -11,6 +11,9 @@
#include <fibre/introspection.hpp>
#pragma GCC push_options
#pragma GCC optimize ("s")
[% for intf in interfaces.values() %][% if not intf.builtin %]
template<typename T>
struct [[intf.fullname | to_pascal_case]]TypeInfo : TypeInfo {
@@ -18,6 +21,17 @@ struct [[intf.fullname | to_pascal_case]]TypeInfo : TypeInfo {
static const PropertyInfo property_table[];
static const [[intf.fullname | to_pascal_case]]TypeInfo<T> singleton;
static Introspectable make_introspectable(T& obj) { return TypeInfo::make_introspectable(&obj, &singleton); }
introspectable_storage_t get_child(introspectable_storage_t obj, size_t idx) const override {
T* ptr = *(T**)&obj;
introspectable_storage_t res;
switch (idx) {
[%- for property in intf.attributes.values() %]
case [[loop.index0]]: *(decltype([[intf.c_type]]::get_[[property.name]](std::declval<T*>()))*)(&res) = [[intf.c_type]]::get_[[property.name]](ptr); break;
[%- endfor %]
}
return res;
}
};
[% endif %][% endfor %]
@@ -25,10 +39,12 @@ struct [[intf.fullname | to_pascal_case]]TypeInfo : TypeInfo {
template<typename T>
const PropertyInfo [[intf.fullname | to_pascal_case]]TypeInfo<T>::property_table[] = {
[%- for property in intf.attributes.values() %]
{"[[property.name]]", [](Introspectable& obj){ as<std::remove_reference_t<decltype([[intf.c_type]]::get_[[property.name]](std::declval<T*>()))>>(obj) = [[intf.c_type]]::get_[[property.name]](as<T*>(obj)); }, &[[(property.type.purename or property.type.fullname) | to_pascal_case]]TypeInfo<std::remove_reference_t<decltype(*[[intf.c_type]]::get_[[property.name]](std::declval<T*>()))>>::singleton},
{"[[property.name]]", &[[(property.type.purename or property.type.fullname) | to_pascal_case]]TypeInfo<std::remove_reference_t<decltype(*[[intf.c_type]]::get_[[property.name]](std::declval<T*>()))>>::singleton},
[%- endfor %]
};
template<typename T>
const [[intf.fullname | to_pascal_case]]TypeInfo<T> [[intf.fullname | to_pascal_case]]TypeInfo<T>::singleton{[[intf.fullname | to_pascal_case]]TypeInfo<T>::property_table, sizeof([[intf.fullname | to_pascal_case]]TypeInfo<T>::property_table) / sizeof([[intf.fullname | to_pascal_case]]TypeInfo<T>::property_table[0])};
[% endif %][% endfor %]
#pragma GCC pop_options
+5 -4
View File
@@ -252,19 +252,20 @@ def regularize_attribute(path, name, elem, c_is_class):
elem['fullname'] = join_name(path, name)
elem['typeargs'] = elem.get('typeargs', {})
elem['c_name'] = elem.get('c_name', None) or (elem['name'] + ('_' if c_is_class else ''))
elem['c_getter'] = elem.get('c_getter', elem['c_name'])
elem['c_setter'] = elem.get('c_setter', elem['c_name'] + ' = ')
if ('c_getter' in elem) or ('c_setter' in elem):
elem['c_getter'] = elem.get('c_getter', elem['c_name'])
elem['c_setter'] = elem.get('c_setter', elem['c_name'] + ' = ')
if isinstance(elem['type'], str) and elem['type'].startswith('readonly '):
elem['typeargs']['fibre.Property.mode'] = 'readonly'
elem['typeargs']['fibre.Property.type'] = elem['type'][len('readonly '):]
elem['type'] = 'fibre.Property'
if elem['typeargs']['fibre.Property.mode'] == 'readonly': elem.pop('c_setter')
if elem['typeargs']['fibre.Property.mode'] == 'readonly' and 'c_setter' in elem: elem.pop('c_setter')
elif ('flags' in elem['type']) or ('values' in elem['type']):
elem['typeargs']['fibre.Property.mode'] = elem['typeargs'].get('fibre.Property.mode', None) or 'readwrite'
elem['typeargs']['fibre.Property.type'] = regularize_valuetype(path, to_pascal_case(name), elem['type'])
elem['type'] = 'fibre.Property'
if elem['typeargs']['fibre.Property.mode'] == 'readonly': elem.pop('c_setter')
if elem['typeargs']['fibre.Property.mode'] == 'readonly' and 'c_setter' in elem: elem.pop('c_setter')
else:
elem['type'] = regularize_interface(path, to_pascal_case(name), elem['type'])
return elem