策略
多核cpu调度算法分为两种,一种是全局队列调度,一种是局部队列调度。
全局队列调度 :操作系统维护一个全局的任务等待队列。当系统中有一个CPU核心空闲时,操作系统就从全局任务等待队列中选取就绪任务开始在此核心上执行。这种方法的优点是CPU核心利用率较高。
局部队列调度:操作系统为每个CPU内核维护一个局部的任务等待队列。当系统中有一个CPU内核空闲时,便从该核心的任务等待队列中选取恰当的任务执行。这种方法的优点是任务基本上无需在多个CPU核心间切换,有利于提高CPU核心局部Cache命中率。
因为目前多数多核CPU操作系统采用的是基于全局队列的任务调度算法,因此本题中也用基于全局队列的任务调度算法。原有的针对进程的多级反馈队列调度算法不变,但新维护一个cpu队列。当有进程需要运行时,查询该队列,若有cpu空闲时,则将新的进程放入该cpu运行。
具体实现方法为:在定义中增加结构体cpu和multi_cpu分别表示cpu和cpu队列。
代码
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <limits.h>
#include <stdbool.h>
//cpu运行节点
struct cpu_run{
int cid;
int run_time;
struct cpu_run *next;
};
//cpu运行节点队列
struct cpu_run_queue{
int size;
struct cpu_run *head; //链表
struct cpu_run *tail;
};
// 进程的结构体
struct process{
int pid;
int running_time; //in minisec
int request_time;
int remaining_time;
int init_time;
int start_time;
int end_time;
struct cpu_run_queue *cpu_run_queues;
};
// 就绪队列的节点
struct node{
struct process *proc;
struct node *next;
};
// 就绪队列
struct queue{
int size;
int time_slot;
struct node *head; //链表
struct node *tail;
};
// 多级队列
struct multi_queue{
int level;
struct queue *queues; //数组
};
// CPU
struct cpu{
int cid;
int cpu_time;//cpu上次结束工作的时间
};
// 多CPU
struct multi_cpu{
int num_cpu;
struct cpu *cpus; //数组
};
// 模拟调度过程中的墙上时间
int MACHINE_TIME = 0;
struct queue *finished_tasks;
void init_mlfq(struct multi_queue *mlfq, int level, int num_proc,struct multi_cpu *mlcpu,int num_cpu);
struct queue* init_empty_queue();
bool schedule(struct multi_queue *mlfq,struct multi_cpu *mlcpu,int num_cpu);
void mlfq_run();
void join_queue(struct queue *subque, struct node *job);
void print_schedule_results();
int time_forward(int elapse);
struct node* out_queue(struct queue *subque);
struct process* process_generator(int pid);
struct queue* processes_generator(int num_proc);
float get_average_turnover(struct queue *procs);
float get_average_weighted_turnover(struct queue *procs);
//--------------------------------------------------//
//打印调度结果
void print_schedule_results(){
struct node *p = finished_tasks->tail;
while(p!=NULL){
printf("********************************************\n");
printf("Process pid: \t %d\n", p->proc->pid);
printf("request time: \t %d\n", p->proc->request_time);
printf("Init time:\t %d\n", p->proc->init_time);
printf("Start time: \t %d\n", p->proc->start_time);
printf("Running time:\t %d\n", p->proc->running_time);
printf("Finish time:\t %d\n", p->proc->end_time);
printf("Time span:\t %d\n", p->proc->end_time - p->proc->init_time);
printf("Cpu allocate:\t \n");
struct cpu_run *c = p->proc->cpu_run_queues->tail;
while(c!=NULL){
printf(" Cpu id:\t %d ",c->cid);
printf("Run_time:\t %d",c->run_time);
printf("\n");
c=c->next;
}
p = p->next;
}
return;
}
//--------------------------------------------------//
//平均周转时间
float get_average_turnover(struct queue *procs){
struct node *p = procs->tail;
int count = procs->size;
int total_turnover = 0;
while(p!=NULL){
total_turnover += p->proc->end_time - p->proc->init_time;
p = p->next;
}
return (float)total_turnover/(float)count;
}
//--------------------------------------------------//
//带权周转时间
float get_average_weighted_turnover(struct queue *procs){
struct node *p = procs->tail;
int count = procs->size;
float total_turnover = 0;
while(p!=NULL){
total_turnover += (p->proc->end_time - p->proc->init_time)/p->proc->running_time;
p = p->next;
}
return total_turnover/(float)count;
}
//--------------------------------------------------//
//初始化空队
struct queue* init_empty_queue(){
struct queue *empty_queue = (struct queue*)malloc(sizeof(struct queue));
empty_queue->size = 0;
empty_queue->time_slot = 0;
empty_queue->head = NULL;
empty_queue->tail = NULL;
return empty_queue;
}
//--------------------------------------------------//
//初始化空cpu_run队
struct cpu_run_queue* init_empty_cpu_run_queue(){
struct cpu_run_queue *empty_cpu_run_queue = (struct cpu_run_queue*)malloc(sizeof(struct cpu_run_queue));
empty_cpu_run_queue->size = 0;
empty_cpu_run_queue->head = NULL;
empty_cpu_run_queue->tail = NULL;
return empty_cpu_run_queue;
}
//--------------------------------------------------//
void mlfq_run(){
struct multi_queue *mlfq = (struct multi_queue*)malloc(sizeof(struct multi_queue));
struct multi_cpu *mlcpu = (struct multi_cpu*)malloc(sizeof(struct multi_cpu));
int num_proc = 20;
int level = 7;
int num_cpu=5;
init_mlfq(mlfq, level, num_proc,mlcpu,num_cpu);
printf("********************************************\n");
printf("Initialize mlfq finished.\n");
printf("Number of levels in mlfq: \t\t %d\n", level);
printf("Number of processes to be scheduled: \t %d\n", num_proc);
printf("Number of cpus to be scheduled: \t %d\n", num_cpu);
finished_tasks = init_empty_queue();
printf("Initialize finished_tasks finished.\n");
printf("Starts mlfq scheduling...\n");
MACHINE_TIME = 0;
while(schedule(mlfq,mlcpu,num_cpu));
}
//--------------------------------------------------//
// 模拟计算时钟
int time_forward(int elapse){
MACHINE_TIME += elapse;
return MACHINE_TIME;
}
//--------------------------------------------------//
//入队
void join_queue(struct queue *subque, struct node *job){
if(subque->size!=0){
job->next = subque->tail;
subque->size = subque->size + 1;
subque->tail = job;
}
else{
job->next = NULL;
subque->size = subque->size + 1;
subque->head = job;
subque->tail = job;
}
}
//--------------------------------------------------//
//出队
struct node* out_queue(struct queue *subque){
struct node *job = NULL;
if(subque->size==0){
return NULL;
}
else if(subque->size==1){
job = subque->tail;
job->next = NULL;
subque->tail = NULL;
subque->head = NULL;
subque->size = 0;
return job;
}
else{
job = subque->head;
job->next = NULL;
struct node *p;
p = subque->tail;
for(int i=0; i<subque->size-2; i++){
p = p->next;
}
p->next = NULL;
subque->size = subque->size - 1;
subque->head = p;
return job;
}
}
//--------------------------------------------------//
//cpu_run入队
void join_cpu_run_queue(struct cpu_run_queue *subque, struct cpu_run *job){
if(subque->size!=0){
job->next = subque->tail;
subque->size = subque->size + 1;
subque->tail = job;
}
else{
job->next = NULL;
subque->size = subque->size + 1;
subque->head = job;
subque->tail = job;
}
}
//--------------------------------------------------//
//调度
bool schedule(struct multi_queue *mlfq,struct multi_cpu *mlcpu,int num_cpu){
bool flag = false;
for(int i=0; i<mlfq->level; i++){//对于每一层
struct queue *q = &((mlfq->queues)[i]); //取出队列
struct node *p = (mlfq->queues)[i].head; //取出队列首结点
if(p!=NULL){
if(p->proc->init_time > MACHINE_TIME)
time_forward(p->proc->init_time - MACHINE_TIME);
if(p->proc->start_time == INT_MAX)
p->proc->start_time = MACHINE_TIME;
flag = true;
//如果剩余的运行时间大于当前队列的时间片
if(p->proc->remaining_time > q->time_slot){
p->proc->running_time += q->time_slot;
p->proc->remaining_time = p->proc->remaining_time - q->time_slot;
if(p->proc->remaining_time!=0){
//看哪个cpu空闲,便将该进程分配给该cpu
for(int i=0;i<num_cpu;i++){
if((mlcpu->cpus)[i].cpu_time<=MACHINE_TIME){
(mlcpu->cpus)[i].cpu_time+=q->time_slot;
//生成cpu_run结构体,放入该进程对应的cpu_run队列中
struct cpu_run *cr= (struct cpu_run *)malloc(sizeof(struct cpu_run));
cr->cid=i;
cr->run_time=q->time_slot;
join_cpu_run_queue(p->proc->cpu_run_queues, cr);
break;
}
}
}
out_queue(q);
}
else {
p->proc->running_time += p->proc->remaining_time;
for(int i=0;i<num_cpu;i++){
if((mlcpu->cpus)[i].cpu_time<=MACHINE_TIME){
(mlcpu->cpus)[i].cpu_time+= p->proc->remaining_time;
//生成cpu_run结构体,放入该进程对应的cpu_run队列中
struct cpu_run *cr= (struct cpu_run *)malloc(sizeof(struct cpu_run));
cr->cid=i;
cr->run_time=p->proc->remaining_time;
join_cpu_run_queue(p->proc->cpu_run_queues, cr);
break;
}
}
p->proc->end_time = p->proc->remaining_time+MACHINE_TIME;
p->proc->remaining_time = 0;
out_queue(q);
}
}
else{
continue; //取出下一层运行
}
//如果运行后还有剩余运行时间,则放入下一层
if(p->proc->remaining_time!=0){
//如果下一层还有
if((i+1)!=mlfq->level){
join_queue(&((mlfq->queues)[i+1]), p);
}
//如果没有下一层了
else{
join_queue(&((mlfq->queues)[i]), p);
}
}
//完成了,放入已完成队列
else{
join_queue(finished_tasks, p);
}
break;
}
return flag;
}
//--------------------------------------------------//
//初始化
void init_mlfq(struct multi_queue *mlfq, int level, int num_proc, struct multi_cpu *mlcpu, int num_cpu){
struct queue *procs;
procs = processes_generator(num_proc);
mlfq->level = level;
mlfq->queues = (struct queue *)calloc(level, sizeof(struct queue));
for(int i=0; i<level; i++){
(mlfq->queues)[i].size = 0;
(mlfq->queues)[i].time_slot = (i+1)*2;
(mlfq->queues)[i].head = NULL;
}
mlfq->queues[0] = *procs;
mlcpu->cpus = (struct cpu *)calloc(num_cpu, sizeof(struct cpu));
mlcpu->num_cpu = num_cpu;
for(int i = 0;i<num_cpu;i++){
(mlcpu->cpus)[i].cid = i;
(mlcpu->cpus)[i].cpu_time = 0;
}
}
//--------------------------------------------------//
//随机生成进程
struct process* process_generator(int pid){
struct process *proc = (struct process *)malloc(sizeof(struct process));
proc->pid = pid;
proc->running_time = 0;
proc->request_time = 10 + rand()%91;
proc->remaining_time = proc->request_time;
proc->init_time = MACHINE_TIME;
time_forward(10+rand()%41);
proc->start_time = INT_MAX;
proc->end_time = INT_MAX;
proc->cpu_run_queues = init_empty_cpu_run_queue();
return proc;
}
//--------------------------------------------------//
//随机生成进程队列
struct queue* processes_generator(int num_proc){
struct queue *procs;
procs = (struct queue *)malloc(sizeof(struct queue));
procs->size = 0;
procs->time_slot = 0;
if(num_proc<=0){
printf("ERROR in process_generator: argument non-positive!");
return NULL;
}
for(int i=0; i<num_proc; i++){
struct node *tmp = (struct node *)malloc(sizeof(struct node));
tmp->proc = process_generator(i);
tmp->next = NULL;
join_queue(procs, tmp);
}
return procs;
}
//--------------------------------------------------//
int main(int argc, char* argv[]){
mlfq_run();
print_schedule_results();
float average_turnover = get_average_turnover(finished_tasks);
float average_weighted_turnover = get_average_weighted_turnover(finished_tasks);
printf("********************************************\n");
printf("Average turnover: \t\t %f\n", average_turnover);
printf("Average weighted turnover: \t %f\n", average_weighted_turnover);
return 0;
}
运行效果: