Pamięci flash, czyli pendrive, microSD itd.

Czasem człowiekowi wydaje się, że coś wie i… no właśnie, wydaje się. Że są różne pendrive’y (czy tam ogólnie pamięci flash), to wiedziałem. Wiedziałem też, że mają klasy i poszczególne klasy odpowiadają różnym prędkościom zapisu. I tyle.

Niedawno od hrw dowiedziałem się, że to nie do końca tak, że parametrów jest znacznie więcej i że w praktyce mają one spore znaczenie przy stosowaniu karty jako nośnika dla systemu Linux. Bo jednak czym innym jest zapis filmu na FAT, a czym innym realne operacje na jakichś linuksowych systemach plików.

Ostatnio uruchomiłem grzejnik na starym pendrive, użyłem ext2 i zdarzyło mi się trochę ponarzekać na μblogu, że wolno działa i w ogóle. Dostałem odpowiedź, że minimalny cluster size dla nośnika flash powinien być 4k. Co przypomniało mi wcześniejszą rozmowę i skłoniło do zadania pytania jak sprawdzić cluster size? Co dość szybko przywiodło mnie do wpisu nt. optymalizacji systemu plików dla pamięci flash.

Zauważyłem, że blog do którego powyżej linkuję ma raptem trzy wpisy i to sprzed roku, więc ryzyko zniknięcia jest spore. Pozwolę sobie zacytować dla pamięci część dotyczącą analizy:

  1. Interesting parts of this result are the diff changes drastically at two places:
    1. from  8388608 (8Mb) to 4194304 (4MB): Based in example readme in flashbench, this indicates that there was no performance overhead reading two blocks over the 4mb boundary, but there was for 8mb boundary. The guess is then that the erasure block is 8mb large on my sd-card
    2. before 8192 and after. I would really like to know why there is a bump at 8k, but times after that are so much lower, so 8k is obviously some sort of boundary point.
  2. From this, I deduce two things,
    1. Ext4 should have a block size of 4k, and the “stride” value should be 2. This will cause ext4 to think that units of 2 blocks (8k) can and should be treated as one.
    2. Ext4 should have the stripe-size set to 1024. This value was calculated by taking 8M (guessed erasure block size) dividing by 8K (size of a stride, 2 times block size (4K)). This will (hopefully) cause Ext4 to try to align writes so that while erasure blocks are written continuously and make it avoid sub-block updates.

Część dotyczącą ustawiania początku partycji w fdisk:

First sector (2048-15759359, default 2048): 16384

Wraz z wyjaśnieniem, skąd to się wzięło:

Fdisk uses blocks of 512 bytes, so that means that we want to start at 8*1024^2/512 = 16384.

No i na koniec część dotycząca tworzenia samego filesystemu ext4:

Reformat the filesystem, this time with Ext4 with block size of 4k, without journaling, but with additional parameters to encourage Ext4 to do the right thing with respect to the erasure block:

mkfs.ext4 -O ^has_journal -E stride=2,stripe-width=1024 -b 4096 -L Fedora14Arm  /dev/mmcblk0p1

Na koniec dwa linki, które autor wpisu podaje jako źródła:

Zachęcam do lektury całego wpisu z którego pochodzą powyższe cytaty, bo powyżej są jedynie najważniejsze wyjątki, które bez kontekstu nie do końca w czymkolwiek pomogą.

Inny, prostszy (ale starszy) wpis o podobnej tematyce: http://linux-howto-guide.blogspot.com/2009/10/increase-usb-flash-drive-write-speed.html

No i dowiedziałem się, że pożyteczne narzędzie to flashbench (pakiet jest w Debianie unstable), że żaden ext2 dla nośników flash, tylko ext4 bez journala, za to z dodatkowymi opcjami, zależnymi od parametrów karty. I że nie tylko w przypadku SSD warto stosować alignment. Różnica prędkości między ext2 a ext4 po tuningu? Wg autora wpisu 8 razy szybciej dla małych plików i dwa szybciej dla dużych. Trochę mi wszystko opadło, ale za to wiem, co będę robić w weekend.

UPDATE: Trochę się pobawiłem i wyszło mi, że metoda pomiaru jest średnio dokładna. Albo pendrive zwalnia w miarę używania (w sensie „wykonana ilość zapisów”), albo reboot/hibernacja drastycznie zmieniają wyniki, albo nie wiem co jest grane. Bo zrobiłem test na FAT, potem na ext4 po dopasowaniu partycji (brak zauważalnych różnic), potem zabawa z ustawieniami ext4 i… między pierwszym testem na ext4, a końcowym, na identycznych parametrach ext4 były 4 sekundy różnicy. Przy podstawie 22 sekundy, więc prawie 20% wolniej. Zagadka. A ponieważ nie widzę zysku między FAT a ext4, to chęć do migracji ext2 -> ext4 gwałtownie spadła. Może kiedyś.

