Skip to content

CPUAffinity

CPUAffinity.cpp demonstrates CPU affinity node access checks and status inspection through GenTL nodes.


//=============================================================================
// Copyright (c) 2026 FLIR Integrated Imaging Solutions, Inc. All Rights Reserved.
//
// This software is the confidential and proprietary information of FLIR
// Integrated Imaging Solutions, Inc. ("Confidential Information"). You
// shall not disclose such Confidential Information and shall use it only in
// accordance with the terms of the license agreement you entered into
// with FLIR Integrated Imaging Solutions, Inc. (FLIR).
//
// FLIR MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
// SOFTWARE, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE, OR NON-INFRINGEMENT. FLIR SHALL NOT BE LIABLE FOR ANY DAMAGES
// SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
// THIS SOFTWARE OR ITS DERIVATIVES.
//=============================================================================

/**
 * @example CPUAffinity.cpp
 *
 * @brief CPUAffinity.cpp demonstrates CPU affinity node access checks and
 * status inspection through GenTL nodes.
 *
 * This example shows how to:
 * - Access system-level CPU affinity nodes
 * - Read CPU affinity privilege and service status
 * - Check access to CPU affinity service control commands (start/stop)
 * - Enumerate interfaces and inspect interface-level CPU affinity nodes
 * - Check write access for interface CPU affinity control nodes
 *
 * Note: This example is Windows-only and may require elevated privileges to
 * access some CPU affinity-related nodes.
 */

#include "Spinnaker.h"
#include "SpinGenApi/SpinnakerGenApi.h"
#include <iostream>

using namespace Spinnaker;
using namespace Spinnaker::GenApi;
using namespace Spinnaker::GenICam;
using namespace std;

namespace
{
    // Set to true to enable the optional CPU affinity configuration step.
    //
    // *** NOTES ***
    // When enabled, the example will attempt to write CPUAffinityEnable on each
    // GigE interface. This requires admin privileges and will modify the CPU
    // affinity configuration on the system. Leave as false to run in read-only
    // inspection mode.
    constexpr bool configureCpuAffinity = false;

    // Core list to apply to the selected GigE interface when configureCpuAffinity
    // is enabled. Use a comma-separated list (e.g. "1,2,3").
    const std::string reservedCoresToSet = "2,3,4,5";

    // Exact interface index to target for CPU affinity configuration.
    // No fallback search is performed.
    const int interfaceIndexToSet = 1;

    // Print privilege level value
    void PrintPrivilegeLevel(const std::string& label, const int64_t privilegeLevel)
    {
        cout << label << privilegeLevel;

        if (privilegeLevel == 1)
        {
            cout << " (No Admin Rights)" << endl;
        }
        else if (privilegeLevel == 2)
        {
            cout << " (Admin Rights Available)" << endl;
        }
        else
        {
            cout << " (Unknown)" << endl;
        }
    }

    // Print CPU affinity service status
    void PrintCpuAffinityServiceStatus(const int64_t serviceStatus)
    {
        cout << "CPU Affinity Service Status: " << serviceStatus;

        if (serviceStatus == 0)
        {
            cout << " (Stopped)" << endl;
        }
        else if (serviceStatus == 1)
        {
            cout << " (Running)" << endl;
        }
        else
        {
            cout << " (Unknown)" << endl;
        }
    }

    // Print media optimization status/enable (Boolean node)
    void PrintMediaOptimizationEnable(const bool mediaOptimizationEnable)
    {
        cout << "Media Optimization Enable: " << (mediaOptimizationEnable ? "1 (Enabled)" : "0 (Disabled)") << endl;
    }

