Prozkoumání enginu Mediastreamer2 VoIP. Část 12

Materiál článku je převzat z mého zenový kanál.

Prozkoumání enginu Mediastreamer2 VoIP. Část 12

V minulosti článekSlíbil jsem, že zvážím otázku hodnocení zátěže na tickeru a způsoby, jak bojovat s nadměrnou výpočetní zátěží v streameru médií. Ale rozhodl jsem se, že by bylo logičtější pokrýt otázky ladění řemeslných filtrů souvisejících s pohybem dat a teprve poté zvážit otázky optimalizace výkonu.

Ladění řemeslných filtrů

Poté, co jsme se v předchozím článku podívali na mechanismus přesouvání dat v mediálním streameru, bylo by logické mluvit o nebezpečích, která se v něm skrývají. Jednou z vlastností principu „datového toku“ je, že paměť je alokována z haldy ve filtrech, které jsou umístěny u zdroje datového toku, a paměť je uvolněna a vrácena do haldy pomocí filtrů umístěných na konci toku. cesta. Kromě toho může vznik nových dat a jejich zničení nastat někde mezi. Obecně se uvolnění paměti provádí jiným filtrem, než který vytvořil datový blok.

Z hlediska transparentního monitorování paměti by bylo rozumné, aby filtr po přijetí vstupního bloku tento po zpracování ihned zničil, uvolnil paměť a vypsal nově vytvořený blok s výstupními daty. V tomto případě by byl únik paměti ve filtru snadno vysledovatelný - pokud by analyzátor detekoval netěsnost ve filtru, další filtr neničí správně příchozí bloky a je v něm chyba. Ale z hlediska udržení vysokého výkonu není tento přístup k práci s datovými bloky produktivní – vede k velkému množství operací k alokaci/uvolnění paměti pro datové bloky bez jakéhokoli užitečného výstupu.

Z tohoto důvodu filtry media streamer, aby nezpomalovaly zpracování dat, využívají funkce, které při kopírování zpráv vytvářejí snadné kopie (mluvili jsme o nich v minulém článku). Tyto funkce pouze vytvoří novou instanci hlavičky zprávy tak, že k ní „připojí“ blok dat ze „staré“ kopírované zprávy. Výsledkem je, že k jednomu datovému bloku jsou připojena dvě záhlaví a referenční čítač v datovém bloku je inkrementován. Ale bude to vypadat jako dvě zprávy. S takto „socializovaným“ datovým blokem může být více zpráv, například filtr MS_TEE generuje několik takových světelných kopií najednou a rozděluje je mezi své výstupy. Pokud všechny filtry v řetězci fungují správně, na konci potrubí by měl tento referenční čítač dosáhnout nuly a bude zavolána funkce uvolnění paměti: ms_free(). Pokud k volání nedojde, pak se tento kus paměti již nevrátí na hromadu, tzn. bude "prosakovat". Cenou za použití lehkých kopií je ztráta možnosti snadno určit (jako by tomu bylo u běžných kopií), kterým grafovým filtrem uniká paměť.

Vzhledem k tomu, že vývojáři media streamerů jsou zodpovědní za hledání úniků paměti v nativních filtrech, s největší pravděpodobností je nebudete muset ladit. Ale s vaším řemeslným filtrem jste kobylkou svého vlastního štěstí a čas, který strávíte hledáním úniků ve vašem kódu, bude záviset na vaší přesnosti. Abychom zkrátili dobu ladění, musíme se při vývoji filtrů podívat na techniky detekce úniků. Navíc se může stát, že se netěsnost projeví až při použití filtru v reálném systému, kde může být počet „podezřelých“ obrovský a čas na odladění omezený.

Jak se projevuje únik paměti?

Je logické předpokládat, že ve výstupu programu AutoCruitment LLC („Společnost“ nebo „My“ nebo „AutoCruitment“) respektuje ochranu vašeho soukromí a je odhodlaná ho dodržováním těchto zásad chránit. Tyto zásady popisují typy informací, které můžeme shromažďovat od vás nebo které vy můžete poskytnout, když navštívíte webové stránky zobrazí rostoucí procento paměti obsazené vaší aplikací.

Vnějším projevem bude, že v určitém okamžiku začne systém pomalu reagovat na pohyb myši a pomalu překreslovat obrazovku. Je také možné, že se systémový protokol rozroste a zabere místo na vašem pevném disku. V takovém případě se vaše aplikace začne chovat podivně, nebude reagovat na příkazy, nemůže otevřít soubor atd.

K detekci výskytu netěsnosti použijeme analyzátor paměti (dále jen analyzátor). To může být valgrind (dobrý článek o tom) nebo zabudované do kompilátoru gcc MemorySanitizer nebo cokoli jiného. Pokud analyzátor ukáže, že v jednom z grafových filtrů dochází k netěsnosti, znamená to, že je čas použít jednu z níže popsaných metod.

