blob: 5c7738a45a14b8102dfd0f87c46edd45f2cb14ce [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <fcntl.h>
#include <fstream>
#include <sstream>
#include <stdlib.h>
#include <string>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include "Memtrack.h"
#include <sys/types.h>
#include <dirent.h>
namespace aidl {
namespace android {
namespace hardware {
namespace memtrack {
struct dmabuf_trace_memory {
__u32 version;
__u32 pid;
__u32 count;
__u32 type;
__u32 *flags;
__u32 *size_in_bytes;
__u32 reserved[2];
};
#define DMABUF_TRACE_BASE 't'
#define DMABUF_TRACE_IOCTL_GET_MEMORY _IOWR(DMABUF_TRACE_BASE, 0, struct dmabuf_trace_memory)
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
#define min(x, y) ((x) < (y) ? (x) : (y))
static uint32_t available_flags[] = {
MemtrackRecord::FLAG_SMAPS_UNACCOUNTED | MemtrackRecord::FLAG_SHARED_PSS | MemtrackRecord::FLAG_SYSTEM | MemtrackRecord::FLAG_NONSECURE,
MemtrackRecord::FLAG_SMAPS_UNACCOUNTED | MemtrackRecord::FLAG_SHARED_PSS | MemtrackRecord::FLAG_DEDICATED | MemtrackRecord::FLAG_NONSECURE,
MemtrackRecord::FLAG_SMAPS_UNACCOUNTED | MemtrackRecord::FLAG_SHARED_PSS | MemtrackRecord::FLAG_SYSTEM | MemtrackRecord::FLAG_SECURE,
MemtrackRecord::FLAG_SMAPS_UNACCOUNTED | MemtrackRecord::FLAG_SHARED_PSS | MemtrackRecord::FLAG_DEDICATED | MemtrackRecord::FLAG_SECURE,
};
static uint32_t sgpu_available_flags[] = {
MemtrackRecord::FLAG_SMAPS_ACCOUNTED | MemtrackRecord::FLAG_PRIVATE | MemtrackRecord::FLAG_NONSECURE,
MemtrackRecord::FLAG_SMAPS_UNACCOUNTED | MemtrackRecord::FLAG_PRIVATE | MemtrackRecord::FLAG_NONSECURE,
};
const char DMABUF_TRACE_PATH[] = "/dev/dmabuf_trace";
static void getDmaBufMem(pid_t pid, std::vector<MemtrackRecord>* _aidl_return) {
struct dmabuf_trace_memory data;
unsigned int count = ARRAY_SIZE(available_flags);
struct LocalSweeper {
int fd;
uint32_t *flags;
uint32_t *size_in_bytes;
LocalSweeper() : fd(0), flags(nullptr), size_in_bytes(nullptr) { }
~LocalSweeper() {
if (fd)
close(fd);
if (flags)
free(flags);
if (size_in_bytes)
free(size_in_bytes);
}
} sweeper;
int fd = open(DMABUF_TRACE_PATH, O_RDONLY | O_CLOEXEC);
if (fd < 0)
return;
sweeper.fd = fd;
data.flags = (uint32_t *)calloc(count, sizeof(int32_t));
if (!data.flags)
return;
sweeper.flags = data.flags;
data.size_in_bytes = (uint32_t *)calloc(count, sizeof(int32_t));
if (!data.size_in_bytes)
return;
sweeper.size_in_bytes = data.size_in_bytes;
data.count = count;
data.type = (uint32_t)MemtrackType::GRAPHICS;
data.pid = pid;
for (size_t i = 0; i < count; i++)
data.flags[i] = available_flags[i];
int ret = ioctl(fd, DMABUF_TRACE_IOCTL_GET_MEMORY, &data);
if (ret < 0)
return;
for (size_t i = 0; i < count; i++) {
MemtrackRecord record = {
.flags = static_cast<int32_t>(data.flags[i]),
.sizeInBytes = static_cast<long>(data.size_in_bytes[i]),
};
_aidl_return->emplace_back(record);
}
}
static void getGpuMem(pid_t pid, std::vector<MemtrackRecord>* _aidl_return) {
size_t allocated_records = ARRAY_SIZE(sgpu_available_flags);
FILE *fp;
char line[1024] = {0, }, mem_type[16] = {0, };
int r, cur_pid;
size_t mem_size = 0;
/* fastpath to return the necessary number of
* * records */
if (allocated_records == 0)
return;
fp = fopen("/sys/kernel/gpu/mem_info", "r");
if (fp == NULL)
return;
while(1) {
if (fgets(line, sizeof(line), fp) == NULL)
break;
r = sscanf(line, "%s", mem_type);
if (!strcmp(mem_type, "pid:")) {
r = sscanf(line, "%*s %d %zu\n", &cur_pid, &mem_size);
if (!r) {
fclose(fp);
return;
}
if(cur_pid != pid)
continue;
else
break;
}
mem_size = 0;
break;
}
if (fp != NULL)
fclose(fp);
if (allocated_records > 0) {
MemtrackRecord record = {
.flags = static_cast<int32_t>(sgpu_available_flags[0]),
.sizeInBytes = static_cast<long>(0),
};
_aidl_return->emplace_back(record);
}
if (allocated_records > 1) {
MemtrackRecord record = {
.flags = static_cast<int32_t>(sgpu_available_flags[1]),
.sizeInBytes = static_cast<long>(mem_size),
};
_aidl_return->emplace_back(record);
}
}
ndk::ScopedAStatus Memtrack::getMemory(int pid, MemtrackType type,
std::vector<MemtrackRecord>* _aidl_return) {
struct stat st;
if (pid < 0) {
return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
}
if (type != MemtrackType::OTHER && type != MemtrackType::GL && type != MemtrackType::GRAPHICS &&
type != MemtrackType::MULTIMEDIA && type != MemtrackType::CAMERA) {
return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
}
_aidl_return->clear();
switch (type) {
case MemtrackType::GL:
if (!stat("/sys/kernel/gpu", &st) && S_ISDIR(st.st_mode))
getGpuMem(pid, _aidl_return);
break;
case MemtrackType::GRAPHICS:
getDmaBufMem(pid, _aidl_return);
break;
default:
break;
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Memtrack::getGpuDeviceInfo(std::vector<DeviceInfo>* _aidl_return) {
DeviceInfo dev_info = {.id = 0, .name = "exynos"};
FILE *fp;
char gpu_model[32] = {0, }, dev_type[32] = {0, }, *r = 0;
int i = 0;
fp = fopen("/sys/kernel/gpu/gpu_model", "r");
if (fp != NULL) {
r = fgets(gpu_model, sizeof(gpu_model), fp);
while (gpu_model[i]) {
if (gpu_model[i] == '_') {
dev_type[i] = '\0';
break;
}
dev_type[i] = gpu_model[i];
i++;
}
fclose(fp);
}
_aidl_return->clear();
if (r && !strcmp(dev_type, "AMDGPU"))
dev_info = {.id = 0, .name = gpu_model};
_aidl_return->emplace_back(dev_info);
return ndk::ScopedAStatus::ok();
}
} // namespace memtrack
} // namespace hardware
} // namespace android
} // namespace aidl