2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <cutils/open_memstream.h>
22 #define HPROF_MAGIC_STRING "JAVA PROFILE 1.0.3"
24 #define U2_TO_BUF_BE(buf, offset, value) \
26 unsigned char *buf_ = (unsigned char *)(buf); \
27 int offset_ = (int)(offset); \
28 u2 value_ = (u2)(value); \
29 buf_[offset_ + 0] = (unsigned char)(value_ >> 8); \
30 buf_[offset_ + 1] = (unsigned char)(value_ ); \
33 #define U4_TO_BUF_BE(buf, offset, value) \
35 unsigned char *buf_ = (unsigned char *)(buf); \
36 int offset_ = (int)(offset); \
37 u4 value_ = (u4)(value); \
38 buf_[offset_ + 0] = (unsigned char)(value_ >> 24); \
39 buf_[offset_ + 1] = (unsigned char)(value_ >> 16); \
40 buf_[offset_ + 2] = (unsigned char)(value_ >> 8); \
41 buf_[offset_ + 3] = (unsigned char)(value_ ); \
44 #define U8_TO_BUF_BE(buf, offset, value) \
46 unsigned char *buf_ = (unsigned char *)(buf); \
47 int offset_ = (int)(offset); \
48 u8 value_ = (u8)(value); \
49 buf_[offset_ + 0] = (unsigned char)(value_ >> 56); \
50 buf_[offset_ + 1] = (unsigned char)(value_ >> 48); \
51 buf_[offset_ + 2] = (unsigned char)(value_ >> 40); \
52 buf_[offset_ + 3] = (unsigned char)(value_ >> 32); \
53 buf_[offset_ + 4] = (unsigned char)(value_ >> 24); \
54 buf_[offset_ + 5] = (unsigned char)(value_ >> 16); \
55 buf_[offset_ + 6] = (unsigned char)(value_ >> 8); \
56 buf_[offset_ + 7] = (unsigned char)(value_ ); \
60 * Initialize an hprof context struct.
62 * This will take ownership of "fileName".
64 void hprofContextInit(hprof_context_t *ctx, char *fileName, int fd,
65 bool writeHeader, bool directToDdms)
67 memset(ctx, 0, sizeof (*ctx));
70 * Have to do this here, because it must happen after we
71 * memset the struct (want to treat fileDataPtr/fileDataSize
72 * as read-only while the file is open).
74 FILE* fp = open_memstream(&ctx->fileDataPtr, &ctx->fileDataSize);
77 ALOGE("hprof: open_memstream failed: %s", strerror(errno));
81 ctx->directToDdms = directToDdms;
82 ctx->fileName = fileName;
86 ctx->curRec.allocLen = 128;
87 ctx->curRec.body = (unsigned char *)malloc(ctx->curRec.allocLen);
88 //xxx check for/return an error
91 char magic[] = HPROF_MAGIC_STRING;
96 /* Write the file header.
98 * [u1]*: NUL-terminated magic string.
100 fwrite(magic, 1, sizeof(magic), fp);
102 /* u4: size of identifiers. We're using addresses
103 * as IDs, so make sure a pointer fits.
105 U4_TO_BUF_BE(buf, 0, sizeof(void *));
106 fwrite(buf, 1, sizeof(u4), fp);
108 /* The current time, in milliseconds since 0:00 GMT, 1/1/70.
110 if (gettimeofday(&now, NULL) < 0) {
113 nowMs = (u8)now.tv_sec * 1000 + now.tv_usec / 1000;
116 /* u4: high word of the 64-bit time.
118 U4_TO_BUF_BE(buf, 0, (u4)(nowMs >> 32));
119 fwrite(buf, 1, sizeof(u4), fp);
121 /* u4: low word of the 64-bit time.
123 U4_TO_BUF_BE(buf, 0, (u4)(nowMs & 0xffffffffULL));
124 fwrite(buf, 1, sizeof(u4), fp); //xxx fix the time
128 int hprofFlushRecord(hprof_record_t *rec, FILE *fp)
131 unsigned char headBuf[sizeof (u1) + 2 * sizeof (u4)];
134 headBuf[0] = rec->tag;
135 U4_TO_BUF_BE(headBuf, 1, rec->time);
136 U4_TO_BUF_BE(headBuf, 5, rec->length);
138 nb = fwrite(headBuf, 1, sizeof(headBuf), fp);
139 if (nb != sizeof(headBuf)) {
140 return UNIQUE_ERROR();
142 nb = fwrite(rec->body, 1, rec->length, fp);
143 if (nb != (int)rec->length) {
144 return UNIQUE_ERROR();
149 //xxx if we used less than half (or whatever) of allocLen, shrink the buffer.
154 int hprofFlushCurrentRecord(hprof_context_t *ctx)
156 return hprofFlushRecord(&ctx->curRec, ctx->memFp);
159 int hprofStartNewRecord(hprof_context_t *ctx, u1 tag, u4 time)
161 hprof_record_t *rec = &ctx->curRec;
164 err = hprofFlushRecord(rec, ctx->memFp);
167 } else if (rec->dirty) {
168 return UNIQUE_ERROR();
179 static inline int guaranteeRecordAppend(hprof_record_t *rec, size_t nmore)
183 minSize = rec->length + nmore;
184 if (minSize > rec->allocLen) {
185 unsigned char *newBody;
188 newAllocLen = rec->allocLen * 2;
189 if (newAllocLen < minSize) {
190 newAllocLen = rec->allocLen + nmore + nmore/2;
192 newBody = (unsigned char *)realloc(rec->body, newAllocLen);
193 if (newBody != NULL) {
195 rec->allocLen = newAllocLen;
197 //TODO: set an error flag so future ops will fail
198 return UNIQUE_ERROR();
202 assert(rec->length + nmore <= rec->allocLen);
206 int hprofAddU1ListToRecord(hprof_record_t *rec, const u1 *values,
211 err = guaranteeRecordAppend(rec, numValues);
216 memcpy(rec->body + rec->length, values, numValues);
217 rec->length += numValues;
222 int hprofAddU1ToRecord(hprof_record_t *rec, u1 value)
226 err = guaranteeRecordAppend(rec, 1);
231 rec->body[rec->length++] = value;
236 int hprofAddUtf8StringToRecord(hprof_record_t *rec, const char *str)
238 /* The terminating NUL character is NOT written.
240 //xxx don't do a strlen; add and grow as necessary, until NUL
241 return hprofAddU1ListToRecord(rec, (const u1 *)str, strlen(str));
244 int hprofAddU2ListToRecord(hprof_record_t *rec, const u2 *values,
247 int err = guaranteeRecordAppend(rec, numValues * 2);
252 //xxx this can be way smarter
253 //xxx also, don't do this bytewise if aligned and on a matching-endian arch
254 unsigned char *insert = rec->body + rec->length;
255 for (size_t i = 0; i < numValues; i++) {
256 U2_TO_BUF_BE(insert, 0, *values++);
257 insert += sizeof(*values);
259 rec->length += numValues * 2;
264 int hprofAddU2ToRecord(hprof_record_t *rec, u2 value)
266 return hprofAddU2ListToRecord(rec, &value, 1);
269 int hprofAddU4ListToRecord(hprof_record_t *rec, const u4 *values,
272 int err = guaranteeRecordAppend(rec, numValues * 4);
277 //xxx this can be way smarter
278 //xxx also, don't do this bytewise if aligned and on a matching-endian arch
279 unsigned char *insert = rec->body + rec->length;
280 for (size_t i = 0; i < numValues; i++) {
281 U4_TO_BUF_BE(insert, 0, *values++);
282 insert += sizeof(*values);
284 rec->length += numValues * 4;
289 int hprofAddU4ToRecord(hprof_record_t *rec, u4 value)
291 return hprofAddU4ListToRecord(rec, &value, 1);
294 int hprofAddU8ListToRecord(hprof_record_t *rec, const u8 *values,
297 int err = guaranteeRecordAppend(rec, numValues * 8);
302 //xxx this can be way smarter
303 //xxx also, don't do this bytewise if aligned and on a matching-endian arch
304 unsigned char *insert = rec->body + rec->length;
305 for (size_t i = 0; i < numValues; i++) {
306 U8_TO_BUF_BE(insert, 0, *values++);
307 insert += sizeof(*values);
309 rec->length += numValues * 8;
314 int hprofAddU8ToRecord(hprof_record_t *rec, u8 value)
316 return hprofAddU8ListToRecord(rec, &value, 1);