dawn_wire: Use memcpy in Serializer / Deserializer when possible
This patch uses memcpy to copy the arrays in basic types instead of iterating every elements in a for-loop. In the next step we will copy specific structures with memcpy. With this patch, the performance of dawn_perf_tests BufferUploadPerf.Run/*_WriteBuffer_BufferSize_* with "-w" will be greatly improved (~30%). BUG=chromium:1266727 Change-Id: I7c6fb0fafa63bd6b602eeef8cf2c0ae0cfc7b0be Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/71180 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org> Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
This commit is contained in:
parent
3a036ab698
commit
6d6b63c470
|
@ -84,6 +84,7 @@ class Type:
|
||||||
self.dict_name = name
|
self.dict_name = name
|
||||||
self.name = Name(name, native=native)
|
self.name = Name(name, native=native)
|
||||||
self.category = json_data['category']
|
self.category = json_data['category']
|
||||||
|
self.is_wire_transparent = False
|
||||||
|
|
||||||
|
|
||||||
EnumValue = namedtuple('EnumValue', ['name', 'value', 'valid', 'json_data'])
|
EnumValue = namedtuple('EnumValue', ['name', 'value', 'valid', 'json_data'])
|
||||||
|
@ -113,6 +114,7 @@ class EnumType(Type):
|
||||||
raise Exception("Duplicate value {} in enum {}".format(
|
raise Exception("Duplicate value {} in enum {}".format(
|
||||||
value.value, name))
|
value.value, name))
|
||||||
all_values.add(value.value)
|
all_values.add(value.value)
|
||||||
|
self.is_wire_transparent = True
|
||||||
|
|
||||||
|
|
||||||
BitmaskValue = namedtuple('BitmaskValue', ['name', 'value', 'json_data'])
|
BitmaskValue = namedtuple('BitmaskValue', ['name', 'value', 'json_data'])
|
||||||
|
@ -128,6 +130,7 @@ class BitmaskType(Type):
|
||||||
self.full_mask = 0
|
self.full_mask = 0
|
||||||
for value in self.values:
|
for value in self.values:
|
||||||
self.full_mask = self.full_mask | value.value
|
self.full_mask = self.full_mask | value.value
|
||||||
|
self.is_wire_transparent = True
|
||||||
|
|
||||||
|
|
||||||
class CallbackType(Type):
|
class CallbackType(Type):
|
||||||
|
@ -145,6 +148,7 @@ class TypedefType(Type):
|
||||||
class NativeType(Type):
|
class NativeType(Type):
|
||||||
def __init__(self, is_enabled, name, json_data):
|
def __init__(self, is_enabled, name, json_data):
|
||||||
Type.__init__(self, name, json_data, native=True)
|
Type.__init__(self, name, json_data, native=True)
|
||||||
|
self.is_wire_transparent = True
|
||||||
|
|
||||||
|
|
||||||
# Methods and structures are both "records", so record members correspond to
|
# Methods and structures are both "records", so record members correspond to
|
||||||
|
|
|
@ -269,12 +269,18 @@
|
||||||
{{member_transfer_type(member)}}* memberBuffer;
|
{{member_transfer_type(member)}}* memberBuffer;
|
||||||
WIRE_TRY(buffer->NextN(memberLength, &memberBuffer));
|
WIRE_TRY(buffer->NextN(memberLength, &memberBuffer));
|
||||||
|
|
||||||
//* This loop cannot overflow because it iterates up to |memberLength|. Even if
|
{% if member.type.is_wire_transparent %}
|
||||||
//* memberLength were the maximum integer value, |i| would become equal to it just before
|
memcpy(
|
||||||
//* exiting the loop, but not increment past or wrap around.
|
memberBuffer, record.{{memberName}},
|
||||||
for (decltype(memberLength) i = 0; i < memberLength; ++i) {
|
{{member_transfer_sizeof(member)}} * memberLength);
|
||||||
{{serialize_member(member, "record." + memberName + "[i]", "memberBuffer[i]" )}}
|
{% else %}
|
||||||
}
|
//* This loop cannot overflow because it iterates up to |memberLength|. Even if
|
||||||
|
//* memberLength were the maximum integer value, |i| would become equal to it
|
||||||
|
//* just before exiting the loop, but not increment past or wrap around.
|
||||||
|
for (decltype(memberLength) i = 0; i < memberLength; ++i) {
|
||||||
|
{{serialize_member(member, "record." + memberName + "[i]", "memberBuffer[i]" )}}
|
||||||
|
}
|
||||||
|
{% endif %}
|
||||||
}
|
}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
return WireResult::Success;
|
return WireResult::Success;
|
||||||
|
@ -392,12 +398,23 @@
|
||||||
record->{{memberName}} = copiedMembers;
|
record->{{memberName}} = copiedMembers;
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
//* This loop cannot overflow because it iterates up to |memberLength|. Even if
|
{% if member.type.is_wire_transparent %}
|
||||||
//* memberLength were the maximum integer value, |i| would become equal to it just before
|
//* memcpy is not allowed to copy from volatile objects. However, these arrays
|
||||||
//* exiting the loop, but not increment past or wrap around.
|
//* are just used as plain data, and don't impact control flow. So if the
|
||||||
for (decltype(memberLength) i = 0; i < memberLength; ++i) {
|
//* underlying data were changed while the copy was still executing, we would
|
||||||
{{deserialize_member(member, "memberBuffer[i]", "copiedMembers[i]")}}
|
//* get different data - but it wouldn't cause unexpected downstream effects.
|
||||||
}
|
memcpy(
|
||||||
|
copiedMembers,
|
||||||
|
const_cast<const {{member_transfer_type(member)}}*>(memberBuffer),
|
||||||
|
{{member_transfer_sizeof(member)}} * memberLength);
|
||||||
|
{% else %}
|
||||||
|
//* This loop cannot overflow because it iterates up to |memberLength|. Even if
|
||||||
|
//* memberLength were the maximum integer value, |i| would become equal to it
|
||||||
|
//* just before exiting the loop, but not increment past or wrap around.
|
||||||
|
for (decltype(memberLength) i = 0; i < memberLength; ++i) {
|
||||||
|
{{deserialize_member(member, "memberBuffer[i]", "copiedMembers[i]")}}
|
||||||
|
}
|
||||||
|
{% endif %}
|
||||||
}
|
}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue