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