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