Raziskovanje mehanizma VoIP Mediastreamer2. 12. del

Gradivo članka je vzeto iz mojega zen kanal.

Raziskovanje mehanizma VoIP Mediastreamer2. 12. del

V preteklosti članek, obljubil sem, da bom preučil vprašanje ocenjevanja obremenitve tickerja in načinov za boj proti čezmerni računalniški obremenitvi v medijskem pretakalniku. Vendar sem se odločil, da bi bilo bolj logično obravnavati vprašanja razhroščevanja obrtnih filtrov, povezanih s premikanjem podatkov, in šele nato obravnavati vprašanja optimizacije delovanja.

Odpravljanje napak v obrtnih filtrih

Potem ko smo v prejšnjem članku pogledali mehanizem premikanja podatkov v medijskem streamerju, bi bilo logično spregovoriti o nevarnostih, ki se skrivajo v njem. Ena od značilnosti načela "pretoka podatkov" je, da se pomnilnik dodeli iz kopice v filtrih, ki se nahajajo na izvoru pretoka podatkov, pomnilnik pa se sprosti in vrne v kopico s filtri, ki se nahajajo na koncu toka. pot. Poleg tega se lahko ustvarjanje novih podatkov in njihovo uničenje zgodi nekje vmes. Na splošno sprostitev pomnilnika izvede drug filter kot tisti, ki je ustvaril podatkovni blok.

Z vidika transparentnega spremljanja pomnilnika bi bilo smiselno, da bi filter, ko prejme vhodni blok, le-tega po obdelavi takoj uničil, sprostil pomnilnik in izpisal novonastali blok z izhodnimi podatki. V tem primeru bi zlahka izsledili puščanje pomnilnika v filtru - če bi analizator zaznal puščanje v filtru, potem naslednji filter ne uniči pravilno dohodnih blokov in je v njem napaka. Toda z vidika ohranjanja visoke zmogljivosti ta pristop k delu s podatkovnimi bloki ni produktiven - vodi do velikega števila operacij za dodelitev/sprostitev pomnilnika za podatkovne bloke brez kakršnega koli uporabnega rezultata.

Zato filtri media streamer, da ne bi upočasnili obdelave podatkov, pri kopiranju sporočil uporabljajo funkcije, ki ustvarjajo preproste kopije (o njih smo govorili v prejšnjem članku). Te funkcije samo ustvarijo nov primerek glave sporočila tako, da mu "priložijo" blok podatkov iz "starega" sporočila, ki se kopira. Posledično sta dve glavi pripeti na en podatkovni blok in referenčni števec v podatkovnem bloku se poveča. Vendar bo videti kot dve sporočili. S takšnim "socializiranim" podatkovnim blokom je lahko več sporočil, na primer filter MS_TEE ustvari ducat takšnih lahkih kopij hkrati in jih razdeli med svoje izhode. Če vsi filtri v verigi delujejo pravilno, mora ta referenčni števec do konca cevovoda doseči nič in poklicana bo funkcija za sprostitev pomnilnika: ms_free(). Če do klica ne pride, ta kos pomnilnika ne bo več vrnjen v kopico, tj. bo "puščalo". Cena za uporabo lahkih kopij je izguba zmožnosti enostavnega ugotavljanja (kot bi bilo v primeru navadnih kopij), kateri filter grafa pušča pomnilnik.

Ker so razvijalci medijskih programov za pretakanje odgovorni za iskanje uhajanja pomnilnika v izvornih filtrih, vam jih najverjetneje ne bo treba odpravljati. Toda s svojim craft filtrom ste sami kobilica svoje sreče in čas, ki ga boste porabili za iskanje puščanj v kodi, bo odvisen od vaše natančnosti. Da bi skrajšali vaš čas odpravljanja napak, moramo pri razvoju filtrov upoštevati tehnike odkrivanja puščanja. Poleg tega se lahko zgodi, da se bo puščanje pokazalo šele, ko bo filter uporabljen v resničnem sistemu, kjer je lahko število "osumljencev" ogromno in čas za odpravljanje napak omejen.

Kako se odraža uhajanje spomina?

Logično je domnevati, da v izhodu programa vrh bo prikazal vse večji odstotek pomnilnika, ki ga zaseda vaša aplikacija.

Zunanja manifestacija bo, da se bo sistem na neki točki začel počasi odzivati ​​na premikanje miške in počasi prerisovati zaslon. Možno je tudi, da se sistemski dnevnik poveča in zavzame prostor na vašem trdem disku. V tem primeru se bo vaša aplikacija začela nenavadno obnašati, ne bo se odzivala na ukaze, ne bo mogla odpreti datoteke itd.

Za odkrivanje pojava puščanja bomo uporabili analizator pomnilnika (v nadaljevanju analizator). Lahko bi bilo valgrind (dobro članek o tem) ali vgrajen v prevajalnik GCC Memory Sanitizer ali karkoli drugega. Če analizator pokaže, da pride do puščanja v enem od filtrov grafa, to pomeni, da je čas, da uporabite eno od spodaj opisanih metod.

