Bagaimana swapoff bisa selambat itu?

77

Entah bagaimana saya menukar memori 14 GB. Setelah membunuh pelakunya, saya memiliki banyak memori bebas, jadi saya pikir saya bisa memasukkan data penting lagi. Jadi dengan 5 GB dari 32 GB yang digunakan dan 14 GB ruang swap yang digunakan, saya berlari swapoff -a.... dan 4 jam kemudian sekitar setengah dari pekerjaan selesai.

Ini berarti kurang dari 1 MB / s, sementara saya dapat dengan mudah menyalin 200 MB / s. Swap saya dienkripsi tetapi begitu juga semua partisi normal dan dengan aes-ni itu tidak menyebabkan beban CPU yang nyata (dan mengisi ruang swap hanya membutuhkan waktu beberapa menit). Saya melihat bahwa tidak ada alasan khusus untuk mengoptimalkan swapoff, namun saya bertanya-tanya bagaimana itu bisa menjadi lambat?


Hanya menambahkan beberapa data lagi: Memori utama saya adalah 32 GB dan saya memiliki ruang swap 32 GB di masing-masing dari 4 harddisk (pasti berlebihan, tapi siapa yang peduli?). Seluruh ruang swap dapat (didekripsi dan) dibaca dalam waktu kurang dari 5 menit:

time -p sudo sh -c 'for i in /dev/mapper/cryptswap?; do md5sum $i & done; wait'
014a2b7ef300e11094134785e1d882af  /dev/mapper/cryptswap1
a6d8ef09203c1d8d459109ff93b6627c  /dev/mapper/cryptswap4
05aff81f8d276ddf07cf26619726a405  /dev/mapper/cryptswap3
e7f606449327b9a016e88d46049c0c9a  /dev/mapper/cryptswap2
real 264.27

Membaca bagian dari partisi tidak bisa lebih lambat daripada membaca semuanya. Namun membaca sekitar 1/10 dari itu membutuhkan waktu sekitar 100 kali lebih lama.

Saya mengamati bahwa selama swapoffkedua CPU sebagian besar idle (mungkin 10% dari satu inti) dan begitu pula disk ("diukur" oleh LED). Saya juga melihat bahwa ruang swap dimatikan satu demi satu.

maaartinus
sumber
1
Saya bertanya-tanya, apakah fenomena yang sama terjadi ketika sistem memuat halaman kembali ke RAM dengan sendirinya? Sebagai contoh, jika saya suatu sistem diskors ke disk dan kemudian mulai, semuanya telah ditukar dan sedang dimuat kembali ke RAM. Tampaknya sangat lambat bagi saya juga.
Petr Pudlák
Apakah semua perangkat swap diaktifkan dengan prioritas yang sama?
Nils
@Petr Pudlák: Menangguhkan ke disk sedikit berbeda, hanya menulis konten RAM ke ruang kosong di area swap, dan ini (dan un-menangguhkan) mungkin jauh lebih cepat. Saya tidak dapat mencoba karena tidak berfungsi dengan swap terenkripsi.
maaartinus
@Nils: Ya, prioritasnya sama dan disk dan partisi mereka juga.
maaartinus
Itu membuatnya lebih aneh. Dalam hal ini swap dilucuti di semua disk - ini harus sangat cepat. Apakah iostat -d 5menunjukkan IO rendah pada disk swapoffjuga?
Nils

Jawaban:

53

Pertama, mari kita lihat apa yang dapat Anda harapkan dari hard drive Anda. Hard drive Anda dapat melakukan 200 MB / s secara berurutan . Ketika Anda mencari waktu, itu bisa menjadi jauh lebih lambat. Untuk mengambil contoh sewenang-wenang, lihat spesifikasi untuk salah satu disk 3TB modern Seagate, ST3000DM001 :

  • Kecepatan data berkelanjutan maksimum: 210 MB / s

  • Carilah rata-rata baca: <8,5 ms

  • Bytes per sektor: 4.096

