From 26052616915fe2324755687c7db73d69c521b34d Mon Sep 17 00:00:00 2001 From: "Torne (Richard Coles)" Date: Fri, 2 May 2014 14:57:42 +0100 Subject: [PATCH] Test that relro sharing actually saves memory. Spawn 20 child processes, have them all load the library, and compare the total PSS used in the case where we use dlopen() and the case where we use android_dlopen_ext() with relro sharing. We assume we will save at least 10% of the memory; in practise this example saves 40% or more so this should be a reasonable threshold. Bug: 14299541 Change-Id: Idccf6b8b0eb137abae2200f1ce68fb76b3cbdd75 --- tests/Android.mk | 4 ++ tests/dlext_test.cpp | 123 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) diff --git a/tests/Android.mk b/tests/Android.mk index 9db372ad0..3aef5bb25 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -252,8 +252,12 @@ bionic-unit-tests_ldflags := \ -Wl,--export-dynamic \ -Wl,-u,DlSymTestFunction \ +bionic-unit-tests_c_includes := \ + $(call include-path-for, libpagemap) \ + bionic-unit-tests_shared_libraries_target := \ libdl \ + libpagemap \ module := bionic-unit-tests module_tag := optional diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp index 4b2a5e23c..b56fc4102 100644 --- a/tests/dlext_test.cpp +++ b/tests/dlext_test.cpp @@ -24,8 +24,11 @@ #include #include #include +#include #include +#include + #define ASSERT_DL_NOTNULL(ptr) \ ASSERT_TRUE(ptr != NULL) << "dlerror: " << dlerror() @@ -209,6 +212,8 @@ protected: EXPECT_EQ(4, f()); } + void SpawnChildrenAndMeasurePss(const char* lib, bool share_relro, size_t* pss_out); + android_dlextinfo extinfo_; char relro_file_[PATH_MAX]; }; @@ -230,3 +235,121 @@ TEST_F(DlExtRelroSharingTest, RelroFileEmpty) { ASSERT_NO_FATAL_FAILURE(TryUsingRelro(LIBNAME)); } + +TEST_F(DlExtRelroSharingTest, VerifyMemorySaving) { + ASSERT_NO_FATAL_FAILURE(CreateRelroFile(LIBNAME)); + int relro_fd = open(relro_file_, O_RDONLY); + ASSERT_NOERROR(relro_fd); + extinfo_.flags |= ANDROID_DLEXT_USE_RELRO; + extinfo_.relro_fd = relro_fd; + int pipefd[2]; + ASSERT_NOERROR(pipe(pipefd)); + + size_t without_sharing, with_sharing; + ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(LIBNAME, false, &without_sharing)); + ASSERT_NO_FATAL_FAILURE(SpawnChildrenAndMeasurePss(LIBNAME, true, &with_sharing)); + + // We expect the sharing to save at least 10% of the total PSS. In practice + // it saves 40%+ for this test. + size_t expected_size = without_sharing - (without_sharing/10); + EXPECT_LT(with_sharing, expected_size); +} + +void getPss(pid_t pid, size_t* pss_out) { + pm_kernel_t* kernel; + ASSERT_EQ(0, pm_kernel_create(&kernel)); + + pm_process_t* process; + ASSERT_EQ(0, pm_process_create(kernel, pid, &process)); + + pm_map_t** maps; + size_t num_maps; + ASSERT_EQ(0, pm_process_maps(process, &maps, &num_maps)); + + size_t total_pss = 0; + for (size_t i = 0; i < num_maps; i++) { + pm_memusage_t usage; + ASSERT_EQ(0, pm_map_usage(maps[i], &usage)); + total_pss += usage.pss; + } + *pss_out = total_pss; + + free(maps); + pm_process_destroy(process); + pm_kernel_destroy(kernel); +} + +void DlExtRelroSharingTest::SpawnChildrenAndMeasurePss(const char* lib, bool share_relro, + size_t* pss_out) { + const int CHILDREN = 20; + + // Create children + pid_t childpid[CHILDREN]; + int childpipe[CHILDREN]; + for (int i=0; i