2015-10-03 13 views
11

zbudowaliśmy w bazie pamięci, która zjada około 100-150g RAM w jednym Vec, która jest wypełniona tak:Dlaczego `change_protection` hog CPU podczas ładowania dużej ilości danych do pamięci RAM?

let mut result = Vec::with_capacity(a_very_large_number); 
while let Ok(n) = reader.read(&mut buffer) { 
    result.push(...); 
} 

perf top pokazuje, że czas spędzony w tym głównie funkcję „change_protection”:

Samples: 48K of event 'cpu-clock', Event count (approx.): 694742858 
62.45% [kernel]    [k] change_protection 
18.18% iron     [.] database::Database::init::h63748 
    7.45% [kernel]    [k] vm_normal_page 
    4.88% libc-2.17.so   [.] __memcpy_ssse3_back 
    0.92% [kernel]    [k] copy_user_enhanced_fast_string 
    0.52% iron     [.] [email protected] 

użycie procesora tej funkcji rośnie w miarę jak coraz więcej danych jest ładowana do pamięci RAM:

PID USER  PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 
12383 iron  20 0 137g 91g 1372 D 76.1 37.9 27:37.00 iron 

Kod działa na instancji AW3 EC3 r3.8xlarge, a przezroczysta strona hug jest już wyłączona.

[~]$ cat /sys/kernel/mm/transparent_hugepage/defrag 
always madvise [never] 
[~]$ cat /sys/kernel/mm/transparent_hugepage/enabled 
always madvise [never] 

cpuinfo

processor : 0 
vendor_id : GenuineIntel 
cpu family : 6 
model  : 62 
model name : Intel(R) Xeon(R) CPU E5-2670 v2 @ 2.50GHz 
stepping : 4 
microcode : 0x428 
cpu MHz  : 2500.070 
cache size : 25600 KB 
physical id : 0 
siblings : 16 
core id  : 0 
cpu cores : 8 
apicid  : 0 
initial apicid : 0 
fpu  : yes 
fpu_exception : yes 
cpuid level : 13 
wp  : yes 
flags  : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx rdtscp lm constant_tsc rep_good nopl xtopology eagerfpu pni pclmulqdq ssse3 cx16 pcid sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm xsaveopt fsgsbase smep erms 
bogomips : 5000.14 
clflush size : 64 
cache_alignment : 64 
address sizes : 46 bits physical, 48 bits virtual 
power management: 

jądro

3.14.35-28.38.amzn1.x86_64 

jest dlaczego jest prawdziwe pytanie nie tyle nad głową w tej funkcji?

+1

Z którego jądra korzystasz? Używam 4.2.5 i mam podobny problem z mongodą. Gdy pamięć rezydenta mongoasta wzrasta, procesor wydany na ochronę zmiany zwiększa się. Jeśli problem ten powtarza się w rdzeniu i mongorze, ale nie w bardzo różnych wersjach jądra, może to być problem jądra zamiast problemu rdzy lub monogii. – Syncopated

+1

jądro jest zawarte w poście, starałem się przekonwertować program na c, uzyskać ten sam problem. http://stackoverflow.com/questions/33257404/why-update-big-array-makes-change-protection-kernel-call-dominating-cpu – Dapeng

+1

Czy problem repro jeśli pin proces do jednego rdzenia? Może eksperymentować z opcjami numactl? Mój problem z mongiem odchodzi, gdy uruchomię go z numactl --interleave = all. – Syncopated

Odpowiedz

1

Wydaje się, że jest to problem z systemem operacyjnym, a nie problem z tą konkretną funkcją rdzy.

Większość systemów operacyjnych (w tym Linux) używa demand paging. Domyślnie Linux nie przydziela stron fizycznych dla nowo przydzielonej pamięci. Zamiast tego przydzieli pojedynczą stronę zerową z uprawnieniami tylko do odczytu dla całej przydzielonej pamięci (tj. Wszystkie strony pamięci wirtualnej wskażą tę stronę pamięci fizycznej).

Przy próbie zapisu do pamięci wystąpi błąd strony, nowa strona zostanie przydzielona, ​​a jej uprawnienia zostaną odpowiednio ustawione.

Zgaduję, że widzisz ten efekt w swoim programie. Jeśli spróbujesz zrobić to samo po raz drugi, powinno być znacznie szybciej. Istnieją również sposoby kontrolowania tej polityki za pośrednictwem sysctl: https://www.kernel.org/doc/Documentation/vm/overcommit-accounting.

Nie wiem, dlaczego wyłączyłeś THP, ale w tym przypadku pomocne mogą być duże strony, ponieważ zmiana ochrony nastąpi raz na każdą dużą stronę (2Mib) zamiast raz na normalną stronę (4KiB).

Powiązane problemy