Mediastreamer2 VoIP-mootori uurimine. 12. osa

Artikli materjal on võetud minu zen kanal.

Mediastreamer2 VoIP-mootori uurimine. 12. osa

Viimases siit, lubasin kaaluda tickeri koormuse hindamist ja viise, kuidas võidelda meediumivoodri liigse arvutuskoormusega. Kuid otsustasin, et loogilisem oleks käsitleda andmete liikumisega seotud käsitööfiltrite silumise küsimusi ja alles seejärel kaaluda jõudluse optimeerimise küsimusi.

Käsitööfiltrite silumine

Pärast seda, kui vaatasime eelmises artiklis andmete teisaldamise mehhanismi meediumivoodris, oleks loogiline rääkida selles peituvatest ohtudest. Andmevoo põhimõtte üks omadusi on see, et mälu eraldatakse hunnikust filtrites, mis asuvad andmevoo allika juures ning mälu vabastatakse ja tagastatakse kuhja voo lõpus asuvate filtrite abil. tee. Lisaks võib uute andmete loomine ja nende hävitamine toimuda kuskil vahepeal. Üldiselt teostab mälu vabastamise teistsugune filter kui see, mis andmeploki lõi.

Läbipaistva mälu monitooringu seisukohalt oleks mõistlik, et filter sisendploki saamisel selle koheselt peale töötlemist, mälu vabastamist hävitaks ning väljastaks vastloodud ploki koos väljundandmetega. Sel juhul oleks filtri mäluleke kergesti jälgitav - kui analüsaator tuvastas filtris lekke, siis järgmine filter ei hävita korralikult sissetulevaid plokke ja selles on viga. Kuid suure jõudluse säilitamise seisukohalt ei ole selline lähenemine andmeplokkidega töötamisele produktiivne - see toob kaasa suure hulga toiminguid andmeplokkide mälu eraldamiseks/vabastamiseks ilma kasuliku väljundita.

Sel põhjusel kasutavad meediumivoofiltrid, et andmetöötlust mitte aeglustada, funktsioone, mis loovad sõnumite kopeerimisel lihtsaid koopiaid (neist rääkisime eelmises artiklis). Need funktsioonid loovad ainult sõnumi päise uue eksemplari, "lisades" sellele kopeeritava "vana" sõnumi andmeploki. Selle tulemusena kinnitatakse ühele andmeplokile kaks päist ja suurendatakse andmeploki võrdlusloendurit. Kuid see näeb välja nagu kaks sõnumit. Sellise “sotsialiseeritud” andmeplokiga võib sõnumeid olla rohkem, näiteks MS_TEE filter genereerib korraga kümmekond sellist kerget koopiat, jaotades need oma väljundite vahel. Kui kõik ahela filtrid töötavad õigesti, peaks konveieri lõpuks see võrdlusloendur jõudma nullini ja mälu vabastamise funktsioon kutsutakse välja: ms_free(). Kui kõnet ei tule, siis seda mälutükki enam kuhja tagasi ei saa, st. see "lekib". Kergete koopiate kasutamise hind on võime kaotada lihtsalt (nagu tavakoopiate puhul), milline graafikufilter mälu lekib.

Kuna meediumistriimi arendajad vastutavad omafiltrites mälulekke leidmise eest, ei pea te neid tõenäoliselt siluma. Kuid oma käsitööfiltriga olete oma õnne rohutirts ja aeg, mille kulutate koodis lekete otsimisele, sõltub teie täpsusest. Silumisaja vähendamiseks peame filtrite väljatöötamisel vaatama lekke tuvastamise tehnikaid. Lisaks võib juhtuda, et leke avaldub alles siis, kui filtrit rakendatakse reaalses süsteemis, kus “kahtlusaluste” arv võib olla tohutu ja silumisaeg piiratud.

Kuidas mäluleke avaldub?

On loogiline eeldada, et programmi väljundis ülemine näitab teie rakenduse poolt hõivatud mälu suurenevat protsenti.

Väline ilming on see, et mingil hetkel hakkab süsteem aeglaselt reageerima hiire liikumisele ja joonistama aeglaselt ekraani ümber. Samuti on võimalik, et süsteemilogi kasvab, kulutades kõvakettal ruumi. Sel juhul hakkab teie rakendus kummaliselt käituma, ei reageeri käskudele, ei saa faili avada jne.

Lekke tuvastamiseks kasutame mäluanalüsaatorit (edaspidi analüsaator). See võib olla valgrind (hea artikkel selle kohta) või kompilaatorisse sisse ehitatud gcc MemorySanitizer või midagi muud. Kui analüsaator näitab, et ühes graafikufiltris esineb leke, tähendab see, et on aeg rakendada üht allpool kirjeldatud meetoditest.

Kolme männi meetod

