Shkruajmë mbi motorin VoIP Mediastreamer2. Pjesa 12

Materiali i artikullit është marrë nga kanali im zen.

Shkruajmë mbi motorin VoIP Mediastreamer2. Pjesa 12

Në të kaluarën artikullin, unë premtova të shqyrtoj çështjen e vlerësimit të ngarkesës në ticker dhe mënyrat për të luftuar ngarkesën e tepërt të llogaritjes në mediastreamer. Por vendosa se do të ishte më logjike të ndriçoja çështjet e debugimit të filtrave të krijuar për craft, të lidhura me lëvizjen e të dhënave dhe më pas të shqyrtoj çështjet e optimizimit të performancës.

Debugimi i filtrave të krijuar për craft

Pas asaj që ne trajtuam në artikullin e mëparshëm mekanizmin e lëvizjes së të dhënave në mediastreamer, do të ishte logjike të flasim për rreziqet që fshihen brenda tij. Një nga karakteristikat e parimit "data flow" është se alokimi i memories nga grumbulli ndodh në filtrat që janë në fillim të fluxit të të dhënave, ndërsa çlirimi i memories me kthimin në grumbull bëhet nga filtrat që ndodhen në fund të rrugës së fluxit. Përveç kësaj, krijimi i të dhënave të reja dhe shkatërrimi i tyre mund të ndodhin diku në pikat ndërmjet. Në rastin më të zakonshëm, çlirimi i memories nuk bëhet nga filtri që krijoi bllokun e të dhënave.

Nga pikëpamja e monitorimit transparent të memories, do të ishte e arsyeshme që filtri, duke marrë bllokun hyrës, pas përpunimit ta shkatërrojë atë menjëherë me çlirimin e memories, dhe në dalje të paraqiste një bllok të ri të krijuar me të dhënat dalëse. Në këtë rast, humbja e memories në filtra do të ndihmonte lehtësisht në gjurmimin — nëse analizatori ka gjetur një humbje në filtra, atëherë do të thotë që filtri që vjen pas nuk shkatërron blloqet hyrëse siç duhet dhe që gabimi është te ai. Por nga pikëpamja e mbajtjes së një performancë të lartë, një qasje e tillë ndaj punës me blloqet e të dhënave, nuk është produktive — ajo çon në një numër të madh operacionesh në alokimin/çlirimin e memories për blloqet e të dhënave pa ndonjë përfitim të dobishëm.

Për këtë arsye, filtrat e mediastreamerit, për të mos ngadalësuar procesimin e të dhënave, kur kopjojnë mesazhe, përdorin funksione që krijojnë kopje të lehta (ne flasim për to në artikullin e kaluar). Këto funksione thjesht krijojnë një instancë të re të titullit të mesazhit "duke e lidhur" atë me një bllok të dhënash nga mesazhi "i vjetër" që po kopjohet. Si rezultat, dy tituj lidhjen me një bllok të dhënash dhe ekzekutohet një inkrementim i numrit të referencave në bllokun e të dhënave. Por kjo do të duket si dy mesazhe. Mund të ketë edhe më shumë mesazhe me këtë bllok të dhënash "të ndarë", kështu që, për shembull, filtrat MS_TEE krijojnë menjëherë një dhjetë të tillë kopje të lehta, duke i shpërndarë ato në daljet e tyre. Nëse të gjitha filtrat në zinxhir punojnë siç duhet, në fund të konvejnerit ky numër referencash duhet të arrijë zero dhe do të thirret funksioni i lirimit të memories: ms_free(). Nëse thirrja nuk ndodh, atëherë do të thotë se ky copë i memories nuk do të kthehet në grumbull, dmth. do të "rrjedhë". Çmimi për përdorimin e kopjeve të lehta është humbja e mundësisë për të ushtruar lehtë (siç do të ishte në rastin e përdorimit të kopjeve të zakonshme) në cilin filtrin e grafit rjedh memoria.

Duke qenë se përgjegjësia për gjetjen e rrjedhjeve të memories në filtrat "e natyrshëm" bie mbi zhvilluesit e mediastreamerit, ka të ngjarë që ju të mos keni nevojë t'i debugioni ata. Por me filtrin tuaj të bërë vetë — ju jeni vetë zevzeku i fatit tuaj dhe saktësia juaj do të ndihmojë në përcaktimin e kohës 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, ndodh që rrjedhja të shfaqet vetëm kur aplikoni filtrin në një sistem real, ku numri i "të dyshuarve" mund të jetë i madh, dhe koha për debugim e kufizuar.

Si shfaqet një rrjedhje memorjeje?

Është logjike të supozohet se në daljen e programit top do të shfaqet një rritje e përqindjes së memories që zë aplikacioni juaj.

Shfaqja e jashtme do të përbëhet nga ajo që në një moment sistemi do të fillojë të reagojë ngadalë ndaj lëvizjes së mausit, duke e ricizuar ekranin ngadalë. Ndërkohë, logu sistemor mund të rritet, duke zënë hapësirë në diskun e ngurtë. Ndonjëherë aplikacioni juaj do të fillojë të sillet çuditshëm, duke mos u përgjigjur ndaj komandave, duke mos mundur të hapë skedarin etj.

Për të zbuluar faktin e shfaqjes së një rrjedhje, do të përdorim një analizator të memories (të mëvonshëm analizatori). Kjo mund të jetë Valgrind (i mirë artikull për të) ose e integruar në kompilatorin gcc MemorySanitizer ose diçka tjetër. Nëse analizatori tregon se rrjedhja ndodh në një nga filtrat e grafikës, 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ë lart, në rast të rrjedhjes së memories, analizatori do të tregojë filtrin që kërkoi alokimin e memories nga heap. Por nuk do të tregojë filtrin që "harroi" ta kthejë, i cili në të vërtetë është fajtor. Kështu, analizatori mund të konfirmojë vetëm shqetësimet tona, por nuk tregon rrënjën e tyre.

