summaryrefslogtreecommitdiff
path: root/libmemtrack/dmabuf.cpp
blob: ba548ff1bf3d1e7ffe84692aabf572e2ac73141a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include <fstream>
#include <sstream>
#include <regex>
#include <vector>
#include <algorithm>

#include <cerrno>
#include <sys/stat.h>

#include <hardware/memtrack.h>
#include <hardware/exynos/ion.h>

#include "memtrack_exynos.h"

using namespace std;

#define NUM_AVAILABLE_FLAGS 4U
static unsigned int available_flags [NUM_AVAILABLE_FLAGS] = {
    MEMTRACK_FLAG_SMAPS_UNACCOUNTED | MEMTRACK_FLAG_SHARED_PSS | MEMTRACK_FLAG_SYSTEM | MEMTRACK_FLAG_NONSECURE,
    MEMTRACK_FLAG_SMAPS_UNACCOUNTED | MEMTRACK_FLAG_SHARED_PSS | MEMTRACK_FLAG_DEDICATED | MEMTRACK_FLAG_NONSECURE,
    MEMTRACK_FLAG_SMAPS_UNACCOUNTED | MEMTRACK_FLAG_SHARED_PSS | MEMTRACK_FLAG_SYSTEM | MEMTRACK_FLAG_SECURE,
    MEMTRACK_FLAG_SMAPS_UNACCOUNTED | MEMTRACK_FLAG_SHARED_PSS | MEMTRACK_FLAG_DEDICATED| MEMTRACK_FLAG_SECURE,
};

struct DmabufBuffer {
    unsigned int id;
    unsigned int type;
    size_t size;
    size_t pss;
    DmabufBuffer(unsigned int _id, size_t _size, size_t _pss)
        : id(_id), type(MEMTRACK_FLAG_SMAPS_UNACCOUNTED | MEMTRACK_FLAG_SHARED_PSS), size(_size), pss(_pss)
    { }
    void setPoolType(string _type) { type |= (_type == "carveout") ? MEMTRACK_FLAG_DEDICATED : MEMTRACK_FLAG_SYSTEM; }
    void setFlags(unsigned int flags) { type |= (flags & ION_FLAG_PROTECTED) ? MEMTRACK_FLAG_SECURE : MEMTRACK_FLAG_NONSECURE; }
};

const char DMABUF_FOOTPRINT_PATH[] = "/sys/kernel/debug/dma_buf/footprint/";
static bool build_dmabuf_footprint(vector<DmabufBuffer> &buffers, pid_t pid)
{
    ostringstream dmabuf_path;
    dmabuf_path << DMABUF_FOOTPRINT_PATH << pid;

    ifstream dmabuf(dmabuf_path.str());
    if (!dmabuf)
        return false;
    //
    // exp_name      size     share
    // ion-102   69271552  34635776
    regex rex("\\s*ion-(\\d+)\\s+(\\d+)\\s+(\\d+).*");
    smatch mch;
    // 1-id, 2-size, 3-pss
    for (string line; getline(dmabuf, line); )
        if (regex_match(line, mch, rex))
            buffers.emplace_back(stoul(mch[1], 0, 10), stoul(mch[2], 0, 10), stoul(mch[3], 0, 10));

    return true;
}

const char ION_BUFFERS_PATH[] = "/sys/kernel/debug/ion/buffers";
static bool complete_dmabuf_footprint(int type, vector<DmabufBuffer> &buffers)
{
    ifstream ion(ION_BUFFERS_PATH);
    if (!ion)
        return false;

    // [  id]            heap heaptype flags size(kb) : iommu_mapped...
    // [ 106] ion_system_heap   system  0x40    16912 : 19080000.dsim(0)
    regex rexion("\\[ *(\\d+)\\] +[[:alnum:]\\-_]+ +(\\w+) +([x[:xdigit:]]+) +(\\d+).*");
    smatch mch;
    // 1-id, 2-heaptype, 3-flags, 4-size
    for (string line; getline(ion, line); ) {
        if (regex_match(line, mch, rexion)) {
            unsigned int id = stoul(mch[1], 0, 10);
            unsigned int flags = stoul(mch[3], 0, 16);
            size_t len = stoul(mch[4], 0, 10) * 1024;
            auto elem = find_if(begin(buffers), end(buffers), [id, len] (auto &item) {
                                    return (item.id == id) && (item.size == len);
                                });
            // passes if type = OTHER && not flag & hwrender or type == GRAPHIC && flag & hwrender
            if ((elem != end(buffers)) && ((type == MEMTRACK_TYPE_OTHER) == !(flags & ION_FLAG_MAY_HWRENDER))) {
                elem->setFlags(flags);
                elem->setPoolType(mch[2]);
            }
        }
    }

    return true;
}

int dmabuf_memtrack_get_memory(pid_t pid, int type, struct memtrack_record *records, size_t *num_records)
{
    if ((type != MEMTRACK_TYPE_OTHER) && (type != MEMTRACK_TYPE_GRAPHICS))
        return -ENODEV;

    if (*num_records == 0) {
        *num_records = NUM_AVAILABLE_FLAGS;
        return 0;
    }

    *num_records = (*num_records < NUM_AVAILABLE_FLAGS) ? *num_records : NUM_AVAILABLE_FLAGS;

    for (size_t i = 0; i < *num_records; i++) {
        records[i].size_in_bytes = 0;
        records[i].flags = available_flags[i];
    }

    vector<DmabufBuffer> buffers;

    if (!build_dmabuf_footprint(buffers, pid))
        return -ENODEV;

    if (buffers.size() == 0)
        return 0;

    if (!complete_dmabuf_footprint(type, buffers))
        return -ENODEV;

    for (auto item: buffers) {
        for (size_t i = 0; i < *num_records; i++) {
            if (item.type == available_flags[i]) {
                records[i].size_in_bytes += item.pss;
                break;
            }
        }
    }

    return 0;
}