STB Suite

用于 SCSI、SATA、SAS、iSCSI 硬盘驱动器、磁带驱动器和库外围设备的专业工程、筛选和测试软件,通过现成的 HBA 提供

命令概率排序器简介

命令概率排序器 (CPS) 是 VCPSSL v8.2.0 中的一个新 API,它允许您定义一组将要发出的命令; 每个命令都有一个指定的概率,它将被选择执行。 这个新的 API 相当复杂并且有很多特性——我们将通过例子来介绍这些特性。

作为第一个示例,假设您想发出大量写入和读取,但时不时发出不同的命令(例如 Log Sense 命令)。 并且假设您有进一步的要求,即大约每 1000 个 I/O 发出此 Log Sense 命令。 命令概率序列器非常适合实现上述测试场景。 虽然下面的编码示例一开始看起来很吓人,但现在主要关注以下几项:我们正在设置三个用户定义的命令“Write”、“Read”和“Log Sense”,我们需要指定诸如是否 数据进出驱动器(“nDataDir”字段),以及需要传输多少数据(“nTransferLen”字段)。 这是我们第一个示例的代码 – 关注 RED 中具有“nDataDir”和“nTransferLength”参数的代码行,以及命令的实际定义。

 

const int c_nLenOfArray = 3;

DMM_UserDefinedCDB arrOfCDB[c_nLenOfArray];

double arrOfProb[c_nLenOfArray];

int nIndex;

const long c_lNumberOfIOToIssue = 10000;

//Set up the “Write” command (Write is opcode 0x2A)

BYTE cCDB0[] = {0x2A,0,0,0,0,0,0,0,1,0};

nIndex = 0;

memcpy(arrOfCDB[nIndex].cCDBBytes,cCDB0,10);

arrOfCDB[nIndex].nCDBLength = 10;

arrOfCDB[nIndex].nDataDir = 0;

arrOfCDB[nIndex].nTransferLength = 512;

//Set up the “Read” command (Read opcode is 0x28)

BYTE cCDB1[] = {0x28,0,0,0,0,0,0,0,1,0};

nIndex = 1;

memcpy(arrOfCDB[nIndex].cCDBBytes,cCDB1,10);

arrOfCDB[nIndex].nCDBLength = 10;

arrOfCDB[nIndex].nDataDir = 1;

arrOfCDB[nIndex].nTransferLength = 512;

//Set up the “Log Sense” command (Log Sense opcode is 0x4D)

BYTE cCDB2[] = {0x4D,0,0×40,0,0,0,0,0,0,0x80,0};

nIndex = 2;

memcpy(arrOfCDB[nIndex].cCDBBytes,cCDB2,10);

arrOfCDB[nIndex].nCDBLength = 10;

arrOfCDB[nIndex].nDataDir = 1;

arrOfCDB[nIndex].nTransferLength = 128;

//Now define the probabilities for each of the three commands

//“Write”, “Read”, “Log Sense”

arrOfProb[0] = 0.4995; //this is the probability for the “Write” command

arrOfProb[1] = 0.4995; //this is the probability for the “Read” command

arrOfProb[2] = 0.001; //.001 probability means the Log Sense command will be issued

//with probability .001 (i.e. every 1000th I/O)

VCSCSIAddDiskComProbSeqTest(arrOfCDB,

arrOfProb,

c_nLenOfArray,

c_lNumberOfIOToIssue);

在上面的示例中,我们要发出的命令集是 3(因此我们将 c_nLenOfArry 设置为 3),要发出的命令数是 10000(因此我们将 c_lNumberOfIOToIssue 设置为 10000)。 还要注意在对 API VCSCSIAddDiskComProbSeqTest 的调用中,我们传入了两个数组:第一个是命令序列,第二个是包含这些命令概率的序列。

注意:您的概率之和必须恰好是 1.0(或 100%)。 请注意,在我们的示例中,概率 .4995、.4995 和 .001 的总和正好是 1.0

这是上述测试的 BAM(总线分析器模块)输出:

正如您在跟踪中看到的那样,有 Write、Log Sense 和 Read 命令。 在跟踪的下部,在 I/O 统计页面上,它显示了发出的命令的数量和类型。 有 5019 个读取命令、4966 个写入命令和 15 个 Log Sense 命令(请注意,5019 + 4966 + 15 = 10000,这是我们指定给 CPS 发出的命令数)。 从这个特定的运行中,我们看到读取命令形成了 5019/10000 = 50.19% 的命令,写入命令形成了 4966/10000 = 49.66% 的命令,而 Log Sense 命令形成了 15/10000 = 0.15%。 这些百分比几乎正是我们为 CPS 指定的概率。

 

