OSDN Git Service

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