Подтвердить что ты не робот

Почему "change_protection" обрабатывает CPU при загрузке большого объема данных в оперативную память?

Мы создали базу данных в памяти, которая ест около 100-150G RAM в одном Vec, который заполняется следующим образом:

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

perf top показывает, что время в основном выполняется в этой функции "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]

Использование ЦП этой функции возрастает по мере того, как все больше и больше данных загружается в ОЗУ:

  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

Код работает на экземпляре r3.8xlarge AWS EC2, а прозрачная огромная страница уже отключена.

[~]$ 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:

Ядро

3.14.35-28.38.amzn1.x86_64

реальный вопрос - почему в этой функции так много накладных расходов?

4b9b3361

Ответ 1

Кажется, это проблема ОС, а не проблема с этой специфической функцией ржавчины.

Большинство ОС (включая Linux) используют запрос подкачки. По умолчанию Linux не будет выделять физические страницы для вновь выделенной памяти. Вместо этого он будет выделять одну нулевую страницу с разрешениями только для чтения для всей выделенной памяти (т.е. Все страницы виртуальной памяти будут указывать на эту страницу отдельной физической памяти).

Если вы попытаетесь записать в память, произойдет ошибка страницы, будет выделена новая страница, и соответствующие разрешения будут установлены соответствующим образом.

Я предполагаю, что вы видите этот эффект в своей программе. Если вы попытаетесь сделать то же самое во второй раз, это должно быть намного быстрее. Существуют также способы управления этой политикой через sysctl: https://www.kernel.org/doc/Documentation/vm/overcommit-accounting.

Не знаете, почему вы отключили THP, но в этом случае вам могут помочь большие страницы, так как изменение защиты произойдет один раз для каждой большой страницы (2Mib) вместо одного на обычную страницу (4KiB).