Home | History | Annotate | Download | only in libmemtrack
      1 /*
      2  * Copyright (C) 2013 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 <memtrack/memtrack.h>
     18 
     19 #define LOG_TAG "memtrack"
     20 
     21 #include <log/log.h>
     22 
     23 #include <errno.h>
     24 #include <malloc.h>
     25 #include <string.h>
     26 
     27 #include <hardware/memtrack.h>
     28 
     29 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
     30 
     31 static const memtrack_module_t *module;
     32 
     33 struct memtrack_proc {
     34     pid_t pid;
     35     struct memtrack_proc_type {
     36         enum memtrack_type type;
     37         size_t num_records;
     38         size_t allocated_records;
     39         struct memtrack_record *records;
     40     } types[MEMTRACK_NUM_TYPES];
     41 };
     42 
     43 int memtrack_init(void)
     44 {
     45     int err;
     46 
     47     if (module) {
     48         return 0;
     49     }
     50 
     51     err = hw_get_module(MEMTRACK_HARDWARE_MODULE_ID,
     52             (hw_module_t const**)&module);
     53     if (err) {
     54         ALOGE("Couldn't load %s module (%s)", MEMTRACK_HARDWARE_MODULE_ID,
     55                 strerror(-err));
     56         return err;
     57     }
     58 
     59     return module->init(module);
     60 }
     61 
     62 struct memtrack_proc *memtrack_proc_new(void)
     63 {
     64     if (!module) {
     65         return NULL;
     66     }
     67 
     68     return calloc(sizeof(struct memtrack_proc), 1);
     69 }
     70 
     71 void memtrack_proc_destroy(struct memtrack_proc *p)
     72 {
     73     enum memtrack_type i;
     74 
     75     if (p) {
     76         for (i = 0; i < MEMTRACK_NUM_TYPES; i++) {
     77             free(p->types[i].records);
     78         }
     79     }
     80     free(p);
     81 }
     82 
     83 static int memtrack_proc_get_type(struct memtrack_proc_type *t,
     84             pid_t pid, enum memtrack_type type)
     85 {
     86     size_t num_records = t->num_records;
     87     int ret;
     88 
     89 retry:
     90     ret = module->getMemory(module, pid, type, t->records, &num_records);
     91     if (ret) {
     92         t->num_records = 0;
     93         return ret;
     94     }
     95     if (num_records > t->allocated_records) {
     96         /* Need more records than allocated */
     97         free(t->records);
     98         t->records = calloc(sizeof(*t->records), num_records);
     99         if (!t->records) {
    100             return -ENOMEM;
    101         }
    102         t->allocated_records = num_records;
    103         goto retry;
    104     }
    105     t->num_records = num_records;
    106 
    107     return 0;
    108 }
    109 
    110 /* TODO: sanity checks on return values from HALs:
    111  *   make sure no records have invalid flags set
    112  *    - unknown flags
    113  *    - too many flags of a single category
    114  *    - missing ACCOUNTED/UNACCOUNTED
    115  *   make sure there are not overlapping SHARED and SHARED_PSS records
    116  */
    117 static int memtrack_proc_sanity_check(struct memtrack_proc *p)
    118 {
    119     (void)p;
    120     return 0;
    121 }
    122 
    123 int memtrack_proc_get(struct memtrack_proc *p, pid_t pid)
    124 {
    125     enum memtrack_type i;
    126 
    127     if (!module) {
    128         return -EINVAL;
    129     }
    130 
    131     if (!p) {
    132         return -EINVAL;
    133     }
    134 
    135     p->pid = pid;
    136     for (i = 0; i < MEMTRACK_NUM_TYPES; i++) {
    137         memtrack_proc_get_type(&p->types[i], pid, i);
    138     }
    139 
    140     return memtrack_proc_sanity_check(p);
    141 }
    142 
    143 static ssize_t memtrack_proc_sum(struct memtrack_proc *p,
    144             enum memtrack_type types[], size_t num_types,
    145             unsigned int flags)
    146 {
    147     ssize_t sum = 0;
    148     size_t i;
    149     size_t j;
    150 
    151     for (i = 0; i < num_types; i++) {
    152         enum memtrack_type type = types[i];
    153         for (j = 0; j < p->types[type].num_records; j++) {
    154             if ((p->types[type].records[j].flags & flags) == flags) {
    155                 sum += p->types[type].records[j].size_in_bytes;
    156             }
    157         }
    158     }
    159 
    160     return sum;
    161 }
    162 
    163 ssize_t memtrack_proc_graphics_total(struct memtrack_proc *p)
    164 {
    165     enum memtrack_type types[] = { MEMTRACK_TYPE_GRAPHICS };
    166     return memtrack_proc_sum(p, types, ARRAY_SIZE(types), 0);
    167 }
    168 
    169 ssize_t memtrack_proc_graphics_pss(struct memtrack_proc *p)
    170 {
    171     enum memtrack_type types[] = { MEMTRACK_TYPE_GRAPHICS };
    172     return memtrack_proc_sum(p, types, ARRAY_SIZE(types),
    173                 MEMTRACK_FLAG_SMAPS_UNACCOUNTED);
    174 }
    175 
    176 ssize_t memtrack_proc_gl_total(struct memtrack_proc *p)
    177 {
    178     enum memtrack_type types[] = { MEMTRACK_TYPE_GL };
    179     return memtrack_proc_sum(p, types, ARRAY_SIZE(types), 0);
    180 }
    181 
    182 ssize_t memtrack_proc_gl_pss(struct memtrack_proc *p)
    183 {
    184     enum memtrack_type types[] = { MEMTRACK_TYPE_GL };
    185     return memtrack_proc_sum(p, types, ARRAY_SIZE(types),
    186                 MEMTRACK_FLAG_SMAPS_UNACCOUNTED);
    187 }
    188 
    189 ssize_t memtrack_proc_other_total(struct memtrack_proc *p)
    190 {
    191     enum memtrack_type types[] = { MEMTRACK_TYPE_MULTIMEDIA,
    192                                         MEMTRACK_TYPE_CAMERA,
    193                                         MEMTRACK_TYPE_OTHER };
    194     return memtrack_proc_sum(p, types, ARRAY_SIZE(types), 0);
    195 }
    196 
    197 ssize_t memtrack_proc_other_pss(struct memtrack_proc *p)
    198 {
    199     enum memtrack_type types[] = { MEMTRACK_TYPE_MULTIMEDIA,
    200                                         MEMTRACK_TYPE_CAMERA,
    201                                         MEMTRACK_TYPE_OTHER };
    202     return memtrack_proc_sum(p, types, ARRAY_SIZE(types),
    203                 MEMTRACK_FLAG_SMAPS_UNACCOUNTED);
    204 }
    205