    // Read and print CPU affinity information from system-level GenTL nodes
    int ReadCpuAffinitySystemNodes(INodeMap& systemTLNodeMap)
    {
        cout << "*** SYSTEM CPU AFFINITY INFORMATION ***" << endl << endl;

        try
        {
            CEnumerationPtr pPrivilege = systemTLNodeMap.GetNode("CpuAffinityPrivilege");

            if (IsReadable(pPrivilege))
            {
                PrintPrivilegeLevel("CPU Affinity Privilege Level: ", pPrivilege->GetIntValue());
            }
            else
            {
                cout << "CPU Affinity Privilege node not available on this system" << endl;
            }
        }
        catch (Spinnaker::Exception& e)
        {
            cout << "CPU Affinity Privilege node not available on this system: " << e.what() << endl;
        }

        try
        {
            CEnumerationPtr pServiceStatus = systemTLNodeMap.GetNode("CpuAffinityServiceStatus");

            if (IsReadable(pServiceStatus))
            {
                PrintCpuAffinityServiceStatus(pServiceStatus->GetIntValue());
            }
            else
            {
                cout << "CPU Affinity Service Status node not available on this system" << endl;
            }
        }
        catch (Spinnaker::Exception& e)
        {
            cout << "CPU Affinity Service Status node not available on this system: " << e.what() << endl;
        }

        try
        {
            CIntegerPtr pAvailableCores = systemTLNodeMap.GetNode("CpuAffinityAvailableCores");

            if (IsReadable(pAvailableCores))
            {
                cout << "Available CPU Cores: " << pAvailableCores->GetValue() << endl;
            }
            else
            {
                cout << "Available CPU Cores node not available on this system" << endl;
            }
        }
        catch (Spinnaker::Exception& e)
        {
            cout << "Available CPU Cores node not available on this system: " << e.what() << endl;
        }

        cout << endl;
        return 0;
    }

    // Show access state of system-level CPU affinity service control commands
    int ShowCpuAffinityControlNodes(INodeMap& systemTLNodeMap)
    {
        try
        {
            CCommandPtr pStartService = systemTLNodeMap.GetNode("CpuAffinityServiceStart");

            if (IsWritable(pStartService))
            {
                cout << "CPU Affinity Service Start command available (write access granted)" << endl;
                // Note: Actual execution would require admin privileges
                // pStartService->Execute();
            }
            else
            {
                cout << "CPU Affinity Service Start command not writable (may require admin privileges)" << endl;
            }
        }
        catch (Spinnaker::Exception& e)
        {
            cout << "CPU Affinity Service Start command not available on this system: " << e.what() << endl;
        }

        try
        {
            CCommandPtr pStopService = systemTLNodeMap.GetNode("CpuAffinityServiceStop");

            if (IsWritable(pStopService))
            {
                cout << "CPU Affinity Service Stop command available (write access granted)" << endl;
                // Note: Actual execution would require admin privileges
                // pStopService->Execute();
            }
            else
            {
                cout << "CPU Affinity Service Stop command not writable (may require admin privileges)" << endl;
            }
        }
        catch (Spinnaker::Exception& e)
        {
            cout << "CPU Affinity Service Stop command not available on this system: " << e.what() << endl;
        }

        return 0;
    }

    // Read and print media optimization information from system-level GenTL nodes.
    int ReadMediaOptimizationSystemNodes(INodeMap& systemTLNodeMap)
    {
        cout << endl << "*** SYSTEM MEDIA OPTIMIZATION INFORMATION ***" << endl << endl;

        try
        {
            CEnumerationPtr pMediaOptimizationPrivilege = systemTLNodeMap.GetNode("MediaOptimizationPrivilege");

            if (IsReadable(pMediaOptimizationPrivilege))
            {
                PrintPrivilegeLevel("Media Optimization Privilege Level: ", pMediaOptimizationPrivilege->GetIntValue());
            }
            else
            {
                cout << "Media Optimization Privilege node not available on this system" << endl;
            }
        }
        catch (Spinnaker::Exception& e)
        {
            cout << "Media Optimization Privilege node not available on this system: " << e.what() << endl;
        }

        try
        {
            CBooleanPtr pMediaOptimizationEnable = systemTLNodeMap.GetNode("MediaOptimizationEnable");

            if (IsReadable(pMediaOptimizationEnable))
            {
                PrintMediaOptimizationEnable(pMediaOptimizationEnable->GetValue());
            }
            else
            {
                cout << "Media Optimization Enable node not available on this system" << endl;
            }
        }
        catch (Spinnaker::Exception& e)
        {
            cout << "Media Optimization Enable node not available on this system: " << e.what() << endl;
        }

        cout << endl;
        return 0;
    }

