Sivuvälimuisti tallentaa äskettäin käytetyt sivut kiintolevyltä, mikä lyhentää samojen tietojen myöhempien käyttökertojen hakuaikoja. Sivuvälimuisti ei paranna suorituskykyä, kun sivua käytetään kiintolevyltä ensimmäisen kerran. Joten jos sovellus aikoo lukea tiedoston kerran ja vain kerran, sivuvälimuistin ohittaminen on parempi tapa edetä. Tämä on mahdollista käyttämällä O_DIRECT-lippua. Tämä tarkoittaa, että ydin ei ota tätä nimenomaista tietoa huomioon sivuvälimuistissa. Välimuistikiistan vähentäminen tarkoittaa, että muilla sivuilla (joita käytettäisiin toistuvasti) on paremmat mahdollisuudet säilyä sivun välimuistissa. Tämä parantaa välimuistin ja osuman suhdetta ja tarjoaa paremman suorituskyvyn.
void ioReadOnceFile()
{
/* Käyttämällä direct_fd ja direct_f ohittaa ytimen sivuvälimuistin.
* - direct_fd on matalan tason tiedostokuvaaja
* - direct_f on tiedostovirta, joka on samanlainen kuin fopen()
*:n palauttama tiedostovirta HUOMAUTUS: Käytä getpagesize()-funktiota optimaalisen kokoisten puskureiden määrittämiseen.
*/
int direct_fd = open("tiedostonimi", O_DIRECT | O_RDWR);
TIEDOSTO *direct_f = fdopen (direct_fd, "w + ");
/* suora levy-I/O tehty TÄSTÄ*/
fclose(f);
sulje(fd);
}
Harkitse tapausta, jossa lukema on suuressa tiedostossa (eli tietokannassa), joka koostuu valtavasta määrästä sivuja. Jokainen seuraava avattu sivu menee sivuvälimuistiin ja pudotetaan pois myöhemmin, kun yhä useampia sivuja luetaan. Tämä pienentää välimuistin osumasuhdetta huomattavasti. Tässä tapauksessa sivuvälimuisti ei tarjoa suorituskyvyn parannuksia. Siksi olisi parempi ohittaa sivuvälimuisti, kun käytät suuria tiedostoja.
void ioLargeFile()
{
/* direct_fd ja direct_f ohittaa ytimen sivuvälimuistin.
* - direct_fd on matalan tason tiedostokuvaaja
* - direct_f on tiedostovirta, joka on samanlainen kuin fopen()
*:n palauttama tiedostovirta HUOMAUTUS: Käytä getpagesize()-funktiota optimaalisen kokoisten puskureiden määrittämiseen.
*/
int direct_fd = open("largefile.bin", O_DIRECT | O_RDWR | O_LARGEFILE);
TIEDOSTO *direct_f = fdopen (direct_fd, "w + ");
/* suora levy-I/O tehty TÄSTÄ*/
fclose(f);
sulje(fd);
}
IO-ajastin optimoi kiintolevylle jonossa olevien I/O-toimintojen järjestyksen. Koska hakuaika on kiintolevyn raskain rangaistus, useimmat I/O-aikatauluttajat yrittävät minimoida hakuajan. Tämä toteutetaan hissialgoritmin muunnelmana, eli satunnaisesti järjestettyjen pyyntöjen järjestäminen useista prosesseista järjestykseen, jossa tiedot ovat kiintolevyllä, vaatii huomattavan määrän CPU-aikaa.
Tiettyjä monimutkaisia toimintoja sisältäviä tehtäviä rajoittaa yleensä se, kuinka nopeasti CPU pystyy käsittelemään valtavia määriä dataa. Taustalla toimiva monimutkainen I/O-ajastin voi kuluttaa arvokkaita suoritinsyklejä, mikä heikentää järjestelmän suorituskykyä. Tässä tapauksessa vaihtaminen yksinkertaisempaan algoritmiin, kuten no-op, vähentää suorittimen kuormitusta ja voi parantaa järjestelmän suorituskykyä.
echo noop > / sys / block / / queue / scheduler
Vaikka tämä lopulta saa työn tehtyä, se ei todellakaan ole optimaalisin tapa. Ytimen näkökulmasta optimaalisin koko I/O-pyynnöille on tiedostojärjestelmän lohkon koko (eli sivukoko). Koska kaikki tiedostojärjestelmän (ja ytimen sivuvälimuistin) I/O-toiminnot ovat sivuja, sovelluksen on järkevää tehdä siirtoja myös sivukoon kerrannaisina. Myös monisegmenttisten välimuistien siirtyessä kiintolevyille nyt hyötyisi valtavasti I/O:n tekemisestä lohkokoon kerrannaisina.
Seuraavalla komennolla voidaan määrittää optimaalinen lohkokokotilasto
--printf="bs=%s optimal-bs=%S\n" --file-system /dev/
Kun sovellus aloittaa SYNC I/O -lukemisen, ydin asettaa tietojen lukutoiminnon jonoon ja palaa vasta, kun pyydettyjen tietojen koko lohko on luettu takaisin. Tänä aikana ydin merkitsee sovelluksen prosessin estetyksi I/O:lle. Muut prosessit voivat käyttää prosessoria, mikä parantaa järjestelmän yleistä suorituskykyä.
Kun sovellus aloittaa SYNC I/O -kirjoituksen, ydin asettaa tietojen kirjoitustoiminnon jonoon ja asettaa sovelluksen prosessin lukittuun I/O:hon. Valitettavasti tämä tarkoittaa sitä, että nykyisen sovelluksen prosessi on estetty eikä se voi tehdä mitään muuta käsittelyä (tai I/O:ta), ennen kuin tämä kirjoitustoiminto on valmis.
Kun sovellus käynnistää ASYNC I/O -lukemisen, read()-funktio palaa yleensä luettuaan suuren tietolohkon osajoukon. Sovelluksen on toistuvasti kutsuttava read()-kutsua, jonka koko on vielä lukematta, kunnes kaikki vaaditut tiedot on luettu. Jokainen ylimääräinen lukukutsu tuo mukanaan jonkin verran yleiskustannuksia, koska se tuo kontekstin vaihdon käyttäjätilan ja ytimen välillä. Tiukan silmukan toteuttaminen toistuvaan read()-kutsuun tuhlaa suoritinsyklejä, joita muut prosessit olisivat voineet käyttää. Siksi blokkaus yleensä toteutetaan select()-komennolla, kunnes seuraava read() palauttaa nollasta poikkeavat tavut read-in. eli ASYNC on tehty estämään aivan kuten SYNC-luku.
Kun sovellus aloittaa ASYNC I/O -kirjoituksen, ydin päivittää vastaavat sivut sivuvälimuistiin ja merkitsee ne likaisiksi. Sitten ohjausobjekti palaa nopeasti sovellukseen, joka voi jatkaa suorittamista. Tiedot siirretään kiintolevylle myöhemmin optimaalisempana ajankohtana (alhainen suorittimen kuormitus) optimaalisemmalla tavalla (peräkkäin niputettu kirjoitus).
Siksi SYNC-reads ja ASYNC-writes ovat yleensä hyvä tapa edetä, koska niiden avulla ydin voi optimoida taustalla olevien I/O-pyyntöjen järjestyksen ja ajoituksen.