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