flashsim源码阅读-4

再次回到disksim_simulate_event()函数主体:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
void disksim_simulate_event (int num)
{
event *curr;

if ((curr = getnextevent()) == NULL) {
disksim_simstop ();
}
else {

switch(disksim->trace_mode) {
case DISKSIM_NONE:
case DISKSIM_MASTER:
// fprintf(outputfile, "*** DEBUG TRACE\t%f\t%d\t%d\n",
// simtime, curr->type, num);
// fflush(outputfile);
break;

case DISKSIM_SLAVE:
break;
}

simtime = curr->time;

if (curr->type == INTR_EVENT) {
intr_acknowledge (curr);
}
else if ((curr->type >= IO_MIN_EVENT) && (curr->type <= IO_MAX_EVENT)) {
io_internal_event ((ioreq_event *)curr);
}
else if ((curr->type >= PF_MIN_EVENT) && (curr->type <= PF_MAX_EVENT)) {
pf_internal_event(curr);
}
else if (curr->type == TIMER_EXPIRED) {
timer_event *timeout = (timer_event *) curr;
(*timeout->func) (timeout);
}
else if ((curr->type >= MEMS_MIN_EVENT)
&& (curr->type <= MEMS_MAX_EVENT)) {
io_internal_event ((ioreq_event *)curr);
}
else if (curr->type == CHECKPOINT) {
if (disksim->checkpoint_interval) {
disksim_register_checkpoint(simtime + disksim->checkpoint_interval);
}
disksim_checkpoint (disksim->checkpointfilename);
}
else if (curr->type == STOP_SIM) {
disksim_simstop ();
}
else if (curr->type == EXIT_DISKSIM) {
exit (0);
}
else {
fprintf(stderr, "Unrecognized event in simulate: %d\n", curr->type);
exit(1);
}

对event的type类型的宏定义在disksim_global.h中有:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* Event Type Ranges */

#define NULL_EVENT 0
#define PF_MIN_EVENT 1
#define PF_MAX_EVENT 97
#define INTR_EVENT 98
#define INTEND_EVENT 99
#define IO_MIN_EVENT 100
#define IO_MAX_EVENT 120
#define TIMER_EXPIRED 121
#define CHECKPOINT 122
#define STOP_SIM 123
#define EXIT_DISKSIM 124
#define MEMS_MIN_EVENT 200
#define MEMS_MAX_EVENT 220

函数getnextevent()在disksim.c中的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
INLINE static event * getnextevent ()
{
event *curr = getfromintq();
event *temp;

if (curr) {
simtime = curr->time;
//取到的event为非空
if (curr->type == NULL_EVENT) {
if ((disksim->iotrace) && io_using_external_event(curr)) {
if ((temp = io_get_next_external_event(disksim->iotracefile)) == NULL) {
disksim->stop_sim = TRUE;
}
} else {
fprintf(stderr, "NULL_EVENT not linked to any external source\n");
exit(1);
}
if (temp) {
temp->type = NULL_EVENT;
addtointq(temp);
}
}
}
else {
//取到的event为空
fprintf (outputfile, "Returning NULL from getnextevent\n");
fflush (outputfile);
}
return(curr);
}

getnextevent函数最主要的是通过调用getfromintq从调度队列中取出一个event,取出这个event的时候当前的系统时间simtime等于这个event所指定的time。但是对于函数中当取到的event的类型为NULL_EVENT的处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if (curr->type == NULL_EVENT) {
if ((disksim->iotrace) && io_using_external_event(curr)) {
if ((temp = io_get_next_external_event(disksim->iotracefile)) == NULL) {
disksim->stop_sim = TRUE;
}
} else {
fprintf(stderr, "NULL_EVENT not linked to any external source\n");
exit(1);
}
if (temp) {
temp->type = NULL_EVENT;
addtointq(temp);
}
}

我目前猜测,当event类型为NULL_EVENT是表示当前的bus channel是空闲的,可以服务读写请求,是依据这句话猜测的

1
if ((disksim->iotrace) && io_using_external_event(curr))

这里又涉及了disksim结构体的一个变量iotrace这个变量最早出现和配置是在disksim_setup_disksim()函数中,关于这个函数的详细解释在明天的笔记中讲初始化的时候会研究,先看其关于iotrace配置的代码段:

1
2
3
4
if(strcmp(argv[5], "0") != 0) {
disksim->synthgen = 1;
disksim->iotrace = 0;
}

这里需要解释下关于仿真器disksim的使用在Linux终端输入的命令参数是:disksim \参数文件 \输出文件 \ trace输入格式\trace文件\synthgen(是否激活disksim内部负载生成仿真,一般为0)
对应在main(argv)的参数表:argv[0],…,argv[5]。
disksim->synthgen=1表示disksim自己生成trace进行仿真,disksim->iotrace为非零表示使用外部trace,为0表示不用外部负载。
那么看下io_using_external_event(event *curr)函数是干什么的,该函数在disksim_iosim.c中定义:

1
2
3
4
5
6
7
8
9
int io_using_external_event (event *curr)
{
if (io_extq == curr) {
curr->type = io_extq_type;
io_extq = NULL;
return(1);
}
return(0);
}

这个函数判断输入的event 指针指向的内容和当前的io_extq指针指向的内容是否相同,相同返回1且将curr的type置为io_extq_type(这是一个宏),不同返回0。
io_extqio_extq_type都是宏,在disksim_iosim.c文件头部(删除现在不必要的显示)就声明了:

1
2
3
4
5
/* one remapping #define for each variable in iosim_info_t */
#define io_extq (disksim->iosim_info->io_extq)
#define io_extqlen (disksim->iosim_info->io_extqlen)
#define io_extq_type (disksim->iosim_info->io_extq_type)
。。。。。。。。。。还有一些相关宏不再此展示,之后看到再研究

又扯到disksim结构体的定义了,iosim_info是disksim中对硬件相关模型的定义一种,且看节选代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

/* opaque structures for different modules */
/*不透明封装的结构体*/
struct iosim_info *iosim_info;
struct device_info *deviceinfo;
struct disk_info *diskinfo;
struct simpledisk_info *simplediskinfo;
struct simpleflash_info *simpleflashinfo;
struct mems_info *memsinfo;
struct iodriver_info *iodriver_info;
struct businfo *businfo;
struct ctlrinfo *ctlrinfo;
struct pf_info *pf_info;
struct synthio_info *synthio_info;
struct iotrace_info *iotrace_info;
struct rand48_info *rand48_info;

上述的结构体在disksim_global.h中只是声明,具体的定义都在各自的文件里面,如iosim_info在disksim_iosim.c中才定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
typedef struct iosim_info {
event * io_extq;
int io_extqlen;
int io_extq_type;
double ioscale;
double last_request_arrive;
double constintarrtime;
int validatebuf[10];
int tracemappings;
int tracemap[TRACEMAPPINGS];
int tracemap1[TRACEMAPPINGS];
int tracemap2[TRACEMAPPINGS];
int tracemap3[TRACEMAPPINGS];
int tracemap4[TRACEMAPPINGS];
statgen *tracestats;
statgen *tracestats1;
statgen *tracestats2;
statgen *tracestats3;
statgen *tracestats4;
statgen *tracestats5;
} iosim_info_t;

现在可以理解io_extq就是一个event类型的指针,io_extq_type就是个int型的数和event中的type是一样的,那么io_extq_type有那些宏定义可以选择,我猜测和前面的event的type类型选择是一样的。把前面的if的语句展开仔细看理解

1
2
3
4
5
6
7
8
if ((disksim->iotrace) && io_using_external_event(curr)) {
if ((temp = io_get_next_external_event(disksim->iotracefile)) == NULL) {
disksim->stop_sim = TRUE;
}
} else {
fprintf(stderr, "NULL_EVENT not linked to any external source\n");
exit(1);
}

###总结getnextevent()函数
这么理解函数,从intq队列中取出一个event,如果该event的类型为NULL_EVENT时,getnextevent()函数根据仿真采用负载为外部负载且调用io_using_external_event()判断当前的event和io_extq指向的内容是否相同,若相同则把event的类型改成当前的io_extq_type的类型,io_get_next_external_event()函数应该能判断外部的负载输入是否结束,从而将disksim->stop_sim置为TRUE,结束仿真,如果外部负载不为空,即(temp = io_get_next_external_event(disksim->iotracefile)返回不为空,则把该temp的类型置为NULL_EVENT,调用addtointq(temp);将temp加入intq队列中,这么操作有点栈的意思。先从intq取栈顶的元素event,event的类型为NULL_EVENT则一般是为使用外部负载,需要判断外部负载判断结束时间驱动,没有结束,则将新的NULL_EVENT的event类型(temp)压入栈(intq)。这是我目前的理解。

###该函数的继续延伸阅读
getnextevent()函数调用了io_get_next_external_event()函数,在介绍这个函数之前,先引入了解处理I/O请求的结构体ioreq_event,在disksim_global.h中有定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
typedef struct ioreq_ev {
double time;
int type;
struct ioreq_ev *next;
struct ioreq_ev *prev;
int bcount;
int blkno;
u_int flags;
u_int busno;
u_int slotno;
int devno;
int opid;
void *buf;
int cause;
int tempint1;
int tempint2;
void *tempptr1;
void *tempptr2;
void *mems_sled; /* mems sled associated with a particular event */
void *mems_reqinfo; /* per-request info for mems subsystem */
double start_time; /* temporary; used for memulator timing */
} ioreq_event;

其实ioreq_eventevent结构体可以强制类型转化的,这个在io_get_next_external_event()函数里面有句话:

1
2
3
ioreq_event *temp;
ASSERT(io_extq == NULL);
temp = (ioreq_event *) getfromextraq();

getfromextrq函数返回的是event结构体指针,这里突然理解了,event的结构体里面的

1
char space[DISKSIM_EVENT_SPACESIZE];

其实就是为了将这部分内存字段转化为其他类型的时候存其他数据使用的。代码读到这突然觉得需要系统的捋一边系统的初始化过程和主要的结构体变量了,思路有点乱。

热评文章