杭电实验一:用云主机加速内核编译

杭电实验一:用云主机加速内核编译


本次实验我使用极客云,价格良心,使用的是容器。本博客只打算粗略地写一写,写起来很头大。

(ps:如果你觉得本文不错,可以去传送门的博客园链接中赞助我-。-
欢迎杭电学弟学妹加我好友,联系方式也在博客园链接中。)

下载内核

进入主机后输入,下载linux内核,下载4.18会比较好一些

wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.18.19.tar.xz

使用命令解压

xz -d linux-4.19.tar.xz

tar -xvf linux-4.19.tar

安装make

我们需要安装make

apt-get install make

我们第一次编译先调用

make mrproper

期间报错需要安装:

sudo apt-get install libncurses5-dev

然后调用:

make menuconfig

点save=>exit

我们可以先make一下,大概不超过15分钟,-j表示使用最大核心数。

make -j

期间根据提示需要安装:

sudo apt-get install bison
sudo apt-get install flex
sudo apt-get install libelf-dev
sudo apt-get install libssl-dev
sudo apt-get install bc
apt-get install python-software-properties
apt-get install software-properties-common
  • make mrproper命令会删除所有的编译生成文件、内核配置文件(.config文件)和各种备份文件,所以几乎只在第一次执行内核编译前才用这条命令。

    make clean命令则是用于删除大多数的编译生成文件,但是会保留内核的配置文件.config,还有足够的编译支持来建立扩展模块。所以你若只想删除前一次编译过程的残留数据,只需执行make clean命令。

    总而言之,make mrproper删除的范围比make clean大,实际上,make mrproper在具体执行时第一步就是调用make clean

更改gcc

由于云主机内gcc版本过低,可能在make时会报错,我们需要下载gcc-8

sudo add-apt-repository ppa:ubuntu-toolchain-r/test

sudo apt-get update

sudo apt-get install gcc-8 g+±8

gcc-8 --version

由于默认用gcc编译内核,我们只好把gcc改为gcc-8

cd /user/bin

创建软连接ln -s gcc-8 gcc

添加系统调用

vim linux-4.19/arch/x86/entry/syscalls/syscall_64.tbl

336 64 mychangenicesyscall __x64_sys_change_nice_syscall

注意不要放在最后,放在合适的位置。

vim linux-4.19/include/linux/syscalls.h

int change_nice_syscall(pid_t pid, int flag, int nicevalue,void_user*prio,void_user*nice) 

sys.c

摘自https://blog.csdn.net/babybabyup/article/details/79839734#comments,里面有些错误,已改正。

SYSCALL_DEFINE5,2是两个变量,5是五个变量,0是没有变量。

SYSCALL_DEFINE5(mysetnice,pid_t,pid,int,flag,int,nicevalue,void __user*,prio,void __user*,nice){
    struct pid * kpid;/*进程描述符指针,指向一个枚举类型*/
    struct task_struct * task;/*任务描述符信息*/
    kpid = find_get_pid(pid);/* 根据进程号返回kpid,并增加引用次数count+1*/
    /*当引用计数为0时,当前进程就可以被抢占.*/
    task = pid_task(kpid, PIDTYPE_PID);/* 返回task_struct */
    int n;
    n = task_nice(task);/* 返回进程当前nice值 */
    int p;				/*这里linux内核编译时建议,先声明后赋值,不建议一起做*/
    p = task_prio(task);/*返回进程当前prio值*/
    if(flag == 1)
    {
        set_user_nice(task, nicevalue);/* 修改进程nice值 */
        n = task_nice(task);/*重新取得进程nice值*/
        p = task_prio(task);/*重新取得进程当前prio值*/
        copy_to_user(nice,&n,sizeof(n));/*将nice值拷贝到用户空间*/
        copy_to_user(prio,&p,sizeof(p));/*将prio值拷贝到用户空间*/
        return 0;  
    }
    else if(flag == 0)
    {
        copy_to_user(nice,&n,sizeof(n));/*将nice值拷贝到用户空间*/
        copy_to_user(prio,&p,sizeof(p));/*将prio值拷贝到用户空间*/
        return 0;
    }
    return EFAULT;

}
  • 关于用户空间和系统空间

