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