# Cobalt 实时应用概述

该教程和源代码参考应用程序定义了多个命令行参数，用于控制执行流程。这允许通过不同选项来实验，影响实时操作。这些选项包括：采样和工作负载迭代的次数、要分配的内存块大小、是否作为实时优先级线程运行、是否锁定内存、让出系统事件的时间间隔，以及是否通过改变间隔来建立固定的循环时间节奏。

应用程序的输出包括：最小和最大工作负载执行时间（以微秒和时钟周期为单位）、抖动（jitter）以及启用时错过的循环次数。输出可以格式化为易于阅读的文本，或者以逗号分隔值（CSV）的形式输出，便于导入其他应用程序中。

### 参数摘要和示例输出

可以使用 -h 标志执行教程应用程序以查看帮助信息。

    sinsegye@sinsegye-sx21:~$ sudo ./latency --help
    based on xkernel/cobalt v3.2.3
    µsage: latency [options]:
    -h                              print histograms of min, avg, max latencies
    -g <file>                       dump histogram to <file> in gnuplot format
    -s                              print statistics of min, avg, max latencies
    -H <histogram-size>             default = 200, increase if your last bucket is full
    -B <bucket-size>                default = 1000ns, decrease for more resolution
    -p <period_µs>                  sampling period
    -l <data-lines per header>      default=21, 0 to supress headers
    -T <test_duration_seconds>      default=0, so ^C to end
    -q                              supresses RTD, RTH lines if -T is µsed
    -D <testing_device_no>          number of testing device, default=0
    -t <test_mode>                  0=µser task (default), 1=kernel task, 2=timer IRQ
    -f                              freeze trace for each new max latency
    -c <cpu>                        pin measuring task down to given CPU
    -P <priority>                   task priority (test mode 0 and 1 only)
    -b                              break upon mode switch
    --main-prio=<prio>		main thread priority
    --print-buffer-size=<bytes>	size of a print relay buffer (16k)
    --print-buffer-count=<num>	number of print relay buffers (4)
    --print-sync-delay=<ms>	max delay of output synchronization (100 ms)
    --cpu-affinity=<cpu[,cpu]...>	set CPU affinity of threads
    --[no-]sanity			disable/enable sanity checks
    --verbose[=level] 		set verbosity to desired level [=1]
    --silent, --quiet 		same as --verbose=0
    --trace[=level] 		set tracing to desired level [=1]
    --version			get version information
    --dump-config			dump configuration settings
    --help				display help

示例如下:

    sinsegye@sinsegye-sx21:~$ sudo ./latency -c1 -t0 -p 100 -P 99 -h
    == Sampling period: 100 µs
    == Test mode: periodic µser-mode task
    == All results in microseconds
    warming up...
    RTT|  00:00:01  (periodic µser-mode task, 100 µs period, priority 99)
    RTH|----lat min|----lat avg|----lat max|-overrun|---msw|---lat best|--lat worst
    RTD|     -2.070|     -1.332|      2.250|       0|     0|     -2.070|      2.250
    RTD|     -2.090|     -1.335|      2.708|       0|     0|     -2.090|      2.708
    RTD|     -1.995|     -1.336|      2.440|       0|     0|     -2.090|      2.708
    RTD|     -1.998|     -1.334|      2.412|       0|     0|     -2.090|      2.708
    RTD|     -2.081|     -1.339|      1.893|       0|     0|     -2.090|      2.708
    RTD|     -1.959|     -1.335|      2.392|       0|     0|     -2.090|      2.708
    RTD|     -2.021|     -1.339|      2.162|       0|     0|     -2.090|      2.708
    RTD|     -2.056|     -1.336|      2.341|       0|     0|     -2.090|      2.708
    ---|--param|----range-|--samples
    HSD|    min|   1 -  2 |        3
    HSD|    min|   2 -  3 |        5
    ---|--param|----range-|--samples
    HSD|    avg|   0 -  1 |     7598
    HSD|    avg|   1 -  2 |    74213
    HSD|    avg|   2 -  3 |       21
    ---|--param|----range-|--samples
    HSD|    max|   1 -  2 |        1
    HSD|    max|   2 -  3 |        7
    HSH|--param|--samples-|--average--|---stddev--
    HSS|    min|         8|      1.625|      0.518
    HSS|    avg|     81832|      0.907|      0.291
    HSS|    max|         8|      1.875|      0.354
    ---|-----------|-----------|-----------|--------|------|-------------------------
    RTS|     -2.090|     -1.335|      2.708|       0|     0|    00:00:08/00:00:08

