nohz_full CPU 上的一次时钟中断

背景:用户程序(名称为fa_pmu.test,pid为14368)开始运行在CPU0 上,通过调用sched_setaffinity 调度至CPU2 上,CPU2 是nohz_full,isolated 的,也就是说默认没有任何程序运行,并通过在CPU2 上通过ftrace 查看地切换过程。

问题:根据nohz_full 原理,用户程序(fa_pmu.test)应该不再受到时钟中断的干扰,但从程序表现来看还是有中断,通过/proc/interrupts 的记录应该就是时钟中断。

结论:(在给出具体分析前,先给出结论。)在测试环境(内核Linux5.4.*)中,用户程序的系统调用退出时并不能保证nohz_full 功能使能,需要在下一次时钟中断的时候才使能nohz_full。也就是说安全起见,实时任务需要在系统调用后忙等一段时间,以消除遗留时钟中断影响。除了忙等,经测试,Linux 6.7+以上版本已经解决该问题。

分析步骤如下:

1 运行在idle 状态

CPU2 默认没有任务程序运行,处于idle 状态,

static void do_idle(void)
{
  // …
  while(!need_resched()) {
    //…
    cpuidle_idle_call();
  }
  //..
  tick_nohz_idle_exit();
  //..
  schedle_idle();
  //..
}

程序运行在do_idle()->cpuidle_idle_call()->arch_cpu_idle()->x86_idle() 中
x86_idle 实际调用的是mwait_idle 还是poll_idle 需看配置。

2 退出Idle(tick_nohz_idle_exit())

CPU2 退出 idle while 循环后,首先执行的是tick_nohz_idle_exit,
该函数主要执行:
1)tick_nohz_stop_idle()->update_ts_time_stats() 更新调度统计信息
2)__tick_nohz_idle_restart_tick()->tick_nohz_restart_sched_tick() 重启tick

void tick_nohz_idle_exit(void)
{
  //…
  if (idle_active || tick_stopped)
  now = ktime_get();

  if (idle_active)
    tick_nohz_stop_idle(ts, now);

  if (tick_stopped)
    __tick_nohz_idle_restart_tick(ts, now);
  //…
}

重启tick(tick_nohz_restart_sched_tick()->tick_nohz_restart),取消调度时钟(hrtimer_cancel()),设置下一次tick,注意这里会导致产生下一次tick。

3 切换任务(schedule_idle())

用户程序会在schedule_idle() 中切换运行。

void __sched schedule_idle(void)
{
  WARN_ON_ONCE(current->state);
  do {
    __schedule(false);
  } while (need_resched());
}

schedule_idle()->__sched() 切换过程如下:
__sched()->rcu_note_context_switch() 处理rcu 相关内容
__sched()->pick_next_task() 将选择下一个任务进行处理
__sched()->context_switch() 将完成任务切换,比如切换mm(switch_mm_irqs_off())寄存器和栈(switch_to())
在这之后用户态任务切换至fa_pmu.test,从此之后将从fa_pmu.test 的内核栈开始执行。
__sched()->context_switch()->finish_task_switch() 完成任务切换的善后工作。

4 切换完成后,将从fa_pmu.test 的系统调用(sched_setaffinity)返回

