xref: /aosp_15_r20/external/perfetto/src/tools/multithreaded_alloc.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker  * Copyright (C) 2020 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker  *
4*6dbdd20aSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker  *
8*6dbdd20aSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker  *
10*6dbdd20aSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker  * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker  */
16*6dbdd20aSAndroid Build Coastguard Worker 
17*6dbdd20aSAndroid Build Coastguard Worker #include <stdio.h>
18*6dbdd20aSAndroid Build Coastguard Worker #include <stdlib.h>
19*6dbdd20aSAndroid Build Coastguard Worker #include <unistd.h>
20*6dbdd20aSAndroid Build Coastguard Worker 
21*6dbdd20aSAndroid Build Coastguard Worker #include <atomic>
22*6dbdd20aSAndroid Build Coastguard Worker #include <cinttypes>
23*6dbdd20aSAndroid Build Coastguard Worker #include <condition_variable>
24*6dbdd20aSAndroid Build Coastguard Worker #include <iterator>
25*6dbdd20aSAndroid Build Coastguard Worker #include <mutex>
26*6dbdd20aSAndroid Build Coastguard Worker #include <optional>
27*6dbdd20aSAndroid Build Coastguard Worker #include <thread>
28*6dbdd20aSAndroid Build Coastguard Worker #include <vector>
29*6dbdd20aSAndroid Build Coastguard Worker 
30*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/logging.h"
31*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/time.h"
32*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/getopt.h"
33*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/string_utils.h"
34*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/heap_profile.h"
35*6dbdd20aSAndroid Build Coastguard Worker 
36*6dbdd20aSAndroid Build Coastguard Worker namespace {
37*6dbdd20aSAndroid Build Coastguard Worker 
38*6dbdd20aSAndroid Build Coastguard Worker void EnabledCallback(void*, const AHeapProfileEnableCallbackInfo*);
39*6dbdd20aSAndroid Build Coastguard Worker 
40*6dbdd20aSAndroid Build Coastguard Worker std::atomic<bool> done;
41*6dbdd20aSAndroid Build Coastguard Worker std::atomic<uint64_t> allocs{0};
42*6dbdd20aSAndroid Build Coastguard Worker 
43*6dbdd20aSAndroid Build Coastguard Worker #pragma GCC diagnostic push
44*6dbdd20aSAndroid Build Coastguard Worker #pragma GCC diagnostic ignored "-Wglobal-constructors"
45*6dbdd20aSAndroid Build Coastguard Worker #pragma GCC diagnostic ignored "-Wexit-time-destructors"
46*6dbdd20aSAndroid Build Coastguard Worker std::mutex g_wake_up_mutex;
47*6dbdd20aSAndroid Build Coastguard Worker std::condition_variable g_wake_up_cv;
48*6dbdd20aSAndroid Build Coastguard Worker uint64_t g_rate = 0;
49*6dbdd20aSAndroid Build Coastguard Worker 
50*6dbdd20aSAndroid Build Coastguard Worker uint32_t g_heap_id = AHeapProfile_registerHeap(
51*6dbdd20aSAndroid Build Coastguard Worker     AHeapInfo_setEnabledCallback(AHeapInfo_create("test_heap"),
52*6dbdd20aSAndroid Build Coastguard Worker                                  EnabledCallback,
53*6dbdd20aSAndroid Build Coastguard Worker                                  nullptr));
54*6dbdd20aSAndroid Build Coastguard Worker 
55*6dbdd20aSAndroid Build Coastguard Worker #pragma GCC diagnostic pop
56*6dbdd20aSAndroid Build Coastguard Worker 
EnabledCallback(void *,const AHeapProfileEnableCallbackInfo * info)57*6dbdd20aSAndroid Build Coastguard Worker void EnabledCallback(void*, const AHeapProfileEnableCallbackInfo* info) {
58*6dbdd20aSAndroid Build Coastguard Worker   std::lock_guard<std::mutex> l(g_wake_up_mutex);
59*6dbdd20aSAndroid Build Coastguard Worker   g_rate = AHeapProfileEnableCallbackInfo_getSamplingInterval(info);
60*6dbdd20aSAndroid Build Coastguard Worker   g_wake_up_cv.notify_all();
61*6dbdd20aSAndroid Build Coastguard Worker }
62*6dbdd20aSAndroid Build Coastguard Worker 
ScrambleAllocId(uint64_t alloc_id,uint32_t thread_idx)63*6dbdd20aSAndroid Build Coastguard Worker uint64_t ScrambleAllocId(uint64_t alloc_id, uint32_t thread_idx) {
64*6dbdd20aSAndroid Build Coastguard Worker   return thread_idx | (~alloc_id << 24);
65*6dbdd20aSAndroid Build Coastguard Worker }
66*6dbdd20aSAndroid Build Coastguard Worker 
Thread(uint32_t thread_idx,uint64_t pending_allocs)67*6dbdd20aSAndroid Build Coastguard Worker void Thread(uint32_t thread_idx, uint64_t pending_allocs) {
68*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_CHECK(thread_idx < 1 << 24);
69*6dbdd20aSAndroid Build Coastguard Worker   uint64_t alloc_id = 0;
70*6dbdd20aSAndroid Build Coastguard Worker   size_t thread_allocs = 0;
71*6dbdd20aSAndroid Build Coastguard Worker   while (!done.load(std::memory_order_relaxed)) {
72*6dbdd20aSAndroid Build Coastguard Worker     AHeapProfile_reportAllocation(g_heap_id,
73*6dbdd20aSAndroid Build Coastguard Worker                                   ScrambleAllocId(alloc_id, thread_idx), 1);
74*6dbdd20aSAndroid Build Coastguard Worker     if (alloc_id > pending_allocs)
75*6dbdd20aSAndroid Build Coastguard Worker       AHeapProfile_reportFree(
76*6dbdd20aSAndroid Build Coastguard Worker           g_heap_id, ScrambleAllocId(alloc_id - pending_allocs, thread_idx));
77*6dbdd20aSAndroid Build Coastguard Worker     alloc_id++;
78*6dbdd20aSAndroid Build Coastguard Worker     thread_allocs++;
79*6dbdd20aSAndroid Build Coastguard Worker   }
80*6dbdd20aSAndroid Build Coastguard Worker   allocs.fetch_add(thread_allocs, std::memory_order_relaxed);
81*6dbdd20aSAndroid Build Coastguard Worker }
82*6dbdd20aSAndroid Build Coastguard Worker 
83*6dbdd20aSAndroid Build Coastguard Worker }  // namespace
84*6dbdd20aSAndroid Build Coastguard Worker 
main(int argc,char ** argv)85*6dbdd20aSAndroid Build Coastguard Worker int main(int argc, char** argv) {
86*6dbdd20aSAndroid Build Coastguard Worker   if (argc != 4) {
87*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_FATAL("%s NUMBER_THREADS RUNTIME_MS PENDING_ALLOCS", argv[0]);
88*6dbdd20aSAndroid Build Coastguard Worker   }
89*6dbdd20aSAndroid Build Coastguard Worker 
90*6dbdd20aSAndroid Build Coastguard Worker   std::optional<uint64_t> opt_no_threads =
91*6dbdd20aSAndroid Build Coastguard Worker       perfetto::base::CStringToUInt64(argv[1]);
92*6dbdd20aSAndroid Build Coastguard Worker   if (!opt_no_threads) {
93*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_FATAL("Invalid number of threads: %s", argv[1]);
94*6dbdd20aSAndroid Build Coastguard Worker   }
95*6dbdd20aSAndroid Build Coastguard Worker   uint64_t no_threads = *opt_no_threads;
96*6dbdd20aSAndroid Build Coastguard Worker 
97*6dbdd20aSAndroid Build Coastguard Worker   std::optional<uint64_t> opt_runtime_ms =
98*6dbdd20aSAndroid Build Coastguard Worker       perfetto::base::CStringToUInt64(argv[2]);
99*6dbdd20aSAndroid Build Coastguard Worker   if (!opt_runtime_ms) {
100*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_FATAL("Invalid runtime: %s", argv[2]);
101*6dbdd20aSAndroid Build Coastguard Worker   }
102*6dbdd20aSAndroid Build Coastguard Worker   uint64_t runtime_ms = *opt_runtime_ms;
103*6dbdd20aSAndroid Build Coastguard Worker 
104*6dbdd20aSAndroid Build Coastguard Worker   std::optional<uint64_t> opt_pending_allocs =
105*6dbdd20aSAndroid Build Coastguard Worker       perfetto::base::CStringToUInt64(argv[3]);
106*6dbdd20aSAndroid Build Coastguard Worker   if (!opt_runtime_ms) {
107*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_FATAL("Invalid number of pending allocs: %s", argv[3]);
108*6dbdd20aSAndroid Build Coastguard Worker   }
109*6dbdd20aSAndroid Build Coastguard Worker   uint64_t pending_allocs = *opt_pending_allocs;
110*6dbdd20aSAndroid Build Coastguard Worker 
111*6dbdd20aSAndroid Build Coastguard Worker   std::unique_lock<std::mutex> l(g_wake_up_mutex);
112*6dbdd20aSAndroid Build Coastguard Worker   g_wake_up_cv.wait(l, [] { return g_rate > 0; });
113*6dbdd20aSAndroid Build Coastguard Worker 
114*6dbdd20aSAndroid Build Coastguard Worker   perfetto::base::TimeMillis end =
115*6dbdd20aSAndroid Build Coastguard Worker       perfetto::base::GetWallTimeMs() + perfetto::base::TimeMillis(runtime_ms);
116*6dbdd20aSAndroid Build Coastguard Worker   std::vector<std::thread> threads;
117*6dbdd20aSAndroid Build Coastguard Worker   for (size_t i = 0; i < static_cast<size_t>(no_threads); ++i)
118*6dbdd20aSAndroid Build Coastguard Worker     threads.emplace_back(Thread, i, pending_allocs);
119*6dbdd20aSAndroid Build Coastguard Worker 
120*6dbdd20aSAndroid Build Coastguard Worker   perfetto::base::TimeMillis current = perfetto::base::GetWallTimeMs();
121*6dbdd20aSAndroid Build Coastguard Worker   while (current < end) {
122*6dbdd20aSAndroid Build Coastguard Worker     usleep(useconds_t((end - current).count()) * 1000);
123*6dbdd20aSAndroid Build Coastguard Worker     current = perfetto::base::GetWallTimeMs();
124*6dbdd20aSAndroid Build Coastguard Worker   }
125*6dbdd20aSAndroid Build Coastguard Worker 
126*6dbdd20aSAndroid Build Coastguard Worker   done.store(true, std::memory_order_relaxed);
127*6dbdd20aSAndroid Build Coastguard Worker 
128*6dbdd20aSAndroid Build Coastguard Worker   for (std::thread& th : threads)
129*6dbdd20aSAndroid Build Coastguard Worker     th.join();
130*6dbdd20aSAndroid Build Coastguard Worker 
131*6dbdd20aSAndroid Build Coastguard Worker   printf("%" PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64 "\n",
132*6dbdd20aSAndroid Build Coastguard Worker          no_threads, runtime_ms, pending_allocs, g_rate,
133*6dbdd20aSAndroid Build Coastguard Worker          allocs.load(std::memory_order_relaxed));
134*6dbdd20aSAndroid Build Coastguard Worker   return 0;
135*6dbdd20aSAndroid Build Coastguard Worker }
136