    // Show read/write access for media optimization control nodes.
    int ShowMediaOptimizationControlNodes(INodeMap& systemTLNodeMap)
    {
        try
        {
            CBooleanPtr pMediaOptimizationEnable = systemTLNodeMap.GetNode("MediaOptimizationEnable");

            if (IsReadable(pMediaOptimizationEnable))
            {
                PrintMediaOptimizationEnable(pMediaOptimizationEnable->GetValue());
            }
            else
            {
                cout << "Media Optimization Enable node not available on this system" << endl;
            }

            if (IsWritable(pMediaOptimizationEnable))
            {
                cout << "Media Optimization Enable node is writable" << endl;
                // Note: Actual execution would require admin privileges
                // pMediaOptimizationEnable->SetValue(!pMediaOptimizationEnable->GetValue());
            }
            else
            {
                cout << "Media Optimization Enable node is not writable (may require admin privileges)" << endl;
            }
        }
        catch (Spinnaker::Exception& e)
        {
            cout << "Media Optimization Enable node not available on this system: " << e.what() << endl;
        }

        return 0;
    }

    // Configure reserved cores and enable CPU affinity enforcement.
    //
    // Writing CPUAffinityEnable = true pins RSS queues to the reserved CPU cores
    // defined in the CPU affinity config file. If no cores have been configured
    // yet, a default core assignment is applied automatically.
    //
    // Requires admin privileges. Targets a specified GigE interface index.
    int ConfigureInterfaceCpuAffinity(SystemPtr system)
    {
        int result = 0;
        bool settingsChanged = false;
        bool hasOriginalReservedCores = false;
        bool hasOriginalEnable = false;
        std::string originalReservedCores;
        bool originalCpuAffinityEnable = false;

        cout << endl << "*** CONFIGURING INTERFACE CPU AFFINITY ***" << endl << endl;

        InterfaceList interfaceList = system->GetInterfaces();
        const unsigned int numInterfaces = interfaceList.GetSize();

        // Find the GigE interface
        InterfacePtr pTargetInterface = nullptr;
        std::string targetInterfaceName;

        if (interfaceIndexToSet < 0 || static_cast<unsigned int>(interfaceIndexToSet) >= numInterfaces)
        {
            cout << "Interface index " << interfaceIndexToSet << " is out of range (0-"
                 << (numInterfaces == 0 ? 0 : numInterfaces - 1) << ")." << endl;
            interfaceList.Clear();
            return -1;
        }

        try
        {
            pTargetInterface = interfaceList.GetByIndex(static_cast<unsigned int>(interfaceIndexToSet));
            INodeMap& interfaceTLNodeMap = pTargetInterface->GetTLNodeMap();

            CBooleanPtr pCPUAffinityEnable = interfaceTLNodeMap.GetNode("CPUAffinityEnable");
            if (!IsAvailable(pCPUAffinityEnable))
            {
                cout << "Interface " << interfaceIndexToSet
                     << " does not expose CPUAffinityEnable (likely not a configurable GigE interface)." << endl;
                interfaceList.Clear();
                return -1;
            }

            CStringPtr pDisplayName = interfaceTLNodeMap.GetNode("InterfaceDisplayName");
            if (IsReadable(pDisplayName))
            {
                targetInterfaceName = std::string(pDisplayName->GetValue());
            }
            else
            {
                targetInterfaceName = "Interface " + std::to_string(interfaceIndexToSet);
            }
        }
        catch (Spinnaker::Exception& e)
        {
            cout << "Error accessing interface " << interfaceIndexToSet << ": " << e.what() << endl;
            interfaceList.Clear();
            return -1;
        }

        cout << "Configuring: " << targetInterfaceName << endl;

        try
        {
            INodeMap& interfaceTLNodeMap = pTargetInterface->GetTLNodeMap();
            CStringPtr pReservedCores = interfaceTLNodeMap.GetNode("ReceiveSideScalingReservedCores");
            CBooleanPtr pCPUAffinityEnable = interfaceTLNodeMap.GetNode("CPUAffinityEnable");

            if (!IsWritable(pReservedCores) || !IsWritable(pCPUAffinityEnable))
            {
                cout << "  CPU affinity cannot be configured (admin privileges required)" << endl;
                interfaceList.Clear();
                return -1;
            }

            // Save current values so this example can restore them before exit.
            if (IsReadable(pReservedCores))
            {
                originalReservedCores = std::string(pReservedCores->GetValue());
                hasOriginalReservedCores = true;
            }

            if (IsReadable(pCPUAffinityEnable))
            {
                originalCpuAffinityEnable = pCPUAffinityEnable->GetValue();
                hasOriginalEnable = true;
            }

            cout << "  Original Reserved CPU cores: "
                 << (originalReservedCores.empty() ? "(none)" : originalReservedCores) << endl;
            if (hasOriginalEnable)
            {
                cout << "  Original CPU affinity enable: " << (originalCpuAffinityEnable ? "true" : "false") << endl;
            }

            //
            // Set reserved cores on the selected interface
            //
            // *** NOTES ***
            // ReceiveSideScalingReservedCores expects a comma-separated core list.
            // CPU 0 is reserved for system use.
            //
            pReservedCores->SetValue(reservedCoresToSet.c_str());
            settingsChanged = true;
            cout << "  Reserved CPU cores set to: " << reservedCoresToSet << endl;

            //
            // Enable CPU affinity on the selected interface
            //
            // *** NOTES ***
            // If no cores are currently reserved for this interface, a default
            // core assignment is applied by the GenTL layer. Use SpinView or
            // the CPU affinity config file to specify explicit core assignments
            // before enabling.
            //
            pCPUAffinityEnable->SetValue(true);
            cout << "  CPU affinity enabled" << endl;

            // Read back the resulting core assignment to confirm
            CIntegerPtr pCoreCount = interfaceTLNodeMap.GetNode("ReceiveSideScalingReservedCoresCount");
            bool hasReservedCoreCount = false;
            int64_t reservedCoreCount = 0;
            if (IsReadable(pCoreCount))
            {
                reservedCoreCount = pCoreCount->GetValue();
                hasReservedCoreCount = true;
                cout << "  Reserved CPU core count: " << reservedCoreCount << endl;
            }

            CStringPtr pCores = interfaceTLNodeMap.GetNode("ReceiveSideScalingReservedCores");
            if (IsReadable(pCores))
            {
                if (hasReservedCoreCount && reservedCoreCount == 0)
                {
                    cout << "  Reserved CPU cores: None" << endl;
                }
                else
                {
                    const std::string coreList = std::string(pCores->GetValue());
                    if (coreList.empty() || coreList == "false" || coreList == "False" || coreList == "FALSE")
                    {
                        cout << "  Reserved CPU cores: None" << endl;
                    }
                    else
                    {
                        cout << "  Reserved CPU cores: " << coreList << endl;
                    }
                }
            }
        }
        catch (Spinnaker::Exception& e)
        {
            cout << "Error configuring " << targetInterfaceName << ": " << e.what() << endl;
            result = -1;
        }

        if (settingsChanged)
        {
            try
            {
                INodeMap& interfaceTLNodeMap = pTargetInterface->GetTLNodeMap();
                CStringPtr pReservedCores = interfaceTLNodeMap.GetNode("ReceiveSideScalingReservedCores");
                CBooleanPtr pCPUAffinityEnable = interfaceTLNodeMap.GetNode("CPUAffinityEnable");

                if (IsWritable(pReservedCores))
                {
                    if (hasOriginalReservedCores)
                    {
                        pReservedCores->SetValue(originalReservedCores.c_str());
                    }
                }

                if (hasOriginalEnable && IsWritable(pCPUAffinityEnable))
                {
                    pCPUAffinityEnable->SetValue(originalCpuAffinityEnable);
                }

                cout << "  Original CPU affinity settings restored" << endl;
            }
            catch (Spinnaker::Exception& e)
            {
                cout << "Error restoring original settings for " << targetInterfaceName << ": " << e.what() << endl;
                result = -1;
            }
        }

        interfaceList.Clear();
        return result;
    }

