본문으로 건너뛰기

저장소 아키텍처 및 설계

이 페이지는 라이브러리의 구조, 책임 범위, 그리고 모듈 및 런타임 계약을 깨뜨리지 않고 프레임워크를 확장하는 방법을 이해해야 하는 기여자들을 위한 것입니다.


프레임워크 대 환경

"Neat"이라는 용어는 관련되어 있지만 분리된 두 가지 측면을 나타내는 데 사용됩니다.

  • Neat Library: 이 저장소의 C++/Python 라이브러리 및 런타임입니다. 모델 패키를 로드하고, 파이프라인을 구성하고, 계약을 검증하고, Modalix 하드웨어에서 실행하며, 공개 API를 제공합니다.
  • Neat SDK / 환경: 프레임워크를 중심으로 구축된 컨테이너화된 개발 워크플로로, DevKit Sync, 공유 작업 공간 및 에이전트 도구를 포함합니다.

이 저장소를 변경할 때, 사람과 에이전트 모두를 지원하는 프레임워크 속성을 최적화하십시오. 즉, 명시적인 API, 결정론적 동작, 구조화된 진단, 엄격한 검증 및 안정적인 공개 계약을 제공해야 합니다.


이 라이브러리의 용도

주요 사용자

다음 작업을 수행하려는 개발자:

  • 재사용 가능한 빌딩 블록에서 파이프라인을 조립합니다(원시 GStreamer 보일러플레이트 코드를 작성하지 않고).
  • 파이프라인을 조기에 검증하고(CI에 적합) 오류를 빠르게 이해합니다.
  • appsink를 통해 C++에서 파이프라인을 실행하고 프레임을 소비합니다.
  • 선택적으로 RTSP를 통해 파이프라인을 제공합니다(gst-rtsp-server 사용).
  • GStreamer 파이프라인 코드를 작성하지 않고 텐서 친화적인 출력을 통해 ML 코드를 공급합니다.

패키지 소유권

선택된 Core 아티팩트는 함께 설치되는 Neat, LLiMa 및 Internals Debian 패키지의 단일 진실 공급원입니다. Core는 종속성 버전을 선택하거나 다시 작성하지 않고 해당 아티팩트 집합을 사용하고 전달합니다. 아티팩트 외부의 패키지는 플랫폼이 소유하며, 호환되지 않는 플랫폼은 Core 또는 LLiMa에서 임시로 수정하는 대신 업데이트해야 합니다.

일반적인 워크플로

  • 디코딩/수집: 파일 또는 RTSP -> 디페이/디멀티플렉스/파싱 -> 디코딩 -> 변환/캡스 -> appsink -> C++ 소비자
  • 검증: 빌드 + 파싱 + 프리롤(PAUSED)을 통해 초기 협상 문제를 감지
  • RTSP 제공: appsrc를 사용하여 합성 프레임을 RTSP 서버 파이프라인으로 푸시
  • 이미지/비디오 텐서 어댑터: 이미지/비디오/RTSP -> 디코딩 -> 변환/스케일 -> add_output_tensor(...) -> Run::pull_tensors()
  • 튜토리얼: 튜토리얼에서 실행 가능한 순서대로 학습 경로를 시작합니다.

표준 프로덕션 파이프라인(단일 진실 공급원)

이 저장소의 표준 "프로덕션 경로"는 다음과 같습니다. 입력 -> 전처리 -> MLA -> 후처리. 단일 진실 공급원은 tests/e2e_pipelines/obj_detection/sync_yolov8_test.cpp입니다.

이 테스트가 변경되면 README + 아키텍처를 업데이트하여 문서가 일관되게 유지되도록 합니다.

정신적 모델(비즈니스 로직 <-> 파이프라인 연결)

애플리케이션은 비즈니스 로직을 유지하고, 프레임워크는 파이프라인 연결을 담당합니다.

Business logic
|
v
Nodes/Graph fragments -> GStreamer fragments -> caps negotiation -> runtime (Run)
| |
+-----------------------------------------------------------+
Sample / Tensor

핵심 개념

이 프레임워크는 몇 가지 핵심 개념을 중심으로 구성되어 있습니다. 대부분의 사용자 코드는 Model, Graph, Run, TensorSample와만 상호 작용합니다. 더 낮은 수준의 개발자는 Node, 재사용 가능한 그래프 조각, MPK 계약 파싱 및 그래프 내부 요소와 함께 작업합니다.

개념역할
모델 아카이브MPK 추론 계약, 플러그인 전용 구성, 모델 바이너리 및 커널 아티팩트를 포함하는 밀봉된 .tar.gz 아티팩트입니다.
Model.tar.gz 모델 아카이브의 공개 로더입니다. MPK 계약을 파싱하고, 경로 계획을 실행하며, 모델 단계를 노출하고, 간단한 run(...) / Graph 구성 진입점을 제공합니다.
Tensordtype, shape, 레이아웃, 스토리지, 장치 및 의미 메타데이터를 포함하는 형식화된 숫자 페이로드입니다.
Sample텐서, 텐서 목록 또는 번들을 둘러싼 런타임/미디어 컨테이너입니다. 필드를 읽기 전에 Sample::kind를 확인하십시오.
Node결정적인 GStreamer 조각과 소유된 요소 이름을 출력하는 원자적 파이프라인 단계입니다.
재사용 가능한 그래프 조각디코딩된 RTSP 입력 또는 모델 단계와 같이 여러 노드로 확장되는 미리 만들어진 Graph입니다.
Graph어셈블리 및 검증 경계입니다. 노드, 모델 및 재사용 가능한 그래프 조각은 협상되고 빌드 가능한 파이프라인이 됩니다.
RunGraph::build(...)에서 반환된 활성 파이프라인 핸들입니다. 푸시/풀/런타임 라이프사이클을 소유합니다.
그래프단일 파이프라인 내에서 DAG 구성을 위해 빌더 그래프를 사용하고, 파이프라인 간의 단계/실행을 조정하기 위해 런타임 그래프를 사용합니다.

왼쪽에서 오른쪽으로 관계를 읽으십시오.

model archive on disk -> Model -> Graph fragments/Nodes -> Graph -> Run
|
v
Tensor/Sample flow

Model은 초보 사용자를 위한 진입점 역할을 하지만, 별도의 실행 엔진은 아닙니다. 이는 Graph에 추가할 수 있는 모델 그래프 조각/노드로 해결됩니다. Graph는 핵심 조립 개념이며, Run은 빌드 후의 활성 객체입니다.


기여자 대상 설계 원칙

