From 272eebbbcd74c03dbdf66f96121115bb7f9a2f32 Mon Sep 17 00:00:00 2001 From: yang-g Date: Wed, 8 Nov 2017 15:25:51 -0800 Subject: Only allocate what we need in the last slice for proto serialization --- test/cpp/codegen/proto_utils_test.cc | 110 +++++++++++++++++++++++++++++++---- 1 file changed, 98 insertions(+), 12 deletions(-) (limited to 'test/cpp/codegen') diff --git a/test/cpp/codegen/proto_utils_test.cc b/test/cpp/codegen/proto_utils_test.cc index fd05c90e9d..ba89b299ef 100644 --- a/test/cpp/codegen/proto_utils_test.cc +++ b/test/cpp/codegen/proto_utils_test.cc @@ -16,15 +16,16 @@ * */ +#include #include #include +#include +#include #include namespace grpc { namespace internal { -static GrpcLibraryInitializer g_gli_initializer; - // Provide access to GrpcBufferWriter internals. class GrpcBufferWriterPeer { public: @@ -44,35 +45,120 @@ class ProtoUtilsTest : public ::testing::Test {}; // GrpcBufferWriter Next()/Backup() invocations could result in a dangling // pointer returned by Next() due to the interaction between grpc_slice inlining // and GRPC_SLICE_START_PTR. -TEST_F(ProtoUtilsTest, BackupNext) { - // Ensure the GrpcBufferWriter internals are initialized. - g_gli_initializer.summon(); - +TEST_F(ProtoUtilsTest, TinyBackupThenNext) { grpc_byte_buffer* bp; - GrpcBufferWriter writer(&bp, 8192); + const int block_size = 1024; + GrpcBufferWriter writer(&bp, block_size, 8192); GrpcBufferWriterPeer peer(&writer); void* data; int size; // Allocate a slice. ASSERT_TRUE(writer.Next(&data, &size)); - EXPECT_EQ(8192, size); - // Return a single byte. Before the fix that this test acts as a regression - // for, this would have resulted in an inlined backup slice. + EXPECT_EQ(block_size, size); + // Return a single byte. writer.BackUp(1); - EXPECT_TRUE(!peer.have_backup()); - // On the next allocation, the slice is non-inlined. + EXPECT_FALSE(peer.have_backup()); + // On the next allocation, the returned slice is non-inlined. ASSERT_TRUE(writer.Next(&data, &size)); EXPECT_TRUE(peer.slice().refcount != NULL); + EXPECT_EQ(block_size, size); // Cleanup. g_core_codegen_interface->grpc_byte_buffer_destroy(bp); } +namespace { + +// Set backup_size to 0 to indicate no backup is needed. +void BufferWriterTest(int block_size, int total_size, int backup_size) { + grpc_byte_buffer* bp; + GrpcBufferWriter writer(&bp, block_size, total_size); + + int written_size = 0; + void* data; + int size = 0; + bool backed_up_entire_slice = false; + + while (written_size < total_size) { + EXPECT_TRUE(writer.Next(&data, &size)); + EXPECT_GT(size, 0); + EXPECT_TRUE(data); + int write_size = size; + bool should_backup = false; + if (backup_size > 0 && size > backup_size) { + write_size = size - backup_size; + should_backup = true; + } else if (size == backup_size && !backed_up_entire_slice) { + // only backup entire slice once. + backed_up_entire_slice = true; + should_backup = true; + write_size = 0; + } + // May need a last backup. + if (write_size + written_size > total_size) { + write_size = total_size - written_size; + should_backup = true; + backup_size = size - write_size; + ASSERT_GT(backup_size, 0); + } + for (int i = 0; i < write_size; i++) { + ((uint8_t*)data)[i] = written_size % 128; + written_size++; + } + if (should_backup) { + writer.BackUp(backup_size); + } + } + EXPECT_EQ(grpc_byte_buffer_length(bp), (size_t)total_size); + + grpc_byte_buffer_reader reader; + grpc_byte_buffer_reader_init(&reader, bp); + int read_bytes = 0; + while (read_bytes < total_size) { + grpc_slice s; + EXPECT_TRUE(grpc_byte_buffer_reader_next(&reader, &s)); + for (size_t i = 0; i < GRPC_SLICE_LENGTH(s); i++) { + EXPECT_EQ(GRPC_SLICE_START_PTR(s)[i], read_bytes % 128); + read_bytes++; + } + grpc_slice_unref(s); + } + EXPECT_EQ(read_bytes, total_size); + grpc_byte_buffer_reader_destroy(&reader); + grpc_byte_buffer_destroy(bp); +} + +TEST(WriterTest, TinyBlockTinyBackup) { + for (int i = 2; i < (int)GRPC_SLICE_INLINED_SIZE; i++) { + BufferWriterTest(i, 256, 1); + } +} + +TEST(WriterTest, SmallBlockTinyBackup) { BufferWriterTest(64, 256, 1); } + +TEST(WriterTest, SmallBlockNoBackup) { BufferWriterTest(64, 256, 0); } + +TEST(WriterTest, SmallBlockFullBackup) { BufferWriterTest(64, 256, 64); } + +TEST(WriterTest, LargeBlockTinyBackup) { BufferWriterTest(4096, 8192, 1); } + +TEST(WriterTest, LargeBlockNoBackup) { BufferWriterTest(4096, 8192, 0); } + +TEST(WriterTest, LargeBlockFullBackup) { BufferWriterTest(4096, 8192, 4096); } + +TEST(WriterTest, LargeBlockLargeBackup) { BufferWriterTest(4096, 8192, 4095); } + +} // namespace } // namespace internal } // namespace grpc int main(int argc, char** argv) { + // Ensure the GrpcBufferWriter internals are initialized. + grpc::internal::GrpcLibraryInitializer init; + init.summon(); + grpc::GrpcLibraryCodegen lib; + ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } -- cgit v1.2.3