Jika Anda tidak perlu mencari, dan jika swap Anda berada di dekat tepi disk, Anda dapat berharap untuk melihat hingga tingkat maksimum = 210 MB / s

Tetapi jika data swap Anda sepenuhnya terfragmentasi, dalam skenario terburuk, Anda harus mencari-cari untuk setiap sektor yang Anda baca. Itu berarti Anda hanya bisa membaca 4 KB setiap 8,5 ms, atau 4 KB / 0,0085 = 470 KB / s

Jadi langsung dari kelelawar, itu tidak terbayangkan bahwa Anda sebenarnya berlari melawan kecepatan hard drive.


Yang mengatakan, itu tampak konyol yang swapoffakan berjalan sangat lambat dan harus membaca halaman rusak, terutama jika mereka ditulis dengan cepat (yang menyiratkan in-order). Tapi itu mungkin saja cara kerja kernel. Laporan bug Ubuntu # 486666 membahas masalah yang sama:

The swap is being removed at speed of 0.5 MB/s, while the
hard drive speed is 60 MB/s;
No other programs are using harddrive a lot, system is not under
high load etc.

Ubuntu 9.10 on quad core.

Swap partition is encrypted.
Top (atop) shows near 100% hard drive usage
  DSK | sdc | busy 88% | read 56 | write 0 | avio 9 ms |
but the device transfer is low (kdesysguard)
  0.4 MiB/s on /dev/sdc reads, and 0 on writes

Salah satu balasan adalah:

It takes a long time to sort out because it has to rearrange and flush the
memory, as well as go through multiple decrypt cycles, etc. This is quite
normal

Laporan bug ditutup tidak terselesaikan.

Buku Mel Gorman " Memahami Linux Virtual Memory Manager " agak ketinggalan zaman, tetapi setuju bahwa ini adalah operasi yang lambat:

Fungsi yang bertanggung jawab untuk menonaktifkan suatu area, cukup dapat diprediksi, disebut sys_swapoff(). Fungsi ini terutama berkaitan dengan memperbarui swap_info_struct. Tugas utama paging di setiap halaman paged-out adalah tanggung jawab try_to_unuse()yang sangat mahal.

Ada sedikit lebih banyak diskusi dari tahun 2007 tentang milis linux-kernel dengan subjek " mempercepat swapoff " - meskipun kecepatan yang mereka bahas ada sedikit lebih tinggi daripada yang Anda lihat.


Ini adalah pertanyaan menarik yang mungkin pada umumnya diabaikan, karena swapoffjarang digunakan. Saya berpikir bahwa jika Anda benar-benar ingin melacaknya, langkah pertama akan mencoba untuk menonton pola penggunaan disk Anda lebih hati-hati (mungkin dengan atop, iostatatau bahkan alat-alat yang lebih kuat seperti perfatau systemtap). Hal-hal yang harus dicari mungkin pencarian yang berlebihan, operasi I / O kecil, penulisan ulang yang konstan dan pergerakan data, dll.

Jim Paris
sumber
5
Penjelasan yang bagus. Perlu dicatat bahwa mungkin untuk menghindari sebagian besar fragmentasi dan membebaskan sebagian besar swap dengan cepat dengan melakukan dump
Brandon DuPree
Bukan hanya fragmentasi / mencari waktu. Swap saya menggunakan SSD dan pembacaan acak sangat cepat, namun perintah swapoff jauh lebih lambat dari yang seharusnya dan beban SSD saya duduk di sekitar util 1%. Saya curiga ada daftar-berjalan yang terlibat di suatu tempat di kernel atau di swapoff (yang menggunakan ~ 90-100% CPU). Tentu saja jika semua pekerjaan dilakukan secara berurutan dan pencarian disk lambat juga dapat bertambah secara signifikan.
Thomas Guyot-Sionnest
33

