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 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