Uurime VoIP moodulit Mediastreamer2. Osa 12

Artikli sisu on pärit minu zen-kanalist.

Uurime VoIP moodulit Mediastreamer2. Osa 12

Eelmises osas artiklis, lubasin, uurisin ko koormuse hindamise ja ülemäärase arvutuskoormuse käsitlemise küsimusi meedia voogesitajas. Otsustasin, et oleks mõistlik arutada käsitööfilterite silumist, mis puudutab andmete liikumist, ning seejärel käsitleda jõudluse optimeerimise küsimusi.

Käsitööfilterite silumine

Pärast seda, kui me eelmisel artiklis käsitlesime andmete ülekande mehhanismi meedia voogesitajas, oleks mõistlik rääkida sellega kaasnevatest ohtudest. Üks "andmevoo" põhiprintsiipe on see, et mälu eraldamine hunnikust toimub filterites, mis asuvad andmevoo alguses, ning mälu vabastamine toimub juba filterite poolt, mis asuvad voolu lõpus. Lisaks võivad uute andmete loomine ja nende hävitamine toimuda kuskil vahepealsetes punktides. Üldiselt vabastab mälu mitte see filter, mis andmeploki lõi.

Lähenedes mälu läbipaistvale jälgimisele, oleks mõistlik, et filter, kui ta saab sisendi ploki, hävitaks selle kohe pärast töötlemist, vabastades mälu, ja kuvaks seejärel välja loodud ploki väljundandmetega. Sel juhul oleks mäluleke filtris kergesti jälgitav — kui analüsaator tuvastab filtris mälulekke, tähendab see, et järgmine filter ei hävita sisenevaid plokke õigesti ja probleem on temas. Kuid kõrge jõudluse säilitamise seisukohalt pole selline lähenemine andmeplokkide töötlemiseks tootlik — see toob kaasa suure hulga operatsioone mälu eraldamise/ vabastamise jaoks andmeplokkide jaoks, ilma igasuguse kasuliku väljundita.

Seetõttu kasutavad meedia voogesituse filtrid andmesõnumite kopeerimist süüdistavate kergete koopiate loomise funktsioone (mille kohta rääkisime eelmisel artiklil). Need funktsioonid loovad lihtsalt uue sõnumi päise eksemplari, "sidudes" selle andmeploki kopeeritavast "vanast" sõnumist. Tulemuseks on, et ühe andmeplokiga on seotud kaks päist ja andmeploki viidete arvu suurenemine. Kuid see näeb välja nagu kaks sõnumit. Selliste "jagatud" andmeplokkidega sõnumeid võib olla rohkem — näiteks filter MS_TEE loob kohe kümmekond sellist kerget koopiat, jaotades need oma väljunditele. Kui kõik filtrid lõngas töötavad õigesti, siis peab viidete arvu langema nullini ja vabastamise funktsioon tuleb välja kutsuda: ms_free(). Kui kutsumist ei toimu, tähendab see, et see mäluplokk ei naase enam hunnikusse, st see "lekib". Kergete koopiate kasutamise hind on see, et kaotatakse võimalus hõlpsasti kindlaks teha (nagu see oleks tavaliste koopiate kasutamisel), millises grafis filter lekib mälu.

Kuna vastutus mälulekkete leidmise eest "looduslikes" filtrites lasub meedia voogesitaja arendajatel, ei pruugi te neid siluda. Kuid oma käsitööfiltri puhul — olete ise oma õnne sepistaja ja teie ettevaatlikkus sõltub ajast, mille te oma koodi lekete otsimisele kulutate. Aja säästmiseks silumisega peame uurima lekete lokaliseerimise tehnikaid filtrite arendamisel. Samuti võib juhtuda, et leak ilmneb alles siis, kui filter kasutusele võtta reaalses süsteemis, kus "kahtlaste" arv võib olla tohutu ja silumisaeg piiratud.

Kuidas mäluleke välja paistab?

On loogiline eeldada, et programmi väljundis top kuvatakse teie rakenduse kasutatav mälu protsent, mis kasvab.

Väline ilming on see, et mingil hetkel hakkab süsteem hiire liikumisele aeglaselt reageerima, ekraani aeglaselt ümber joonistama. Samuti võib süsteemi logi suureneda, söödes ruumi kõvakettal. Sel ajal hakkab teie rakendus käituma kummaliselt, mitte vastama käskudele, ei suuda faile avada jne.

Mälulekke esinemise tuvastamiseks kasutame mäluanalüsaatorit (edasiantud analüsaator). See võib olla Valgrind (hea artikkel temast) või kogumisse sisseehitatud gcc MemorySanitizer või midagi muud. Kui analüsaator näitab, et leak toimub ühe grafi filtris, siis see tähendab, et on aeg rakendada ühte allpool kirjeldatud meetodeid.

Kolme männi meetod

