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