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