• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2006 The Android Open Source Project
2 
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <inttypes.h>
7 #include <string.h>
8 #include <unistd.h>
9 #include "dmtrace.h"
10 
11 static const short kVersion = 2;
12 
13 const DmTrace::Header DmTrace::header = {
14     0x574f4c53, kVersion, sizeof(DmTrace::Header), 0LL
15 };
16 
17 static char *keyHeader = "*version\n" "2\n" "clock=thread-cpu\n";
18 static char *keyThreadHeader = "*threads\n";
19 static char *keyFunctionHeader = "*methods\n";
20 static char *keyEnd = "*end\n";
21 
DmTrace()22 DmTrace::DmTrace() {
23     fData = NULL;
24     fTrace = NULL;
25     threads = new std::vector<ThreadRecord*>;
26     functions = new std::vector<FunctionRecord*>;
27 }
28 
~DmTrace()29 DmTrace::~DmTrace() {
30     delete threads;
31     delete functions;
32 }
33 
open(const char * dmtrace_file,uint64_t start_time)34 void DmTrace::open(const char *dmtrace_file, uint64_t start_time)
35 {
36     fTrace = fopen(dmtrace_file, "w");
37     if (fTrace == NULL) {
38         perror(dmtrace_file);
39         exit(1);
40     }
41 
42     // Make a temporary file to write the data into.
43     char tmpData[32];
44     strcpy(tmpData, "/tmp/dmtrace-data-XXXXXX");
45     int data_fd = mkstemp(tmpData);
46     if (data_fd < 0) {
47         perror("Cannot create temporary file");
48         exit(1);
49     }
50 
51     // Ensure it goes away on exit.
52     unlink(tmpData);
53     fData = fdopen(data_fd, "w+");
54     if (fData == NULL) {
55         perror("Can't make temp data file");
56         exit(1);
57     }
58 
59     writeHeader(fData, start_time);
60 }
61 
close()62 void DmTrace::close()
63 {
64     if (fTrace == NULL)
65         return;
66     writeKeyFile(fTrace);
67 
68     // Take down how much data we wrote to the temp data file.
69     long size = ftell(fData);
70     // Rewind the data file and append its contents to the trace file.
71     rewind(fData);
72     char *data = (char *)malloc(size);
73     fread(data, size, 1, fData);
74     fwrite(data, size, 1, fTrace);
75     free(data);
76     fclose(fData);
77     fclose(fTrace);
78 }
79 
80 /*
81  * Write values to the binary data file.
82  */
write2LE(FILE * fstream,unsigned short val)83 void DmTrace::write2LE(FILE* fstream, unsigned short val)
84 {
85     putc(val & 0xff, fstream);
86     putc(val >> 8, fstream);
87 }
88 
write4LE(FILE * fstream,unsigned int val)89 void DmTrace::write4LE(FILE* fstream, unsigned int val)
90 {
91     putc(val & 0xff, fstream);
92     putc((val >> 8) & 0xff, fstream);
93     putc((val >> 16) & 0xff, fstream);
94     putc((val >> 24) & 0xff, fstream);
95 }
96 
write8LE(FILE * fstream,unsigned long long val)97 void DmTrace::write8LE(FILE* fstream, unsigned long long val)
98 {
99     putc(val & 0xff, fstream);
100     putc((val >> 8) & 0xff, fstream);
101     putc((val >> 16) & 0xff, fstream);
102     putc((val >> 24) & 0xff, fstream);
103     putc((val >> 32) & 0xff, fstream);
104     putc((val >> 40) & 0xff, fstream);
105     putc((val >> 48) & 0xff, fstream);
106     putc((val >> 56) & 0xff, fstream);
107 }
108 
writeHeader(FILE * fstream,uint64_t startTime)109 void DmTrace::writeHeader(FILE *fstream, uint64_t startTime)
110 {
111     write4LE(fstream, header.magic);
112     write2LE(fstream, header.version);
113     write2LE(fstream, header.offset);
114     write8LE(fstream, startTime);
115 }
116 
writeDataRecord(FILE * fstream,int threadId,unsigned int methodVal,unsigned int elapsedTime)117 void DmTrace::writeDataRecord(FILE *fstream, int threadId,
118                              unsigned int methodVal,
119                              unsigned int elapsedTime)
120 {
121     write2LE(fstream, threadId);
122     write4LE(fstream, methodVal);
123     write4LE(fstream, elapsedTime);
124 }
125 
addFunctionEntry(int functionId,uint32_t cycle,uint32_t pid)126 void DmTrace::addFunctionEntry(int functionId, uint32_t cycle, uint32_t pid)
127 {
128     writeDataRecord(fData, pid, functionId, cycle);
129 }
130 
addFunctionExit(int functionId,uint32_t cycle,uint32_t pid)131 void DmTrace::addFunctionExit(int functionId, uint32_t cycle, uint32_t pid)
132 {
133     writeDataRecord(fData, pid, functionId | 1, cycle);
134 }
135 
addFunction(int functionId,const char * name)136 void DmTrace::addFunction(int functionId, const char *name)
137 {
138     FunctionRecord *rec = new FunctionRecord;
139     rec->id = functionId;
140     rec->name = name;
141     functions->push_back(rec);
142 }
143 
addFunction(int functionId,const char * clazz,const char * method,const char * sig)144 void DmTrace::addFunction(int functionId, const char *clazz,
145                           const char *method, const char *sig)
146 {
147     // Allocate space for all the strings, plus 2 tab separators plus null byte.
148     // We currently don't reclaim this space.
149     int len = strlen(clazz) + strlen(method) + strlen(sig) + 3;
150     char *name = new char[len];
151     sprintf(name, "%s\t%s\t%s", clazz, method, sig);
152 
153     addFunction(functionId, name);
154 }
155 
parseAndAddFunction(int functionId,const char * name)156 void DmTrace::parseAndAddFunction(int functionId, const char *name)
157 {
158     // Parse the "name" string into "class", "method" and "signature".
159     // The "name" string should look something like this:
160     //   name = "java.util.LinkedList.size()I"
161     // and it will be parsed into this:
162     //   clazz = "java.util.LinkedList"
163     //   method = "size"
164     //   sig = "()I"
165 
166     // Find the first parenthesis, the start of the signature.
167     char *paren = (char*)strchr(name, '(');
168 
169     // If not found, then add the original name.
170     if (paren == NULL) {
171         addFunction(functionId, name);
172         return;
173     }
174 
175     // Copy the signature
176     int len = strlen(paren) + 1;
177     char *sig = new char[len];
178     strcpy(sig, paren);
179 
180     // Zero the parenthesis so that we can search backwards from the signature
181     *paren = 0;
182 
183     // Search for the last period, the start of the method name
184     char *dot = (char*)strrchr(name, '.');
185 
186     // If not found, then add the original name.
187     if (dot == NULL || dot == name) {
188         delete[] sig;
189         *paren = '(';
190         addFunction(functionId, name);
191         return;
192     }
193 
194     // Copy the method, not including the dot
195     len = strlen(dot + 1) + 1;
196     char *method = new char[len];
197     strcpy(method, dot + 1);
198 
199     // Zero the dot to delimit the class name
200     *dot = 0;
201 
202     addFunction(functionId, name, method, sig);
203 
204     // Free the space we allocated.
205     delete[] sig;
206     delete[] method;
207 }
208 
addThread(int threadId,const char * name)209 void DmTrace::addThread(int threadId, const char *name)
210 {
211     ThreadRecord *rec = new ThreadRecord;
212     rec->id = threadId;
213     rec->name = name;
214     threads->push_back(rec);
215 }
216 
updateName(int threadId,const char * name)217 void DmTrace::updateName(int threadId, const char *name)
218 {
219     std::vector<ThreadRecord*>::iterator iter;
220 
221     for (iter = threads->begin(); iter != threads->end(); ++iter) {
222         if ((*iter)->id == threadId) {
223             (*iter)->name = name;
224             return;
225         }
226     }
227 }
228 
writeKeyFile(FILE * fstream)229 void DmTrace::writeKeyFile(FILE *fstream)
230 {
231     fwrite(keyHeader, strlen(keyHeader), 1, fstream);
232     writeThreads(fstream);
233     writeFunctions(fstream);
234     fwrite(keyEnd, strlen(keyEnd), 1, fstream);
235 }
236 
writeThreads(FILE * fstream)237 void DmTrace::writeThreads(FILE *fstream)
238 {
239     std::vector<ThreadRecord*>::iterator iter;
240 
241     fwrite(keyThreadHeader, strlen(keyThreadHeader), 1, fstream);
242     for (iter = threads->begin(); iter != threads->end(); ++iter) {
243         fprintf(fstream, "%d\t%s\n", (*iter)->id, (*iter)->name);
244     }
245 }
246 
writeFunctions(FILE * fstream)247 void DmTrace::writeFunctions(FILE *fstream)
248 {
249     std::vector<FunctionRecord*>::iterator iter;
250 
251     fwrite(keyFunctionHeader, strlen(keyFunctionHeader), 1, fstream);
252     for (iter = functions->begin(); iter != functions->end(); ++iter) {
253         fprintf(fstream, "0x%x\t%s\n", (*iter)->id, (*iter)->name);
254     }
255 }
256