Nagu juba eespool mainitud, näitab mälulekke korral analüsaator filtrit, mis küsis mälu eraldamist kuhjast. Kuid see ei näita filtrit, mis "unustas" selle tagasi anda, mis on tegelikult probleemne. Seetõttu suudab analüsaator ainult kinnitada meie kahtlusi, kuid mitte näidata nende juurt.

Et selgitada välja "halva" filtri asukoht graafikus, saab läheneda graafi vähendamise teele miinimumarvuni sõlmede, kus analüsaator siiski tuvastab leke, ja jätta kolme puu sisse probleemne filter lokaliseerimiseks.

Kuid võib juhtuda, et filtreid graafis vähendades rikute filtrite tavapärast suhtlemist teiste teie süsteemi elementidega ja leke ei pruugi enam ilmneda. Sel juhul tuleb töötada täiskohaga graafi ja kasutada allpool kirjeldatud lähenemist.

Libiseva isolaatori meetod

Lihtsuse huvides kasutan graafi, mis koosneb ainsast filtri ahelast. See on joonisel kujutatud.

Uurime VoIP moodulit Mediastreamer2. Osa 12

Tavaline graaf, milles koos valmis filtritega media streameri juures on neli käsitööfiltrit F1…F4, neljast erinevast tüübist, mille olete ammu teinud ja mille õigsuses ei kahtle. Siiski oletame, et mõned neist sisaldavad mäluleket. Käivitades meie programmi analüsaatoriga, saame tema raportist teada, et mingi filter küsis teatud hulga mälu ja ei tagastanud seda kuhja N korda. Kergesti võib oletada, et viide on filtreerivate funktsioonide internele tüübile MS_VOID_SOURCE. Selle ülesanne on mälu kuhjast ära võtta. Tagastama peaksid seda teised filtrid. See tähendab, et me tuvastame leke olemasolu.

Et määrata, kus konveieril toimus tegevusetus, mis viis mälulekkele, soovitatakse lisada täiendav filter, mis lihtsalt edastab sõnumid sisendilt väljundile, kuid samal ajal loob mitte kerge, vaid tavapärase "raske" koopia sisendsõnumist, seejärel täielikult kustutades sisendile jõudnud sõnumi. Sellist filtrit nimetame isolaatoriks. Arvame, et kuna filter on lihtne, on leke selles välistatud. Veel üks positiivne omadus on see, et kui me lisame selle meie graafi mis tahes kohta, ei mõjuta see skeemi toimimist. Kujutame isolaatorifiltri kahe ringiga ringina.

Lülitame isolaatori sisse kohe pärast voidsource filtri:
Uurime VoIP moodulit Mediastreamer2. Osa 12

Käivitame programmi taas analüsaatoriga ning näeme, et seekord kuulutab analüsaator süüdlaseks isolaatori. Lõppude lõpuks loob just tema nüüd andmeplokke, mis kaovad tundmatu hooletu filtri (või filtrite) tõttu. Järgmise sammuna liigutame isolaatorit ahelas ühe filtri võrra edasi ja käivitame analüüsi uuesti. Nii, samm-sammult isolaatorit paremale liikudes, saame olukorra, kus analüsaatori järgmises raportis "lekkinud" mälublokkide arv väheneb. See tähendab, et sellel sammul sattus isolaator ahelas kohe pärast probleemset filtrit. Kui "halb" filter oli ainus, siis võib leke täiesti kaduda. Nii oleme lokaliseerinud probleemse filtri (või ühe mitmest). "Korrigeerides" filtrit, saame jätkata isolaatori liigutamist paremale ahelas, kuni saavutame mälulekke täieliku lõpetamise.

Isolaatorifiltri rakendamine

Isolaatori rakendamine näeb välja nagu tavaline filter. Pealkirjafail:

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

Ise 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 juhtfunktsioonide asendamise meetod

Peenemate uuringute jaoks on meediumi streamerisse ette nähtud võimalus asendada mälufunktsioone teie omadest, mis lisaks põhifunktsioonile fikseerivad "Kes, kuhu ja miks". Kolme funktsiooni asemel. 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);

Selline võimalus aitab olukordades, kus analüsaator aeglustab filtrite tööd nii palju, et häirib süsteemi tööd, kuhu meie skeem on integreeritud. Sellises olukorras tuleb loobuda analüsaatorist ja kasutada mälufunktsioonide asendust.

Olemas oleme kaalunud toimingute algoritmi lihtsa graafi jaoks, mis ei sisalda hargnemisi. Kuid seda lähenemist saab rakendada ka muude juhtumite jaoks, muidugi koos keerukuse suurendamisega, kuid idee jääb samaks.

Järgmises artiklis käsitleme koormuse hindamist tikkeril ja viise üleliigse arvutuskoormuse vähendamiseks meediastreameris.

Allikas: habr.com

Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster