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:
Jiawei Shao 2021-12-02 07:29:41 +00:00 committed by Dawn LUCI CQ
parent 3a036ab698
commit 6d6b63c470
2 changed files with 33 additions and 12 deletions

View File

@ -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

View File

@ -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));
{% if member.type.is_wire_transparent %}
memcpy(
memberBuffer, record.{{memberName}},
{{member_transfer_sizeof(member)}} * memberLength);
{% else %}
//* This loop cannot overflow because it iterates up to |memberLength|. Even if //* 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 //* memberLength were the maximum integer value, |i| would become equal to it
//* exiting the loop, but not increment past or wrap around. //* just before exiting the loop, but not increment past or wrap around.
for (decltype(memberLength) i = 0; i < memberLength; ++i) { for (decltype(memberLength) i = 0; i < memberLength; ++i) {
{{serialize_member(member, "record." + memberName + "[i]", "memberBuffer[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 %}
{% if member.type.is_wire_transparent %}
//* memcpy is not allowed to copy from volatile objects. However, these arrays
//* are just used as plain data, and don't impact control flow. So if the
//* underlying data were changed while the copy was still executing, we would
//* 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 //* 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 //* memberLength were the maximum integer value, |i| would become equal to it
//* exiting the loop, but not increment past or wrap around. //* just before exiting the loop, but not increment past or wrap around.
for (decltype(memberLength) i = 0; i < memberLength; ++i) { for (decltype(memberLength) i = 0; i < memberLength; ++i) {
{{deserialize_member(member, "memberBuffer[i]", "copiedMembers[i]")}} {{deserialize_member(member, "memberBuffer[i]", "copiedMembers[i]")}}
} }
{% endif %}
} }
{% endfor %} {% endfor %}