Uurime VoIP-mootorit Mediastreamer2. Osa 12

Artikli materjal on saadud minu Dzen-kanalist.

Uurime VoIP-mootorit Mediastreamer2. Osa 12

Eelmisel artiklis, lubasin ma hindama koormuse hinnangut tikkerile ja viise, kuidas vältida ülemäärast arvutuskoormust meediastreameris. Kuid otsustasin, et oleks mõistlikum käsitleda käsitööfilterite tõrkeotsingu küsimusi, mis on seotud andmete liikumisega, ja alles seejärel arutada jõudluse optimeerimise küsimusi.

Käsitööfilterite tõrkeotsing

Pärast seda, kui me eelnevas artiklis käsitlesime andmete liikumismehhanismi meediastreameris, oleks loogiline rääkida varjatud ohtudest. Üks andmevoo printsiibi eripärasid seisneb selles, et mälu eraldamine kuhjast toimub filtrites, mis asuvad andmevoo alguses, ja mälu vabastamine tagasi kuhja toimub filtrites, mis asuvad voolu lõpus. Lisaks sellele võib uute andmete loomine ja nende hävitamine toimuda kuskil vahepealsete punktide juures. Üldiselt vabastab mälu mitte see filter, mis lõi andmeploki.

Ahnuse jälgimise kaudu oleks mõistlik, et filter, saades sisendi ploki, pärast töötlemist kohe hävitaks selle, vabastades mälu, ja väljundina esitaks uue loodud ploki väljundandmetega. Sel juhul oleks filteris mäluleke kergesti jälgitav — kui analüsaator tuvastab leke filtris, tähendab see, et sellele järgnev filter ei hävita saabunud plokke nõuetekohaselt ja viga on temas. Kuid kõrgema jõudluse säilitamise seisukohalt ei ole selline lähenemine andmeplokkidega töötamiseks tõhus — see viib suurte operatsioonide arvu tekkeni, et eraldada/vabastada mälu andmeplokkide jaoks ilma igasuguse kasulikku väljundita.

Seetõttu kasutavad meedia voogedastuse filtrid, et mitte aeglustada andmete töötlemist, sõnumite kopeerimisel funktsioone, mis loovad kergeid koopiaid (oleme sellest rääkinud eelmises artiklis). Need funktsioonid loovad lihtsalt uue sõnumi päise eksemplari, "kinnitades" sellele kopeeritava "vana" sõnumi andmeploki. Tulemuseks on see, et ühe andmeplokiga on seotud kaks päist ja andmeploki viidete loendurit suurendatakse. Kuid see näeb välja nagu kaks sõnumit. Sõnumeid, millel on selline "jagatud" andmeplokk, võib olla ka rohkem, näiteks filter MS_TEE genereerib kohe tosin sellist kerget koopia, jaotades need oma väljundite vahel. Kui kõik filtrid töötlusahelas toimivad õigesti, peab see viidete loendur lõpp-punktiks jõudma nullini ja aktiveeritakse mäluhalduse funktsioon: ms_free(). Kui kutset ei toimu, siis tähendab see, et see mäluosa ei naase kuhugi, st see "lekib". Kergemate koopiaid kasutamise hind on võimaluse kaotus kergesti tuvastada (nagu oleks see tavakoopiate puhul) millises filtris mälulekete probleem toimub.

Kuna vastutus mälulekete leidmise eest "kodufiltrites" lasub meedia voogedastuse arendajatel, peate tõenäoliselt neid ise siluma. Aga oma käsitöölise filtriga — olete te ise oma õnne sepaks ja teie hoolivus määrab aja, mille te veedate lekete leidmisega oma koodis. Teie vaeva lühendamiseks peame uurima leke lokaliseerimise tehnikaid filtrite arendamisel. Samuti võib juhtuda, et leke avaldub alles filtrit reaalses süsteemis rakendades, kus "kahtlaste" arv võib osutuda tohutuks ja silumise aeg piiratud.

Kuidas mäluleke end väljendab?

On mõistlik eeldada, et programmi väljundis top kuvatakse teie rakendust kasutava mäluprotsendi kasvav osakaal.

Väline ilming toimub selles, et mingil hetkel hakkab süsteem aeglaselt reageerima hiire liikumisele, aeglaselt uuendama ekraani. Samuti võib süsteemi logi suureneda, tarbides ruumi kõvakettal. Sellega seoses hakkavad teie rakendused käituma kummaliselt, ei reageeri käskudele, ei suuda avada faile jne.

Kuna tuvastame leke, kasutame mäluanalüsaatorit (edaspidi analüsaator). See võib olla Valgrind (head artikkel sellest) või kompilaatorisse sisseehitatud gcc MemorySanitizer või midagi muud. Kui analüsaator näitab, et leke toimub mõnes graafikfilteris, tähendab see, et on aeg rakendada ühte allpool kirjeldatud meetoditest.

Kolme männi meetod