# tracer: function_graph
#
# CPU  DURATION                  FUNCTION CALLS
# |     |   |                     |   |   |   |
  2)   0.469 us    |          __srcu_read_lock();
  2)               |          rcu_irq_enter_irqson() {
  2)               |            rcu_irq_enter() {
  2)   0.149 us    |              rcu_dynticks_eqs_exit();
  2)   0.359 us    |            }
  2)   0.568 us    |          }
  2)               |          /* cpu_idle: state=4294967295 cpu_id=2 */
  2)               |          rcu_irq_exit_irqson() {
  2)   0.106 us    |            rcu_irq_exit();
  2)   0.305 us    |          }
  2)   0.103 us    |          __srcu_read_unlock();
  2) $ 1751875 us  |        } /* mwait_idle */
  2) $ 1751875 us  |      } /* arch_cpu_idle */
  2) $ 1751875 us  |    } /* default_idle_call */
  2)               |    rcu_idle_exit() {
  2)               |      rcu_eqs_exit.constprop.0() {
  2)   0.099 us    |        rcu_dynticks_eqs_exit();
  2)   0.296 us    |      }
  2)   0.522 us    |    }
  2)   0.107 us    |    arch_cpu_idle_exit();
  2)               |    tick_nohz_idle_exit() {
  2)   0.184 us    |      ktime_get();
  2)               |      update_ts_time_stats() {
  2)   0.135 us    |        nr_iowait_cpu();
  2)   0.329 us    |      }
  2)               |      tick_nohz_restart_sched_tick() {
  2)   0.119 us    |        timer_clear_idle();
  2)   0.132 us    |        calc_load_nohz_stop();
  2)               |        hrtimer_cancel() {
  2)               |          hrtimer_try_to_cancel() {
  2)   0.202 us    |            hrtimer_active();
  2)   0.390 us    |          }
  2)   0.576 us    |        }
  2)   0.104 us    |        hrtimer_forward();
  2)               |        hrtimer_start_range_ns() {
  2)               |          lock_hrtimer_base() {
  2)   0.170 us    |            _raw_spin_lock_irqsave();
  2)   0.354 us    |          }
  2)               |          enqueue_hrtimer() {
  2)               |            /* hrtimer_start: hrtimer=00000000b4a6017d function=tick_sched_timer expires=71074629358859 softexpires=71074629358859 mode=0xa */
  2)   0.232 us    |          }
  2)               |          hrtimer_reprogram() {
  2)               |            tick_program_event() {
  2)               |              clockevents_switch_state() {
  2)               |                lapic_timer_set_oneshot() {
  2)   0.231 us    |                  __setup_APIC_LVTT();
  2)   0.421 us    |                }
  2)   0.704 us    |              }
  2)               |              clockevents_program_event() {
  2)   0.114 us    |                ktime_get();
  2)               |                lapic_next_deadline() {
  2)               |                  do_trace_write_msr() {
  2)               |                    /* write_msr: 6e0, value e8c9fcda004c */
  2)   0.194 us    |                  }
  2)   0.444 us    |                }
  2)   0.847 us    |              }
  2)   2.019 us    |            }
  2)   2.206 us    |          }
  2)   0.116 us    |          _raw_spin_unlock_irqrestore();
  2)   3.391 us    |        }
  2)   4.891 us    |      }
  2)   0.178 us    |      tick_nohz_account_idle_ticks.isra.0();
  2)   6.067 us    |    }
  2)   0.098 us    |    sched_ttwu_pending();
  2)               |    schedule_idle() {
  2)               |      rcu_note_context_switch() {
  2)               |        /* rcu_utilization: Start context switch */
  2)   0.099 us    |        rcu_preempt_deferred_qs();
  2)               |        /* rcu_utilization: End context switch */
  2)   0.477 us    |      }
  2)   0.138 us    |      _raw_spin_lock();
  2)   0.098 us    |      put_prev_task_idle();
  2)   0.172 us    |      pick_next_task_stop();
  2)   0.115 us    |      pick_next_task_dl();
  2)               |      pick_next_task_rt() {
  2)               |        update_rt_rq_load_avg() {
  2)   0.097 us    |          __accumulate_pelt_segments();
  2)   0.390 us    |        }
  2)   0.618 us    |      }
  2)               |      /* sched_switch: prev_comm=swapper/2 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=fa_pmu.test next_pid=14368 next_prio=0 */
  2)               |      switch_mm_irqs_off() {
  2)   0.117 us    |        __srcu_read_lock();
  2)               |        rcu_irq_enter_irqson() {
  2)   0.110 us    |          rcu_irq_enter();
  2)   0.310 us    |        }
  2)               |        /* tlb_flush: pages:-1 reason:flush on task switch (0) */
  2)               |        rcu_irq_exit_irqson() {
  2)   0.208 us    |          rcu_irq_exit();
  2)   0.403 us    |        }
  2)   0.108 us    |        __srcu_read_unlock();
  2)   1.738 us    |      }
  2)               |      do_trace_write_msr() {
  2)               |        /* write_msr: c0000100, value 4d8880 */
  2)   0.215 us    |      }
 ------------------------------------------
  2)    <idle>-0    => fa_pmu.-14368 
 ------------------------------------------

  2)               |              finish_task_switch() {
  2)               |                vtime_common_task_switch() {
  2)               |                  vtime_account_idle() {
  2)   0.110 us    |                    get_vtime_delta();
  2)   0.310 us    |                  }
  2)   0.121 us    |                  arch_vtime_task_switch();
  2)   0.775 us    |                }
  2)   0.111 us    |                _raw_spin_unlock_irq();
  2)               |                __mmdrop() {
  2)               |                  pgd_free() {
  2)   0.107 us    |                    _raw_spin_lock();
  2)   0.100 us    |                    _raw_spin_unlock();
  2)               |                    free_pages() {
  2)               |                      free_pages.part.0() {
  2)               |                        __free_pages() {
  2)               |                          free_unref_page() {
  2)               |                            free_pcp_prepare() {
  2)               |                              /* mm_page_free: page=000000009c017469 pfn=3247560 order=0 */
  2)               |                              __memcg_kmem_uncharge() {
  2)               |                                __memcg_kmem_uncharge_memcg() {
  2)               |                                  page_counter_uncharge() {
  2)               |                                    page_counter_cancel() {
  2)   0.095 us    |                                      propagate_protected_usage();
  2)   0.311 us    |                                    }
  2)               |                                    page_counter_cancel() {
  2)   0.099 us    |                                      propagate_protected_usage();
  2)   0.300 us    |                                    }
  2)               |                                    page_counter_cancel() {
  2)   0.096 us    |                                      propagate_protected_usage();
  2)   0.303 us    |                                    }
  2)               |                                    page_counter_cancel() {
  2)   0.107 us    |                                      propagate_protected_usage();
  2)   0.309 us    |                                    }
  2)   1.706 us    |                                  }
  2)               |                                  page_counter_uncharge() {
  2)               |                                    page_counter_cancel() {
  2)   0.116 us    |                                      propagate_protected_usage();
  2)   0.325 us    |                                    }
  2)               |                                    page_counter_cancel() {
  2)   0.117 us    |                                      propagate_protected_usage();
  2)   0.317 us    |                                    }
  2)               |                                    page_counter_cancel() {
  2)   0.116 us    |                                      propagate_protected_usage();
  2)   0.317 us    |                                    }
  2)               |                                    page_counter_cancel() {
  2)   0.128 us    |                                      propagate_protected_usage();
  2)   0.329 us    |                                    }
  2)   1.763 us    |                                  }
  2)   3.772 us    |                                }
  2)   4.062 us    |                              }
  2)   4.347 us    |                            }
  2)   0.109 us    |                            free_unref_page_prepare.part.0();
  2)   0.198 us    |                            free_unref_page_commit.isra.0();
  2)   5.042 us    |                          }
  2)   5.227 us    |                        }
  2)   5.412 us    |                      }
  2)   5.598 us    |                    }
  2)   6.175 us    |                  }
  2)   0.098 us    |                  destroy_context_ldt();
  2)               |                  kmem_cache_free() {
  2)   0.134 us    |                    __slab_free();
  2)               |                    /* kmem_cache_free: call_site=return_to_handler+0x0/0x27 ptr=00000000d1cf1f6d */
  2)   0.501 us    |                  }
  2)   7.206 us    |                }
  2)   0.128 us    |                __tick_nohz_task_switch();
  2)   8.784 us    |              }
  2) + 41.532 us   |            } /* cpu_stop_queue_work */
  2)               |            wait_for_completion() {
  2)   0.124 us    |              _raw_spin_lock_irq();
  2)   0.098 us    |              _raw_spin_unlock_irq();
  2)   0.518 us    |            }
  2) + 42.835 us   |          } /* stop_one_cpu */
  2) + 50.017 us   |        } /* __set_cpus_allowed_ptr */
  2)               |        cpuset_cpus_allowed() {
  2)   0.136 us    |          _raw_spin_lock_irqsave();
  2)   0.144 us    |          __rcu_read_lock();
  2)   0.104 us    |          __rcu_read_unlock();
  2)   0.107 us    |          _raw_spin_unlock_irqrestore();
  2)   1.048 us    |        }
  2) + 54.746 us   |      } /* sched_setaffinity */
  2) + 55.299 us   |    } /* __x64_sys_sched_setaffinity */