    // Read and print interface-level CPU affinity nodes for all interfaces.
    int ReadInterfaceCpuAffinityNodes(SystemPtr system)
    {
        int result = 0;

        cout << endl << "*** INTERFACE CPU AFFINITY INFORMATION ***" << endl << endl;

        InterfaceList interfaceList = system->GetInterfaces();
        const unsigned int numInterfaces = interfaceList.GetSize();

        cout << "Number of interfaces detected: " << numInterfaces << endl << endl;

        for (unsigned int i = 0; i < numInterfaces; i++)
        {
            try
            {
                InterfacePtr pInterface = interfaceList.GetByIndex(i);
                INodeMap& interfaceTLNodeMap = pInterface->GetTLNodeMap();

                try
                {
                    CStringPtr pInterfaceDisplayName = interfaceTLNodeMap.GetNode("InterfaceDisplayName");

                    if (IsReadable(pInterfaceDisplayName))
                    {
                        cout << "Interface " << i << ": " << pInterfaceDisplayName->GetValue() << endl;
                    }
                }
                catch (Spinnaker::Exception&)
                {
                    cout << "Interface " << i << ": (name not available)" << endl;
                }

                bool hasReservedCoreCount = false;
                int64_t reservedCoreCount = 0;

                try
                {
                    CIntegerPtr pReservedCoreCount = interfaceTLNodeMap.GetNode("ReceiveSideScalingReservedCoresCount");

                    if (IsReadable(pReservedCoreCount))
                    {
                        reservedCoreCount = pReservedCoreCount->GetValue();
                        hasReservedCoreCount = true;
                        cout << "  Reserved CPU Core Count: " << reservedCoreCount << endl;
                    }
                    else
                    {
                        cout << "  Reserved CPU Core Count: (not available on this interface)" << endl;
                    }
                }
                catch (Spinnaker::Exception&)
                {
                    cout << "  Reserved CPU Core Count: (not available on this interface)" << endl;
                }

                try
                {
                    CStringPtr pReservedCores = interfaceTLNodeMap.GetNode("ReceiveSideScalingReservedCores");

                    if (IsReadable(pReservedCores))
                    {
                        if (hasReservedCoreCount && reservedCoreCount == 0)
                        {
                            cout << "  Reserved CPU Cores: None" << endl;
                        }
                        else
                        {
                            cout << "  Reserved CPU Cores: " << pReservedCores->GetValue() << endl;
                        }
                    }
                    else
                    {
                        cout << "  Reserved CPU Cores: (not available on this interface)" << endl;
                    }
                }
                catch (Spinnaker::Exception&)
                {
                    cout << "  Reserved CPU Cores: (not available on this interface)" << endl;
                }

                try
                {
                    CBooleanPtr pCPUAffinityEnable = interfaceTLNodeMap.GetNode("CPUAffinityEnable");

                    if (IsAvailable(pCPUAffinityEnable))
                    {
                        if (IsReadable(pCPUAffinityEnable))
                        {
                            cout << "  CPU Affinity Enable: " << (pCPUAffinityEnable->GetValue() ? "true" : "false")
                                 << endl;
                        }

                        if (IsWritable(pCPUAffinityEnable))
                        {
                            cout << "  CPU Affinity Enable node is writable" << endl;
                        }
                        else
                        {
                            cout << "  CPU Affinity Enable node is not writable (may require admin privileges)" << endl;
                        }
                    }
                    else
                    {
                        cout << "  CPU Affinity Enable: (not available on this interface)" << endl;
                    }
                }
                catch (Spinnaker::Exception&)
                {
                    cout << "  CPU Affinity Enable: (not available on this interface)" << endl;
                }

                cout << endl;
            }
            catch (Spinnaker::Exception& e)
            {
                cout << "Error accessing interface " << i << ": " << e.what() << endl;
                result = -1;
            }
        }

        interfaceList.Clear();
        return result;
    }
} // namespace

