Eksplorimi i motorit VoIP Mediastreamer2. Pjesa 12

Materiali i artikullit është marrë nga ime kanal zen.

Eksplorimi i motorit VoIP Mediastreamer2. Pjesa 12

Në të fundit artikull, Unë premtova të shqyrtoj çështjen e vlerësimit të ngarkesës në tiker dhe mënyrat për të luftuar ngarkesën e tepërt të llogaritjes në transmetuesin e medias. Por vendosa që do të ishte më logjike të mbuloja çështjet e korrigjimit të filtrave artizanale që lidhen me lëvizjen e të dhënave dhe vetëm atëherë të shqyrtoja çështjet e optimizimit të performancës.

Korrigjimi i filtrave artizanal

Pasi shikuam mekanizmin e lëvizjes së të dhënave në një transmetues mediatik në artikullin e mëparshëm, do të ishte logjike të flasim për rreziqet që fshihen në të. Një nga tiparet e parimit të "rrjedhës së të dhënave" është se memoria shpërndahet nga grumbulli në filtrat që ndodhen në burimin e rrjedhës së të dhënave, dhe kujtesa çlirohet dhe kthehet në grumbull nga filtrat e vendosur në fund të rrjedhës. rrugë. Përveç kësaj, krijimi i të dhënave të reja dhe shkatërrimi i tyre mund të ndodhë diku në mes. Në përgjithësi, lirimi i memories kryhet nga një filtër i ndryshëm nga ai që krijoi bllokun e të dhënave.

Nga pikëpamja e monitorimit transparent të memories, do të ishte e arsyeshme që filtri, me marrjen e një blloku hyrës, ta shkatërronte menjëherë pas përpunimit, duke çliruar memorien dhe të nxirrte një bllok të sapokrijuar me të dhëna dalëse. Në këtë rast, një rrjedhje memorie në filtër do të gjurmohej lehtësisht - nëse analizuesi zbuloi një rrjedhje në filtër, atëherë filtri tjetër nuk shkatërron blloqet hyrëse siç duhet dhe ka një gabim në të. Por nga pikëpamja e ruajtjes së performancës së lartë, kjo qasje për të punuar me blloqet e të dhënave nuk është produktive - ajo çon në një numër të madh operacionesh për ndarjen/lirimin e memories për blloqet e të dhënave pa ndonjë dalje të dobishme.

Për këtë arsye, filtrat e transmetimit të mediave, për të mos ngadalësuar përpunimin e të dhënave, përdorin funksione që krijojnë kopje të lehta gjatë kopjimit të mesazheve (për to folëm në artikullin e mëparshëm). Këto funksione krijojnë vetëm një shembull të ri të kokës së mesazhit duke "bashkëngjitur" asaj një bllok të dhënash nga mesazhi "i vjetër" që po kopjohet. Si rezultat, dy tituj janë bashkangjitur në një bllok të dhënash dhe numëruesi i referencës në bllokun e të dhënave rritet. Por do të duket si dy mesazhe. Mund të ketë më shumë mesazhe me një bllok të tillë të "socializuar" të të dhënave, për shembull, filtri MS_TEE gjeneron një duzinë kopjesh të tilla të lehta menjëherë, duke i shpërndarë ato midis daljeve të tij. Nëse të gjithë filtrat në zinxhir funksionojnë si duhet, deri në fund të tubacionit ky numërues referencë duhet të arrijë zero dhe funksioni i lëshimit të memories do të thirret: ms_free(). Nëse thirrja nuk ndodh, atëherë kjo pjesë e memories nuk do të kthehet më në grumbull, d.m.th. do të "rrjedh". Çmimi për përdorimin e kopjeve të lehta është humbja e aftësisë për të përcaktuar lehtësisht (siç do të ishte rasti me kopjet e zakonshme) se cili filtër grafik po rrjedh memorie.