Some Linux Commands for Backups and Restores

The machine that hosts the site(http://blog.foool.net) collapsed some time ago, and this is not the first time that such a breakdown happens. I reinstalled the machine and restored the data, including the database and some ordinary files. The followings are some useful commands that helped me to backup and restore the system.

Disk Info.

df -h

list info. of all file systems. (‘h’ indicates to print the size with the human-readable format )

lsblk

list info. of all block devices.

File info.

du -a / | sort -nr | head -10

list the top 10 largest directories and files.

-a counts all files, not just directories.

-n compare according to string numerical value.

-r reverse the results.

-<num> list only the top <num> items.

du -sh

the storage amount of the current directory.

-s display only a total result

find . -type f -printf "%s %p\n" | sort -nr | head -10

list the top 10 biggest files of the current directory.

Backup & Restore

ssh user@remote "dd if=/dev/sda | gzip -1 -" | dd of=image.gz

Backup disk /dev/sda to a remote compressed image file.

The second – of “gzip -1 -” means reading the input from standard input.

ssh user@ip ‘dd if=/home/user/sdb.img.gz’ | gunzip -1 - | dd of=/dev/sdb

Restore disk /dev/sdb from a remote compressed image file.

sudo rsync -aAXv / –-delete --exclude={/dev/*,/proc/*,/lost+found}  user@ip:path

Backup all files, excluding some specific ones, to remote.

-aAXv (a)archive mode, (A)perserve ACLs, (X)preserve extended attributes, (v)verbose.

在Linux 中测量延迟

原文地址:http://btorpey.github.io/blog/2014/02/18/clock-sources-in-linux/

他山之石,可以攻玉,该文章将详细地介绍了在Linux 系统中使用TSC 时钟精确地计算一段代码过程(中断和函数等)执行时间需要注意的内容,可以配置Intel 官方文档《How to Benchmark Code Execution Times on Intel® IA-32 and IA-64 Instruction Set Architectures》一起阅读。下面是译文。

为了在现代(操作)系统中的测量(一段过程的)延迟,我们需要(测量时间间隔的时钟)至少能够以微秒为单位,最好以纳秒为单位。好消息是,使用相对现代的硬件和软件,可以准确地测量小到几个纳秒的时间间隔。

但是,为确保您的(测量)结果是准确的,更重要的是要了解您要测量什么,以及不同情况下测量过程的边界是什么。

概要

为了(在Linux 中测量延迟)获得最佳效果,您应该使用:

  • (使用)Linux 内核 2.6.18 或更高版本 —— 这是第一个包含 hrtimers (高精度时钟)包的版本。最好的是 2.6.32 或更高版本,包括了对大多数不同时钟源的支持。
  • 具有恒定不变的 TSC(constant, invariant TSC (time-stamp counter))的 CPU。这意味着 TSC 在所有插槽和CPU核心上都以恒定速率运行,而不管电源管理(代码)对 CPU 的频率进行如何更改。如果 CPU 支持 RDTSCP 指令那就更好了(RDTSCP 会使得读取的时间更准确和稳定)。
  • TSC 应配置为Linux 内核的时钟源。
  • 您应该测量发生在同一台机器上的两个事件之间的间隔(机器内计时,即intra-machine timing)。
  • 对于机器内计时,您最好的选择使用汇编语言直接读取 TSC。在我的测试机器上,软件读取 TSC 大约需要 100ns,这是该方法准确性的(边界)限制(要测量100ns 以内的时间间隔是不实际的)。但不同机器读取TSC 开销不尽相同,这就是为什么我提供了源代码,您可以用来进行测量自己的机器。
    • 请注意,上面提到的100ns 主要是因为我的Linux 机器不支持RDTSCP 指令。所以为了获取合理准确的计时,在RDTSC 之前还执行了CPUID 指令以序列化指令执行过程。而在另一台支持RDTSCP 指令的机器(新 MacBook Air)上,开销下降了大约 14ns。

下面将讨论时钟在Linux 上的工作原理,如何从软件(角度)访问各种时钟,以及如何测量访问它们的开销。

继续阅读

Futex 简述

简介:futex 全称为Fast User-space Mutex,是Linux 2.5.7 内核引入的锁原语,不同于其他进程间通信IPC原语(如信号量Semaphore、信号Signal和各种锁pthread_mutex_lock),futex更轻量级、快速,一般应用开发人员可能很少用到,但可基于futex实现各类读写锁、屏障(barriers)和信号机制等。

相关背景

在Linux的早期版本(内核Linux 2.5.7 版本以前),进程间通信(Inter-Process Communication,IPC)沿用的是传统Unix系统和System V 的IPC,如信号量(Semaphores)和Socket 等,这些IPC 均基于系统调用(System Call)。这类方法的缺点是当系统竞争度较低时,每次都进行系统调用,会造成较大系统开销。

原理和做法

用户程序每次调用IPC机制都会产生系统调用,程序发生用户态和内核态的切换,futex 的基本思想是竞争态总是很少发生的,只有在竞争态才需要进入内核,否则在用户态即可完成。futex的两个目标是:1)尽量避免系统调用;2)避免不必要的上下文切换(导致的TLB失效等)。

具体而言,任务获取一个futex 将发起带锁的减指令,并验证数值结果值是否为0(加上了锁),如果成功则可继续执行程序,失败(为已经占用的锁继续加锁)则任务在内核被阻塞。为相同futex 变量的加锁的任务被阻塞后放在同一个队列,解锁任务通过减少变量(只有一个加锁且锁队列为空)或进入内核从锁队列唤醒任务。

注意:futex 在Linux 的内核实现为一个系统调用(SYS_futex),用户程序如果直接调用它肯定会进入内核态,它还需要和其他语句(如原子操作)配合使用,新手在未理解其futex 原理和并发控制机制时极易犯错,这也是为什么不推荐直接使用它的原因。

继续阅读

安装RTAI5.2 基于Ubuntu18.04和4.14.111 内核

本文记录在我笔记本上安装最新版本RTAI(5.2)的过程和中间遇到的问题及解决方法,虽然不能覆盖所有问题,但希望能给后来者一些帮助。

安装的主要步骤:

1、安装操作系统和工具;

2、给内核打补丁并配置;

3、安装打补丁的内核与RTAI。

步骤一:安装操作系统和工具

1.1 安装操作系统

我选择的是Ubuntu18.04,因为这是带Linux 4.**.***内核的最新Ubuntu 版本(Ubuntu19.04 是以Linux5.**内核开始了)。而RTAI5.2 支持的最新内核版本即为4.14.111;

1.2 安装工具

这些工具是内核编译时需要的,下面命令可以保存为脚本执行

sudo apt install libncurses5-dev

sudo apt install libssl-dev

sudo apt install bison

sudo apt install flex

sudo apt install libssl-dev

sudo apt install libelf-dev

sudo apt install make gcc

sudo apt install patch

sudo apt install unzip

sudo apt install autoconf

注意:如果你使用的是不同的Linux 发布版(Redhat或openSUSE),有些包的名称是不同的,比如对于Redhat,libssl的安装包是libssl-devel。

注意:如果你采用的是Ubuntu16.04,那么可能因为包依赖的原因,你无法用apt install 命令安装libssl1.1,而这个包是在编译4.14.111 内核时必须的,所以建议你要么换更高版本OS,要么在Ubuntu 网站( https://packages.debian.org/stretch/amd64/libssl1.1/download )手动安装该包(sudo dpkg -i libssl1.1_1.1.0k-1~deb9u1_amd64.deb)。

1.3 安装已编译的Linux 内核4.14.111 (可选的)

该步骤是可选的,它会给系统安装上Linux4.14.111 的内核,从而获得一个默认的内核配置文件供后面使用,如果你是第一次安装RTAI,建议你执行该步骤。

在内核网站 https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/ 下载内核安装包:

cd ~/Downloads/

wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/linux-headers-4.14.111-0414111_4.14.111-0414111.201904052241_all.deb

wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/linux-headers-4.14.111-0414111-lowlatency_4.14.111-0414111.201904052241_amd64.deb

wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/linux-image-unsigned-4.14.111-0414111-lowlatency_4.14.111-0414111.201904052241_amd64.deb`

wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/linux-modules-4.14.111-0414111-lowlatency_4.14.111-0414111.201904052241_amd64.deb

然后使用dpkg -i 命令安装

sudo dpkg -i *.deb   #执行该命令是可能会遇到错,再重新执行该命令可以解决;

sudo update-grub

sudo reboot

重启后可以在Grub (长按shift进入Grub)中看到安装后的内核有“Generic” 和“lowlatency” 两种。如果进入Grub 有困难,在Grub 配置文件(/etc/default/grub)中修改配置`GRUB_TIMEOUT_STYLE=hidden` 为`GRUB_TIMEOUT_STYLE=false`并更新Grub 菜单`sudo update-grub`。

步骤二:内核打补丁和编译

2.1 下载内核 (https://cdn.kernel.org/pub/linux/kernel/v4.x/)

内核的名称为 linux-4.1.111.tar.gz,为之后编译和安装方便,将源码解压到`/usr/src` 中,并创建一个软链接到该源码目录。

cd /usr/src

sudo tar xvf linux-4.1.111.tar.gz

sudo ln -sf linux-4.1.111 linux

然后,从`/boot` 中拷贝配置文件:

cd /usr/src/linux

sudo cp /boot/config-4.14.111-0414111-lowlatency .config

如果你已经有了一个配置文件(比如你安装过老版本RTAI,在其Linux 内核中拷贝其配置文件即可)uIf you already have a configuration file (e.g. in your old RTAI patched Linux system), just copy it to the source path(`/usr/src/linux`).

2.2 给内核打补丁(Ubuntu 的补丁和RTAI 的补丁)

Ubuntu 是Linux 的一个发行版本,并对Linux 内核代码做了少量修改,所以在编译内核前应该打上Ubuntu 的补丁(https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/)。

cd ~/Downloads/

wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/0001-base-packaging.patch

wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/0002-UBUNTU-SAUCE-add-vmlinux.strip-to-BOOT_TARGETS1-on-p.patch

wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/0003-UBUNTU-SAUCE-tools-hv-lsvmbus-add-manual-page.patch

wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/0004-adhoc-from-__future__-import-syncconfig.patch

wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/0005-UBUNTU-SAUCE-no-up-disable-pie-when-gcc-has-it-enabl.patch

wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/0006-debian-changelog.patch

wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v4.14.111/0007-configs-based-on-Ubuntu-4.14.0-11.13.patch

cd /usr/src/linux

sudo patch -p1 < ~/Downloads/0001-base-packaging.patch

sudo patch -p1 < ~/Downloads/0002-UBUNTU-SAUCE-add-vmlinux.strip-to-BOOT_TARGETS1-on-p.patch

sudo patch -p1 < ~/Downloads/0003-UBUNTU-SAUCE-tools-hv-lsvmbus-add-manual-page.patch

sudo patch -p1 < ~/Downloads/0004-adhoc-from-__future__-import-syncconfig.patch

sudo patch -p1 < ~/Downloads/0005-UBUNTU-SAUCE-no-up-disable-pie-when-gcc-has-it-enabl.patch

sudo patch -p1 < ~/Downloads/0006-debian-changelog.patch

sudo patch -p1 < ~/Downloads/0007-configs-based-on-Ubuntu-4.14.0-11.13.patch

下载RTAI5.2 并给内核打上相应的补丁 :

wget https://www.rtai.org/userfiles/downloads/RTAI/rtai-5.2.tar.bz2

sudo cp rtai-5.2.tar.bz2 /usr/src/

sudo tar xvf rtai-5.2.tar.bz2

sudo ln -sf rtai-5.2 rtai

cd /usr/src/linux

sudo patch -p1 < /usr/src/rtai/base/arch/x86/patches/hal-linux-4.14.111-x86-3.patch

同样方便起见,我们也为rtai 的源码创建了一个软链接。

注意:安装RTAI补丁和PREEMPT-RT补丁的过程是类似的,如果你想安装PREEMPT-RT补丁,它的地址在这里。下载xz或gz格式后的补丁,可以用xz工具解压发现,是一个个编了序号的补丁,通过下面命令逐个应用补丁

patch -p1 -i /path/to/004-patch.x.y.z

也可以通过下面命令应用所有补丁

xzcat /path/to/patch.xz | patch -p1

bzcat /path/to/patch.xz | patch -p1

2.3 配置内核

配置内核主要参考下面的资料:

如果你的配置文件是从其他老的内核里拷贝过来的,首先应执行:

cd /usr/src/linux

sudo make oldconfig

否则直接执行:

sudo make menuconfig

下面是配置项中应修改的部分:

[改为 -rtai] General setup -> Local Version

[改为 None] General setup -> Stack Protector buffer overflow detection

[Enable] Processor type and features -> Interrupt pipeline

[Disable] Power management and ACPI options -> CPU Frequency Scaling

[Disable] Power management and ACPI options -> ACPI Support -> Processor

[Disable] Power management and ACPI options -> CPU Idle -> CPU idle PM support

[Disable] Kernel hacking -> Compile-time checks and compiler options -> Compile the kernel with debug info

[Disable] Kernel hacking -> Tracers

[Disable] Device Drivers -> Microsoft Hyper-V guest support

[Disable] Device Drivers -> Staging drivers -> Data acquisition support (comedi)

在 README.CONF_RMRKS 文件中要求disable `AUDITSYSCALL`,但是我们在选项中没有找到这一项。一个可替代的方法是编辑 `/usr/src/linux/init/Kconfig`文件,找到`AUDITSYSCALL` 如下部分:

config AUDITSYSCALL

    def_bool y

    depends on AUDIT && HAVE_ARCH_AUDITSYSCALL

替换为:

config AUDITSYSCALL

    bool “Enable system-call auditing support”

    depends on AUDIT && HAVE_ARCH_AUDITSYSCALL

    default y if SECURITY_SELINUX

    help

      Enable low-overhead system-call auditing infrastructure that

      can be used independently or with another kernel subsystem,

      such as SELinux.

然后,你就可以在‘General Setup’选项下看到`ADUITSYSCALL`,取消即可。

如果你的主机是多CPU 或多核的,那么 `Processor type and features` 下的SMP 选项要使能(enabled),并且最大CPU 个数(`Maximum numbers of CPUs`)不应小于物理核心个数(即不考虑Hyperthreading)。因此,建议你在BIOS 中取消Hyperthreading。

步骤三:编译安装内核和RTAI

3.1 编译和安装Linux 内核

cd /usr/src/linux

sudo touch REPORTING-BUGS

sudo make -j3

sudo make modules

sudo make modules_install

sudo make install

sudo update-initramfs –c -k 4.14.111-rtai [注意修改这里的版本名称]

sudo update-grub [注意修改/etc/default/grub 启动项为自己的内核]

sudo reboot

从Linux 内核网站下载的4.14.111 版本的源码目录下没有`REPORTING-BUGS`这个文件,可能会导致你在编译的时候遇到`recipe for target ‘kernel_headers’ failed` 的错误,所以我们首先创建了这个文件。

如果一切顺利的的话,你重启后将在Grub 上看到你自己编译的内核选项:ubuntu18.04_4.14.111-rtai 。

3.2 安装RTAI5.2

RTAI 需要autotools 生成链接编译工具:

cd /usr/src/rtai

sudo autoconf

sudo ./configure

接着配置RTAI :

sudo cp ../linux/.config .rtai_config

sudo make menuconfig

将CPU 个数(`number of CPUs`)设置为实际的物理核心个数即可。

sudo make

sudo make install

如果在编译时遇到下面的错误:

make:execup: .//config.guess: Permission denied

make:execup: .//config.sub: Permission denied

手动修改权限后再编译:

chmod 764 ./config.guess

chmod 764 ./config.sub

RTAI 默认的安装路径是`/usr/realtime`,其中`modules`目录下是编译后的模块库, `testSuite` 目录下是RTAI 的测试程序,通过手动加载模块和运行测试程序可以验证RTAI是否安装成功。

cd /usr/realtime/modules

sudo insmod rtai_hal.ko

sudo insmod rtai_sched.ko

sudo insmod rtai_fifos.ko

sudo insmod rtai_sem.ko

sudo insmod rtai_shm.ko

sudo insmod rtai_rtdm.ko

一般来说,负责进程调度的 rtai_sched.ko 模块如果加载后无死机,则安装成功。

可能遇到的问题

最后罗列一些可能遇到的问题:

1 编译内核时, `implicit declaration of function ‘ipipe_root_**_syscalls’ did you mean ‘ipipe_handle_syscall’ ……` 错误

原因:在内核配置里,ipipeline 没有使能(Enable);

2 加载`sudo insmod rtai_hal.ko` 和`sudo insmod rtai_` 后,系统冻死,键盘和鼠标均无响应

可能原因:General setup -> Stack Protector buffer overflow detection 选项默认是`Strong`,应设置为`None`或 `Regular`,更多配置项参考 README.CONF_RMRKS 。

3 不能进入编译Linux内核后的系统,提示`Gave up waiting for root file system device. Common problems:  …… ALERT! UUID=8e478c20-25e4-49c0-…… does not exist. Drop to the shell`.

可能原因:系统无法识别存储设备,注意配置内核时关于存储的驱动(SATA/PATA)要使能,因为我是在U盘中安装的系统,因此U盘相关的驱动也得使能。

4  当准备加载 rtai_hal.ko 模块时,提示`ERROR: Could not insert module rtai_hal.ko: Operation not permitted`错误,系统日志Syslog(`/var/log/syslog`) 提示`RTAI[hal] RTAI configured with less than num online CPUs`。

可能原因:RTAI 配置的CPU 个数比实际CPU 核心数要多,切记不要算上超线程(Hyperthreading)。

以上错误远不能包含所有你在安装RTAI 时遇到的问题,但你还可以借助下面的工具来帮助你的调试。

一些有用的命令和工具

  • Dmesg

dmesg

  • Syslog  

sudo cat /var/logsys

  • Systemctl

   Systemctl -failed   # 查看哪些内核没有被正常加载

  • RTAI 官网和邮件列表

www.rtai.org

  • Dpkg

dpkg –list | grep linux-image

  • mkinitramfs

如何定制自己的color scheme

在vim 配置文件vimrc 中通过colorscheme 命令可以选择自己喜欢的配色方案,在vim 下输入

:colorscheme torte

既可以选择系统自带torte 配色方案,当然你也可以在vim.org 下载自己喜欢的配色方案,在debian 中用户的配色方案放置在/usr/share/vim/vim72/colors/ 目录下。每个配色方案都是一个单独的vim 文件,比如很多vim 用户喜欢用的desert.vim ,但我觉得这样的配色太花哨了,torte 更适合我。所以如果想定制自己的vim 颜色方案可以看看下面的内容。

继续阅读