2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include "HeapInternal.h"
22 #include "HeapSource.h"
25 int dvmGetHeapDebugInfo(HeapDebugInfoType info)
28 case kVirtualHeapSize:
29 return (int)dvmHeapSourceGetValue(HS_FOOTPRINT, NULL, 0);
30 case kVirtualHeapAllocated:
31 return (int)dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0);
37 /* Looks up the cmdline for the process and tries to find
38 * the most descriptive five characters, then inserts the
39 * short name into the provided event value.
41 #define PROC_NAME_LEN 5
42 static void insertProcessName(long long *ep)
44 static bool foundRealName = false;
45 static char name[PROC_NAME_LEN] = { 'X', 'X', 'X', 'X', 'X' };
46 long long event = *ep;
49 int fd = open("/proc/self/cmdline", O_RDONLY);
52 ssize_t n = read(fd, buf, sizeof(buf) - 1);
55 memset(name, 0, sizeof(name));
56 if (n <= PROC_NAME_LEN) {
57 // The whole name fits.
60 /* We need to truncate. The name will look something
61 * like "com.android.home". Favor the characters
62 * immediately following the last dot.
65 char *dot = strrchr(buf, '.');
67 /* Or, look for a slash, in case it's something like
68 * "/system/bin/runtime".
70 dot = strrchr(buf, '/');
73 dot++; // Skip the dot
74 size_t dotlen = strlen(dot);
75 if (dotlen < PROC_NAME_LEN) {
76 /* Use all available characters. We know that
77 * n > PROC_NAME_LEN from the check above.
79 dot -= PROC_NAME_LEN - dotlen;
81 strncpy(name, dot, PROC_NAME_LEN);
83 // No dot; just use the leading characters.
84 memcpy(name, buf, PROC_NAME_LEN);
87 if (strcmp(buf, "zygote") != 0) {
88 /* If the process is no longer called "zygote",
97 event &= ~(0xffffffffffLL << 24);
98 event |= (long long)name[0] << 56;
99 event |= (long long)name[1] << 48;
100 event |= (long long)name[2] << 40;
101 event |= (long long)name[3] << 32;
102 event |= (long long)name[4] << 24;
107 // See device/data/etc/event-log-tags
108 #define EVENT_LOG_TAG_dvm_gc_info 20001
109 #define EVENT_LOG_TAG_dvm_gc_madvise_info 20002
111 void dvmLogGcStats(size_t numFreed, size_t sizeFreed, size_t gcTimeMs)
113 const GcHeap *gcHeap = gDvm.gcHeap;
114 size_t perHeapActualSize[HEAP_SOURCE_MAX_HEAP_COUNT],
115 perHeapAllowedSize[HEAP_SOURCE_MAX_HEAP_COUNT],
116 perHeapNumAllocated[HEAP_SOURCE_MAX_HEAP_COUNT],
117 perHeapSizeAllocated[HEAP_SOURCE_MAX_HEAP_COUNT];
118 unsigned char eventBuf[1 + (1 + sizeof(long long)) * 4];
119 size_t actualSize, allowedSize, numAllocated, sizeAllocated;
121 size_t softLimit = dvmHeapSourceGetIdealFootprint();
122 size_t nHeaps = dvmHeapSourceGetNumHeaps();
124 /* Enough to quiet down gcc for unitialized variable check */
125 perHeapActualSize[0] = perHeapAllowedSize[0] = perHeapNumAllocated[0] =
126 perHeapSizeAllocated[0] = 0;
127 actualSize = dvmHeapSourceGetValue(HS_FOOTPRINT, perHeapActualSize,
128 HEAP_SOURCE_MAX_HEAP_COUNT);
129 allowedSize = dvmHeapSourceGetValue(HS_ALLOWED_FOOTPRINT,
130 perHeapAllowedSize, HEAP_SOURCE_MAX_HEAP_COUNT);
131 numAllocated = dvmHeapSourceGetValue(HS_OBJECTS_ALLOCATED,
132 perHeapNumAllocated, HEAP_SOURCE_MAX_HEAP_COUNT);
133 sizeAllocated = dvmHeapSourceGetValue(HS_BYTES_ALLOCATED,
134 perHeapSizeAllocated, HEAP_SOURCE_MAX_HEAP_COUNT);
137 * Construct the the first 64-bit value to write to the log.
138 * Global information:
141 * [62-24] ASCII process identifier
142 * [23-12] GC time in ms
143 * [11- 0] Bytes freed
148 (long long)intToFloat12(gcTimeMs) << 12 |
149 (long long)intToFloat12(sizeFreed);
150 insertProcessName(&event0);
153 * Aggregated heap stats:
156 * [61-60] Reserved; must be zero
157 * [59-48] Objects freed
158 * [47-36] Actual size (current footprint)
159 * [35-24] Allowed size (current hard max)
160 * [23-12] Objects allocated
161 * [11- 0] Bytes allocated
165 (long long)intToFloat12(numFreed) << 48 |
166 (long long)intToFloat12(actualSize) << 36 |
167 (long long)intToFloat12(allowedSize) << 24 |
168 (long long)intToFloat12(numAllocated) << 12 |
169 (long long)intToFloat12(sizeAllocated);
172 * Report the current state of the zygote heap(s).
174 * The active heap is always heap[0]. We can be in one of three states
177 * (1) Still in the zygote. Zygote using heap[0].
178 * (2) In the zygote, when the first child is started. We created a
179 * new heap just before the first fork() call, so the original
180 * "zygote heap" is now heap[1], and we have a small heap[0] for
181 * anything we do from here on.
182 * (3) In an app process. The app gets a new heap[0], and can also
183 * see the two zygote heaps [1] and [2] (probably unwise to
184 * assume any specific ordering).
186 * So if nHeaps == 1, we want the stats from heap[0]; else we want
187 * the sum of the values from heap[1] to heap[nHeaps-1].
190 * Zygote heap stats (except for the soft limit, which belongs to the
194 * [61-60] Reserved; must be zero
195 * [59-48] Soft Limit (for the active heap)
196 * [47-36] Actual size (current footprint)
197 * [35-24] Allowed size (current hard max)
198 * [23-12] Objects allocated
199 * [11- 0] Bytes allocated
202 size_t zActualSize, zAllowedSize, zNumAllocated, zSizeAllocated;
203 int firstHeap = (nHeaps == 1) ? 0 : 1;
206 zActualSize = zAllowedSize = zNumAllocated = zSizeAllocated = 0;
207 for (hh = firstHeap; hh < nHeaps; hh++) {
208 zActualSize += perHeapActualSize[hh];
209 zAllowedSize += perHeapAllowedSize[hh];
210 zNumAllocated += perHeapNumAllocated[hh];
211 zSizeAllocated += perHeapSizeAllocated[hh];
214 (long long)intToFloat12(softLimit) << 48 |
215 (long long)intToFloat12(zActualSize) << 36 |
216 (long long)intToFloat12(zAllowedSize) << 24 |
217 (long long)intToFloat12(zNumAllocated) << 12 |
218 (long long)intToFloat12(zSizeAllocated);
221 * Report the current external allocation stats and the native heap
224 * [63-48] Reserved; must be zero (TODO: put new data in these slots)
225 * [47-36] dlmalloc_footprint
226 * [35-24] mallinfo: total allocated space
227 * [23-12] External byte limit
228 * [11- 0] External bytes allocated
231 size_t externalLimit, externalBytesAllocated;
232 size_t uordblks, footprint;
236 * This adds 2-5msec to the GC cost on a DVT, or about 2-3% of the cost
237 * of a GC, so it's not horribly expensive but it's not free either.
239 extern size_t dlmalloc_footprint(void);
243 //start = dvmGetRelativeTimeNsec();
245 uordblks = mi.uordblks;
246 footprint = dlmalloc_footprint();
247 //end = dvmGetRelativeTimeNsec();
248 //LOGD("mallinfo+footprint took %dusec; used=%zd footprint=%zd\n",
249 // (int)((end - start) / 1000), mi.uordblks, footprint);
251 uordblks = footprint = 0;
255 dvmHeapSourceGetValue(HS_EXTERNAL_LIMIT, NULL, 0);
256 externalBytesAllocated =
257 dvmHeapSourceGetValue(HS_EXTERNAL_BYTES_ALLOCATED, NULL, 0);
259 (long long)intToFloat12(footprint) << 36 |
260 (long long)intToFloat12(uordblks) << 24 |
261 (long long)intToFloat12(externalLimit) << 12 |
262 (long long)intToFloat12(externalBytesAllocated);
264 /* Build the event data.
265 * [ 0: 0] item count (4)
266 * [ 1: 1] EVENT_TYPE_LONG
268 * [10:10] EVENT_TYPE_LONG
270 * [19:19] EVENT_TYPE_LONG
272 * [28:28] EVENT_TYPE_LONG
275 unsigned char *c = eventBuf;
277 *c++ = EVENT_TYPE_LONG;
278 memcpy(c, &event0, sizeof(event0));
280 *c++ = EVENT_TYPE_LONG;
281 memcpy(c, &event1, sizeof(event1));
283 *c++ = EVENT_TYPE_LONG;
284 memcpy(c, &event2, sizeof(event2));
286 *c++ = EVENT_TYPE_LONG;
287 memcpy(c, &event3, sizeof(event3));
289 (void) android_btWriteLog(EVENT_LOG_TAG_dvm_gc_info, EVENT_TYPE_LIST,
290 eventBuf, sizeof(eventBuf));
293 void dvmLogMadviseStats(size_t madvisedSizes[], size_t arrayLen)
295 unsigned char eventBuf[1 + (1 + sizeof(int)) * 2];
298 size_t nHeaps = dvmHeapSourceGetNumHeaps();
300 assert(arrayLen >= nHeaps);
302 firstHeap = nHeaps > 1 ? 1 : 0;
305 for (i = 0; i < nHeaps; i++) {
306 total += madvisedSizes[i];
307 if (i >= firstHeap) {
308 zyg += madvisedSizes[i];
312 /* Build the event data.
313 * [ 0: 0] item count (2)
314 * [ 1: 1] EVENT_TYPE_INT
315 * [ 2: 5] total madvise byte count
316 * [ 6: 6] EVENT_TYPE_INT
317 * [ 7:10] zygote heap madvise byte count
319 unsigned char *c = eventBuf;
321 *c++ = EVENT_TYPE_INT;
322 memcpy(c, &total, sizeof(total));
324 *c++ = EVENT_TYPE_INT;
325 memcpy(c, &zyg, sizeof(zyg));
328 (void) android_btWriteLog(EVENT_LOG_TAG_dvm_gc_madvise_info,
329 EVENT_TYPE_LIST, eventBuf, sizeof(eventBuf));
336 typedef struct HeapDumpContext {
344 dump_context(const HeapDumpContext *ctx)
346 fprintf(ctx->fp, "0x%08x %12.12zd %s\n", (uintptr_t)ctx->chunkStart,
347 ctx->chunkLen, ctx->chunkFree ? "FREE" : "USED");
351 heap_chunk_callback(const void *chunkptr, size_t chunklen,
352 const void *userptr, size_t userlen, void *arg)
354 HeapDumpContext *ctx = (HeapDumpContext *)arg;
355 bool chunkFree = (userptr == NULL);
357 if (chunkFree != ctx->chunkFree ||
358 ((char *)ctx->chunkStart + ctx->chunkLen) != chunkptr)
360 /* The new chunk is of a different type or isn't
361 * contiguous with the current chunk. Dump the
362 * old one and start a new one.
364 if (ctx->chunkStart != NULL) {
365 /* It's not the first chunk. */
368 ctx->chunkStart = (void *)chunkptr;
369 ctx->chunkLen = chunklen;
370 ctx->chunkFree = chunkFree;
372 /* Extend the current chunk.
374 ctx->chunkLen += chunklen;
378 /* Dumps free and used ranges, as text, to the named file.
380 void dvmDumpHeapToFile(const char *fileName)
385 fp = fopen(fileName, "w+");
387 LOGE("Can't open %s for writing: %s\n", fileName, strerror(errno));
390 LOGW("Dumping heap to %s...\n", fileName);
392 fprintf(fp, "==== Dalvik heap dump ====\n");
393 memset(&ctx, 0, sizeof(ctx));
395 dvmHeapSourceWalk(heap_chunk_callback, (void *)&ctx);
397 fprintf(fp, "==== end heap dump ====\n");
399 LOGW("Dumped heap to %s.\n", fileName);