Meqenëse zhvilluesit e transmetuesit të medias janë përgjegjës për gjetjen e rrjedhjeve të kujtesës në filtrat vendas, me shumë mundësi nuk do t'ju duhet t'i korrigjoni ato. Por me filtrin tuaj artizanal, ju jeni karkaleca e lumturisë suaj dhe koha që kaloni duke kërkuar për rrjedhje në kodin tuaj do të varet nga saktësia juaj. Për të reduktuar kohën tuaj të korrigjimit, duhet të shikojmë teknikat e zbulimit të rrjedhjeve kur zhvillojmë filtra. Për më tepër, mund të ndodhë që rrjedhja të shfaqet vetëm kur filtri të aplikohet në një sistem real, ku numri i "të dyshuarve" mund të jetë i madh dhe koha për korrigjimin e kufizuar.

Si shfaqet një rrjedhje e kujtesës?

Është logjike të supozohet se në daljen e programit më i lartë do të tregojë përqindjen në rritje të memories së zënë nga aplikacioni juaj.

Manifestimi i jashtëm do të jetë që në një moment sistemi do të fillojë t'i përgjigjet ngadalë lëvizjes së miut dhe ngadalë të rivizatojë ekranin. Është gjithashtu e mundur që regjistri i sistemit të rritet, duke ngrënë hapësirë ​​në hard diskun tuaj. Në këtë rast, aplikacioni juaj do të fillojë të sillet në mënyrë të çuditshme, të mos përgjigjet ndaj komandave, të mos hapë një skedar, etj.

Për të zbuluar shfaqjen e një rrjedhjeje, ne do të përdorim një analizues memorie (në tekstin e mëtejmë referuar si analizues). Mund te jete valgrind (mirë artikull rreth tij) ose të integruar në përpilues gcc Dezinfektues i kujtesës apo ndonjë gjë tjetër. Nëse analizuesi tregon se një rrjedhje ndodh në një nga filtrat e grafikut, 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ç u përmend më lart, nëse ka një rrjedhje memorie, analizuesi do të tregojë filtrin që kërkoi ndarjen e memories nga grumbulli. Por nuk do të vërë në dukje filtrin që “harroi” ta kthejë, që në fakt është fajtori. Kështu, analizuesi mund të konfirmojë vetëm frikën tonë, por jo të tregojë rrënjën e tyre.

Për të zbuluar vendndodhjen e filtrit "të keq" në grafik, mund të shkoni duke e zvogëluar grafikun në numrin minimal të nyjeve në të cilat analizuesi ende zbulon një rrjedhje dhe të lokalizojë filtrin problematik në tre pishat e mbetura.

Por mund të ndodhë që duke zvogëluar numrin e filtrave në grafik, do të prishni rrjedhën normale të ndërveprimit midis filtrave dhe elementëve të tjerë të sistemit tuaj dhe rrjedhja nuk do të shfaqet më. Në këtë rast, do t'ju duhet të punoni me një grafik me madhësi të plotë dhe të përdorni qasjen e përshkruar më poshtë.

Metoda e izolatorit rrëshqitës

Për thjeshtësi të paraqitjes, ne do të përdorim një grafik që përbëhet nga një zinxhir filtrash. Ajo shfaqet në foto.

Eksplorimi i motorit VoIP Mediastreamer2. Pjesa 12

Një grafik i rregullt në të cilin, krahas filtrave të gatshëm të media streamer, përdoren edhe katër filtra craft F1...F4, të katër llojeve të ndryshme, të cilat i keni bërë shumë kohë më parë dhe nuk keni asnjë dyshim për korrektësinë e tyre. Megjithatë, le të supozojmë se disa prej tyre kanë rrjedhje memorie. Duke ekzekutuar programin tonë për të monitoruar analizuesin, mësojmë nga raporti i tij se një filtër i caktuar kërkoi një sasi të caktuar memorie dhe nuk e ktheu atë në grumbullin N numër herë. Mund të merrni me mend lehtësisht se do të ketë një lidhje me funksionet e filtrit të brendshëm të tipit MS_VOID_SOURCE. Detyra e tij është të marrë kujtesën nga grumbulli. Filtrat e tjerë duhet ta kthejnë atë atje. Ato. ne do të zbulojmë faktin e rrjedhjes.

