您的位置:首页 > 其它

测试工具sgp_dd分析

2012-05-15 17:28 239 查看
测试工具sgp_dd是sg3_utils包中的一个测试裸盘读写速度的工具,它利用多线程以将磁盘分区域并行读写的方式来测试







分析目的集中于信号处理方式、多线程以及SCSI命令简介

包含文件及宏定义

除了包含linux中的库文件之外,在sgp_dd.c中还包含了3个头文件,跟sg有关:

l sg_lib.h:SG通用库头文件;

l sg_cmds_basic.h:SG基本命令头文件;

l sg_io_linux: SG在linux平台上的io处理函数头文件;

一些关于默认块大小、默认每次传输块数、SCSI命令描述块大小(CDB:command descriptor block)、设备类型的宏定义:

#define FT_OTHER 1 /* filetype other than one of the following */

#define FT_SG 2 /* filetype is sg char device */

#define FT_RAW 4 /* filetype is raw char device */

#define FT_DEV_NULL 8 /* either "/dev/null" or "." as filename */

#define FT_ST 16 /* filetype is st char device (tape) */

#define FT_BLOCK 32 /* filetype is a block device */

#define FT_ERROR 64 /* couldn't "stat" file */

通过stat()函数获得设备文件名代表的文件属性信息st,可通过查看st. st_mode判断是字符设备还是块设备,st. st_rdev的主次设备号,判断具体是哪种设备。相关函数和宏有:S_ISCHR()、S_ISBLK()、major()和minor等。

几个结构体

结构体struct flags_t,各种标记组合的结构体

类型

描述
int

append

用于设置打开标记O_APPEND

int

coe

continue on error, 0->exit (def), 1->zero + continue

出错时时根据这个值决定如何处理

int

dio

is direct IO, 1->attempt, 0->indirect IO (def),用于设置struct sg_io_hdr的flags |= SG_FLAG_DIRECT_IO

int

direct

int

dpo

用于设置CDB

int

dsync

用于设置open标记O_SYNC

int

excl

用于设置open标记O_EXCL

int

fua

force unit access: 0->don't(def), 1->OFILE, 2->IFILE,

3->OFILE+IFILE

用于设置CDB

[root@oss5 ~]# sgp_dd --help | grep dpo

Usage: sgp_dd [bs=BS] [count=COUNT] [ibs=BS] [if=IFILE][iflag=FLAGS]

[obs=BS] [of=OFILE][oflag=FLAGS] [seek=SEEK] [skip=SKIP]

[--help] [--version]

[bpt=BPT] [cdbsz=6|10|12|16][coe=0|1] [deb=VERB] [dio=0|1]

[fua=0|1|2|3] [sync=0|1][thr=THR] [time=0|1] [verbose=VERB]

where:

bpt is blocks_per_transfer(default is 128)

bs must be device blocksize (default 512)

cdbsz size of SCSI READ orWRITE cdb (default is 10)

coe continue on error,0->exit (def), 1->zero + continue

count number of blocks tocopy (def: device size)

deb for debug, 0->none(def), > 0->varying degrees of debug

dio is direct IO,1->attempt, 0->indirect IO (def)

fua force unit access:0->don't(def), 1->OFILE, 2->IFILE,

3->OFILE+IFILE

if file or device to readfrom (def: stdin)

iflag comma separated listfrom: [coe,dio,direct,dpo,dsync,excl,

fua, null]

of file or device towrite to (def: stdout), OFILE of '.'

treated as /dev/null

oflag comma separated listfrom: [append,coe,dio,direct,dpo,dsync,

excl,fua,null]

sync 0->no sync(def), 1->SYNCHRONIZECACHE on OFILE after copy

thr is number of threads,must be > 0, default 4, max 16

time 0->no timing(def),1->time plus calculate throughput

verbose same as 'deb=VERB':increase verbosity

--help output this usagemessage then exit

--version output version stringthen exit

Copy from IFILE to OFILE, similar to ddcommand

specialized for SCSI devices, uses multiplePOSIX threads

读命令:

Disable Page Out (DPO) allows the initiator to warn the target that
the data being read isunlikely to be requested again soon and so is not worth keeping in the target'sdata cache. Force Unit Access (FUA) tells the target to fetch the data from themedia surface and to not use a cached copy

