From 20d14b51fe40bafd3462e1b6d8e58c24bf596c17 Mon Sep 17 00:00:00 2001 From: "Neil R. Spruit" Date: Tue, 2 Dec 2025 11:51:40 -0800 Subject: [PATCH] feature: Add zelGetTracingLayerState to query if tracing is enabled Signed-off-by: Neil R. Spruit --- doc/loader_api.md | 14 +++ include/loader/ze_loader.h | 22 ++++ source/lib/ze_lib.cpp | 30 ++++++ test/CMakeLists.txt | 38 +++++++ test/loader_api.cpp | 215 +++++++++++++++++++++++++++++++++++++ 5 files changed, 319 insertions(+) diff --git a/doc/loader_api.md b/doc/loader_api.md index 2da1a96f..6a38dc3f 100644 --- a/doc/loader_api.md +++ b/doc/loader_api.md @@ -50,3 +50,17 @@ Disables the tracing layer intercepts at runtime by restoring the previous call This does not unload the tracing layer library such that one can call `zelEnableTracingLayer` and `zelDisableTracingLayer` as many times one needs to during the application. NOTE: The each call to `zelEnableTracingLayer` tracks a reference count of how many calls to enable have been seen. The Tracing Layer intercepts will not be removed until the reference count has reached 0 indicating that all users of the tracing layer have called `zelDisableTracingLayer`. + +### zelGetTracingLayerState + +Queries the current enabled state of the tracing layer at runtime. + +This function allows applications to check whether the tracing layer is currently active, returning the state through a boolean pointer. + +- __*enabled__ Pointer to a boolean that will be set to `true` if the tracing layer is currently enabled, or `false` if it is disabled. + +The function returns: +- `ZE_RESULT_SUCCESS` on successful query +- `ZE_RESULT_ERROR_INVALID_NULL_POINTER` if the `enabled` pointer is null + +This is a read-only, thread-safe operation that can be called multiple times concurrently. The tracing layer state is global to the process and reflects the current reference count maintained by `zelEnableTracingLayer` and `zelDisableTracingLayer` - the layer is considered enabled when the reference count is greater than zero. diff --git a/include/loader/ze_loader.h b/include/loader/ze_loader.h index 5b6261e2..e2f79a18 100644 --- a/include/loader/ze_loader.h +++ b/include/loader/ze_loader.h @@ -135,6 +135,28 @@ zelRegisterTeardownCallback( ZE_DLLEXPORT ze_result_t ZE_APICALL zelDisableTracingLayer(); +/** + * @brief Retrieves the current enabled state of the Level Zero tracing layer. + * + * This function queries whether the tracing layer is active and writes the result + * to the provided boolean pointer. + * + * @param enabled + * Pointer to a boolean that will be set to true if the tracing layer is + * currently enabled, or false if it is disabled. Must be a valid, non-null + * pointer. + * + * @return + * ZE_RESULT_SUCCESS on success. + * ZE_RESULT_ERROR_INVALID_NULL_POINTER if `enabled` is null. + * Other ze_result_t error codes may be returned for implementation-specific failures. + * + * @note The tracing layer state is global to the process. The function is read-only + * and thread-safe; multiple callers can query the state concurrently. + */ +ZE_DLLEXPORT ze_result_t ZE_APICALL +zelGetTracingLayerState(bool* enabled); // Pointer to bool to receive tracing layer state + #if defined(__cplusplus) } // extern "C" #endif diff --git a/source/lib/ze_lib.cpp b/source/lib/ze_lib.cpp index bfeffd07..5c888730 100644 --- a/source/lib/ze_lib.cpp +++ b/source/lib/ze_lib.cpp @@ -587,6 +587,36 @@ zelEnableTracingLayer() return ZE_RESULT_SUCCESS; } +ze_result_t ZE_APICALL +zelGetTracingLayerState +( + bool* enabled // Pointer to bool to receive tracing layer state +) +{ + if (enabled == nullptr) { + return ZE_RESULT_ERROR_INVALID_NULL_POINTER; + } + #ifdef L0_STATIC_LOADER_BUILD + if(nullptr == ze_lib::context->loader) + return ZE_RESULT_ERROR_UNINITIALIZED; + typedef ze_result_t (ZE_APICALL *zelGetTracingLayerStateInternal_t)(bool* enabled); + auto getDynamicTracingState = reinterpret_cast( + GET_FUNCTION_PTR(ze_lib::context->loader, "zelGetTracingLayerState") ); + return getDynamicTracingState(enabled); + #else + if (ze_lib::context->dynamicTracingSupported == false) { + return ZE_RESULT_ERROR_UNSUPPORTED_FEATURE; + } + if (loader::context) { + *enabled = loader::context->tracingLayerEnabled; + } + if (!*enabled) { + *enabled = (ze_lib::context->tracingLayerEnableCounter.load() > 0); + } + #endif + return ZE_RESULT_SUCCESS; +} + ze_result_t ZE_APICALL zelDisableTracingLayer() { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7c77e35f..bd28e2d8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -191,6 +191,42 @@ endif() add_test(NAME tests_loader_teardown_check COMMAND tests --gtest_filter=*GivenLoaderNotInDestructionStateWhenCallingzelCheckIsLoaderInTearDownThenFalseIsReturned) set_property(TEST tests_loader_teardown_check PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1") +add_test(NAME tests_tracing_layer_state_null_pointer COMMAND tests --gtest_filter=*TracingLayerState.GivenNullPointerWhenCallingzelGetTracingLayerStateThenErrorInvalidNullPointerIsReturned) +set_property(TEST tests_tracing_layer_state_null_pointer PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1") + +add_test(NAME tests_tracing_layer_state_valid_pointer COMMAND tests --gtest_filter=*TracingLayerState.GivenValidPointerWhenCallingzelGetTracingLayerStateThenSuccessIsReturned) +set_property(TEST tests_tracing_layer_state_valid_pointer PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1") + +add_test(NAME tests_tracing_layer_state_not_enabled COMMAND tests --gtest_filter=*TracingLayerState.GivenTracingLayerNotEnabledWhenCallingzelGetTracingLayerStateThenFalseIsReturned) +set_property(TEST tests_tracing_layer_state_not_enabled PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1") + +add_test(NAME tests_tracing_layer_state_enabled COMMAND tests --gtest_filter=*TracingLayerState.GivenTracingLayerEnabledWhenCallingzelGetTracingLayerStateThenTrueIsReturned) +set_property(TEST tests_tracing_layer_state_enabled PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1") + +add_test(NAME tests_tracing_layer_state_enabled_then_disabled COMMAND tests --gtest_filter=*TracingLayerState.GivenTracingLayerEnabledThenDisabledWhenCallingzelGetTracingLayerStateThenFalseIsReturned) +set_property(TEST tests_tracing_layer_state_enabled_then_disabled PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1") + +add_test(NAME tests_tracing_layer_state_multiple_enable COMMAND tests --gtest_filter=*TracingLayerState.GivenMultipleEnableCallsWhenCallingzelGetTracingLayerStateThenTrueIsReturned) +set_property(TEST tests_tracing_layer_state_multiple_enable PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1") + +add_test(NAME tests_tracing_layer_state_multiple_enable_partial_disable COMMAND tests --gtest_filter=*TracingLayerState.GivenMultipleEnableAndPartialDisableWhenCallingzelGetTracingLayerStateThenTrueIsReturned) +set_property(TEST tests_tracing_layer_state_multiple_enable_partial_disable PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1") + +add_test(NAME tests_tracing_layer_state_multiple_calls_enabled COMMAND tests --gtest_filter=*TracingLayerState.GivenMultipleCallsTozelGetTracingLayerStateWhenTracingEnabledThenAllReturnTrue) +set_property(TEST tests_tracing_layer_state_multiple_calls_enabled PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1") + +add_test(NAME tests_tracing_layer_state_multiple_calls_disabled COMMAND tests --gtest_filter=*TracingLayerState.GivenMultipleCallsTozelGetTracingLayerStateWhenTracingDisabledThenAllReturnFalse) +set_property(TEST tests_tracing_layer_state_multiple_calls_disabled PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1") + +add_test(NAME tests_tracing_layer_state_enabled_via_environment COMMAND tests --gtest_filter=*TracingLayerState.GivenTracingLayerEnabledViaEnvironmentWhenCallingzelGetTracingLayerStateThenTrueIsReturned) +set_property(TEST tests_tracing_layer_state_enabled_via_environment PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1") + +add_test(NAME tests_tracing_layer_state_enabled_via_environment_and_dynamic COMMAND tests --gtest_filter=*TracingLayerState.GivenTracingLayerEnabledViaEnvironmentWhenCallingzelEnableTracingLayerThenStateRemainsTrue) +set_property(TEST tests_tracing_layer_state_enabled_via_environment_and_dynamic PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1") + +add_test(NAME tests_tracing_layer_state_enabled_via_environment_disable_dynamic COMMAND tests --gtest_filter=*TracingLayerState.GivenTracingLayerEnabledViaEnvironmentAndDynamicallyWhenDisablingDynamicTracingThenStateRemainsTrue) +set_property(TEST tests_tracing_layer_state_enabled_via_environment_disable_dynamic PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1") + add_test(NAME test_zello_world_legacy COMMAND zello_world --enable_legacy_init --enable_null_driver --force_loader_intercepts --enable_validation_layer --enable_tracing_layer --enable_tracing_layer_runtime) set_property(TEST test_zello_world_legacy PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1") @@ -650,6 +686,8 @@ else() set_property(TEST init_driver_unit_tests PROPERTY ENVIRONMENT "ZE_ENABLE_LOADER_DEBUG_TRACE=1;ZE_ENABLE_NULL_DRIVER=1;") endif() + + # These tests are currently not supported on Windows. The reason is that the std::cerr is not being redirected to a pipe in Windows to be then checked against the expected output. if(NOT MSVC) add_test(NAME tests_event_deadlock COMMAND tests --gtest_filter=*GivenLevelZeroLoaderPresentWhenCallingzeCommandListAppendMemoryCopyWithCircularDependencyOnEventsThenValidationLayerPrintsWarningOfDeadlock*) diff --git a/test/loader_api.cpp b/test/loader_api.cpp index e2a70837..c80e23ab 100644 --- a/test/loader_api.cpp +++ b/test/loader_api.cpp @@ -411,6 +411,221 @@ TEST( EXPECT_FALSE(zelCheckIsLoaderInTearDown()); } +TEST( + TracingLayerState, + GivenNullPointerWhenCallingzelGetTracingLayerStateThenErrorInvalidNullPointerIsReturned) { + + EXPECT_EQ(ZE_RESULT_ERROR_INVALID_NULL_POINTER, zelGetTracingLayerState(nullptr)); +} + +TEST( + TracingLayerState, + GivenValidPointerWhenCallingzelGetTracingLayerStateThenSuccessIsReturned) { + + uint32_t pCount = 0; + ze_init_driver_type_desc_t desc = {ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC}; + desc.flags = UINT32_MAX; + desc.pNext = nullptr; + EXPECT_EQ(ZE_RESULT_SUCCESS, zeInitDrivers(&pCount, nullptr, &desc)); + bool enabled = false; + EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetTracingLayerState(&enabled)); +} + +TEST( + TracingLayerState, + GivenTracingLayerNotEnabledWhenCallingzelGetTracingLayerStateThenFalseIsReturned) { + + uint32_t pCount = 0; + ze_init_driver_type_desc_t desc = {ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC}; + desc.flags = UINT32_MAX; + desc.pNext = nullptr; + EXPECT_EQ(ZE_RESULT_SUCCESS, zeInitDrivers(&pCount, nullptr, &desc)); + bool enabled = true; + EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetTracingLayerState(&enabled)); + EXPECT_FALSE(enabled); +} + +TEST( + TracingLayerState, + GivenTracingLayerEnabledWhenCallingzelGetTracingLayerStateThenTrueIsReturned) { + + uint32_t pCount = 0; + ze_init_driver_type_desc_t desc = {ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC}; + desc.flags = UINT32_MAX; + desc.pNext = nullptr; + EXPECT_EQ(ZE_RESULT_SUCCESS, zeInitDrivers(&pCount, nullptr, &desc)); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelEnableTracingLayer()); + bool enabled = false; + EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetTracingLayerState(&enabled)); + EXPECT_TRUE(enabled); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelDisableTracingLayer()); +} + +TEST( + TracingLayerState, + GivenTracingLayerEnabledThenDisabledWhenCallingzelGetTracingLayerStateThenFalseIsReturned) { + + uint32_t pCount = 0; + ze_init_driver_type_desc_t desc = {ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC}; + desc.flags = UINT32_MAX; + desc.pNext = nullptr; + EXPECT_EQ(ZE_RESULT_SUCCESS, zeInitDrivers(&pCount, nullptr, &desc)); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelEnableTracingLayer()); + bool enabled = false; + EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetTracingLayerState(&enabled)); + EXPECT_TRUE(enabled); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelDisableTracingLayer()); + enabled = true; + EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetTracingLayerState(&enabled)); + EXPECT_FALSE(enabled); +} + +TEST( + TracingLayerState, + GivenMultipleEnableCallsWhenCallingzelGetTracingLayerStateThenTrueIsReturned) { + + uint32_t pCount = 0; + ze_init_driver_type_desc_t desc = {ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC}; + desc.flags = UINT32_MAX; + desc.pNext = nullptr; + EXPECT_EQ(ZE_RESULT_SUCCESS, zeInitDrivers(&pCount, nullptr, &desc)); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelEnableTracingLayer()); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelEnableTracingLayer()); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelEnableTracingLayer()); + bool enabled = false; + EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetTracingLayerState(&enabled)); + EXPECT_TRUE(enabled); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelDisableTracingLayer()); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelDisableTracingLayer()); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelDisableTracingLayer()); +} + +TEST( + TracingLayerState, + GivenMultipleEnableAndPartialDisableWhenCallingzelGetTracingLayerStateThenTrueIsReturned) { + + uint32_t pCount = 0; + ze_init_driver_type_desc_t desc = {ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC}; + desc.flags = UINT32_MAX; + desc.pNext = nullptr; + EXPECT_EQ(ZE_RESULT_SUCCESS, zeInitDrivers(&pCount, nullptr, &desc)); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelEnableTracingLayer()); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelEnableTracingLayer()); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelEnableTracingLayer()); + bool enabled = false; + EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetTracingLayerState(&enabled)); + EXPECT_TRUE(enabled); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelDisableTracingLayer()); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetTracingLayerState(&enabled)); + EXPECT_TRUE(enabled); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelDisableTracingLayer()); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetTracingLayerState(&enabled)); + EXPECT_TRUE(enabled); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelDisableTracingLayer()); + enabled = true; + EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetTracingLayerState(&enabled)); + EXPECT_FALSE(enabled); +} + +TEST( + TracingLayerState, + GivenMultipleCallsTozelGetTracingLayerStateWhenTracingEnabledThenAllReturnTrue) { + + uint32_t pCount = 0; + ze_init_driver_type_desc_t desc = {ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC}; + desc.flags = UINT32_MAX; + desc.pNext = nullptr; + EXPECT_EQ(ZE_RESULT_SUCCESS, zeInitDrivers(&pCount, nullptr, &desc)); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelEnableTracingLayer()); + bool enabled1 = false, enabled2 = false, enabled3 = false; + EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetTracingLayerState(&enabled1)); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetTracingLayerState(&enabled2)); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetTracingLayerState(&enabled3)); + EXPECT_TRUE(enabled1); + EXPECT_TRUE(enabled2); + EXPECT_TRUE(enabled3); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelDisableTracingLayer()); +} + +TEST( + TracingLayerState, + GivenMultipleCallsTozelGetTracingLayerStateWhenTracingDisabledThenAllReturnFalse) { + + uint32_t pCount = 0; + ze_init_driver_type_desc_t desc = {ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC}; + desc.flags = UINT32_MAX; + desc.pNext = nullptr; + EXPECT_EQ(ZE_RESULT_SUCCESS, zeInitDrivers(&pCount, nullptr, &desc)); + bool enabled1 = true, enabled2 = true, enabled3 = true; + EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetTracingLayerState(&enabled1)); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetTracingLayerState(&enabled2)); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetTracingLayerState(&enabled3)); + EXPECT_FALSE(enabled1); + EXPECT_FALSE(enabled2); + EXPECT_FALSE(enabled3); +} + +TEST( + TracingLayerState, + GivenTracingLayerEnabledViaEnvironmentWhenCallingzelGetTracingLayerStateThenTrueIsReturned) { + + uint32_t pCount = 0; + ze_init_driver_type_desc_t desc = {ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC}; + desc.flags = UINT32_MAX; + desc.pNext = nullptr; + putenv_safe( const_cast( "ZE_ENABLE_TRACING_LAYER=1" ) ); + EXPECT_EQ(ZE_RESULT_SUCCESS, zeInitDrivers(&pCount, nullptr, &desc)); + bool enabled = false; + EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetTracingLayerState(&enabled)); + EXPECT_TRUE(enabled); +} + +TEST( + TracingLayerState, + GivenTracingLayerEnabledViaEnvironmentWhenCallingzelEnableTracingLayerThenStateRemainsTrue) { + + uint32_t pCount = 0; + ze_init_driver_type_desc_t desc = {ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC}; + desc.flags = UINT32_MAX; + desc.pNext = nullptr; + putenv_safe( const_cast( "ZE_ENABLE_TRACING_LAYER=1" ) ); + EXPECT_EQ(ZE_RESULT_SUCCESS, zeInitDrivers(&pCount, nullptr, &desc)); + bool enabled = false; + EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetTracingLayerState(&enabled)); + EXPECT_TRUE(enabled); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelEnableTracingLayer()); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetTracingLayerState(&enabled)); + EXPECT_TRUE(enabled); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelDisableTracingLayer()); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetTracingLayerState(&enabled)); + EXPECT_TRUE(enabled); +} + +TEST( + TracingLayerState, + GivenTracingLayerEnabledViaEnvironmentAndDynamicallyWhenDisablingDynamicTracingThenStateRemainsTrue) { + + uint32_t pCount = 0; + ze_init_driver_type_desc_t desc = {ZE_STRUCTURE_TYPE_INIT_DRIVER_TYPE_DESC}; + desc.flags = UINT32_MAX; + desc.pNext = nullptr; + putenv_safe( const_cast( "ZE_ENABLE_TRACING_LAYER=1" ) ); + EXPECT_EQ(ZE_RESULT_SUCCESS, zeInitDrivers(&pCount, nullptr, &desc)); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelEnableTracingLayer()); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelEnableTracingLayer()); + bool enabled = false; + EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetTracingLayerState(&enabled)); + EXPECT_TRUE(enabled); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelDisableTracingLayer()); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetTracingLayerState(&enabled)); + EXPECT_TRUE(enabled); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelDisableTracingLayer()); + EXPECT_EQ(ZE_RESULT_SUCCESS, zelGetTracingLayerState(&enabled)); + EXPECT_TRUE(enabled); +} + + + class CaptureOutput { private: int original_fd;