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