A Mediastreamer2 VoIP motor felfedezése. 12. rész

A cikk anyaga az én zen csatorna.

A Mediastreamer2 VoIP motor felfedezése. 12. rész

Az utolsóban cikk, Megígértem, hogy megvizsgálom a ticker terhelésének felmérését és a média streamer túlzott számítási terhelése elleni küzdelem módjait. De úgy döntöttem, hogy logikusabb lenne, ha kitérnék az adatmozgással kapcsolatos kézműves szűrők hibakeresésének kérdéseire, és csak ezután foglalkoznék a teljesítményoptimalizálással.

Kézműves szűrők hibakeresése

Miután az előző cikkben megnéztük az adatok mozgatásának mechanizmusát a média streamerben, logikus lenne a benne rejlő veszélyekről beszélni. Az „adatfolyam” elv egyik jellemzője, hogy a halomból az adatfolyam forrásánál elhelyezkedő szűrőkben foglalják le a memóriát, és az áramlás végén elhelyezett szűrők felszabadítják és visszajuttatják a memóriát a kupacba. pálya. Ezenkívül valahol a kettő között történhet új adatok létrehozása és megsemmisítése. A memóriafelszabadítást általában más szűrő hajtja végre, mint az, amelyik létrehozta az adatblokkot.

A transzparens memóriafigyelés szempontjából célszerű lenne, ha a szűrő egy bemeneti blokk vételekor azt feldolgozás után azonnal megsemmisítené, a memória felszabadításával, és egy újonnan létrehozott blokkot adna ki kimeneti adatokkal. Ebben az esetben a szűrő memóriaszivárgása könnyen nyomon követhető - ha az analizátor szivárgást észlel a szűrőben, akkor a következő szűrő nem semmisíti meg megfelelően a bejövő blokkokat, és hiba van benne. A nagy teljesítmény fenntartása szempontjából azonban ez az adatblokkokkal való munkavégzés nem produktív – nagyszámú művelethez vezet az adatblokkok memóriájának lefoglalására/felszabadítására, hasznos kimenet nélkül.

Emiatt a média streamer szűrők, hogy ne lassítsák az adatfeldolgozást, olyan funkciókat használnak, amelyek egyszerű másolatokat készítenek az üzenetek másolásakor (az előző cikkben beszéltünk róluk). Ezek a funkciók csak akkor hozzák létre az üzenet fejlécének új példányát, ha „csatolnak” hozzá egy adatblokkot a másolandó „régi” üzenetből. Ennek eredményeként egy adatblokkhoz két fejléc kapcsolódik, és az adatblokkban lévő referenciaszámláló növekszik. De úgy fog kinézni, mint két üzenet. Egy ilyen „szocializált” adatblokknál több üzenet is lehet, például az MS_TEE szűrő egy tucat ilyen fénymásolatot generál egyszerre, elosztva azokat a kimenetei között. Ha a lánc összes szűrője megfelelően működik, a folyamat végére ennek a referenciaszámlálónak el kell érnie a nullát, és a memóriafelszabadítási függvény meghívásra kerül: ms_free(). Ha a hívás nem történik meg, akkor ez a memóriadarab többé nem kerül vissza a kupacba, azaz. "szivárogni fog". A könnyű másolatok használatának ára annak a képességének elvesztése, hogy könnyen megállapítható legyen (mint a normál másolatok esetében), hogy melyik grafikonszűrő szivárog ki a memóriából.

Mivel a média streamer fejlesztői felelősek a natív szűrők memóriaszivárgásának megtalálásáért, valószínűleg nem kell hibakeresést végeznie. A kézműves szűrővel azonban saját boldogságod szöcske vagy, és a kódodban lévő szivárgások keresésével töltött idő a pontosságodtól függ. A hibakeresési idő csökkentése érdekében a szűrők fejlesztése során figyelembe kell vennünk a szivárgásészlelési technikákat. Emellett előfordulhat, hogy a szivárgás csak akkor jelenik meg, ha a szűrőt egy valós rendszerben alkalmazzák, ahol a „gyanúsítottak” száma óriási és a hibakeresési idő korlátozott.

