使用进程组将特定的CPU留给特定的进程执行
以上使用的是cgroup v1,V2比较难用
安装
cgroup工具sudo apt install cgroup-tools
(可能需要)将计算机的Cgroup版本切换到v1
检查当前计算机使用的
cgroup配置bash
mount | grep cgroup- 如果你看到 cgroup2,说明你的系统使用的是 cgroups v2
- 切换:
sudo nano /etc/default/grub- 将
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"修改为GRUB_CMDLINE_LINUX_DEFAULT="systemd.unified_cgroup_hierarchy=0" - 更新grub并重启
sudo update-grubsudo reboot
给进程组分配适当的核心
sudo cgcreate -g cpuset:/<专属CPU组名>
sudo cgset -r cpuset.cpus="0,1" <专属CPU组名>
sudo cgset -r cpuset.mems="0" <专属CPU组名>使用在该CPU组下执行进程
sudo cgexec -g cpuset:/<专属CPU组名> <command>
结果
可见,虽然进程开启了4个线程,但是只占用了两个CPU核心,而且进程是两个两个执行的
创建额外的进程组
sudo cgcreate -g cpuset:/<其他进程共享剩余CPU核心的组>
将其他CPU分配给这个进程组
sudo cgset -r cpuset.cpus="2-11" <其他进程共享剩余CPU核心的组>
sudo cgset -r cpuset.mems="0" <其他进程共享剩余CPU核心的组>将系统剩余的进程划归这个进程组管理
sudo cgclassify -g cpuset:/<其他进程共享剩余CPU核心的组> $(pgrep -u $(whoami))
此时直接使用命令行执行一个具有20个线程的程序
CPU使用情况如图
- 虽然其他核心都被占满仍然不够,但是不会影响上述两个核心
也就是被上述进程独占的CPU不会受到任何影响
关于
sudo cgclassify -g cpuset:/<其他进程共享剩余CPU核心的组> $(pgrep -u $(whoami))的解释$(pgrep -u $(whoami))将所有当前用户的进程 ID 列出来,并将这些进程传递给cgclassify。- 这样,
cgclassify会将这些进程添加到<其他进程共享剩余CPU核心的组>cgroup 中。 - 如果当前用户的所有进程都被分配到 <其他进程共享剩余CPU核心的组> cgroup 中,那么新创建的进程(由这些进程派生的子进程)默认也会属于同一个 cgroup
- 因此,执行上述命令之后,即使不显式的指定进程组创建的进程,也会在
<其他进程共享剩余CPU核心的组>运行测试用的C语言程序
typedef struct {
long long start;
long long end;
long long sum;
} ThreadData;
// 计算时间差,以毫秒为单位
long get_time_diff_ms(struct timespec start, struct timespec end) {
return (end.tv_sec - start.tv_sec) * 1000 + (end.tv_nsec - start.tv_nsec) / 1000000;
}
long get_time_diff_ns(struct timespec start, struct timespec end) {
return (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_nsec - start.tv_nsec) / 1000;
}
// 设置进程为实时进程的函数
int set_realtime(int priority) {
struct sched_param param;
// 实时优先级范围通常为 1 到 99,99 为最高优先级
if (priority < 1 || priority > 99) {
fprintf(stderr, "Priority must be between 1 and 99.\n");
return -1;
}
// 设置调度参数的优先级
param.sched_priority = priority;
// 将进程设置为 SCHED_FIFO 调度策略
if (sched_setscheduler(0, SCHED_FIFO, ¶m) == -1) {
fprintf(stderr, "Failed to set realtime priority: %s\n", strerror(errno));
return -1;
}
printf("Process is now running with real-time priority %d\n", priority);
return 0;
}
// 累加函数,计算从 start 到 end 的累加和
void* accumulateRange(void* arg) {
ThreadData* data = (ThreadData*)arg;
struct timespec startTime, endTime;
// 记录开始时间
clock_gettime(CLOCK_MONOTONIC, &startTime);
data->sum = 0;
for (long long i = data->start; i <= data->end; ++i) {
data->sum += i;
}
printf("Thread calculating sum from %lld to %lld: %lld\n", data->start, data->end, data->sum);
// 记录结束时间
clock_gettime(CLOCK_MONOTONIC, &endTime);
long elapsedTime = get_time_diff_ns(startTime, endTime);
printf("Thread execution time: %ld (ns)\n", elapsedTime);
pthread_exit(NULL);
}
int main() {
long long rangeStart = 1; // 累加范围起始值
long long rangeEnd = ACC_RANGE; // 累加范围终止值
// int rangePerThread = (rangeEnd - rangeStart + 1) / NUM_THREADS;
set_realtime(90);
pthread_t threads[NUM_THREADS];
ThreadData threadData[NUM_THREADS];
struct timespec startTime, endTime;
// 记录开始时间
clock_gettime(CLOCK_MONOTONIC, &startTime);
// 创建线程并分配累加范围
for (int i = 0; i < NUM_THREADS; ++i) {
threadData[i].start = rangeStart;
threadData[i].end = rangeEnd;
pthread_create(&threads[i], NULL, accumulateRange, (void*)&threadData[i]);
}
// 等待所有线程完成,并汇总结果
long long totalSum = 0;
for (int i = 0; i < NUM_THREADS; ++i) {
pthread_join(threads[i], NULL);
// totalSum += threadData[i].sum;
}
// 记录结束时间
clock_gettime(CLOCK_MONOTONIC, &endTime);
// 计算并输出总运行时间
// long elapsedTime = get_time_diff_ms(startTime, endTime);
// printf("Total sum from %d to %d: %d\n", rangeStart, rangeEnd, totalSum);
// printf("Total execution time: %ld (ms)\n", elapsedTime);
long elapsedTime = get_time_diff_ns(startTime, endTime);
// printf("Total sum from %lld to %lld: %lld\n", rangeStart, rangeEnd, totalSum);
printf("Total execution time: %ld (ns)\n", elapsedTime);
return 0;
}如何删除进程组cgroup
查看当前的进程组结构
systemd-cgls查看进程组中所有进程
cat /sys/fs/cgroup/<group name>/cgroup.procs将所有进程移回根组之中
sudo cgclassify -g cpuset:/ $(cat /sys/fs/cgroup/<group name>/cgroup.procs然后执行
cat /sys/fs/cgroup/<group name>/cgroup.procs发现没有输出,证明当前组没有还在执行的进程了执行
sudo rmdir /sys/fs/cgroup/<group name>删除对应的进程组然后查看
ls /sys/fs/cgroup可见该进程组对应的CPU目录确实被删除了
python和C++如何将自己切换到某个组
python
- 不要直接使用类似于
os.system("sudo cgclassify -g cpuset:/<某个组> $$") - 因为os.system是启动了一个新的进程,可能无法正确切换当前的进程到某个组
- 要使用
os.system("sudo cgclassify -g cpuset:/ignite %d" % os.getpid()) - 使用
os.system("sudo cat /proc/self/cgroup | grep cpuset")查看在哪个组
C++
- 示例代码
int main() {
pid_t pid = getpid(); // 获取当前进程的 PID
// 打开 cgroup.procs 文件
int fd = open(CGROUP_PATH, O_WRONLY);
if (fd == -1) {
perror("Failed to open cgroup.procs");
return 1;
}
// 将 PID 写入 cgroup.procs
char pid_str[20];
snprintf(pid_str, sizeof(pid_str), "%d", pid);
if (write(fd, pid_str, sizeof(pid_str)) == -1) {
perror("Failed to write PID to cgroup.procs");
close(fd);
return 1;
}
close(fd);
printf("Process %d moved to ignite cgroup.\n", pid);
// 显示当前进程的 cgroup 信息
system("cat /proc/self/cgroup | grep cpuset");
return 0;
}