UPDATE2: Dodane cytaty z bloga. Bawiłem się trochę w optymalizacje/benchmarki na czterech różnych pendrive’ach. Tylko jeden zareagował pozytywnie na zmianę alignmentu (OK, bez wyliczeń było, po prostu początek partycji na sektorze 16384) i zmianę systemu na ext4. Przy okazji wyszło na jaw, że pendrive, który uznałem za wolny jest ok. 3 razy wolniejszy od pozostałych, niezależnie od ustawień.

Praca na desktopie z małą ilością RAM po raz drugi.

Jakiś czas temu pisałem o pierwszym podejściu do małej ilości RAM na desktopie, więc pora na część drugą. Przejrzałem podrzucone linki nt. optymalizacji działania dekstopu. Dysk był już ustawiony optymalnie, niepotrzebne usługi powyłączane, więc tak naprawdę tylko zmniejszyłem ilość uruchamianych konsol w inittabie. Nie zauważyłem zmiany w ilości zużywanego RAM, ale i tak ich nie potrzebuję – dwie wystarczają z naddatkiem. Swappiness nadal jest ustawione na 0 i IMO działa OK.

Zauważyłem, że spowalnianie występuje głównie na jednym desktopie (tym w pracy, starszy, bardziej zapchany dysk), przy pracy z pakietami (aktualizacja listy, instalacja), co skłania mnie do wniosku, że głównym winowajcą jest fragmentacja filesystemu. W obu przypadkach jest to ReiserFS (zaszłość, kiedyś był najlepszym wyborem, teraz chętnie widziałbym ext4 w tym miejscu), ale w domu z pewnością fragmentacja jest mniejsza – pół dysku zawsze było wolne.

Tak czy inaczej, wydaje mi się, że wypracowałem sposób na drastyczne ograniczenie spowalniania komputera przy pracy z pakietami. Korzystam z niego mniej więcej raz na tydzień. Cudów nie ma, czyli najpierw zamykam programy, które zużywają najwięcej RAM: Iceweasel, czyli Firefox, Icedove, czyli Thunderbird i PSI. Trwa to chwilę, a zwalnia znaczne obszary RAM.

Następnie uruchamiam prosty skrypt, który robi sync na dyskach, opróżnia bufory dyskowe, a następnie wyłącza i ponownie włącza swap.

#!/bin/bash

echo Syncing hard discs
sync
sleep 5
sync

echo Flushing disc buffers
echo 3 > /proc/sys/vm/drop_caches

echo Turning swap off
swapoff -a

echo Turning swap on
swapon -a

Celem jest najpierw zwolnienie jak największego obszaru pamięci, a następnie wymuszenie przerzucenia danych ze swap do RAM. Szybsze od restartu, działa w tle, więc można pracować w tym czasie. Po wykonaniu skryptu można swobodnie uruchomić przeglądarkę, pocztę, komunikator i aktualizować system. Najgorsze co może się wydarzyć, to niewyłączenie swapa, jeśli nie będzie wystarczającej ilości dostępnej pamięci, ale nie jest to krytyczne i zdarza się rzadko (zwł. po wyłączeniu przeglądarki). Wydaje mi się, że po takim zabiegu system działa znacznie lepiej.

Praca na desktopie z małą ilością RAM po raz pierwszy.

Tło problemu.

Tak się składa, że apetyt programów i systemów na pamięć RAM systematycznie rośnie, a moje desktopy ilością RAMu nie grzeszą. Faktem jest, że RAM jest teraz tani i praktycznie nie sposób kupić nowego komputera z mniej niż 2-4 GB RAM (chyba, że netbook jakiś), ale… nie każdy sprzęt jest nowy (mój nie jest), nie każdy pozwala na większą ilość RAM no i – przede wszystkim – inwestowanie w stosunkowo drogi, stary RAM do równie starego sprzętu nie ma IMO sensu. A skoro działa, to po co wymieniać? 😉

Poza tym, Linux potrafi działać na komputerach z małą ilością RAMu. Przynajmniej powinien umieć. W każdym razie możliwa jest w miarę komfortowa praca na desktopach z 0,5-1 GB RAM, nawet z KDE (3.5), chociaż ostatnio pożegnałem się z KDE i zwykle używam LXDE. Oczywiście zależy, co się robi, ale przy typowym korzystaniu, typu włączenie komputera, uruchomienie paru programów (komunikator, przeglądarka WWW, konsola, coś do PDF, jakiś arkusz kalkulacyjny czy edytor tekstu itp.) i wyłączenie komputera na koniec dnia, wszysko było OK, nawet na 0,5 GB nie odczuwałem specjalnego spowalniania i wykorzystania swap (czasem się zdarzało, ale nie jakoś krytycznie), ale odkąd korzystam z laptopów, hibernacji lub niewyłączania komputera, jest znacznie gorzej.

