Istraživanje Mediastreamer2 VoIP motora. Dio 12

Materijal članka je preuzet sa mog zen kanal.

Istraživanje Mediastreamer2 VoIP motora. Dio 12

U poslednjem članak, obećao sam da ću razmotriti pitanje procjene opterećenja tikera i načina rješavanja prevelikog opterećenja računara u medijskom streameru. Ali odlučio sam da bi bilo logičnije pokriti pitanja otklanjanja grešaka u craft filterima koji se odnose na kretanje podataka i tek onda razmotriti probleme optimizacije performansi.

Otklanjanje grešaka u craft filterima

Nakon što smo u prethodnom članku ispitali mehanizam kretanja podataka u medijskom streameru, logično bi bilo govoriti o opasnostima koje se kriju u njemu. Jedna od karakteristika principa "protoka podataka" je da se dodjela memorije iz hrpe događa u filterima koji se nalaze na izvorima toka podataka, a filteri koji se nalaze na kraju putanje toka već oslobađaju memoriju s povratkom na gomilu. Osim toga, stvaranje novih podataka i njihovo uništavanje može se dogoditi negdje u međutačkama. Općenito, oslobađanje memorije se vrši pomoću filtera koji nije onaj koji je kreirao blok podataka.

Sa stanovišta transparentnog praćenja memorije, bilo bi razumno da filter prilikom prijema ulaznog bloka odmah uništi isti nakon obrade, oslobađa memoriju, a na izlaz stavi novostvoreni blok sa izlaznim podacima. U ovom slučaju, curenje memorije u filteru bi se moglo lako ući u trag — ako je analizator otkrio curenje u filteru, onda filter koji ga prati ne uništava pravilno dolazne blokove i postoji greška u njemu. Ali sa stanovišta održavanja visokih performansi, ovaj pristup radu s blokovima podataka nije produktivan - dovodi do velikog broja operacija za dodjelu / oslobađanje memorije za blokove podataka bez ikakvog korisnog iscrpljivanja.

Iz tog razloga, filteri media streamera, kako ne bi usporavali obradu podataka, prilikom kopiranja poruka koriste funkcije koje kreiraju lagane kopije (o njima smo govorili u prethodnom članku). Ove funkcije samo kreiraju novu kopiju zaglavlja poruke tako što "prikače" blok podataka iz kopirane "stare" poruke na njega. Kao rezultat, dva zaglavlja su pripojena jednom bloku podataka i referentni brojač u bloku podataka se povećava. Ali to će izgledati kao dvije poruke. Može biti više poruka sa takvim "javnim" blokom podataka, na primjer, MS_TEE filter generiše deset takvih svijetlih kopija odjednom, distribuirajući ih među svojim izlazima. Ako svi filteri u lancu rade ispravno, do kraja cjevovoda ovaj broj referenci bi trebao dostići nulu i funkcija oslobađanja memorije će biti pozvana: ms_free(). Ako se poziv ne dogodi, tada se ovaj dio memorije više neće vraćati u hrpu, tj. on "cure". Cijena korištenja lakih kopija je gubitak mogućnosti lakog određivanja (kao što bi bilo u slučaju korištenja običnih kopija) u kojem grafskom filteru curi memorija.

Budući da odgovornost za pronalaženje curenja memorije u "nativnim" filterima leži na programerima medijskog streamera, najvjerovatnije nećete morati da ih otklanjate. Ali s vašim filterom za izradu, vi ste sami skakavac svoje sreće, a vrijeme koje provedete tražeći curenje u vašem kodu ovisit će o vašoj točnosti. Da bismo skratili vaše vrijeme za otklanjanje grešaka, moramo razmotriti tehnike lokalizacije curenja prilikom dizajniranja filtera. Osim toga, može se desiti da će se curenje manifestirati samo prilikom primjene filtera u stvarnom sistemu, gdje broj "osumnjičenih" može biti ogroman, a vrijeme za otklanjanje grešaka ograničeno.

Kako se manifestuje curenje memorije?

Logično je pretpostaviti da u izlazu programa vrh će pokazati sve veći postotak memorije koju zauzima vaša aplikacija.

Spoljna manifestacija će se sastojati u činjenici da će u nekom trenutku sistem polako reagovati na kretanje miša, polako precrtavajući ekran. Takođe je moguće da će sistemski dnevnik rasti i zauzeti prostor na čvrstom disku. U tom slučaju, vaša aplikacija će se početi čudno ponašati, neće odgovarati na komande, ne može otvoriti datoteku itd.

Da bismo identifikovali činjenicu curenja, koristićemo analizator memorije (u daljem tekstu analizator). To može biti valgrind (dobro članak o tome) ili ugrađen u kompajler gcc MemorySanitizer ili nešto drugo. Ako analizator pokaže da se curenje javlja u jednom od filtara grafa, to znači da je vrijeme da se primijeni jedna od metoda opisanih u nastavku.

