Skip to content

Commit f63ba6f

Browse files
TocarIPcopybara-github
authored andcommitted
Optimize TcParser::RepeatedVarint
We spend more time on reallocating than parsing, so count and preallocate space once. Saves some cpu and a lot or RAM. name cpu/op cpu/op vs base BM_Parse_MemberParseFromString 748.7n ± 3% 682.3n ± 1% -8.87% (p=0.002 n=6) BM_Parse_RiegeliParseFromString 749.0n ± 3% 680.5n ± 1% -9.15% (p=0.002 n=6) BM_Parse_RiegeliParseFromChain 758.7n ± 3% 691.8n ± 8% -8.82% (p=0.002 n=6) BM_Parse_MemberParseFromCord 767.2n ± 4% 701.6n ± 4% -8.55% (p=0.002 n=6) BM_Parse_RiegeliParseFromCord 765.9n ± 3% 704.0n ± 2% -8.08% (p=0.002 n=6) name peak-mem(Bytes)/op peak-mem(Bytes)/op vs base BM_Parse_MemberParseFromString 3.072k ± 0% 1.792k ± 0% -41.67% (p=0.002 n=6) BM_Parse_RiegeliParseFromString 3.072k ± 0% 1.792k ± 0% -41.67% (p=0.002 n=6) BM_Parse_RiegeliParseFromChain 3.072k ± 0% 1.792k ± 0% -41.67% (p=0.002 n=6) BM_Parse_MemberParseFromCord 3.072k ± 0% 1.792k ± 0% -41.67% (p=0.002 n=6) BM_Parse_RiegeliParseFromCord 3.072k ± 0% 1.792k ± 0% -41.67% (p=0.002 n=6 PiperOrigin-RevId: 819415796
1 parent f60dc49 commit f63ba6f

File tree

1 file changed

+25
-6
lines changed

1 file changed

+25
-6
lines changed

src/google/protobuf/generated_message_tctable_lite.cc

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,20 +1157,39 @@ PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedVarint(
11571157
}
11581158
SetCachedHasBitForRepeated(hasbits, data.hasbit_idx());
11591159
auto& field = RefAt<RepeatedField<FieldType>>(msg, data.offset());
1160-
Arena* arena = msg->GetArena();
11611160
const auto expected_tag = UnalignedLoad<TagType>(ptr);
1161+
// Count the number of varint (same as number of bytes with 0 in top bit)
1162+
// and preallocte space in repeated field.
1163+
int len = 0;
1164+
auto ptr2 = ptr;
1165+
do {
1166+
ptr2 += sizeof(TagType);
1167+
// Defend against overflowing avaible data due to malformed input of
1168+
// infinite number of bytes with top bit set. Longest legal varin is 10
1169+
// bytes, which is also < 16 bytes of slop.
1170+
int limit = 10;
1171+
while ((*ptr2 & 0x80) && limit--) ptr2++;
1172+
len++;
1173+
ptr2++;
1174+
if (ABSL_PREDICT_FALSE(!ctx->DataAvailable(ptr2))) break;
1175+
} while (UnalignedLoadNoPrefetch<TagType>(ptr2) == expected_tag);
1176+
int added = 0;
1177+
field.Reserve(field.size() + len);
1178+
// Allows us to skip SOO checks.
1179+
FieldType* x = field.AddNAlreadyReserved(len);
11621180
do {
1181+
ABSL_DCHECK(ctx->DataAvailable(ptr));
1182+
ABSL_DCHECK_EQ(UnalignedLoadNoPrefetch<TagType>(ptr), expected_tag);
11631183
ptr += sizeof(TagType);
11641184
FieldType tmp;
11651185
ptr = ParseVarint(ptr, &tmp);
11661186
if (ABSL_PREDICT_FALSE(ptr == nullptr)) {
11671187
PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
11681188
}
1169-
field.AddWithArena(arena, ZigZagDecodeHelper<FieldType, zigzag>(tmp));
1170-
if (ABSL_PREDICT_FALSE(!ctx->DataAvailable(ptr))) {
1171-
PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
1172-
}
1173-
} while (UnalignedLoad<TagType>(ptr) == expected_tag);
1189+
added++;
1190+
*x = (ZigZagDecodeHelper<FieldType, zigzag>(tmp));
1191+
x++;
1192+
} while (added < len);
11741193
PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
11751194
}
11761195

0 commit comments

Comments
 (0)