blob: bcad8b1f93690ccba7964f1b149779314368e765 [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
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>
Andy McFadden4b851a72010-07-09 16:50:05 -070028#include <fcntl.h>
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080029#include <errno.h>
30#include <sys/time.h>
31#include <time.h>
32
33
34#define kHeadSuffix "-hptemp"
35
36hprof_context_t *
Andy McFadden4b851a72010-07-09 16:50:05 -070037hprofStartup(const char *outputFileName, int fd, bool directToDdms)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080038{
Andy McFadden6bf992c2010-01-28 17:01:39 -080039 hprofStartup_String();
40 hprofStartup_Class();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080041#if WITH_HPROF_STACK
Andy McFadden6bf992c2010-01-28 17:01:39 -080042 hprofStartup_StackFrame();
43 hprofStartup_Stack();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080044#endif
45
Andy McFadden6bf992c2010-01-28 17:01:39 -080046 hprof_context_t *ctx = malloc(sizeof(*ctx));
47 if (ctx == NULL) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080048 LOGE("hprof: can't allocate context.\n");
Andy McFadden6bf992c2010-01-28 17:01:39 -080049 return NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080050 }
51
Andy McFadden4b851a72010-07-09 16:50:05 -070052 /* pass in name or descriptor of the output file */
53 hprofContextInit(ctx, strdup(outputFileName), fd, false, directToDdms);
Andy McFadden6bf992c2010-01-28 17:01:39 -080054
Andy McFadden4b851a72010-07-09 16:50:05 -070055 assert(ctx->memFp != NULL);
Andy McFadden6bf992c2010-01-28 17:01:39 -080056
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080057 return ctx;
58}
59
60/*
The Android Open Source Project99409882009-03-18 22:20:24 -070061 * Finish up the hprof dump. Returns true on success.
62 */
63bool
Andy McFadden6bf992c2010-01-28 17:01:39 -080064hprofShutdown(hprof_context_t *tailCtx)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080065{
Andy McFadden4b851a72010-07-09 16:50:05 -070066 /* flush the "tail" portion of the output */
Andy McFadden6bf992c2010-01-28 17:01:39 -080067 hprofFlushCurrentRecord(tailCtx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080068
Andy McFadden6bf992c2010-01-28 17:01:39 -080069 /*
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");
Andy McFadden6bf992c2010-01-28 17:01:39 -080076 hprofFreeContext(tailCtx);
Andy McFadden4b851a72010-07-09 16:50:05 -070077 return false;
Andy McFadden6bf992c2010-01-28 17:01:39 -080078 }
Andy McFadden4b851a72010-07-09 16:50:05 -070079 hprofContextInit(headCtx, strdup(tailCtx->fileName), tailCtx->fd, true,
Andy McFadden6bf992c2010-01-28 17:01:39 -080080 tailCtx->directToDdms);
81
Andy McFadden4b851a72010-07-09 16:50:05 -070082 LOGI("hprof: dumping heap strings to \"%s\".\n", tailCtx->fileName);
Andy McFadden6bf992c2010-01-28 17:01:39 -080083 hprofDumpStrings(headCtx);
84 hprofDumpClasses(headCtx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080085
86 /* Write a dummy stack trace record so the analysis
87 * tools don't freak out.
88 */
Andy McFadden6bf992c2010-01-28 17:01:39 -080089 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
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080093
94#if WITH_HPROF_STACK
Andy McFadden6bf992c2010-01-28 17:01:39 -080095 hprofDumpStackFrames(headCtx);
96 hprofDumpStacks(headCtx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080097#endif
98
Andy McFadden6bf992c2010-01-28 17:01:39 -080099 hprofFlushCurrentRecord(headCtx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800100
101 hprofShutdown_Class();
102 hprofShutdown_String();
103#if WITH_HPROF_STACK
104 hprofShutdown_Stack();
105 hprofShutdown_StackFrame();
106#endif
107
Andy McFadden4b851a72010-07-09 16:50:05 -0700108 /* flush to ensure memstream pointer and size are updated */
109 fflush(headCtx->memFp);
110 fflush(tailCtx->memFp);
Andy McFadden6bf992c2010-01-28 17:01:39 -0800111
Andy McFadden4b851a72010-07-09 16:50:05 -0700112 if (tailCtx->directToDdms) {
Andy McFadden6bf992c2010-01-28 17:01:39 -0800113 /* 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 /*
Andy McFadden4b851a72010-07-09 16:50:05 -0700122 * Open the output file, and copy the head and tail to it.
Andy McFadden6bf992c2010-01-28 17:01:39 -0800123 */
Andy McFadden4b851a72010-07-09 16:50:05 -0700124 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;
Andy McFadden6bf992c2010-01-28 17:01:39 -0800156 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800157 }
158
Andy McFadden4b851a72010-07-09 16:50:05 -0700159 /* 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
Andy McFadden6bf992c2010-01-28 17:01:39 -0800163 hprofFreeContext(headCtx);
164 hprofFreeContext(tailCtx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800165
The Android Open Source Project99409882009-03-18 22:20:24 -0700166 return true;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800167}
Andy McFadden6bf992c2010-01-28 17:01:39 -0800168
169/*
170 * Free any heap-allocated items in "ctx", and then free "ctx" itself.
171 */
172void
173hprofFreeContext(hprof_context_t *ctx)
174{
175 assert(ctx != NULL);
176
Andy McFadden4b851a72010-07-09 16:50:05 -0700177 /* we don't own ctx->fd, do not close */
178
179 if (ctx->memFp != NULL)
180 fclose(ctx->memFp);
Andy McFadden6bf992c2010-01-28 17:01:39 -0800181 free(ctx->curRec.body);
182 free(ctx->fileName);
183 free(ctx->fileDataPtr);
184 free(ctx);
185}