### 功能流程图

### 参数详情

#### histograms（-h）

打印最小、平均、最大延迟的直方图

选项是指在执行 latency 测试工具时，程序将输出一份关于实时系统延迟的统计直方图，显示系统的 最小延迟、平均延迟 和 最大延迟 的分布情况。

生成的直方图如下：

    ---|--param|----range-|--samples
    HSD|    min|   1 -  2 |        6
    ---|--param|----range-|--samples
    HSD|    avg|   0 -  1 |    21441
    HSD|    avg|   1 -  2 |    44170
    HSD|    avg|   2 -  3 |       19
    ---|--param|----range-|--samples
    HSD|    max|   2 -  3 |        6
    HSH|--param|--samples-|--average--|---stddev--
    HSS|    min|         6|      1.000|      0.000
    HSS|    avg|     65630|      0.674|      0.470
    HSS|    max|         6|      2.000|      0.000
    ---|-----------|-----------|-----------|--------|------|-------------------------
    RTS|     -1.501|     -1.097|      2.580|       0|     0|    00:00:06/00:00:06

第一部分：最小延迟统计 (min)

    ---|--param|----range-|--samples
    HSD|    min|   1 -  2 |        6

- HSD：表示是延迟的 `Histogram Data`。
- min：统计的参数是最小延迟。
- range：延迟的范围是 1 - 2 微秒。
- samples：有 6 个样本落在该延迟范围内。

第二部分：平均延迟统计 (avg)

    ---|--param|----range-|--samples
    HSD|    avg|   0 -  1 |    21441
    HSD|    avg|   1 -  2 |    44170
    HSD|    avg|   2 -  3 |       19

- HSD：同样表示是延迟的 `Histogram Data`。
- avg：统计的参数是平均延迟。
- range：延迟的范围，例如 0 - 1 微秒、1 - 2 微秒。
- samples：分别有 21441 个样本落在 0 - 1 微秒范围内，44170 个样本落在 1 - 2 微秒范围内，19 个样本落在 2 - 3 微秒范围内

第三部分：最大延迟统计 (max)

    ---|--param|----range-|--samples
    HSD|    max|   2 -  3 |        6

- max：统计的参数是最大延迟。
- range：最大延迟的范围是 2 - 3 微秒。
- samples：有 6 个样本的最大延迟落在这个范围。

第四部分：整体统计 (HSH)

    HSH|--param|--samples-|--average--|---stddev--
    HSS|    min|         6|      1.000|      0.000
    HSS|    avg|     65630|      0.674|      0.470
    HSS|    max|         6|      2.000|      0.000

- HSH：表示 `Histogram Summary Header`。统计的是整体情况。
- param：参数类型，min 是最小延迟，avg 是平均延迟，max 是最大延迟。
- samples：样本数。例如，有 6 个样本用于最小延迟，65630 个样本用于平均延迟，6 个样本用于最大延迟。
- average：延迟的平均值。例如，最小延迟的平均值为 1.000 微秒，平均延迟为 0.674 微秒，最大延迟为 2.000 微秒。
- stddev：标准差。这个值表示数据的离散程度，例如，平均延迟的标准差为 0.470，表示大多数延迟样本分布在平均值的 0.470 微秒左右。

第五部分：系统实时性统计 (RTS)

    ---|-----------|-----------|-----------|--------|------|-------------------------
    RTS|     -1.501|     -1.097|      2.580|       0|     0|    00:00:06/00:00:06