Hogyan nyilvánul meg a memóriazavar?

Logikus azt feltételezni, hogy a program kimenetében felső megmutatja az alkalmazás által elfoglalt memória növekvő százalékát.

A külső megnyilvánulás az lesz, hogy egy bizonyos ponton a rendszer lassan reagál az egér mozgására, és lassan újrarajzolja a képernyőt. Az is lehetséges, hogy a rendszernapló növekedni fog, és helyet foglal a merevlemezen. Ebben az esetben az alkalmazás furcsán kezd viselkedni, nem reagál a parancsokra, nem tud megnyitni egy fájlt stb.

A szivárgás észleléséhez memóriaanalizátort (a továbbiakban analizátor) használunk. Lehet, hogy valgrind (jó cikk róla) vagy beépítve a fordítóba gcc MemorySanitizer vagy bármi mást. Ha az analizátor azt mutatja, hogy az egyik grafikonszűrőben szivárgás lép fel, akkor ez azt jelenti, hogy ideje alkalmazni az alábbiakban ismertetett módszerek valamelyikét.

Három fenyő módszer

Ahogy fentebb említettük, memóriaszivárgás esetén az analizátor arra a szűrőre mutat, amely memóriafoglalást kért a kupacból. De nem mutat rá arra a szűrőre, amelyik „elfelejtette” visszaküldeni, ami valójában a tettes. Így az elemző csak megerősítheti félelmeinket, de nem jelzi annak gyökerét.

A „rossz” szűrő helyének meghatározásához a grafikonon csökkentheti a grafikont azon csomópontok minimális számára, amelyeknél az analizátor még mindig szivárgást észlel, és lokalizálja a problémás szűrőt a fennmaradó három fenyőben.

Előfordulhat azonban, hogy a szűrők számának csökkentésével a grafikonon megzavarja a szűrők és a rendszer más elemei közötti interakció normál menetét, és a szivárgás megszűnik. Ebben az esetben teljes méretű grafikonnal kell dolgoznia, és az alábbiakban vázolt megközelítést kell alkalmaznia.

Csúszó szigetelő módszer

A bemutatás egyszerűsítése érdekében olyan grafikont fogunk használni, amely egy szűrőláncból áll. Ő látható a képen.

A Mediastreamer2 VoIP motor felfedezése. 12. rész

Egy normál grafikon, amelyen a kész média streamer szűrőkkel együtt négy darab F1...F4 kézműves szűrőt használnak, négy különböző típusból, amelyeket Ön már régen készített, és nincs kétsége a helyességükről. Tételezzük fel azonban, hogy közülük többnek memóriaszivárgása van. Az analizátor figyelésére szolgáló programunkat futtatva a jelentéséből megtudjuk, hogy egy bizonyos szűrő bizonyos mennyiségű memóriát kért, és nem adta vissza a kupacba N számú alkalommal. Könnyen kitalálhatja, hogy lesz egy hivatkozás az MS_VOID_SOURCE típusú belső szűrőfunkciókra. Az ő feladata, hogy emléket vegyen a kupacból. Más szűrőknek vissza kell juttatniuk oda. Azok. észleljük a szivárgás tényét.

Annak meghatározására, hogy a folyamat melyik szakaszán történt tétlenség, ami memóriaszivárgáshoz vezetett, egy további szűrő bevezetése javasolt, amely egyszerűen áthelyezi az üzeneteket a bemenetről a kimenetre, ugyanakkor létrehozza a bemeneti üzenet nem világos másolatát. , hanem egy normál „nehéz”, majd teljesen törli a belépéskor kapott üzenetet. Az ilyen szűrőt szigetelőnek nevezzük. Úgy gondoljuk, hogy mivel a szűrő egyszerű, nincs benne szivárgás. És még egy pozitív tulajdonság - ha hozzáadjuk bárhová a grafikonon, ez semmilyen módon nem befolyásolja az áramkör működését. A szűrő-leválasztót kör alakban ábrázoljuk kettős áramkörrel.

A leválasztót közvetlenül a voidsource szűrő után kapcsoljuk be:
A Mediastreamer2 VoIP motor felfedezése. 12. rész

