1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker * Copyright (C) 2015 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker *
4*288bf522SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker *
8*288bf522SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker *
10*288bf522SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker */
16*288bf522SAndroid Build Coastguard Worker
17*288bf522SAndroid Build Coastguard Worker #include <err.h>
18*288bf522SAndroid Build Coastguard Worker #include <errno.h>
19*288bf522SAndroid Build Coastguard Worker #include <fcntl.h>
20*288bf522SAndroid Build Coastguard Worker #include <inttypes.h>
21*288bf522SAndroid Build Coastguard Worker #include <malloc.h>
22*288bf522SAndroid Build Coastguard Worker #include <stdint.h>
23*288bf522SAndroid Build Coastguard Worker #include <stdio.h>
24*288bf522SAndroid Build Coastguard Worker #include <stdlib.h>
25*288bf522SAndroid Build Coastguard Worker #include <string.h>
26*288bf522SAndroid Build Coastguard Worker #include <sys/stat.h>
27*288bf522SAndroid Build Coastguard Worker #include <sys/types.h>
28*288bf522SAndroid Build Coastguard Worker #include <unistd.h>
29*288bf522SAndroid Build Coastguard Worker
30*288bf522SAndroid Build Coastguard Worker #include <memory_trace/MemoryTrace.h>
31*288bf522SAndroid Build Coastguard Worker
32*288bf522SAndroid Build Coastguard Worker #include "Alloc.h"
33*288bf522SAndroid Build Coastguard Worker #include "File.h"
34*288bf522SAndroid Build Coastguard Worker #include "NativeInfo.h"
35*288bf522SAndroid Build Coastguard Worker #include "Pointers.h"
36*288bf522SAndroid Build Coastguard Worker #include "Thread.h"
37*288bf522SAndroid Build Coastguard Worker #include "Threads.h"
38*288bf522SAndroid Build Coastguard Worker
39*288bf522SAndroid Build Coastguard Worker #include <log/log.h>
40*288bf522SAndroid Build Coastguard Worker #include <log/log_read.h>
41*288bf522SAndroid Build Coastguard Worker
42*288bf522SAndroid Build Coastguard Worker constexpr size_t kDefaultMaxThreads = 512;
43*288bf522SAndroid Build Coastguard Worker
GetMaxAllocs(const memory_trace::Entry * entries,size_t num_entries)44*288bf522SAndroid Build Coastguard Worker static size_t GetMaxAllocs(const memory_trace::Entry* entries, size_t num_entries) {
45*288bf522SAndroid Build Coastguard Worker size_t max_allocs = 0;
46*288bf522SAndroid Build Coastguard Worker size_t num_allocs = 0;
47*288bf522SAndroid Build Coastguard Worker for (size_t i = 0; i < num_entries; i++) {
48*288bf522SAndroid Build Coastguard Worker switch (entries[i].type) {
49*288bf522SAndroid Build Coastguard Worker case memory_trace::THREAD_DONE:
50*288bf522SAndroid Build Coastguard Worker break;
51*288bf522SAndroid Build Coastguard Worker case memory_trace::MALLOC:
52*288bf522SAndroid Build Coastguard Worker case memory_trace::CALLOC:
53*288bf522SAndroid Build Coastguard Worker case memory_trace::MEMALIGN:
54*288bf522SAndroid Build Coastguard Worker if (entries[i].ptr != 0) {
55*288bf522SAndroid Build Coastguard Worker num_allocs++;
56*288bf522SAndroid Build Coastguard Worker }
57*288bf522SAndroid Build Coastguard Worker break;
58*288bf522SAndroid Build Coastguard Worker case memory_trace::REALLOC:
59*288bf522SAndroid Build Coastguard Worker if (entries[i].ptr == 0 && entries[i].u.old_ptr != 0) {
60*288bf522SAndroid Build Coastguard Worker num_allocs--;
61*288bf522SAndroid Build Coastguard Worker } else if (entries[i].ptr != 0 && entries[i].u.old_ptr == 0) {
62*288bf522SAndroid Build Coastguard Worker num_allocs++;
63*288bf522SAndroid Build Coastguard Worker }
64*288bf522SAndroid Build Coastguard Worker break;
65*288bf522SAndroid Build Coastguard Worker case memory_trace::FREE:
66*288bf522SAndroid Build Coastguard Worker if (entries[i].ptr != 0) {
67*288bf522SAndroid Build Coastguard Worker num_allocs--;
68*288bf522SAndroid Build Coastguard Worker }
69*288bf522SAndroid Build Coastguard Worker break;
70*288bf522SAndroid Build Coastguard Worker }
71*288bf522SAndroid Build Coastguard Worker if (num_allocs > max_allocs) {
72*288bf522SAndroid Build Coastguard Worker max_allocs = num_allocs;
73*288bf522SAndroid Build Coastguard Worker }
74*288bf522SAndroid Build Coastguard Worker }
75*288bf522SAndroid Build Coastguard Worker return max_allocs;
76*288bf522SAndroid Build Coastguard Worker }
77*288bf522SAndroid Build Coastguard Worker
PrintLogStats(const char * log_name)78*288bf522SAndroid Build Coastguard Worker static void PrintLogStats(const char* log_name) {
79*288bf522SAndroid Build Coastguard Worker logger_list* list =
80*288bf522SAndroid Build Coastguard Worker android_logger_list_open(android_name_to_log_id(log_name), ANDROID_LOG_NONBLOCK, 0, getpid());
81*288bf522SAndroid Build Coastguard Worker if (list == nullptr) {
82*288bf522SAndroid Build Coastguard Worker printf("Failed to open log for %s\n", log_name);
83*288bf522SAndroid Build Coastguard Worker return;
84*288bf522SAndroid Build Coastguard Worker }
85*288bf522SAndroid Build Coastguard Worker while (true) {
86*288bf522SAndroid Build Coastguard Worker log_msg entry;
87*288bf522SAndroid Build Coastguard Worker ssize_t retval = android_logger_list_read(list, &entry);
88*288bf522SAndroid Build Coastguard Worker if (retval == 0) {
89*288bf522SAndroid Build Coastguard Worker break;
90*288bf522SAndroid Build Coastguard Worker }
91*288bf522SAndroid Build Coastguard Worker if (retval < 0) {
92*288bf522SAndroid Build Coastguard Worker if (retval == -EINTR) {
93*288bf522SAndroid Build Coastguard Worker continue;
94*288bf522SAndroid Build Coastguard Worker }
95*288bf522SAndroid Build Coastguard Worker // EAGAIN means there is nothing left to read when ANDROID_LOG_NONBLOCK is set.
96*288bf522SAndroid Build Coastguard Worker if (retval != -EAGAIN) {
97*288bf522SAndroid Build Coastguard Worker printf("Failed to read log entry: %s\n", strerrordesc_np(retval));
98*288bf522SAndroid Build Coastguard Worker }
99*288bf522SAndroid Build Coastguard Worker break;
100*288bf522SAndroid Build Coastguard Worker }
101*288bf522SAndroid Build Coastguard Worker if (entry.msg() == nullptr) {
102*288bf522SAndroid Build Coastguard Worker continue;
103*288bf522SAndroid Build Coastguard Worker }
104*288bf522SAndroid Build Coastguard Worker // Only print allocator tagged log entries.
105*288bf522SAndroid Build Coastguard Worker std::string_view tag(entry.msg() + 1);
106*288bf522SAndroid Build Coastguard Worker if (tag != "scudo" && tag != "jemalloc") {
107*288bf522SAndroid Build Coastguard Worker continue;
108*288bf522SAndroid Build Coastguard Worker }
109*288bf522SAndroid Build Coastguard Worker printf("%s\n", &tag.back() + 2);
110*288bf522SAndroid Build Coastguard Worker }
111*288bf522SAndroid Build Coastguard Worker android_logger_list_close(list);
112*288bf522SAndroid Build Coastguard Worker }
113*288bf522SAndroid Build Coastguard Worker
ProcessDump(const memory_trace::Entry * entries,size_t num_entries,size_t max_threads)114*288bf522SAndroid Build Coastguard Worker static void ProcessDump(const memory_trace::Entry* entries, size_t num_entries,
115*288bf522SAndroid Build Coastguard Worker size_t max_threads) {
116*288bf522SAndroid Build Coastguard Worker // Do a pass to get the maximum number of allocations used at one
117*288bf522SAndroid Build Coastguard Worker // time to allow a single mmap that can hold the maximum number of
118*288bf522SAndroid Build Coastguard Worker // pointers needed at once.
119*288bf522SAndroid Build Coastguard Worker size_t max_allocs = GetMaxAllocs(entries, num_entries);
120*288bf522SAndroid Build Coastguard Worker Pointers pointers(max_allocs);
121*288bf522SAndroid Build Coastguard Worker Threads threads(&pointers, max_threads);
122*288bf522SAndroid Build Coastguard Worker
123*288bf522SAndroid Build Coastguard Worker dprintf(STDOUT_FILENO, "Maximum threads available: %zu\n", threads.max_threads());
124*288bf522SAndroid Build Coastguard Worker dprintf(STDOUT_FILENO, "Maximum allocations in dump: %zu\n", max_allocs);
125*288bf522SAndroid Build Coastguard Worker dprintf(STDOUT_FILENO, "Total pointers available: %zu\n\n", pointers.max_pointers());
126*288bf522SAndroid Build Coastguard Worker
127*288bf522SAndroid Build Coastguard Worker NativePrintInfo("Initial ");
128*288bf522SAndroid Build Coastguard Worker
129*288bf522SAndroid Build Coastguard Worker for (size_t i = 0; i < num_entries; i++) {
130*288bf522SAndroid Build Coastguard Worker if (((i + 1) % 100000) == 0) {
131*288bf522SAndroid Build Coastguard Worker dprintf(STDOUT_FILENO, " At line %zu:\n", i + 1);
132*288bf522SAndroid Build Coastguard Worker NativePrintInfo(" ");
133*288bf522SAndroid Build Coastguard Worker }
134*288bf522SAndroid Build Coastguard Worker const memory_trace::Entry& entry = entries[i];
135*288bf522SAndroid Build Coastguard Worker Thread* thread = threads.FindThread(entry.tid);
136*288bf522SAndroid Build Coastguard Worker if (thread == nullptr) {
137*288bf522SAndroid Build Coastguard Worker thread = threads.CreateThread(entry.tid);
138*288bf522SAndroid Build Coastguard Worker }
139*288bf522SAndroid Build Coastguard Worker
140*288bf522SAndroid Build Coastguard Worker // Wait for the thread to complete any previous actions before handling
141*288bf522SAndroid Build Coastguard Worker // the next action.
142*288bf522SAndroid Build Coastguard Worker thread->WaitForReady();
143*288bf522SAndroid Build Coastguard Worker
144*288bf522SAndroid Build Coastguard Worker thread->SetEntry(&entry);
145*288bf522SAndroid Build Coastguard Worker
146*288bf522SAndroid Build Coastguard Worker bool does_free = AllocDoesFree(entry);
147*288bf522SAndroid Build Coastguard Worker if (does_free) {
148*288bf522SAndroid Build Coastguard Worker // Make sure that any other threads doing allocations are complete
149*288bf522SAndroid Build Coastguard Worker // before triggering the action. Otherwise, another thread could
150*288bf522SAndroid Build Coastguard Worker // be creating the allocation we are going to free.
151*288bf522SAndroid Build Coastguard Worker threads.WaitForAllToQuiesce();
152*288bf522SAndroid Build Coastguard Worker }
153*288bf522SAndroid Build Coastguard Worker
154*288bf522SAndroid Build Coastguard Worker // Tell the thread to execute the action.
155*288bf522SAndroid Build Coastguard Worker thread->SetPending();
156*288bf522SAndroid Build Coastguard Worker
157*288bf522SAndroid Build Coastguard Worker if (entries[i].type == memory_trace::THREAD_DONE) {
158*288bf522SAndroid Build Coastguard Worker // Wait for the thread to finish and clear the thread entry.
159*288bf522SAndroid Build Coastguard Worker threads.Finish(thread);
160*288bf522SAndroid Build Coastguard Worker }
161*288bf522SAndroid Build Coastguard Worker
162*288bf522SAndroid Build Coastguard Worker // Wait for this action to complete. This avoids a race where
163*288bf522SAndroid Build Coastguard Worker // another thread could be creating the same allocation where are
164*288bf522SAndroid Build Coastguard Worker // trying to free.
165*288bf522SAndroid Build Coastguard Worker if (does_free) {
166*288bf522SAndroid Build Coastguard Worker thread->WaitForReady();
167*288bf522SAndroid Build Coastguard Worker }
168*288bf522SAndroid Build Coastguard Worker }
169*288bf522SAndroid Build Coastguard Worker // Wait for all threads to stop processing actions.
170*288bf522SAndroid Build Coastguard Worker threads.WaitForAllToQuiesce();
171*288bf522SAndroid Build Coastguard Worker
172*288bf522SAndroid Build Coastguard Worker NativePrintInfo("Final ");
173*288bf522SAndroid Build Coastguard Worker
174*288bf522SAndroid Build Coastguard Worker // Free any outstanding pointers.
175*288bf522SAndroid Build Coastguard Worker // This allows us to run a tool like valgrind to verify that no memory
176*288bf522SAndroid Build Coastguard Worker // is leaked and everything is accounted for during a run.
177*288bf522SAndroid Build Coastguard Worker threads.FinishAll();
178*288bf522SAndroid Build Coastguard Worker pointers.FreeAll();
179*288bf522SAndroid Build Coastguard Worker
180*288bf522SAndroid Build Coastguard Worker // Print out the total time making all allocation calls.
181*288bf522SAndroid Build Coastguard Worker char buffer[256];
182*288bf522SAndroid Build Coastguard Worker uint64_t total_nsecs = threads.total_time_nsecs();
183*288bf522SAndroid Build Coastguard Worker NativeFormatFloat(buffer, sizeof(buffer), total_nsecs, 1000000000);
184*288bf522SAndroid Build Coastguard Worker dprintf(STDOUT_FILENO, "Total Allocation/Free Time: %" PRIu64 "ns %ss\n", total_nsecs, buffer);
185*288bf522SAndroid Build Coastguard Worker
186*288bf522SAndroid Build Coastguard Worker // Send native allocator stats to the log
187*288bf522SAndroid Build Coastguard Worker mallopt(M_LOG_STATS, 0);
188*288bf522SAndroid Build Coastguard Worker
189*288bf522SAndroid Build Coastguard Worker // No need to avoid allocations at this point since all stats have been sent to the log.
190*288bf522SAndroid Build Coastguard Worker printf("Native Allocator Stats:\n");
191*288bf522SAndroid Build Coastguard Worker PrintLogStats("system");
192*288bf522SAndroid Build Coastguard Worker PrintLogStats("main");
193*288bf522SAndroid Build Coastguard Worker }
194*288bf522SAndroid Build Coastguard Worker
main(int argc,char ** argv)195*288bf522SAndroid Build Coastguard Worker int main(int argc, char** argv) {
196*288bf522SAndroid Build Coastguard Worker if (argc != 2 && argc != 3) {
197*288bf522SAndroid Build Coastguard Worker if (argc > 3) {
198*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "Only two arguments are expected.\n");
199*288bf522SAndroid Build Coastguard Worker } else {
200*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "Requires at least one argument.\n");
201*288bf522SAndroid Build Coastguard Worker }
202*288bf522SAndroid Build Coastguard Worker fprintf(stderr, "Usage: %s MEMORY_LOG_FILE [MAX_THREADS]\n", basename(argv[0]));
203*288bf522SAndroid Build Coastguard Worker fprintf(stderr, " MEMORY_LOG_FILE\n");
204*288bf522SAndroid Build Coastguard Worker fprintf(stderr, " This can either be a text file or a zipped text file.\n");
205*288bf522SAndroid Build Coastguard Worker fprintf(stderr, " MAX_THREADs\n");
206*288bf522SAndroid Build Coastguard Worker fprintf(stderr, " The maximum number of threads in the trace. The default is %zu.\n",
207*288bf522SAndroid Build Coastguard Worker kDefaultMaxThreads);
208*288bf522SAndroid Build Coastguard Worker fprintf(stderr, " This pre-allocates the memory for thread data to avoid allocating\n");
209*288bf522SAndroid Build Coastguard Worker fprintf(stderr, " while the trace is being replayed.\n");
210*288bf522SAndroid Build Coastguard Worker return 1;
211*288bf522SAndroid Build Coastguard Worker }
212*288bf522SAndroid Build Coastguard Worker
213*288bf522SAndroid Build Coastguard Worker #if defined(__LP64__)
214*288bf522SAndroid Build Coastguard Worker dprintf(STDOUT_FILENO, "64 bit environment.\n");
215*288bf522SAndroid Build Coastguard Worker #else
216*288bf522SAndroid Build Coastguard Worker dprintf(STDOUT_FILENO, "32 bit environment.\n");
217*288bf522SAndroid Build Coastguard Worker #endif
218*288bf522SAndroid Build Coastguard Worker
219*288bf522SAndroid Build Coastguard Worker #if defined(__BIONIC__)
220*288bf522SAndroid Build Coastguard Worker dprintf(STDOUT_FILENO, "Setting decay time to 1\n");
221*288bf522SAndroid Build Coastguard Worker mallopt(M_DECAY_TIME, 1);
222*288bf522SAndroid Build Coastguard Worker #endif
223*288bf522SAndroid Build Coastguard Worker
224*288bf522SAndroid Build Coastguard Worker size_t max_threads = kDefaultMaxThreads;
225*288bf522SAndroid Build Coastguard Worker if (argc == 3) {
226*288bf522SAndroid Build Coastguard Worker max_threads = atoi(argv[2]);
227*288bf522SAndroid Build Coastguard Worker }
228*288bf522SAndroid Build Coastguard Worker
229*288bf522SAndroid Build Coastguard Worker memory_trace::Entry* entries;
230*288bf522SAndroid Build Coastguard Worker size_t num_entries;
231*288bf522SAndroid Build Coastguard Worker GetUnwindInfo(argv[1], &entries, &num_entries);
232*288bf522SAndroid Build Coastguard Worker
233*288bf522SAndroid Build Coastguard Worker dprintf(STDOUT_FILENO, "Processing: %s\n", argv[1]);
234*288bf522SAndroid Build Coastguard Worker
235*288bf522SAndroid Build Coastguard Worker ProcessDump(entries, num_entries, max_threads);
236*288bf522SAndroid Build Coastguard Worker
237*288bf522SAndroid Build Coastguard Worker FreeEntries(entries, num_entries);
238*288bf522SAndroid Build Coastguard Worker
239*288bf522SAndroid Build Coastguard Worker return 0;
240*288bf522SAndroid Build Coastguard Worker }
241