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 
     17 /*
     18  * Preparation and completion of hprof data generation.  The output is
     19  * written into two files and then combined.  This is necessary because
     20  * we generate some of the data (strings and classes) while we dump the
     21  * heap, and some analysis tools require that the class and string data
     22  * appear first.
     23  */
     24 #include "Hprof.h"
     25 
     26 #include <string.h>
     27 #include <unistd.h>
     28 #include <fcntl.h>
     29 #include <errno.h>
     30 #include <sys/time.h>
     31 #include <time.h>
     32 
     33 
     34 #define kHeadSuffix "-hptemp"
     35 
     36 hprof_context_t *
     37 hprofStartup(const char *outputFileName, int fd, bool directToDdms)
     38 {
     39     hprofStartup_String();
     40     hprofStartup_Class();
     41 #if WITH_HPROF_STACK
     42     hprofStartup_StackFrame();
     43     hprofStartup_Stack();
     44 #endif
     45 
     46     hprof_context_t *ctx = malloc(sizeof(*ctx));
     47     if (ctx == NULL) {
     48         LOGE("hprof: can't allocate context.\n");
     49         return NULL;
     50     }
     51 
     52     /* pass in name or descriptor of the output file */
     53     hprofContextInit(ctx, strdup(outputFileName), fd, false, directToDdms);
     54 
     55     assert(ctx->memFp != NULL);
     56 
     57     return ctx;
     58 }
     59 
     60 /*
     61  * Finish up the hprof dump.  Returns true on success.
     62  */
     63 bool
     64 hprofShutdown(hprof_context_t *tailCtx)
     65 {
     66     /* flush the "tail" portion of the output */
     67     hprofFlushCurrentRecord(tailCtx);
     68 
     69     /*
     70      * Create a new context struct for the start of the file.  We
     71      * heap-allocate it so we can share the "free" function.
     72      */
     73     hprof_context_t *headCtx = malloc(sizeof(*headCtx));
     74     if (headCtx == NULL) {
     75         LOGE("hprof: can't allocate context.\n");
     76         hprofFreeContext(tailCtx);
     77         return false;
     78     }
     79     hprofContextInit(headCtx, strdup(tailCtx->fileName), tailCtx->fd, true,
     80         tailCtx->directToDdms);
     81 
     82     LOGI("hprof: dumping heap strings to \"%s\".\n", tailCtx->fileName);
     83     hprofDumpStrings(headCtx);
     84     hprofDumpClasses(headCtx);
     85 
     86     /* Write a dummy stack trace record so the analysis
     87      * tools don't freak out.
     88      */
     89     hprofStartNewRecord(headCtx, HPROF_TAG_STACK_TRACE, HPROF_TIME);
     90     hprofAddU4ToRecord(&headCtx->curRec, HPROF_NULL_STACK_TRACE);
     91     hprofAddU4ToRecord(&headCtx->curRec, HPROF_NULL_THREAD);
     92     hprofAddU4ToRecord(&headCtx->curRec, 0);    // no frames
     93 
     94 #if WITH_HPROF_STACK
     95     hprofDumpStackFrames(headCtx);
     96     hprofDumpStacks(headCtx);
     97 #endif
     98 
     99     hprofFlushCurrentRecord(headCtx);
    100 
    101     hprofShutdown_Class();
    102     hprofShutdown_String();
    103 #if WITH_HPROF_STACK
    104     hprofShutdown_Stack();
    105     hprofShutdown_StackFrame();
    106 #endif
    107 
    108     /* flush to ensure memstream pointer and size are updated */
    109     fflush(headCtx->memFp);
    110     fflush(tailCtx->memFp);
    111 
    112     if (tailCtx->directToDdms) {
    113         /* send the data off to DDMS */
    114         struct iovec iov[2];
    115         iov[0].iov_base = headCtx->fileDataPtr;
    116         iov[0].iov_len = headCtx->fileDataSize;
    117         iov[1].iov_base = tailCtx->fileDataPtr;
    118         iov[1].iov_len = tailCtx->fileDataSize;
    119         dvmDbgDdmSendChunkV(CHUNK_TYPE("HPDS"), iov, 2);
    120     } else {
    121         /*
    122          * Open the output file, and copy the head and tail to it.
    123          */
    124         assert(headCtx->fd == tailCtx->fd);
    125 
    126         int outFd;
    127         if (headCtx->fd >= 0) {
    128             outFd = dup(headCtx->fd);
    129             if (outFd < 0) {
    130                 LOGE("dup(%d) failed: %s\n", headCtx->fd, strerror(errno));
    131                 /* continue to fail-handler below */
    132             }
    133         } else {
    134             outFd = open(tailCtx->fileName, O_WRONLY|O_CREAT, 0644);
    135             if (outFd < 0) {
    136                 LOGE("can't open %s: %s\n", headCtx->fileName, strerror(errno));
    137                 /* continue to fail-handler below */
    138             }
    139         }
    140         if (outFd < 0) {
    141             hprofFreeContext(headCtx);
    142             hprofFreeContext(tailCtx);
    143             return false;
    144         }
    145 
    146         int result;
    147         result = sysWriteFully(outFd, headCtx->fileDataPtr,
    148             headCtx->fileDataSize, "hprof-head");
    149         result |= sysWriteFully(outFd, tailCtx->fileDataPtr,
    150             tailCtx->fileDataSize, "hprof-tail");
    151         close(outFd);
    152         if (result != 0) {
    153             hprofFreeContext(headCtx);
    154             hprofFreeContext(tailCtx);
    155             return false;
    156         }
    157     }
    158 
    159     /* throw out a log message for the benefit of "runhat" */
    160     LOGI("hprof: heap dump completed (%dKB)\n",
    161         (headCtx->fileDataSize + tailCtx->fileDataSize + 1023) / 1024);
    162 
    163     hprofFreeContext(headCtx);
    164     hprofFreeContext(tailCtx);
    165 
    166     return true;
    167 }
    168 
    169 /*
    170  * Free any heap-allocated items in "ctx", and then free "ctx" itself.
    171  */
    172 void
    173 hprofFreeContext(hprof_context_t *ctx)
    174 {
    175     assert(ctx != NULL);
    176 
    177     /* we don't own ctx->fd, do not close */
    178 
    179     if (ctx->memFp != NULL)
    180         fclose(ctx->memFp);
    181     free(ctx->curRec.body);
    182     free(ctx->fileName);
    183     free(ctx->fileDataPtr);
    184     free(ctx);
    185 }
    186