|  | // Copyright (C) 2021 The Android Open Source Project | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | #include <benchmark/benchmark.h> | 
|  |  | 
|  | #include "perfetto/heap_profile.h" | 
|  | #include "src/profiling/memory/heap_profile_internal.h" | 
|  |  | 
|  | #include "src/profiling/memory/client.h" | 
|  | #include "src/profiling/memory/client_api_factory.h" | 
|  |  | 
|  | namespace perfetto { | 
|  | namespace profiling { | 
|  |  | 
|  | namespace { | 
|  | uint32_t GetHeapId() { | 
|  | static uint32_t heap_id = | 
|  | AHeapProfile_registerHeap(AHeapInfo_create("dev.perfetto.benchmark")); | 
|  | return heap_id; | 
|  | } | 
|  |  | 
|  | ClientConfiguration g_client_config; | 
|  | int g_shmem_fd; | 
|  |  | 
|  | base::UnixSocketRaw& GlobalServerSocket() { | 
|  | static base::UnixSocketRaw* srv_sock = new base::UnixSocketRaw; | 
|  | return *srv_sock; | 
|  | } | 
|  |  | 
|  | void DisconnectGlobalServerSocket() { | 
|  | base::UnixSocketRaw destroy; | 
|  | std::swap(destroy, GlobalServerSocket()); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | // This is called by AHeapProfile_initSession (client_api.cc) to construct a | 
|  | // client. The Client API requires to be linked against another compliation | 
|  | // unit that provides this function. This way, it can be used in different | 
|  | // circumstances (central heapprofd, fork heapprofd) and be agnostic about the | 
|  | // details. This is is used to create a test Client here. | 
|  | void StartHeapprofdIfStatic() {} | 
|  | std::shared_ptr<Client> ConstructClient( | 
|  | UnhookedAllocator<perfetto::profiling::Client> unhooked_allocator) { | 
|  | base::UnixSocketRaw cli_sock; | 
|  | base::UnixSocketRaw& srv_sock = GlobalServerSocket(); | 
|  | std::tie(cli_sock, srv_sock) = base::UnixSocketRaw::CreatePairPosix( | 
|  | base::SockFamily::kUnix, base::SockType::kStream); | 
|  | auto ringbuf = SharedRingBuffer::Create(8 * 1048576); | 
|  | ringbuf->InfiniteBufferForTesting(); | 
|  | PERFETTO_CHECK(ringbuf); | 
|  | PERFETTO_CHECK(cli_sock); | 
|  | PERFETTO_CHECK(srv_sock); | 
|  | g_shmem_fd = ringbuf->fd(); | 
|  | return std::allocate_shared<Client>(unhooked_allocator, std::move(cli_sock), | 
|  | g_client_config, std::move(*ringbuf), | 
|  | getpid(), GetMainThreadStackRange()); | 
|  | } | 
|  |  | 
|  | static void BM_ClientApiOneTenthAllocation(benchmark::State& state) { | 
|  | const uint32_t heap_id = GetHeapId(); | 
|  |  | 
|  | ClientConfiguration client_config{}; | 
|  | client_config.default_interval = 32000; | 
|  | client_config.all_heaps = true; | 
|  | g_client_config = client_config; | 
|  | PERFETTO_CHECK(AHeapProfile_initSession(malloc, free)); | 
|  |  | 
|  | PERFETTO_CHECK(g_shmem_fd); | 
|  | auto ringbuf = SharedRingBuffer::Attach(base::ScopedFile(dup(g_shmem_fd))); | 
|  |  | 
|  | for (auto _ : state) { | 
|  | AHeapProfile_reportAllocation(heap_id, 0x123, 3200); | 
|  | } | 
|  | DisconnectGlobalServerSocket(); | 
|  | ringbuf->SetShuttingDown(); | 
|  | } | 
|  |  | 
|  | BENCHMARK(BM_ClientApiOneTenthAllocation); | 
|  |  | 
|  | static void BM_ClientApiOneHundrethAllocation(benchmark::State& state) { | 
|  | const uint32_t heap_id = GetHeapId(); | 
|  |  | 
|  | ClientConfiguration client_config{}; | 
|  | client_config.default_interval = 32000; | 
|  | client_config.all_heaps = true; | 
|  | g_client_config = client_config; | 
|  | PERFETTO_CHECK(AHeapProfile_initSession(malloc, free)); | 
|  |  | 
|  | PERFETTO_CHECK(g_shmem_fd); | 
|  | auto ringbuf = SharedRingBuffer::Attach(base::ScopedFile(dup(g_shmem_fd))); | 
|  |  | 
|  | for (auto _ : state) { | 
|  | AHeapProfile_reportAllocation(heap_id, 0x123, 320); | 
|  | } | 
|  | DisconnectGlobalServerSocket(); | 
|  | ringbuf->SetShuttingDown(); | 
|  | } | 
|  |  | 
|  | BENCHMARK(BM_ClientApiOneHundrethAllocation); | 
|  |  | 
|  | static void BM_ClientApiAlmostNoAllocation(benchmark::State& state) { | 
|  | const uint32_t heap_id = GetHeapId(); | 
|  |  | 
|  | ClientConfiguration client_config{}; | 
|  | client_config.default_interval = 10000000000000000; | 
|  | client_config.all_heaps = true; | 
|  | g_client_config = client_config; | 
|  | PERFETTO_CHECK(AHeapProfile_initSession(malloc, free)); | 
|  |  | 
|  | PERFETTO_CHECK(g_shmem_fd); | 
|  | auto ringbuf = SharedRingBuffer::Attach(base::ScopedFile(dup(g_shmem_fd))); | 
|  |  | 
|  | for (auto _ : state) { | 
|  | AHeapProfile_reportAllocation(heap_id, 0x123, 1); | 
|  | } | 
|  | DisconnectGlobalServerSocket(); | 
|  | ringbuf->SetShuttingDown(); | 
|  | } | 
|  |  | 
|  | BENCHMARK(BM_ClientApiAlmostNoAllocation); | 
|  |  | 
|  | static void BM_ClientApiSample(benchmark::State& state) { | 
|  | const uint32_t heap_id = GetHeapId(); | 
|  |  | 
|  | ClientConfiguration client_config{}; | 
|  | client_config.default_interval = 32000; | 
|  | client_config.all_heaps = true; | 
|  | g_client_config = client_config; | 
|  | PERFETTO_CHECK(AHeapProfile_initSession(malloc, free)); | 
|  |  | 
|  | PERFETTO_CHECK(g_shmem_fd); | 
|  | auto ringbuf = SharedRingBuffer::Attach(base::ScopedFile(dup(g_shmem_fd))); | 
|  |  | 
|  | for (auto _ : state) { | 
|  | AHeapProfile_reportSample(heap_id, 0x123, 20); | 
|  | } | 
|  | DisconnectGlobalServerSocket(); | 
|  | ringbuf->SetShuttingDown(); | 
|  | } | 
|  |  | 
|  | BENCHMARK(BM_ClientApiSample); | 
|  |  | 
|  | static void BM_ClientApiDisabledHeapAllocation(benchmark::State& state) { | 
|  | const uint32_t heap_id = GetHeapId(); | 
|  |  | 
|  | ClientConfiguration client_config{}; | 
|  | client_config.default_interval = 32000; | 
|  | client_config.all_heaps = false; | 
|  | g_client_config = client_config; | 
|  | PERFETTO_CHECK(AHeapProfile_initSession(malloc, free)); | 
|  |  | 
|  | PERFETTO_CHECK(g_shmem_fd); | 
|  | auto ringbuf = SharedRingBuffer::Attach(base::ScopedFile(dup(g_shmem_fd))); | 
|  |  | 
|  | for (auto _ : state) { | 
|  | AHeapProfile_reportAllocation(heap_id, 0x123, 20); | 
|  | } | 
|  | DisconnectGlobalServerSocket(); | 
|  | ringbuf->SetShuttingDown(); | 
|  | } | 
|  |  | 
|  | BENCHMARK(BM_ClientApiDisabledHeapAllocation); | 
|  |  | 
|  | static void BM_ClientApiDisabledHeapFree(benchmark::State& state) { | 
|  | const uint32_t heap_id = GetHeapId(); | 
|  |  | 
|  | ClientConfiguration client_config{}; | 
|  | client_config.default_interval = 32000; | 
|  | client_config.all_heaps = false; | 
|  | g_client_config = client_config; | 
|  | PERFETTO_CHECK(AHeapProfile_initSession(malloc, free)); | 
|  |  | 
|  | PERFETTO_CHECK(g_shmem_fd); | 
|  | auto ringbuf = SharedRingBuffer::Attach(base::ScopedFile(dup(g_shmem_fd))); | 
|  |  | 
|  | for (auto _ : state) { | 
|  | AHeapProfile_reportFree(heap_id, 0x123); | 
|  | } | 
|  | DisconnectGlobalServerSocket(); | 
|  | ringbuf->SetShuttingDown(); | 
|  | } | 
|  |  | 
|  | BENCHMARK(BM_ClientApiDisabledHeapFree); | 
|  |  | 
|  | static void BM_ClientApiEnabledHeapFree(benchmark::State& state) { | 
|  | const uint32_t heap_id = GetHeapId(); | 
|  |  | 
|  | ClientConfiguration client_config{}; | 
|  | client_config.default_interval = 32000; | 
|  | client_config.all_heaps = true; | 
|  | g_client_config = client_config; | 
|  | PERFETTO_CHECK(AHeapProfile_initSession(malloc, free)); | 
|  |  | 
|  | PERFETTO_CHECK(g_shmem_fd); | 
|  | auto ringbuf = SharedRingBuffer::Attach(base::ScopedFile(dup(g_shmem_fd))); | 
|  |  | 
|  | for (auto _ : state) { | 
|  | AHeapProfile_reportFree(heap_id, 0x123); | 
|  | } | 
|  | DisconnectGlobalServerSocket(); | 
|  | ringbuf->SetShuttingDown(); | 
|  | } | 
|  |  | 
|  | BENCHMARK(BM_ClientApiEnabledHeapFree); | 
|  |  | 
|  | static void BM_ClientApiMallocFree(benchmark::State& state) { | 
|  | for (auto _ : state) { | 
|  | volatile char* x = static_cast<char*>(malloc(100)); | 
|  | if (x) { | 
|  | x[0] = 'x'; | 
|  | free(const_cast<char*>(x)); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | BENCHMARK(BM_ClientApiMallocFree); | 
|  |  | 
|  | }  // namespace profiling | 
|  | }  // namespace perfetto |