Mësojmë motorin VoIP Mediastreamer2. Pjesa 12

Materiali i artikujt është marrë nga kanali im Dzen.

Mësojmë motorin VoIP Mediastreamer2. Pjesa 12

Në të kaluarën artikulli ynë, unë premtova të shqyrtoj çështjen e vlerësimit të ngarkesës në ticker dhe mënyrat e luftimit të ngarkesës përtej normalitetit në mediastreamer. Por vendosa se do të ishte më logjike të trajtoheshin çështjet e debugging-ut të filtrave krijues, të lidhura me lëvizjen e të dhënave dhe pastaj të shqyrtoheshin çështjet e optimizimit të performancës.

Debugging i filtrave krijues

Pasi që në artikullin e mëparshëm shqyrtuam mekanizmin e lëvizjes së të dhënave në mediastreamer, do të ishte logjike të flisnim për rreziqet që fshihen në të. Një nga karakteristikat e parimit 'data flow' është se ndanimi i memories nga heap ndodh në filtrat që janë në burimin e rrjedhës së të dhënave, ndërsa çlirimi i memories dhe kthimi në heap realizohet nga filtrat që ndodhen në fund të rrugës së rrjedhës. Përveç kësaj, krijimi i të dhënave të reja dhe shkatërrimi i tyre mund të ndodhin ndokund në pikë të ndërmjetme. Në mënyrë të përgjithshme, çlirimi i memories nuk kryhet nga ai filtrat që krijoi bllokun e të dhënave.

Nga perspectiva e monitorimit të transparencës për memory, do të ishte e arsyeshme që filtri, duke marrë bllokun hyrës, pas përpunimit ta shkatërrojë menjëherë atë duke çliruar memorien dhe në dalje të vendosë bllokun e ri të krijuar me të dhënat e daljes. Në këtë rast, një rrjedhje e memories në filtra do të ishte e lehtë për t'u gjurmuar — nëse analisti zbulojë një rrjedhje në filtrim, do të thotë që filtri i ardhshëm nuk e shkatërron bllokun hyrës siç duhet dhe gabimi është te ai. Por nga perspektiva e ruajtjes së një performancë të lartë, një qasje e tillë në punën me blloket e të dhënave nuk është produktive — ajo çon në një numër të madh operacionesh të ndarjes/çlirimit të memories për blloket e të dhënave pa ndonjë prodhim të dobishëm.

Për këtë arsye, filtrat e mediastream-it, për të mos ngadalësuar procesimin e të dhënave, gjatë kopjimit të mesazheve përdorin funksione që krijojnë kopje të lehta (për to folëm në artikullin e kaluar). Këto funksione thjesht krijojnë një instancë të re të titullit të mesazhit duke "lidhur" me të një bllok të të dhënave nga mesazhi "vjetër" që po kopjohet. Si rezultat, një bllok të dhënash i ngjitur ka dy tituj dhe numri i referencave në bllokun e të dhënave rritet. Por kjo do të duket si dy mesazhe. Mund të ketë më shumë mesazhe me një bllok të dhënash "të përbashkët", për shembull, filtri MS_TEE krijon menjëherë dhjetë të tilla kopje të lehta, duke i shpërndarë ato në daljet e tij. Nëse të gjithë filtrat në zinxhir punojnë siç duhet, në fund të linjës ky numër referencash duhet të arrijë zero dhe do të thirret funksioni për çlirimin e memories: ms_free(). Nëse ky thirrje nuk ndodh, atëherë kjo pjesë memorje nuk do të kthehet më në grumbull, dmth. do të "rrjedhë". Çmimi për përdorimin e kopjeve të lehta është humbja e mundësisë për t'u vendosur lehtë (siç do të ishte në rastin e kopjeve të zakonshme) në cilin filtri grafi po rrjedh memorja.

