• 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 <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