/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <stdlib.h> #include <unistd.h> #include <pagemap/pagemap.h> #define SIMPLEQ_INSERT_SIMPLEQ_TAIL(head_a, head_b) \ do { \ if (!SIMPLEQ_EMPTY(head_b)) { \ if ((head_a)->sqh_first == NULL) \ (head_a)->sqh_first = (head_b)->sqh_first; \ *(head_a)->sqh_last = (head_b)->sqh_first; \ (head_a)->sqh_last = (head_b)->sqh_last; \ } \ } while (/*CONSTCOND*/0) /* We use an array of int to store the references to a given offset in the swap 1 GiB swap means 512KiB size array: offset are the index */ typedef unsigned short pm_pswap_refcount_t; struct pm_proportional_swap { unsigned int array_size; pm_pswap_refcount_t *offset_array; }; void pm_memusage_zero(pm_memusage_t *mu) { mu->vss = mu->rss = mu->pss = mu->uss = mu->swap = 0; mu->p_swap = NULL; SIMPLEQ_INIT(&mu->swap_offset_list); } void pm_memusage_pswap_init_handle(pm_memusage_t *mu, pm_proportional_swap_t *p_swap) { mu->p_swap = p_swap; } void pm_memusage_add(pm_memusage_t *a, pm_memusage_t *b) { a->vss += b->vss; a->rss += b->rss; a->pss += b->pss; a->uss += b->uss; a->swap += b->swap; SIMPLEQ_INSERT_SIMPLEQ_TAIL(&a->swap_offset_list, &b->swap_offset_list); } pm_proportional_swap_t * pm_memusage_pswap_create(int swap_size) { pm_proportional_swap_t *p_swap = NULL; p_swap = malloc(sizeof(pm_proportional_swap_t)); if (p_swap == NULL) { fprintf(stderr, "Error allocating proportional swap.\n"); } else { p_swap->array_size = swap_size / getpagesize(); p_swap->offset_array = calloc(p_swap->array_size, sizeof(pm_pswap_refcount_t)); if (p_swap->offset_array == NULL) { fprintf(stderr, "Error allocating proportional swap offset array.\n"); free(p_swap); p_swap = NULL; } } return p_swap; } void pm_memusage_pswap_destroy(pm_proportional_swap_t *p_swap) { if (p_swap) { free(p_swap->offset_array); free(p_swap); } } void pm_memusage_pswap_add_offset(pm_memusage_t *mu, unsigned int offset) { pm_swap_offset_t *soff; if (mu->p_swap == NULL) return; if (offset >= mu->p_swap->array_size) { fprintf(stderr, "SWAP offset %d is out of swap bounds.\n", offset); return; } if (mu->p_swap->offset_array[offset] == USHRT_MAX) { fprintf(stderr, "SWAP offset %d ref. count if overflowing ushort type.\n", offset); } else { mu->p_swap->offset_array[offset]++; } soff = malloc(sizeof(pm_swap_offset_t)); if (soff) { soff->offset = offset; SIMPLEQ_INSERT_TAIL(&mu->swap_offset_list, soff, simpleqe); } } void pm_memusage_pswap_get_usage(pm_memusage_t *mu, pm_swapusage_t *su) { int pagesize = getpagesize(); pm_swap_offset_t *elem; if (su == NULL) return; su->proportional = su->unique = 0; SIMPLEQ_FOREACH(elem, &mu->swap_offset_list, simpleqe) { su->proportional += pagesize / mu->p_swap->offset_array[elem->offset]; su->unique += mu->p_swap->offset_array[elem->offset] == 1 ? pagesize : 0; } } void pm_memusage_pswap_free(pm_memusage_t *mu) { pm_swap_offset_t *elem = SIMPLEQ_FIRST(&mu->swap_offset_list); while (elem) { SIMPLEQ_REMOVE_HEAD(&mu->swap_offset_list, simpleqe); free(elem); elem = SIMPLEQ_FIRST(&mu->swap_offset_list); } }