Esplorante la Mediastreamer2 VoIP-motoron. Parto 12

La materialo de la artikolo estas prenita el mia zen kanalo.

Esplorante la Mediastreamer2 VoIP-motoron. Parto 12

En la lasta artikolo, Mi promesis konsideri la temon de takso-ŝarĝo takso kaj manieroj trakti troan komputika ŝarĝo en la amaskomunikilara streamer. Sed mi decidis, ke estus pli logike kovri la problemojn pri senararigado de metiaj filtriloj rilate al datummovado kaj nur tiam konsideri problemojn pri agado-optimumigo.

Sencimigi metiajn filtrilojn

Post kiam ni ekzamenis la mekanismon de datummovado en amaskomunikila streamer en la antaŭa artikolo, estus logike paroli pri la danĝeroj kaŝitaj en ĝi. Unu el la trajtoj de la principo de "datumfluo" estas, ke la atribuo de memoro el la amaso okazas en la filtriloj situantaj ĉe la fontoj de la datumfluo, kaj la filtriloj situantaj ĉe la fino de la fluvojo jam malasignas la memoron kun reveno. al la amaso. Krome, la kreado de novaj datumoj kaj ilia detruo povas okazi ie en la interaj punktoj. Ĝenerale, la liberigo de memoro estas farita per filtrilo alia ol tiu, kiu kreis la datumblokon.

El la vidpunkto de travidebla memormonitorado, estus racie por la filtrilo, ricevinte enigblokon, tuj detrui ĝin post prilaborado, liberigante la memoron, kaj eligi nove kreitan blokon kun eligdatenoj. En ĉi tiu kazo, memorfuĝo en la filtrilo estus facile spurita - se la analizilo detektus likon en la filtrilo, tiam la sekva filtrilo ne detruas envenantajn blokojn ĝuste kaj estas eraro en ĝi. Sed el la vidpunkto de konservado de alta rendimento, ĉi tiu aliro por labori kun datumblokoj ne estas produktiva - ĝi kondukas al granda nombro da operacioj por asigni/liberan memoron por datumblokoj sen iu ajn utila eligo.

Tial la filtriloj de amaskomunikiloj streamer, por ne malrapidigi la datumtraktadon, uzas funkciojn, kiuj kreas facilajn kopiojn kiam oni kopias mesaĝojn (pri ili ni parolis en la antaŭa artikolo). Ĉi tiuj funkcioj nur kreas novan ekzemplon de la mesaĝo-kapo per "aldonante" al ĝi blokon de datumoj de la "malnova" mesaĝo kopiita. Kiel rezulto, du titoloj estas alkroĉitaj al unu datumbloko kaj la referenca nombrilo en la datumbloko estas pliigita. Sed ĝi aspektos kiel du mesaĝoj. Povas esti pli da mesaĝoj kun tia "socialigita" datumbloko, ekzemple, la MS_TEE-filtrilo generas dekduon da tiaj malpezaj kopioj samtempe, distribuante ilin inter siaj eliroj. Se ĉiuj filtriloj en la ĉeno funkcias ĝuste, antaŭ la fino de la dukto ĉi tiu referenca nombrilo devas atingi nulon kaj la memorliberiga funkcio estos nomita: ms_free(). Se la voko ne okazas, tiam ĉi tiu memoraĵo ne plu estos resendita al la amaso, t.e. ĝi "fluos". La prezo por uzi malpezajn kopiojn estas la perdo de la kapablo facile determini (kiel estus la kazo kun regulaj kopioj) kiu grafika filtrilo likas memoron.

Ĉar la respondeco pri trovado de memorfuĝoj en la "denaskaj" filtriloj kuŝas ĉe la programistoj de la amaskomunikila streamer, tiam plej verŝajne vi ne devos sencimigi ilin. Sed kun via metia filtrilo, vi mem estas la akrido de via propra feliĉo, kaj la tempo, kiun vi pasigas serĉante likojn en via kodo, dependos de via precizeco. Por redukti vian sencimigan tempon, ni devas rigardi likajn lokalizteknikojn dum desegnado de filtriloj. Krome, povas okazi, ke la liko manifestiĝos nur kiam oni aplikas la filtrilon en reala sistemo, kie la nombro da "suspektatoj" povas esti grandega, kaj la tempo por senararigado estas limigita.

Kiel memorfluo manifestiĝas?

Estas logike supozi ke en la eligo de la programo supro montros kreskantan procenton de memoro okupita de via aplikaĵo.

La ekstera manifestiĝo estos, ke iam la sistemo komencos respondi malrapide al musmovo kaj malrapide redesegni la ekranon. Ankaŭ eblas, ke la sistema protokolo kreskos, manĝante spacon sur via malmola disko. En ĉi tiu kazo, via aplikaĵo komencos konduti strange, ne respondi al komandoj, ne povas malfermi dosieron, ktp.

Por detekti la aperon de liko, ni uzos memoran analizilon (ĉi-poste nomata analizilo). Ĝi povus esti valgrind (bona artikolo pri ĝi) aŭ enkonstruita en la kompililo gcc MemorySanitizer aŭ io alia. Se la analizilo montras, ke la liko okazas en unu el la grafikaj filtriloj, tio signifas, ke estas tempo apliki unu el la metodoj priskribitaj sube.

Metodo de Tri Pinoj

