
Översättningen av artikeln förbereddes för studenter i kursen .
Tidigare har jag berättat om hur man kontrollerar och aktiverar användning av HugePages i Linux.
Denna artikel kommer att vara användbar endast om du verkligen har en plats att använda HugePages. Jag har stött på många människor som bedrar sig själva med utsikterna att HugePages magiskt kommer att öka prestandan. Ändå är hugepaging ett komplext ämne, och vid felaktig användning kan det sänka prestandan.
Del 1: Kontrollera att hugepages är aktiverade i Linux (originalet )
Problem:
Det är nödvändigt att kontrollera om HugePages är aktiverade på ditt system.
Lösningen:
Det är ganska enkelt:
cat /sys/kernel/mm/transparent_hugepage/enabledDu får något i stil med detta:
always [madvise] neverDu kommer att se en lista med tillgängliga alternativ (always, madvise, never), där det aktuella aktiva alternativet kommer att anges i parentes (som standard madvise).
madvise betyder att transparent hugepages är aktiverade endast för minnesområden som uttryckligen begär hugepages med hjälp av .
always betyder att transparent hugepages är alltid aktiverat för alla processer. Vanligtvis ökar detta prestandan, men om du har ett användningsfall där många processer förbrukar en liten mängd minne, kan den totala minnesbelastningen öka kraftigt.
never betyder att transparent hugepages kommer inte att aktiveras ens vid begäran med hjälp av madvise. För mer information, se Linux-kärnan.
Hur man ändrar standardvärdet
Alternativ 1: Ändra direkt sysfs (efter omstart kommer parametern att återgå till standardvärdet):
echo always >/sys/kernel/mm/transparent_hugepage/enabled
echo madvise >/sys/kernel/mm/transparent_hugepage/enabled
echo never >/sys/kernel/mm/transparent_hugepage/enabledAlternativ 2: Ändra systemets standardvärde genom att omkompilera kärnan med en ändrad konfiguration (detta alternativ rekommenderas endast om du använder en egen kärna):
- För att sätta always som standard, använd:
CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y # Kommentera bort CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y - För att sätta madvise som standard, använd:
CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y # Kommentera bort CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
Del 2: Fördelar och nackdelar med HugePages
Vi kommer att selektivt förklara fördelarna, nackdelarna och möjliga fel vid användning av Hugepages. Eftersom det är en tekniskt komplex och noggrann artikel kommer den troligtvis att vara svår att förstå för personer som luras att tro att Hugepages är en universallösning. Jag kommer att offra noggrannhet för enkelhetens skull. Det är värt att notera att många ämnen verkligen är komplexa och därför starkt förenklade.
Observera att vi pratar om 64-bitars x86-system som körs på Linux, och att jag förutsätter att systemet stödjer transparent hugepages (eftersom det inte är ett fel om hugepages inte används), vilket är fallet praktiskt taget i alla moderna Linux-miljöer.
I länkarna nedan kommer jag att bifoga mer teknisk information.
Virtuell minne
Om du är en C++-programmerare vet du att objekt i minnet har specifika adresser (pekare värden).
Dessa adresser återspeglar dock inte nödvändigtvis de fysiska adresserna i minnet (adresser i RAM). De representerar adresser i det virtuella minnet. Processorn har en speciell modul, MMU (minneshanteringsenhet), som hjälper kärnan att matcha det virtuella minnet med den fysiska platsen.
Denna metod har många fördelar, men de mest grundläggande är:
- Prestanda (av olika anledningar);
- Isolering av program, det vill säga att inget program kan läsa från minnet av ett annat program.
Vad är sidor?
Det virtuella minnet är indelat i sidor. Varje enskild sida pekar på specifik fysisk minne, den kan peka på en del av RAM eller på en adress tilldelad en fysisk enhet, såsom ett grafikkort.
De flesta sidor du hanterar pekar antingen på RAM eller byts ut (swap), det vill säga lagras på en hårddisk eller SSD. Kärnan hanterar den fysiska placeringen av varje sida. Om en bytt ut sida åtkomst görs pausar kärnan den tråd som försöker få åtkomst till minnet, läser sidan från hårddisken/SSD till RAM, och fortsätter sedan exekveringen av tråden.
Processen är transparent för tråden, det vill säga att den inte nödvändigtvis läser direkt från hårddisken/SSD. Storleken på vanliga sidor är 4096 byte. Storleken på Hugepages är 2 megabyte.
Översättningsbuffy (TLB)
När programmet adresserar en minnessida måste processorn veta från vilken fysisk sida den ska läsa data (det vill säga ha en virtuell adresskarta).
I kärnan finns en datastruktur (sidtabell) som innehåller all information om de använda sidorna. Med hjälp av denna datastruktur kan en virtuell adress kopplas till en fysisk adress.
Men sidtabellen är ganska komplex och arbetar långsamt, så vi kan helt enkelt inte analysera hela datastrukturen varje gång en process adresserar minnet.
Lyckligtvis har vår processor en TLB som cachar kopplingen mellan virtuella och fysiska adresser. Det innebär att även om vi behöver analysera sidtabellen första gången vi ska få tillgång, kan alla efterföljande åtgärder på sidan hanteras i TLB, vilket säkerställer snabbare prestanda.
Eftersom den implementeras som en fysisk enhet (vilket gör den snabb) är dess kapacitet begränsad. Så om du vill få tillgång till fler sidor kan inte TLB lagra kopplingen för alla, vilket gör att ditt program kommer att fungera mycket långsammare.
Hugepages kommer till undsättning
Så vad kan vi göra för att undvika att TLB överfylls? (Vi antar att programmet fortfarande behöver samma mängd minne).
Det är här Hugepages kommer in. Istället för 4096 byte, som kräver endast en post i TLB, kan en post i TLB nu peka på enorma 2 megabyte. Låt oss anta att TLB har 512 poster, här utan Hugepages kan vi mappa:
4096 b⋅512=2 MBMed dem kan vi mappa:
2 MB⋅512=1 GBDet är därför Hugepages är fantastiska. De kan förbättra prestandan utan betydande ansträngning. Men det finns betydande begränsningar.
Byten av Hugepages
Kärnan spårar automatiskt användningsfrekvensen för varje minnessida. Om det inte finns tillräckligt med fysisk minne (RAM), kommer kärnan att flytta mindre viktiga (mer sällan använda) sidor till hårddisken för att frigöra en del RAM för viktigare sidor.
I princip gäller samma sak för Hugepages. Men kärnan kan endast byta hela sidor, inte enskilda byte.
Anta att vi har ett sådant program:
char* mymemory = malloc(2*1024*1024); // Låt oss kalla detta en Hugepage!
// Vi fyller mymemory med någon data
// Vi gör många andra saker,
// som kommer att leda till att sidan mymemory byts ut
// ...
// Begär åtkomst till endast den första byten
putchar(mymemory[0]); I detta fall måste kärnan läsa hela 2 megabyte information från hårddisken/SSD:n bara för att du ska läsa en byte. När det gäller vanliga sidor behöver endast 4096 byte läsas från hårddisken/SSD:n.
Därför, om hugepage byts ut, sker läsningen snabbare endast om du behöver få åtkomst till hela sidan. Det betyder att om du försöker få åtkomst till slumpmässiga delar av minnet och bara läser ett par kilobyte, bör du använda vanliga sidor och inte oroa dig för mer.
Å andra sidan, om du behöver få åtkomst till en stor del av minnet sekventiellt, kommer hugepages att öka din prestanda. Du måste dock kontrollera detta själv (och inte med en abstrakt mjukvara) och se vad som fungerar snabbare.
Minnessallokering
Om du skriver i C vet du att du kan begära både mycket små (eller nästan hur stora som helst) mängder minne från heapen med hjälp av malloc(). Anta att du behöver 30 byte minne:
char* mymemory = malloc(30);För programvaruutvecklaren kan det verka som att du 'begär' 30 byte minne från operativsystemet och returnerar en pekare till viss virtuell minne. Men egentligen malloc () är helt enkelt en C-funktion som internt anropar funktionerna för att begära eller frigöra minne från operativsystemet.
Men att begära mer och mer minne för varje allokering är ineffektivt; det är mycket troligt att någon minnessegment redan har frigjorts (free()), och vi kan återanvända det. malloc() implementerar ganska komplexa algoritmer för att återanvända frigjort minne.
För dig sker detta dock osynligt, så varför borde det bekymra dig? Eftersom anropet free() inte innebär att .
Det finns ett begrepp som kallas minnesfragmentering. I extrema fall finns det segment i heap-minnet där endast några få byte används, medan allt däremellan har frigjorts. (free()).
Observera att minnesfragmentering är ett otroligt komplext ämne, och även små förändringar i programmet kan ha stor inverkan på den. I de flesta fall orsakar program inte betydande minnesfragmentering, men du bör vara medveten om att om det finns problem med fragmentering i ett visst område av heapet, kan hugepages bara förvärra situationen.
Selektiv tillämpning av hugepages
Efter att ha läst artikeln har du identifierat vilka delar av ditt program som kan dra nytta av hugepages och vilka som inte kan. Så bör du överhuvudtaget aktivera hugepages?
Lyckligtvis kan du använda madvise(), för att aktivera hugepaging endast för de minnesområden där det kommer att vara effektivt.
Börja med att kontrollera att hugepages fungerar i madvise()-läge, med hjälp av i början av artikeln.
Använd sedan madvise(), för att ange för kärnan var hugepages ska användas.
#include <sys/mman.h>
// Аллоцируйте большое количество памяти, которую будете использовать
size_t size = 256*1024*1024;
char* mymemory = malloc(size);
// Просто включите hugepages…
madvise(mymemory, size, MADV_HUGEPAGE);
// … и задайте следующее
madvise(mymemory, size, MADV_HUGEPAGE | MADV_SEQUENTIAL)Observera att denna metod bara är rekommendationer till kärnan för minneshantering. Det betyder inte att kärnan automatiskt kommer att använda hugepages för det angivna minnet.
Kolla dokumentationen , för att lära dig mer om minneshantering och madvise(), detta ämne har en otroligt brant inlärningskurva. Så om du avser att verkligen förstå det, förbered dig på att läsa och testa i flera veckor innan du kan förvänta dig några positiva resultat.
Vad ska man läsa?
Har du en fråga? Skriv i kommentarerna!
Källa: habr.com
