Eszközök

NVIDIA TensorRT: élő előrehaladás és megszakítható buildek IProgressMonitorrel Pythonban és C++-ban

A cikk főszereplője az NVIDIA TensorRT és az IProgressMonitor API, amely több kiadása óta elérhető az NvInfer.h fejlécen.

NVIDIA TensorRT: élő előrehaladás és megszakítható buildek IProgressMonitorrel Pythonban és C++-ban

A TensorRT motor (engine) felépítése percektől akár több percig is eltarthat, különösen erősen típusos hálózatok, komplex taktika-keresés és hideg időzítési cache esetén új GPU SKU-kon. Sok integráció azonban semmilyen visszajelzést nem ad build közben, illetve nincs lehetőség a korai megszakításra. Hosszú, automata ügynök‑workflownál ez GPU‑órák pazarlásához és elakadt munkamenetekhez vezet.

TensorRT-ben található az IProgressMonitor nevű API, amely több kiadáson át elérhető a NvInfer.h fejlécek között. Az API lehetővé teszi, hogy a builder élő, fa struktúrájú előrehaladási eseményeket hívjon meg, és hogy a hívó oldal visszajelzést adjon a folyamatról, illetve kérje a megszakítást. Az alábbiakban bemutatjuk a minimális, beilleszthető megvalósítást Pythonban és C++‑ban, a megszakítási útvonal hozzáadását (Ctrl‑C vagy programból indított stop), és azt, hogy hová továbbítsuk a progress adatfolyamot IDE‑ben, HTTP szolgáltatásban vagy ügynök runtime‑ban.

Mit nyújt az IProgressMonitor?

Az IProgressMonitor egy absztrakt alaposztály, amelyet a TensorRT a builder során meghív. Három metódust kell felülírni; a viselkedés azonos Pythonban és C++‑ban (csak a névhasználat tér el):

  • phase_start / phaseStart(phaseName, parentPhase, nbSteps): lefoglal egy sort és rögzíti a num_steps értéket.
  • step_complete / stepComplete(phaseName, step) -> bool: lépteti a fázist; visszaadott False/false értékkel a build megszakítható.
  • phase_finish / phaseFinish(phaseName): eltávolítja a fázist.

A parent_phase nem‑null értéke beágyazott fázist jelez, így a monitor faformában látja az előrehaladást. A megvalósításnak szálbiztosnak kell lennie, mert a TensorRT belső szálai többször is meghívhatják ugyanazt a monitor‑példányt.

A monitort a builder konfigurációjába kell kapcsolni egyetlen hívással:

  • Python: config.progress_monitor = MyMonitor()
  • C++: config->setProgressMonitor(&myMonitor);

Amikor a builder dolgozik, megnyitja a "Building Engine" fázist, azon belül a "Tactic Selection" típusú beágyazott fázist stb. A builder a step_complete hívások után várja a monitor visszatérési értékét: true folytatja a buildet, false megszakítást kér. A megszakítási útvonal (cancel) azt jelenti, hogy a builder nem kezd új lépéseket, és visszahúzza az aktív fázisokat phase_finish hívásokkal fordított sorrendben.

Mi készül el a bemutatóban

A bemutató egy egyszerű, betölthető IProgressMonitor‑alapú implementációt mutat Pythonban és C++‑ban, hozzáad egy megszakítási jelet, és megmutatja, hogyan lehet az előrehaladást terminálra vagy külső felületekre továbbítani.

Előfeltételek

  • Egy NVIDIA GPU.
  • TensorRT (az aktuális OSS kiadás) és Python bindingek, vagy a C++ minták buildje.
  • Python 3.10 vagy újabb (Python útvonalon futtatáshoz).
  • A TensorRT mintaadatok: ResNet‑50 ONNX (Pythonhoz) és MNIST ONNX (C++-hoz), amelyek megtalálhatók a sample‑data archívumban vagy az NGC konténerekben /usr/src/tensorrt/data alatt.
  • ANSI VT kódokat támogató terminál (modern Linux shell vagy Windows Terminal VT engedélyezésével).

1) IProgressMonitor alosztály Pythonban

A Python példamegvalósítás egy kis osztály, amely a fázisok aktív állapotát és lépásszámait követi, valamint egy Lockkal biztosítja a szálbiztonságot. A lényeg: a Lock kötelező, mert a TensorRT több belső szálról hívhatja a monitort, és csak a step_complete képes megszakítást kérni — phase_start nem ad lehetőséget a fázis előzetes elutasítására.

A mintakód a cikkben szerepel; a fontosabb viselkedés:

  • phase_start létrehozza a fázis állapotot és renderel.
  • step_complete frissíti az aktuális lépést, renderel, és visszaadja, hogy a build folytatható‑e a cancel flag állapota alapján.
  • phase_finish eltávolítja a fázist és renderel.

2) Fésűs (nested) progress barok kirajzolása VT escape-ekkel

A renderer az a része az implementációnak, ami a legtöbbet változhat a környezet szerint; a minta egy terminálra rajzoló megközelítést mutat be. A minta logika:

  • A fázisokat a beágyazottság szerint sorba rendezzük, hogy a gyerekfázisok a szülők alatt rajzolódjanak.
  • Az előző render során kiírt sorok számával mozgatjuk a kurzort fel, és felülírjuk azokat a sorokat a jelenlegi állapot szerint.
  • Egy sor formátuma: név, 40 karakter széles sáv, és a befejezett/összes lépések száma.
  • Amikor egy fázis eltűnik, kitörlünk minden, a korábbi renderből hátramaradt sort.

