1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <err.h>
18 #include <inttypes.h>
19 #include <stdint.h>
20 #include <stdio.h>
21 #include <unistd.h>
22
23 #include <string>
24
25 #include "Alloc.h"
26 #include "Pointers.h"
27 #include "Utils.h"
28
AllocGetData(const std::string & line,AllocEntry * entry)29 void AllocGetData(const std::string& line, AllocEntry* entry) {
30 int line_pos = 0;
31 char name[128];
32 // All lines have this format:
33 // TID: ALLOCATION_TYPE POINTER
34 // where
35 // TID is the thread id of the thread doing the operation.
36 // ALLOCATION_TYPE is one of malloc, calloc, memalign, realloc, free, thread_done
37 // POINTER is the hex value of the actual pointer
38 if (sscanf(line.c_str(), "%d: %127s %" SCNx64 " %n", &entry->tid, name, &entry->ptr, &line_pos) !=
39 3) {
40 errx(1, "File Error: Failed to process %s", line.c_str());
41 }
42 const char* line_end = &line[line_pos];
43 std::string type(name);
44 if (type == "malloc") {
45 // Format:
46 // TID: malloc POINTER SIZE_OF_ALLOCATION
47 if (sscanf(line_end, "%zu", &entry->size) != 1) {
48 errx(1, "File Error: Failed to read malloc data %s", line.c_str());
49 }
50 entry->type = MALLOC;
51 } else if (type == "free") {
52 // Format:
53 // TID: free POINTER
54 entry->type = FREE;
55 } else if (type == "calloc") {
56 // Format:
57 // TID: calloc POINTER ITEM_COUNT ITEM_SIZE
58 if (sscanf(line_end, "%" SCNd64 " %zu", &entry->u.n_elements, &entry->size) != 2) {
59 errx(1, "File Error: Failed to read calloc data %s", line.c_str());
60 }
61 entry->type = CALLOC;
62 } else if (type == "realloc") {
63 // Format:
64 // TID: calloc POINTER NEW_SIZE OLD_POINTER
65 if (sscanf(line_end, "%" SCNx64 " %zu", &entry->u.old_ptr, &entry->size) != 2) {
66 errx(1, "File Error: Failed to read realloc data %s", line.c_str());
67 }
68 entry->type = REALLOC;
69 } else if (type == "memalign") {
70 // Format:
71 // TID: memalign POINTER ALIGNMENT SIZE
72 if (sscanf(line_end, "%" SCNd64 " %zu", &entry->u.align, &entry->size) != 2) {
73 errx(1, "File Error: Failed to read memalign data %s", line.c_str());
74 }
75 entry->type = MEMALIGN;
76 } else if (type == "thread_done") {
77 entry->type = THREAD_DONE;
78 } else {
79 errx(1, "File Error: Unknown type %s", type.c_str());
80 }
81 }
82
AllocDoesFree(const AllocEntry & entry)83 bool AllocDoesFree(const AllocEntry& entry) {
84 switch (entry.type) {
85 case MALLOC:
86 case CALLOC:
87 case MEMALIGN:
88 case THREAD_DONE:
89 return false;
90
91 case FREE:
92 return entry.ptr != 0;
93
94 case REALLOC:
95 return entry.u.old_ptr != 0;
96 }
97 }
98
MallocExecute(const AllocEntry & entry,Pointers * pointers)99 static uint64_t MallocExecute(const AllocEntry& entry, Pointers* pointers) {
100 int pagesize = getpagesize();
101 uint64_t time_nsecs = Nanotime();
102 void* memory = malloc(entry.size);
103 MakeAllocationResident(memory, entry.size, pagesize);
104 time_nsecs = Nanotime() - time_nsecs;
105
106 pointers->Add(entry.ptr, memory);
107
108 return time_nsecs;
109 }
110
CallocExecute(const AllocEntry & entry,Pointers * pointers)111 static uint64_t CallocExecute(const AllocEntry& entry, Pointers* pointers) {
112 int pagesize = getpagesize();
113 uint64_t time_nsecs = Nanotime();
114 void* memory = calloc(entry.u.n_elements, entry.size);
115 MakeAllocationResident(memory, entry.u.n_elements * entry.size, pagesize);
116 time_nsecs = Nanotime() - time_nsecs;
117
118 pointers->Add(entry.ptr, memory);
119
120 return time_nsecs;
121 }
122
ReallocExecute(const AllocEntry & entry,Pointers * pointers)123 static uint64_t ReallocExecute(const AllocEntry& entry, Pointers* pointers) {
124 void* old_memory = nullptr;
125 if (entry.u.old_ptr != 0) {
126 old_memory = pointers->Remove(entry.u.old_ptr);
127 }
128
129 int pagesize = getpagesize();
130 uint64_t time_nsecs = Nanotime();
131 void* memory = realloc(old_memory, entry.size);
132 MakeAllocationResident(memory, entry.size, pagesize);
133 time_nsecs = Nanotime() - time_nsecs;
134
135 pointers->Add(entry.ptr, memory);
136
137 return time_nsecs;
138 }
139
MemalignExecute(const AllocEntry & entry,Pointers * pointers)140 static uint64_t MemalignExecute(const AllocEntry& entry, Pointers* pointers) {
141 int pagesize = getpagesize();
142 uint64_t time_nsecs = Nanotime();
143 void* memory = memalign(entry.u.align, entry.size);
144 MakeAllocationResident(memory, entry.size, pagesize);
145 time_nsecs = Nanotime() - time_nsecs;
146
147 pointers->Add(entry.ptr, memory);
148
149 return time_nsecs;
150 }
151
FreeExecute(const AllocEntry & entry,Pointers * pointers)152 static uint64_t FreeExecute(const AllocEntry& entry, Pointers* pointers) {
153 if (entry.ptr == 0) {
154 return 0;
155 }
156
157 void* memory = pointers->Remove(entry.ptr);
158 uint64_t time_nsecs = Nanotime();
159 free(memory);
160 return Nanotime() - time_nsecs;
161 }
162
AllocExecute(const AllocEntry & entry,Pointers * pointers)163 uint64_t AllocExecute(const AllocEntry& entry, Pointers* pointers) {
164 switch (entry.type) {
165 case MALLOC:
166 return MallocExecute(entry, pointers);
167 case CALLOC:
168 return CallocExecute(entry, pointers);
169 case REALLOC:
170 return ReallocExecute(entry, pointers);
171 case MEMALIGN:
172 return MemalignExecute(entry, pointers);
173 case FREE:
174 return FreeExecute(entry, pointers);
175 default:
176 return 0;
177 }
178 }
179