---- 整理自狄泰软件唐佐林老师课程
查看所有文章链接:(更新中)Linux系统编程训练营 - 目录
文章目录
1. 初探Linux进程调度
已知:父进程创建子进程后,父子进程同时运行
- 问题:如果计算机只有一个处理器,父子进程以什么方式同时执行?
1.1 Linux系统调度
- 内核具有进程调度的能力,多个进程可同时运行
- 微观上,处理器同一时间只能执行一个进程
- 同时运行多个进程时,每个进程都会获得适当的执行时间片
- 当执行时间片用完时,内核调度下一个进程执行
1.2 进程调度原理
- n个进程(n >= 2)同时位于内存中
- 处理器执行完每个进程,每个进程拥有一个时间片
- 时间片用完,通过时钟中断完成进程切换(调度)
1.3 Linux系统调度策略
- 普通调度策略
- SCHED_OTHER:Linux默认的调度策略,也被称为CFS(Completely Fair Scheduler),给每个进程动态计算优先级,根据优先级和进程执行的历史记录来确定下一个执行的进程。
- 实时调度策略
- SCHED_FIFO:基于优先级顺序调度进程,并在一个进程获得CPU时一直执行,直到进程主动释放。
- SCHED_RR:基于“时间片轮转”的调度策略,给每个进程设置一个固定的时间片,并按照优先级顺序对进程进行轮流调度。
1.4 进程调度实验设计
1.4.1 实验目标
- 验证 同一时刻只有一个进程在执行
- 验证 不同调度策略,进程执行的连续性不同
1.4.2 实验设计
- n个进程同时运行,统计各个进程的执行时刻
- 进程运行方式:
- 每个slice时间记录如下值:进程编号,当前时间值,完成度
- 在total时间后结束运行,并输出记录的数据
- 通过记录的数据分析进程调度策略
1.5 实验需解决的问题
- 如何让进程每次“固定”工作slice时间(单位毫秒)?
- 如何获取和改变进程的调度策略?
- 如何记录数据并输出数据(需要保存数据)?
- 如何图形化显示数据?
1.5.1 “固定”时间工作量估算
- Linux中的时间获取
1.5.2 获取/改变进程调度策略
- chrt命令简介
Linux系统中可以使用chrt命令来查看、设置一个进程的优先级和调度策略 - 命令用法
1.5.3 记录进程运行后产生数据
1.5.4 图形化数据显示与分析
1.6 编程实验:进程调度实验
- taskset实验
- 进程调度实验
#include <sys/wait.h>
#include <sys/resource.h>
#include <time.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sched.h>
#include <fcntl.h>
#define NLOOP_FOR_ESTIMATION 1000000000UL
#define NSECS_PER_MSEC 1000000UL
#define NSECS_PER_SEC 1000000000UL
#define DiffNS(begin, end) ((end.tv_sec - begin.tv_sec) * NSECS_PER_SEC \
+ (end.tv_nsec - begin.tv_nsec))
static unsigned long g_load_per_slice;
static struct timespec g_time_begin;
static unsigned long estimate_loops_per_msec() // 1ms有多少次循环
{
struct timespec begin = {0};
struct timespec end = {0};
unsigned long i = 0;
clock_gettime(CLOCK_MONOTONIC, &begin);
while (i < NLOOP_FOR_ESTIMATION) i++;
clock_gettime(CLOCK_MONOTONIC, &end);
return NLOOP_FOR_ESTIMATION / (DiffNS(begin, end) / NSECS_PER_MSEC);
}
static inline void work()
{
unsigned int i = 0;
// g_load_per_slice 每个时间片的循环次数
// 经过 1 个时间片的循环次数后返回,模拟工作 1 个时间片
while (i < g_load_per_slice) i++;
}
static void test(int id, struct timespec* tss, int nrecord)
{
struct timespec ts = {0};
char buf[128] = {0};
int fd = -1;
int i = 0;
// nrecord 记录的时间片数,也就是进程要执行的总时间
for (i = 0; i < nrecord; i++) {
work();
clock_gettime(CLOCK_MONOTONIC, tss + i);
}
sprintf(buf, "./%d-proc.log", id);
printf("%s\n", buf);
fd = open(buf, O_WRONLY | O_CREAT | O_TRUNC);
if (fd != -1) {
for (i = 0; i < nrecord; i++) {
sprintf(buf, "%d\t%ld\t%d\n",
id,
DiffNS(g_time_begin, tss[i]) / NSECS_PER_MSEC,
(i + 1) * 100 / nrecord);
write(fd, buf, strlen(buf));
}
}
close(fd);
}
int main(int argc, char* argv[])
{
int nproc = atoi(argv[1]); // 创建多少个进程
int total = atoi(argv[2]); // 每个进程需要执行的时间
int slice = atoi(argv[3]); // 时间片
int nrecord = total / slice;
// 申请记录 nrecord 条记录的 logbuf
struct timespec* logbuf = malloc(nrecord * sizeof(*logbuf));
pid_t* pids = malloc(nproc * sizeof(*pids));
total = total / slice * slice;
if (logbuf && pids) {
int i = 0;
int n = 0;
printf("nproc = %d\n", nproc);
printf("total = %d\n", total);
printf("slice = %d\n", slice);
printf("SCHED_OTHER = %d\n", SCHED_OTHER);
printf("SCHED_FIFO = %d\n", SCHED_FIFO);
printf("SCHED_RR = %d\n", SCHED_RR);
printf("Begin estimate work load per slice...\n");
g_load_per_slice = estimate_loops_per_msec() * slice; // 每个时间片的循环次数
printf("End ==> g_load_per_slice = %ld\n", g_load_per_slice);
clock_gettime(CLOCK_MONOTONIC, &g_time_begin); // 统计的起始时间
for (i = 0; i < nproc; i++) {
pids[i] = fork();
if (pids[i] < 0) {
int j = 0;
while (j < n) {
kill(pids[j++], SIGKILL); // 杀死创建成功的子进程
}
printf("Process create error...\n");
break;
} else if (pids[i] == 0) {
int sched = sched_getscheduler(0);
int pri = getpriority(PRIO_PROCESS, 0);
printf("task %d ==> schedule policy: %d\n", i, sched);
printf("task %d ==> schedule priority: %d\n", i, pri);
test(i, logbuf, nrecord);
exit(0);
} else {
n++;
}
}
}
free(logbuf);
free(pids);
return 0;
}
import sys
import numpy as np
import matplotlib.pyplot as plt
flag = sys.argv[1]
nproc = int(sys.argv[2])
data = []
colors = []
for fid in range(0, nproc):
fname = str(fid) + '-proc.log'
fd = open(fname, 'r')
lines = fd.readlines()
for s in lines:
s = s.strip().split('\t')
data.append( [int(s[0]), int(s[1]), int(s[2])] )
fd.close()
color = '#'
for c in np.random.randint(0, 255, 3):
color += format(c, '02X')
colors.append(color)
x_value = []
y_value = []
c_value = []
if flag == 'id-time':
for d in data:
y_value.append(d[0])
x_value.append(d[1])
c_value.append(colors[d[0]])
plt.scatter(x_value, y_value, c=c_value)
plt.title('Data Analysis')
plt.ylabel('Process No.')
plt.xlabel('TIme(ms)')
plt.show()
if flag == 'work-time':
for d in data:
y_value.append(d[2])
x_value.append(d[1])
c_value.append(colors[d[0]])
plt.scatter(x_value, y_value, c=c_value)
plt.title('Data Analysis')
plt.ylabel('Work Load')
plt.xlabel('TIme(ms)')
plt.show()
1.6.1 SCHED_OTHER
1.6.2 SCHED_RR
1.6.3 SCHED_FIFO