Fontos: ha a terminál renderer csatlakoztatva van, ne irányítsuk át stdoutot fájlba vagy pipe‑ra — a VT escape kódok belekerülnek a logba és olvashatatlanná teszik azt. Nem‑interaktív sinkekhez cseréljük a render metódust strukturált eseménykibocsátóra (pl. JSON üzenetek).

3) Megszakítási útvonal hozzáadása

A megszakítás egyszerű: telepítünk egy SIGINT kezelőt, amely felkapcsol egy flaget a monitorban (vagy C++‑ban egy atomic<bool>), majd a step_complete ezt figyelembe veszi és False/false visszaadással kéri a buildert a megszakításra. A build_serialized_network() függvény None értéket ad vissza Pythonban megszakítás esetén; az alkalmazásnak érdemes tájékoztatni a felhasználót a visszahúzás (unwind) késleltetéséről („Cancelling…”), mert a builder a jelenlegi lépés befejezéséig folytatódhat.

A flaget nem csak a jelkezelő állíthatja: IDE Stop gomb, ügynök timeout vagy CI cancel webhook is egyszerűen beállíthatja monitor._cancelled = True (Python) vagy monitor.requestCancel() (C++), és a build a következő step határnál leáll.

4) Ugyanez C++‑ban

A C++ implementáció megfelel a Python változatnak: egy nvinfer1::IProgressMonitor leszármazott, mutexszel a szálbiztonságért, és std::atomic<bool> a cancel flaghez. A metódusok (phaseStart, stepComplete, phaseFinish) ugyanazt a szerepet töltik be. A monitor config->setProgressMonitor(&monitor) hívással csatolható.

Az atomic szükséges, mert requestCancel() másik szálról vagy jelkezelőből is hívható lehet.

Hová érdemes bekötni a monitor megfigyelését valós rendszerekben

Az IProgressMonitor a builder és az alkalmazás felületei közötti egyetlen integrációs pont. Ettől feljebb történik a megjelenítés, a szállítás és a protokoll; alatta marad a builder belső munkája (taktika időkészlet, kernel kiválasztás stb.). Néhány tipikus felhasználási példa:

  • IDE kiterjesztés: a render() helyett LSP window/showProgress vagy $/progress értesítések küldése; minden fázis saját token, step_complete jelentés egy riport esemény, phase_finish a befejezés.
  • FastAPI / HTTP szolgáltatás: háttérszálon futtatott build, render() üzeneteket tologat egy asyncio.Queue‑ba, amit a HTTP handler SSE‑vel továbbít. A cancel végpont POST /builds/{id}/cancel meghívja monitor.requestCancel().
  • Ügynök eszköz: strukturált eseményeket küldünk minden fázis‑átmenetnél (JSON chunkok: {"phase":...,"step":...,"total":...}), az ügynök runtime megjeleníti a felhasználónak, és a timeout esetén ugyanazt a requestCancel() hívást használja.

Az IProgressMonitor teszi lehetővé, hogy hosszú build folyamatok megfigyelhetők és megszakíthatók legyenek — ez fontos ügynök runtime‑ok és interaktív fejlesztési környezetek számára.

Gyakori buktatók és viselkedési sarokpontok

  • Ne irányítsuk át stdoutot, ha a terminál renderer aktív; a kódok beszennyezik a logot.
  • phase_start nem képes megszakítani a fázist; az első lehetséges megszakítási pont a phase első step_complete hívása.
  • phase_finish előfordulhat anélkül, hogy összes num_steps jelentést kaptunk — ez hibakezelés, belső rövidre zárás vagy megszakítás következménye lehet. Ne feltételezzük, hogy current_step == num_steps.
  • A megszakítás késleltetett lehet: a builder befejezi a jelenlegi lépést a visszatérési érték ellenőrzése előtt; hosszú taktika‑keresések másodperces vagy több másodperces késleltetést okozhatnak.
  • A megvalósításnak szálbiztosnak kell lennie; nem védett dict vagy unordered_map hozzáférés idővel összeomláshoz vezethet.

Gyors kezdés

A gyors mód a teljes futtatáshoz:

git clone --depth 1 https://github.com/NVIDIA/TensorRT.git cd TensorRT/samples/python/simple_progress_monitor python3 simple_progress_monitor.py

Ez elindít egy élő, animált ResNet‑50 buildet. A C++ megfelelő a samples/sampleProgressMonitor/ könyvtárban található.

Következő lépések

Nagyobb rendszerekben cseréljük le a terminál rendererét az alkalmazás meglévő szállítási útjára: Language Server Protocol értesítésekre, Server‑Sent Events‑re vagy strukturált eszköz‑hívási csomagokra. Az IProgressMonitor lesz az a pont, ahol a TensorRT build előrehaladását az alkalmazás saját progress modelljére fordítjuk.

További források

  • TensorRT Python API dokumentáció az IProgressMonitorhez
  • TensorRT C++ API dokumentáció nvinfer1::IProgressMonitor-hoz
  • Python simple_progress_monitor minta
  • C++ sampleProgressMonitor minta
  • TensorRT GitHub release‑ek és sample adatcsomagok

A fenti minták és leírások alapján az IProgressMonitor beépítése viszonylag egyszerű módot ad arra, hogy a TensorRT build folyamata megfigyelhető és megszakítható legyen integrált fejlesztői és üzemeltetési környezetekben.