一、引言
diskspd是微软开源的一个磁盘性能分析的程序,链接如下。
https://github.com/microsoft/diskspd
小学期分组对项目进行分析,我们小组的任务是分析其中的XmlProfileParser模块。
小组成员:关浩博、张存涛、张迪。
1.1 Diskspd简单介绍
Diskspd是一个检查存储性能的软件。可用于针对文件,分区或物理磁盘运行存储性能测试。Diskspd可以生成各种磁盘请求模式,用于分析和诊断存储性能问题。
1.2 xml文件介绍
XML 指可扩展标记语言,用于存取和传输数据,本质上是文本文件。Xml文件最重要的一个优点就是可以自定义标签。也就是说用户根据想要传输信息来约定好每个标签的含义和数据类型。
既然xml可以用户自己规定标签,那么怎样规定它的标签以便于多个用户来使用呢?
和xml类似的另一种XML Schema文件,就是来解决这个问题的。XML Schema语言用来描述XML文档的结构。文件扩展名为xsd。在XmlProfileParser项目中的和XmlProfileParser.cpp在同一目录下的diskspd.xsd。DiskSpd所用xml的标签就在diskspd.xsd文件中规定了。用户可以根据diskspd.xsd中的标签写相应的xml文件,来传递参数,使diskspd.exe执行相应的功能。
1.3 XmlProfileParser类的作用简单介绍
XmlProfileParser类的作用就是解析Xml文件,将解析所得到的参数存到Profile类的一个实例对象中。简单来说,XmlProfileParser类就是将xml文件中传递的参数读取出来以便于应用程序获取参数,来对磁盘进行相应的操作处理。
二、XmlProfileParser类介绍
2.1 类功能简单介绍
通过XmlProfileParser类图,可以清晰地看到XmlProfileParser类中没有任何的成员变量,只有唯一的一个ParseFile()这个公有函数。而其他的私有函数又可以大致分为两类,第一类是基本操作函数。如从xml文件中获取字符串、整型、bool型。第二类就是获取特定参数的值,当然第二类函数通过调用第一类基本操作函数来获取基本文本信息来处理的,最终达到解析文件中特定参数的功能。如_ParseEtw()函数(解析Windows事件跟踪的参数函数)就调用了_GetBool()函数来检验对应参数是否存在,最终到达了解析Windows事件跟踪的功能。
2.2 流程图
2.3 系统结构图
2.4 类函数具体介绍
ParseFile()
ParseFile()函数是XmlProfileParser类最关键的函数,通过这个函数可以获得xml文件中所有的想要传递的参数。通过这个函数实现了XmlProfileParser类的功能。
ParseFile()
函数原型:bool ParseFile(const char pszPath, Profile *pProfile, HMODULE hModule);
函数原型中的三个参数的含义是:
*pszPath:指出当前xml文件所在的位置,pProfile:xml文件解析的结果存储类的实例对象,hModule:句柄对象,指出当前程序。
函数调用关系
ParseFile()函数调用了五个私有函数:
(1) _ParseEtw():解析事件追踪
(2) _ParseTimeSpans():解析持续时间
(3) _GetProgress():解析项目信息
(4) _GetString():解析文件结果格式
(5) _GetString():解析文件最大值和打开方式
(6) _GetVerbose 解析日志
_ParseEtw()
函数原型:HRESULT _ParseEtw(IXMLDOMDocument2 *pXmlDoc, Profile *pProfile);
详细功能:
两个参数分别是XML文档类的实例对象和pProfile类的实例。
通过_GetBool()函数,查看对应xml文件的标签后面是否有一下信息。如果有,则将设置pProfile类的相应属性。
ETW/Process 事件追踪过程
ETW/Thread 事件追踪线程
ETW/ImageLoad 事件追踪 镜像加载
ETW/DiskIO 事件追踪磁盘读写
ETW/MemoryPageFaults 事件追踪内存页错误
ETW/MemoryHardFaults 事件追踪硬盘存储错误
ETW/Network 事件追踪网络
ETW/Registry 事件追踪寄存器
ETW/UsePagedMemory 事件追踪使用分页的内存
ETW/UsePerfTimer 事件追踪使用性能计时器
ETW/UseSystemTimer 事件追踪使用系统计时器
ETW/UseCyclesCounter 事件追踪使用周期计数器
_ParseTimeSpans()
函数原型:HRESULT _ParseTimeSpans(IXMLDOMDocument2 *pXmlDoc, Profile *pProfile);
功能:
两个参数分别是XML文档文件夹类的实例对象和pProfile类的实例。通过读取标签的TimeSpans/TimeSpan然后开始循环查找其他内容。
_ParseTimeSpan()
函数原型:HRESULT _ParseTimeSpan(IXMLDOMNode *pXmlNode, TimeSpan *pTimeSpan);
两个参数分别是XML文档结点类的实例对象和pProfile类的实例。
首先读取_GetUINT32()读取相应标签后的无符号的int,然后设置pProfile相关成员变量。最后通过_ParseAffinityAssignment()、_ParseAffinityGroupAssignment()、_ParseTargets()解析xml文件中的亲和力赋值,组亲和力赋值和多任务。也就是在持续事件内要检查磁盘的任务还有参数值。
Duration 持续时间
Warmup 预热
Cooldown 冷却
RandSeed 随机种子
RandomWriteData 随机写数据
ThreadCount 线程数
RequestCount 请求数
DisableAffinity 禁用亲和力
CompletionRoutines 完成例程
MeasureLatency 测量延迟
CalculateIopsStdDev 计算存储IOPS
IoBucketDuration IO桶持续时间
_ParseTargets()
函数原型:HRESULT _ParseTargets(IXMLDOMNode *pXmlNode, TimeSpan *pTimeSpan);
参数:pXmlNode xml文件结点 pTimeSpan 持续时间
功能:对xml文件进行遍历,每次遍历调用_ParseTarget()来设置一个子任务。最后将持续时间内的所有子任务全部取出。
_ParseTarget()
函数原型:HRESULT _ParseTarget(IXMLDOMNode *pXmlNode, Target *pTarget);
参数:pXmlNode xml文件结点 pTarget子任务
功能:对于所有的子任务开一个线程来执行。用_ParseThreadTargets()来开设置子任务的线程。
Path路径
BlockSize块大小
StrideSize步幅的大小
InterlockedSequential联锁顺序
BaseFileOffset基本文件偏移量
SequentialScan顺序扫描
RandomAccess随机存取
TemporaryFile临时文件
UseLargePages使用较大页面
RequestCount请求数目
Random随机值
DisableOSCache禁用操作系统缓存
MemoryMappedIo内存映射输入输出
DisableAllCache禁用所有缓存
DisableLocalCache禁用本地缓存
WriteThrough通过写方式
FlushType 嵌入式
(ViewOfFile NonVolatileMemory:查看的文件非挥发性内存非挥发性内存不流失)
BurstSize 释放量
ThinkTime测试磁盘时间
Throughput吞吐量
ThreadsPerFile线程每个文件
FileSize文件大小
MaxFileSize最大文件大小
WriteRatio写的比
ParallelAsyncIO 并行异步IO
ThreadStride线程步幅
IOPriority IO优先权
Weight 权值
_ParseRandomDataSource()
函数原型:HRESULT _ParseRandomDataSource(IXMLDOMNode *pXmlNode, Target *pTarget);
参数:lNode xml文件结点 pTarget 子任务
功能:解析数据源的相关信息
RandomDataSource 随机数据源
SizeInBytes 随机数据源的大小
FilePath 文件路径
_ParseWriteBufferContent()
函数原型:HRESULT _ParseWriteBufferContent(IXMLDOMNode *pXmlNode, Target *pTarget);
功能:设置写缓冲内容,数据来源于随机数据源(通过调用_ParseRandomDataSource()函数来实现)
WriteBufferContent写缓冲区内容
Pattern模式(三种模式Sequential,Zero,Random)
Sequential顺序
Zero零
Random随机
_ParseThreadTargets()
函数原型:HRESULT _ParseThreadTargets(IXMLDOMNode *pXmlNode, Target *pTarget);
功能:解析子任务的线程。(循环遍历,每次调用_ParseThreadTarget())
_ParseThreadTarget()
函数原型:HRESULT _ParseThreadTarget(IXMLDOMNode *pXmlNode, ThreadTarget *pThreadTarget);
功能:解析的子任务的功能。
_ParseAffinityAssignment()
函数原型:HRESULT _ParseAffinityAssignment(IXMLDOMNode *pXmlNode, TimeSpan *pTimeSpan);
功能:解析赋值和关联组赋值。(亲和力)
_GetString()
函数原型:HRESULT _GetString(IXMLDOMNode *pXmlNode, const char *pszQuery, string *psValue) const;
功能:解析xml文件中pszQuery指定标签中的字符串
_GetUINT32()
函数原型:HRESULT _GetUINT32(IXMLDOMNode *pXmlNode, const char *pszQuery, UINT32 *pulValue) const;
功能:解析xml文件中pszQuery指定标签中的无符号32位整型
_GetUINT64()
函数原型:
HRESULT _GetUINT64(IXMLDOMNode *pXmlNode, const char *pszQuery, UINT64 *pullValue) const;
功能:解析xml文件中pszQuery指定标签中的无符号64位整型
_GetDWORD ()
函数原型:HRESULT _GetDWORD(IXMLDOMNode *pXmlNode, const char *pszQuery, DWORD *pdwValue) const;
功能:解析xml文件中pszQuery指定标签中的64位整型
_GetBool()
函数原型:HRESULT _GetBool(IXMLDOMNode *pXmlNode, const char *pszQuery, bool *pfValue) const;
功能:解析xml文件中pszQuery指定标签中的是否有值。
_GetUINT32Attr()
函数原型:HRESULT _GetUINT32Attr(IXMLDOMNode *pXmlNode, const char *pszAttr, UINT32 *pulValue) const;
功能:解析xml文件中pszQuery指定标签中无符号32位整型指定亲和力的值。
_GetVerbose()
函数原型:HRESULT _GetVerbose(IXMLDOMDocument2 *pXmlDoc, bool *pfVerbose);
功能:解析xml文件中所包含的文件日志信息。
_GetProgress()
函数原型:HRESULT _GetProgress(IXMLDOMDocument2 *pXmlDoc, DWORD *pdwProgress);
功能:解析xml文件中所包含的文件中所包含的项目信息。
三、XML分析与测试
3.1 简介
对于本程序来说,XML是一种参数的输入方式,因此开发者要提供一个固定的格式,方便使用者编写XML文件。
开发者提供了XML Schema文件diskspd.xsd,约定了XML文件的格式:标签的次序、嵌套关系、默认值等。该文件被嵌入diskspd.exe中。
3.2 diskspd.xsd部分分析
我们以diskspd.xsd文件的一小段为例,它所描述的XML文件的格式为:有一个复合类型元素Profile,其中的子元素的顺序是任意的;Profile的一个子元素为TimeSpans,最大出现次数和最小出现次数均为1;TimeSpans是复合类型元素,子元素是按次序出现的;TimeSpans的第一个子元素为TimeSpan,最小出现次数为1,最大次数为无穷大;TimeSpan是复合类型元素,子元素顺序任意,一个子元素为Targets,最大和最小出现次数均为1;Targets是符合类型元素,子元素是按次序的,第一个子元素为Target,最小出现次数为1,最大为无穷大;Target是复合类型元素,子元素出现顺序任意,子元素分别为:Path(出现且仅出现1次,类型为string)、BlockSize(出现0次或1次,类型为unsignedInt)、StrideSize(出现0次或1次,类型为unsignedLong)、InterlockedSequential(出现0次或1次,类型为boolean)……
3.3 XML测试
根据上一部分的分析方法,在对XML Schema文件diskspd.xsd进行简单分析后,我们就可以编写一些符合diskspd程序要求的XML文件,进而通过XML文件传递参数给diskspd程序。
简单版
编写以上xml文件,相当于相当于命令diskspd test.ghb,要求在当前文件夹存在文件test.ghb才能正确执行。
在命令行里输入diskspd -Xxml1.xml即可传入xml1.xml中的信息到diskspd程序中。运行结果如下。
复杂一点的版本
XML输入方式就是为复杂的功能而提供的,使用XML文件进行参数的输入可以为每一个目标或线程加上不同的参数,普通的命令行形式是无法做到这一点的
这个例子要求diskspd.exe当前文件夹下存在文件test.ghb、test2.ghb、test3.ghb、test4.ghb。运行结果如下。