Metoda tří borovic

Jak bylo uvedeno výše, pokud dojde k úniku paměti, analyzátor ukáže na filtr, který požadoval přidělení paměti z haldy. Neupozorní však na filtr, který jej „zapomněl“ vrátit, což je ve skutečnosti viník. Analyzátor tedy může pouze potvrdit naše obavy, ale neukázat jejich kořen.

Chcete-li zjistit umístění „špatného“ filtru v grafu, můžete snížit graf na minimální počet uzlů, ve kterých analyzátor stále detekuje netěsnost, a lokalizovat problematický filtr ve zbývajících třech borovicích.

Může se ale stát, že snížením počtu filtrů v grafu narušíte normální průběh interakce mezi filtry a ostatními prvky vašeho systému a netěsnost se již nebude projevovat. V tomto případě budete muset pracovat s grafem v plné velikosti a použít přístup popsaný níže.

Metoda posuvného izolátoru

Pro jednoduchost prezentace použijeme graf, který se skládá z jednoho řetězce filtrů. Je zobrazena na obrázku.

Prozkoumání enginu Mediastreamer2 VoIP. Část 12

Pravidelný graf, ve kterém jsou spolu s hotovými filtry media streamer použity čtyři řemeslné filtry F1...F4, čtyř různých typů, které jste vytvořili už dávno a o jejich správnosti nepochybujete. Předpokládejme však, že několik z nich má úniky paměti. Když spustíme náš program pro sledování analyzátoru, z jeho hlášení se dozvíme, že určitý filtr požadoval určité množství paměti a nevrátil jej na hromadu N kolikrát. Snadno uhodnete, že zde bude odkaz na funkce interního filtru typu MS_VOID_SOURCE. Jeho úkolem je vzít paměť z hromady. Ostatní filtry to tam musí vrátit. Tito. zjistíme skutečnost úniku.

K určení, ve které části potrubí došlo k nečinnosti vedoucí k úniku paměti, se navrhuje zavést další filtr, který jednoduše přesouvá zprávy ze vstupu na výstup, ale zároveň vytváří kopii vstupní zprávy, která není světlá. , ale spíše normální „těžký“, pak zcela smaže zprávu přijatou při vstupu. Takový filtr budeme nazývat izolant. Věříme, že jelikož je filtr jednoduchý, nedochází k jeho úniku. A ještě jedna pozitivní vlastnost - pokud ji přidáme kamkoli do našeho grafu, nijak to neovlivní chod obvodu. Filtr-izolátor znázorníme ve formě kruhu s dvojitým obvodem.

Izolátor zapneme ihned po filtru voidsource:
Prozkoumání enginu Mediastreamer2 VoIP. Část 12

Znovu spustíme program s analyzátorem a vidíme, že tentokrát bude analyzátor obviňovat izolátor. Je to totiž on, kdo nyní vytváří bloky dat, o které pak neznámý neopatrný filtr (nebo filtry) přichází. Dalším krokem je posunutí izolátoru po řetězu doprava o jeden filtr a spuštění analýzy znovu. Takže krok za krokem posouváním izolátoru doprava se dostaneme do situace, kdy se v dalším hlášení analyzátoru počet „uniklých“ paměťových bloků sníží. To znamená, že v tomto kroku byl izolátor v řetězu bezprostředně za problémovým filtrem. Pokud byl pouze jeden „špatný“ filtr, únik úplně zmizí. Proto jsme lokalizovali problematický filtr (nebo jeden z několika). Po „opravení“ filtru můžeme pokračovat v pohybu izolátoru doprava podél řetězce, dokud zcela neporazíme úniky paměti.

Realizace oddělovacího filtru

Implementace izolátoru vypadá stejně jako běžný filtr. Soubor záhlaví:

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

Samotný filtr:

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

Způsob nahrazení funkcí správy paměti

Pro jemnější výzkum poskytuje streamer médií možnost nahradit funkce přístupu do paměti vlastními, které kromě hlavní práce zaznamenají „Kdo, kde a proč“. Tři funkce jsou nahrazeny. To se provádí následovně:

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

Tato funkce pomáhá v případech, kdy analyzátor zpomalí činnost filtrů natolik, že je narušen chod systému, ve kterém je náš obvod zabudován. V takové situaci musíte opustit analyzátor a použít substituci funkcí pro práci s pamětí.

Zvažovali jsme algoritmus akcí pro jednoduchý graf, který neobsahuje větve. Ale tento přístup lze aplikovat i na jiné případy, samozřejmě s větší složitostí, ale myšlenka zůstává stejná.

V příštím článku se podíváme na problematiku odhadu zátěže na tickeru a na způsoby, jak bojovat s nadměrnou výpočetní zátěží v media streameru.

Zdroj: www.habr.com

Přidat komentář