다음은 프레임워크의 기반이 되는 핵심 아키텍처 원칙입니다. 구현 옵션을 결정할 때 이를 활용하십시오.

  • 결정성이 최우선입니다. 요소 이름, 생성된 파이프라인 문자열, 직렬화된 파이프라인 데이터, 보고서 필드 및 테스트를 재현 가능하게 유지합니다. 진단 및 에이전트 루프는 안정적인 식별자에 의존합니다.
  • 디버깅 가능성이 가장 중요합니다. 오류 발생 시 문자열만 반환하는 것이 아니라 구조화된 데이터를 반환해야 합니다. GraphReport.error_code, repro_note, 버스 메시지 및 재현 가능한 백엔드 파이프라인을 제공해야 합니다.
  • 자동 대체는 허용되지 않습니다. 모델 입력 오류 또는 하드웨어/런타임 오류를 조용히 형식 변환, 그래프 패밀리 변경, CPU로 대체하거나 플러그인 오류를 무시하여 숨기지 마십시오.
  • 실행 전에 검증합니다. 런타임 스레드가 시작되거나 하드웨어 리소스가 할당되기 전에 구조, 캡, 모양 및 계약 검증을 우선적으로 수행합니다.
  • MPK 계약은 모델의 단일 진실 공급원입니다. Core의 라우팅, dtype, 형상, 양자화 및 단계 결정은 mpk.json / *_mpk.json에서 가져와야 합니다. 단계별 JSON 파일은 플러그인 전용입니다.
  • 논리적 랭크와 런타임 지오메트리는 분리되어야 합니다. 코어는 MPK에서 작성된 frame_shape를 논리적 출력 계약으로 유지하고 필요에 따라 명시적인 MLA 지오메트리를 파생시킵니다. 랭크-2 모양은 선언된 바이트 범위가 고유한 해석을 식별하는 경우에만 NC 또는 HW로 허용됩니다. 모호하거나 일관성이 없는 계약은 모델 로딩 중에 실패합니다.
  • 공개 API는 안정적으로 유지되어야 합니다. include/* 아래의 공개 헤더는 설치 및 지원됩니다. 서명을 변경하는 대신 점진적인 변경 및 사용 중단 경로를 선호합니다.
  • 동시성은 제한되고 관찰 가능해야 합니다. 스트리밍 스레드 작업은 가벼워야 합니다. 프로브 측면 진단에는 원자 또는 이에 상응하는 스레드 안전 처리 기능이 필요합니다. 종료 시에는 프로세스가 중단되지 않아야 합니다.

모델 실행 경로

모델 기반 파이프라인의 경우, 상위 수준 경로는 다음과 같습니다.

input Sample/Tensor
-> optional preprocessing / format normalization
-> MLA inference stages selected from MPK contract
-> optional postprocessing / box decode
-> output Sample/Tensor

사용자에게 보이는 Model 인터페이스는 MLA 하드웨어 인터페이스보다 더 사용자 친화적으로 설계되었습니다. MLA는 INT8/BF16 및 테셀레이션 레이아웃을 요구할 수 있지만, 사용자 코드는 일반적으로 FP32 및 일반 텐서 레이아웃으로 작동합니다. 프레임워크는 매니페스트 기반 어댑터 단계를 통해 이러한 격차를 해소합니다.

전처리 및 후처리는 명시적인 프레임워크 단계/옵션입니다. 형식 불일치, 필수 전처리 메타데이터 누락, 사용 불가능한 MLA 디스패처, 유효하지 않은 모델 아카이브 또는 MPK 계약, 또는 캡스 협상 실패는 숨겨진 런타임 수정이 아닌 실행 가능한 구조화된 오류로 나타나야 합니다.


저장소 레이아웃

상위 수준 구조

  • include/ -- 공개 헤더 (지원되는 API 표면)
  • src/ -- 구현
  • docs/ -- 문서 (이 파일)
  • examples/ -- 간단한 실행 가능한 예제
  • tests/ -- 단위/통합 테스트
  • python/ -- pyneat 패키지 소스, nanobind 바인딩 및 Python 테스트
  • old_* -- 레거시 단일체 구현 스냅샷 (참조/마이그레이션을 위해 보관)

공개 헤더 트리 (include/)

공개 헤더는 include/<module>/... 아래에 있습니다. 예: include/pipeline/Graph.h, include/model/Model.h.

공개 편의 엔트리 헤더:

  • include/neat.h (엄브렐라)
  • include/neat/runtime.h
  • include/neat/models.h
  • include/neat/nodes.h
  • include/neat/node_groups.h

의도적으로 include/neat/graph.h 공개 엄브렐라 헤더는 없습니다. 런타임/컴파일러 테스트에서 하위 수준 그래프 서브스트레이트가 필요한 경우 좁은 범위의 include/graph/... 헤더를 직접 포함합니다. 애플리케이션, 예제 및 공개 문서는 <neat.h>에서 제공하는 단일 공개 simaai::neat::Graph를 사용해야 합니다.

내부 헤더 및 런타임 플러그인 경로

include/ 아래의 공개 헤더는 설치되고 안정적인 API로 처리됩니다. src/**/internal 아래의 내부 헤더는 설치되지 않습니다. 예제/튜토리얼은 공개 API만 사용해야 합니다.

런타임 환경 참고 사항:

  • 번들된 GStreamer 플러그인을 deps/gst-plugins에 사용하는 경우 GST_PLUGIN_PATH 및/또는 GST_PLUGIN_PATH_1_0에 해당 디렉터리가 포함되도록 설정합니다.
  • cmake --install로 설치한 경우 플러그인은 ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/sima-neat/gst-plugins 아래에 배치됩니다. 해당 경로를 GST_PLUGIN_PATH 및/또는 GST_PLUGIN_PATH_1_0에 추가합니다.
  • scripts/use_neatdecoder.sh를 사용하여 현재 셸에 대한 플러그인 경로를 설정합니다.
  • 플러그인을 시스템 전체에 설치하는 경우 시스템 GStreamer 캐시를 다시 빌드합니다.

계획된 것과 안정적인 것 (API 표면)

