diff options
author | erikchen <erikchen@chromium.org> | 2015-11-24 10:28:48 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-11-24 18:29:46 +0000 |
commit | e50acd8893ed6898bc5767ae6fd9859493be3a0d (patch) | |
tree | fa9243513287cb9c0a34dbf0c2445e114140fe2b /ipc | |
parent | 8bea8800993569264106223337a53ec02001b342 (diff) | |
download | chromium_src-e50acd8893ed6898bc5767ae6fd9859493be3a0d.zip chromium_src-e50acd8893ed6898bc5767ae6fd9859493be3a0d.tar.gz chromium_src-e50acd8893ed6898bc5767ae6fd9859493be3a0d.tar.bz2 |
reland 1: Add basic memory usage tests for attachment brokering.
One of the assumptions of the newly added tests was violated under a sanitizer
build. This is not particularly surprising, so I disabled that check for
sanitizer builds.
> I added two tests for memory leaks in the attachment brokering process. The
> first checks memory usage after brokering a single, large, shared memory object.
> The second checks memory usage after brokering a thousand, smaller memory
> objects.
>
> BUG=557387
> Committed: https://crrev.com/a519e56d03e1f6d69b7475bdd006f5e47b4f581e
> Cr-Commit-Position: refs/heads/master@{#360935}
BUG=557387
Review URL: https://codereview.chromium.org/1464413002
Cr-Commit-Position: refs/heads/master@{#361391}
Diffstat (limited to 'ipc')
-rw-r--r-- | ipc/attachment_broker_mac_unittest.cc | 183 |
1 files changed, 180 insertions, 3 deletions
diff --git a/ipc/attachment_broker_mac_unittest.cc b/ipc/attachment_broker_mac_unittest.cc index 2e370cd..9e2a995 100644 --- a/ipc/attachment_broker_mac_unittest.cc +++ b/ipc/attachment_broker_mac_unittest.cc @@ -5,6 +5,7 @@ #include "build/build_config.h" #include <fcntl.h> +#include <mach/mach_vm.h> #include <sys/mman.h> #include "base/command_line.h" @@ -12,8 +13,12 @@ #include "base/files/scoped_file.h" #include "base/files/scoped_temp_dir.h" #include "base/mac/mac_util.h" +#include "base/mac/mach_logging.h" #include "base/memory/scoped_ptr.h" #include "base/memory/shared_memory.h" +#include "base/strings/string_number_conversions.h" +#include "base/synchronization/spin_wait.h" +#include "base/time/time.h" #include "ipc/attachment_broker_messages.h" #include "ipc/attachment_broker_privileged_mac.h" #include "ipc/attachment_broker_unprivileged_mac.h" @@ -30,6 +35,14 @@ const char kDataBuffer2[] = "The lazy dog and a fox."; const char kDataBuffer3[] = "Two green bears but not a potato."; const char kDataBuffer4[] = "Red potato is best potato."; const std::string g_service_switch_name = "service_name"; +const size_t g_large_message_size = 8 * 1024 * 1024; +const int g_large_message_count = 1000; +const size_t g_medium_message_size = 512 * 1024; + +// Running the message loop is expected to increase the number of resident +// pages. The exact amount is non-deterministic, but for a simple test suite +// like this one, the increase is expected to be less than 1 MB. +const size_t g_expected_memory_increase = 1024 * 1024; enum TestResult { RESULT_UNKNOWN, @@ -37,6 +50,16 @@ enum TestResult { RESULT_FAILURE, }; +mach_vm_size_t GetResidentSize() { + task_basic_info_64 info; + mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT; + kern_return_t kr = task_info(mach_task_self(), TASK_BASIC_INFO_64, + reinterpret_cast<task_info_t>(&info), &count); + MACH_CHECK(kr == KERN_SUCCESS, kr) << "Couldn't get resident size."; + + return info.resident_size; +} + base::mac::ScopedMachSendRight GetMachPortFromBrokeredAttachment( const scoped_refptr<IPC::BrokerableAttachment>& attachment) { if (attachment->GetType() != @@ -418,6 +441,9 @@ class IPCAttachmentBrokerMacTest : public IPCTestBase { void FinalCleanUp() { // There should be no leaked names. + SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE( + base::TimeDelta::FromSeconds(10), + active_names_at_start_ == IPC::GetActiveNameCount()); EXPECT_EQ(active_names_at_start_, IPC::GetActiveNameCount()); // Close the channel so the client's OnChannelError() gets fired. @@ -481,6 +507,12 @@ struct ChildProcessGlobals { // destroyed. scoped_ptr<IPC::AttachmentBrokerPrivilegedMac> broker; base::mac::ScopedMachSendRight server_task_port; + + // Total resident memory before running the message loop. + mach_vm_size_t initial_resident_size; + + // Whether to emit log statements while processing messages. + bool message_logging; }; using OnMessageReceivedCallback = void (*)(IPC::Sender* sender, @@ -510,6 +542,7 @@ scoped_ptr<ChildProcessGlobals> CommonChildProcessSetUp() { new IPC::AttachmentBrokerPrivilegedMac(&globals->port_provider)); globals->port_provider.InsertEntry(getppid(), server_task_port.get()); globals->server_task_port.reset(server_task_port.release()); + globals->message_logging = true; return globals; } @@ -528,17 +561,22 @@ int CommonPrivilegedProcessMain(OnMessageReceivedCallback callback, globals->broker->RegisterCommunicationChannel(channel.get()); CHECK(channel->Connect()); + globals->initial_resident_size = GetResidentSize(); + while (true) { - LOG(INFO) << "Privileged process spinning run loop."; + if (globals->message_logging) + LOG(INFO) << "Privileged process spinning run loop."; base::MessageLoop::current()->Run(); ProxyListener::Reason reason = listener.get_reason(); if (reason == ProxyListener::CHANNEL_ERROR) break; while (listener.has_message()) { - LOG(INFO) << "Privileged process running callback."; + if (globals->message_logging) + LOG(INFO) << "Privileged process running callback."; callback(channel.get(), listener.get_first_message(), globals.get()); - LOG(INFO) << "Privileged process finishing callback."; + if (globals->message_logging) + LOG(INFO) << "Privileged process finishing callback."; listener.pop_first_message(); } } @@ -1152,4 +1190,143 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleToSelfDelayedPort) { "SendSharedMemoryHandleToSelfDelayedPort"); } +// Tests the memory usage characteristics of attachment brokering a single large +// message. This test has the *potential* to be flaky, since it compares +// resident memory at different points in time, and that measurement is +// non-deterministic. +TEST_F(IPCAttachmentBrokerMacTest, MemoryUsageLargeMessage) { + // Mach-based SharedMemory isn't support on OSX 10.6. + if (base::mac::IsOSSnowLeopard()) + return; + + CommonSetUp("MemoryUsageLargeMessage"); + + std::string test_string(g_large_message_size, 'a'); + SendMessage1(test_string); + base::MessageLoop::current()->Run(); + CommonTearDown(); +} + +void MemoryUsageLargeMessageCallback(IPC::Sender* sender, + const IPC::Message& message, + ChildProcessGlobals* globals) { + EXPECT_LE(GetResidentSize(), + globals->initial_resident_size + g_expected_memory_increase); + + base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message)); + scoped_ptr<base::SharedMemory> shared_memory( + MapSharedMemoryHandle(shm, false)); + EXPECT_LE(GetResidentSize(), + globals->initial_resident_size + g_expected_memory_increase); + + char* addr = static_cast<char*>(shared_memory->memory()); + for (size_t i = 0; i < g_large_message_size; i += 1024) { + addr[i] = 'a'; + } + EXPECT_GE(GetResidentSize(), + globals->initial_resident_size + g_large_message_size); + + shared_memory.reset(); +#if !defined(ADDRESS_SANITIZER) && !defined(LEAK_SANITIZER) && \ + !defined(MEMORY_SANITIZER) && !defined(THREAD_SANITIZER) && \ + !defined(UNDEFINED_SANITIZER) + // Under a sanitizer build, releasing memory does not necessarily reduce the + // amount of resident memory. + EXPECT_LE(GetResidentSize(), + globals->initial_resident_size + g_expected_memory_increase); +#endif + + SendControlMessage(sender, true); +} + +MULTIPROCESS_IPC_TEST_CLIENT_MAIN(MemoryUsageLargeMessage) { + return CommonPrivilegedProcessMain(&MemoryUsageLargeMessageCallback, + "MemoryUsageLargeMessage"); +} + +// Tests the memory usage characteristics of attachment brokering many small +// messages. This test has the *potential* to be flaky, since it compares +// resident memory at different points in time, and that measurement is +// non-deterministic. +TEST_F(IPCAttachmentBrokerMacTest, MemoryUsageManyMessages) { + // Mach-based SharedMemory isn't support on OSX 10.6. + if (base::mac::IsOSSnowLeopard()) + return; + + CommonSetUp("MemoryUsageManyMessages"); + + for (int i = 0; i < g_large_message_count; ++i) { + std::string message = base::IntToString(i); + message += '\0'; + size_t end = message.size(); + message.resize(g_medium_message_size); + std::fill(message.begin() + end, message.end(), 'a'); + SendMessage1(message); + + base::MessageLoop::current()->RunUntilIdle(); + } + + if (get_result_listener()->get_result() == RESULT_UNKNOWN) + base::MessageLoop::current()->Run(); + + CommonTearDown(); +} + +void MemoryUsageManyMessagesCallback(IPC::Sender* sender, + const IPC::Message& message, + ChildProcessGlobals* globals) { + static int message_index = 0; + + { + // Map the shared memory, and make sure that its pages are counting towards + // resident size. + base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message)); + scoped_ptr<base::SharedMemory> shared_memory( + MapSharedMemoryHandle(shm, false)); + + char* addr = static_cast<char*>(shared_memory->memory()); + std::string message_string(addr); + int message_int; + ASSERT_TRUE(base::StringToInt(message_string, &message_int)); + ASSERT_EQ(message_index, message_int); + for (size_t i = 0; i < g_medium_message_size; i += 1024) { + addr[i] = 'a'; + } + } + + ++message_index; + + if (message_index == 1) { + // Disable message logging, since it significantly contributes towards total + // memory usage. + LOG(INFO) << "Disable privileged process message logging."; + globals->message_logging = false; + } + + if (message_index == g_large_message_count) { + size_t memory_increase_kb = + (GetResidentSize() - globals->initial_resident_size) / 1024; + LOG(INFO) << "Increase in memory usage in KB: " << memory_increase_kb; + +#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \ + defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \ + defined(UNDEFINED_SANITIZER) + // Under a sanitizer build, releasing memory does not necessarily reduce the + // amount of resident memory. + bool success = true; +#else + // The total increase in resident size should be less than 1MB. The exact + // amount is not deterministic. + bool success = memory_increase_kb < 1024; +#endif + + SendControlMessage(sender, success); + } +} + +MULTIPROCESS_IPC_TEST_CLIENT_MAIN(MemoryUsageManyMessages) { + return CommonPrivilegedProcessMain(&MemoryUsageManyMessagesCallback, + "MemoryUsageManyMessages"); +} + } // namespace |