De Mediastreamer2 VoIP-engine verkennen. Deel 12

Het materiaal van het artikel is afkomstig uit mijn zen-kanaal.

De Mediastreamer2 VoIP-engine verkennen. Deel 12

In het verleden статье, beloofde ik de kwestie van de schatting van de tickerbelasting en manieren om met overmatige computerbelasting in de mediastreamer om te gaan, te overwegen. Maar ik besloot dat het logischer zou zijn om de problemen van het debuggen van ambachtelijke filters met betrekking tot gegevensverplaatsing te behandelen en pas daarna te kijken naar problemen met prestatie-optimalisatie.

Debuggen van ambachtelijke filters

Nadat we in het vorige artikel het mechanisme van gegevensbeweging in een mediastreamer hebben onderzocht, zou het logisch zijn om te praten over de gevaren die erin verborgen zitten. Een van de kenmerken van het "gegevensstroom" -principe is dat de toewijzing van geheugen uit de heap plaatsvindt in de filters die zich aan de bronnen van de gegevensstroom bevinden, en de filters aan het einde van het stroompad maken het geheugen al ongedaan met terugkeer naar de hoop. Bovendien kan het ontstaan ​​van nieuwe gegevens en de vernietiging ervan ergens in de tussenliggende punten plaatsvinden. Over het algemeen wordt het vrijgeven van geheugen uitgevoerd door een ander filter dan degene die het gegevensblok heeft gemaakt.

Vanuit het oogpunt van transparante monitoring van het geheugen zou het redelijk zijn als het filter, wanneer het een invoerblok ontvangt, dit na verwerking onmiddellijk vernietigt, geheugen vrijmaakt en een nieuw gemaakt blok met uitvoergegevens op de uitvoer plaatst. In dit geval kan het geheugenlek in het filter gemakkelijk worden opgespoord. Als de analysator een lek in het filter heeft gedetecteerd, vernietigt het filter dat erop volgt de inkomende blokken niet goed en zit er een fout in. Maar vanuit het oogpunt van het handhaven van hoge prestaties, is deze benadering van het werken met datablokken niet productief - het leidt tot een groot aantal bewerkingen om geheugen toe te wijzen / vrij te maken voor datablokken zonder enige bruikbare uitputting.

Om deze reden gebruiken mediastreamerfilters, om de gegevensverwerking niet te vertragen, functies die lichte kopieën maken bij het kopiëren van berichten (we hebben er in een vorig artikel over gesproken). Deze functies maken alleen een nieuwe kopie van de berichtkop door het datablok van het gekopieerde "oude" bericht eraan te "hechten". Hierdoor worden twee headers aan één datablok gekoppeld en wordt de referentieteller in het datablok opgehoogd. Maar het ziet eruit als twee berichten. Er kunnen meer berichten zijn met zo'n "openbaar" gegevensblok, het MS_TEE-filter genereert bijvoorbeeld tien van dergelijke lichte kopieën tegelijk en verdeelt ze over zijn uitvoer. Als alle filters in de keten correct werken, zou deze referentietelling tegen het einde van de pijplijn nul moeten zijn en zal de geheugendeallocatiefunctie worden aangeroepen: ms_free(). Als de oproep niet plaatsvindt, wordt dit stuk geheugen niet meer teruggestuurd naar de heap, d.w.z. hij "lekt". De kosten van het gebruik van lichte kopieën zijn het verlies van de mogelijkheid om gemakkelijk te bepalen (zoals het geval zou zijn bij het gebruik van gewone kopieën) in welk grafiekfilter het geheugen lekt.

Aangezien de verantwoordelijkheid voor het vinden van geheugenlekken in de "native" filters bij de ontwikkelaars van de mediastreamer ligt, hoeft u ze hoogstwaarschijnlijk niet te debuggen. Maar met je crafting-filter ben je zelf de sprinkhaan van je eigen geluk, en de tijd die je besteedt aan het zoeken naar lekken in je code hangt af van je nauwkeurigheid. Om uw foutopsporingstijd te verkorten, moeten we kijken naar leklokalisatietechnieken bij het ontwerpen van filters. Bovendien kan het gebeuren dat het lek zich pas manifesteert wanneer het filter wordt toegepast in een echt systeem, waar het aantal "verdachten" enorm kan zijn en de tijd voor het debuggen beperkt is.

Hoe manifesteert een geheugenlek zich?

Het is logisch om aan te nemen dat in de uitvoer van het programma top toont een toenemend percentage van het geheugen dat door uw toepassing wordt ingenomen.

De externe manifestatie zal erin bestaan ​​dat het systeem op een gegeven moment langzaam zal reageren op de beweging van de muis, waardoor het scherm langzaam opnieuw wordt getekend. Het is ook mogelijk dat het systeemlogboek groeit en ruimte op de harde schijf opslokt. In dit geval begint uw applicatie zich vreemd te gedragen, reageert niet op opdrachten, kan het bestand niet openen, enz.

Om het feit van een lek te identificeren, gebruiken we een geheugenanalysator (hierna de analysator genoemd). Het zou kunnen Valgrind (Goed artikel erover) of ingebouwd in de compiler gcc Geheugenontsmettingsmiddel of iets anders. Als de analysator laat zien dat het lek zich voordoet in een van de grafiekfilters, dan betekent dit dat het tijd is om een ​​van de hieronder beschreven methoden toe te passen.