第二个示例:使用递增模式编写每个偶数 LBA,使用递减模式编写每个奇数 LBA

在这个例子中,我们将介绍 CPS 的另外两个特性——即如何设置数据模式,以及如何自动调整您的写入和读取(以及其他命令)。 要了解您为什么要调整写入命令,假设您暂时没有调整命令。 然后,每次我们发出命令时,我们都将写入驱动器上完全相同的位置(在示例 1 中,我们将每次写入 LBA 0)。 为了允许调整命令写入的位置,我们引入了“nGap”参数。 nGap 参数告诉 CPS 调整写入命令的位置多少。 例如,如果 nGap 为 7,则连续写入将转到 LBA 0、7、14、21 等。

为了写出每个偶数 LBA(即 LBA 0、2、4、6、8、10……),我们需要 nGap 正好为 2。

所以这里是如何查看上述类型的测试 - 关注 RED 中具有“eTestPattern”和“nGap”参数的代码行。

const int c_nLenOfArray = 2;

DMM_UserDefinedCDB arrOfCDB[c_nLenOfArray];

double arrOfProb[c_nLenOfArray];

int nIndex;

const long c_lNumberOfIOToIssue = 10000;

//Set up the “Write” command that writes to even LBA, with Incrementing pattern

BYTE cCDB0[] = {0x2A,0,0,0,0,0,0,0,1,0};

nIndex = 0;

memcpy(arrOfCDB[nIndex].cCDBBytes,cCDB0,10);

arrOfCDB[nIndex].nCDBLength = 10;

arrOfCDB[nIndex].nDataDir = 0;

arrOfCDB[nIndex].nTransferLength = 512;

arrOfCDB[nIndex].eTestPattern = eIncrementing;

arrOfCDB[nIndex].nGap = 2;

//Set up the “Write” command that writes to odd LBA, with Decrementing pattern

BYTE cCDB1[] = {0x2A,0,0,0,0,1,0,0,1,0};

nIndex = 1;

memcpy(arrOfCDB[nIndex].cCDBBytes,cCDB1,10);

arrOfCDB[nIndex].nCDBLength = 10;

arrOfCDB[nIndex].nDataDir = 0;

arrOfCDB[nIndex].nTransferLength = 512;

arrOfCDB[nIndex].eTestPattern = eDecrementing;

arrOfCDB[nIndex].nGap = 2;

//Now define the probabilities for these two commands. There’s no reason you have

//to make the probabilities the same.

arrOfProb[0] = 0.71; //71% of the time we’ll be writing to the even LBA

arrOfProb[1] = 0.29; //29% of the time we’ll be writing to the odd LBA

VCSCSIAddDiskComProbSeqTest(arrOfCDB,

arrOfProb,

c_nLenOfArray,

c_lNumberOfIOToIssue);

 

这是上述测试的 BAM(总线分析器模块)输出:

请注意,在 BAM 跟踪中,第一个写入命令写入一个递减模式(到 LBA 1),而接下来的三个写入命令写入一个递增模式(到 LBA 0、2、4)。 注意具有递增模式的写入命令之间的“间距”——它们恰好相隔两个块,这正是我们为 CPS 指定的 nGap 值。

 

第三个示例:将专用数据发送到驱动器

在第三个示例中,我们将向您展示如何通过“模式选择”命令将唯一数据发送到驱动器。 我们将设置 AWRE(“错误恢复”模式页面上的“自动写入重新分配启用”位为 0)。 此模式选择仅以百分之一的概率(即概率 0.001)完成。

const int c_nLenOfArray = 3;

DMM_UserDefinedCDB arrOfCDB[c_nLenOfArray];

double arrOfProb[c_nLenOfArray];

int nIndex;

const long c_lNumberOfIOToIssue = 10000;

//执行模式选择(模式选择的操作码为 0x15)

BYTE cCDB0[] = {0x15,0x11,0,0,0×18,0};

BYTE cModeSelectBuffer[24] = {0,0,0,0×08,0,0,0,0,0,0,2,0,1,0x0a,4,1,0,0,0,0,1,0,0,0};

