blob: 8fde10512468fd2f4c84e2566cbb89bf571b06a6 [file] [log] [blame]
/*
* Copyright (C) 2013 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 <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <log/log.h>
#include <hardware/memtrack.h>
#include "memtrack_exynos.h"
/* Following includes added for directory parsing. */
#include <sys/types.h>
#include <dirent.h>
/* Some general defines. */
#define MALI_DEBUG_FS_PATH "/d/mali/mem/"
#define MALI_DEBUG_MEM_FILE "/mem_profile"
#define MAX_FILES_PER_PID 8
// strlen(MALI_DEBUG_FS_PATH) = 12
// strlen(MALI_DEBUG_MEM_FILE) = 12
// max pid len = 5 (0 ~ 65535)
// max pid suffix len = 5 (5 digits)
// + underscore between pid and suffix
#define MAX_FILES_PER_NAME 36
static int libmemtrack_gbl_input_filename_counter = 0;
static char libmemtrack_gbl_input_filename[MAX_FILES_PER_PID][MAX_FILES_PER_NAME];
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
#define min(x, y) ((x) < (y) ? (x) : (y))
struct memtrack_record record_templates[] = {
{
.flags = MEMTRACK_FLAG_SMAPS_ACCOUNTED |
MEMTRACK_FLAG_PRIVATE |
MEMTRACK_FLAG_NONSECURE,
},
{
.flags = MEMTRACK_FLAG_SMAPS_UNACCOUNTED |
MEMTRACK_FLAG_PRIVATE |
MEMTRACK_FLAG_NONSECURE,
},
};
static void scan_directory_for_filenames(pid_t pid)
{
/* As per ARM, there can be multiple files */
DIR *directory;
struct dirent *entries;
char pid_string[12] = {0};
int pid_len;
/* Open directory. */
directory = opendir(MALI_DEBUG_FS_PATH);
pid_len = snprintf(pid_string, sizeof(pid_string), "%d_", pid);
libmemtrack_gbl_input_filename_counter = 0;
if (directory != NULL) {
/* Keep reading the directory. */
while ((entries = readdir(directory))) {
/* Check if the PID is present in the direcotry entry.
* If it is present, then keep the filename for reading
* contents. Also concatenate the directory path, so that
* file can be opened.
* */
if (!strncmp(entries->d_name, pid_string, pid_len)) {
snprintf(libmemtrack_gbl_input_filename[libmemtrack_gbl_input_filename_counter], MAX_FILES_PER_NAME, "%s%s%s", MALI_DEBUG_FS_PATH, entries->d_name, MALI_DEBUG_MEM_FILE);
libmemtrack_gbl_input_filename_counter++;
}
}
/* Close directory before leaving. */
(void) closedir(directory);
} else {
ALOGE("libmemtrack-hw -- Couldn't open the directory - %s \r\n", MALI_DEBUG_FS_PATH);
}
return;
}
int mali_memtrack_get_memory(pid_t pid, int __unused type,
struct memtrack_record *records,
size_t *num_records)
{
size_t allocated_records = min(*num_records, ARRAY_SIZE(record_templates));
FILE *fp;
int local_count;
long long int temp_val = 0, total_memory_size = 0, native_buf_mem_size = 0;
bool native_buffer_read = false;
char line[1024] = {0};
*num_records = ARRAY_SIZE(record_templates);
/* fastpath to return the necessary number of records */
if (allocated_records == 0) {
return 0;
}
memcpy(records, record_templates,
sizeof(struct memtrack_record) * allocated_records);
/* First, scan the directoy. */
scan_directory_for_filenames(pid);
local_count = 0;
total_memory_size = 0;
native_buf_mem_size = 0;
while (local_count < libmemtrack_gbl_input_filename_counter) {
fp = fopen(&libmemtrack_gbl_input_filename[local_count][0], "r");
if (fp == NULL) {
/* Unable to open the file. Either move to next file, or
* return to caller. */
local_count++;
continue;
}
while (1) {
char memory_type[16] = {0};
char memory_type_2[16] = {0};
int ret = 0;
if (native_buffer_read == false) {
if (fgets(line, sizeof(line), fp) == NULL) {
if (native_buffer_read == false) {
/* Unable to read Native buffer.
* Probably DDK doesn't support Native Buffer.
* Reset to start of file and look for Total
* Memory. */
fseek(fp, 0, SEEK_SET);
/* Also, set Native buffer flag and memory sizes. */
native_buffer_read = true;
continue;
}
}
/* Search for Total memory. */
/* Format:
*
* Channel: Native Buffer (Total memory: 44285952)
*
*/
ret = sscanf(line, "%*s %15s %15s %*s %*s %lld \n", memory_type, memory_type_2, &temp_val);
if (ret != 3)
continue;
if ((strcmp(memory_type, "Native") == 0) &&
(strcmp(memory_type_2, "Buffer") == 0)) {
/* Set native buffer memory read flag to true. */
native_buffer_read = true;
if ((INT64_MAX - temp_val) > native_buf_mem_size)
native_buf_mem_size += temp_val;
else
native_buf_mem_size = INT64_MAX;
} else {
/* Ignore case. Nothing to do here. */
/* Continue reading file until NativeBuffer is found. */
}
} else {
if (fgets(line, sizeof(line), fp) == NULL) {
/* Unable to find, so break the loop here.*/
break;
}
/* Search for Total memory. */
/* Format:
*
* Total allocated memory: 36146960
*
*/
ret = sscanf(line, "%15s %*s %*s %lld \n", memory_type, &temp_val);
if (ret != 2)
continue;
if (strcmp(memory_type, "Total") == 0) {
/* Store total memory. */
if ((INT64_MAX - temp_val) > total_memory_size)
total_memory_size += temp_val;
else
total_memory_size = INT64_MAX;
} else {
/* Ignore case. Nothing to do here. */
}
} /* end if (native_buffer_read == false) */
} /* End while(1) */
if (fp != NULL) {
/* Close the opened file. */
fclose(fp);
/* Reset some of the local variables here. */
fp = NULL;
native_buffer_read = false;
}
/* Manage local variables and counters. */
local_count++;
} /* while (local_count <= libmemtrack_gbl_input_filename_counter) */
/* Arrange and return memory size details. */
if (allocated_records > 0)
records[0].size_in_bytes = 0;
if (allocated_records > 1)
{
if (native_buf_mem_size >= 0 && total_memory_size > native_buf_mem_size)
records[1].size_in_bytes = total_memory_size - native_buf_mem_size;
else
records[1].size_in_bytes = 0;
}
return 0;
}