Kiel menciite supre, se estas memorfuko, la analizilo montros la filtrilon kiu petis memor-atribuon de la amaso. Sed ĝi ne atentigos la filtrilon, kiu "forgesis" redoni ĝin, kiu, fakte, estas la kulpulo. Tiel, la analizilo povas nur konfirmi niajn timojn, sed ne indiki ilian radikon.

Por ekscii la lokon de la "malbona" ​​filtrilo en la grafeo, vi povas iri reduktante la grafeon al la minimuma nombro da nodoj ĉe kiuj la analizilo ankoraŭ detektas likon kaj lokalizi la probleman filtrilon en la ceteraj tri pinoj.

Sed povas okazi, ke reduktante la nombron da filtriloj en la kolumno vi interrompos la normalan kurson de interago inter filtriloj kaj aliaj elementoj de via sistemo kaj la liko ne plu aperos. En ĉi tiu kazo, vi devos labori kun plengranda grafeo kaj uzi la aliron priskribitan sube.

Glita izolita metodo

Por simpleco de prezento, ni uzos grafeon kiu konsistas el unu ĉeno de filtriloj. Ŝi estas montrita en la bildo.

Esplorante la Mediastreamer2 VoIP-motoron. Parto 12

Ordinara grafikaĵo, en kiu, kune kun pretaj filtriloj de amaskomunikiloj, estas uzataj kvar metiaj filtriloj F1...F4, kvar malsamaj tipoj, kiujn vi faris antaŭ longe kaj ne dubas pri ilia ĝusteco. Tamen, supozu, ke pluraj el ili havas memorfluon. Dum funkciado de nia analizilo-kontrolprogramo, ni lernas el ĝia raporto, ke certa filtrilo petis certan kvanton da memoro kaj ne resendis ĝin al la amaso N fojojn. Estas facile konjekti, ke estos referenco al la internaj filtrilaj funkcioj de la tipo MS_VOID_SOURCE. Lia tasko estas preni memoron el la amaso. Aliaj filtriloj devus resendi ĝin tien. Tiuj. ni trovos la likon.

Por determini, ĉe kiu sekcio de la dukto neaktiveco okazis, kiu kaŭzis memorlikon, oni proponas enkonduki plian filtrilon, kiu simple ŝanĝas mesaĝojn de la enigo al la eligo, sed samtempe kreas nemalpezan, normalan. "peza" kopio de la eniga mesaĝo, tiam tute forigante la mesaĝon kiu alvenis al la eligo. Tian filtrilon ni nomos izolilo. Ni kredas, ke ĉar la filtrilo estas simpla, elfluado en ĝi estas ekskludita. Kaj unu plia pozitiva propraĵo - se ni aldonas ĝin al iu ajn loko en nia grafeo, tiam ĉi tio neniel influos la funkciadon de la cirkvito. Ni prezentos la izolan filtrilon kiel cirklon kun duobla konturo.

Ni ŝaltas la izolilon tuj post la malplenfonta filtrilo:
Esplorante la Mediastreamer2 VoIP-motoron. Parto 12

Ni rulas la programon kun la analizilo denove, kaj ni vidas, ke ĉi-foje, la analizilo kulpigos la izolilon. Ja estas li, kiu nun kreas blokojn de datumoj, kiuj poste perdiĝas per nekonata neglekta filtrilo (aŭ filtriloj). La sekva paŝo estas movi la izolilon laŭ la ĉeno dekstren, per unu filtrilo, kaj komenci la analizon denove. Do, paŝon post paŝo, movante la izolilon dekstren, ni ricevas situacion, kiam la nombro da "fluitaj" memorblokoj en la sekva raporto de la analizilo malpliiĝas. Ĉi tio signifas, ke ĉe ĉi tiu paŝo la izolilo finiĝis en la ĉeno tuj post la problema filtrilo. Se ekzistis nur unu "malbona" ​​filtrilo, tiam la liko tute malaperos. Tiel, ni lokalizis la probleman filtrilon (aŭ unu el pluraj). "Riparinte" la filtrilon, ni povas daŭrigi movi la izolilon dekstren laŭ la ĉeno ĝis la memorfuĝoj estas tute forigitaj.

Efektivigo de izola filtrilo

La izola efektivigo aspektas kiel normala filtrilo. Kapa dosiero:

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

La filtrilo mem:

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

Metodo por anstataŭigi memorajn administrajn funkciojn

Por pli subtila esplorado, la amaskomunikila streamer provizas la kapablon anstataŭigi la memorajn alirfunkciojn per via propra, kiu, krom la ĉefa laboro, riparos "Kiu, kie kaj kial." Tri funkcioj estas anstataŭigitaj. Ĉi tio estas farita en la sekva maniero:

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

Ĉi tiu funkcio helpas en kazoj kie la analizilo malrapidigas la funkciadon de la filtriloj tiom multe, ke la funkciado de la sistemo, en kiu nia cirkvito estas konstruita, estas interrompita. En tia situacio, vi devas forlasi la analizilon kaj uzi anstataŭigon de funkcioj por labori kun memoro.

Ni konsideris algoritmon de agoj por simpla grafeo, kiu ne enhavas branĉojn. Sed ĉi tiu aliro povas esti aplikita al aliaj kazoj, kompreneble kun komplikaĵo, sed la ideo restas la sama.

En la sekva artikolo, ni rigardos la aferon pri taksado de la ŝarĝo sur teletajpilo kaj manieroj kontraŭbatali troan komputikan ŝarĝon en amaskomunikila streamer.

fonto: www.habr.com

Aldoni komenton