Home | History | Annotate | Download | only in hprof
      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