Pavarësisht nga përgjegjësia për gjetjen e rrjedhjeve të memories në filtrat "origjinalë" që bien në pjesët e mediastream-it, me sa duket nuk do t'ju duhet t'i debugoni ata. Por me filtrin tuaj artizanal - vetë jeni çekiç për fatin tuaj dhe saktësia juaj do të vendosë kohën që do të kaloni në kërkimin e rrjedhjeve në kodin tuaj. Për të shkurtuar kohën tuaj të mundimit me debugimin, ne duhet të shqyrtojmë teknikat e lokalizimit të rrjedhjeve gjatë zhvillimit të filtrave. Gjithashtu, mund të ndodhë që rrjedhja të shfaqet vetëm kur aplikoni filtin në një sistem real, ku numri i "të dyshuarve" mund të jetë kolosal dhe koha për debugim e kufizuar.

Si shfaqet një rrjedhje memorje?

Është logjike të supozohet se në daljen e programit top do të tregojë një përqindje në rritje të memories që zë një aplikacion tuaj.

Shfaqja e jashtme do të përbëhet nga fakti se në një moment sistemi do të fillojë të reagojë ngadalë ndaj lëvizjeve të mausit, do të rifreskojë ekranin ngadalë. Gjithashtu, logu i sistemit mund të rritet, duke konsumuar hapësirë në diskun e harduerit. Në këtë rast, aplikacioni juaj do të fillojë të sillet çuditshëm, nuk do të përgjigjet ndaj komandave, nuk do të mund të hapë skedarë, etj.

Për të zbuluar faktin e ndodhjes së një rrjedhjeje, do të përdorim një analizator memoriesh (më tej analizatori). Kjo mund të jetë Valgrind (i mirë artikulli për të) ose i integruar në kompilator gcc MemorySanitizer apo diçka tjetër. Nëse analizatori tregon se rrjedhja ndodh në një nga filtrat e grafit, atëherë kjo do të thotë se është koha për të aplikuar një nga metodat e përshkruara më poshtë.

Metoda e tre pishave

Siç është thënë më parë, gjatë rrjedhjes së memories, analizatori do të tregojë filtrin që kërkoi ndarjen e memories nga grumbulli. Por nuk do të tregojë filtrin që "harroi" ta kthejë, i cili, në fakt, është fajtori. Me këtë, analizatori mund të konfirmojë vetëm shqetësimet tona, por jo të tregojë rrënjën e tyre.

Për të zbuluar vendndodhjen e filtrit "të keq" në graf, mund të shkojmë përmes reduktimit të grafit në numrin minimal të nyjeve, në të cilat analizatori ende zbulon rrjedhjen dhe në tre pishat e mbetura të lokalizojmë filtrin problematik.

Por mund të ndodhë që duke reduktuar numrin e filtrave në graf, ju do të prisni rregullin e zakonshëm të ndërveprimit të filtrave me elementët e tjerë të sistemit tuaj dhe rrjedhja do të ndalojë së shfaquri. Në këtë rast, do të duhet të punoni me grafikun në përmasat e plota dhe të përdorni qasjen që është paraqitur më poshtë.

Metoda e izoluesit lëvizës

Për thjeshtësi, do të përdorim grafikun që përballet nga një zinxhir filtrash. Ai është paraqitur në figurë.

Mësojmë motorin VoIP Mediastreamer2. Pjesa 12

Një grafik normal, në të cilin së bashku me filtrat e gatshëm të mediastreamer janë aplikuar katër filtrat e krijuar F1…F4, katër lloje të ndryshme që i keni krijuar një kohë më parë dhe në saktësinë e tyre nuk keni dyshime. Megjithatë, le të supozojmë se disa nga ata kanë një rrjedhje memorjeje. Duke e ekzekutuar programin tonë për mbikëqyrjen e analizuesit, nga raporti i tij do të mësojmë se një filtër ka kërkuar një sasi të caktuar memorjeje dhe nuk e ka kthyer atë në grumbull N herë. Është e lehtë të kuptohet se do të ketë një referencë në funksionet e brendshme të filtrit të tipit MS_VOID_SOURCE. Detyra e tij është të marr memorjen nga grumbulli. Të tjerët duhet ta kthejnë atë atje. Pra, ne do të zbulojmë faktin e rrjedhjes.