Kuidas juba eespool mainitud, leke toimub siis, kui analüsaator näitab filtrit, mis soovis mälu eraldamist hunnikust. Kuid see ei näita filtrit, mis "unustas" selle tagasi anda, kes on tegelikult süüdi. Seega võib analüsaator ainult kinnitada meie kahtlusi, kuid mitte näidata nende juuri.

Kuna "halva" filtri asukoha kindlakstegemiseks graafikus võime vähendada graafi minimaalsele sõlmede arvule, mille juures analüsaator ikka veel tuvastab leke, ja jäävatest kolmest männist lokaliseerida probleemne filter.

Kuid võib juhtuda, et filtreid graafikus vähendades rikute tavapärast filtrite interaktsiooni teiste teie süsteemi elementidega ja leke lakkab ilmnema. Sellisel juhul tuleb töötada täissuuruses graafiku ja kasutada lähenemist, mis on allpool kirjeldatud.

Libiseva isolatori meetod

Lihtsuse tõttu kasutame graafi, mis koosneb ühest filtri ahelast. See on illustreeritud joonisel.

Uurime VoIP-mootorit Mediastreamer2. Osa 12

Tavaline graaf, kus koos valmis filtritega meediavoogude jaoks on rakendatud neli käsitsi valmistatud filtrit F1…F4, neljast erinevast tüübist, mille olete kunagi loonud ja mille õigsuses ei kahtle. Siiski eeldame, et mitmes neist on mälu lekkeid. Käivitades meie programmi analüüsija jälgimiseks, saame tema raportist teada, et mingi filter on taotlenud teatud koguse mälu ja ei ole seda tagasi kuhja N-oodatud arv kordi. Kerge on arvata, et viide on filtrite sisemistele funktsioonidele nagu MS_VOID_SOURCE. Selle ülesanne on võtta mälu kuhjast. Teised filtrid peaksid selle sinna tagasi tooma. Sellega avastame lekke olemasolu.

Kuna selgitame välja, millises konveieri osas toimus inaktiivsuse tõttu mälu leke, pakutakse välja täiendava filtri kasutuselevõtt, mis lihtsalt edastab sõnumid sissest väljundisse, kuid samal ajal loob normaalse "raskema" koopia sissetulevast sõnumist, eemaldades seejärel täielikult sissetuleva sõnumi. Nimetame seda filtrit isolatsiooniks. Eeldame, et kuna filter on lihtne, siis lekkeid selles ei esine. Veel üks positiivne omadus on see, et kui lisame selle meie graafikusse ükskõik kuhu, ei mõjuta see skeemi toimimist. Kujutame filtrit-isolatsiooni ringina, millel on topeltkontuur.

Lülitame isolatsiooni sisse kohe pärast filtrit voidsource:
Uurime VoIP-mootorit Mediastreamer2. Osa 12

Käivitame programmi analüsaatoriga uuesti ja näeme, et seekord määrab analüsaator süü isolatsioonile. Lõppude lõpuks, just tema loob andmeblokid, mis seejärel kaovad tundmatule lohakal filtrile (või filtritele). Järgmisel sammul liigutame isolatsiooni ahelas paremale, ühe filtri võrra ja käivitame analüüsi uuesti. Nii, samm-sammult isolatsiooni paremale liikudes, saame olukorra, kui järgmises analüüsi aruandes vähenevad "lekkinud" mälu blokkide arv. See tähendab, et selle sammu käigus asus isolatsioon probleemse filtri järel. Kui "halb" filter oli üks, siis leke kaob täielikult. Nii lokaliseerime probleemse filtri (või ühe mitmest). Pärast filtrisse "parandamist" saame jätkata isolatsiooni paremale liikumist ahelas, kuni mälu leketest on täielik ülekaalus.

Isolatsioonifiltri teostus

Isolaatori teostus näeb välja nagu tavaline filter. Pealkirja fail:

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

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

Mälu juhtimise funktsioonide asendamise meetod

Täiendavateks uuringuteks on meediastreameris võimalik asendada mälu juurdepääsu funktsioonid omaenda funktsioonidega, mis lisaks põhitööle registreerivad "Kes, kuhu ja miks". Asendatakse kolm funktsiooni. Seda teha 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);

Selline võimalus on abiks olukordades, kus analyser vähendab filtrite tööd nii palju, et see rikub süsteemi, kuhu meie skeem on integreeritud. Sellises olukorras tuleb analyysist loobuda ja kasutada mälu töötlemise funktsioonide asendust.

Oleme käsitlenud toimingute algoritmi lihtsa graafi jaoks, mis ei sisalda hargnevaid osi. Kuid seda lähenemist saab rakendada ka muudel juhtudel, muidugi keerukamalt, kuid idee jääb samaks.

Järgmises artiklis käsitleme koormuse hindamise küsimust tickeril ja viise, kuidas vältida ülemäärast arvutuskoormust meediastrimmeris.

Allikas: habr.com

Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster