The Kernel

Dec 26, 2012 02:46

Бесконечный менеджмент сжирает всё время, но вот что успелось...

(trivia: война за "исчезающие мегабайты" в pv_ops ядрах под Xen'ом)

упринткашил все функции из nobootmem.c (JFYI: изменение в конфиге настроек вокруг нумы не влияет на ситуацию радикально).

Имеем (3.8.0-rc1+ #6 SMP Wed Dec 26 02:29:43 MSK 2012 x86_64 GNU/Linux), 256Мб.

Отладочный вывод:

free_all_bootmem: nobootmem.c MAX_NUMNODES=1
[ 0.000000] reset_node_lowmem_managed_pages: is_highmem(z)=0, z->managed_pages=3914
[ 0.000000] reset_node_lowmem_managed_pages: is_highmem(z)=0, z->managed_pages=60480
[ 0.000000] reset_node_lowmem_managed_pages: is_highmem(z)=0, z->managed_pages=0
[ 0.000000] reset_node_lowmem_managed_pages: is_highmem(z)=0, z->managed_pages=0

Считаем: (3914+60480)*4=257576к, мы же ожидаем увидеть 262144к, разница 4568к.
Заметим, free в машине показывает 223500к, то есть где-то ещё 30 мб пропало.

Дальше вывод:
[ 0.000000] free_low_memory_core_early: start=65536, end=630784, __free_memory_core(start, end)=138, count=138
[ 0.000000] free_low_memory_core_early: start=1048576, end=16777216, __free_memory_core(start, end)=3840, count=3978
[ 0.000000] free_low_memory_core_early: start=27643904, end=31371264, __free_memory_core(start, end)=910, count=4888
[ 0.000000] free_low_memory_core_early: start=31780864, end=31903744, __free_memory_core(start, end)=30, count=4918
[ 0.000000] free_low_memory_core_early: start=54112256, end=54636544, __free_memory_core(start, end)=128, count=5046
[ 0.000000] free_low_memory_core_early: start=54648832, end=54661120, __free_memory_core(start, end)=3, count=5049
[ 0.000000] free_low_memory_core_early: start=54775808, end=134217664, __free_memory_core(start, end)=19394, count=24443
[ 0.000000] free_low_memory_core_early: start=134217728, end=253755392, __free_memory_core(start, end)=29184, count=53627
[ 0.000000] free_low_memory_core_early: start=257949696, end=260026368, __free_memory_core(start, end)=507, count=54134
[ 0.000000] free_low_memory_core_early: start=260042752, end=264241152, __free_memory_core(start, end)=1025, count=55159
[ 0.000000] free_low_memory_core_early: start=264355840, end=267290816, __free_memory_core(start, end)=716, count=55875
[ 0.000000] free_low_memory_core_early: start=267684624, end=267684672, __free_memory_core(start, end)=0, count=55875
[ 0.000000] free_low_memory_core_early: start=267684680, end=267684736, __free_memory_core(start, end)=0, count=55875
[ 0.000000] free_low_memory_core_early: start=267684740, end=267684800, __free_memory_core(start, end)=0, count=55875
[ 0.000000] free_low_memory_core_early: start=267684808, end=267684864, __free_memory_core(start, end)=0, count=55875
[ 0.000000] free_low_memory_core_early: start=267684872, end=267684928, __free_memory_core(start, end)=0, count=55875
[ 0.000000] free_low_memory_core_early: start=267693232, end=267693248, __free_memory_core(start, end)=0, count=55875
[ 0.000000] free_low_memory_core_early: start=267693360, end=267693376, __free_memory_core(start, end)=0, count=55875
[ 0.000000] free_low_memory_core_early: start=267693408, end=267693440, __free_memory_core(start, end)=0, count=55875
[ 0.000000] free_low_memory_core_early: start=267693544, end=267693568, __free_memory_core(start, end)=0, count=55875
[ 0.000000] free_low_memory_core_early: start=267693672, end=267693696, __free_memory_core(start, end)=0, count=55875
[ 0.000000] free_low_memory_core_early: start=267693800, end=267693824, __free_memory_core(start, end)=0, count=55875
[ 0.000000] free_low_memory_core_early: start=267694048, end=267694080, __free_memory_core(start, end)=0, count=55875
[ 0.000000] totalram_pages = free_all_bootmem()=55875
[ 0.000000] Memory: 223500k/262144k available (3675k kernel code, 448k absent, 38196k reserved, 5084k data, 660k init)

(тут я обратил внимание на последнюю строчку. 262144k available - это то, значение, которое мы ставили.

Ок, нам тут дали подробную распиновку:

223500 доступно.
3675 - ядро.
448 - absent (насколько я понимаю, это тот злосчастный кусочек от 640k до мегабайта, в наследство от msdos).
38196 - зарезервировано.
5084 - data
660 - init

Сумма всего этого 271563, то есть больше, чем есть на самом деле. Разница между available и mem_kb - это 38644к, то есть unavailable + absent.

Отсюда вопрос (оставляем в стороне unavailable):
Что за reserved и какогохера?

Заметим, available строго соответствует дебаг выводу из free_low_memory_core_early

Вчитаемся в функцию. (она попаганена моим дебагом):

unsigned long __init free_low_memory_core_early(int nodeid)
{
unsigned long count = 0;
unsigned long t = 0;
phys_addr_t start, end, size;
u64 i;
printk (KERN_ERR "free_low_memory_core_early:%i\n", nodeid);
for_each_free_mem_range(i, MAX_NUMNODES, &start, &end, NULL){
t=__free_memory_core(start, end);
count +=t;
printk(KERN_ERR "free_low_memory_core_early: start=%lu, end=%lu, __free_memory_core(start, end)=%lu, count=%lu\n", (long unsigned) start, (long unsigned)end,t,count);
}

/* free range that is used for reserved array if we allocate it */
size = get_allocated_memblock_reserved_regions_info(&start);
if (size)
count += __free_memory_core(start, start + size);

return count;
}

У меня есть ощущение, что get_allocated_memblock_reserved_regions_info(&start) возвращает ноль, и вот там-то у нас эти 38Мб и заныканы...

Ща соберу с ещё большим отладом.

upd: так и есть
[ 0.000000] free_low_memory_core_early, size=0

Тогда вопрос: а откуда ядро знает про reserved, если get_allocated_memblock_reserved_regions_info(&start) равно нулю?

Кстати, у меня есть некоторый вопрос про код...

unsigned long __init free_low_memory_core_early(int nodeid)
{
unsigned long count = 0;
phys_addr_t start, end, size;
u64 i;
printk (KERN_ERR "free_low_memory_core_early:%i\n", nodeid);
for_each_free_mem_range(i, MAX_NUMNODES, &start, &end, NULL)
count +=__free_memory_core(start, end);

/* free range that is used for reserved array if we allocate it */
size = get_allocated_memblock_reserved_regions_info(&start);
if (size)
count += __free_memory_core(start, start + size);
return count;
}

Почему get_allocated_memblock_reserved_regions_info(&start) вызывается для последнего и только последнего start? Ведь for_each_free_mem_range в финале возвращает... Я не знаю что (пока что), но интуиция мне говорит, что тут что-то не так.

В любом случае, выясняем, как линукс считает reserved в выводе выше.

Греп нас приводит обратно в arch/x86/mm/init_64.c, в void __init mem_init(void).

reservedpages = max_pfn - totalram_pages - absent_pages;

facepalm. facepalm. facepalm. То есть оно считает, что reserved, это всё, что не absent и не totalram_pages.

Другими словами, рыть надо всё-таки именно в район посчёта totalram_pages. Я на 90% уверен, что проблема именно в длинном дампе free_low_memory_core_early (см выше).

linux kernel, xen, memory on demand

Previous post Next post
Up