Për të zbuluar vendndodhjen e filtrit "të keq" në grafikë, mund të ndiqni rrugën e reduktimit të grafikës në numrin minimal të nyjeve, në të cilat analizatori akoma zbulon rrjedhjen dhe në tre pishat e mbetura të lokalizoni filtrin problematik.

Por mund të ndodhë që, duke reduktuar numrin e filtrave në grafikë, ju prishni mënyrën normale të ndërveprimit të filtrave me elementë të tjerë të sistemit tuaj dhe rrjedhja do të ndalojë së shfaquri. Në këtë rast, do të duhet të punoni me grafikun me përmasa të plota dhe të përdorni qasjen që do të përshkruhet më poshtë.

Metoda e izolueseve të lëvizshëm

Për thjeshtësi, do të përdorim një grafik që përbëhet nga një zinxhir filtrash. Ai është përshkruar në ilustrim.

Shkruajmë mbi motorin VoIP Mediastreamer2. Pjesa 12

Një graf normal, në të cilin përveç filtrave të gatshëm të mediastreamer-it janë aplikuar katër filtra artizanale F1…F4, katër lloje të ndryshme, të cilat i keni krijuar shumë kohë më parë dhe nuk keni dyshime në saktësinë e tyre. Megjithatë le të supozojmë se në disa prej tyre ka një rrjedhje memorjeje. Duke e drejtuar programin tonë për mbikëqyrjen e analizatorit, nga raporti i tij do të mësojmë se një filtër ka kërkuar një sasi memorjeje dhe nuk e ka kthyer atë në grumbull N herë. Lehtë mund të supozohet 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. Duhet ta kthejnë atje filtrat e tjerë. Pra, do të zbulojmë faktin e rrjedhjes.

Për të përcaktuar në cilin segment të linjës së prodhimit ndodhi paaktiviteti që çoi në rrjedhjen e memorjes, sugjerohet të futet një filtër shtesë, i cili thjesht transferon mesazhet nga hyrja në dalje, por në të njëjtën kohë krijon një kopje të pasme, në një "kopje të rëndë" normale të mesazhit në hyrje, dhe pastaj plotësisht e heq mesazhin që erdhi në hyrje. Do ta quajmë këtë filtër izolator. Besojmë se, duke qenë se filtri është i thjeshtë, rrjedhja në të është e përjashtuar. Një tjetër pronë e mirë është se nëse e shtojmë atë në çdo vend të grafit tonë, kjo nuk do të ndikojë në funksionimin e skemës. Do ta paraqesim filtrin izolator në formën e një rrethi me dy konture.

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

Përsëri aktivizojmë programin me analizatorin dhe shohim se këtë herë, analizatori do të bjerë fajin mbi izolatorin. Sepse tani ai krijon blloqe të dhënash që më pas humbasin nga një filtër (ose filtra) të pakujdesshëm. Hapi tjetër është të zhvendosim izolatorin në zinxhir në të djathtë, në një filtër dhe përsëri të aktivizojmë analizën. Kështu, hap pas hapi, duke lëvizur izolatorin në të djathtën, do të arrijmë një situatë ku në raportin e ardhshëm të analizatorit numri i blloqeve të "rrjedhura" të memorjes do të reduktohet. Kjo do të thotë se në këtë hap izolatori u gjend në zinxhir menjëherë pas filtrit problematik. Nëse filtri "i keq" ishte një, atëherë rrjedhja do të zhduket. Në këtë mënyrë kemi lokalizuar filtrin problematik (apo një nga disa të tillë). Pasi ta "rregullojmë" filtrin, mund të vazhdojmë të lëvizim izolatorin në të djathtën në zinxhir deri në një fitore të plotë mbi rrjedhjet e memorjes.

Implementimi i filtrit izolator

Zbatimi i izolatorit duket gjithashtu 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

Filtri 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 studime më të hollësishme, mediastreamer ofron mundësinë e zëvendësimit të funksioneve të aksesit në memorie me ato tuaja, të cilat, përveç punës kryesore, do të regjistrojnë "Kush, ku dhe përse". Zëvendosen tre funksione. Kjo bëhet si më poshtë:

OrtpMemoryFunctions rezerv;
OrtpMemoryFunctions unë;

rezerv.malloc_fun = ortp_malloc;
rezerv.realloc_fun = ortp_realloc;
rezerv.free_fun = ortp_free;

unë.malloc_fun = &my_malloc;
unë.realloc_fun = &my_realloc;
unë.free_fun = &my_free;

ortp_set_memory_functions(&my);

Një mundësi e tillë ndihmon në rastet kur analistii ngadalëson punën e filtreve aq shumë sa që pengon funksionimin e sistemit në të cilin është integruar skema jonë. Në një situatë të tillë, duhet të heqim dorë nga analisti dhe të përdorim zëvendësimin e funksioneve të punës me memorien.

Ne shqyrtuam algoritmin e veprimeve për një grafik të thjeshtë, pa degëzime. Por ky qasje mund të aplikohet edhe për raste të tjera, sigurisht me ndërlikim, por ideja do të mbetet e njëjtë.

Në artikullin e ardhshëm, ne do të shqyrtojmë çështjen e vlerësimit të ngarkesës në ticker dhe mënyrat për të përballuar ngarkesën e tepruar të llogaritjeve në mediastreamer.

Burimi: habr.com

Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS 🔥 Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS | ProHoster