Three Pines-methode

Zoals hierboven vermeld, zal de analysator in het geval van een geheugenlek verwijzen naar het filter dat om geheugentoewijzing van de heap heeft verzocht. Maar het zal niet verwijzen naar het filter dat "vergeten" is om het terug te sturen, wat in feite de schuld is. De analysator kan dus alleen onze angsten bevestigen, maar niet wijzen op de oorzaak ervan.

Om de locatie van het "slechte" filter in de grafiek te achterhalen, kunt u de grafiek verkleinen tot het minimum aantal knooppunten waarop de analysator nog steeds een lek detecteert en het problematische filter lokaliseren in de resterende drie dennen.

Maar het kan gebeuren dat door het aantal filters in de kolom te verminderen, u de normale interactie tussen filters en andere elementen van uw systeem verstoort en het lek niet meer verschijnt. In dit geval moet u werken met een grafiek op ware grootte en de hieronder beschreven aanpak gebruiken.

Glijdende isolatormethode

Voor de eenvoud van de presentatie gebruiken we een grafiek die uit een enkele reeks filters bestaat. Op de foto staat ze afgebeeld.

De Mediastreamer2 VoIP-engine verkennen. Deel 12

Een gewone grafiek, waarin, samen met kant-en-klare mediastreamerfilters, vier ambachtelijke filters F1...F4 worden gebruikt, vier verschillende typen die je lang geleden hebt gemaakt en geen twijfel hebt over hun juistheid. Stel echter dat verschillende van hen een geheugenlek hebben. Bij het uitvoeren van ons analyseprogramma voor supervisie leren we uit het rapport dat een bepaald filter om een ​​bepaalde hoeveelheid geheugen vroeg en dit niet terugstuurde naar de heap N keer. Het is gemakkelijk te raden dat er een verwijzing zal zijn naar de interne filterfuncties van het type MS_VOID_SOURCE. Zijn taak is om geheugen uit de hoop te halen. Andere filters zouden het daar moeten terugbrengen. Die. wij zullen het lek vinden.

Om te bepalen op welk deel van de pijplijn inactiviteit heeft plaatsgevonden die tot een geheugenlek heeft geleid, wordt voorgesteld een extra filter te introduceren dat eenvoudigweg berichten verschuift van invoer naar uitvoer, maar tegelijkertijd een niet-lichte kopie van de invoer creëert. bericht in een normale "zware" kopie, en vervolgens het bericht dat bij binnenkomst binnenkwam volledig verwijderen. We zullen zo'n filter een isolator noemen. Wij zijn van mening dat, aangezien het filter eenvoudig is, lekkage erin is uitgesloten. En nog een positieve eigenschap - als we het op een willekeurige plaats in onze grafiek toevoegen, heeft dit op geen enkele manier invloed op de werking van het circuit. We zullen het isolatorfilter weergeven als een cirkel met een dubbele contour.

Schakel de isolator direct na het voidsourse-filter in:
De Mediastreamer2 VoIP-engine verkennen. Deel 12

We voeren het programma opnieuw uit met de analysator en we zien dat deze keer de analysator de schuld bij de isolator legt. Hij is het tenslotte die nu datablokken creëert, die vervolgens verloren gaan door een onbekend nalatig filter (of filters). De volgende stap is om de isolator langs de ketting één filter naar rechts te verschuiven en de analyse opnieuw te starten. Dus als we de isolator stap voor stap naar rechts verplaatsen, krijgen we een situatie waarin het aantal "gelekte" geheugenblokken in het volgende rapport van de analysator afneemt. Dit betekent dat bij deze stap de isolator direct na het problematische filter in de ketting terecht is gekomen. Als er maar één "slecht" filter was, zal het lek helemaal verdwijnen. Zo hebben we het problematische filter (of een van de vele) gelokaliseerd. Nadat we het filter hebben "gerepareerd", kunnen we de isolator langs de ketting naar rechts blijven verplaatsen totdat de geheugenlekken volledig zijn geëlimineerd.

Het implementeren van een isolatorfilter

De isolator-implementatie ziet eruit als een normaal filter. Header-bestand:

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

Het filter zelf:

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

Methode voor het vervangen van geheugenbeheerfuncties

Voor meer subtiel onderzoek biedt de mediastreamer de mogelijkheid om de geheugentoegangsfuncties te vervangen door die van uzelf, die naast het hoofdwerk "Wie, waar en waarom" zal opnemen. Drie functies worden vervangen. Dit gebeurt op de volgende manier:

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

Deze functie komt te hulp in gevallen waarin de analysator de filters zo vertraagt ​​dat de werking van het systeem waarin ons circuit is gebouwd, wordt verstoord. In een dergelijke situatie moet u de analysator verlaten en de vervanging van geheugenfuncties gebruiken.

We hebben een algoritme van acties overwogen voor een eenvoudige grafiek die geen takken bevat. Maar deze aanpak kan worden toegepast op andere gevallen, natuurlijk met complicaties, maar het idee blijft hetzelfde.

In het volgende artikel zullen we kijken naar de kwestie van de schatting van de tickerbelasting en hoe om te gaan met overmatige rekenbelasting in de mediastreamer.

Bron: www.habr.com

Voeg een reactie