Główni winowajcy (na laptopie firmowym) to: Firefox 4 – 21% RAM, Icedove – 7,5%, Xorg – 5,4%, plugin-container (czytaj: flash) 3,8%, psi – 3,4% i konsole 2,8%. Na prywatnym lapku podobnie, tylko Firefox 3.6 zajmuje 11%, i dochodzi Chromium 6,7% (najwyższe wystąpienie, jest ich kilka) i liferea 5,4%. Niby nic specjalnego, ale po kilkunastu dniach okazuje się, że na swapie użyte jest 100-400 MB, a przy odpaleniu jakiejś większej aplikacji (czytaj Openoffice) dysk zaczyna ostro pracować. Przy czym dyski w laptopach to zwykle 5400 rpm, więc raczej nie są demonami szybkości… Jednak najgorsze dzieje się przy instalacji aktualizacji – wajig daily upgrade praktycznie zabija maszynę, do tego stopnia, że chwilowo traci responsywność – trzeba czekać na przełączenie się między oknami, kursor myszy nie porusza się płynnie itp.

Podejście pierwsze: zmiana parametru swappiness.

Określa on, jak chętnie system korzysta ze swap na dysku i przyjmuje wartości od 0 do 100 (szerszy opis parametru swappiness i dyskusja). Domyślnie wynosi on 60, co niekoniecznie jest wartością dobrą dla desktopa. Jak widać, trwa spór o to, czy lepiej ustawić 0 czy 100. Wyszedłem z założenia, że 0 jest lepszą wartością.

Tymczasowe ustawienie wartości swappiness na 0:

echo 0 > /proc/sys/vm/swappiness

Sprawdzenie aktualnego ustawienia:

cat /proc/sys/vm/swappiness

Jeśli chcemy, aby zmiana była wykonywana przy każdym uruchomieniu, to do /etc/sysctl.conf dodajemy linię:

vm.swappiness = 0

Dla jasności: ustawienie swappiness na 0 nie powoduje, że system w ogóle nie korzysta ze swap. Korzysta, jeśli musi tylko mniej chętnie w normalnych warunkach. Efekt: większość czasu jest lepiej, widać, że system praktycznie nie korzysta ze swap. Niestety, jak już zacznie korzystać, to utrata responsywności jest większa, niż przy domyślnej wartości 60 (ocena metodą najdoskonalszą, czyli na oko), więc nie do końca o to mi chodziło.

Podejście drugie: dodanie compcache.

Okazało się, że w Debianie w końcu pojawił się compcache w postaci pakietu o nazwie compcache-tools. Pakiet jest nieco śmieszny (tzn. kwalifikuje się to na bug report…), bo działa na kernelu 2.6.32 ze Squeeze, natomiast na 2.6.38 z testing/unstable brakuje modułu, choć sam pakiet właśnie testing/unstable jest. W skrócie – działa to tak, że zamiast po prostu zapisywać dane z RAM na dysk, najpierw dodatkowo je kompresuje (w RAM), a dopiero potem ew. zrzuca na dysk. Czyli większe użycie procesora w zamian za mniejsze zużycie pamięci i mniej operacji na dysku.

Aktywacja compcache (nieco inna, niż w manie, wersja z mana z insmod nie działała):

modprobe ramzswap
rzscontrol /dev/ramzswap0 --memlimit_kb=153600 --backing_swap=/swapfile.swp --init
swapon /dev/ramzswap0

Kolejno: załadownie modułu, określenie parametrów i inicjacja kompresowanego swap (tu: 150 MB RAM i wykorzystanie swap w pliku /swapfile.swp), aktywacja swap. Miałem to włączone przez kilkanaście dni, łącznie ze swappiness 0, ale nie podejmuję się oceny. IMHO niespecjalnie się różni od gołego zmniejszonego swappiness. Natomiast po reboocie system podziałał z 2 dni (bez włączonego compcache) i… system plików (reiserfs) przemontował się w RO. Fsck znalazł błędy, przebudowanie drzewa naprawiło, ale… zgubił 76 plików – i tak były niedostępne (nic krytycznego, głównie moduły Perla).

WTF? Przecież nigdy wcześniej takich cyrków nie było. Co więcej, przy próbie włączenia compcache otrzymałem komunikat typu backing swapfile has holes. To z kolei naprowadziło mnie na ten opis problemu. Niestety, pasuje idealnie, co skutecznie zniechęciło mnie – przynajmniej na jakiś czas – do zabaw z compcache. Odkryłem co prawda nieużywaną partycję swap, której mógłbym użyć, zamiast pliku, ale najpierw doczytam dokładnie. Uszkodzenia systemu plików to nie jest to, co tygrysy lubią najbardziej.

The end?

Zanim będę kontynuował, pozwolę sobie zapytać, jakie ustawienia parametru swappiness i ew. inne ustawienia proponujecie dla desktopa z Linuksem i LXDE, stosunkowo mocnym procesorem i stosunkowo małą ilością pamięci RAM (1 GB)?