blob: f832f03fbea0cfaf5650e4bae707fae3548683d5 [file] [log] [blame]
Christopher Ferris7bd01782016-04-20 12:30:58 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <errno.h>
30#include <fcntl.h>
Chia-hung Duanf7e8b172022-11-01 21:37:56 +000031#include <inttypes.h>
Christopher Ferris7bd01782016-04-20 12:30:58 -070032#include <pthread.h>
33#include <stdatomic.h>
34#include <stdint.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <sys/types.h>
38
39#include <mutex>
40
41#include <android-base/stringprintf.h>
Christopher Ferrise39602c2024-11-02 05:02:43 +000042#include <memory_trace/MemoryTrace.h>
Christopher Ferris7bd01782016-04-20 12:30:58 -070043
44#include "Config.h"
Christopher Ferris7bd01782016-04-20 12:30:58 -070045#include "DebugData.h"
Christopher Ferrise39602c2024-11-02 05:02:43 +000046#include "Nanotime.h"
Christopher Ferris7bd01782016-04-20 12:30:58 -070047#include "RecordData.h"
Christopher Ferris4da25032018-03-07 13:38:48 -080048#include "debug_disable.h"
49#include "debug_log.h"
Christopher Ferris7bd01782016-04-20 12:30:58 -070050
Christopher Ferris7bd01782016-04-20 12:30:58 -070051struct ThreadData {
Christopher Ferrise39602c2024-11-02 05:02:43 +000052 ThreadData(RecordData* record_data) : record_data(record_data) {}
53
54 RecordData* record_data = nullptr;
Christopher Ferris7bd01782016-04-20 12:30:58 -070055 size_t count = 0;
56};
57
Christopher Ferrisf756e4c2024-11-19 04:28:20 +000058void RecordData::ThreadKeyDelete(void* data) {
Christopher Ferris7bd01782016-04-20 12:30:58 -070059 ThreadData* thread_data = reinterpret_cast<ThreadData*>(data);
60
61 thread_data->count++;
62
63 // This should be the last time we are called.
64 if (thread_data->count == 4) {
65 ScopedDisableDebugCalls disable;
66
Christopher Ferrisf756e4c2024-11-19 04:28:20 +000067 memory_trace::Entry* entry = thread_data->record_data->InternalReserveEntry();
68 if (entry != nullptr) {
69 *entry = memory_trace::Entry{
70 .tid = gettid(), .type = memory_trace::THREAD_DONE, .end_ns = Nanotime()};
71 }
Christopher Ferris7bd01782016-04-20 12:30:58 -070072 delete thread_data;
73 } else {
74 pthread_setspecific(thread_data->record_data->key(), data);
75 }
76}
77
Christopher Ferris06993a62022-09-07 18:19:45 -070078RecordData* RecordData::record_obj_ = nullptr;
79
80void RecordData::WriteData(int, siginfo_t*, void*) {
81 // Dump from here, the function must not allocate so this is safe.
82 record_obj_->WriteEntries();
Christopher Ferris7bd01782016-04-20 12:30:58 -070083}
84
Christopher Ferris9b88d0a2024-06-13 13:22:02 -070085void RecordData::WriteEntriesOnExit() {
86 if (record_obj_ == nullptr) return;
87
88 // Append the current pid to the file name to avoid multiple processes
89 // writing to the same file.
90 std::string file(record_obj_->file());
91 file += "." + std::to_string(getpid());
92 record_obj_->WriteEntries(file);
93}
94
Christopher Ferris06993a62022-09-07 18:19:45 -070095void RecordData::WriteEntries() {
Christopher Ferris9b88d0a2024-06-13 13:22:02 -070096 WriteEntries(file_);
97}
98
99void RecordData::WriteEntries(const std::string& file) {
Christopher Ferris06993a62022-09-07 18:19:45 -0700100 std::lock_guard<std::mutex> entries_lock(entries_lock_);
101 if (cur_index_ == 0) {
102 info_log("No alloc entries to write.");
Christopher Ferris7bd01782016-04-20 12:30:58 -0700103 return;
104 }
105
Christopher Ferris9b88d0a2024-06-13 13:22:02 -0700106 int dump_fd = open(file.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW, 0755);
Christopher Ferris06993a62022-09-07 18:19:45 -0700107 if (dump_fd == -1) {
Christopher Ferris9b88d0a2024-06-13 13:22:02 -0700108 error_log("Cannot create record alloc file %s: %s", file.c_str(), strerror(errno));
Christopher Ferris06993a62022-09-07 18:19:45 -0700109 return;
Christopher Ferris7bd01782016-04-20 12:30:58 -0700110 }
111
Christopher Ferris06993a62022-09-07 18:19:45 -0700112 for (size_t i = 0; i < cur_index_; i++) {
Christopher Ferrisf756e4c2024-11-19 04:28:20 +0000113 if (entries_[i].type == memory_trace::UNKNOWN) {
114 // This can happen if an entry was reserved but not filled in due to some
115 // type of error during the operation.
116 continue;
117 }
Christopher Ferrise39602c2024-11-02 05:02:43 +0000118 if (!memory_trace::WriteEntryToFd(dump_fd, entries_[i])) {
Christopher Ferris06993a62022-09-07 18:19:45 -0700119 error_log("Failed to write record alloc information: %s", strerror(errno));
120 break;
121 }
122 }
123 close(dump_fd);
124
125 // Mark the entries dumped.
126 cur_index_ = 0U;
Christopher Ferris7bd01782016-04-20 12:30:58 -0700127}
128
129RecordData::RecordData() {
130 pthread_key_create(&key_, ThreadKeyDelete);
131}
132
133bool RecordData::Initialize(const Config& config) {
Christopher Ferris06993a62022-09-07 18:19:45 -0700134 record_obj_ = this;
Elliott Hughes3e235912018-02-01 14:21:51 -0800135 struct sigaction64 dump_act = {};
Christopher Ferris06993a62022-09-07 18:19:45 -0700136 dump_act.sa_sigaction = RecordData::WriteData;
Christopher Ferris7bd01782016-04-20 12:30:58 -0700137 dump_act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
Elliott Hughes3e235912018-02-01 14:21:51 -0800138 if (sigaction64(config.record_allocs_signal(), &dump_act, nullptr) != 0) {
Christopher Ferris7bd01782016-04-20 12:30:58 -0700139 error_log("Unable to set up record dump signal function: %s", strerror(errno));
140 return false;
141 }
142 pthread_setspecific(key_, nullptr);
143
Christopher Ferrisc328e442019-04-01 19:31:26 -0700144 if (config.options() & VERBOSE) {
145 info_log("%s: Run: 'kill -%d %d' to dump the allocation records.", getprogname(),
146 config.record_allocs_signal(), getpid());
147 }
Christopher Ferris7bd01782016-04-20 12:30:58 -0700148
Christopher Ferris06993a62022-09-07 18:19:45 -0700149 entries_.resize(config.record_allocs_num_entries());
150 cur_index_ = 0U;
Christopher Ferris9b88d0a2024-06-13 13:22:02 -0700151 file_ = config.record_allocs_file();
Christopher Ferris7bd01782016-04-20 12:30:58 -0700152
153 return true;
154}
155
156RecordData::~RecordData() {
Christopher Ferris7bd01782016-04-20 12:30:58 -0700157 pthread_key_delete(key_);
158}
159
Christopher Ferrisf756e4c2024-11-19 04:28:20 +0000160memory_trace::Entry* RecordData::InternalReserveEntry() {
Christopher Ferris06993a62022-09-07 18:19:45 -0700161 std::lock_guard<std::mutex> entries_lock(entries_lock_);
162 if (cur_index_ == entries_.size()) {
Christopher Ferrisf756e4c2024-11-19 04:28:20 +0000163 return nullptr;
Christopher Ferris06993a62022-09-07 18:19:45 -0700164 }
165
Christopher Ferrisf756e4c2024-11-19 04:28:20 +0000166 memory_trace::Entry* entry = &entries_[cur_index_];
167 entry->type = memory_trace::UNKNOWN;
168 if (++cur_index_ == entries_.size()) {
Christopher Ferris06993a62022-09-07 18:19:45 -0700169 info_log("Maximum number of records added, all new operations will be dropped.");
Christopher Ferris7bd01782016-04-20 12:30:58 -0700170 }
Christopher Ferrisf756e4c2024-11-19 04:28:20 +0000171 return entry;
Christopher Ferris7bd01782016-04-20 12:30:58 -0700172}
173
Christopher Ferrisf756e4c2024-11-19 04:28:20 +0000174memory_trace::Entry* RecordData::ReserveEntry() {
Christopher Ferris7bd01782016-04-20 12:30:58 -0700175 void* data = pthread_getspecific(key_);
176 if (data == nullptr) {
Christopher Ferrise39602c2024-11-02 05:02:43 +0000177 ThreadData* thread_data = new ThreadData(this);
Christopher Ferris7bd01782016-04-20 12:30:58 -0700178 pthread_setspecific(key_, thread_data);
179 }
180
Christopher Ferrisf756e4c2024-11-19 04:28:20 +0000181 return InternalReserveEntry();
Christopher Ferris7bd01782016-04-20 12:30:58 -0700182}