copy_to_user

来自:~/arch/i386/lib/usercopy.c

相关函数:copy_from_user

在这里插入图片描述

  • 实时进程(rt_priority)和非实时进程

所谓实时,就是要你即刻处理,换言之,在容忍的范围内得马上处理,优先级要高(之后会讲),并且能够抢占其他进程。

实时进程之间的调度除了看优先级外,还需要看调度策略。

  • find_get_pid

来自:/linux/kernel/pid.c

enum pid_type
{
       PIDTYPE_PID,    //进程的进程号
       PIDTYPE_PGID,   //进程组领头进程的进程号
       PIDTYPE_SID,    //会话领头进程的进程号
       PIDTYPE_MAX 
}; 
  • struct task_struct

task_struct 中的成员变量 prio越小,进程的优先级越高。prio 值的取值范围为0…139。

来自:linux-2.6.30/include/linux/sched.h

#define MAX_USER_RT_PRIO	100
#define MAX_RT_PRIO		MAX_USER_RT_PRIO
 
#define MAX_PRIO		(MAX_RT_PRIO + 40)
#define DEFAULT_PRIO		(MAX_RT_PRIO + 20)

其中,实时进程(sched policy)的优先级取值范围是0…99,非实时进程的取值范围为100…139。

优先级转nice值时,通过当前task的静态优先级的值减去DEFAULT_PRIO。DEFAULT_PRIO的值是120。

  • task_prio
int task_prio(const struct task_struct *p)
{
	return p->prio - MAX_RT_PRIO;//ps 命令得到的priority 值也是 p->prio - 100 得到的!!!
}
  • set_user_nice源码
void set_user_nice(struct task_struct *p, long nice)
{
	bool queued, running;
	int old_prio, delta;
	struct rq_flags rf;
	struct rq *rq;
	//如果当前task的nice值已经等于要设置的nice值,就直接退出
    //从这里可以看出nice值的范围在-20~19 之间
	if (task_nice(p) == nice || nice < MIN_NICE || nice > MAX_NICE)
		return;
	rq = task_rq_lock(p, &rf);//锁住进程队列
	update_rq_clock(rq);
 
	//如果当前是实时进程,这里也可以看出实时进程的的调度策略可以分为deadline/fifo/rr.
	//针对实时进程设置nice值其实是没有作用的,但是这里还是将nice值转成优先级后设置到p->static_prio 
	if (task_has_dl_policy(p) || task_has_rt_policy(p)) {
		p->static_prio = NICE_TO_PRIO(nice);
		goto out_unlock;
	}
	queued = task_on_rq_queued(p);
	running = task_current(rq, p);
	if (queued)
		dequeue_task(rq, p, DEQUEUE_SAVE | DEQUEUE_NOCLOCK);
	if (running)
		put_prev_task(rq, p);
	//将nice值转成优先级设置到static_prio 中,#define NICE_TO_PRIO(nice)	((nice) + DEFAULT_PRIO)
	//这里的DEFAULT_PRIO 值经过计算是120.
	//从这里也可以看出优先级转nice值应该是减去DEFAULT_PRIO #define PRIO_TO_NICE(prio)	((prio) - DEFAULT_PRIO)
 
	p->static_prio = NICE_TO_PRIO(nice);
	set_load_weight(p);
	old_prio = p->prio;
	p->prio = effective_prio(p);
	delta = p->prio - old_prio;
	//如果要设置的nice的task在queue中
	if (queued) {
		enqueue_task(rq, p, ENQUEUE_RESTORE | ENQUEUE_NOCLOCK);
	//如果增大优先级且task正在运行或者减小优先级的话,则重新调度rq。
		if (delta < 0 || (delta > 0 && task_running(rq, p)))
			resched_curr(rq);
	}
	//如果要设置nice值的task正在运行,由于我们这里改变了p的优先级,则重新指定task的rq.
	if (running)
		set_curr_task(rq, p);
	out_unlock:
		task_rq_unlock(rq, p, &rf);
}
  • rq