- RTS：表示实时性统计信息（Real-Time Statistics）。
- 列 1：系统的最小延迟偏差，例如 -1.501 微秒。
- 列 2：系统的最大延迟偏差，例如 -1.097 微秒。
- 列 3：系统的最大正向延迟，例如 2.580 微秒。
- 列 4 和 5：显示的是其他统计信息，例如丢失的实时任务次数，或者其他未定义的数值。
- 列 6：时间信息，表示测试运行时间，例如 6 秒。

#### gnuplot （-g）

选项 -g 在 latency 测试工具中的作用是将生成的延迟直方图以 gnuplot 格式保存到指定的文件中。gnuplot 是一个强大的命令行绘图工具，它能够根据数据生成可视化图表。通过这个选项，用户可以将延迟数据保存为适合用 gnuplot 解析的格式，方便后续生成图表以便进一步分析。

使用 gnuplot 可视化数据：

- 打开 gnuplot:

    gnuplot

- 绘制图表：

在 gnuplot 控制台中，使用如下命令来绘制数据：

    plot 'latency_histogram.gnuplot' µsing 1:2 with lines title 'Latency Histogram'

这条命令会读取 latency_histogram.gnuplot 文件中的数据并将其绘制为一条折线图，表示延迟分布。如下图所示

#### summary （-s）

打印最小、平均、最大延迟的统计信息。这意味着，当你运行带有 -s 选项的 latency 工具时，它将输出系统在实时任务执行期间的 最小延迟、平均延迟 和 最大延迟 的具体数值，而不是生成直方图或其他详细的分布数据。

如下数据：

    HSH|--param|--samples-|--average--|---stddev--
    HSS|    min|         6|      1.000|      0.000
    HSS|    avg|     65630|      0.674|      0.470
    HSS|    max|         6|      2.000|      0.000

- HSH：表示 `Histogram Summary Header`。统计的是整体情况。
- param：参数类型，min 是最小延迟，avg 是平均延迟，max 是最大延迟。
- samples：样本数。例如，有 6 个样本用于最小延迟，65630 个样本用于平均延迟，6 个样本用于最大延迟。
- average：延迟的平均值。例如，最小延迟的平均值为 1.000 微秒，平均延迟为 0.674 微秒，最大延迟为 2.000 微秒。
- stddev：标准差。这个值表示数据的离散程度，例如，平均延迟的标准差为 0.470，表示大多数延迟样本分布在平均值的 0.470 微秒左右。

#### histogram-size （-H）

参数在 latency 工具中用于设置 直方图的桶（bucket）数量，即记录延迟数据时，用来划分延迟范围的区间数量。

- -H ：
  - 该参数指定直方图中的桶（bucket）数量。每个桶代表一个延迟范围，所有采样的延迟值会被归类到相应的桶中。
  - 默认情况下，桶的数量为 200。也就是说，延迟值会被分配到 200 个不同的区间（桶）中，每个桶对应一个延迟范围。

假设你正在测量一个实时系统的延迟，并且设置了 200 个桶。如果测量的延迟从 0 微秒到 1000 微秒，这 1000 微秒的范围将被划分成 200 个区间（每个区间大约为 5 微秒），并将每个延迟样本放入对应的区间中。

#### bucket-size （-B）

参数在 latency 工具中用于设置每个桶（bucket）在直方图中的延迟范围（即每个桶的大小）。具体来说，它定义了每个桶可以记录的延迟值的范围大小，默认为1000纳秒（ns）。

- -B ：
  - 该参数指定每个桶的大小，默认值为 1000 纳秒（1 微秒）。这意味着每个桶将记录 1000 纳秒 的延迟范围。换句话说，所有延迟落在同一个 1000 纳秒的区间内的样本都会被放入同一个桶中。
  - 减少此值以提高分辨率：如果你希望获得更精细的延迟数据，你可以通过减小桶的大小来增加分辨率。较小的桶意味着可以捕获更细粒度的延迟信息。

