Home | History | Annotate | Download | only in alloc
      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 #include <fcntl.h>
     18 #include <stdlib.h>
     19 
     20 #include "Dalvik.h"
     21 #include "HeapInternal.h"
     22 #include "HeapSource.h"
     23 #include "Float12.h"
     24 
     25 int dvmGetHeapDebugInfo(HeapDebugInfoType info)
     26 {
     27     switch (info) {
     28     case kVirtualHeapSize:
     29         return (int)dvmHeapSourceGetValue(HS_FOOTPRINT, NULL, 0);
     30     case kVirtualHeapAllocated:
     31         return (int)dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0);
     32     default:
     33         return -1;
     34     }
     35 }
     36 
     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.
     40  */
     41 #define PROC_NAME_LEN 5
     42 static void insertProcessName(long long *ep)
     43 {
     44     static bool foundRealName = false;
     45     static char name[PROC_NAME_LEN] = { 'X', 'X', 'X', 'X', 'X' };
     46     long long event = *ep;
     47 
     48     if (!foundRealName) {
     49         int fd = open("/proc/self/cmdline", O_RDONLY);
     50         if (fd > 0) {
     51             char buf[128];
     52             ssize_t n = read(fd, buf, sizeof(buf) - 1);
     53             close(fd);
     54             if (n > 0) {
     55                 memset(name, 0, sizeof(name));
     56                 if (n <= PROC_NAME_LEN) {
     57                     // The whole name fits.
     58                     memcpy(name, buf, n);
     59                 } else {
     60                     /* We need to truncate.  The name will look something
     61                      * like "com.android.home".  Favor the characters
     62                      * immediately following the last dot.
     63                      */
     64                     buf[n] = '\0';
     65                     char *dot = strrchr(buf, '.');
     66                     if (dot == NULL) {
     67                         /* Or, look for a slash, in case it's something like
     68                          * "/system/bin/runtime".
     69                          */
     70                         dot = strrchr(buf, '/');
     71                     }
     72                     if (dot != NULL) {
     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.
     78                              */
     79                             dot -= PROC_NAME_LEN - dotlen;
     80                         }
     81                         strncpy(name, dot, PROC_NAME_LEN);
     82                     } else {
     83                         // No dot; just use the leading characters.
     84                         memcpy(name, buf, PROC_NAME_LEN);
     85                     }
     86                 }
     87                 if (strcmp(buf, "zygote") != 0) {
     88                     /* If the process is no longer called "zygote",
     89                      * cache this name.
     90                      */
     91                     foundRealName = true;
     92                 }
     93             }
     94         }
     95     }
     96 
     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;
    103 
    104     *ep = event;
    105 }
    106 
    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
    110 
    111 void dvmLogGcStats(size_t numFreed, size_t sizeFreed, size_t gcTimeMs)
    112 {
    113     size_t perHeapActualSize[HEAP_SOURCE_MAX_HEAP_COUNT],
    114            perHeapAllowedSize[HEAP_SOURCE_MAX_HEAP_COUNT],
    115            perHeapNumAllocated[HEAP_SOURCE_MAX_HEAP_COUNT],
    116            perHeapSizeAllocated[HEAP_SOURCE_MAX_HEAP_COUNT];
    117     unsigned char eventBuf[1 + (1 + sizeof(long long)) * 4];
    118     size_t actualSize, allowedSize, numAllocated, sizeAllocated;
    119     size_t softLimit = dvmHeapSourceGetIdealFootprint();
    120     size_t nHeaps = dvmHeapSourceGetNumHeaps();
    121 
    122     /* Enough to quiet down gcc for unitialized variable check */
    123     perHeapActualSize[0] = perHeapAllowedSize[0] = perHeapNumAllocated[0] =
    124                            perHeapSizeAllocated[0] = 0;
    125     actualSize = dvmHeapSourceGetValue(HS_FOOTPRINT, perHeapActualSize,
    126                                        HEAP_SOURCE_MAX_HEAP_COUNT);
    127     allowedSize = dvmHeapSourceGetValue(HS_ALLOWED_FOOTPRINT,
    128                       perHeapAllowedSize, HEAP_SOURCE_MAX_HEAP_COUNT);
    129     numAllocated = dvmHeapSourceGetValue(HS_OBJECTS_ALLOCATED,
    130                       perHeapNumAllocated, HEAP_SOURCE_MAX_HEAP_COUNT);
    131     sizeAllocated = dvmHeapSourceGetValue(HS_BYTES_ALLOCATED,
    132                       perHeapSizeAllocated, HEAP_SOURCE_MAX_HEAP_COUNT);
    133 
    134     /*
    135      * Construct the the first 64-bit value to write to the log.
    136      * Global information:
    137      *
    138      * [63   ] Must be zero
    139      * [62-24] ASCII process identifier
    140      * [23-12] GC time in ms
    141      * [11- 0] Bytes freed
    142      *
    143      */
    144     long long event0;
    145     event0 = 0LL << 63 |
    146             (long long)intToFloat12(gcTimeMs) << 12 |
    147             (long long)intToFloat12(sizeFreed);
    148     insertProcessName(&event0);
    149 
    150     /*
    151      * Aggregated heap stats:
    152      *
    153      * [63-62] 10
    154      * [61-60] Reserved; must be zero
    155      * [59-48] Objects freed
    156      * [47-36] Actual size (current footprint)
    157      * [35-24] Allowed size (current hard max)
    158      * [23-12] Objects allocated
    159      * [11- 0] Bytes allocated
    160      */
    161     long long event1;
    162     event1 = 2LL << 62 |
    163             (long long)intToFloat12(numFreed) << 48 |
    164             (long long)intToFloat12(actualSize) << 36 |
    165             (long long)intToFloat12(allowedSize) << 24 |
    166             (long long)intToFloat12(numAllocated) << 12 |
    167             (long long)intToFloat12(sizeAllocated);
    168 
    169     /*
    170      * Report the current state of the zygote heap(s).
    171      *
    172      * The active heap is always heap[0].  We can be in one of three states
    173      * at present:
    174      *
    175      *  (1) Still in the zygote.  Zygote using heap[0].
    176      *  (2) In the zygote, when the first child is started.  We created a
    177      *      new heap just before the first fork() call, so the original
    178      *      "zygote heap" is now heap[1], and we have a small heap[0] for
    179      *      anything we do from here on.
    180      *  (3) In an app process.  The app gets a new heap[0], and can also
    181      *      see the two zygote heaps [1] and [2] (probably unwise to
    182      *      assume any specific ordering).
    183      *
    184      * So if nHeaps == 1, we want the stats from heap[0]; else we want
    185      * the sum of the values from heap[1] to heap[nHeaps-1].
    186      *
    187      *
    188      * Zygote heap stats (except for the soft limit, which belongs to the
    189      * active heap):
    190      *
    191      * [63-62] 11
    192      * [61-60] Reserved; must be zero
    193      * [59-48] Soft Limit (for the active heap)
    194      * [47-36] Actual size (current footprint)
    195      * [35-24] Allowed size (current hard max)
    196      * [23-12] Objects allocated
    197      * [11- 0] Bytes allocated
    198      */
    199     long long event2;
    200     size_t zActualSize, zAllowedSize, zNumAllocated, zSizeAllocated;
    201     int firstHeap = (nHeaps == 1) ? 0 : 1;
    202     size_t hh;
    203 
    204     zActualSize = zAllowedSize = zNumAllocated = zSizeAllocated = 0;
    205     for (hh = firstHeap; hh < nHeaps; hh++) {
    206         zActualSize += perHeapActualSize[hh];
    207         zAllowedSize += perHeapAllowedSize[hh];
    208         zNumAllocated += perHeapNumAllocated[hh];
    209         zSizeAllocated += perHeapSizeAllocated[hh];
    210     }
    211     event2 = 3LL << 62 |
    212             (long long)intToFloat12(softLimit) << 48 |
    213             (long long)intToFloat12(zActualSize) << 36 |
    214             (long long)intToFloat12(zAllowedSize) << 24 |
    215             (long long)intToFloat12(zNumAllocated) << 12 |
    216             (long long)intToFloat12(zSizeAllocated);
    217 
    218     /*
    219      * Report the current external allocation stats and the native heap
    220      * summary.
    221      *
    222      * [63-48] Reserved; must be zero (TODO: put new data in these slots)
    223      * [47-36] dlmalloc_footprint
    224      * [35-24] mallinfo: total allocated space
    225      * [23-12] External byte limit
    226      * [11- 0] External bytes allocated
    227      */
    228     long long event3;
    229     size_t externalLimit, externalBytesAllocated;
    230     size_t uordblks, footprint;
    231 
    232 #if 0
    233     /*
    234      * This adds 2-5msec to the GC cost on a DVT, or about 2-3% of the cost
    235      * of a GC, so it's not horribly expensive but it's not free either.
    236      */
    237     extern size_t dlmalloc_footprint(void);
    238     struct mallinfo mi;
    239     //u8 start, end;
    240 
    241     //start = dvmGetRelativeTimeNsec();
    242     mi = mallinfo();
    243     uordblks = mi.uordblks;
    244     footprint = dlmalloc_footprint();
    245     //end = dvmGetRelativeTimeNsec();
    246     //LOGD("mallinfo+footprint took %dusec; used=%zd footprint=%zd\n",
    247     //    (int)((end - start) / 1000), mi.uordblks, footprint);
    248 #else
    249     uordblks = footprint = 0;
    250 #endif
    251 
    252     externalLimit =
    253             dvmHeapSourceGetValue(HS_EXTERNAL_LIMIT, NULL, 0);
    254     externalBytesAllocated =
    255             dvmHeapSourceGetValue(HS_EXTERNAL_BYTES_ALLOCATED, NULL, 0);
    256     event3 =
    257             (long long)intToFloat12(footprint) << 36 |
    258             (long long)intToFloat12(uordblks) << 24 |
    259             (long long)intToFloat12(externalLimit) << 12 |
    260             (long long)intToFloat12(externalBytesAllocated);
    261 
    262     /* Build the event data.
    263      * [ 0: 0] item count (4)
    264      * [ 1: 1] EVENT_TYPE_LONG
    265      * [ 2: 9] event0
    266      * [10:10] EVENT_TYPE_LONG
    267      * [11:18] event1
    268      * [19:19] EVENT_TYPE_LONG
    269      * [20:27] event2
    270      * [28:28] EVENT_TYPE_LONG
    271      * [29:36] event2
    272      */
    273     unsigned char *c = eventBuf;
    274     *c++ = 4;
    275     *c++ = EVENT_TYPE_LONG;
    276     memcpy(c, &event0, sizeof(event0));
    277     c += sizeof(event0);
    278     *c++ = EVENT_TYPE_LONG;
    279     memcpy(c, &event1, sizeof(event1));
    280     c += sizeof(event1);
    281     *c++ = EVENT_TYPE_LONG;
    282     memcpy(c, &event2, sizeof(event2));
    283     c += sizeof(event2);
    284     *c++ = EVENT_TYPE_LONG;
    285     memcpy(c, &event3, sizeof(event3));
    286 
    287     (void) android_btWriteLog(EVENT_LOG_TAG_dvm_gc_info, EVENT_TYPE_LIST,
    288             eventBuf, sizeof(eventBuf));
    289 }
    290 
    291 void dvmLogMadviseStats(size_t madvisedSizes[], size_t arrayLen)
    292 {
    293     unsigned char eventBuf[1 + (1 + sizeof(int)) * 2];
    294     size_t total, zyg;
    295     size_t firstHeap, i;
    296     size_t nHeaps = dvmHeapSourceGetNumHeaps();
    297 
    298     assert(arrayLen >= nHeaps);
    299 
    300     firstHeap = nHeaps > 1 ? 1 : 0;
    301     total = 0;
    302     zyg = 0;
    303     for (i = 0; i < nHeaps; i++) {
    304         total += madvisedSizes[i];
    305         if (i >= firstHeap) {
    306             zyg += madvisedSizes[i];
    307         }
    308     }
    309 
    310     /* Build the event data.
    311      * [ 0: 0] item count (2)
    312      * [ 1: 1] EVENT_TYPE_INT
    313      * [ 2: 5] total madvise byte count
    314      * [ 6: 6] EVENT_TYPE_INT
    315      * [ 7:10] zygote heap madvise byte count
    316      */
    317     unsigned char *c = eventBuf;
    318     *c++ = 2;
    319     *c++ = EVENT_TYPE_INT;
    320     memcpy(c, &total, sizeof(total));
    321     c += sizeof(total);
    322     *c++ = EVENT_TYPE_INT;
    323     memcpy(c, &zyg, sizeof(zyg));
    324     c += sizeof(zyg);
    325 
    326     (void) android_btWriteLog(EVENT_LOG_TAG_dvm_gc_madvise_info,
    327             EVENT_TYPE_LIST, eventBuf, sizeof(eventBuf));
    328 }
    329 
    330 #if 0
    331 #include <errno.h>
    332 #include <stdio.h>
    333 
    334 typedef struct HeapDumpContext {
    335     FILE *fp;
    336     void *chunkStart;
    337     size_t chunkLen;
    338     bool chunkFree;
    339 } HeapDumpContext;
    340 
    341 static void
    342 dump_context(const HeapDumpContext *ctx)
    343 {
    344     fprintf(ctx->fp, "0x%08x %12.12zd %s\n", (uintptr_t)ctx->chunkStart,
    345             ctx->chunkLen, ctx->chunkFree ? "FREE" : "USED");
    346 }
    347 
    348 static void
    349 heap_chunk_callback(const void *chunkptr, size_t chunklen,
    350                     const void *userptr, size_t userlen, void *arg)
    351 {
    352     HeapDumpContext *ctx = (HeapDumpContext *)arg;
    353     bool chunkFree = (userptr == NULL);
    354 
    355     if (chunkFree != ctx->chunkFree ||
    356             ((char *)ctx->chunkStart + ctx->chunkLen) != chunkptr)
    357     {
    358         /* The new chunk is of a different type or isn't
    359          * contiguous with the current chunk.  Dump the
    360          * old one and start a new one.
    361          */
    362         if (ctx->chunkStart != NULL) {
    363             /* It's not the first chunk. */
    364             dump_context(ctx);
    365         }
    366         ctx->chunkStart = (void *)chunkptr;
    367         ctx->chunkLen = chunklen;
    368         ctx->chunkFree = chunkFree;
    369     } else {
    370         /* Extend the current chunk.
    371          */
    372         ctx->chunkLen += chunklen;
    373     }
    374 }
    375 
    376 /* Dumps free and used ranges, as text, to the named file.
    377  */
    378 void dvmDumpHeapToFile(const char *fileName)
    379 {
    380     HeapDumpContext ctx;
    381     FILE *fp;
    382 
    383     fp = fopen(fileName, "w+");
    384     if (fp == NULL) {
    385         LOGE("Can't open %s for writing: %s\n", fileName, strerror(errno));
    386         return;
    387     }
    388     LOGW("Dumping heap to %s...\n", fileName);
    389 
    390     fprintf(fp, "==== Dalvik heap dump ====\n");
    391     memset(&ctx, 0, sizeof(ctx));
    392     ctx.fp = fp;
    393     dvmHeapSourceWalk(heap_chunk_callback, (void *)&ctx);
    394     dump_context(&ctx);
    395     fprintf(fp, "==== end heap dump ====\n");
    396 
    397     LOGW("Dumped heap to %s.\n", fileName);
    398 
    399     fclose(fp);
    400 }
    401 #endif
    402