rodata: optimize memory usage of rodata section [4/5]

PD#SWPL-31258

Problem:
Kernel RO data is too large, about 4.5mb on 32bit and 5.9mb on
64bit kernel

Solution:
1, optimize kallsyms compress code. This can help to increase
about 18% of compress ratio and save about 200 ~ 500KB under
different config.

Signed-off-by: Tao Zeng <tao.zeng@amlogic.com>
Change-Id: I4c058fbb22d89bc50c81fa3266ee0f7613f076f2
Signed-off-by: Tao Zeng <tao.zeng@amlogic.com>
This commit is contained in:
Tao Zeng
2020-08-07 21:03:48 +08:00
committed by Chris
parent 5b574c9eda
commit 2a7548129f
5 changed files with 2415 additions and 174 deletions

View File

@@ -76,6 +76,7 @@ struct alloc_caller {
struct fun_symbol {
const char *name;
int full_match;
int matched;
};
static struct alloc_caller common_caller[COMMON_CALLER_SIZE];
@@ -86,45 +87,45 @@ static struct alloc_caller common_caller[COMMON_CALLER_SIZE];
* functions
*/
static struct fun_symbol common_func[] __initdata = {
{"__alloc_pages_nodemask", 1},
{"kmem_cache_alloc", 1},
{"__get_free_pages", 1},
{"__kmalloc", 1},
{"cma_alloc", 1},
{"dma_alloc_from_contiguous", 1},
{"aml_cma_alloc_post_hook", 1},
{"__dma_alloc", 1},
{"arm_dma_alloc", 1},
{"__kmalloc_track_caller", 1},
{"kmem_cache_alloc_trace", 1},
{"__alloc_from_contiguous", 1},
{"cma_allocator_alloc", 1},
{"cma_release", 1},
{"dma_release_from_contiguous", 1},
{"codec_mm_alloc_in", 0},
{"codec_mm_alloc", 0},
{"codec_mm_alloc_for_dma", 0},
{"codec_mm_extpool_pool_alloc", 1},
{"codec_mm_release", 1},
{"cma_allocator_free", 1},
{"alloc_pages_exact", 1},
{"get_zeroed_page", 1},
{"__vmalloc_node_range", 1},
{"vzalloc", 1},
{"vmalloc", 1},
{"__alloc_page_frag", 1},
{"kmalloc_order", 0},
{"__alloc_pages_nodemask", 1, 0},
{"kmem_cache_alloc", 1, 0},
{"__get_free_pages", 1, 0},
{"__kmalloc", 1, 0},
{"cma_alloc", 1, 0},
{"dma_alloc_from_contiguous", 1, 0},
{"aml_cma_alloc_post_hook", 1, 0},
{"__dma_alloc", 1, 0},
{"arm_dma_alloc", 1, 0},
{"__kmalloc_track_caller", 1, 0},
{"kmem_cache_alloc_trace", 1, 0},
{"__alloc_from_contiguous", 1, 0},
{"cma_allocator_alloc", 1, 0},
{"cma_release", 1, 0},
{"dma_release_from_contiguous", 1, 0},
{"codec_mm_alloc_in", 0, 0},
{"codec_mm_alloc", 0, 0},
{"codec_mm_alloc_for_dma", 0, 0},
{"codec_mm_extpool_pool_alloc", 1, 0},
{"codec_mm_release", 1, 0},
{"cma_allocator_free", 1, 0},
{"alloc_pages_exact", 1, 0},
{"get_zeroed_page", 1, 0},
{"__vmalloc_node_range", 1, 0},
{"vzalloc", 1, 0},
{"vmalloc", 1, 0},
{"__alloc_page_frag", 1, 0},
{"kmalloc_order", 0, 0},
#ifdef CONFIG_NUMA
{"alloc_pages_current", 1},
{"alloc_page_interleave", 1},
{"kmalloc_large_node", 1},
{"kmem_cache_alloc_node", 1},
{"__kmalloc_node", 1},
{"alloc_pages_vma", 1},
{"alloc_pages_current", 1, 0},
{"alloc_page_interleave", 1, 0},
{"kmalloc_large_node", 1, 0},
{"kmem_cache_alloc_node", 1, 0},
{"__kmalloc_node", 1, 0},
{"alloc_pages_vma", 1, 0},
#endif
#ifdef CONFIG_SLUB /* for some static symbols not exported in headfile */
{"new_slab", 0},
{"slab_alloc", 0},
{"new_slab", 0, 0},
{"slab_alloc", 0, 0},
#endif
{} /* tail */
};
@@ -233,110 +234,13 @@ static inline int is_module_addr(unsigned long ip)
return 0;
}
/*
* following 3 functions are modify from kernel/kallsyms.c
*/
static unsigned int __init kallsyms_expand_symbol(unsigned int off,
char *result, size_t maxlen)
{
int len, skipped_first = 0;
const u8 *tptr, *data;
/* Get the compressed symbol length from the first symbol byte. */
data = &kallsyms_names[off];
len = *data;
data++;
/*
* Update the offset to return the offset for the next symbol on
* the compressed stream.
*/
off += len + 1;
/*
* For every byte on the compressed symbol data, copy the table
* entry for that byte.
*/
while (len) {
tptr = &kallsyms_token_table[kallsyms_token_index[*data]];
data++;
len--;
while (*tptr) {
if (skipped_first) {
if (maxlen <= 1)
goto tail;
*result = *tptr;
result++;
maxlen--;
} else
skipped_first = 1;
tptr++;
}
}
tail:
if (maxlen)
*result = '\0';
/* Return to offset to the next symbol. */
return off;
}
static unsigned long __init kallsyms_sym_address(int idx)
{
if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE))
return kallsyms_addresses[idx];
/* values are unsigned offsets if --absolute-percpu is not in effect */
if (!IS_ENABLED(CONFIG_KALLSYMS_ABSOLUTE_PERCPU))
return kallsyms_relative_base + (u32)kallsyms_offsets[idx];
/* ...otherwise, positive offsets are absolute values */
if (kallsyms_offsets[idx] >= 0)
return kallsyms_offsets[idx];
/* ...and negative offsets are relative to kallsyms_relative_base - 1 */
return kallsyms_relative_base - 1 - kallsyms_offsets[idx];
}
/* Lookup the address for this symbol. Returns 0 if not found. */
static unsigned long __init kallsyms_contain_name(const char *name, long full,
unsigned int *offset)
{
char namebuf[KSYM_NAME_LEN];
unsigned long i;
unsigned int off = 0;
for (i = 0; i < kallsyms_num_syms; i++) {
off = kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));
if (full && strcmp(namebuf, name) == 0)
return kallsyms_sym_address(i);
if (!full && strstr(namebuf, name)) {
/* not include tab */
if (!strstr(namebuf, "__kstrtab") &&
!strstr(namebuf, "__kcrctab") &&
!strstr(namebuf, "__ksymtab") &&
(off > *offset)) {
/* update offset for next loop */
*offset = off;
return kallsyms_sym_address(i);
}
}
}
return 0;
}
/*
* set up information for common caller in memory allocate API
*/
static void __init setup_common_caller(unsigned long kaddr)
static int __init setup_common_caller(unsigned long kaddr)
{
unsigned long size, offset;
int i = 0;
const char *name;
char str[KSYM_NAME_LEN];
int i = 0, ret;
for (i = 0; i < COMMON_CALLER_SIZE; i++) {
/* find a empty caller */
@@ -345,34 +249,20 @@ static void __init setup_common_caller(unsigned long kaddr)
}
if (i >= COMMON_CALLER_SIZE) {
pr_err("%s, out of memory\n", __func__);
return;
return -1;
}
name = kallsyms_lookup(kaddr, &size, &offset, NULL, str);
if (name) {
ret = kallsyms_lookup_size_offset(kaddr, &size, &offset);
if (ret) {
common_caller[i].func_start_addr = kaddr;
common_caller[i].size = size;
pr_debug("setup %d caller:%lx + %lx, %pf\n",
i, kaddr, size, (void *)kaddr);
} else
pr_err("can't find symbol %pf\n", (void *)kaddr);
}
static int __init fuzzy_match(const char *name)
{
unsigned int off = 0;
unsigned long addr;
int find = 0;
while (1) {
addr = kallsyms_contain_name(name, 0, &off);
if (addr) {
setup_common_caller(addr);
find++;
} else
break;
return 0;
}
return find;
pr_err("can't find symbol %pf\n", (void *)kaddr);
return -1;
}
static void __init dump_common_caller(void)
@@ -401,28 +291,41 @@ static int __init sym_cmp(const void *x1, const void *x2)
return p1->func_start_addr < p2->func_start_addr ? 1 : -1;
}
static void __init find_static_common_symbol(void)
static int __init match_common_caller(void *data, const char *name,
struct module *module,
unsigned long addr)
{
int i;
unsigned long addr;
int i, ret;
struct fun_symbol *s;
memset(common_caller, 0, sizeof(common_caller));
if (module)
return -1;
if (!strcmp(name, "_etext")) /* end of text */
return -1;
for (i = 0; i < COMMON_CALLER_SIZE; i++) {
s = &common_func[i];
if (!s->name)
break; /* end */
if (s->full_match) {
addr = kallsyms_contain_name(s->name, 1, NULL);
if (addr)
break; /* end */
if (s->full_match && !s->matched) {
if (!strcmp(name, s->name)) { /* strict match */
ret = setup_common_caller(addr);
s->matched = 1;
}
} else if (!s->full_match) {
if (strstr(name, s->name)) /* contians */
setup_common_caller(addr);
else
pr_debug("can't find symbol:%s\n", s->name);
} else {
if (!fuzzy_match(s->name))
pr_info("can't fuzzy match:%s\n", s->name);
}
}
return 0;
}
static void __init find_static_common_symbol(void)
{
memset(common_caller, 0, sizeof(common_caller));
kallsyms_on_each_symbol(match_common_caller, NULL);
sort(common_caller, COMMON_CALLER_SIZE, sizeof(struct alloc_caller),
sym_cmp, NULL);
dump_common_caller();
@@ -817,11 +720,10 @@ struct pagetrace_summary {
static unsigned long find_ip_base(unsigned long ip)
{
unsigned long size, offset;
const char *name;
char str[KSYM_NAME_LEN];
int ret;
name = kallsyms_lookup(ip, &size, &offset, NULL, str);
if (name) /* find */
ret = kallsyms_lookup_size_offset(ip, &size, &offset);
if (ret) /* find */
return ip - offset;
else /* not find */
return ip;

View File

@@ -33,6 +33,30 @@
#define all_var 0
#endif
#ifdef CONFIG_AMLOGIC_MODIFY
#define KEY_WORD_BASE 0x8000
/* using small storage type */
struct short_base {
unsigned long base;
unsigned int start_idx;
unsigned int syms;
unsigned short *table;
};
extern const unsigned int kallsyms_num_syms __weak;
extern const unsigned char kallsyms_names[] __weak;
extern const unsigned int kallsyms_markers[] __weak;
extern const unsigned char kallsyms_token_table[] __weak;
extern const unsigned short kallsyms_token_index[] __weak;
extern const struct short_base kallsyms_short_base[] __weak;
extern const unsigned int kallsyms_short_cnt __weak;
extern const unsigned int kallsyms_num_words __weak;
extern const unsigned char kallsyms_words[] __weak;
extern const unsigned int kallsyms_word_markers[] __weak;
extern const unsigned char kallsyms_word_table[] __weak;
extern const unsigned short kallsyms_word_index[] __weak;
#else
/*
* These will be re-linked against their real values
* during the second link stage.
@@ -55,6 +79,7 @@ extern const u8 kallsyms_token_table[] __weak;
extern const u16 kallsyms_token_index[] __weak;
extern const unsigned long kallsyms_markers[] __weak;
#endif
static inline int is_kernel_inittext(unsigned long addr)
{
@@ -87,6 +112,103 @@ static int is_ksym_addr(unsigned long addr)
return is_kernel_text(addr) || is_kernel_inittext(addr);
}
#ifdef CONFIG_AMLOGIC_MODIFY
static unsigned char *get_word_ptr(unsigned int idx)
{
u8 *name;
int i;
name = (u8 *)&kallsyms_words[kallsyms_word_markers[idx >> 8]];
for (i = 0; i < (idx & 0xFF); i++)
name = name + (*name) + 1;
return name;
}
static int decode_word(int idx, char *result)
{
int data, size = 0, dsize = 0;
unsigned char *word;
const u8 *t;
WARN_ON(idx >= kallsyms_num_words);
word = get_word_ptr(idx);
size = *word++;
while (size) {
if (*word < 0x80) { /* decode for small token */
t = &kallsyms_word_table[kallsyms_word_index[*word]];
word++;
size--;
while (*t) {
result[dsize] = *t;
dsize++;
t++;
}
} else {
data = ((word[0] << 8) + word[1]) - KEY_WORD_BASE;
dsize += decode_word(data, result + dsize);
word += 2;
size -= 2;
}
}
return dsize;
}
static unsigned int kallsyms_expand_symbol_aml(unsigned int off, char *result,
size_t maxlen)
{
int len, skipped_first = 0, wlen, word;
const u8 *t, *p;
p = &kallsyms_names[off];
len = *p;
off += len + 1;
p++;
while (len) {
if (*p < 0x80) { /* decode for small token */
t = &kallsyms_token_table[kallsyms_token_index[*p]];
p++;
len--;
while (*t) {
if (skipped_first) {
if (maxlen <= 1)
goto tail;
*result = *t;
result++;
maxlen--;
} else
skipped_first = 1;
t++;
}
} else {
word = ((p[0] << 8) + p[1]) - KEY_WORD_BASE;
wlen = decode_word(word, result);
if (!skipped_first) {
memmove(result, result + 1, wlen);
skipped_first = 1;
result += (wlen - 1);
} else {
result += wlen;
}
p += 2;
len -= 2;
maxlen -= wlen;
if (maxlen <= 1)
goto tail;
}
}
tail:
if (maxlen)
*result = '\0';
/* Return to offset to the next symbol. */
return off;
}
#endif
/*
* Expand a compressed symbol data into the resulting uncompressed string,
* if uncompressed string is too long (>= maxlen), it will be truncated,
@@ -95,6 +217,12 @@ static int is_ksym_addr(unsigned long addr)
static unsigned int kallsyms_expand_symbol(unsigned int off,
char *result, size_t maxlen)
{
#ifdef CONFIG_AMLOGIC_MODIFY
unsigned int ret;
ret = kallsyms_expand_symbol_aml(off, result, maxlen);
return ret;
#else
int len, skipped_first = 0;
const u8 *tptr, *data;
@@ -137,6 +265,7 @@ tail:
/* Return to offset to the next symbol. */
return off;
#endif
}
/*
@@ -145,11 +274,27 @@ tail:
*/
static char kallsyms_get_symbol_type(unsigned int off)
{
#ifdef CONFIG_AMLOGIC_MODIFY
const unsigned char *p;
int data;
char buf[KSYM_NAME_LEN];
if (kallsyms_names[off + 1] < 0x80) {
p = kallsyms_token_table;
return p[kallsyms_token_index[kallsyms_names[off + 1]]];
}
data = (kallsyms_names[off + 1] << 8) + kallsyms_names[off + 2];
data -= KEY_WORD_BASE;
decode_word(data, buf);
return buf[0];
#else
/*
* Get just the first code, look it up in the token table,
* and return the first char from this token.
*/
return kallsyms_token_table[kallsyms_token_index[kallsyms_names[off + 1]]];
#endif
}
@@ -182,6 +327,31 @@ static unsigned int get_symbol_offset(unsigned long pos)
static unsigned long kallsyms_sym_address(int idx)
{
#ifdef CONFIG_AMLOGIC_MODIFY
const struct short_base *base;
int high, low = 0, mid = 0, ih, find = 0;
base = kallsyms_short_base;
high = kallsyms_short_cnt - 1;
while (1) { /* check which short base group idx is */
mid = (high + low) / 2;
ih = base[mid].start_idx + base[mid].syms;
if (idx >= base[mid].start_idx && idx < ih) {
find = 1;
break;
}
if (low >= high)
break;
if (idx < base[mid].start_idx)
high = mid - 1;
else
low = mid + 1;
}
WARN_ON(!find);
ih = idx - base[mid].start_idx;
return base[mid].table[ih] + base[mid].base;
#else
if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE))
return kallsyms_addresses[idx];
@@ -195,6 +365,7 @@ static unsigned long kallsyms_sym_address(int idx)
/* ...and negative offsets are relative to kallsyms_relative_base - 1 */
return kallsyms_relative_base - 1 - kallsyms_offsets[idx];
#endif
}
/* Lookup the address for this symbol. Returns 0 if not found. */
@@ -240,11 +411,13 @@ static unsigned long get_symbol_pos(unsigned long addr,
unsigned long symbol_start = 0, symbol_end = 0;
unsigned long i, low, high, mid;
#ifndef CONFIG_AMLOGIC_MODIFY
/* This kernel should never had been booted. */
if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE))
BUG_ON(!kallsyms_addresses);
else
BUG_ON(!kallsyms_offsets);
#endif
/* Do a binary search on the sorted kallsyms_addresses array. */
low = 0;

View File

@@ -11,7 +11,11 @@
HOST_EXTRACFLAGS += -I$(srctree)/tools/include
#ifdef CONFIG_AMLOGIC_MODIFY
hostprogs-$(CONFIG_KALLSYMS) += kallsyms_aml
#else
hostprogs-$(CONFIG_KALLSYMS) += kallsyms
#endf
hostprogs-$(CONFIG_LOGO) += pnmtologo
hostprogs-$(CONFIG_VT) += conmakehash
hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount

2157
scripts/kallsyms_aml.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -202,7 +202,12 @@ kallsyms()
local afile="`basename ${2} .o`.S"
${NM} -n ${1} | scripts/kallsyms ${kallsymopt} > ${afile}
# using higher compress ration version
if [ -n "{CONFIG_AMLOGIC_MODIFY}" ]; then
${NM} -n ${1} | scripts/kallsyms_aml ${kallsymopt} > ${afile}
else
${NM} -n ${1} | scripts/kallsyms ${kallsymopt} > ${afile}
fi
${CC} ${aflags} -c -o ${2} ${afile}
}