写命令:

Disable Page Out (DPO) allows the initiator to warn the target that
the data being writtenis unlikely to be read back soon and so is not worth keeping in the target'sdata cache. Force Unit Access (FUA) tells the target to immediately send thedata to the media surface and to not buffer it through a cache. The EBP bittells the
target that it may skip the erase process when writing data. TheRelAdr bit is used to indicate that the LBA value is relative (only used with linkedcommands)

结构体struct request_collection被typedef为Rq_coll,记录了一个sgp_dd命令总共要传输的数据:

类型

描述
int

infd

读取数据的文件句柄,即输入设备

int64_t

skip

从读取数据的文件开头跳过多少个块数据

int

in_type

输入设备类型,FT_*

int

cdbsz_in

读取数据的CDB大小,默认是10

struct flags_t

in_flags

标记集合

int64_t

in_blk

下一个要读取的块的地址

int64_t

in_count

初始化为dd_count(要读取的数据块总数),该成员代表要读取的总块数剩余值,每个线程读完成后都会减去实际读取的块数,每个线程每次读时看到的都不同

int64_t

in_rem_count

残余读取块数,每次线程读取时,有可能无法读取指定的块数,in_rem_count初始化为in_count,每次一个线程完成一个读取操作,就把in_rem_count减去实际读取的blocks,最后命令结束时,用指定要传输的数据总数dd_count减去in_rem_count得到实际读取的数据总数

int

in_partial

实际读取的数据大小非整数个块大小的个数

int

in_stop

读取结束标记

pthread_mutex_t

in_mutex

读取互斥锁

输出:

int

outfd

输出文件句柄

int64_t

seek

输出首地址跳过的块数

int

out_type

输出设备类型,FT_*

int

cdbsz_out

输出CDB大小,默认为10

struct flags_t

out_flags

输出标记组合

int64_t

out_blk

下一次要写入的块位置

int64_t

out_count

初始化为dd_count,每一次线程写,都会减去该线程读取出而要写入的块数,每个线程看到的下一次输出要输出的总块数不同。

int64_t

out_rem_count

初始化为dd_count,每一次线程写,都会减去该线程实际写入的块数,而不是读取出而要写入的块数。

int

out_partial

实际输出的数据大小非整数个块大小的个数

int

out_stop

输出结束标记

pthread_mutex_t

out_mutex

输出互斥量

pthread_cond_t

out_sync_cv

hold writes until "in order"

int

bs

块大小

int

bpt

每次传输多少块

int

dio_incomplete

全部传输中使用dio方式的计数

int

sum_of_resids

Sg函数使用,总共残余的未输出的数据计数

pthread_mutex_t

aux_mutex

主要是保护dio_incomplete和sum_of_resids成员

int

debug

调试相关

该结构体实例对所有的线程都可见。

结构体struct request_element,被typedef为Rq_elem,每个实例仅被一个work thread看到,是一个work thread要传输的全部数据

类型

描述
int

infd

读取文件描述符

int

outfd

输出文件描述符

int

wr

指定in/out,1:out,0:in

int64_t

blk

下一个要读取/输出的块地址

int

num_blks

块数

unsigned char *

buffp

缓存开头,读取的数据放在这,要写的数据也放在这

unsigned char *

alloc_bp

分配了一个缓冲空间,有缓存+1个页大小,上面的buffp指向1页之后的缓存开头

struct sg_io_hdr

io_hdr

Sg相关

unsigned char

cmd[MAX_SCSI_CDBSZ]

SCSI命令CDB

unsigned char

sb[SENSE_BUFF_LEN]

Sg命令执行后的状态信息,从struct sg_io_hdr->sbp指向该缓冲区

int

bs

块大小

int

dio_incomplete

DIO方式则=1,否则=0。DIO的设计方式是:如果用direct io且完成,则sg_io_hdr_t ->info成员的SG_INFO_DIRECT_IO位被设置,否则会以indirect io完成

int

resid

这次线程传输中的残余数据数目,sg_函数中有用

int

cdbsz_in

读取CDB大小

int

cdbsz_out

输出CDB大小

struct flags_t

in_flags

读取标记组合

struct flags_t

out_flags

输出标记组合

int

debug

