智能嵌入式系统设计第九次实验
一、实验目的
依据任务优先执行列表进行划分,将任务分配给空闲的核(处理器)。本次实验通过c++编程实现MuPPA算法。
多核系统划分算法——MuPPA:
Input: 含有 n 个任务 J1,…,Jn的有向无环图 G、G 的节点依赖关系矩阵、任务释放时间表、任务执行时间表、k 个处理器 m1,…,mk
Output: n 个任务在 k 个处理器划分方案、k 个处理器最大执行时间、每个处理器使用率
第 1 步:使用公式计算这 n 个任务的优先级表:
OPri(Ji)=Ei+O(Ji)+Max{OPri(Jk) |Jk∈Suc(Ji)};
第 2 步:使用任务优先级排序算法 TaPSA 构建这 n 个任务优先级表;
(依次按照优先级值、释放时间、执行时间、编号大小排序)
第 3 步:按照任务优先级表级别高低检查其所有前驱任务是否已执行完毕,将所有前驱执行完毕且优先级别最高且释放时间已到的任务分配到空闲较长时间的处理器,同时将这个任务从优先级表中删除;
第 4 步:如果任务优先级表为空则算法结束,否则转到第 3 步。
二、实验内容
编程实现多核划分算法MuPPA,并给出下面两题的划分结果,并计算每个处理器的使用率。
(1). 图6-12含有5个任务,释放时间都是0,安排在两个处理器P1和P2上执行
(2) 将图6-13中11个任务调度到 3个处理器P1,P2和P3,其中 J4的释放时间为4,J8的释放时间为6,其余任务释放时间均为0。
三、实验代码(c++)
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
typedef struct{
int id; //任务编号
int o; //任务出度
int in; //依赖的任务数量
int priority; //任务优先级
int r_time; //任务释放时间
int e_time; //任务执行时间
bool visit; //标记是否已遍历
int processor; //执行任务的处理器
}Task;
typedef struct{
int id; //处理器ID
int e_time; //处理器使用时间
int w_time; //处理器等待时间
bool is_available; //处理器是否空闲
int end_time; //处理器执行任务结束的时间
int task; //正在执行的任务
}Processor;
int n; //任务数量
int h[N][N]; //依赖关系矩阵
int k; //处理器数量
int max_execution = 0; //处理器最大执行时间即系统完工时间
void add_opri(Task *tasks, int i)
{
//优先级已计算,直接返回
if (tasks[i].visit) return;
tasks[i].visit = true; //设置该任务的优先级已计算
int max_p = 0;
for (int j = 0; j < n; j ++ )
{
//任务j是任务i的后继点
if( h[i][j] == 1)
{
//找出优先级最大的直接后继点
add_opri(tasks, j);
if (tasks[j].priority > max_p)
{
max_p = tasks[j].priority;
}
}
}
tasks[i].priority = tasks[i].e_time + tasks[i].o + max_p;
return;
}
int comp (void const *a, void const *b )
{
Task *task_a = (Task *) a;
Task *task_b = (Task *) b;
if(task_b->priority == task_a->priority)
{
if(task_a->r_time == task_b->r_time)
{
if (task_a->e_time == task_b->e_time)
{
//优先级一样,按照释放时间从早到晚排序
return task_a->id - task_b->id;
}
else
{
//优先级和释放时间一样,按执行时间从大到小排序
return task_b->e_time - task_a->e_time;
}
}
else
{
//优先级一样,按照释放时间从早到晚排序
return task_a->r_time - task_b->r_time;
}
}
//优先级大的在前
return task_b->priority - task_a->priority;
}
void task_sort(Task *tasks, int n)
{
//1、按任务优先级进行排序
//2、如果任务优先级相等,依次比较任务释放时间,执行时间和编号
qsort(tasks, n, sizeof(Task), comp);
//3、输出排序结果
cout << "优先级表:";
for (int i = 0; i < n - 1; i ++ )
{
cout << "J" << tasks[i].id << ">";
}
cout << "J" << tasks[n - 1].id << endl;
}
void processor_allocation(Task *tasks, Processor *processors, int n, int k)
{
int time = 0; //记录时刻
int idle = 0; //记录空闲的处理器数
int task_completed = 0; //记录已完成任务数量
while(true)
{
cout << "时刻" << time << ": " ;
//把执行完任务的处理器设为空闲
for (int i = 0; i < k; i ++ )
{
if (processors[i].end_time == time){
processors[i].is_available = true;
//任务结束,把结束的任务的后继任务依赖减一
int task = processors[i].task;
for (int j = i; j < n ; j ++ )
{
if ( h[task - 1][tasks[j].id - 1] == 1)
{
tasks[j].in --;
}
}
processors[i].w_time = 0;
processors[i].task = 0;
idle ++;
}
}
//如果任务都执行完了且所有处理器都空闲就结束啦
if (task_completed == n && idle == k)
{
cout << "执行结束" << endl;
max_execution = time;
break;
}
//cout << "空闲的处理器个数为" << idle << endl;
//有空闲的处理器找任务执行
while(idle != 0){
//找所有前驱执行完毕(in==0),且优先级最高且释放时间已到的任务
int cur_task = -1; //记录即将执行的任务
for (int i = 0; i < n; i ++ )
{
if(tasks[i].processor == -1 && tasks[i].in == 0 && tasks[i].r_time <= time)
{
//找到就结束寻找
cur_task = i;
break;
}
}
//如果有可以执行的任务,就为它分配处理器
if (cur_task != -1)
{
task_completed ++;
//cout << tasks[cur_task].id << " " << endl;
//找空闲时间最长且可以分配的处理器
int max_WTime = -1; //空闲时间最长即执行时间最短
int cur_processor = 0;
for (int i = 0; i < k; i ++ )
{
if (processors[i].w_time > max_WTime && processors[i].is_available){
max_WTime = processors[i].w_time;
cur_processor = i;
}
}
//cout << processors[cur_processor].id << endl;
tasks[cur_task].processor = processors[cur_processor].id;
processors[cur_processor].end_time = tasks[cur_task].e_time + time;
processors[cur_processor].task = tasks[cur_task].id;
processors[cur_processor].e_time += tasks[cur_task].e_time;
processors[cur_processor].is_available = false;
idle --;
}
else
{
for (int i = 0; i < n; i ++){
if (processors[i].is_available)
{
processors[i].w_time ++ ;
}
}
break;
}
}
for (int i = 0; i < k; i ++ )
{
if (processors[i].task != 0)
{
cout << "P" << i + 1 << "执行T" << processors[i].task << " ";
}
else
{
cout << "P" << i + 1 << "空闲" << " ";
}
}
time ++;
cout << endl;
}
}
int main()
{
cout << "任务个数:";
cin >> n ;
cout << "处理器个数:";
cin >> k;
Task *tasks = (Task *) malloc (n * sizeof(Task));
Processor *processors = (Processor *) malloc (k * sizeof(Processor));
memset(h, -1, sizeof(h)); //初始化邻接表
cout << "请输入任务的释放时间:" << endl;
for (int i = 0; i < n; i ++ )
{
tasks[i].id = i + 1; //初始化任务的编号
tasks[i].o = 0; //初始化任务出度为0
tasks[i].in = 0; //初始化任务依赖数为0
tasks[i].visit = false; //初始化任务优先级未计算
tasks[i].processor = -1; //初始化未分配处理器
cin >> tasks[i].r_time;
}
cout << "请输入任务的执行时间:" << endl;
for (int i = 0; i < n; i ++ )
{
cin >> tasks[i].e_time;
}
cout << "请输入任务依赖矩阵:" << endl;
for (int i = 0; i < n; i ++ )
{
for (int j = 0; j < n; j ++ )
{
cin >> h[i][j];
if (h[i][j] == 1)
{
tasks[i].o ++;
tasks[j].in ++;
}
}
cout << endl;
}
cout << "------------------------------------------" << endl;
//1.第一步,计算优先级
for (int i = 0; i < n; i ++ )
{
add_opri(tasks, i);
}
cout << "优先级的计算结果:" << endl;
for (int i = 0; i < n ; i ++ )
{
cout << "OPri(J" << i + 1 << ")=" << tasks[i].priority << endl;
}
cout << "------------------------------------------" << endl;
//2.第二步,使用任务优先级排序算法 TaPSA 构建任务优先级表
task_sort(tasks, n);
cout << "------------------------------------------" << endl;
//3.第三步,将处理器初始化并将任务分配到处理器上执行
for (int i = 0; i < k; i ++ )
{
//初始化处理器
processors[i].id = i + 1;
processors[i].e_time = 0;
processors[i].w_time = 0;
processors[i].end_time = 0;
processors[i].task = 0;
}
processor_allocation(tasks, processors, n, k);
cout << "------------------------------------------" << endl;
//第四步,输出处理器最大执行时间以及每个处理器使用率
cout << "处理器最大执行时间:" << max_execution << endl;
for (int i = 0; i < k; i ++ )
{
cout << "P" << i + 1 << ":";
for (int j = 0; j < n; j ++ )
{
if (tasks[j].processor == processors[i].id){
cout << tasks[j].id << " ";
}
}
cout << endl;
double rate;
rate = double(processors[i].e_time) / double(max_execution) * 100;
cout << "处理器P" << i + 1 << "使用率:" << rate << "%" << endl;
}
free(tasks);
return 0;
}
四、实验结果
(1)
输入:
5
2
0 0 0 0 0
1 1 2 1 1
0 0 0 1 1
0 0 0 1 1
0 0 0 0 1
0 0 0 0 0
0 0 0 0 0
输出:
(2)
输入:
11
3
0 0 0 4 0 0 0 6 0 0 0
1 2 1 4 1 3 1 1 1 2 2
0 0 0 1 0 0 0 0 0 0 0
0 0 0 1 1 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 1 1 0 0 0 0
0 0 0 0 0 0 0 1 1 0 0
0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
输出: