Home | History | Annotate | Download | only in libpagemap
      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 <stdlib.h>
     18 #include <unistd.h>
     19 
     20 #include <pagemap/pagemap.h>
     21 
     22 #define SIMPLEQ_INSERT_SIMPLEQ_TAIL(head_a, head_b)             \
     23     do {                                                        \
     24         if (!SIMPLEQ_EMPTY(head_b)) {                           \
     25             if ((head_a)->sqh_first == NULL)                    \
     26                 (head_a)->sqh_first = (head_b)->sqh_first;      \
     27             *(head_a)->sqh_last = (head_b)->sqh_first;          \
     28             (head_a)->sqh_last = (head_b)->sqh_last;            \
     29         }                                                       \
     30     } while (/*CONSTCOND*/0)
     31 
     32 /* We use an array of int to store the references to a given offset in the swap
     33    1 GiB swap means 512KiB size array: offset are the index */
     34 typedef unsigned short pm_pswap_refcount_t;
     35 struct pm_proportional_swap {
     36     unsigned int array_size;
     37     pm_pswap_refcount_t *offset_array;
     38 };
     39 
     40 void pm_memusage_zero(pm_memusage_t *mu) {
     41     mu->vss = mu->rss = mu->pss = mu->uss = mu->swap = 0;
     42     mu->p_swap = NULL;
     43     SIMPLEQ_INIT(&mu->swap_offset_list);
     44 }
     45 
     46 void pm_memusage_pswap_init_handle(pm_memusage_t *mu, pm_proportional_swap_t *p_swap) {
     47     mu->p_swap = p_swap;
     48 }
     49 
     50 void pm_memusage_add(pm_memusage_t *a, pm_memusage_t *b) {
     51     a->vss += b->vss;
     52     a->rss += b->rss;
     53     a->pss += b->pss;
     54     a->uss += b->uss;
     55     a->swap += b->swap;
     56     SIMPLEQ_INSERT_SIMPLEQ_TAIL(&a->swap_offset_list, &b->swap_offset_list);
     57 }
     58 
     59 pm_proportional_swap_t * pm_memusage_pswap_create(int swap_size)
     60 {
     61     pm_proportional_swap_t *p_swap = NULL;
     62 
     63     p_swap = malloc(sizeof(pm_proportional_swap_t));
     64     if (p_swap == NULL) {
     65         fprintf(stderr, "Error allocating proportional swap.\n");
     66     } else {
     67         p_swap->array_size = swap_size / getpagesize();
     68         p_swap->offset_array = calloc(p_swap->array_size, sizeof(pm_pswap_refcount_t));
     69         if (p_swap->offset_array == NULL) {
     70             fprintf(stderr, "Error allocating proportional swap offset array.\n");
     71             free(p_swap);
     72             p_swap = NULL;
     73         }
     74     }
     75 
     76     return p_swap;
     77 }
     78 
     79 void pm_memusage_pswap_destroy(pm_proportional_swap_t *p_swap) {
     80     if (p_swap) {
     81         free(p_swap->offset_array);
     82         free(p_swap);
     83     }
     84 }
     85 
     86 void pm_memusage_pswap_add_offset(pm_memusage_t *mu, unsigned int offset) {
     87     pm_swap_offset_t *soff;
     88 
     89     if (mu->p_swap == NULL)
     90         return;
     91 
     92     if (offset >= mu->p_swap->array_size) {
     93         fprintf(stderr, "SWAP offset %d is out of swap bounds.\n", offset);
     94         return;
     95     }
     96 
     97     if (mu->p_swap->offset_array[offset] == USHRT_MAX) {
     98         fprintf(stderr, "SWAP offset %d ref. count if overflowing ushort type.\n", offset);
     99     } else {
    100         mu->p_swap->offset_array[offset]++;
    101     }
    102 
    103     soff = malloc(sizeof(pm_swap_offset_t));
    104     if (soff) {
    105         soff->offset = offset;
    106         SIMPLEQ_INSERT_TAIL(&mu->swap_offset_list, soff, simpleqe);
    107     }
    108 }
    109 
    110 void pm_memusage_pswap_get_usage(pm_memusage_t *mu, pm_swapusage_t *su) {
    111 
    112     int pagesize = getpagesize();
    113     pm_swap_offset_t *elem;
    114 
    115     if (su == NULL)
    116         return;
    117 
    118     su->proportional = su->unique = 0;
    119     SIMPLEQ_FOREACH(elem, &mu->swap_offset_list, simpleqe) {
    120         su->proportional += pagesize / mu->p_swap->offset_array[elem->offset];
    121         su->unique += mu->p_swap->offset_array[elem->offset] == 1 ? pagesize : 0;
    122     }
    123 }
    124 
    125 void pm_memusage_pswap_free(pm_memusage_t *mu) {
    126     pm_swap_offset_t *elem = SIMPLEQ_FIRST(&mu->swap_offset_list);
    127     while (elem) {
    128         SIMPLEQ_REMOVE_HEAD(&mu->swap_offset_list, simpleqe);
    129         free(elem);
    130         elem = SIMPLEQ_FIRST(&mu->swap_offset_list);
    131     }
    132 }
    133