1 /*
2 * Copyright (C) 2008 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 #include <sys/time.h>
17 #include <time.h>
18 #include "Hprof.h"
19
20 #define HPROF_MAGIC_STRING "JAVA PROFILE 1.0.3"
21
22 #define U2_TO_BUF_BE(buf, offset, value) \
23 do { \
24 unsigned char *buf_ = (unsigned char *)(buf); \
25 int offset_ = (int)(offset); \
26 u2 value_ = (u2)(value); \
27 buf_[offset_ + 0] = (unsigned char)(value_ >> 8); \
28 buf_[offset_ + 1] = (unsigned char)(value_ ); \
29 } while (0)
30
31 #define U4_TO_BUF_BE(buf, offset, value) \
32 do { \
33 unsigned char *buf_ = (unsigned char *)(buf); \
34 int offset_ = (int)(offset); \
35 u4 value_ = (u4)(value); \
36 buf_[offset_ + 0] = (unsigned char)(value_ >> 24); \
37 buf_[offset_ + 1] = (unsigned char)(value_ >> 16); \
38 buf_[offset_ + 2] = (unsigned char)(value_ >> 8); \
39 buf_[offset_ + 3] = (unsigned char)(value_ ); \
40 } while (0)
41
42 #define U8_TO_BUF_BE(buf, offset, value) \
43 do { \
44 unsigned char *buf_ = (unsigned char *)(buf); \
45 int offset_ = (int)(offset); \
46 u8 value_ = (u8)(value); \
47 buf_[offset_ + 0] = (unsigned char)(value_ >> 56); \
48 buf_[offset_ + 1] = (unsigned char)(value_ >> 48); \
49 buf_[offset_ + 2] = (unsigned char)(value_ >> 40); \
50 buf_[offset_ + 3] = (unsigned char)(value_ >> 32); \
51 buf_[offset_ + 4] = (unsigned char)(value_ >> 24); \
52 buf_[offset_ + 5] = (unsigned char)(value_ >> 16); \
53 buf_[offset_ + 6] = (unsigned char)(value_ >> 8); \
54 buf_[offset_ + 7] = (unsigned char)(value_ ); \
55 } while (0)
56
57 void
hprofContextInit(hprof_context_t * ctx,char * fileName,FILE * fp,bool writeHeader)58 hprofContextInit(hprof_context_t *ctx, char *fileName, FILE *fp,
59 bool writeHeader)
60 {
61 memset(ctx, 0, sizeof (*ctx));
62 ctx->fileName = fileName;
63 ctx->fp = fp;
64
65 ctx->curRec.allocLen = 128;
66 ctx->curRec.body = malloc(ctx->curRec.allocLen);
67 //xxx check for/return an error
68
69 if (writeHeader) {
70 char magic[] = HPROF_MAGIC_STRING;
71 unsigned char buf[4];
72 struct timeval now;
73 u8 nowMs;
74
75 /* Write the file header.
76 *
77 * [u1]*: NUL-terminated magic string.
78 */
79 fwrite(magic, 1, sizeof(magic), fp);
80
81 /* u4: size of identifiers. We're using addresses
82 * as IDs, so make sure a pointer fits.
83 */
84 U4_TO_BUF_BE(buf, 0, sizeof(void *));
85 fwrite(buf, 1, sizeof(u4), fp);
86
87 /* The current time, in milliseconds since 0:00 GMT, 1/1/70.
88 */
89 if (gettimeofday(&now, NULL) < 0) {
90 nowMs = 0;
91 } else {
92 nowMs = (u8)now.tv_sec * 1000 + now.tv_usec / 1000;
93 }
94
95 /* u4: high word of the 64-bit time.
96 */
97 U4_TO_BUF_BE(buf, 0, (u4)(nowMs >> 32));
98 fwrite(buf, 1, sizeof(u4), fp);
99
100 /* u4: low word of the 64-bit time.
101 */
102 U4_TO_BUF_BE(buf, 0, (u4)(nowMs & 0xffffffffULL));
103 fwrite(buf, 1, sizeof(u4), fp); //xxx fix the time
104 }
105 }
106
107 int
hprofFlushRecord(hprof_record_t * rec,FILE * fp)108 hprofFlushRecord(hprof_record_t *rec, FILE *fp)
109 {
110 if (rec->dirty) {
111 unsigned char headBuf[sizeof (u1) + 2 * sizeof (u4)];
112 int nb;
113
114 headBuf[0] = rec->tag;
115 U4_TO_BUF_BE(headBuf, 1, rec->time);
116 U4_TO_BUF_BE(headBuf, 5, rec->length);
117
118 nb = fwrite(headBuf, 1, sizeof(headBuf), fp);
119 if (nb != sizeof(headBuf)) {
120 return UNIQUE_ERROR();
121 }
122 nb = fwrite(rec->body, 1, rec->length, fp);
123 if (nb != (int)rec->length) {
124 return UNIQUE_ERROR();
125 }
126
127 rec->dirty = false;
128 }
129 //xxx if we used less than half (or whatever) of allocLen, shrink the buffer.
130
131 return 0;
132 }
133
134 int
hprofFlushCurrentRecord(hprof_context_t * ctx)135 hprofFlushCurrentRecord(hprof_context_t *ctx)
136 {
137 return hprofFlushRecord(&ctx->curRec, ctx->fp);
138 }
139
140 int
hprofStartNewRecord(hprof_context_t * ctx,u1 tag,u4 time)141 hprofStartNewRecord(hprof_context_t *ctx, u1 tag, u4 time)
142 {
143 hprof_record_t *rec = &ctx->curRec;
144 int err;
145
146 err = hprofFlushRecord(rec, ctx->fp);
147 if (err != 0) {
148 return err;
149 } else if (rec->dirty) {
150 return UNIQUE_ERROR();
151 }
152
153 rec->dirty = true;
154 rec->tag = tag;
155 rec->time = time;
156 rec->length = 0;
157
158 return 0;
159 }
160
161 static inline int
guaranteeRecordAppend(hprof_record_t * rec,size_t nmore)162 guaranteeRecordAppend(hprof_record_t *rec, size_t nmore)
163 {
164 size_t minSize;
165
166 minSize = rec->length + nmore;
167 if (minSize > rec->allocLen) {
168 unsigned char *newBody;
169 size_t newAllocLen;
170
171 newAllocLen = rec->allocLen * 2;
172 if (newAllocLen < minSize) {
173 newAllocLen = rec->allocLen + nmore + nmore/2;
174 }
175 newBody = realloc(rec->body, newAllocLen);
176 if (newBody != NULL) {
177 rec->body = newBody;
178 rec->allocLen = newAllocLen;
179 } else {
180 //TODO: set an error flag so future ops will fail
181 return UNIQUE_ERROR();
182 }
183 }
184
185 assert(rec->length + nmore <= rec->allocLen);
186 return 0;
187 }
188
189 int
hprofAddU1ListToRecord(hprof_record_t * rec,const u1 * values,size_t numValues)190 hprofAddU1ListToRecord(hprof_record_t *rec, const u1 *values, size_t numValues)
191 {
192 int err;
193
194 err = guaranteeRecordAppend(rec, numValues);
195 if (err != 0) {
196 return err;
197 }
198
199 memcpy(rec->body + rec->length, values, numValues);
200 rec->length += numValues;
201
202 return 0;
203 }
204
205 int
hprofAddU1ToRecord(hprof_record_t * rec,u1 value)206 hprofAddU1ToRecord(hprof_record_t *rec, u1 value)
207 {
208 int err;
209
210 err = guaranteeRecordAppend(rec, 1);
211 if (err != 0) {
212 return err;
213 }
214
215 rec->body[rec->length++] = value;
216
217 return 0;
218 }
219
220 int
hprofAddUtf8StringToRecord(hprof_record_t * rec,const char * str)221 hprofAddUtf8StringToRecord(hprof_record_t *rec, const char *str)
222 {
223 /* The terminating NUL character is NOT written.
224 */
225 //xxx don't do a strlen; add and grow as necessary, until NUL
226 return hprofAddU1ListToRecord(rec, (const u1 *)str, strlen(str));
227 }
228
229 int
hprofAddU2ListToRecord(hprof_record_t * rec,const u2 * values,size_t numValues)230 hprofAddU2ListToRecord(hprof_record_t *rec, const u2 *values, size_t numValues)
231 {
232 unsigned char *insert;
233 size_t i;
234 int err;
235
236 err = guaranteeRecordAppend(rec, numValues * 2);
237 if (err != 0) {
238 return err;
239 }
240
241 //xxx this can be way smarter
242 //xxx also, don't do this bytewise if aligned and on a matching-endian arch
243 insert = rec->body + rec->length;
244 for (i = 0; i < numValues; i++) {
245 U2_TO_BUF_BE(insert, 0, *values++);
246 insert += sizeof(*values);
247 }
248 rec->length += numValues * 2;
249
250 return 0;
251 }
252
253 int
hprofAddU2ToRecord(hprof_record_t * rec,u2 value)254 hprofAddU2ToRecord(hprof_record_t *rec, u2 value)
255 {
256 return hprofAddU2ListToRecord(rec, &value, 1);
257 }
258
259 int
hprofAddU4ListToRecord(hprof_record_t * rec,const u4 * values,size_t numValues)260 hprofAddU4ListToRecord(hprof_record_t *rec, const u4 *values, size_t numValues)
261 {
262 unsigned char *insert;
263 size_t i;
264 int err;
265
266 err = guaranteeRecordAppend(rec, numValues * 4);
267 if (err != 0) {
268 return err;
269 }
270
271 //xxx this can be way smarter
272 //xxx also, don't do this bytewise if aligned and on a matching-endian arch
273 insert = rec->body + rec->length;
274 for (i = 0; i < numValues; i++) {
275 U4_TO_BUF_BE(insert, 0, *values++);
276 insert += sizeof(*values);
277 }
278 rec->length += numValues * 4;
279
280 return 0;
281 }
282
283 int
hprofAddU4ToRecord(hprof_record_t * rec,u4 value)284 hprofAddU4ToRecord(hprof_record_t *rec, u4 value)
285 {
286 return hprofAddU4ListToRecord(rec, &value, 1);
287 }
288
289 int
hprofAddU8ListToRecord(hprof_record_t * rec,const u8 * values,size_t numValues)290 hprofAddU8ListToRecord(hprof_record_t *rec, const u8 *values, size_t numValues)
291 {
292 unsigned char *insert;
293 size_t i;
294 int err;
295
296 err = guaranteeRecordAppend(rec, numValues * 8);
297 if (err != 0) {
298 return err;
299 }
300
301 //xxx this can be way smarter
302 //xxx also, don't do this bytewise if aligned and on a matching-endian arch
303 insert = rec->body + rec->length;
304 for (i = 0; i < numValues; i++) {
305 U8_TO_BUF_BE(insert, 0, *values++);
306 insert += sizeof(*values);
307 }
308 rec->length += numValues * 8;
309
310 return 0;
311 }
312
313 int
hprofAddU8ToRecord(hprof_record_t * rec,u8 value)314 hprofAddU8ToRecord(hprof_record_t *rec, u8 value)
315 {
316 return hprofAddU8ListToRecord(rec, &value, 1);
317 }
318