Për të përcaktuar se në cilën pjesë të linjës së prodhimit ka ndodhur papunësia që ka sjellë rrjedhjen e memorjes, sugjerojmë të shtojmë një filtër shtesë, i cili thjesht transferon mesazhet nga hyrja në daljen, por në të njëjtën kohë krijon një kopje jo të lehtë, në një "kopje të rëndë" normale të mesazhit të hyrjes, duke e fshirë plotësisht mesazhin që ka hyrë. Do ta quajmë këtë filtër izolator. Supozojmë se për shkak se filtri është i thjeshtë, atëherë rrjedhja në të është e përjashtuar. Një tjetër pasuri pozitive është se nëse e shtojmë atë në çdo vend të grafikës sonë, kjo nuk do të ketë ndikim në funksionimin e skemës. Do ta paraqesim filtrin-izolator si një rreth me dy kontura.

E aktivizojmë izolatorin menjëherë pas filtrit voidsource:
Mësojmë motorin VoIP Mediastreamer2. Pjesa 12

Përsëri e ekzekutojmë programin me analizuesin, dhe shohim se këtë herë, analizuesi do të vë fajin te izolatori. Sepse ai tani krijon blloqe të dhënash, të cilat më pas humbasin në mënyrë të panjohur nga një filtër (ose filtra) të pandjeshëm. Hapi tjetër është të lëvizim izolatorin në zinxhir në të djathtë, një filtër dhe përsëri fillojmë analizën. Kështu, duke e lëvizur hap pas hapi izolatorin në të djathtë, do të kemi një situatë, kur në raportin e radhës të analizuesit numri i blloqeve të "rrjedhura" të memorjes do të ulet. Kjo do të thotë se në këtë hap izolatori u vendos në zinxhir menjëherë pas filtrit problematik. Nëse "filtëri i keq" ishte një, atëherë rrjedhja do të zhduket plotësisht. Kështu ne lokalizuam filtrin problematik (ose një nga disa). Pas "riparimit" të filtrit, mund të vazhdojmë të lëvizim izolatorin në të djathtë në zinxhir deri në fitoren e plotë mbi rrjedhjet e memorjes.

Zbatimi i filtrit-izolator

Implementimi i izollatorit duket si një filtër i zakonshëm. Titulli:

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

Filtëri vetë:

/* Файл 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 e zëvendësimit të funksioneve të menaxhimit të memories

Për kërkime më të thella, mediastreameri parashikon mundësinë e zëvendësimit të funksioneve të qasjes në memorie me ato tuaja, të cilat përveç funksionit kryesor do të regjistrojnë "Kush, ku dhe pse". Zëvendësohen tre funksione. Kjo bëhet si më poshtë:

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

Kjo mundësi ndihmon kur analizatori ngadalëson punën e filtrave aq shumë sa që dëmton funksionimin e sistemit në të cilin është e integruar skema jonë. Në një situatë të tillë, është e nevojshme të heqim dorë nga analizatori dhe të përdorim zëvendësimin e funksioneve të punës me memorien.

Ne shqyrtuam algoritmin e veprimeve për një graf të thjeshtë, që nuk përmban degëzime. Por ky qasje mund të aplikohet edhe për raste të tjera, ndoshta me shtesë komplikimesh, por ideja do të mbetet e njëjtë.

Në artikullin që vijon, do të shqyrtojmë çështjen e vlerësimit të ngarkesës në ticker dhe mënyrat e trajtimit të ngarkesës së tepruar të llogaritjes në mediastreamer.

Burimi: habr.com

Blini hosting të besueshëm për faqe interneti me mbrojtje nga DDoS, serverë VPS VDS 🔥 Blini hosting të besueshëm për faqe interneti me mbrojtje nga DDoS, serverë VPS VDS | ProHoster