# Cobalt实时应用程序教程

这些教程通常需要一个终端用于执行教程应用程序，至少一个额外的终端用于执行各种影响应用程序行为的压力测试，或用于监控以捕获其操作的统计信息。最好通过 SSH 远程访问执行教程的系统，以避免桌面 GUI 中断影响测量结果（非xkernel内核）。

教程包括：

- CPU 核心关联（CPU Core Affinity）：在一个隔离的核心上执行，以最小化系统和其他应用程序的影响
- 内存锁定（Memory Locking）：锁定内存以避免页面错误，页面错误会导致中断并影响确定性
- 实时优先级（Real-Time Priority）：使用 RT 优先级线程执行应用程序，以避免抢占

### CPU亲和性

- 使用代码设置CPU亲和性

    #include <pthread.h>
    #include <sched.h>
    #include <stdio.h>

    int main() {
        pthread_t thread = pthread_self(); // 获取当前线程
        cpu_set_t cpµset;                  // 定义 CPU 集合
        int cpu = 2;                       // 要绑定的 CPU 核心

        CPU_ZERO(&cpµset);    // 清除 CPU 集合
        CPU_SET(cpu, &cpµset); // 将 CPU 2 添加到集合中

        // 设置线程的 CPU 亲和性
        if (pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpµset) != 0) {
            perror("设置 CPU 亲和性失败");
            return 1;
        }

        printf("线程已成功绑定到 CPU %d。\n", cpu);

        return 0;
    }

- 使用命令行设置CPU亲和性

    # 可以启动一个程序并将其绑定到特定的 CPU（比如 CPU 0 和 CPU 1）
    sudo taskset -c 0,1 my_program

#### 在非隔离的CPU上测试

开始在CPU2上执行应用程序（非隔离）

    latency -c2 -t0 -p 100 -P 99 -h

平均值为 30µs

#### 在隔离的CPU上测试

开始在CPU1上执行应用程序（隔离）

    latency -c1 -t0 -p 100 -P 99 -h

平均值为 10µs

### 内存锁定教程

页面错误（Page faults）会对确定性产生负面影响。内存锁定可以防止应用程序中大部分甚至全部页面错误的发生。

- 使用代码设置内存锁定（mlockall）

        #include <stdio.h>
        #include <stdlib.h>
        #include <sys/mman.h>  // 包含 mlockall 函数的头文件
        #include <unistd.h>    // 包含 sleep 函数的头文件

        int main() {
            // 使用 mlockall 锁定进程的所有内存到物理内存中
            // MCL_CURRENT: 锁定当前内存页
            // MCL_FUTURE: 锁定未来分配的内存页
            if (mlockall(MCL_CURRENT | MCL_FUTURE) != 0) {
                perror("内存锁定失败");
                return 1;
            }

            printf("内存已锁定，防止交换到磁盘。\n");

            // 模拟程序运行，期间内存保持锁定
            for (int i = 0; i < 10; i++) {
                printf("程序运行中...\n");
                sleep(1);  // 休眠 1 秒
            }

            // 解除内存锁定
            if (munlockall() != 0) {
                perror("解除内存锁定失败");
                return 1;
            }

            printf("内存锁定已解除。\n");
            return 0;
        }

可以通过健康监测工具健康进程的Page faults次数

    sudo sjournal_run 1h

### 实时线程优先级

实时应用程序会抢占其他非实时的应用程序。优先级参数设置执行工作负载的线程优先级。当此参数被省略或设置为零时，线程不是实时的。将其设置为99可确保RT执行。

使用代码设置为实时线程优先级

    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    #include <sched.h>
    #include <unistd.h>

    // 线程函数
    void* thread_func(void* arg) {
        while (1) {
            // 模拟一些工作
            sleep(1);
        }
        return NULL;
    }

    int main() {
        pthread_t thread;
        struct sched_param param;
        int policy = SCHED_FIFO;  // 使用 FIFO 实时调度策略
        int max_priority, min_priority;

        // 创建线程
        if (pthread_create(&thread, NULL, thread_func, NULL) != 0) {
            perror("无法创建线程");
            return 1;
        }

        // 获取 SCHED_FIFO 策略的最大和最小优先级
        max_priority = sched_get_priority_max(SCHED_FIFO);
        min_priority = sched_get_priority_min(SCHED_FIFO);

        printf("SCHED_FIFO 最大优先级: %d, 最小优先级: %d\n", max_priority, min_priority);

        // 设置线程的优先级（选择一个合适的值，如最大优先级）
        param.sched_priority = max_priority;

        // 设置线程的调度策略和优先级
        if (pthread_setschedparam(thread, policy, &param) != 0) {
            perror("无法设置线程优先级");
            return 1;
        }

        printf("线程已设置为实时优先级 (SCHED_FIFO, 优先级: %d)\n", param.sched_priority);

        // 等待线程结束
        pthread_join(thread, NULL);

        return 0;
    }

使用命令行设置线程为实时线程

    # 将正在运行的进程转换为实时调度策略
    sudo chrt -f 99 <priority> <pid>

    # 以实时调度策略启动新进程
    sudo chrt -f 99 <priority> <command>

使用下面的命令查看设置是否成功

    chrt -p <pid>