Metoda treh borov

Kot je navedeno zgoraj, bo analizator pokazal na filter, ki je zahteval dodelitev pomnilnika iz kopice, če pride do uhajanja pomnilnika. Ne bo pa opozoril na filter, ki ga je »pozabil« vrniti, kar je pravzaprav krivec. Tako lahko analizator le potrdi naše strahove, ne pa tudi pokaže njihove korenine.

Če želite izvedeti lokacijo "slabega" filtra na grafu, lahko zmanjšate graf na najmanjše število vozlišč, pri katerih analizator še vedno zazna puščanje, in lokalizirajte problematični filter v preostalih treh pinih.

Lahko pa se zgodi, da boste z zmanjšanjem števila filtrov v grafu zmotili normalen potek interakcije med filtri in drugimi elementi vašega sistema in se puščanje ne bo več pojavljalo. V tem primeru boste morali delati z grafom polne velikosti in uporabiti spodaj opisan pristop.

Metoda drsnega izolatorja

Za lažjo predstavo bomo uporabili graf, ki je sestavljen iz ene verige filtrov. Prikazana je na sliki.

Raziskovanje mehanizma VoIP Mediastreamer2. 12. del

Običajni graf, v katerem so poleg že pripravljenih medijskih strimer filtrov uporabljeni štirje craft filtri F1...F4, štirih različnih tipov, ki ste jih izdelali že zdavnaj in ne dvomite v njihovo pravilnost. Vendar predpostavimo, da več od njih pušča pomnilnik. Ko zaženemo naš program za spremljanje analizatorja, iz njegovega poročila izvemo, da je določen filter zahteval določeno količino pomnilnika in ga ni N-krat vrnil v kopico. Zlahka lahko uganete, da bo obstajala povezava do funkcij notranjega filtra tipa MS_VOID_SOURCE. Njegova naloga je vzeti spomin s kupa. Drugi filtri ga morajo vrniti tja. Tisti. odkrili bomo dejstvo puščanja.

Da bi ugotovili, v katerem odseku cevovoda je prišlo do nedejavnosti, ki je povzročila uhajanje pomnilnika, se predlaga uvedba dodatnega filtra, ki preprosto premakne sporočila z vhoda na izhod, hkrati pa ustvari kopijo vhodnega sporočila, ki ni svetloba. , ampak običajno "težko", nato pa popolnoma izbriše sporočilo, prejeto ob vstopu. Tak filter bomo imenovali izolator. Verjamemo, da ker je filter preprost, v njem ne pušča. In še ena pozitivna lastnost - če jo dodamo kjerkoli v našem grafu, to nikakor ne bo vplivalo na delovanje vezja. Filter-izolator bomo prikazali v obliki kroga z dvojnim krogom.

Izolator vklopimo takoj za filtrom voidsource:
Raziskovanje mehanizma VoIP Mediastreamer2. 12. del

Ponovno zaženemo program z analizatorjem in vidimo, da bo analizator tokrat krivil izolator. Navsezadnje je on tisti, ki zdaj ustvarja bloke podatkov, ki jih nato neznani neprevidni filter (ali filtri) izgubi. Naslednji korak je premakniti izolator vzdolž verige v desno, za en filter, in ponovno začeti analizo. Torej, korak za korakom premikanje izolatorja v desno, bomo dobili situacijo, ko se bo v naslednjem poročilu analizatorja število "uhajajočih" pomnilniških blokov zmanjšalo. To pomeni, da je bil v tem koraku izolator v verigi takoj za težavnim filtrom. Če je bil samo en "slab" filter, bo puščanje popolnoma izginilo. Tako smo lokalizirali problematični filter (ali enega od več). Ko "popravimo" filter, lahko nadaljujemo s premikanjem izolatorja v desno vzdolž verige, dokler popolnoma ne premagamo puščanja spomina.

Izvedba izolacijskega filtra

Izvedba izolatorja izgleda tako kot običajni filter. Datoteka glave:

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

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

Metoda za zamenjavo funkcij za upravljanje pomnilnika

Za bolj subtilne raziskave medijski streamer omogoča zamenjavo funkcij dostopa do pomnilnika z lastnimi, ki bodo poleg glavnega dela zabeležile "Kdo, kje in zakaj". Zamenjane so tri funkcije. To se naredi na naslednji način:

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

Ta funkcija pomaga v primerih, ko analizator tako upočasni delovanje filtrov, da je moteno delovanje sistema, v katerega je vgrajeno naše vezje. V takšni situaciji morate opustiti analizator in uporabiti zamenjavo funkcij za delo s pomnilnikom.

Upoštevali smo algoritem dejanj za preprost graf, ki ne vsebuje vej. Toda ta pristop je mogoče uporabiti tudi v drugih primerih, seveda z večjo kompleksnostjo, vendar ideja ostaja enaka.

V naslednjem članku si bomo ogledali vprašanje ocenjevanja obremenitve tickerja in načine za boj proti čezmerni računalniški obremenitvi v medijskem pretakalniku.

Vir: www.habr.com

Dodaj komentar