假设你使用默认的 bucket-size，即 1000 纳秒。如果某次延迟测量结果是 1500 纳秒，那么这个值将会落在第 2 个桶（1000-1999ns）。这样，如果有多个延迟值落在这个区间内，它们都会记录在同一个桶中。

    latency -B 500

这会将每个桶的大小设置为 500 纳秒，相比默认的 1000 纳秒 提供了更高的分辨率。也就是说，延迟会被记录在 500ns 的区间内，而不是 1000ns。

#### period_µs （-p）

在 latency 工具中用于设置 采样周期，单位是 微秒（µs）。它定义了延迟测量之间的时间间隔，即两次延迟采样的时间间隔。

- -p <period_µs>：
  - 这个参数指定 采样周期，也就是每次测量延迟之间的时间间隔，单位是微秒（1微秒 = 1/1000000秒）。
  - 通过设置采样周期，latency 工具可以按照指定的时间间隔不断地测量和记录延迟数据。

    latency -p 1000

这个命令表示将采样周期设置为 1000 微秒，即每隔 1000 微秒（1 毫秒）采集一次延迟数据。这意味着 latency 工具每 1 毫秒对系统的延迟情况进行一次采样并记录数据。

#### data-lines per header (-l)

在 latency 工具中用于设置终端输出不包含打印头信息。具体展示如下：

    == Sampling period: 100 µs
    == Test mode: periodic µser-mode task
    == All results in microseconds
    warming up...
    RTD|     -1.477|     -0.937|      4.687|       0|     0|     -1.477|      4.687
    RTD|     -1.485|     -0.940|      4.476|       0|     0|     -1.485|      4.687
    RTD|     -1.485|     -0.929|      3.963|       0|     0|     -1.485|      4.687
    RTD|     -1.468|     -0.929|      3.752|       0|     0|     -1.485|      4.687
    RTD|     -1.467|     -0.939|      3.767|       0|     0|     -1.485|      4.687
    RTD|     -1.466|     -0.932|      4.254|       0|     0|     -1.485|      4.687

#### test_duration_seconds (-T)

在 latency 工具中用于设置测试的持续时间，默认为0，0代表直到遇到`Ctrl+C`才终止。

#### （-q）

在 latency 工具中用于设置隐藏RTD与RTH行的输出，但是要与 `-T` 选项结合使用才生效。

#### test_mode （-t）

在 latency 工具中用于指定延迟测试的 测试模式。该参数决定了 latency 工具用哪种方式来生成和测量延迟。可以选择以下三种测试模式：

- -t 0：用户任务模式（默认模式）
  - 在此模式下，延迟测量是通过用户空间的任务（线程）来执行的。
  - 系统会创建一个高优先级的用户空间任务，周期性地执行，并测量任务调度之间的延迟。
  - 这种模式主要用于评估在用户空间中执行的实时任务的调度延迟，适合测试应用程序层面的实时性。
- -t 1：内核任务模式
  - 在此模式下，延迟测量是在内核空间进行的。内核中的一个任务将被用于测量调度延迟。
  - 这种模式通过在内核中创建一个高优先级任务，测量该任务的调度延迟。
  - 内核任务模式主要用于分析和评估内核任务的实时性能，适合测试与内核调度相关的实时性问题。
- -t 2：定时器中断模式
  - 在此模式下，延迟测量是基于定时器中断的。系统周期性地产生定时器中断，工具测量这些中断的触发延迟。
  - 定时器中断模式可用于测试系统处理硬件中断（特别是定时器中断）的延迟。该模式更关注底层硬件中断的响应时间，而不是任务调度。
  - 这种模式适合评估硬实时系统中中断延迟对系统性能的影响。

#### cpu （-c）

在 latency 工具中的作用是 将延迟测量任务绑定到指定的 CPU 核心上运行，也就是将测量任务的 CPU 亲和性 固定到特定的一个或多个 CPU 核心。通过这个参数，你可以确保延迟测量任务只在指定的 CPU 上运行，不会被其他 CPU 核心处理，这样有助于更精确地测量特定 CPU 核心上的延迟情况。