int main(int /*argc*/, char** /*argv*/)
{
#if !defined(_WIN32) && !defined(_WIN64)
    cout << "CPUAffinity example is supported on Windows only." << endl;
    return 0;
#else
    int result = 0;

    // Print application build information
    cout << "Application build date: " << __DATE__ << " " << __TIME__ << endl << endl;

    // Retrieve singleton reference to system object
    SystemPtr system = System::GetInstance();

    // Print out current library version
    const LibraryVersion spinnakerLibraryVersion = system->GetLibraryVersion();
    cout << "Spinnaker library version: " << spinnakerLibraryVersion.major << "." << spinnakerLibraryVersion.minor
         << "." << spinnakerLibraryVersion.type << "." << spinnakerLibraryVersion.build << endl
         << endl;

    INodeMap& systemTLNodeMap = system->GetTLNodeMap();

    //
    // Read GenTL system nodes related to CPU affinity.
    //
    // *** NOTES ***
    // These nodes report privilege level, service status, and available CPU cores.
    //
    result = result | ReadCpuAffinitySystemNodes(systemTLNodeMap);

    //
    // Inspect CPU affinity service control command availability.
    //
    // *** NOTES ***
    // Start/stop command nodes may be present but writable only with admin privileges.
    //
    result = result | ShowCpuAffinityControlNodes(systemTLNodeMap);

    //
    // Read GenTL system nodes related to media optimization.
    //
    // *** NOTES ***
    // These nodes report privilege level and whether media optimization is enabled.
    //
    result = result | ReadMediaOptimizationSystemNodes(systemTLNodeMap);

    //
    // Inspect media optimization control node access.
    //
    // *** NOTES ***
    // The enable node may be readable but not writable without elevated permissions.
    //
    result = result | ShowMediaOptimizationControlNodes(systemTLNodeMap);

    //
    // Read interface-level CPU affinity nodes.
    //
    // *** NOTES ***
    // This checks reserved core settings and command access for each detected interface.
    //
    result = result | ReadInterfaceCpuAffinityNodes(system);

    //
    // Optionally enable CPU affinity on GigE interfaces.
    //
    // *** NOTES ***
    // This step is disabled by default. Set configureCpuAffinity = true at the
    // top of this file to enable it. Update reservedCoresToSet above to choose
    // which cores to reserve for the selected interface. Admin privileges are
    // required to write both ReceiveSideScalingReservedCores and CPUAffinityEnable.
    //
    if (configureCpuAffinity)
    {
        result = result | ConfigureInterfaceCpuAffinity(system);
    }

    //
    // Release system
    //
    // *** NOTES ***
    // The system should be released when no longer needed. If not released
    // explicitly, it will clean up automatically when all SystemPtr objects
    // go out of scope.
    //
    system->ReleaseInstance();

    cout << endl << "CPU Affinity example complete." << endl;
    cout << "Done! Press Enter to exit..." << endl;
    getchar();

    return result;
#endif
}