Nagu eespool mainitud, osutab analüsaator mälulekke korral filtrile, mis taotles hunnikust mälu eraldamist. Kuid see ei osuta filtrile, mis "unustas" selle tagastada, mis tegelikult on süüdlane. Seega saab analüsaator meie hirme ainult kinnitada, kuid mitte näidata nende juurt.

“Halva” filtri asukoha graafikul väljaselgitamiseks võite graafiku vähendada minimaalse sõlmede arvuni, mille juures analüsaator ikkagi lekke tuvastab, ja lokaliseerida probleemse filtri ülejäänud kolmes männis.

Kuid võib juhtuda, et graafikul olevate filtrite arvu vähendamisega rikute normaalset filtrite ja oma süsteemi teiste elementide vahelise suhtluse kulgu ning leket enam ei ilmne. Sel juhul peate töötama täissuuruses graafikuga ja kasutama allpool kirjeldatud lähenemisviisi.

Lükandisolaatori meetod

Esitamise lihtsuse huvides kasutame graafikut, mis koosneb ühest filtriahelast. Teda on pildil näidatud.

Mediastreamer2 VoIP-mootori uurimine. 12. osa

Tavaline graafik, millel koos valmis meediastriimifiltritega on kasutatud nelja erinevat tüüpi käsitööfiltrit F1...F4, mille oled ammu teinud ja nende õigsuses ei kahtle. Siiski oletame, et mitmel neist on mälulekkeid. Kui käivitame oma programmi analüsaatori jälgimiseks, saame selle aruandest teada, et teatud filter nõudis teatud kogust mälu ega tagastanud seda hunnikusse N korda. Võite kergesti arvata, et seal on link MS_VOID_SOURCE tüüpi sisemiste filtrifunktsioonide juurde. Tema ülesanne on kuhjast mälu võtta. Teised filtrid peavad selle sinna tagasi viima. Need. tuvastame lekke fakti.

Et teha kindlaks, millises torujuhtme osas toimus tegevusetus, mis viis mälulekkeni, tehakse ettepanek võtta kasutusele täiendav filter, mis lihtsalt nihutab sõnumeid sisendist väljundisse, kuid loob samal ajal sisendteatest koopia, mis ei ole hele. , vaid pigem tavaline “raske”, siis kustutab sissepääsul saadud sõnumi täielikult. Me nimetame sellist filtrit isolaatoriks. Usume, et kuna filter on lihtne, pole selles leket. Ja veel üks positiivne omadus – kui me selle kuhugi oma graafikusse lisame, ei mõjuta see vooluringi tööd kuidagi. Filter-isolaatorit kujutame topeltahelaga ringi kujul.

Lülitame isolaatori sisse kohe pärast tühjusallika filtrit:
Mediastreamer2 VoIP-mootori uurimine. 12. osa

Käitame programmi uuesti analüsaatoriga ja näeme, et seekord süüdistab analüsaator isolaatorit. Tema on ju see, kes nüüd loob andmeplokke, mis siis tundmatu hooletu filter (või filtrid) kaotavad. Järgmine samm on liigutada isolaatorit mööda ketti ühe filtri võrra paremale ja alustada analüüsi uuesti. Seega, liigutades isolaatorit samm-sammult paremale, saame olukorra, kus järgmises analüsaatori aruandes “lekkinud” mäluplokkide arv väheneb. See tähendab, et selles etapis oli isolaator ahelas kohe pärast probleemset filtrit. Kui oli ainult üks "halb" filter, siis leke kaob üldse. Seega lokaliseerisime probleemse filtri (või ühe mitmest). Pärast filtri “fikseerimist” saame jätkata isolaatori liigutamist mööda ketti paremale, kuni mälulekked täielikult alistame.

Isolaatorfiltri rakendamine

Isolaatori teostus näeb välja nagu tavaline filter. Päisefail:

/* Файл 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

Filter ise:

/* Файл 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)

Meetod mäluhaldusfunktsioonide asendamiseks

Peenema uurimistöö jaoks annab meediumistriimer võimaluse asendada mälu juurdepääsu funktsioonid enda omadega, mis lisaks põhitööle salvestab “Kes, kus ja miks”. Kolm funktsiooni asendatakse. Seda tehakse järgmiselt.

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);

See funktsioon on abiks juhtudel, kui analüsaator aeglustab filtrite tööd nii palju, et meie vooluringi ehitatud süsteemi töö on häiritud. Sellises olukorras peate analüsaatorist loobuma ja kasutama mäluga töötamiseks funktsioonide asendamist.

Oleme kaalunud toimingute algoritmi lihtsa graafiku jaoks, mis ei sisalda harusid. Kuid seda lähenemist saab rakendada ka muudel juhtudel, muidugi keerulisemalt, kuid idee jääb samaks.

Järgmises artiklis käsitleme tickeri koormuse hindamise küsimust ja viise, kuidas võidelda meediumistriimi liigse arvutuskoormusega.

Allikas: www.habr.com

Lisa kommentaar