nIndex = 0;

memcpy(arrOfCDB[nIndex].cCDBBytes,cCDB0,6);

arrOfCDB[nIndex].nCDBLength = 6;

arrOfCDB[nIndex].nDataDir = 0;

arrOfCDB[nIndex].nTransferLength = 24;

arrOfCDB[nIndex].pPayloadDataToDrive = &cModeSelectBuffer[0];

//设置“Write”命令(Write is opcode 0x2A)

BYTE cCDB1[] = {0x2A,0,0,0,0,0,0,0,1,0};

nIndex = 1;

memcpy(arrOfCDB[nIndex].cCDBBytes,cCDB1,10);

arrOfCDB[nIndex].nCDBLength = 10;

arrOfCDB[nIndex].nDataDir = 0;

arrOfCDB[nIndex].nTransferLength = 512;

//设置“Read”命令(读取操作码为 0x28)

BYTE cCDB2[] = {0x28,0,0,0,0,0,0,0,1,0};

nIndex = 2;

memcpy(arrOfCDB[nIndex].cCDBBytes,cCDB2,10);

arrOfCDB[nIndex].nCDBLength = 10;

arrOfCDB[nIndex].nDataDir = 1;

arrOfCDB[nIndex].nTransferLength = 512;

//现在定义这两个命令的概率。 你没有理由

//使概率相同。

arrOfProb[0] = 0.001; // .1% of the time we issue mode-select

arrOfProb[1] = 0.4995;

arrOfProb[2] = 0.4995;

VCSCSIAddDiskComProbSeqTest(arrOfCDB,

arrOfProb,

c_nLenOfArray,

c_lNumberOfIOToIssue);

 

这是上述测试的 BAM(总线分析器模块)输出:

 

每个命令的参数定义:

struct _DMM_UserDefinedCDB

{

BOOL bValid;

eUSER_DEFINED_TYPES eUserDefinedType;

char cCDBBytes[16];

int nCDBLength;

int nDataDir;

int nTimeout;

int nTransferLength;

BYTE * pPayloadDataToDrive;

int nAmtDataToLogfile;

char cDataOutFile[MAX_PATH];

ePATTERN_TYPE eTestPattern;

BOOL bCompare;

int nGap;

int nSeed;

}

bValid: 将其设置为 TRUE
eUserDefinedType: 将其设置为 eScsiCDB
cCDBBytes: 将特定命令复制到该字段(必须为 16 字节或更少)
nCDBLength: 将此设置为命令的长度
nDataDir: 如果数据将发送到驱动器,则将此设置为 0,如果数据从驱动器返回,则将其设置为 1。 注意:如果没有数据正在传输,请将其设置为 0。0 是默认值
nTimeout: 将此设置为命令所需的超时时间(默认值为 30)
nTransferLength: 将此设置为要传输的数据量。 如果没有数据正在传输,则将此字段设置为 0
pPayloadDataToDrive: 将此指针设置为包含要传送到驱动器的数据的缓冲区的起始地址。 如果没有数据要传送到驱动器,则将此字段设置为 NULL(这是默认值)。
cDataOutFile: 将字节 0 设置为“?”——这是默认设置
eTestPattern: 将此字段设置为所需的模式。 有关可用模式的列表,请参阅 VCPSSLImports.h 和枚举 ePATTERN_TYPE。
bCompare: 如果命令正在从驱动器接收数据(例如“读取”命令),则将此字段设置为 TRUE。 否则将其设置为 FALSE(这是默认设置)。 从驱动器返回的数据将与 eTestPattern 字段中的数据进行比较
nGap: 对于写入和读取命令,将此字段设置为每个连续命令之间所需的块数

 

返回代码和使用 VCSCSIAddDiskComProbSeq API 可能出现的问题:

此 API 返回 TRUE 表示已将测试添加到您的序列;

如果发生任何问题,它将返回 FALSE。

从 API VCSCSIAddDiskComProbSeq 获得 FALSE 返回码的原因:

  1. 您的序列中的命令数太长。 解决方法:确保序列中最多有 1000 个命令
  2. 所有命令的概率总和不等于 1.0。 解决方法:确保概率实际上加起来为 1.0——很容易“放错”小数点或错误地输入数字。 此外,输入数字,例如,0.25(不是 25)。