- -c ：
  - 表示 CPU 核心编号，你可以通过这个参数指定某个 CPU 核心（如 CPU 0 或 CPU 1），将 latency 工具的测量任务锁定到这个 CPU 上执行。
  - 通过将任务固定在指定 CPU 上，你可以避免因任务在不同 CPU 核心间切换所带来的额外延迟，从而获得更稳定和准确的测量结果。

#### priority （-P）

在 latency 工具中的作用是 设置测量任务的优先级。这个参数指定延迟测量任务在系统调度中的优先级，以确保任务能够按照指定的优先级进行调度。该参数仅适用于测试模式 0（用户任务）和测试模式 1（内核任务），因为这两种模式下任务的调度是受优先级影响的。

- -P ：
  - 该参数用于设置延迟测量任务的调度优先级。优先级数值通常从 1 到 99，数值越高，任务的优先级越高，系统越倾向于优先调度该任务。
  - 在 `MetaOS` 中，优先级决定了任务被调度的顺序。高优先级任务将优先于低优先级任务执行，因此为测量任务设置较高的优先级可以避免被其他任务抢占，获得更准确的延迟数据。
  - 测试模式 0（用户任务） 和 测试模式 1（内核任务） 是可以直接设置优先级的模式，而测试模式 2（定时器中断模式）不受任务优先级的影响，因此该参数不适用于模式 2。

### 通用参数详情

应用程序如何自动识别一组标准的命令行选项，以及如何使用这些选项来调试和配置应用程序。这些选项可以在不需要修改应用程序代码的情况下被解释和执行。例如，使用 --dump-config 选项，应用程序会自动输出其链接的 `Cobalt` 库的构建设置。

Option | Description
--- | ---
`--main-prio=<prio>` | Sets the priority of the main thread
`--print-buffer-size=<bytes>` | Sets the size of the print buffer µsed for output, default is 16k
`--print-buffer-count=<num>` | Sets the total number of buffers in the output ring, default is 4
`--print-sync-delay=<ms>` | Sets the maximum delay before synchronizing the output buffers, default is to refresh every 100 ms
`--cpu-affinity=<cpu[,cpu]...>` | Sets the CPU affinity for threads
`--[no-]sanity` | Turns on/off sanity checks
`--verbose[=level]` | Sets verbosity to the desired level, default is 1
`--silent`, `--quiet` | Same as `--verbose=0`
`--trace[=level]` | Sets tracing to the desired level, default is 1
`--version` | Gets version information of the real-time core
`--dump-config` | Dumps the settings µsed for building the Cobalt library linked to the application
`--help` | Displays help

#### --main-prio

用于这是主线程的线程优先级，通常是在 main() 函数内部进行。

参数 的具体规则如下：

1. 如果 为零 (0): 调用线程将被分配 `SCHED_OTHER` 调度策略。这是标准的非实时调度策略，通常用于普通的后台处理。
2. 如果 大于零 (>0): 调用线程将被分配 `SCHED_FIFO` 调度策略，并设置为给定的优先级。`SCHED_FIFO`（先进先出）是一种实时调度策略，确保了更高优先级的线程总是能够在低优先级线程之前运行。
3. 如果 为负数 (<0): 调用线程的调度参数将保持不变。

#### --print-buffer-size

标准输出函数（如 printf(3), fprintf(3), 和 puts(3)）背后的缓冲机制。

当启用符号封装时，`Cobalt` 会介入常见的 `stdio` 输出调用。这意味着，即便是在实时线程中调用如 `printf` 等函数，也不会因为等待 I/O 操作而阻塞，从而保证了实时性。

这些 `stdio` 调用使用一种缓冲区的机制。这些缓冲区组成一个输出环，由实时线程无锁地填充，然后定期由一个常规的（非实时）Linux 帮助线程刷新到进程的目的输出流（如 `stdout`、`stderr` 或其他特定的流）。

参数用途:

