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