进程就绪队列

  • 其他函数获取nice值

getpriority函数可以像nice函数获取进程nice值,而且他还可以获取一组相关进程的nice值。

make一下

make modules

make modules_install

make install

云主机无法执行update-grub2:服务器采用的是容器,貌似搞不了。

所以我们只能看看编译产生了什么文件,复制到虚拟机上:

/lib/modules 中有个4.19.0(内核库文件)

/boot全部文件(启动的核心档案和内核映像)

常见问题

arch/x86/entry/syscall_64.o:(.rodata+0x1120):对‘sys_zwhsyscall’未定义的引用

这是由于系统调用按其他调用的格式来写,加个__x64_

虚拟机运行

我们在复制好了文件后执行:

sudo update-grub2

我们编写测试样例:

#define _GNU_SOURCE
#include <unistd.h>
#include<sys/syscall.h>
#include<stdio.h>
#include<stdlib.h>
int main(){
    pid_t pid;
    int nicevalue;
    int flag;
    int p = 0;
    int n = 0;
    int *prio;
    int *nice;
    prio = &p;
    nice = &n;

    printf("请输入pid:\n");
    scanf("%d",&pid);
    printf("请输入nice:\n");
    scanf("%d",&nicevalue);

    printf("请输入flag:\n");
    scanf("%d",&flag);

    syscall(336,pid,flag,nicevalue,prio,nice);

    printf("现在的nice为%d\n,prio为%d\n",n,p);
    return 0;
}

测试

我先打开火狐浏览器,用命令查看所有进程:

ps -el

或者正则匹配一下和火狐有关的进程ps -el | grep fire

  • F 代表这个程序的旗标 (flag), 4 代表使用者为 superuser;
  • S 代表这个程序的状态 (STAT);
  • UID 代表执行者身份
  • PID 进程的ID号!
  • PPID 父进程的ID;
  • C CPU使用的资源百分比
  • PRI指进程的执行优先权(Priority的简写),其值越小越早被执行;
  • NI 这个进程的nice值,其表示进程可被执行的优先级的修正数值。
  • ADDR 这个是内核函数,指出该程序在内存的那个部分。如果是个执行 的程序,一般就是『 - 』
  • SZ 使用掉的内存大小;
  • WCHAN 目前这个程序是否正在运作当中,若为 - 表示正在运作;
  • TTY 登入者的终端机位置;
  • TIME 使用掉的 CPU 时间。
  • CMD 所下达的指令名称

找到火狐的pid,图中为XXX,用以下命令可以查到进程详细信息,如nice值。

top -p pid

我们编写测试用例:

#define _GNU_SOURCE
#include <unistd.h>
#include<sys/syscall.h>
#include<stdio.h>
#include<stdlib.h>
int main(){
    pid_t pid;
    int nicevalue;
    int flag;
    int p = 0;
    int n = 0;
    int *prio;
    int *nice;
    prio = &p;
    nice = &n;

    printf("请输入pid:\n");
    scanf("%d",&pid);

    printf("请输入nice:\n");
    scanf("%d",&nicevalue);

    printf("请输入flag:\n");
    scanf("%d",&flag);

    syscall(334,pid,flag,nicevalue,prio,nice);

    printf("现在的nice为%d\n,prio为%d\n",n,p);
    return 0;
}
  • nice值的范围?

PRI指进程的执行优先权(Priority的简写),其值越小越早被执行

进程的nice值表示进程可被执行的优先级的修正数值。

如果nice过大或过小,都会被系统降到最大合法值或提高到最小合法值。

nice范围从-20~19,其中-20最高,19最低,只有系统管理者可以设置负数的等级。

当我们更改nice值时,系统不会对错误的nice值做响应。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值