Saya telah mengalami masalah yang sama dengan laptop saya yang memiliki SSD sehingga mencari waktu seharusnya tidak menjadi masalah.

Saya menemukan penjelasan alternatif . Berikut ini kutipannya

Cara kerjanya sekarang, swapoff melihat setiap halaman memori yang ditukar di partisi swap, dan mencoba menemukan semua program yang menggunakannya. Jika tidak dapat menemukan mereka segera, itu akan melihat tabel halaman dari setiap program yang berjalan untuk menemukan mereka. Dalam kasus terburuk, ini akan memeriksa semua tabel halaman untuk setiap halaman yang diganti di partisi. Itu benar – tabel halaman yang sama diperiksa berulang kali.

Jadi ini adalah masalah kernel daripada yang lainnya.

Nick Craig-Wood
sumber
Tidak, ini bukan masalah kernel IMHO. Begitulah cara swapoffdiimplementasikan. Ketika proses swapping out keluar, tidak butuh waktu lama.
Marki555
15
Ini adalah masalah dengan implementasi swapoff yang ada di kernel - karenanya merupakan masalah kernel! Anda dapat melihat apakah Anda strace swapoffyang cukup banyak melakukan panggilan swapoffsistem.
Nick Craig-Wood
1
Saya punya server dengan 48GB RAM (32cores), memiliki 6 GB bug swap gratis digunakan 0.7GB. swappiness = 10, mencoba membuatnya 0 dan juga mencoba swapoff untuk melihat apa yang terjadi. swapoff membutuhkan waktu lama, mungkin 30 menit, melepaskan swap secara lambat. Saya memiliki SSD di bawah hampir tanpa beban dan CPU serupa, mengharapkan proses swapoff yang mengambil satu cpu 100%.
Sorin
1
Ini masalah bagaimana swapoff diimplementasikan (dalam kernel). Ada beberapa diskusi tentang pendekatan yang jauh lebih baik beberapa tahun yang lalu di kernel-dev, tetapi mereka mengatakan itu adalah sudut pandang dan tidak ingin upaya untuk mengubahnya.
Marki555
7
Di server dengan 1 TB RAM (ya, TB) dan 2 GB swap (persyaratan SAP konyol), swapoff memerlukan waktu 12 jam untuk membebaskan 5% dari 2 GB itu (dengan 1 cpu core 100%).
Marki555
22

Yup, swapoffmekanismenya sangat tidak efisien. Solusinya mudah: beralih pada proses, alih-alih beralih ke halaman yang ditukar. Gunakan skrip python ini (saya tidak berafiliasi):

git clone https://github.com/wiedemannc/deswappify-auto

Perhatikan bahwa mode operasi daemon hanya untuk desktop / laptop yang sering di-hibernasi. Saya tidak akan menjalankannya sebagai daemon pada sistem server - jalankan saja di latar depan, tunggu sampai ada laporan yang menangani beberapa proses kemudian hentikan dan coba:

swapoff /dev/x

Karena sebagian besar halaman sekarang hadir baik dalam swap dan dalam memori, swapoffsangat sedikit yang harus dilakukan dan sekarang harus sangat cepat (saya melihat ratusan MB / s).

Bagian sejarah di depan

Script python tersebut didasarkan pada sisa dari jawaban ini, yang pada gilirannya adalah peningkatan saya dari jawaban yang lebih tua ini yang ditulis oleh jlong . Karena skripnya jauh lebih aman, saya sarankan untuk hanya mencoba sisa jawaban saya sebagai baris pertahanan terakhir :

perl -we 'for(`ps -e -o pid,args`) { if(m/^ *(\d+) *(.{0,40})/) { $pid=$1; $desc=$2; if(open F, "/proc/$pid/smaps") { while(<F>) { if(m/^([0-9a-f]+)-([0-9a-f]+) /si){ $start_adr=$1; $end_adr=$2; }  elsif(m/^Swap:\s*(\d\d+) *kB/s){ print "SSIZE=$1_kB\t gdb --batch --pid $pid -ex \"dump memory /dev/null 0x$start_adr 0x$end_adr\"\t2>&1 >/dev/null |grep -v debug\t### $desc \n" }}}}}' | sort -Vr | head