Metoda tri bora

Kao što je gore spomenuto, u slučaju curenja memorije, analizator će pokazati na filter koji je zatražio dodjelu memorije iz hrpe. Ali neće ukazati na filter koji je "zaboravio" da ga vrati, a što je, zapravo, krivo. Dakle, analizator može samo potvrditi naše strahove, ali ne i ukazati na njihov korijen.

Da biste saznali lokaciju "lošeg" filtera na grafu, možete ići tako da smanjite graf na minimalni broj čvorova na kojima analizator još uvijek otkriva curenje i locira problematični filter u preostala tri bora.

Ali može se dogoditi da smanjenjem broja filtera u koloni poremetite normalan tok interakcije između filtera i drugih elemenata vašeg sistema i curenje se više neće pojavljivati. U ovom slučaju, morat ćete raditi s grafom pune veličine i koristiti pristup opisan u nastavku.

Metoda kliznog izolatora

Radi jednostavnosti prezentacije koristićemo graf koji se sastoji od jednog lanca filtera. Ona je prikazana na slici.

Istraživanje Mediastreamer2 VoIP motora. Dio 12

Običan grafikon, u kojem se uz gotove media streamer filtere koriste četiri craft filtera F1…F4, četiri različita tipa koje ste davno napravili i ne sumnjate u njihovu ispravnost. Međutim, pretpostavimo da nekoliko njih ima curenje memorije. Prilikom pokretanja našeg programa za nadzor analizatora, saznajemo iz njegovog izvještaja da je određeni filter zahtijevao određenu količinu memorije i da je nije vratio u hrpu N puta. Lako je pretpostaviti da će postojati referenca na funkcije internog filtera tipa MS_VOID_SOURCE. Njegov zadatak je da uzme memoriju sa gomile. Ostali filteri bi ga trebali vratiti tamo. One. naći ćemo curenje.

Kako bi se utvrdilo na kojoj se dionici cjevovoda dogodila neaktivnost koja je dovela do curenja memorije, predlaže se uvođenje dodatnog filtera koji jednostavno prebacuje poruke sa ulaza na izlaz, ali istovremeno stvara nesvjetlu, normalnu "teška" kopija ulazne poruke, a zatim potpuno brisanje poruke koja je stigla na izlazni ulaz. Takav filter ćemo nazvati izolatorom. Smatramo da, budući da je filter jednostavan, curenje u njemu je isključeno. I još jedno pozitivno svojstvo - ako ga dodamo na bilo koje mjesto u našem grafu, onda to ni na koji način neće utjecati na rad kruga. Filter izolatora ćemo prikazati kao krug sa dvostrukom konturom.

Omogućite izolator odmah nakon filtera voidsourse:
Istraživanje Mediastreamer2 VoIP motora. Dio 12

Ponovo pokrećemo program sa analizatorom i vidimo da će ovaj put analizator okriviti izolator. Na kraju krajeva, on je taj koji sada stvara blokove podataka, koji su potom izgubljeni od strane nepoznatog nemarnog filtera (ili filtera). Sljedeći korak je pomicanje izolatora duž lanca udesno, za jedan filter, i ponovno pokretanje analize. Dakle, korak po korak, pomjerajući izolator udesno, dolazimo do situacije kada se broj "procurelih" memorijskih blokova u sljedećem izvještaju analizatora smanjuje. To znači da je u ovom koraku izolator završio u lancu odmah nakon problematičnog filtera. Ako je postojao samo jedan "loš" filter, curenje će potpuno nestati. Tako smo lokalizirali problematični filter (ili jedan od nekoliko). Nakon što smo "popravili" filter, možemo nastaviti pomicati izolator udesno duž lanca dok se curenje memorije potpuno ne eliminira.

Implementacija izolatorskog filtera

Implementacija izolatora izgleda baš kao normalan filter. Fajl zaglavlja:

/* Файл 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 zamjene funkcija upravljanja memorijom

Za suptilnije istraživanje, medijski streamer pruža mogućnost zamjene funkcija pristupa memoriji vlastitim, što će, pored glavnog posla, popraviti "Ko, gdje i zašto". Tri funkcije se zamjenjuju. To se radi na sljedeći 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);

Ova karakteristika dolazi u pomoć u slučajevima kada analizator toliko uspori filtere da je poremećen rad sistema u kojem je ugrađeno naše kolo. U takvoj situaciji morate napustiti analizator i koristiti zamjenu memorijskih funkcija.

Razmotrili smo algoritam radnji za jednostavan graf koji ne sadrži grane. Ali ovaj pristup se može primijeniti i na druge slučajeve, naravno uz komplikacije, ali ideja ostaje ista.

U sljedećem članku ćemo se osvrnuti na pitanje procjene opterećenja tikera i kako se nositi s prekomjernim opterećenjem računara u media streameru.

izvor: www.habr.com

Dodajte komentar