Për të përcaktuar se në cilin seksion të tubacionit ka pasur mosveprim që çon në një rrjedhje memorie, propozohet të futet një filtër shtesë që thjesht i zhvendos mesazhet nga hyrja në dalje, por në të njëjtën kohë krijon një kopje të mesazhit hyrës që nuk është i lehtë. , por më tepër një normale "e rëndë", më pas fshin plotësisht mesazhin e marrë në hyrje. Ne do ta quajmë një filtër të tillë një izolant. Ne besojmë se meqenëse filtri është i thjeshtë, nuk ka rrjedhje në të. Dhe një pronë tjetër pozitive - nëse e shtojmë diku në grafikun tonë, kjo nuk do të ndikojë në funksionimin e qarkut në asnjë mënyrë. Ne do të përshkruajmë filtrin-izolues në formën e një rrethi me një qark të dyfishtë.

Ne e ndezim izolatorin menjëherë pas filtrit të burimit të zbrazët:
Eksplorimi i motorit VoIP Mediastreamer2. Pjesa 12

Ne e ekzekutojmë përsëri programin me analizuesin dhe shohim që këtë herë analizuesi do të fajësojë izolatorin. Në fund të fundit, është ai që tani krijon blloqe të dhënash, të cilat më pas humbasin nga një filtër (ose filtra) i panjohur i pakujdesshëm. Hapi tjetër është lëvizja e izolatorit përgjatë zinxhirit në të djathtë, nga një filtër, dhe rifillimi i analizës. Pra, duke lëvizur hap pas hapi izolatorin në të djathtë, do të kemi një situatë ku në raportin tjetër të analizuesit, numri i blloqeve të kujtesës "të rrjedhura" do të ulet. Kjo do të thotë që në këtë hap izoluesi ishte në zinxhir menjëherë pas filtrit të problemit. Nëse kishte vetëm një filtër "të keq", atëherë rrjedhja do të zhduket fare. Kështu, ne lokalizuam filtrin problematik (ose një nga disa). Pasi të kemi "rregulluar" filtrin, mund të vazhdojmë të lëvizim izolatorin në të djathtë përgjatë zinxhirit derisa të mposhtim plotësisht rrjedhjet e kujtesës.

Implementimi i një filtri izolator

Zbatimi i izolatorit duket si një filtër i rregullt. Skedari i kokës:

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

Vetë filtri:

/* Файл 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 për zëvendësimin e funksioneve të menaxhimit të kujtesës

Për kërkime më delikate, transmetuesi i medias ofron mundësinë për të zëvendësuar funksionet e hyrjes në kujtesë me tuajat, të cilat, përveç punës kryesore, do të regjistrojnë "Kush, ku dhe pse". Janë zëvendësuar 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 veçori ndihmon në rastet kur analizuesi ngadalëson funksionimin e filtrave aq shumë saqë funksionimi i sistemit në të cilin është ndërtuar qarku ynë ndërpritet. Në një situatë të tillë, duhet të braktisni analizuesin dhe të përdorni zëvendësimin e funksioneve për të punuar me kujtesën.

Ne kemi shqyrtuar një algoritëm veprimesh për një grafik të thjeshtë që nuk përmban degë. Por kjo qasje mund të zbatohet në raste të tjera, sigurisht me më shumë kompleksitet, por ideja mbetet e njëjtë.

Në artikullin vijues, ne do të shqyrtojmë çështjen e vlerësimit të ngarkesës në një tregues dhe mënyrat për të luftuar ngarkesën e tepërt të llogaritjes në një transmetues media.

Burimi: www.habr.com

Shto një koment