1e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project/*
2e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
3e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project *
4e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * you may not use this file except in compliance with the License.
6e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * You may obtain a copy of the License at
7e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project *
8e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project *
10e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * See the License for the specific language governing permissions and
14e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project * limitations under the License.
15e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project */
16e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
1708ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel#include <stdlib.h>
1808ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel#include <unistd.h>
1908ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel
20e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project#include <pagemap/pagemap.h>
21e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
2208ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel#define SIMPLEQ_INSERT_SIMPLEQ_TAIL(head_a, head_b)             \
2308ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    do {                                                        \
2408ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel        if (!SIMPLEQ_EMPTY(head_b)) {                           \
2508ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel            if ((head_a)->sqh_first == NULL)                    \
2608ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel                (head_a)->sqh_first = (head_b)->sqh_first;      \
2708ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel            *(head_a)->sqh_last = (head_b)->sqh_first;          \
2808ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel            (head_a)->sqh_last = (head_b)->sqh_last;            \
2908ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel        }                                                       \
3008ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    } while (/*CONSTCOND*/0)
3108ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel
3208ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel/* We use an array of int to store the references to a given offset in the swap
3308ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel   1 GiB swap means 512KiB size array: offset are the index */
3408ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudeltypedef unsigned short pm_pswap_refcount_t;
3508ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudelstruct pm_proportional_swap {
3608ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    unsigned int array_size;
3708ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    pm_pswap_refcount_t *offset_array;
3808ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel};
3908ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel
40e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectvoid pm_memusage_zero(pm_memusage_t *mu) {
41745b964daeacf44350db14bc343d53e319e696b8Colin Cross    mu->vss = mu->rss = mu->pss = mu->uss = mu->swap = 0;
4208ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    mu->p_swap = NULL;
4308ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    SIMPLEQ_INIT(&mu->swap_offset_list);
4408ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel}
4508ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel
4608ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudelvoid pm_memusage_pswap_init_handle(pm_memusage_t *mu, pm_proportional_swap_t *p_swap) {
4708ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    mu->p_swap = p_swap;
48e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project}
49e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project
50e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Projectvoid pm_memusage_add(pm_memusage_t *a, pm_memusage_t *b) {
51e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    a->vss += b->vss;
52e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    a->rss += b->rss;
53e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    a->pss += b->pss;
54e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project    a->uss += b->uss;
55745b964daeacf44350db14bc343d53e319e696b8Colin Cross    a->swap += b->swap;
5608ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    SIMPLEQ_INSERT_SIMPLEQ_TAIL(&a->swap_offset_list, &b->swap_offset_list);
5708ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel}
5808ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel
5908ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudelpm_proportional_swap_t * pm_memusage_pswap_create(int swap_size)
6008ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel{
6108ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    pm_proportional_swap_t *p_swap = NULL;
6208ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel
6308ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    p_swap = malloc(sizeof(pm_proportional_swap_t));
6408ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    if (p_swap == NULL) {
6508ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel        fprintf(stderr, "Error allocating proportional swap.\n");
6608ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    } else {
6708ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel        p_swap->array_size = swap_size / getpagesize();
6808ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel        p_swap->offset_array = calloc(p_swap->array_size, sizeof(pm_pswap_refcount_t));
6908ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel        if (p_swap->offset_array == NULL) {
7008ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel            fprintf(stderr, "Error allocating proportional swap offset array.\n");
7108ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel            free(p_swap);
7208ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel            p_swap = NULL;
7308ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel        }
7408ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    }
7508ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel
7608ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    return p_swap;
7708ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel}
7808ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel
7908ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudelvoid pm_memusage_pswap_destroy(pm_proportional_swap_t *p_swap) {
8008ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    if (p_swap) {
8108ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel        free(p_swap->offset_array);
8208ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel        free(p_swap);
8308ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    }
8408ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel}
8508ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel
8608ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudelvoid pm_memusage_pswap_add_offset(pm_memusage_t *mu, unsigned int offset) {
8708ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    pm_swap_offset_t *soff;
8808ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel
8908ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    if (mu->p_swap == NULL)
9008ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel        return;
9108ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel
9298a20cd1283b6ee029e871c0876815300475c40aNick Desaulniers    if (offset >= mu->p_swap->array_size) {
9308ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel        fprintf(stderr, "SWAP offset %d is out of swap bounds.\n", offset);
9408ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel        return;
9598a20cd1283b6ee029e871c0876815300475c40aNick Desaulniers    }
9698a20cd1283b6ee029e871c0876815300475c40aNick Desaulniers
9798a20cd1283b6ee029e871c0876815300475c40aNick Desaulniers    if (mu->p_swap->offset_array[offset] == USHRT_MAX) {
9898a20cd1283b6ee029e871c0876815300475c40aNick Desaulniers        fprintf(stderr, "SWAP offset %d ref. count if overflowing ushort type.\n", offset);
9908ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    } else {
10098a20cd1283b6ee029e871c0876815300475c40aNick Desaulniers        mu->p_swap->offset_array[offset]++;
10108ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    }
10208ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel
10308ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    soff = malloc(sizeof(pm_swap_offset_t));
10408ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    if (soff) {
10508ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel        soff->offset = offset;
10608ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel        SIMPLEQ_INSERT_TAIL(&mu->swap_offset_list, soff, simpleqe);
10708ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    }
10808ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel}
10908ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel
11008ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudelvoid pm_memusage_pswap_get_usage(pm_memusage_t *mu, pm_swapusage_t *su) {
11108ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel
11208ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    int pagesize = getpagesize();
11308ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    pm_swap_offset_t *elem;
11408ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel
11508ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    if (su == NULL)
11608ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel        return;
11708ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel
11808ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    su->proportional = su->unique = 0;
11908ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    SIMPLEQ_FOREACH(elem, &mu->swap_offset_list, simpleqe) {
12008ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel        su->proportional += pagesize / mu->p_swap->offset_array[elem->offset];
12108ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel        su->unique += mu->p_swap->offset_array[elem->offset] == 1 ? pagesize : 0;
12208ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    }
12308ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel}
12408ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel
12508ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudelvoid pm_memusage_pswap_free(pm_memusage_t *mu) {
12608ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    pm_swap_offset_t *elem = SIMPLEQ_FIRST(&mu->swap_offset_list);
12708ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    while (elem) {
12808ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel        SIMPLEQ_REMOVE_HEAD(&mu->swap_offset_list, simpleqe);
12908ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel        free(elem);
13008ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel        elem = SIMPLEQ_FIRST(&mu->swap_offset_list);
13108ea6e722b1f2d6359f54fe39c6bed82f524291cThierry Strudel    }
132e16cb84e2324f05334d18dcf5956f20f44262b62The Android Open Source Project}
133