看来,struct request_collect是总传输数据量的结构体,而struct request_element是其中的一个个分量,要传输的数据块选择bpt和请求要传输的数据总量(剩余量)中的小值。如下所示:

/* Follow clp members are constant during lifetime of thread */

rep->bs = clp->bs;

rep->infd = clp->infd;

rep->outfd = clp->outfd;

rep->debug = clp->debug;

rep->cdbsz_in = clp->cdbsz_in;

rep->cdbsz_out = clp->cdbsz_out;

rep->in_flags = clp->in_flags;

rep->out_flags = clp->out_flags;

while(1) {

status = pthread_mutex_lock(&clp->in_mutex);

if (0 != status) err_exit(status, "lock in_mutex");

if (clp->in_stop || (clp->in_count <= 0)) {

/* no more to do, exit loop then thread */

status = pthread_mutex_unlock(&clp->in_mutex);

if (0 != status) err_exit(status, "unlock in_mutex");

break;

}

/*按最小者来*/

blocks = (clp->in_count > clp->bpt) ? clp->bpt : clp->in_count;

rep->wr = 0;

rep->blk = clp->in_blk;

rep->num_blks = blocks;

clp->in_blk += blocks;

clp->in_count -= blocks;

……………………………..

}

结构体struct sg_io_hdr

类型

描述
int

interface_id

[i] 'S' (required)

int

dxfer_direction

[i]数据传输方向

unsigned char

cmd_len

[i],CDB命令长度

unsigned char

mx_sb_len

[i],sence检测缓冲区最大长度,其中的实际数据长度为sb_len_wr

unsigned short

iovec_count

[i],用于scatter方式

unsigned int

dxfer_len

[i],实际传输数据的长度

void *

dxferp

[i], [*io]输入/输出数据缓冲区

unsigned char *

cmdp

[i], [*i]CDB命令

unsigned char *

sbp

[i], [*o]sense缓冲区

unsigned int

timeout

[i] unit: millisecs

unsigned int flags

flags

[i]

int

pack_id

[i->o]用户标记请求,在命令队列时有效识别那个请求产生的输出结果,驱动用不着

void *

usr_ptr

[i->o],用户私有数据,驱动用不着

unsigned char

status

[o]

unsigned char

masked_status

[o],去掉status中厂商信息并进行部分操作后的结果,与<scsi/scsi.h> (e.g. CHECK_CONDITION)可以匹配

unsigned char

msg_status

[o]消息层状态

unsigned char

sb_len_wr

[o],实际的sense缓冲数据长度

unsigned short

host_status

[o]来自主机适配器的状态

unsigned short

driver_status

[o]驱动状态

int

resid

[o]这次传输中的残余数据数目

unsigned int

duration

[o]

unsigned int

info

[o]

"[i]" 代表函数需要的输入值

"[o]" 函数执行完成后写入的值

"[i->o]" indicates a value that is conveyed from inputto output and apart from one special case,

is not used by the driver. The "[i->o]" members aremeant to aid an application matching

the request sent to a write() to the corresponding response receivedby a read().

"[*i]" indicates a pointer that is used for reading fromuser memory into the driver,仅用于指针

"[*o]" is a pointer used for writing,函数执行结果写入

"[*io]" indicates a pointer used for either reading orwriting.

成员dxfer_direction有以下取值:

· SG_DXFER_NONE:不需要传输数据。比如SCSI Test Unit Ready 命令。

· SG_DXFER_TO_DEV:将数据传输到设备。使用SCSI WRITE 命令。

· SG_DXFER_FROM_DEV:从设备输出数据。使用SCSI READ 命令。

· SG_DXFER_TO_FROM_DEV:双向传输数据。

· SG_DXFER_UNKNOWN:数据的传输方向未知。

6.1. interface_id

6.2. dxfer_direction

6.3. cmd_len

6.4. mx_sb_len

6.5. iovec_count

6.6. dxfer_len

6.7. dxferp

6.8. cmdp

6.9. sbp

6.10. timeout

6.11. flags

6.12. pack_id

6.13. usr_ptr

6.14. status

6.15. masked_status

6.16. msg_status

6.17. sb_len_wr

6.18. host_status

6.19. driver_status

6.20. resid

6.21. duration

6.22. info
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: