// Module included in the following assemblies:
//
// * scalability_and_performance/low_latency_tuning/cnf-tuning-low-latency-nodes-with-perf-profile.adoc

:_mod-docs-content-type: PROCEDURE
[id="cnf-enabling-cpu-isolation-for-executed-processes_{context}"]
= Isolating exec processes from latency-sensitive workloads

[role="_abstract"]
You can prevent `oc exec` and shell processes from interrupting latency-sensitive workloads by applying a `PerformanceProfile` to a node. The Node Tuning Operator (NTO) automatically enables the `ExecCPUAffinity` feature, which pins exec processes to a designated CPU so that your primary workload CPUs remain undisturbed.

.Prerequisites

* You have access to an {product-title} cluster using an account with `cluster-admin` permissions.

.Procedure

. Apply a `PerformanceProfile` tailored to your workload tuning requirements, such as reserved CPU counts or real-time kernel settings. For detailed instructions on generating a profile, see _Creating a performance profile_.

. Create a namespace for testing the performance configuration by running the following command:
+
[source,terminal]
----
$ oc create namespace performance-profile-testing
----
+
[NOTE]
====
You can create the workload in any namespace. This `performance-profile-testing` is used for testing purposes in this example.
====

. Deploy a `Guaranteed` QoS pod that requests whole integer CPUs and uses the generated `RuntimeClass`.

.. Retrieve the `RuntimeClass` created by the PerformanceProfile by running the following command:
+
[source,terminal]
----
$ oc get performanceprofile performance -o=jsonpath='{.status.runtimeClass}{"\n"}'
----
+
The following example shows the expected output:
+
[source,terminal]
----
performance-performance
----

.. Create a YAML file for the pod, for example `my-pod.yaml`. Ensure it requests whole integer CPUs and references the `runtimeClassName` generated by your `PerformanceProfile`:
+
[source,yaml,subs="attributes+"]
----
apiVersion: v1
kind: Pod
metadata:
  name: test
  namespace: performance-profile-testing
spec:
  runtimeClassName: performance-performance
  containers:
  - name: test
    image: "quay.io/openshift-kni/cnf-tests:{product-version}"
    command: ["sleep", "10h"]
    resources:
      requests:
        cpu: "2"
        memory: "256Mi"
      limits:
        cpu: "2"
        memory: "256Mi"
----
+
[NOTE]
====
The following requirements apply for CPU pinning:

* *Guaranteed QoS Class*: To trigger CPU pinning, the Pod must belong to the Guaranteed Quality of Service class. This requires that every container in the pod has both CPU and memory limits defined, and those limits must exactly equal their corresponding requests.

* *Integer CPUs*: The CPU request must be a whole integer.
** *SMT/Hyperthreading*: On systems where Simultaneous Multithreading (SMT) is enabled, the request should typically be a multiple of the threads per core, which is usually 2, to ensure exclusive core allocation.
** *Fractional Requests*: Pods with fractional CPU requests do not trigger the `ExecCPUAffinity` logic and follow the previous scheduling behavior.
* *Capacity*: Ensure your cluster has sufficient isolated CPU capacity available in the node's allocated pool to satisfy the request.
====

.. Apply the pod definition by running the following command:
+
[source,terminal]
----
$ oc apply -f my-pod.yaml
----

. Verify that the pod is running by running the following command:
+
[source,terminal]
----
$ oc get pod -n performance-profile-testing test
----
+
Wait until the pod status shows `Running` before proceeding to the verification steps.

.Verification

. Verify `exec` process pinning as follows:

.. Run the following command to see the specific cores exclusively assigned to this container by the CPU Manager:
+
[source,terminal]
----
$ oc exec -n performance-profile-testing test -- cat /sys/fs/cgroup/cpuset.cpus
----
+
[NOTE]
====
In a single-container pod, the command defaults to that container. In a multi-container pod, you must specify the container name using the `-c <container_name>` flag to ensure you are checking the correct context.
====
+
The following example shows the expected output:
+
[source,terminal]
----
4-5
----
+
The output shows exactly 2 CPUs, such as indexes 4 and 5, because the container requested `cpu: "2"`. The output represents the baseline exclusive CPUs for comparison.

.. Start an exec process in the pod by running the following command:
+
[source,terminal]
----
$ oc exec -n performance-profile-testing test -- sleep 3600 &
----

. Identify the node where the test pod is running:
+
[source,terminal]
----
$ oc get pod test -n performance-profile-testing -o=jsonpath='{.spec.nodeName}{"\n"}'
----

. Start a debug session on the node and set the root directory:
+
[source,terminal]
----
$ oc debug node/<node_name>
----
+
[source,terminal]
----
# chroot /host
----

.. Find the PID of the sleep 3600 process by running the following command:
+
[source,terminal]
----
$ ps -ef | grep "sleep 3600"
----
+
The following example shows the expected output:
+
[source,terminal]
----
1001     12345 12340  0 12:00 ? 00:00:00 sleep 3600
----

.. Identify the dedicated CPU set for the container by running the following command:
+
[source,terminal]
----
$ oc exec -n performance-profile-testing test -- cat /sys/fs/cgroup/cpuset.cpus
----
+
[NOTE]
====
In a multi-container pod, you must specify the container name using the `-c <container_name>` flag.
====
+
The following example shows the expected output for example the specific cores exclusively assigned to this container by the CPU Manager:
+
[source,terminal]
----
4-5
----

.. Check the CPU affinity of the exec process by running the following command, replacing `<PID>` with the PID identified in the previous step:
+
[source,terminal]
----
$ taskset -pc <PID>
----
+
Compare the taskset output against the container's dedicated CPU set from Step 1.
+
In this example, while the container has access to CPUs 4-5, the `ExecCPUAffinity` logic has pinned the exec process specifically to CPU 4. This confirms the pinning logic is active and that your primary workload's exclusive CPUs remain undisturbed.