- 缓冲区大小设置：通过 `--print-buffer-size` 参数，开发者可以设置每个缓冲区的大小。默认情况下，每个缓冲区大小为 16 KB。
- 性能调优：调整缓冲区大小可以根据特定应用的输出需求和性能特征进行优化。更大的缓冲区可能会减少需要刷新的频率，从而降低管理缓冲区的开销，但同时也可能增加内存使用量。

#### --print-buffer-count

用于设置输出环中缓冲区的总数量。这些缓冲区与之前提到的 `--print-buffer-size` 参数密切相关，后者定义了单个缓冲区的大小。

参数用途:

- 缓冲区总数设置：此参数允许你指定输出环中应存在的缓冲区的总数。默认情况下，系统配置有 4 个缓冲区。
- 输出管理：缓冲区是由实时线程填充的，然后由一个非实时的 `Linux` 帮助线程定期清空，将数据刷新到如 `stdout` 或 `stderr` 这样的目的输出流。通过增加缓冲区的数量，可以提高在高负载下处理输出请求的能力，因为这样可以在输出流被阻塞或延迟时存储更多的输出数据。

#### --print-sync-delay

此参数用于设置输出环中缓冲区内容在被同步到最终输出流之前的最大延迟时间，单位为毫秒（ms），这与之前提到的 `--print-buffer-size` 和 `--print-buffer-count` 参数配合使用，共同管理输出数据的处理。

参数用途:

- 延迟时间设置：通过此参数，你可以指定在输出数据被最终刷新到如 stdout 或 stderr 的输出流之前，可以在缓冲区中保留的最长时间。默认情况下，输出环每 100 毫秒被刷新一次。
- 输出流管理：缓冲区由实时线程填充，而清空操作则由一个非实时的 Linux 辅助线程周期性地执行。设置这个延迟参数可以帮助调整输出数据刷新的频率，以适应应用程序的实际需求。

#### --cpu-affinity

用于指定 `Cobalt` 应用程序创建的线程可以运行的 CPU 集合。这个参数在没有明确指定线程应该固定运行在特定 CPU 上时非常有用。默认情况下，线程可以在任何在线的 CPU 上运行。

参数用途:

- CPU 亲和性设置：通过此参数，可以为应用程序中的实时线程指定一个或多个 CPU，允许这些线程只在指定的 CPU 上运行。这可以通过列出有效（即在线的）CPU 编号，并用逗号分隔来实现。
- 线程性能优化：为线程设置 CPU 亲和性可以减少 CPU 之间的上下文切换，提高线程的运行效率。固定线程到特定的 CPU 也有助于更好地利用 CPU 缓存，减少缓存丢失，从而提高性能。
- 重复使用：这个选项可以在命令行中多次出现，每次出现都会累积设置。这意味着可以逐步构建最终的 CPU 亲和性设置，根据需要调整每个线程或线程组的 CPU 分配。

#### --[no-]sanity

用于在 `Cobalt` 库中开启或关闭启动期间的健全性检查。这是一个开关选项，其中 --sanity 表示开启检查，而 --no-sanity 表示关闭检查。这些检查主要在应用程序启动时进行，以确保运行环境符合预期的配置和健康状态。

检查的内容：

这些健全性检查包括但不限于：

- 确认运行 `Cobalt` 库的系统配置是否正确。

#### --verbose

用于设置 `Cobalt` 应用程序的输出详细级别。这个参数允许应用程序在运行时显示多少详细的日志或调试信息。

参数用途:

- 没有指定具体级别：如果在命令行中使用 --verbose 而没有指定级别，那么默认的详细级别会被设置为 1。这意味着将启用基本的详细输出。
- 完全静默：使用 --verbose=0 将会关闭所有日志输出，确保应用程序在运行时不会输出任何信息。这通常用于生产环境，或者当用户需要确保输出不会干扰到程序输出的其他部分时。

#### --silent，--quiet

与参数 `--verbose=0` 相同

#### --trace

用来调整和控制应用程序的跟踪详细度，有助于监控和调试内部操作。