From 6d6b63c4701558ffe15f89de05773aa414ab1ff7 Mon Sep 17 00:00:00 2001 From: Jiawei Shao Date: Thu, 2 Dec 2021 07:29:41 +0000 Subject: [PATCH] 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 Reviewed-by: Austin Eng Commit-Queue: Jiawei Shao --- generator/dawn_json_generator.py | 4 +++ generator/templates/dawn_wire/WireCmd.cpp | 41 ++++++++++++++++------- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/generator/dawn_json_generator.py b/generator/dawn_json_generator.py index 034ad39852..b5babdb186 100644 --- a/generator/dawn_json_generator.py +++ b/generator/dawn_json_generator.py @@ -84,6 +84,7 @@ class Type: self.dict_name = name self.name = Name(name, native=native) self.category = json_data['category'] + self.is_wire_transparent = False EnumValue = namedtuple('EnumValue', ['name', 'value', 'valid', 'json_data']) @@ -113,6 +114,7 @@ class EnumType(Type): raise Exception("Duplicate value {} in enum {}".format( value.value, name)) all_values.add(value.value) + self.is_wire_transparent = True BitmaskValue = namedtuple('BitmaskValue', ['name', 'value', 'json_data']) @@ -128,6 +130,7 @@ class BitmaskType(Type): self.full_mask = 0 for value in self.values: self.full_mask = self.full_mask | value.value + self.is_wire_transparent = True class CallbackType(Type): @@ -145,6 +148,7 @@ class TypedefType(Type): class NativeType(Type): def __init__(self, is_enabled, name, json_data): Type.__init__(self, name, json_data, native=True) + self.is_wire_transparent = True # Methods and structures are both "records", so record members correspond to diff --git a/generator/templates/dawn_wire/WireCmd.cpp b/generator/templates/dawn_wire/WireCmd.cpp index 7df87c996e..b0570d0546 100644 --- a/generator/templates/dawn_wire/WireCmd.cpp +++ b/generator/templates/dawn_wire/WireCmd.cpp @@ -269,12 +269,18 @@ {{member_transfer_type(member)}}* memberBuffer; WIRE_TRY(buffer->NextN(memberLength, &memberBuffer)); - //* 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]" )}} - } + {% 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 + //* 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 %} return WireResult::Success; @@ -392,12 +398,23 @@ record->{{memberName}} = copiedMembers; {% endif %} - //* 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]")}} - } + {% 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(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 %}