107bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani/*
207bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani * Copyright (C) 2013 The Android Open Source Project
307bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani *
407bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani * Licensed under the Apache License, Version 2.0 (the "License");
507bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani * you may not use this file except in compliance with the License.
607bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani * You may obtain a copy of the License at
707bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani *
807bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani *      http://www.apache.org/licenses/LICENSE-2.0
907bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani *
1007bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani * Unless required by applicable law or agreed to in writing, software
1107bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani * distributed under the License is distributed on an "AS IS" BASIS,
1207bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1307bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani * See the License for the specific language governing permissions and
1407bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani * limitations under the License.
1507bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani */
1607bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani
1707bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani#include <errno.h>
1807bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani#include <stdbool.h>
1907bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani#include <stdio.h>
2007bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani#include <string.h>
2107bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani#include <sys/mman.h>
2207bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani
2307bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani#include <hardware/memtrack.h>
2407bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani
2507bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani#include "memtrack_msm.h"
2607bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani
2707bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
2807bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani#define min(x, y) ((x) < (y) ? (x) : (y))
2907bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani
3007bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malanistruct memtrack_record record_templates[] = {
3107bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    {
3207bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani        .flags = MEMTRACK_FLAG_SMAPS_ACCOUNTED |
3307bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani                 MEMTRACK_FLAG_PRIVATE |
3407bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani                 MEMTRACK_FLAG_NONSECURE,
3507bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    },
3607bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    {
3707bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani        .flags = MEMTRACK_FLAG_SMAPS_UNACCOUNTED |
3807bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani                 MEMTRACK_FLAG_PRIVATE |
3907bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani                 MEMTRACK_FLAG_NONSECURE,
4007bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    },
4107bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani};
4207bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani
4307bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malaniint kgsl_memtrack_get_memory(pid_t pid, enum memtrack_type type,
4407bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani                             struct memtrack_record *records,
4507bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani                             size_t *num_records)
4607bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani{
4707bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    size_t allocated_records = min(*num_records, ARRAY_SIZE(record_templates));
4807bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    FILE *fp;
4907bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    char line[1024];
5007bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    char tmp[128];
5107bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    bool is_surfaceflinger = false;
5207bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    size_t accounted_size = 0;
5307bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    size_t unaccounted_size = 0;
5407bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani
5507bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    *num_records = ARRAY_SIZE(record_templates);
5607bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani
5707bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    /* fastpath to return the necessary number of records */
5807bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    if (allocated_records == 0) {
5907bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani        return 0;
6007bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    }
6107bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani
6207bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    snprintf(tmp, sizeof(tmp), "/proc/%d/cmdline", pid);
6307bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    fp = fopen(tmp, "r");
6407bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    if (fp != NULL) {
6507bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani        if (fgets(line, sizeof(line), fp)) {
6607bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani            if (strcmp(line, "/system/bin/surfaceflinger") == 0)
6707bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani                is_surfaceflinger = true;
6807bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani        }
6907bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani        fclose(fp);
7007bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    }
7107bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani
7207bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    memcpy(records, record_templates,
7307bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani           sizeof(struct memtrack_record) * allocated_records);
7407bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani
7507bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    snprintf(tmp, sizeof(tmp), "/d/kgsl/proc/%d/mem", pid);
7607bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    fp = fopen(tmp, "r");
7707bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    if (fp == NULL) {
7807bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani        return -errno;
7907bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    }
8007bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani
8107bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    /* Go through each line of <pid>/mem file and for every entry of type "gpumem"
8207bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani     * check if the gpubuffer entry is usermapped or not. If the entry is usermapped
8307bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani     * count the entry as accounted else count the entry as unaccounted.
8407bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani     */
8507bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    while (1) {
8607bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani        unsigned long size;
8707bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani        char line_type[7];
8807bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani        char flags[7];
8907bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani        char line_usage[19];
9007bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani        int ret;
9107bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani
9207bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani        if (fgets(line, sizeof(line), fp) == NULL) {
9307bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani            break;
9407bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani        }
9507bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani
9607bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani        /* Format:
9707bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani         *  gpuaddr useraddr     size    id flags       type            usage sglen
9807bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani         * 545ba000 545ba000     4096     1 ----pY     gpumem      arraybuffer     1
9907bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani         */
10007bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani        ret = sscanf(line, "%*x %*x %lu %*d %6s %6s %18s %*d\n",
10107bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani                     &size, flags, line_type, line_usage);
10207bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani        if (ret != 4) {
10307bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani            continue;
10407bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani        }
10507bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani
10607bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani        if (type == MEMTRACK_TYPE_GL && strcmp(line_type, "gpumem") == 0) {
10707bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani
10807bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani            if (flags[5] == 'Y')
10907bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani                accounted_size += size;
11007bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani            else
11107bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani                unaccounted_size += size;
11207bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani
11307bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani        } else if (type == MEMTRACK_TYPE_GRAPHICS && strcmp(line_type, "ion") == 0) {
11407bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani            if (!is_surfaceflinger || strcmp(line_usage, "egl_image") != 0) {
11507bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani                unaccounted_size += size;
11607bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani            }
11707bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani        }
11807bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    }
11907bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani
12007bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    if (allocated_records > 0) {
12107bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani        records[0].size_in_bytes = accounted_size;
12207bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    }
12307bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    if (allocated_records > 1) {
12407bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani        records[1].size_in_bytes = unaccounted_size;
12507bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    }
12607bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani
12707bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    fclose(fp);
12807bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani
12907bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani    return 0;
13007bbf1e89c031a5d41a7561433e832d396c311a5Prashant Malani}
131