Ismét lefuttatjuk a programot az analizátorral, és azt látjuk, hogy ezúttal az analizátor a szigetelőt fogja hibáztatni. Végül is ő az, aki most adatblokkokat hoz létre, amelyeket aztán egy ismeretlen gondatlan szűrő (vagy szűrők) elveszít. Következő lépésként mozgassa a szigetelőt a lánc mentén jobbra, egy szűrővel, és kezdje újra az elemzést. Tehát az izolátort lépésről lépésre jobbra mozgatva olyan helyzetet kapunk, hogy a következő analizátor jelentésben a „kiszivárgott” memóriablokkok száma csökkenni fog. Ez azt jelenti, hogy ennél a lépésnél a szigetelő közvetlenül a problémás szűrő után volt a láncban. Ha csak egy „rossz” szűrő volt, akkor a szivárgás teljesen eltűnik. Így lokalizáltuk a problémás szűrőt (vagy egyet a több közül). A szűrő „javítása” után folytathatjuk a leválasztó jobb oldali mozgatását a lánc mentén, amíg teljesen le nem küzdjük a memóriaszivárgást.

Izolátor szűrő megvalósítása

Az izolátor megvalósítása úgy néz ki, mint egy normál szűrő. Fejléc fájl:

/* Файл iso_filter.h  Описание изолирующего фильтра. */

#ifndef iso_filter_h
#define iso_filter_h

/* Задаем идентификатор фильтра. */
#include <mediastreamer2/msfilter.h>

#define MY_ISO_FILTER_ID 1024

extern MSFilterDesc iso_filter_desc;

#endif

Maga a szűrő:

/* Файл iso_filter.c  Описание изолирующего фильтра. */

#include "iso_filter.h"

    static void
iso_init (MSFilter * f)
{
}
    static void
iso_uninit (MSFilter * f)
{
}

    static void
iso_process (MSFilter * f)
{
    mblk_t *im;

    while ((im = ms_queue_get (f->inputs[0])) != NULL)
    {
        ms_queue_put (f->outputs[0], copymsg (im));
        freemsg (im);
    }
}

static MSFilterMethod iso_methods[] = {
    {0, NULL}
};

MSFilterDesc iso_filter_desc = {
    MY_ISO_FILTER_ID,
    "iso_filter",
    "A filter that reads from input and copy to its output.",
    MS_FILTER_OTHER,
    NULL,
    1,
    1,
    iso_init,
    NULL,
    iso_process,
    NULL,
    iso_uninit,
    iso_methods
};

MS_FILTER_DESC_EXPORT (iso_desc)

A memóriakezelési funkciók cseréjének módja

A finomabb kutatás érdekében a média streamer lehetőséget ad arra, hogy a memóriaelérési funkciókat lecserélje a sajátjára, amely a fő munka mellett rögzíti a „Ki, hol és miért” feliratot. Három funkció cserélődik. Ez a következőképpen történik:

OrtpMemoryFunctions reserv;
OrtpMemoryFunctions my;

reserv.malloc_fun = ortp_malloc;
reserv.realloc_fun = ortp_realloc;
reserv.free_fun = ortp_free;

my.malloc_fun = &my_malloc;
my.realloc_fun = &my_realloc;
my.free_fun = &my_free;

ortp_set_memory_functions(&my);

Ez a funkció olyan esetekben segít, amikor az analizátor annyira lelassítja a szűrők működését, hogy annak a rendszernek a működése, amelybe áramkörünk épült, megszakad. Ilyen helyzetben el kell hagynia az analizátort, és a memóriával való munkavégzéshez függvények helyettesítését kell használnia.

Megvizsgáltunk egy műveleti algoritmust egy egyszerű gráfhoz, amely nem tartalmaz ágakat. De ez a megközelítés más esetekre is alkalmazható, persze bonyolultabban, de az ötlet ugyanaz marad.

A következő cikkben megvizsgáljuk a ticker terhelésének becslését és a média streamer túlzott számítási terhelése elleni küzdelem módjait.

Forrás: will.com

Hozzászólás