源码理解
从一开始的disksim_synthio.c文件中的相关函数入手(这是根据之前的源码理解这部分的代码和负载合成有关):
首先根据函数名字猜测1
synthio_generate_io_activity
函数是不是和负载合成的有关,查看该函数的定义如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15void synthio_generate_io_activity (process *procp)
{
synthio_generator *gen;
gen = (synthio_generator *) procp->space;
// fprintf (stderr, "simtime %f, endtime %f, iocnt %d, endiocnt %d\n", simtime, synthio_endtime, synthio_iocnt, synthio_endiocnt);
synthio_iocnt++;
if (synthio_generatenextio(gen)) {
synthio_appendio(procp, gen->pendio);
} else {
disksim_simstop();
}
}
可以看到该函数调用了其他两个相关的函数synthio_generatenextio和synthio_appendio前一个是生成一个IO请求,后一个是将生成的IO请求挂到对应的队列上去之后处理。
查看synthio_generatenextio(也在disksim_synthio.c文件)的定义
1 | static int synthio_generatenextio (synthio_generator *gen) |
可以该函数果然是调用iotrace_get_ioreq_event产生下一个io请求
查看synthio_appendio函数(也在disksim_synthio.c文件)定义:
1 | static void synthio_appendio (process *procp, ioreq_event *tmp) |
该函数的定义过于长,因此删除一部分的代码,可以看到这个代码中源码作者在这里有尝试输出部分的合成请求信息用于调试,但是这部分的New request不是我们想要的合成负载,这里面的负载还包含了一部分的模拟CPU中断的请求,CPU调度的,不可作为外部负载提取。因此利用GDB的bt命令重新查看函数的调用关系:
1 | graph TD |
为了方便理解先从disksim_run_simulation函数开始理解
1 | void disksim_run_simulation () |
开始看到该函数是反复调用disksim_simulate_event函数,查看disksim_simulate_event的定义:
1 | void disksim_simulate_event (int num) |
这个函数最主要的是根据当前的curr->type的类型调用不同函数的处理,curr结构体中包含了一部分和IO请求相关的信息,注意其中的代码片段:
1 | if (curr->type == INTR_EVENT) { |
负载合成是在第2个判断成立下执行的,调用了 pf_internal_event,同时注意到上一个条件貌似就是在执行IO请求。反过来考虑如果当前的负载合成关闭,输入外部负载也会调用这个条件处理IO请求,输入的参数就是外部负载,同理合成的负载也会进入该函数,输入的参数就是我们想要的合成负载数据。
因此进入io_internal_event ((ioreq_event *)curr)该函数查看相关的定义:
1 | void io_internal_event(ioreq_event *curr) |
函数是根据不同的类型模拟控制器处理请求,可以看到代码段:
1 | case IO_REQUEST_ARRIVE: |
其中IO_REQUEST_ARRIVE就是我们想要的外部负载处理的部分,这里调用了 iodriver_request(0, curr)函数:
1 | event * iodriver_request (int iodriverno, ioreq_event *curr) |
可以看到这个函数的注释部分有尝试输出负载:
1 | if (outios) { |
但是这个输出是文件指针outios是打开的,简单起见我们将负载直接输出到输出文件XXX.outv中,添加自己的代码:
1 | //test for output |
这里TheTest是为了后面的文本提取做的标记。
之后再编译运行相关配置文件得到XXX.outv中出现了我们想要的Trace:
1 | Initialization complete |
关于后面的标志位这里需要再提一下:
1 | 最后合成的:trace 每条请求如下: |
标志位里保存了trace的相关信息 ,包括读/写 以及是否local request 等
标志信息的定义在disksim_reqflags.h里,如下所示
1 | #define DISKSIM_WRITE 0x00000000 |
1 | #define DISKSIM_BATCH_COMPLETE 0x80000000 |
通过编写一个小的统计程序来收集生成的trace的信息,证明了生成的trace是满足我们要求的。
但是我们用disksim+flashsim的负载用的是ascii格式,这个标志位在之后需要进行修改:0表示写请求,1表示为读请求。
针对合成的负载提取有用的信息,写了一个shell脚本可以快速提取文件中信息:
1 | #!/bin/bash |
但是提取到的Trace的标位还没有修改完成,因此借助matlab快速的数据处理整合为符合条件的ascii类型的负载
1 | clc |
到此为止,将XXX.txt放入到Disksim+flashsim的仿真器上就能跑了。读写比例自己改配置文件即可。