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 void 65 hprofContextInit(hprof_context_t *ctx, char *fileName, int fd, 66 bool writeHeader, bool directToDdms) 67 { 68 memset(ctx, 0, sizeof (*ctx)); 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 LOGE("hprof: open_memstream failed: %s\n", 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 = 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 129 int 130 hprofFlushRecord(hprof_record_t *rec, FILE *fp) 131 { 132 if (rec->dirty) { 133 unsigned char headBuf[sizeof (u1) + 2 * sizeof (u4)]; 134 int nb; 135 136 headBuf[0] = rec->tag; 137 U4_TO_BUF_BE(headBuf, 1, rec->time); 138 U4_TO_BUF_BE(headBuf, 5, rec->length); 139 140 nb = fwrite(headBuf, 1, sizeof(headBuf), fp); 141 if (nb != sizeof(headBuf)) { 142 return UNIQUE_ERROR(); 143 } 144 nb = fwrite(rec->body, 1, rec->length, fp); 145 if (nb != (int)rec->length) { 146 return UNIQUE_ERROR(); 147 } 148 149 rec->dirty = false; 150 } 151 //xxx if we used less than half (or whatever) of allocLen, shrink the buffer. 152 153 return 0; 154 } 155 156 int 157 hprofFlushCurrentRecord(hprof_context_t *ctx) 158 { 159 return hprofFlushRecord(&ctx->curRec, ctx->memFp); 160 } 161 162 int 163 hprofStartNewRecord(hprof_context_t *ctx, u1 tag, u4 time) 164 { 165 hprof_record_t *rec = &ctx->curRec; 166 int err; 167 168 err = hprofFlushRecord(rec, ctx->memFp); 169 if (err != 0) { 170 return err; 171 } else if (rec->dirty) { 172 return UNIQUE_ERROR(); 173 } 174 175 rec->dirty = true; 176 rec->tag = tag; 177 rec->time = time; 178 rec->length = 0; 179 180 return 0; 181 } 182 183 static inline int 184 guaranteeRecordAppend(hprof_record_t *rec, size_t nmore) 185 { 186 size_t minSize; 187 188 minSize = rec->length + nmore; 189 if (minSize > rec->allocLen) { 190 unsigned char *newBody; 191 size_t newAllocLen; 192 193 newAllocLen = rec->allocLen * 2; 194 if (newAllocLen < minSize) { 195 newAllocLen = rec->allocLen + nmore + nmore/2; 196 } 197 newBody = realloc(rec->body, newAllocLen); 198 if (newBody != NULL) { 199 rec->body = newBody; 200 rec->allocLen = newAllocLen; 201 } else { 202 //TODO: set an error flag so future ops will fail 203 return UNIQUE_ERROR(); 204 } 205 } 206 207 assert(rec->length + nmore <= rec->allocLen); 208 return 0; 209 } 210 211 int 212 hprofAddU1ListToRecord(hprof_record_t *rec, const u1 *values, size_t numValues) 213 { 214 int err; 215 216 err = guaranteeRecordAppend(rec, numValues); 217 if (err != 0) { 218 return err; 219 } 220 221 memcpy(rec->body + rec->length, values, numValues); 222 rec->length += numValues; 223 224 return 0; 225 } 226 227 int 228 hprofAddU1ToRecord(hprof_record_t *rec, u1 value) 229 { 230 int err; 231 232 err = guaranteeRecordAppend(rec, 1); 233 if (err != 0) { 234 return err; 235 } 236 237 rec->body[rec->length++] = value; 238 239 return 0; 240 } 241 242 int 243 hprofAddUtf8StringToRecord(hprof_record_t *rec, const char *str) 244 { 245 /* The terminating NUL character is NOT written. 246 */ 247 //xxx don't do a strlen; add and grow as necessary, until NUL 248 return hprofAddU1ListToRecord(rec, (const u1 *)str, strlen(str)); 249 } 250 251 int 252 hprofAddU2ListToRecord(hprof_record_t *rec, const u2 *values, size_t numValues) 253 { 254 unsigned char *insert; 255 size_t i; 256 int err; 257 258 err = guaranteeRecordAppend(rec, numValues * 2); 259 if (err != 0) { 260 return err; 261 } 262 263 //xxx this can be way smarter 264 //xxx also, don't do this bytewise if aligned and on a matching-endian arch 265 insert = rec->body + rec->length; 266 for (i = 0; i < numValues; i++) { 267 U2_TO_BUF_BE(insert, 0, *values++); 268 insert += sizeof(*values); 269 } 270 rec->length += numValues * 2; 271 272 return 0; 273 } 274 275 int 276 hprofAddU2ToRecord(hprof_record_t *rec, u2 value) 277 { 278 return hprofAddU2ListToRecord(rec, &value, 1); 279 } 280 281 int 282 hprofAddU4ListToRecord(hprof_record_t *rec, const u4 *values, size_t numValues) 283 { 284 unsigned char *insert; 285 size_t i; 286 int err; 287 288 err = guaranteeRecordAppend(rec, numValues * 4); 289 if (err != 0) { 290 return err; 291 } 292 293 //xxx this can be way smarter 294 //xxx also, don't do this bytewise if aligned and on a matching-endian arch 295 insert = rec->body + rec->length; 296 for (i = 0; i < numValues; i++) { 297 U4_TO_BUF_BE(insert, 0, *values++); 298 insert += sizeof(*values); 299 } 300 rec->length += numValues * 4; 301 302 return 0; 303 } 304 305 int 306 hprofAddU4ToRecord(hprof_record_t *rec, u4 value) 307 { 308 return hprofAddU4ListToRecord(rec, &value, 1); 309 } 310 311 int 312 hprofAddU8ListToRecord(hprof_record_t *rec, const u8 *values, size_t numValues) 313 { 314 unsigned char *insert; 315 size_t i; 316 int err; 317 318 err = guaranteeRecordAppend(rec, numValues * 8); 319 if (err != 0) { 320 return err; 321 } 322 323 //xxx this can be way smarter 324 //xxx also, don't do this bytewise if aligned and on a matching-endian arch 325 insert = rec->body + rec->length; 326 for (i = 0; i < numValues; i++) { 327 U8_TO_BUF_BE(insert, 0, *values++); 328 insert += sizeof(*values); 329 } 330 rec->length += numValues * 8; 331 332 return 0; 333 } 334 335 int 336 hprofAddU8ToRecord(hprof_record_t *rec, u8 value) 337 { 338 return hprofAddU8ListToRecord(rec, &value, 1); 339 } 340