blob: 6d9250a07e0969ab714c71c100baaa011e67ddfc [file] [log] [blame]
The Android Open Source Project52d4c302009-03-03 19:29:09 -08001// 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
10static const short kVersion = 2;
11
12const DmTrace::Header DmTrace::header = {
13 0x574f4c53, kVersion, sizeof(DmTrace::Header), 0LL
14};
15
16static char *keyHeader = "*version\n" "2\n" "clock=thread-cpu\n";
17static char *keyThreadHeader = "*threads\n";
18static char *keyFunctionHeader = "*methods\n";
19static char *keyEnd = "*end\n";
20
21DmTrace::DmTrace() {
22 fData = NULL;
23 fTrace = NULL;
24 threads = new std::vector<ThreadRecord*>;
25 functions = new std::vector<FunctionRecord*>;
26}
27
28DmTrace::~DmTrace() {
29 delete threads;
30 delete functions;
31}
32
33void 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
61void 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 */
82void DmTrace::write2LE(FILE* fstream, unsigned short val)
83{
84 putc(val & 0xff, fstream);
85 putc(val >> 8, fstream);
86}
87
88void 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
96void 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
108void 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
116void 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
125void DmTrace::addFunctionEntry(int functionId, uint32_t cycle, uint32_t pid)
126{
127 writeDataRecord(fData, pid, functionId, cycle);
128}
129
130void DmTrace::addFunctionExit(int functionId, uint32_t cycle, uint32_t pid)
131{
132 writeDataRecord(fData, pid, functionId | 1, cycle);
133}
134
135void 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
143void 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
155void 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
208void 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
216void 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
228void 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
236void 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
246void 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}