1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License.
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License.
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Preparation and completion of hprof data generation.  The output is
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * written into two files and then combined.  This is necessary because
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * we generate some of the data (strings and classes) while we dump the
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * heap, and some analysis tools require that the class and string data
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * appear first.
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "Hprof.h"
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <string.h>
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <unistd.h>
284b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden#include <fcntl.h>
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <errno.h>
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <sys/time.h>
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <time.h>
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kHeadSuffix "-hptemp"
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projecthprof_context_t *
374b851a75f7712086a9fc4427f68c99b83725f37dAndy McFaddenhprofStartup(const char *outputFileName, int fd, bool directToDdms)
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
396bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    hprofStartup_String();
406bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    hprofStartup_Class();
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#if WITH_HPROF_STACK
426bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    hprofStartup_StackFrame();
436bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    hprofStartup_Stack();
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
466bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    hprof_context_t *ctx = malloc(sizeof(*ctx));
476bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    if (ctx == NULL) {
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGE("hprof: can't allocate context.\n");
496bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden        return NULL;
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
524b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden    /* pass in name or descriptor of the output file */
534b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden    hprofContextInit(ctx, strdup(outputFileName), fd, false, directToDdms);
546bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden
554b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden    assert(ctx->memFp != NULL);
566bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return ctx;
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
6199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Finish up the hprof dump.  Returns true on success.
6299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
6399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectbool
646bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFaddenhprofShutdown(hprof_context_t *tailCtx)
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
664b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden    /* flush the "tail" portion of the output */
676bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    hprofFlushCurrentRecord(tailCtx);
686bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden
696bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    /*
706bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden     * Create a new context struct for the start of the file.  We
716bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden     * heap-allocate it so we can share the "free" function.
726bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden     */
736bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    hprof_context_t *headCtx = malloc(sizeof(*headCtx));
746bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    if (headCtx == NULL) {
756bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden        LOGE("hprof: can't allocate context.\n");
766bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden        hprofFreeContext(tailCtx);
774b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden        return false;
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
794b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden    hprofContextInit(headCtx, strdup(tailCtx->fileName), tailCtx->fd, true,
806bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden        tailCtx->directToDdms);
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
824b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden    LOGI("hprof: dumping heap strings to \"%s\".\n", tailCtx->fileName);
836bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    hprofDumpStrings(headCtx);
846bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    hprofDumpClasses(headCtx);
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* Write a dummy stack trace record so the analysis
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * tools don't freak out.
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
896bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    hprofStartNewRecord(headCtx, HPROF_TAG_STACK_TRACE, HPROF_TIME);
906bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    hprofAddU4ToRecord(&headCtx->curRec, HPROF_NULL_STACK_TRACE);
916bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    hprofAddU4ToRecord(&headCtx->curRec, HPROF_NULL_THREAD);
926bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    hprofAddU4ToRecord(&headCtx->curRec, 0);    // no frames
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#if WITH_HPROF_STACK
956bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    hprofDumpStackFrames(headCtx);
966bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    hprofDumpStacks(headCtx);
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
996bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    hprofFlushCurrentRecord(headCtx);
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    hprofShutdown_Class();
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    hprofShutdown_String();
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#if WITH_HPROF_STACK
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    hprofShutdown_Stack();
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    hprofShutdown_StackFrame();
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1084b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden    /* flush to ensure memstream pointer and size are updated */
1094b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden    fflush(headCtx->memFp);
1104b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden    fflush(tailCtx->memFp);
1116bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden
1124b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden    if (tailCtx->directToDdms) {
1136bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden        /* send the data off to DDMS */
1146bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden        struct iovec iov[2];
1156bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden        iov[0].iov_base = headCtx->fileDataPtr;
1166bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden        iov[0].iov_len = headCtx->fileDataSize;
1176bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden        iov[1].iov_base = tailCtx->fileDataPtr;
1186bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden        iov[1].iov_len = tailCtx->fileDataSize;
1196bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden        dvmDbgDdmSendChunkV(CHUNK_TYPE("HPDS"), iov, 2);
1206bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    } else {
1216bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden        /*
1224b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden         * Open the output file, and copy the head and tail to it.
1236bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden         */
1244b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden        assert(headCtx->fd == tailCtx->fd);
1254b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden
1264b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden        int outFd;
1274b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden        if (headCtx->fd >= 0) {
1284b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden            outFd = dup(headCtx->fd);
1294b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden            if (outFd < 0) {
1304b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden                LOGE("dup(%d) failed: %s\n", headCtx->fd, strerror(errno));
1314b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden                /* continue to fail-handler below */
1324b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden            }
1334b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden        } else {
1344b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden            outFd = open(tailCtx->fileName, O_WRONLY|O_CREAT, 0644);
1354b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden            if (outFd < 0) {
1364b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden                LOGE("can't open %s: %s\n", headCtx->fileName, strerror(errno));
1374b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden                /* continue to fail-handler below */
1384b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden            }
1394b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden        }
1404b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden        if (outFd < 0) {
1414b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden            hprofFreeContext(headCtx);
1424b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden            hprofFreeContext(tailCtx);
1434b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden            return false;
1444b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden        }
1454b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden
1464b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden        int result;
1474b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden        result = sysWriteFully(outFd, headCtx->fileDataPtr,
1484b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden            headCtx->fileDataSize, "hprof-head");
1494b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden        result |= sysWriteFully(outFd, tailCtx->fileDataPtr,
1504b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden            tailCtx->fileDataSize, "hprof-tail");
1514b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden        close(outFd);
1524b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden        if (result != 0) {
1534b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden            hprofFreeContext(headCtx);
1544b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden            hprofFreeContext(tailCtx);
1554b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden            return false;
1566bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden        }
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1594b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden    /* throw out a log message for the benefit of "runhat" */
1604b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden    LOGI("hprof: heap dump completed (%dKB)\n",
1614b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden        (headCtx->fileDataSize + tailCtx->fileDataSize + 1023) / 1024);
1624b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden
1636bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    hprofFreeContext(headCtx);
1646bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    hprofFreeContext(tailCtx);
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
16699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    return true;
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
1686bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden
1696bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden/*
1706bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden * Free any heap-allocated items in "ctx", and then free "ctx" itself.
1716bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden */
1726bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFaddenvoid
1736bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFaddenhprofFreeContext(hprof_context_t *ctx)
1746bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden{
1756bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    assert(ctx != NULL);
1766bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden
1774b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden    /* we don't own ctx->fd, do not close */
1784b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden
1794b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden    if (ctx->memFp != NULL)
1804b851a75f7712086a9fc4427f68c99b83725f37dAndy McFadden        fclose(ctx->memFp);
1816bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    free(ctx->curRec.body);
1826bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    free(ctx->fileName);
1836bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    free(ctx->fileDataPtr);
1846bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden    free(ctx);
1856bf992c9d51f1e12aa37fe4c791c156402a9b79bAndy McFadden}
186