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