Проучване на VoIP двигателя на Mediastreamer2. част 12

Материалът на статията е взет от моя дзен канал.

Проучване на VoIP двигателя на Mediastreamer2. част 12

В последния Статия, обещах да разгледам въпроса за оценката на натоварването на тикерите и начините за справяне с прекомерното изчислително натоварване в медийния стример. Но реших, че би било по-логично да обхвана проблемите с отстраняването на грешки на занаятчийски филтри, свързани с движението на данни, и едва след това да разгледам проблемите с оптимизирането на производителността.

Отстраняване на грешки на крафт филтри

След като разгледахме механизма на движение на данни в медиен стример в предишната статия, би било логично да говорим за опасностите, скрити в него. Една от характеристиките на принципа на "потока от данни" е, че разпределението на паметта от купчината става във филтрите, разположени в източниците на потока от данни, а филтрите, разположени в края на пътя на потока, вече освобождават паметта с връщане до купчината. Освен това създаването на нови данни и тяхното унищожаване може да се случи някъде в междинните точки. По принцип освобождаването на паметта се извършва от филтър, различен от този, който е създал блока с данни.

От гледна точка на прозрачното наблюдение на паметта би било разумно филтърът, когато получи входен блок, веднага да го унищожи след обработка, освобождавайки памет, и да постави новосъздадения блок с изходни данни на изхода. В този случай изтичането на памет във филтъра може лесно да бъде проследено — ако анализаторът открие изтичане във филтъра, тогава филтърът след него не унищожава правилно входящите блокове и в него има грешка. Но от гледна точка на поддържане на висока производителност, този подход за работа с блокове от данни не е продуктивен - той води до голям брой операции за разпределяне / освобождаване на памет за блокове от данни без никакво полезно изпускане.

Поради тази причина медийният стример филтрира, за да не забавя обработката на данни, когато копира съобщения, използва функции, които създават леки копия (говорихме за тях в предишна статия). Тези функции само създават ново копие на заглавката на съобщението чрез „прикачване“ на блока с данни от копираното „старо“ съобщение към него. В резултат на това две заглавки са прикрепени към един блок от данни и броячът на препратки в блока от данни се увеличава. Но ще изглежда като две съобщения. Може да има повече съобщения с такъв "обществен" блок от данни, например филтърът MS_TEE генерира десет такива леки копия наведнъж, разпределяйки ги между своите изходи. Ако всички филтри във веригата работят правилно, до края на конвейера този референтен брой трябва да достигне нула и функцията за освобождаване на паметта ще бъде извикана: ms_free(). Ако повикването не се случи, тогава тази част от паметта вече няма да бъде върната в купчината, т.е. той "изтича". Цената на използването на леки копия е загубата на способността лесно да се определи (както би било в случай на използване на обикновени копия) в кой графичен филтър изтича паметта.

Тъй като отговорността за намирането на изтичане на памет в „родните“ филтри е на разработчиците на медийния стример, тогава най-вероятно няма да се налага да ги отстранявате. Но с вашия крафт филтър вие сами сте скакалецът на собственото си щастие и времето, което прекарвате в търсене на течове във вашия код, ще зависи от вашата точност. За да намалим времето ви за отстраняване на грешки, трябва да разгледаме техниките за локализиране на течове, когато проектираме филтри. Освен това може да се случи изтичането да се прояви само при прилагане на филтъра в реална система, където броят на „заподозрените“ може да бъде огромен и времето за отстраняване на грешки е ограничено.

Как се проявява изтичането на памет?

Логично е да се предположи, че в изхода на програмата връх ще покаже нарастващ процент памет, заета от вашето приложение.

Външното проявление ще се състои в това, че в даден момент системата ще реагира бавно на движението на мишката, бавно преначертавайки екрана. Възможно е също така системният журнал да нарасне, изяждайки място на твърдия диск. В този случай вашето приложение ще започне да се държи странно, не отговаря на команди, не може да отвори файла и т.н.

За да идентифицираме факта на изтичане, ще използваме анализатор на паметта (наричан по-долу анализатор). Може да бъде Валгринд (добре статия за него) или вграден в компилатора GCC Memory Sanitizer или нещо друго. Ако анализаторът покаже, че течът възниква в един от филтрите на графиката, това означава, че е време да приложите един от методите, описани по-долу.

Метод на три бора