Ini berjalan mungkin 2 detik dan tidak akan benar-benar melakukan apa-apa, cukup daftarkan 10 segmen memori teratas (sebenarnya ia mencetak lebih banyak satu-liner; ya saya memang suka satu-liner; cukup periksa perintah, terima risiko, salin dan tempel ke shell Anda; ini sebenarnya akan dibaca dari swap).

...Paste the generated one-liners...
swapoff /your/swap    # much faster now

Satu-liner utama aman (untuk saya), kecuali membaca banyak / proc.

Sub-perintah yang disiapkan untuk ujian manual Anda tidak aman . Setiap perintah akan menggantung satu proses selama membaca segmen memori dari swap. Jadi tidak aman dengan proses yang tidak mentolerir jeda. Kecepatan transfer yang saya lihat berada di urutan 1 gigabyte per menit. (Skrip python tersebut menghilangkan kekurangan itu).

Bahaya lain adalah terlalu banyak tekanan memori pada sistem, jadi periksalah seperti biasa free -m

Apa fungsinya?

for(`ps -e -o pid,args`) {

  if(m/^ *(\d+) *(.{0,40})/) { 
    $pid=$1; 
    $desc=$2; 

    if(open F, "/proc/$pid/smaps") { 

      while(<F>) { 

        if(m/^([0-9a-f]+)-([0-9a-f]+) /si){ 
          $start_adr=$1; 
          $end_adr=$2; 
        } elsif( m/^Swap:\s*(\d\d+) *kB/s ){
          print "SSIZE=$1_kB\t gdb --batch --pid $pid -ex \"dump memory /dev/null 0x$start_adr 0x$end_adr\"\t2>&1 >/dev/null |grep -v debug\t### $desc \n" 
        }
      }
    }
  }
}

Output dari skrip perl ini adalah serangkaian gdbperintah dump memory (range)yang memanggil halaman yang ditukar ke memori.

Output dimulai dengan ukuran, jadi cukup mudah untuk melewatinya | sort -Vr | headuntuk mendapatkan 10 segmen terbesar berdasarkan ukuran (SSIZE). The -Vberdiri untuk menyortir versi-nomor-cocok, tetapi bekerja untuk tujuan saya. Saya tidak dapat menemukan cara membuat pengurutan numerik berfungsi.

kubanczyk
sumber
Anda akan menggunakan jenis angka di sini dengansort -t = -k 2n
Stéphane Chazelas
9
Sepertinya tidak perlu menggunakan gdb untuk mengintip memori proses (setidaknya pada kernel baru-baru ini). Seseorang dapat membuka /proc/$pid/mem, mencari, dan membaca secara langsung. Inilah PoC yang sebagian besar didasarkan pada cuplikan Anda: gist.github.com/WGH-/91260f6d65db88be2c847053c49be5ae Proses cara ini tidak dihentikan, AFAIK seharusnya tidak ada bahaya yang disebabkan oleh ini.
WGH
10

Selama swapoff, jika slot swap yang digunakan terdeteksi, maka kernel pertama kali bertukar di halaman. Fungsi unuse_process () kemudian mencoba untuk menemukan semua entri tabel halaman yang sesuai dengan halaman yang baru saja ditukar dan membuat pembaruan yang diperlukan untuk tabel halaman. Pencarian ini sangat lengkap dan memakan waktu: mengunjungi setiap deskriptor memori (dari keseluruhan sistem) dan memeriksa entri tabel halamannya satu per satu.

Silakan lihat halaman 724 dari "Memahami versi Linux Kernel 3".

Leslie
sumber