M7350/qcom-opensource/kernel/kernel-tests/memory_prof/alloc_profiles.c
2024-09-09 08:57:42 +00:00

347 lines
9.2 KiB
C

/*
* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <err.h>
#include <stdint.h>
#include <linux/msm_ion.h>
#include "memory_prof.h"
#include "memory_prof_util.h"
#include "memory_prof_module.h"
#include "alloc_profiles.h"
/**
* split_string() - split a string by a delimiter
*
* @string - string to split
* @delim - delimiter char
* @output - output array of C-strings. Must have enough room for us.
* @output_lens - how much room we have in each entry of @output
*
* Returns the number of entries found
*/
int split_string(const char * const string, char delim, char *output[],
int output_sizes)
{
char *word, *string_cpy;
int nentries = 0;
size_t len = strlen(string) + 1;
const char delim_string[2] = { delim, '\0' };
MALLOC(char *, string_cpy, len);
STRNCPY_SAFE(string_cpy, string, len);
word = strtok(string_cpy, delim_string);
if (!word) {
warnx("Malformed line: %s", string_cpy);
return 0;
}
STRNCPY_SAFE(*output, word, output_sizes);
output++;
nentries++;
for (word = strtok(NULL, delim_string);
word;
word = strtok(NULL, delim_string)) {
STRNCPY_SAFE(*output, word, output_sizes);
output++;
nentries++;
}
free(string_cpy);
return nentries;
}
bool endswith(const char * const string, const char * const suffix)
{
int s1 = strlen(string);
int s2 = strlen(suffix);
int len = MIN(s1, s2);
return 0 == strcmp(string + (s1 - len), suffix + (s2 - len));
}
int parse_size_string_smap(const char * const size_string,
unsigned long *bytes,
struct size_suffix_size_type_mapping *size_map)
{
const struct size_suffix_size_type_mapping *smap;
char *scopy;
for (smap = &size_suffix_to_size_type_mappings[0];
smap->suffix;
smap++) {
if (endswith(size_string, smap->suffix))
break;
}
if (!smap->suffix) {
STRTOL(*bytes, size_string, 0);
return 0;
}
STRDUP(scopy, size_string);
/* chop off the suffix */
scopy[strlen(scopy) - strlen(smap->suffix)] = '\0';
*size_map = *smap;
STRTOL(*bytes, scopy, 0);
*bytes *= smap->multiplier;
free(scopy);
return 0;
}
int parse_size_string(const char * const size_string,
unsigned long *bytes)
{
struct size_suffix_size_type_mapping smap;
return parse_size_string_smap(size_string, bytes, &smap);
}
const struct size_suffix_size_type_mapping size_suffix_to_size_type_mappings[] =
{
{.suffix = "KB", .size_type=ST_KB, .multiplier = 1024},
{.suffix = "MB", .size_type=ST_MB, .multiplier = 1024 * 1024},
{.suffix = "GB", .size_type=ST_GB, .multiplier = 1024 * 1024 * 1024},
{.suffix = NULL},
};
#define MAKE_HEAP_INFO(heap) { .heap_id = heap, .heap_id_string = #heap }
struct heap_info {
unsigned int heap_id;
const char * const heap_id_string;
} heap_info[] = {
MAKE_HEAP_INFO(ION_CP_MM_HEAP_ID),
MAKE_HEAP_INFO(ION_CP_MFC_HEAP_ID),
MAKE_HEAP_INFO(ION_CP_WB_HEAP_ID),
MAKE_HEAP_INFO(ION_CAMERA_HEAP_ID),
MAKE_HEAP_INFO(ION_SYSTEM_CONTIG_HEAP_ID),
MAKE_HEAP_INFO(ION_ADSP_HEAP_ID),
MAKE_HEAP_INFO(ION_PIL1_HEAP_ID),
MAKE_HEAP_INFO(ION_SF_HEAP_ID),
MAKE_HEAP_INFO(ION_IOMMU_HEAP_ID),
MAKE_HEAP_INFO(ION_PIL2_HEAP_ID),
MAKE_HEAP_INFO(ION_QSECOM_HEAP_ID),
MAKE_HEAP_INFO(ION_AUDIO_HEAP_ID),
MAKE_HEAP_INFO(ION_MM_FIRMWARE_HEAP_ID),
MAKE_HEAP_INFO(ION_SYSTEM_HEAP_ID),
MAKE_HEAP_INFO(ION_HEAP_ID_RESERVED),
MAKE_HEAP_INFO(ION_SECURE_HEAP_ID),
/* sentinel */
{ .heap_id_string = NULL }
};
int find_heap_id_value(const char * const heap_id_string,
unsigned int *val)
{
struct heap_info *h;
for (h = &heap_info[0]; h->heap_id_string; ++h) {
if (0 == strcmp(heap_id_string, h->heap_id_string)) {
*val = h->heap_id;
return 0;
}
}
return 1;
}
#define MAKE_FLAG_INFO(flag) { .flag_value = flag, .flag_string = #flag }
struct flag_info {
unsigned int flag_value;
const char * const flag_string;
} flag_info[] = {
MAKE_FLAG_INFO(ION_FLAG_CACHED),
MAKE_FLAG_INFO(ION_FLAG_CACHED_NEEDS_SYNC),
MAKE_FLAG_INFO(ION_FLAG_POOL_FORCE_ALLOC),
MAKE_FLAG_INFO(ION_SECURE),
MAKE_FLAG_INFO(ION_FLAG_SECURE),
MAKE_FLAG_INFO(ION_FLAG_CP_PIXEL),
MAKE_FLAG_INFO(ION_FLAG_CP_NON_PIXEL),
MAKE_FLAG_INFO(ION_FLAG_CP_BITSTREAM),
MAKE_FLAG_INFO(MP_GFP_KERNEL),
MAKE_FLAG_INFO(MP_GFP_HIGHMEM),
MAKE_FLAG_INFO(MP_GFP_ZERO),
MAKE_FLAG_INFO(MP_GFP_HIGHUSER),
MAKE_FLAG_INFO(MP_GFP_NOWARN),
MAKE_FLAG_INFO(MP_GFP_NORETRY),
MAKE_FLAG_INFO(MP_GFP_NO_KSWAPD),
MAKE_FLAG_INFO(MP_GFP_WAIT),
MAKE_FLAG_INFO(MP_GFPNOT_WAIT),
MAKE_FLAG_INFO(MP_IOMMU_WRITE),
MAKE_FLAG_INFO(MP_IOMMU_READ),
MAKE_FLAG_INFO(MP_IOMMU_CACHE),
MAKE_FLAG_INFO(MP_IOMMU_SECURE),
MAKE_FLAG_INFO(MP_IOMMU_ATTACH),
/* sentinel */
{ .flag_string = NULL }
};
int find_flag_value(const char * const flag, int *val)
{
struct flag_info *f;
if (0 == strcmp(flag, "0")) {
*val = 0;
return 0;
}
for (f = &flag_info[0]; f->flag_string; ++f) {
if (0 == strcmp(flag, f->flag_string)) {
*val = f->flag_value;
return 0;
}
}
return 1;
}
uint64_t parse_flags(const char * const word)
{
uint64_t ret = 0;
int i, nflags;
char *flags_words[MAX_FLAGS];
size_t len = strlen(word) + 1;
for (i = 0; i < MAX_FLAGS; ++i)
MALLOC(char *, flags_words[i], MAX_FLAGS_STRING_LEN);
nflags = split_string(word, '|', flags_words, MAX_FLAGS_STRING_LEN);
for (i = 0; i < nflags; ++i) {
int f;
if (find_flag_value(flags_words[i], &f))
warnx("Unknown flag: %s\n", flags_words[i]);
else
ret |= f;
}
for (i = 0; i < MAX_FLAGS; ++i)
free(flags_words[i]);
return ret;
}
bool parse_bool(const char * const word)
{
return 0 == strcmp("true", word);
}
/* how many more alloc profile entries to {re-,m}alloc when we need more */
#define MORE_PROFILE_ENTRIES 30
/**
* get_alloc_profile() - Get allocation profile
*
* @reader: struct alloc_profile_reader to use for reading lines.
*/
struct alloc_profile_entry *get_alloc_profile(
struct alloc_profile_reader *reader)
{
char *buf = NULL;
char *words[MAX_ALLOC_PROFILE_FIELDS];
int i;
struct alloc_profile_entry *current = NULL, *base = NULL, new;
int nentries = 0;
int current_capacity = 0;
const size_t more_alloc_size = sizeof(struct alloc_profile_entry)
* MORE_PROFILE_ENTRIES;
for (i = 0; i < MAX_ALLOC_PROFILE_FIELDS; ++i)
MALLOC(char *, words[i], MAX_ALLOC_PROFILE_WORD_LEN);
for (;;) {
struct line_info line_info;
int nwords;
struct alloc_profile_handler *iter;
const char *tmp;
/*
* On the first iteration, buf = NULL. On subsequent
* interations buf is a pointer that was returned by
* strdup. Free it.
*/
free(buf);
memset(&new, 0, sizeof(new));
if (current_capacity == nentries) {
size_t current_size = (current_capacity
* sizeof(struct alloc_profile_entry));
REALLOC(struct alloc_profile_entry *,
base, current_size + more_alloc_size);
current = base + nentries;
memset(current, 0, more_alloc_size);
current_capacity += MORE_PROFILE_ENTRIES;
}
tmp = reader->getline(reader);
if (!tmp)
break;
STRDUP(buf, tmp);
nwords = split_string(buf, ',', words,
MAX_ALLOC_PROFILE_WORD_LEN);
if (nwords < 1) {
warn("Malformed line: `%s'", buf);
continue;
}
for_each_alloc_profile_handler(iter) {
if (strcmp(words[0], iter->keyword))
continue;
new.handler = iter;
break;
}
if (!new.handler) {
warnx("Couldn't find parser for %s\n",
words[0]);
continue;
}
if (iter->ops->ctor)
iter->ops->ctor(&new);
if (iter->priv_size)
MALLOC(void *, new.priv, iter->priv_size);
line_info.words = &words[0];
line_info.nwords = nwords;
if (iter->ops->parse)
if (iter->ops->parse(&new, &line_info)) {
warnx("Error in parser for %s\n", words[0]);
continue;
}
*current++ = new;
nentries++;
}
/* sentinel */
new.handler = NULL;
*current = new;
for (i = 0; i < MAX_ALLOC_PROFILE_FIELDS; ++i)
free(words[i]);
return nentries ? base : NULL;
}