Както бе споменато по-горе, в случай на изтичане на памет, анализаторът ще посочи филтъра, който е поискал разпределение на памет от купчината. Но няма да посочи филтъра, който е "забравил" да го върне, което всъщност е виновен. Така анализаторът може само да потвърди страховете ни, но не и да посочи корена им.

За да разберете местоположението на „лошия“ филтър в графиката, можете да отидете, като намалите графиката до минималния брой възли, при които анализаторът все още открива теч, и локализирайте проблемния филтър в останалите три бора.

Но може да се случи, че чрез намаляване на броя на филтрите в колоната ще нарушите нормалния ход на взаимодействие между филтрите и другите елементи на вашата система и течът вече няма да се появи. В този случай ще трябва да работите с графика в пълен размер и да използвате подхода, описан по-долу.

Метод на плъзгащ се изолатор

За простота на представянето ще използваме графика, която се състои от една верига от филтри. Тя е показана на снимката.

Проучване на VoIP двигателя на Mediastreamer2. част 12

Обикновена графика, в която наред с готовите медийни стриймър филтри се използват четири занаятчийски филтъра F1…F4, четири различни вида, които сте направили отдавна и не се съмнявате в тяхната коректност. Да предположим обаче, че няколко от тях имат изтичане на памет. Когато изпълняваме нашата програма за надзор на анализатора, научаваме от неговия отчет, че определен филтър е поискал определено количество памет и не го е върнал в купчината N пъти. Лесно е да се познае, че ще има препратка към функциите на вътрешния филтър от типа MS_VOID_SOURCE. Неговата задача е да вземе памет от купчината. Други филтри трябва да го върнат там. Тези. ще намерим теча.

За да се определи в кой участък от тръбопровода е възникнала неактивност, която е довела до изтичане на памет, се предлага да се въведе допълнителен филтър, който просто премества съобщенията от входа към изхода, но в същото време създава нелек, нормален "тежко" копие на входното съобщение, след което напълно изтриване на съобщението, което е пристигнало на изхода. Такъв филтър ще наричаме изолатор. Вярваме, че тъй като филтърът е прост, изтичането в него е изключено. И още едно положително свойство - ако го добавим на което и да е място в нашата графика, това няма да повлияе по никакъв начин на работата на веригата. Ще изобразим изолационния филтър като кръг с двоен контур.

Активирайте изолатора веднага след филтъра voidsourse:
Проучване на VoIP двигателя на Mediastreamer2. част 12

Пускаме отново програмата с анализатора и виждаме, че този път анализаторът ще хвърли вината върху изолатора. В крайна сметка той е този, който сега създава блокове от данни, които след това се губят от неизвестен небрежен филтър (или филтри). Следващата стъпка е да преместите изолатора по веригата надясно с един филтър и да започнете анализа отново. И така, стъпка по стъпка, премествайки изолатора надясно, получаваме ситуация, когато броят на "изтеклите" блокове памет в следващия отчет на анализатора намалява. Това означава, че на тази стъпка изолаторът е попаднал във веригата веднага след проблемния филтър. Ако имаше само един "лош" филтър, тогава течът ще изчезне напълно. Така локализирахме проблемния филтър (или един от няколко). След като "фиксираме" филтъра, можем да продължим да движим изолатора надясно по веригата, докато течовете на паметта бъдат напълно елиминирани.

Внедряване на изолиращ филтър

Изпълнението на изолатора изглежда точно като нормален филтър. Заглавен файл:

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

Самият филтър:

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

Метод за подмяна на функциите за управление на паметта

За по-фини изследвания медийният стример предоставя възможност за замяна на функциите за достъп до паметта със собствени, което в допълнение към основната работа ще коригира „Кой, къде и защо“. Подменят се три функции. Това става по следния начин:

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

Тази функция идва на помощ в случаите, когато анализаторът забавя филтрите толкова много, че работата на системата, в която е изградена нашата верига, е нарушена. В такава ситуация трябва да изоставите анализатора и да използвате замяната на функциите на паметта.

Разгледахме алгоритъм от действия за проста графа, която не съдържа разклонения. Но този подход може да се приложи и в други случаи, разбира се с усложнения, но идеята остава същата.

В следващата статия ще разгледаме проблема с оценката на натоварването на тикерите и как да се справим с прекомерното изчислително натоварване в медийния стример.

Източник: www.habr.com

Добавяне на нов коментар