Ipari zen

Szak-irodalom. A fejlesztő jajszava haikuban. A technika ördöge avagy a lelketlen vasban a mélyen emberi.

A szoftverfejlesztés művészete és a zen

2010.05.28. 22:59 Ipari zen

Ne tégy el befőttet, ha úgyis más zabálja fel

Címkék: cache hit cache flush cache miss per cpu spinlock winpcap

Csúf viszály kél, ha

változódon megannyi

proci osztozik.

Nemrégiben egy kisebb projekt keretében egy meglévő egyszálú linux kernel modult kellett átalakítani többszálúvá, mert egy szálon már nem tudott megfelelő teljesíményt nyújtani. A jelenlegi állapotban egy 8 processzoros gépen, 8 konkurrens szálon fut nagyjából ugyanaz az adatfeldolgozó rutin. A szálak működését befolyásoló tényezők egy közös memóraiterületen vannak tárolva és akár működés közben is változhatnak. Ezeket sikerült megfelelő read/write spinlockokkal úgy zárolni, hogy a modul teljesítménye az eredeti egyszálas verzió többszörösére nőtt. Ezzel a feladat nagyjából megoldottnak volt tekinthető, ám egy kóbor ötlettől vezérelve kitaláltuk, hogy jó lenne statisztikákat kapni futás közben arról, hogy mennyi és milyen típusú adatot dolgoztunk fel. Mindössze néhány egyszerű számlálóról volt szó, pillanatok alatt kész is lett. Csakhogy döbbenten tapasztaltuk, annyira gyorsan dolgozik a modul, hogy nem győzi számolni az elvégzett munkát.

Azaz, ha bekapcsoltuk a statisztikákat, a modul teljesítménye majdnem a felére esett vissza a statisztika nélküli állapothoz képest. Túl nagynak tűnt a költség, főleg tekintetbe véve, hogy a statisztikaszámolás elhanyagolható műveletigénnyel bírt a többihez képest. A rejtélyt a guglizás sem oldotta meg, végül a linux kernel forrásának nézegetése vezetett nyomra. Megpróbáltam benne hasonló statisztikaszámolásra keresni megoldásokat és láss csodát, volt is. A problémát ugyanis az okozza, hogy számlálók közösek az összes szálra és processzorra nézve. A kurrens értékét mindegyik processzoron levő szál előrelátóan berántja a cache-be. Igen ám, de amikor az egyik szál inkrementálja ezt az értéket, akkor az összes többi processzornak ki kell dobnia a cache-ből a szépen előre bespájzolt értéket és újra fel kell töltenie a cache-t, egyszóval kevés lesz a cache hit és rettenetesen megszaporodnak a cache flush-ok. Egy módon lehet ezzel elegánsan elbánni, ha minden processzornak saját számlálója van. Ebben az esetben a processzor becache-seli a saját változóját és azt nem bántja senki más. Ha a teljes összegre van szükség, akkor időnként összegezni kell a számlálókat. A linux 2.6-os linux kerneltől egész jó támogatás van erre a mechanizmusra.

<linux/percpu.h>
DEFINE_PER_CPU(int, counter)

Ezzel a makróval egy int típusú counter nevű változót tudunk létrehozni, amelyikből minden processzornak van egy példánya. A változó típusa lehet egyszerű változó, struktúra, tömb vagy akár pointer is, amihez később foglalunk dinamikusan processzoronkénti memóriát (ez az alloc_percpu utasítással tehető meg). A frissen definiált változónkat a következőképpen használhatjuk:get_cpu_var(counter)++;
put_cpu_var(counter);

A get_cpu_var/put_cpu_var páros gyakorlatilag biztosítja azt, hogy a per-cpu változók kezelése közben ne szakítsa meg semmi a szál működését és ne költöztessék át másik processzorra, így semmilyen más lockolásra nincsen szükség a használatuk közben.

Ahhoz, hogy összegezni is tudjuk a processzorok számlálóit, rendelkezésre áll a per_cpu parancs amivel bármelyik processzor változópéldánya elérhető.

int cpu;
int sum_counter = 0;
for_each_online_cpu(cpu)
    sum += per_cpu(counter, cpu);
Itt van egy kicsit bővebb leírás a működéséről.

A Windows kernel API-ban sajnos nem találtam támogatást rá, de a nyílt forráskódú Winpcap halókártya driverében található egy hasonló megoldás. A Winpcap foráskódja letölthető innen,  a packetNtx/driver könyvtárban kell keresgélni.

1 komment

A bejegyzés trackback címe:

https://ipari-zen.blog.hu/api/trackback/id/tr142039160

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

Sopánka76 2010.08.05. 22:32:25

Tanulságos. Köszönjük!