129 lines
4.3 KiB
C++
129 lines
4.3 KiB
C++
#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;
|
|
}
|