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