영역 / API상태참고 사항
핵심 파이프라인 API (Graph, Run, Tensor, Sample)안정적주요 지원 C++ 인터페이스입니다.
빌더 내부 (Node, 비공개 노드-벡터 헬퍼, GraphPrinter)내부STL 전용이며, GStreamer 구성 지원 이전 버전입니다.
모델 API (Model, 재사용 가능한 그래프 조각)안정적표준 모델-아카이브 통합 경로입니다.
include/policy/*안정적최소한 검증된 정책 계약 및 기본값 (Decoder, Encoder, Memory, RTSP).
include/nodes/groups/ImageToH264RtspGroup.h계획됨빈 자리 표시자 그룹입니다.
Python 바인딩 (python/, pyneat)베타Nanobind 기반 바인딩 및 패키징은 저장소 내에 존재합니다. API 인터페이스는 Tensor, Graph/Run, Model 및 핵심 노드/그룹 헬퍼에 중점을 둡니다.

모듈 및 책임

builder/ -- 노드 계약 및 비공개 선형 구성 지원 (GStreamer 없음)

목적: 파이프라인이 논리적 부분에서 어떻게 구성되는지 정의합니다.

주요 유형:

  • Node -- 파이프라인 빌딩 블록을 구현하는 인터페이스
  • 비공개 노드-벡터 헬퍼 및 GraphPrinter -- 구성 유틸리티 및 진단

규칙: 빌더는 대부분 STL 전용으로 유지되어야 합니다. GStreamer 런타임 객체를 소유해서는 안 됩니다.


nodes/ -- 유형화된 파이프라인 빌딩 블록

목적: 결정적인 GStreamer 조각을 출력하는 즉시 사용할 수 있는 Node 구현을 제공합니다.

예:

  • nodes/io/HttpSource, nodes/io/RTSPInput, nodes/io/StillImageInput
  • nodes/common/* (Caps, Queue, Output 등)
  • nodes/sima/* (SiMa.ai 디코딩/인코딩/파싱/페이로드 노드)
  • nodes/rtp/* (디페이/페이로드 헬퍼)
  • nodes/groups/* (일반적인 다중 노드 레시피)

계약: 각 Node는 다음을 생성해야 합니다.

  • backend_fragment(index) -- 주어진 인덱스에서 이 노드에 대한 GStreamer 조각
  • element_names(index) -- 이 노드에서 소유한 결정적인 요소 이름 (진단 및 강제 적용용)

gst/ -- 간결한 GStreamer 유틸리티

목적: 일반적인 GStreamer 패턴에 대한 작은 래퍼/헬퍼입니다.

예:

  • 초기화 (GstInit)
  • 런칭 문자열 파싱 (GstParseLaunch)
  • 버스 드레이닝/문자열화 (GstBusWatch)
  • 캡 헬퍼 / 요소 검사 (GstHelpers, GstIntrospection)
  • 패드 탭 / 프로브 헬퍼 (GstPadTap)

규칙: gst/pipeline/에 의존해서는 안 됩니다 (종속성 순환 및 "유틸리티 레이어" 팽창을 방지하기 위해).


pipeline/ -- 런타임 오케스트레이션 및 공개 API

목적: 런타임 수명 주기를 소유합니다: 빌드 -> 파싱 -> 실행 -> 소비 -> 정리, 진단 포함.

주요 유형:

  • Graph -- 사용자를 위한 주요 진입점
  • Run -- 푸시/풀 API가 있는 파이프라인 실행 핸들
  • Sample -- 풀을 통해 반환되는 구조화된 출력 페이로드
  • GraphReport -- 실패, 정지 및 재현에 대한 구조화된 진단
  • Errors -- 예외 (NeatError)는 보고서를 포함합니다.

오류 의미론 계약

GraphReport.error_code는 표준 머신 분류 필드입니다. 프레임워크 런타임/빌드/IO 경로가 터미널 오류를 안정적인 코드 계층으로 매핑합니다.

  • misconfig.pipeline_shape
  • misconfig.caps
  • misconfig.input_shape
  • misconfig.input_capacity
  • misconfig.media_caps
  • misconfig.tensor_dtype_missing
  • misconfig.option_out_of_range
  • build.parse_launch
  • build.pipeline_syntax
  • build.plugin_missing
  • build.property_invalid
  • runtime.pull
  • runtime.element_failed
  • runtime.output_timeout
  • io.parse
  • io.open
  • io.file_not_found
  • io.permission_denied
  • io.rtsp_connection_failed
  • io.camera_not_found
  • codec.*, resource.*, infra.*internal.*

GStreamer 오류는 하나의 내부 파서, 분류기 및 렌더러를 거칩니다. 분류는 버전이 지정된 Neat 진단 ID를 우선적으로 사용하고, 그 다음에는 기본 GStreamer 도메인/코드 및 요소 팩토리를 사용하며, 마지막으로 이전 플러그인에 대한 좁은 호환성 매핑을 사용합니다. 알 수 없는 오류는 runtime.element_failed를 사용합니다. 협상이 실제로 실패하지 않은 경우 misconfig.media_caps로 보고되지 않습니다. 파이프라인에서 여러 오류가 발생하면 가장 구체적인 근본 원인이 렌더링되고 모든 오류가 버스 로그에 유지됩니다.

GraphReport.repro_note는 사람이 읽을 수 있는 요약입니다. 프로덕션 렌더링에는 일반 언어로 된 원인, 관련 있는 관찰/예상 값, 구체적인 사용자 작업 및 안정적인 진단 ID가 포함됩니다. 원시 플러그인 문자열, 소스 위치 및 GStreamer 도메인/코드는 디버깅 전용입니다. 괄호로 묶인 공개 코드는 NeatError가 생성될 때 한 번 추가됩니다. GraphReport.bus는 플러그인/런타임 오류 세부 정보의 단일 진실 공급원입니다.

빌드(입력) 흐름의 경우 GraphReport.build_adaptation은 해결된 모양 정책/기능, 시드/최대 제한에 대한 원본, 바이트 가드 원본 및 적용/건너뛴 조정 작업을 기록합니다. 오류가 발생하지 않는 런타임 풀의 경우 PullError.code는 동일한 분류 체계를 사용합니다. 입력 스트림 작업자 오류는 유형이 지정된 오류 코드를 유지하고 작업자 스레드 경계를 통해 보고되므로 Run::pull() 및 Python 예외 변환기는 동일한 NeatError를 표시합니다.

지원 분류 순서는 다음과 같습니다.

  1. error_code로 분류
  2. repro_note 읽기
  3. 첫 번째 터미널 bus 오류 검사
  4. repro_gst_launch로 재현

내부 파이프라인 진단

src/pipeline/internal/ (내부 전용)에서:

  • Diagnostics.h -- 런타임에서 사용하는 공유 진단 유형:
    • DiagCtx (버스 로그 + 노드 보고서 + 경계/요소 카운터)
    • BoundaryFlowCounters (스트리밍 스레드에서 업데이트되는 원자 카운터)
    • ElementTimingCounters (원자 단위의 요소별 계산 시간)
    • ElementFlowCounters (원자 단위의 요소별 흐름 통계)
  • GstDiagnosticsUtil.h -- GStreamer 진단 형식 지정 및 수집을 위한 도우미

SIMA 정적 매니페스트 컨텍스트 계약

모델 파이프라인의 경우 정적 단계/텐서 계약 데이터는 프레임워크에서 빌드되고 파이프라인 수준 GstContext로 주입됩니다.

  • 컨텍스트 유형: sima.model.manifest.v1
  • 컨텍스트 필드:
    • manifest_version
    • manifest_json (기존 호환성을 위한 페이로드)
    • manifest_accessor_v1 (ABI 호환 액세서 테이블 포인터)
    • 선택 사항: session_id, model_id
  • 매니페스트의 소유권/수명은 파이프라인 수명과 연결됩니다. 플러그인은 포인터를 빌려 사용하고 필요한 데이터를 복사합니다.
  • 저장소 경계: 이 저장소는 플러그인/디스패처 저장소에 대한 빌드 시 의존성을 추가해서는 안 됩니다. 통합은 인터페이스를 통해서만 이루어집니다(런타임 GstContext, 속성, 캡/메타, C-ABI 계약).

마이그레이션된 필드에 대한 해결 우선순위는 결정적입니다.

  1. 계약/런타임 신호(모양/메타/캡)에서 추론
  2. 컨텍스트/기본값/속성 경로
  3. 하드 버스 오류 (절대 중단/SIGSEGV 발생하지 않음)

StageTransformRuleRegistry (내부)는 해결기가 MLA 입력과 MLA 출력에서 텐서 계약을 상속받는 MLA가 아닌 스테이지와 출력 양자화가 전파되는 시기를 알려주는 단일 매핑 테이블입니다. 이를 통해 사전/사후 파생을 명시적이고 테스트 가능하게 유지합니다.

집계기 템플릿을 사용하는 마이그레이션된 SIMA 플러그인의 경우, 런타임 구성은 이제 컨텍스트/속성 기반 해결 방식을 따릅니다.

  1. 스테이지 정적 필드는 매니페스트 컨텍스트에서 가져옵니다.
  2. 런타임 매개변수는 속성/컨텍스트 기본값에서 가져옵니다.
  3. 해결되지 않은 필수 필드는 명시적으로 실패합니다(프레임워크에서 스테이지-JSON 폴백 없음).

simaaiprocesscvu의 경우, CM에서 파생된 배선은 먼저 추론하고 컨텍스트 sink_pad_tensor_index_map를 사용하여 결정적인 다중 입력 매핑을 수행합니다. 기존 입력 버퍼 이름은 폴백 전용으로 유지됩니다.

logical_stage_id는 제공된 경우 stage-id/stage_id 파이프라인 속성에서 해결되고, 그렇지 않으면 요소 이름으로 폴백됩니다. SIMA 모델 경로 조각 빌더는 기본적으로 stage-idsimaaiprocesscvu, simaaiprocessmlasimaaiboxdecode 요소에 설정합니다.

YOLO26 BoxDecode 클래스 수 계약

모델에서 관리하는 YOLO26 감지, 자세 및 분할 경로의 경우, MPK 클래스 헤드 깊이가 권한 있는 클래스 수입니다. Model::Options::num_classes = 0는 추론된 값을 선택합니다. 양수 값은 해당 값과 일치해야 합니다. 불일치가 발생하면 계약 구성 중에 오류가 발생하고 구성된 값, MPK에서 파생된 값 및 디코딩 유형이 보고됩니다. 이를 통해 잘못된 클래스 수가 그룹화된 원시 헤드 레이아웃을 해석하는 데 사용되지 않도록 방지합니다. SSD 및 사전 YOLO26 비-자세 YOLO 계열은 기존 명시적 재정의 동작을 유지하고, 자세 및 SuperPoint 디코더는 해당 계열별 규칙을 유지합니다.

SuperPoint BoxDecode 계약

SuperPoint는 다른 모델에서 관리하는 BoxDecode 계열과 동일한 MPK-to-static-manifest 경계를 사용하며, 다음과 같은 추가 불변 조건을 갖습니다.

  • MPK 레코드는 검출기-로짓과 디스크립터-그리드 텐서의 식별자, 저장 표현, dtype/shape 정보, 숫자 프로필 출처, 그리고 선택적인 명시적 NMS 및 경계 제어를 소유합니다. 코어는 텐서 값을 통해 이러한 역할을 식별하지 않습니다.
  • 코어는 각 역할에 정확히 하나의 텐서를 바인딩하고, 프로필 지문과 지원되는 표현을 검증하며, 명시적인 Model::Options::superpoint 재정의를 적용하고, 누락된 프로필 기본값만 해결합니다. 프로필을 변경하면 해당 프로필의 파생된 기본값이 다시 계산되지만, MPK 또는 API에서 명시적으로 작성된 제어는 유지됩니다.
  • 버전이 지정된 정적 매니페스트 ABI는 해결된 계약을 simaaiboxdecode로 전달합니다. 플러그인은 구성 중에만 매니페스트 포인터를 참조하고 런타임에 필요한 모든 상태를 복사해야 합니다. 코어는 파이프라인 수명 동안 매니페스트 소유권을 유지합니다.
  • 프로덕션 출력은 FEATURE_POINTS_V1 와이어 형식과 특징 의미 메타데이터를 사용합니다. FEATURE_POINTS_LEGACY_A65_V0는 호환성을 위해 명시적으로 선택한 경우에만 사용할 수 있습니다. 소비자는 버퍼 크기를 통해 어떤 형식인지 추론해서는 안 됩니다.

contracts/ -- 검증 규칙

목적: "gst_parse_launch가 성공했다"를 넘어 "유효한 파이프라인이 어떤 모습인지"를 인코딩합니다.

예시:

  • 검증기 인터페이스 및 레지스트리
  • 구조화된 ValidationReport

이 레이어는 CI에 사용하거나 런타임 전에 문제를 감지하는 데 사용할 수 있습니다.


policy/ -- 사용자 정의 가능한 동작

목적: 조정 가능한 매개변수(기본값, 메모리 제약 조건, 인코더/디코더/RTSP 정책 선택)를 중앙 집중화합니다.

목표는 "조정 가능한 매개변수"를 명시적이고 쉽게 찾을 수 있도록 하여 여기저기 흩어져 있는 코드에 숨겨진 상태로 두지 않는 것입니다.


모델 아카이브 통합

목적: .tar.gz 모델 아카이브를 Model을 통해 로드하고, 파싱된 MPK 추론 계약을 라우팅 가능한 그래프 조각으로 조정합니다.

안전한 아카이브 로더는 내부 구현 세부 사항입니다. 애플리케이션 코드는 Model을 구성하고 model.graph() 또는 단계별 특정 조각을 구성해야 합니다.

일반적인 사용법:

simaai::neat::Model model("resnet_50.tar.gz");
simaai::neat::Graph graph;
graph.add(model.graph());

모델 단계 조각

목적: Model에서 전처리, 추론, 후처리 또는 전체 경로를 구성하되, 내부 아카이브 로더를 노출하지 않습니다.

주요 API:

  • Model::preprocess()
  • Model::inference()
  • Model::postprocess()
  • Model::graph()

이는 전처리가 한 번 수행되고 MLA/BoxDecode가 별도의 그래프 또는 스레드에서 실행되는 하이브리드 흐름에 사용됩니다.


작업이 실행되는 위치 (CPU / CVU / MLA)

프로세서 라우팅은 MPK 계약(모델 아카이브에 정의된 CVU/MLA 단계)과 선택적인 런타임 재정의에 의해 결정됩니다.

  • Model::Options는 전처리, 후처리, 명명 및 버퍼링 옵션을 제어합니다.
  • SIMA_MLA_NEXT_CPU는 일부 구성에서 MLA의 다음 단계를 재정의할 수 있습니다.
  • 파이프라인 노드 자체는 선언적입니다. 실제 실행은 GStreamer 플러그인 및 해당 구성에서 발생합니다.

실질적인 영향: 더 많은 버퍼와 명시적인 라우팅은 처리량을 향상시킬 수 있지만, 캡 불일치 또는 버퍼 크기 부족은 협상 중에 빠르게 실패하게 됩니다.


런타임 모델 (실행 방식)

초기화

모든 런타임 진입점은 단일 안전 초기화 루틴을 호출합니다.

  • gst_init_once() (스레드 안전, std::call_once)

또한 런타임 경로는 필수 플러그인이 존재하는지 확인할 수 있습니다.

  • require_element("appsink", ...)

파이프라인 구축

GraphNode 객체와 재사용 가능한 그래프 조각을 추가하여 구축됩니다. RTSP의 경우 코덱을 인식하는 조각을 사용하여 소스가 디코딩되기 전에 언패킷되고 파싱되도록 합니다.

simaai::neat::nodes::groups::RtspDecodedInputOptions source;
source.url = "rtsp://example/live";
source.codec = simaai::neat::nodes::groups::RtspCodec::H265;
source.source_fps = 30;

simaai::neat::Graph graph;
graph.add(simaai::neat::nodes::groups::RtspDecodedInput(source));
graph.add(simaai::neat::nodes::Output());

내부적으로:

  1. 그래프는 논리적 구성 정점당 하나의 노드 객체를 강제합니다. 반복적인 connect() 호출은 팬아웃을 위해 해당 인덱싱된 정점을 재사용할 수 있습니다.

  2. 구성 변경은 단일 단위로 커밋되거나 완전히 롤백됩니다.

  3. 그래프는 각 노드에 대해 backend_fragment(i)를 요청하고 !를 사용하여 조각을 연결합니다.

  4. 선택적으로 노드 사이에 경계 마커를 삽입합니다.

    • identity name=sima_b<i> silent=true
  5. 정확한 name= 바인딩을 분석하고, GStreamer를 사용하여 한 번 파싱하고, 구성된 객체 트리를 나열합니다. 중복되거나 누락된 이름은 다운스트림 구성 전에 실패합니다.

  6. DiagCtx를 빌드합니다.

    • 재현성을 위한 node_reports
    • boundariesBoundaryFlowCounters (원자)로 사용

푸시/풀 런타임 모델

Run은 입력/출력 큐와 입력 스레드를 소유합니다.

  • push(...)는 입력 큐에 입력을 추가합니다(RunOptions::overflow_policy에 따라 차단하거나 삭제).
  • pull(...)은 앱싱크에서 Sample 출력을 큐에서 제거합니다.
  • try_push(...)는 차단되지 않습니다(큐가 가득 차면 false를 반환합니다).

이를 통해 완전한 비동기 파이프라인(생산자/소비자 분할)뿐만 아니라 단일 실행 흐름(Graph::run(...))도 지원합니다.

디코더 승인 라이프사이클

단일 파이프라인 또는 연결된 그래프 런타임을 선택하기 전에 코어는 컴파일된 실행 계획을 스캔하여 유형이 지정된 H.264/H.265 SimaDecode 노드를 찾습니다. 적격한 모든 디코더는 하나의 그룹으로 승인되며, 결과 예약은 최상위 Run에 의해 파이프라인 작업자가 중지될 때까지 소유됩니다. 이는 선형 Graph::add(...) 파이프라인, 일반 연결 세그먼트 및 융합된 실시간 분기에 동일하게 적용됩니다.

승인에는 알려진 디코더의 너비, 높이 및 프레임 속도가 필요합니다. 코어는 프레임 속도를 임의로 생성하지 않습니다. 불완전한 계약 또는 사용할 수 없는 선택적 승인 엔드포인트는 경고를 생성하고 계획을 변경하지 않습니다. SIMA_DECODER_ADMISSION_REQUIRE=1의 경우, 두 조건 중 하나라도 충족되지 않으면 디코더 하드웨어가 시작되기 전에 실패합니다. 용량 거부 및 잘못된 임대 응답은 항상 실패합니다.

실시간 팬인 감소

애플리케이션은 일반 Graph::connect(...)를 사용하여 실시간 에지를 설명하고 일반 Graph::build(...)를 사용하여 이를 구체화합니다. GraphLinkOptions는 최신-스트림 정책, 스트림 ID, 예약된 큐 깊이 필드 및 선택적 원시 프레임 승인 제한을 포함합니다. 최신-스트림 감소는 항상 스트림당 하나의 보류 중인 샘플을 유지합니다.

실행 그래프 컴파일러(애플리케이션이 아님)는 실시간 다중 소스 팬인이 단일 GStreamer 파이프라인으로 융합될 수 있는지 결정합니다. 적격한 개인 입력 없는 소스 분기는 해당 스트림별 멀티플렉서 및 소비자와 함께 감소되어 디코딩된 장치 버퍼가 앱싱크/앱소스 경계를 넘지 않도록 합니다. 부적격한 최신-스트림 토폴로지는 분할된 상태로 유지됩니다. 이미 융합된 소스 세그먼트는 해당 분기를 재귀적으로 보존할 수 있을 때까지 부적격 상태로 유지됩니다.

내부 경계 타이밍

하나의 논리적 Graph는 여러 GStreamer 파이프라인 세그먼트로 감소될 수 있습니다. 코어는 각 내부 경계에 appsrc를 삽입합니다.

주입된 경계는 전달받은 타임라인을 전송하며 타임스탬프를 직접 생성하지 않습니다. 오직 공개되고 애플리케이션 소유의 Input만이 타임스탬프를 생성합니다.

appsrc는 자체 세그먼트의 런타임에서 타임스탬프를 생성하므로, 타임스탬프를 생성하는 경계는 팬아웃의 각 부분에 서로 다른 클록을 제공합니다. 비디오 RTP는 동일한 프레임을 설명하는 모델 출력 메타데이터와 더 이상 일치하지 않으며, 어떤 애플리케이션도 이를 수정할 수 없습니다. 애플리케이션에서 선언한 Input 노드를 줄이면 InputOptions가 애플리케이션에서 설정되어도 주입된 경계에 도달하지 않습니다.

세그먼트 자료화 경로를 추가할 때:

  • 이 불변성을 위한 유일한 위치인 injected_boundary_input_options(...)를 사용하여 주입된 옵션을 빌드합니다.
  • is_live = true를 유지합니다. 이를 지우면 라이브 세그먼트가 중단됩니다.
  • 공개 InputOptions::do_timestamp의 기본값을 그대로 두고, PTS가 없는 cv::Mat가 입력 시에도 PTS를 받도록 합니다.

경계는 보존된 GstBuffer를 제로 복사 방식으로 전달하므로, 이미 존재하는 타임스탬프는 전달 과정을 거쳐도 유지됩니다. 타임스탬프 생성을 거부한다고 해서 이를 제거할 수는 없습니다.

입력 계약 전문화

일부 복합 파이프라인 노드는 둘 이상의 안전한 백엔드 표현을 가집니다. 그래프 컴파일러는 정적으로 설정된 OutputSpec에서 이러한 노드를 전문화합니다. 공개 그래프를 변경하거나 첫 번째 런타임 샘플에서 영구적인 토폴로지를 추론하지 않습니다. Derived 또는 Authoritative 계약은 최적화된 표현을 선택할 수 있습니다. Hint, 알 수 없는 형식/메모리 또는 누락된 백엔드 기능은 보수적인 표현을 선택합니다.

예를 들어, raw VideoSender는 시스템 또는 SiMaAI 메모리의 안정적인 NV12 계약에서만 NV12 변환을 생략하고, neatencoder가 읽기 전용 input-layout-aware=true 기능을 광고할 때만 생략합니다. OutputSpec는 현재 평면 스트라이드 및 오프셋을 포함하지 않으므로, 해당 기능 게이트를 우회하는 메모리 도메인은 없습니다. 누락되거나 false인 기능은 지원되지 않는 것으로 처리되므로 Core은 이전 내부 패키지와 함께 안전하게 유지됩니다.

raw 비디오의 기하학적 구조와 물리적 저장 레이아웃은 별도의 계약으로 유지됩니다. OutputSpec 및 캡스는 보이는 너비와 높이를 설명합니다. Core은 이러한 값을 코덱 블록, DMA 피치 또는 표면 높이 정렬에 맞게 반올림해서는 안 됩니다. 레이아웃 인식 플러그인은 GstVideoMeta 또는 GstVideoInfo에서 물리적 평면 오프셋 및 스트라이드를 파생시키고, 물리적 계약이 호환되지 않을 때 재포맷하며, 코덱/하드웨어 허가를 인코더 서비스에 맡깁니다. 이를 통해 정확한 디코딩된 기하학적 구조를 유지하면서 장치별 정렬을 공개 그래프 API에서 제외합니다.

파싱 및 실행

라이브러리는 주로 다음을 사용합니다.

  • gst_parse_launch(pipeline_string, &err)

이를 통해 유연성과 디버깅 가능성을 제공합니다(정확한 문자열을 gst-launch-1.0로 다시 재생할 수 있음).

실행

일반적인 흐름(Graph::build() / Run):

  1. 계약을 적용합니다(예: build() + 풀에 대한 "sink last").
  2. 파이프라인 문자열을 생성합니다(+ 선택적 경계).
  3. 파이프라인을 파싱합니다.
  4. 선택적으로 요소 이름 지정 계약을 적용합니다.
  5. 선택적 경계 프로브를 연결합니다.
  6. 파이프라인을 PLAYING 상태로 설정합니다.
  7. 푸시/풀 제어를 위한 Run 핸들을 반환합니다.

프레임의 수명 주기(일반적인 설명)

  1. 생성: 노드가 결정적인 gst-launch 문자열이 됩니다.
  2. 협상: GStreamer가 요소 간의 캡(형식, 크기, 메모리)을 협상합니다.
  3. 실행: 입력이 파이프라인으로 푸시되거나(또는 소스에서 풀됩니다).
  4. 샘플: Appsink가 Sample / Tensor를 코드에 반환합니다.
  5. 오류: 협상 또는 런타임 실패 시 NeatError와 함께 GraphReport가 발생합니다.

캡 협상은 자동으로 이루어지며, 실패는 초기에(유효성 검사/프리롤) 또는 런타임에 진단 정보를 통해 발생하며, 이를 통해 문제를 재현할 수 있습니다(describe_backend() + 보고서).

카메라 할당 소유권

CameraInput은 카메라 캡 바로 뒤에 neatcamerabridge를 배치하고, 라이브 큐 앞에 배치합니다. 협상 중에 브리지는 표준 풀을 사용하여 상위 GST_QUERY_ALLOCATION에 응답하고 GstVideoMeta를 요청합니다. 풀은 검증된 평면을 하나의 패킹된 SiMaAI 할당에서 할당하고, 평면당 하나의 DMA-BUF를 내보냅니다. 호환되는 libcamerasrc는 해당 DMA-BUF를 ISP 캡처 큐로 가져옵니다. 그런 다음 브리지는 동일한 패킹된 할당을 풀링하여 다운스트림 처리에 사용합니다. 엄격 모드에서는 해당 계약을 충족하지 않는 모든 버퍼를 거부합니다. CPU 복사는 명시적인 호환성 폴백으로 남습니다.

애플리케이션에서 사용하는 캡처 깊이는 커널의 개인 CSI-to-ISP RAW 전송 링과 후속 GStreamer 큐 모두와 독립적입니다. CameraInputWithCaptureBuffers에 대한 선택적 capture_buffer_count 인수는 ISP 출력, libcamera 및 애플리케이션을 통해 유지되는 버퍼를 제어합니다. queue_depthleaky_queue는 다운스트림 지연 시간과 프레임 삭제 정책를 별도로 제어합니다. 선택적 호환성 복사 풀은 필요에 따라 증가하며 해당 큐 깊이에 의해 제한되지 않으므로 누수 큐는 상위 브리지가 먼저 중단되지 않도록 삭제 정책을 적용할 수 있습니다.

종료

종료는 의도적으로 방어적입니다. 일부 플러그인 스택은 상태 변경 시 멈출 수 있습니다. 런타임은 호스트 프로세스/CI가 데드락되는 것을 피하는 것을 선호합니다.

일반적인 패턴은 다음과 같습니다.

  • EOS 전송
  • GST_STATE_NULL 설정
  • 객체 해제
  • 타임아웃 안전 장치 적용(필요한 경우 멈추는 대신 누수)

SimaAI 동시성

SimaAI 플러그인은 프로세스당 여러 파이프라인을 지원합니다. 여러 파이프라인을 동시에 실행하는 경우 GraphOptions 또는 Model 이름 접미사/접두사를 통해 요소 이름을 고유하게 지정하여 GStreamer 이름 충돌을 방지합니다.


제약 조건 및 안전

  • 입력 형식은 caps와 일치해야 합니다: InputOptions 및 모델 구성은 형식/너비/높이에 대해 일치해야 합니다. 불일치가 발생하면 협상 중 또는 입력이 전달될 때 즉시 오류가 발생합니다.
  • 캡슐화된 동적 입력: 런타임 재협상은 빌드된 그래프가 동적 기능을 광고할 때만 허용됩니다. FullyDynamic 그래프는 원시 비디오 지오메트리/형식/프레임 속도/미디어 caps를 재협상할 수 있습니다. IngressDynamicCvuOnly는 지오메트리 변경을 허용하고 빌드 시 다운스트림 계약 검사에서 안정적인 출력 동작이 입증될 때만 형식 변경을 허용합니다.
  • 유효한 범위 내의 동적: max_*는 엄격한 상한선입니다. max_*가 설정되지 않은 경우 width/height/depth가 암시적 상한선으로 작동합니다.
  • 모델 대 그래프 기본값: 이제 두 흐름 모두 src/pipeline/internal/InputPolicy.*를 통해 시드/최대/바이트 가드 정책을 확인합니다. Model은 여전히 문서화된 메타데이터 기반 기본값을 적용합니다(예: 1920x1080 상한선). Graph는 구성되지 않은 한 노드 옵션에 따라 작동합니다.
  • caps_override가 우선 적용됩니다: 설정된 경우 재협상이 차단되고 모양 변경에는 재빌드가 필요합니다.
흐름시드 기본값최대 기본값바이트 가드 기본값
Model(있는 경우) 전처리 메타데이터, 그렇지 않은 경우 사용자 형식/옵션에서 추론명시적 input_max_*; 그렇지 않은 경우 정책 기본값(예: 1920x1080, 형식에서 파생된 깊이)명시적 RunOptions.max_input_bytes, 그렇지 않은 경우 InputPolicy에서 파생된 제한된 추정치 또는 탄력적 기본값
Graph입력 노드 옵션 및/또는 시드 입력 샘플명시적 max_*; 그렇지 않은 경우 제공된 시드 width/height/depth에서 암시적명시적 RunOptions.max_input_bytes, 그렇지 않은 경우 InputPolicy에서 파생된 제한된 추정치 또는 탄력적 기본값
  • SimaAI 동시성: 여러 파이프라인을 프로세스 내에서 실행할 수 있습니다. 요소 이름을 고유하게 유지하십시오.

프레임별 속성 전파

소스는 Sample::attributesGstSimaMeta의 중첩 구조로 연결합니다. 버퍼를 유지하는 요소는 메타데이터를 자연스럽게 전달합니다. 버퍼를 할당하거나 재사용하는 핵심 경계는 속성을 깊이 복사하고 오래된 값을 지웁니다. neatdecoder는 디코딩 전에 동일한 프레임 컨텍스트를 스냅샷으로 저장하고 데몬에서 제공하는 상관 관계 ID로 복원하므로 순서가 변경되거나 삭제된 프레임은 속성을 다른 출력으로 이동할 수 없습니다. 협상된 디코더/데몬 프로토콜은 해당 상관 관계 계약을 소유합니다. 레거시 디코더 프로토콜은 FIFO 전용으로 유지됩니다.

지원되는 사용자 인터페이스 경로 및 제한 사항은 프레임별 속성에 설명되어 있습니다.


스레딩 및 소유권 모델

스레드

  • GStreamer 스트리밍 스레드: 패드 프로브, 디코딩, 스케줄링
  • 사용자 스레드: appsink 폴링 + 주기적 버스 비우기
  • RTSP 서버 스레드: gst-rtsp-server 모드의 GLib 메인 루프

소유권 규칙(GStreamer 객체)

  • GStreamer 객체는 참조 횟수를 사용합니다.
  • GstObject*를 획득한 범위를 벗어나 저장하는 경우, 해당 객체를 gst_object_ref()해야 합니다.
  • 완료되면 항상 정확히 한 번 gst_object_unref()를 호출해야 합니다.

진단 스레드 안전성 (중요)

패드 프로브는 스트리밍 스레드에서 실행되므로, 프로브에서 업데이트된 진단 정보는 잠금 없이 사용할 수 있어야 합니다.

설계는 다음과 같습니다.

  • BoundaryFlowCounters원자 변수를 저장합니다.
  • 패드 프로브는 원자 fetch_add() / store() 연산만 수행합니다.
  • 보고는 BoundaryFlowCounters::snapshot()을 사용하여 원자 변수를 BoundaryFlowStats (일반 정수)로 변환합니다.

이를 통해 데이터 경쟁을 방지하면서 프로브의 성능을 유지합니다.


진단 및 관측 가능성

DiagCtx는 다음을 캡처합니다.

  • 파이프라인 문자열 (재현용)
  • 노드 보고서 (각 노드가 생성한 내용)
  • 버스 메시지 (뮤텍스 사용)
  • 경계 흐름 카운터 (원자 변수)
  • 요소 타이밍 + 흐름 카운터 (원자 변수)

경계 흐름 프로브

활성화되면 런타임은 경계 identity 요소에 패드 프로브를 연결합니다. 다음 사항을 추적합니다.

  • 버퍼 수 (입력/출력)
  • 마지막으로 확인된 PTS (ns)
  • 마지막으로 확인된 월 타임 (단조 증가 시간, us)

이는 "가능성 있는 정체" 요약을 생성하는 데 사용됩니다.

  • "마지막으로 경계 X에서 활동이 T 시점에 시작/종료되는 것을 확인했습니다."

요소 타이밍 프로브

활성화되면 (SIMA_GST_ELEMENT_TIMINGS=1), 런타임은 각 요소의 모든 패드 (정적, 동적 및 요청)에 싱크 + 소스 패드 프로브를 연결하고 src_ts - sink_ts를 버퍼별로 기록합니다. 이를 통해 플러그인 계측에 의존하지 않고 요소별 계산 시간을 얻을 수 있습니다.

버퍼를 대체하는 요소의 경우, 구현은 GstSimaMeta 상관 관계 (프레임 ID/스트림 ID)로 대체하고 missed_in/missed_out 카운터를 기록합니다.

요소 흐름 프로브

활성화되면 (SIMA_GST_FLOW_DEBUG=1), 런타임은 요소별 패드 프로브를 연결하여 버퍼/바이트 수 및 캡 변경 사항을 추적하고, 그래프의 모든 플러그인에 대한 처리량 컨텍스트를 제공합니다.

버스 로깅 및 오류

런타임은 버스 메시지를 DiagCtx로 드레인합니다. 오류 메시지 (GST_MESSAGE_ERROR)가 발생하면 NeatError를 발생시키고, 여기에는 GraphReport 및 재현 힌트가 포함됩니다.

DOT 덤프

활성화되면 런타임은 gst_debug_bin_to_dot_file_with_ts(...)를 통해 구성된 디렉터리에 DOT 그래프를 출력할 수 있습니다.

디버깅 플레이북 (프로덕션)

  1. 파이프라인 재현: Graph::describe_backend() 또는 last_pipeline().
  2. 보고서 캡처: MeasureReport::to_text() 또는 NeatError::report().
  3. 대상 프로브 활성화:
    • SIMA_GST_BOUNDARY_PROBES=1: 정체 위치 파악
    • SIMA_GST_ELEMENT_TIMINGS=1: 요소별 타이밍
    • SIMA_GST_FLOW_DEBUG=1: 요소별 흐름 카운터
  4. DOT 그래프 생성: SIMA_GST_DOT_DIR을 설정하고 재현합니다.
  5. 검증 강화: SIMA_GST_ENFORCE_NAMES=1 및 프리롤 시간 초과 검증.

출력 처리

Run::pull()Sample을 반환하며, 여기에는 다음이 포함될 수 있습니다.

  • Tensor 페이로드 (SampleKind::Tensor)
  • 여러 출력의 번들 (SampleKind::Bundle)

텐서 페이로드를 사용하고 전체 Sample 엔벨로프를 사용하지 않으려는 경우, ML 중심 워크플로에 대해 Run::pull_tensors(...)를 사용합니다.


파이프라인 직렬화(저장/로드)

파이프라인은 JSON으로 저장하고 복원할 수 있습니다.

  • Graph::save(path)는 노드 유형/레이블/프래그먼트/요소를 포함하는 버전이 지정된 JSON을 작성합니다.
  • Graph::load(path)ConfiguredNode 래퍼를 통해 노드를 다시 생성합니다.

현재 스키마는 의도적으로 최소화되고 재현 가능하며, 나중에 더 풍부한 노드 구성으로 발전할 수 있습니다. 또한 이는 향후 바인딩 및 도구에 대한 브리지 역할을 합니다.


UX 도우미

  • Graph::describe()GraphPrinter를 사용하여 사람이 읽을 수 있는 노드 목록을 렌더링합니다.
  • Graph::describe_backend()는 빠른 디버깅을 위해 gst-launch 문자열을 반환합니다.

요소 이름 지정 및 결정성

결정적인 요소 이름은 핵심 설계 원칙이며, 이를 통해 다음이 가능합니다.

  • 싱크 및 핵심 요소에 대한 gst_bin_get_by_name()
  • 안정적인 프로브 연결
  • 안정적인 진단 및 재현성
  • 선택적인 이름 지정 계약 적용("모든 요소는 일부 노드에 속함")

노드 작성자는 다음을 보장해야 합니다.

  • 요소가 검색 가능해야 하는 경우 프래그먼트에는 안정적인 name= 필드가 포함되어야 합니다.
  • element_names()는 프래그먼트가 생성하는 모든 명시적 요소 이름을 반환해야 합니다.
  • 선언 및 명명된 패드 참조는 동기화된 상태를 유지해야 합니다.

이름의 무결성은 build()의 일부이며, 이전 validate() 호출에 의존하지 않습니다. 이름은 재귀적 짧은 이름을 사용하는 프레임워크 조회 때문에 하나의 구체화된 파이프라인 세그먼트 내에서 고유합니다. 별도로 구문 분석된 연결된 세그먼트는 동일한 이름을 재사용할 수 있습니다. 프레임워크는 이름이 패드 및 라우팅 표현식에 참여할 수 있기 때문에 이름을 변경하는 대신 충돌을 거부합니다.

입력에 따라 연결된 세그먼트는 첫 번째 입력에서 구체화될 수 있습니다. 따라서 빌드 실패는 첫 번째 push() 또는 pull()에서 보고되며, 원래 GraphReport가 보존됩니다.


스테이지 이름 지정 및 연결

프레임워크는 이제 플러그인 JSON을 플러그인 소유 데이터로 처리하며, 파이프라인 빌드 중에 스테이지별 JSON 필드를 다시 작성하거나 검증하지 않습니다.

연결의 단일 진실 공급원:

  1. 노드 프래그먼트의 결정적인 GStreamer 요소 이름.
  2. SIMA 모델 경로 요소의 stage-id.
  3. 정적 스테이지/텐서 계약 조회를 위한 sima.model.manifest.v1 컨텍스트.

시사점:

  • 빌드는 더 이상 node_name / input_buffers[*].name / buffers.input[*].name를 변경하지 않습니다.
  • 빌드는 더 이상 JSON 기반 연결 검사를 수행하지 않습니다.
  • 이름 변환은 여전히 요소 이름에만 적용됩니다.

모델 관리 그래프 실행의 경우, 스테이지 확인은 stage-id + 매니페스트 컨텍스트에 의해 수행됩니다. 모델이 아닌 그래프 실행의 경우, 명시적 플러그인 속성이 런타임 제어 평면입니다.


검증 및 계약

검증은 런타임보다 일찍 문제를 감지하기 위해 존재합니다.

  • validate()는 구문 분석하고 사전 롤링(PAUSED)하여 협상 정체를 감지할 수 있습니다.
  • contracts/는 "파이프라인 정확성"에 대한 구조화된 검증기를 제공합니다.

필수적인 최종 런타임 이름 검사도 일반적인 빌드 경로에서 실행됩니다. ValidateOptions는 이름 무결성이 적용되는지 여부가 아닌, 추가적인 검증 작업을 제어합니다.

연결된 그래프의 경우, validate()는 엔드포인트 토폴로지를 컴파일하지만 입력에 따라 달라지는 세그먼트에 대한 런타임 문자열을 생성하지 않습니다. 각 세그먼트는 실제 입력 계약이 사용 가능하고 세그먼트가 구체화될 때 필수적인 검사를 받습니다.

의도된 동작:

  • 런타임 흐름은 치명적인 오류가 발생하면 예외를 발생시킵니다.
  • 검증 흐름은 구조화된 보고서를 반환합니다(CI에 적합).

SSD BoxDecode 계약 해결

SSD 모델 패키지는 그래프 컴파일 중에 정확한 수술 후 헤드 계약의 개인 레지스트리를 기준으로 검증됩니다. 해결기는 모든 순서가 지정된 논리적 위치 및 신뢰도 H/W/C 모양을 비교합니다. 레벨을 정렬하거나, 모델 이름을 사용하거나, 일반적인 SSD와 유사한 대체 방식을 허용하지 않습니다. 현재 등록된 레시피는 SSD300-v1, SSD-Mobile-300-v1, SSD-Mobile-320-v1 및 SSDlite-Mobile-320-v1입니다.

해결된 레시피는 점수 활성화, 신뢰도 채널 순서, 배경 클래스, 허용되는 클래스 선택, 필수 300x300 또는 320x320 모델 프레임 및 Stretch 전처리 방식을 소유합니다. 코어는 레시피를 내부 SsdRecipeId로 저장합니다. 공개 및 플러그인 ABI 디코딩 유형은 BoxDecodeType::Ssd / ssd로 유지되며, 이는 배포된 객체 디코더에서 지원하는 토큰입니다. 지원되지 않거나 잘못된 헤드 지오메트리, 충돌하는 활성화, 유효하지 않은 클래스 선택, Stretch가 아닌 크기 조정 또는 잘못된 모델 프레임은 파이프라인 시작 전에 실패합니다. 레시피 검색은 컴파일 시간에만 수행되며 프레임별 작업은 추가되지 않습니다.


RTSP 서버 모드

run_rtsp()gst-rtsp-server를 사용합니다.

  • 서버는 전용 스레드에서 GLib 메인 루프와 함께 실행됩니다.
  • media-configure에서 코드는 이름을 기준으로 appsrc를 찾고 캡/속성을 구성합니다.
  • 프레임은 명시적인 타임스탬프와 함께 주기적으로(타이머 기반) 푸시됩니다.

각 클라이언트는 팩토리 구성에 따라 자체 미디어 인스턴스를 가질 수 있습니다.


환경/구성 노브

런타임은 환경 기반 디버깅 노브를 지원합니다.

  • SIMA_GST_DOT_DIR -- 실패/디버그에 대한 DOT 그래프 작성
  • SIMA_GST_BOUNDARY_PROBES -- 경계 흐름 카운터 활성화
  • SIMA_GST_STAGE_TIMINGS -- 단계 타이밍 프로브 활성화
  • SIMA_GST_ELEMENT_TIMINGS -- 요소 타이밍 프로브 활성화
  • SIMA_GST_FLOW_DEBUG -- 요소별 흐름 카운터 활성화
  • SIMA_GST_ENFORCE_NAMES -- 명명 계약 적용
  • SIMA_GST_RUN_INPUT_TIMEOUT_MS -- 런/빌드 입력 경로에 대한 입력 타임아웃
  • SIMA_GST_VALIDATE_TIMEOUT_MS -- 프리롤에 대한 검증 타임아웃
  • SIMA_GST_VALIDATE_INSERT_BOUNDARIES -- 검증() 중에 경계 삽입
  • SIMA_GST_RUN_INSERT_BOUNDARIES -- 빌드/런() 중에 경계 삽입
  • SIMA_GST_TEARDOWN_TIMEOUT_MS -- NULL 상태까지 대기(ms)
  • SIMA_GST_TEARDOWN_REAPER_MS -- 리퍼 재시도 간격(ms)
  • SIMA_GST_TEARDOWN_ASYNC -- 대기 건너뛰기, 리퍼에 위임

이러한 설정은 의도적으로 공개 API 외부에 있으므로 재컴파일하지 않고 CI 환경이나 실제 환경에서 활성화할 수 있습니다. src/pipeline/internal/*에는 추가적인 저수준 디버그 플래그가 있습니다(입력 스트림 로깅, 샘플 덤프, 풀 디버그). 깊이 있는 진단이 필요하지 않은 경우 사용자에게 제공되는 문서에는 이러한 플래그를 포함하지 마십시오.


PCIe 호스트 런타임 경계

별도로 패키징된 PCIe 호스트 API에는 두 가지 공개 레벨이 있습니다.

  • pcie::Model은 단일 모델에 대한 소스 호환 편리 API입니다.
  • pcie::Runtime은 얇은 OAAX C ABI 어댑터를 지원하기 위해 설계된 카드 범위의 다중 모델 코디네이터입니다.

런타임은 논리적 모델 ID, 호출자가 제공하는 요청 ID, 논블로킹 큐잉, 모든 모델에서 검색, 일괄 로드, 독립적인 언로드 및 멱등성 정리 기능을 제공합니다. 하드웨어 큐 ID는 구현 세부 정보로 유지됩니다. 현재 Modalix 구현은 각 PCIe 큐에 정확히 하나의 로드된 모델을 할당하고 가상 이더넷 SSH/SCP 제어 경로를 통해 모델 아카이브를 계속 전송합니다.

추론 요청 상관 관계는 PCIe/카드 왕복 통신에서 GstSimaHostMeta.frame-id에 인코딩된 부호 있는 32비트 OAAX 요청 ID를 사용합니다. 비트 패턴은 불투명하며 공개 완료 시 변경되지 않은 상태로 복원해야 합니다. 런타임은 모델-큐 레지스트리를 소유하고 각 큐의 결과를 집계합니다. 카드 측 pcie-pipeline-builder는 큐당 하나의 프로세스와 하나의 모델 그래프로 유지됩니다.

카드 전송은 레거시 이름의 GstSimaMeta.pcie-buffer-id 필드에 별도의 개인 요청 토큰을 포함합니다. 이는 정확한 드라이버 요청 및 진행 중인 크레딧을 식별합니다. 일반 플러그인은 변경되지 않은 상태로 전달할 수 있지만 검사하거나 생성해서는 안 됩니다. stream-id는 출력 라우팅 키로 유지되고, frame-id는 애플리케이션 상관 관계 키로 유지됩니다. neatpciesink만 요청 토큰을 확인합니다. 성공적인 작업은 DATA 응답을 반환합니다. 디코더 삭제, 플러시, 재시작 또는 다운스트림 오류가 발생하면 상관 관계가 있는 NEAT_PCIE_FRAME_RETURN_ERROR가 반환되어 동일한 호스트 크레딧이 해제되고 영향을 받는 호스트 파이프라인이 차단 상태로 두는 대신 실행 가능한 오류와 함께 종료됩니다.

표준화된 OAAX runtime_* C 심볼은 이 기본 API 위에 있는 어댑터 경계입니다. OAAX 소유권 규칙, 상태 코드 및 마지막 오류 저장소는 C++ API 대신 해당 어댑터에 속합니다.


라이브러리 확장 방법

새 노드 추가

  1. include/nodes/<category>/<YourNode>.h에 헤더 파일을 만듭니다.

  2. src/nodes/<category>/<YourNode>.cpp에 구현합니다.

  3. 다음을 확인합니다.

    • backend_fragment(i)가 유효하고 결정적입니다.
    • 모든 중요한 요소가 이름이 지정되고 element_names(i)에 의해 반환됩니다.
  4. 테스트를 추가합니다(이상적으로 다음 중 하나):

    • 파싱/유효성 검사 테스트
    • 간단한 소스/싱크 파이프라인을 사용하여 실행/빌드 테스트

런타임 진단 추가

  • DiagCtxGraphReport에 필드를 추가하는 것을 선호합니다.
  • 스트리밍 스레드에서 업데이트가 발생하는 경우 원자(atomics)(또는 다른 잠금 없는 메커니즘)을 사용합니다.
  • 보고를 위해 일반 스냅샷 유형으로 변환합니다.

종속성 규칙(협상 불가)

  • builder/는 GStreamer 또는 pipeline/에 의존해서는 안 됩니다.
  • gst/pipeline/에 의존해서는 안 됩니다.
  • nodes/pipeline/에 의존해서는 안 됩니다(노드는 런타임 오케스트레이터가 아닌 빌드 시 설명입니다).
  • pipeline/은 오케스트레이터이며 gst/, builder/, nodes/, contracts/, policy/, 모델 내부 요소에 의존할 수 있습니다.

이렇게 하면 아키텍처의 모듈성을 유지하고 순환 종속성을 방지할 수 있습니다.


테스트 및 예제

  • examples/는 일반적인 엔드투엔드 사용 패턴을 보여줍니다.

    • RTSP 디코딩
    • 모델 아카이브 실행
    • RTSP 서버 실행
  • tests/는 중요한 동작을 확인합니다.

    • 파일 읽기 경로
    • 그룹 확장 동등성(입력 그룹)
    • 텐서 출력 경로 + 저장/로드 왕복 테스트
    • model_resnet50_multi_test는 여러 그래프/런 인스턴스를 사용하여 모델 정확도를 검증합니다.

기능을 추가할 때 다음을 수행하는 테스트를 추가하는 것이 좋습니다.

  • 파이프라인 문자열을 결정적으로 재현합니다.
  • 캡스 협상 가정을 검증합니다.
  • 오류 발생 시 유용한 GraphReport 진단 정보를 생성하도록 합니다.

문서 일관성 유지

문서와 코드를 일관되게 유지합니다.

  • 공개 헤더(include/*)를 변경하는 경우 README 및 아키텍처를 업데이트합니다.
  • 표준 프로덕션 파이프라인 테스트(tests/e2e_pipelines/obj_detection/sync_yolov8_test.cpp)를 변경하는 경우 문서 모두를 업데이트합니다.
  • 새 환경 매개변수를 추가하는 경우 "환경/구성 매개변수" 섹션에 추가합니다.

설계 원칙

  1. 결정성이 최우선

    • 안정적인 요소 이름, 안정적인 파이프라인 문자열, 안정적인 보고서
  2. 디버깅 용이성이 최우선

    • 버스 로그, DOT 덤프, 경계 프로브, 명확한 재현 단계
  3. 안전한 동시성

    • 스트리밍 스레드 프로브는 원자 변수에만 액세스합니다(스냅샷은 일반 보고서를 생성합니다).
  4. 프로세스를 중단시키지 않음

    • 정리 작업은 방어적입니다. 손상된 플러그인 스택에서 영원히 차단되는 것을 방지합니다.
  5. 공개 API를 안정적으로 유지

    • 내부 리팩토링은 의도적으로 버전 관리를 하지 않는 한 사용자 코드를 중단해서는 안 됩니다.