当前位置: 首页 > 工具软件 > Filebench > 使用案例 >

filebench工作负载描述语言

黄昊英
2023-12-01

== Workload Model Language==

Filebench使用综合应用程序模型描述,可用于派生分析模型和重建应用程序的足迹;允许预测和描述,但大大减少了时间和成本。该语言可以准确地表示应用程序的工作负载,从而方便预测、建模和测量系统性能。综合基准测试是通过使用语言中描述的模型在测试系统上生成负载来实现的,其方式类似于实际应用程序在系统上运行时的方式。系统的性能可以在负载产生期间进行测量。对于基准测试,模型是通过动态地重新创建正确数量的进程(或线程)、内存占用和I/O,以及在实际应用程序中看到的所有进程间同步来实现的。这种语言也可以用来驱动一个分析模型。这允许在系统的子组件发生变化时向前预测系统性能的变化。工作负载描述是通过将其描述为一系列进程、线程和流来实现的。每个进程代表一个地址空间,其中包含一个或多个线程。每个线程代表一个关闭的流操作队列的顺序执行流。每个流程操作都是一个预定义的系统操作,例如文件读写等。

  model -> process -> thread -> {flowop, flowop, flowop...}
                   -> thread -> ...
        -> process -> ...

例如,f语言中的随机I/O工作负载可以用以下方式表示

  define process randomizer
  define thread random-thread procname=randomizer
  {
        flowop random-read type=read,filename=bigfile,
                                   random,iosize=2k
        flowop random-write type=write,filename=bigfile,
                                   random,iosize=2k
  }

我们还引入了流之间的流同步;以促进在真实应用程序中看到的内部流约束的复制。例如,一个数据库工作负载可能由两个相互依赖的关键进程组成。在这种情况下,每个的流程操作循环将被链接:

  {read, read, read, block on other flowop}  -
                                             |
  {write, write, write, wakeup other flowop} -

一个简单的数据库表示由三个进程组成:

  define process logwr
  define process dbwr instances=1
  define process shadow instances=$shadows
  
  define thread logwr procname=logwr,memsize=10m
  { 
    flowop log-write type=write,filename=log,
        iosize=1m,workingset=1m,random,dsync
    flowop log-block type=semblock,value=40
  }
  
  define thread dbwr procname=dbwr,memsize=10m
  { 
    flowop dbwr-write type=write,filename=datafile,
        iosize=1m,workingset=1m,random,dsync
    flowop dbwr-block type=semblock,value=10,highwater=1000
  }
  
  define thread shadow procname=shadow,memsize=10m
  { 
    flowop shadowread-a type=read,filename=datafile,
        iosize=2k,workingset=10m,random,dsync
    flowop shadow-post-log type=sempost,value=1,
                                  target=log-block
  }

=工作负载模型语言示例=(目前可能有很多变化)

#!/usr/benchmarks/filebench/go_filebench -f

debug 1

define file name=bigfile1,path=$datadir1/myrandfile,size=50g,prealloc,reuse,paralloc

define process name=rand-read,instances=1
{
  thread name=rand-thread,memsize=10m,instances=100
  {
    flowop read name=rand-read1,filename=bigfile1,iosize=$iosize,random,directio
    flowop eventlimit name=rand-rate
  }
}
Usage:
filebench: interpret f script and generate file workload
Options:
   [-h] Display verbose help
   [-p] Disable opening /proc to set uacct to enable truss

工作负载模型“f”语言定义:(会随新功能的增加而更改)
Variables:

set $var = value
    $var   - regular variables
    ${var} - internal special variables
    $(var) - environment variables
define randvar name = $random_var
                       [, type=]
                       [, seed=]
                       [, gamma=]
                       [, mean=]
                       [, min=]
                       [, round=]
                       [, randsrc=]
                       [[, type=tabular], randtable = {{, , }, {...}, ... }]
set $random_var.|seed=|gamma=|mean=|min=|round=|randsrc=>

Files and Filesets:

define file name=,path=,size=
                        [,paralloc]
                        [,prealloc]
                        [,reuse]

define fileset name=,path=,entries=,size=
                        [,dirwidth=]
                        [,dirdepthrv=
                        [,dirgamma=[100-10000] (Gamma * 1000)
                        [,sizegamma=[100-10000] (Gamma * 1000)
                        [,prealloc[=percent]]

Processes and Threads:

define process name=[,instances=]
{
  thread ...
  thread ...
  thread ...
}

  thread  name=[,instances=]

  {
    flowop ...
    flowop ...
    flowop ...
  }

Flowops:

flowop [aiowrite|write|read] name=, 
                        filename|filesetname=,
                        iosize=
                        [,fd=]
                        [,directio]
                        [,dsync]
                        [,opennext]
                        [,iters=]
                        [,random]
                        [,workingset=]
                        [,indexed=]

flowop [appendfile|appendfilerand] name=
                        filename|filesetname=
                        [,fd=]
                        [,directio]
                        [,dsync]
                        [,opennext]
                        [,iters=]
                        [,workingset=]
                        [,indexed=]

flowop [writewholefile|readwholefile] name=, 
                        filename|filesetname=
                        [,fd=]
                        [,directio]
                        [,dsync]
                        [,opennext]
                        [,iters=]
                        [,workingset=]
                        [,indexed=]

flowop aiowait name=,target=

flowop createfile name=, filesetname=
                        [,fd=]
                        [,indexed=]

flowop [deletefile|statfile] name=,
                        filesetname=|fd=
                        [,indexed=]

flowop closefile name=, fd=

flowop openfile name=,
                        filename|filesetname=,
                        [,opennext]
                        [,fd=]

flowop [makedir|removedir] name=, filesetname=
                        [,indexed=]

flowop listdir name=, filesetname=

flowop fsync name= [,fd=]


flowop sempost name=,target=,
                        value=

flowop semblock name=,value=,
                        highwater=

flowop block name=

flowop hog name=,value=

flowop wakeup name=,target=,

flowop eventlimit name=
flowop [bwlimit|iopslimit|opslimit] name=
                        [,target=]

flowop finishoncount name=, value=
                        [,target=]
flowop finishonbytes name=, value=
                        [,target=]

Commands:

eventgen rate=
create [files|processes]
stats [clear|snap]
stats command "shell command $var1,$var2..."
stats directory 
run 
sleep 
quit

FileBench本质上是I/O工作负载流建模语言的解释器,该语言的文件后缀为.f。典型工作负载模型有四个主要部分:设置默认值、定义文件或文件集、定义进程、线程和它们执行的流序列,以及最后的工作负载使用信息。你也可以在一行的开头加上#来包含注释。
FileBench的“‘set’”命令用于设置(并创建第一次遇到的)用户定义变量的值。变量名的前面必须有一个美元符号。典型的set命令如下所示

'''set $dir=/tmp'''

它创建一个名为“$dir”的新变量,并将其初始值设置为字符串“’/tmp’”。这些变量可以在以后定义文件、进程、线程和flowops时通过名称引用。如果在设置之前被引用,它们默认为零。

接下来,典型的工作负载模型将定义文件或文件集(或两者都有),用作运行模型时FileBench将生成的I/O的目的地。文件是FileBench对单个文件系统文件的抽象,而文件集是共享公共根目录和整体名称的文件集。两者都具有与之相关的文件大小等属性,但是文件集具有控制如何构建文件集(以及相关的目录树)的附加属性。一个典型的文件定义如下:

'''define file name=bigfile1, path=$dir, size=$filesize, prealloc, reuse'''

and fileset :

'''define fileset name=datafiles, path=$dir, size=$filesize, filesizegamma=0, entries=$nfiles, dirwidth=1024, prealloc=100, reuse'''

这两种类型都需要“name”和“path”属性,而文件集至少也必须具有“entries”和“dirwidth”属性。对于其他属性,使用默认值,包括不预分配,不重用,文件大小为0,文件大小分布“gamma”为1500,目录宽度分布“gamma”为1500。
文件和文件集都由I/O流程使用它们的name属性引用。一个文件对应于一个单一的文件系统文件,其路径名是“‘path’‘和’name’'属性的组合。文件集对应于一个目录和文件树,其根目录的路径名是“‘path’‘和’name’'属性的组合。文件集中的其余目录和文件以数字命名,每个级别从00000001开始。至少,文件集的根目录将包含一个名为00000001的子目录,该子目录又包含一个名为00000001的文件。因此,使用上面的示例值,第一个文件的完整路径名将是

/tmp/datafiles/00000001/00000001

FileBench遵循现代操作系统定义“进程”的实践,“进程”由一个或多个执行“指令”的“线程”组成。在FileBench的情况下,文件系统“进程”和“线程”分别对应于工作负载语言的“‘进程’”和“‘线程’”,而工作负载语言中的指令滚动则由“‘flowops’”执行。使用“定义进程”命令,该命令指定一组进程特定的属性,并在一对花括号中包含一个或多个线程定义。例如

define process name=rand-read, instances=1
{
    thread ...
}

定义一个名为“rand-read”的“进程”,它将生成一个文件系统进程的实例。该示例还包含一个“线程”定义,该定义本身将包含一个名称、一些属性和一个由大括号括起来的要执行的“flowops”列表,例如

    thread name=rand-thread,memsize=5m,instances=$nthreads
    {
      flowop ...
      ...
    }

这将导致进程中创建的操作系统线程数$nthreads,每个线程运行用大括号包围的flowops列表,每个线程具有5兆字节的共享内存区域。创建的线程独立地循环遍历flowops列表,重复该列表,直到工作负载终止。典型的流定义如下所示

 flowop read name=rand-read1, filename=largefile1, iosize=$iosize, random

它指定了一个名为“rand-read1”的“read”类型流,该流访问文件“largefile1”,读取I/ o的长度为“$iosize”到“random”的文件偏移量。一个工作负载可以由几个“‘进程’”组成,每个进程在运行时生成多个OS进程实例,每个进程实例由多个“线程”定义组成,而每个“线程”定义又可以生成多个OS线程实例。每个“线程”定义还将包括其所有实例都将执行的“flowops”列表。

FileBench有一个可扩展的帮助工具,它由内置的使用消息组成,这些消息提供使用flowop语言语法的帮助,以及一个使用命令,它添加了特定于工作负载的帮助消息。使用实例指定如何修改所使用的I/O大小的usage命令为:

'''usage " set $filesize= defaults to $filesize"'''

以$开头的标记被解释为变量名,其值的字符串表示形式被替换为实际的变量名。反斜杠\可以用来抑制这种解释。因此,上面的行将导致流包含在一个帮助消息中:

set $filesize= defaults to 1048576

假设$filesize之前被设置为1m (1m字节)。

=== Examples: Understanding Typical Workload files ===

FileBench提供的所有标准工作负载文件都遵循初始注释块、变量默认设置块、文件和文件集定义块、过程定义块和最后使用字符串块的格式。分组中的工作负载文件到块FileBench建议这里不是必需的,但符合要求的变量被设置在被使用的文件,文件集,进程,线程或flowop定义,文件和文件集定义被flowops之前,和是首选风格。
本节将详细研究两个工作负载文件,一个相对简单的工作负载“randomread”。和一个更复杂的工作负载“oltp.f”。
==== randomread.f ====

#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#

set $dir=/tmp
set $filesize=5g
set $iosize=8k
set $nthreads=1
set $workingset=0
set $directio=0

define file name=largefile1,path=$dir,size=$filesize,prealloc,reuse,paralloc

define process name=rand-read,instances=1
{
  thread name=rand-thread,memsize=5m,instances=$nthreads
  {
    flowop read name=rand-read1,filename=largefile1,iosize=$iosize,random,workingset=$workingset,directio=$directio
  }
}

echo "Random Read Version 3.0 personality successfully loaded"

该工作负载将随机偏移量读入单个大文件。它一直运行到外部停止为止,通常是在经过指定的秒数时由主FileBench进程停止。
在本例中,开头的注释块包括一个CDDL许可证、Sun版权和一个版本号。下一部分创建变量并为它们设置默认值。这个工作负载的默认值是:

" '$dir''是创建文件的默认目录,设置为/tmp
" '$nthreads''为单个线程定义创建的线程实例数,设置为1
" '$iosize''每次I/O的字节数,设置为8196。
" '$filesize'测试文件的字节大小,设置为1048576
" '$workingset''实际使用的文件的子区域。在这里设置为0意味着使用整个文件。
" '$directio''是否绕过文件系统。在这里设置为0表示不进行旁路。

接下来是" ‘define file’'语句,用于随机读取。F创建单个文件。属性集包括

" 'name''文件的名称,在本例中为largefile1
 '''path''' 将在其中创建此largefile1的目录的路径名。
" 'size "要创建的文件的大小,在运行时设置为$filesize的最新值。
" 'prealloc " '指示FileBench创建并填充文件的数量,该数量在运行之初由size属性指定。如果没有,将创建一个大小为零的文件。
" 'reuse "指示FileBench重用已经存在且至少与filesize属性指定的大小相同的文件。如果太大,它将被截断到正确的大小。

设置了变量并定义了文件之后,下一步是定义一个或多个进程。在这个例子中,一个进程被定义并传递了两个属性,它的名称(rand-read)和要创建的实例数(1)。每个" ‘defined process’'还需要至少一个线程,在define process语句后面的大括号中由" ‘thread’'语句定义。在这个例子中,只有一个线程具有三个属性

'name'它的名字(rand-read1)。
''memsize''线程内存的大小(5 mb)
" 'instances''要创建的操作系统线程数($nthreads)。

流程定义部分的最后一步是定义每个线程将循环执行的流程。它们在线程定义之后用一组大括号括起来。在我们的rand-read1线程中,只有两个flowops,一个用于执行文件读取,另一个用于设置每秒执行flowops的次数的上限。

" 'flowop read''从文件中读取。** " 'name " '流的名称(rand-read1) ** " 'filename " '要从
(largefile1)中读取的文件** " 'iosize " '每个读I/O的大小,由var $iosize设置。** " 'random''在工
作集中随机选择每个文件偏移量。** " 'workingset " '只使用文件的第一个$workingset字节。如果
workingset的值被设置为0,就像本例中$workingset的默认值一样,那么工作集将成为整个文件。** " 
'directio " '如果这个属性不带值,它将启用直接IO。如果它被设置为一个值,就像这里一样,它被设置为
$directio的值,这个值为0,在这个例子中$diretio的默认值是0,则禁用它,而其他任何值都启用它。


''flowop eventlimit''将这个线程中的flowop序列的执行速率限制为每个事件传递一次。使用一个单独的命令来
建立速率,默认为0。如果速率为0,则禁用事件子系统,事件限制变为无操作。** " 'name''流的名称(rand-
rate)

由于每个文件、文件集、进程、线程和flowop的FileBench实体都被放置在每种类型实体的全局列表中,因此建议为它们使用唯一的名称。这些名称用于在必要时定位flowops,因此重复的名称将使其中一个重复项无法访问。目前,仅在少数情况下引用单独的flowops,但未来可能会出现更多这样的情况。
randomread。例如,下一个语句是" 'echo " '命令,它在控制台上打印用引号括起来的字符串。在本例中,它通知用户工作负载模型已成功加载,因为在解析早期语句时遇到的任何错误都将在到达这一点之前结束工作负载文件的加载。
工作负载文件以一组用法语句结束,当遇到这些语句时,它们会被打印到控制台,并保存在帮助字符串中。在这里,工作负载的作者可以向工作负载用户提供有关运行工作负载的信息。与本例一样,当前的实践是将其限制为用户可配置参数及其默认设置的列表,但如果需要,该工具当然支持包含更多信息。
例如," ‘usage’'语句集生成以下帮助消息

Usage: set $dir=

       set $filesize=   defaults to 1048576
       set $iosize=    defaults to 8192
       set $nthreads=  defaults to 1
       set $workingset=  defaults to 0
       set $directio=   defaults to 0
       run runtime (e.g. run 60)

==== oltp.f ====

randomread.f工作负载说明了工作负载模型的基本结构。oltp.f工作负载遵循相同的基本结构,但添加了文件集和多个进程,并使用了几种额外的流处理类型,包括那些支持异步I/O和进程间同步的流处理类型。


#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#

set $dir=/tmp
set $eventrate=0
set $runtime=30
set $iosize=2k
set $nshadows=200
set $ndbwriters=10
set $usermode=200000
set $filesize=10m
set $memperthread=1m
set $workingset=0
set $logfilesize=10m
set $nfiles=10
set $nlogfiles=1
set $directio=0

eventgen rate = $eventrate

# Define a datafile and logfile
define fileset name=datafiles,path=$dir,size=$filesize,entries=$nfiles,dirwidth=1024,prealloc=100,reuse
define fileset name=logfile,path=$dir,size=$logfilesize,entries=$nlogfiles,dirwidth=1024,prealloc=100,reuse

define process name=lgwr,instances=1
{
  thread name=lgwr,memsize=$memperthread,useism
  {
    flowop aiowrite name=lg-write,filesetname=logfile,
        iosize=256k,random,directio=$directio,dsync
    flowop aiowait name=lg-aiowait
    flowop semblock name=lg-block,value=3200,highwater=1000
  }
}

# Define database writer processes
define process name=dbwr,instances=$ndbwriters
{
  thread name=dbwr,memsize=$memperthread,useism
  {
    flowop aiowrite name=dbwrite-a,filesetname=datafiles,
        iosize=$iosize,workingset=$workingset,random,iters=100,opennext,directio=$directio,dsync
    flowop hog name=dbwr-hog,value=10000
    flowop semblock name=dbwr-block,value=1000,highwater=2000
    flowop aiowait name=dbwr-aiowait
  }
}

define process name=shadow,instances=$nshadows
{
  thread name=shadow,memsize=$memperthread,useism
  {
    flowop read name=shadowread,filesetname=datafiles,
      iosize=$iosize,workingset=$workingset,random,opennext,directio=$directio
    flowop hog name=shadowhog,value=$usermode
    flowop sempost name=shadow-post-lg,value=1,target=lg-block,blocking
    flowop sempost name=shadow-post-dbwr,value=1,target=dbwr-block,blocking
    flowop eventlimit name=random-rate
  }
}

echo "OLTP Version 3.0  personality successfully loaded"

run 60

oltp。F工作负载定义了两个文件集:“‘datafiles’”和“‘logfile’”。这些定义说明了 randomread. f没有使用的几个属性。其中一些是必需的,因为它们是文件集:

“filesizegamma”。用于确定随机文件大小和子目录宽度的伽马分布的伽马参数。它被设置为0,即指定所有文件将被分配到文件大小的字节数,并且只创建一个顶级目录。
“entries”。由数据文件和日志文件集创建的文件数,它们的值分别从“$nfiles”和“$nlogfiles”变量中获取。
“dirwidth”。每个子目录宽度的平均值。除非将filesizegamma设置为0,就像本例中那样,这使它成为每个子目录的最大宽度。
" 'prealloc " '这个属性决定文件是否被预分配,对于文件集,也可以提供一个从0到100的数字,这个数字决定预分配的文件的百分比。在本例中,将预分配100%的文件。
" 'cached " '一个布尔值,其值取自" '$cached " '变量,它决定文件系统缓存是否在运行开始时被刷新。

在oltp.f工作负载中,变量“nfiles”和“nlogfiles”最初分别被设置为10和1,这意味着默认情况下将使用10个文件创建数据文件集,而使用1创建日志文件集。变量" 'cached " '被设置为0,这意味着默认情况下文件系统的缓存将在每次运行开始时刷新。这些和其他变量在使用之前可能会被重置为其他值,从而改变给定运行的配置。
oltp.f工作负载还定义了三个流程,并指定其中两个的多个实例。这三个进程是日志写入进程(" 'lgwr " ')、数据库写入进程(" 'dbwr " ')和数据库读取进程(" 'shadow " ‘),它们分别在运行时创建了" ‘1’’、" 'ndbwriters " '和" 'nshadows " '实例。在工作负载文件中,“ndbwriters”变量被设置为“10”,“nshadows”变量被设置为“200”,所以默认是10个“dbwr”流程实例和200个“shadow”流程实例。

这三个process定义中的每一个都包含一个thread和一个flowops列表,这些流程的执行生成OLTP工作负载的一部分。这些列表包括一些在随机读工作负载中没有的流程,以及读flowop的一个新属性,它进一步说明了工作负载建模语言的强大功能。具体来说," dbwr “进程和线程通过” aiowrite “和” aiowait " " flowops “演示了异步写入的使用,通过” hog " " flowop “演示了cpu周期消耗,通过” semblock " " flowop “演示了信号量操作。而“shadow”进程和线程则使用“opennext”属性在文件集中循环,并使用“sempost”流程进行信号量操作的其他方面。
“dbwr”线程有一个“aiowrite”和“aiowait”的流,它包含一个“hog”和“semblock”的流。“aiowrite”流获得与其他读写操作相同的属性,将向文件系统发出异步写,然后继续到下一个流,即“hog”流。“hog”流为“value”迭代执行字节写循环,因此每次调用消耗大约固定数量的cpu周期。其后是“semblock”流,它通过阻塞其信号量来同步“dbwr”线程和“shadow”线程,直到“shadow”线程中的“sempost”流发出足够多的消息。当线程的flowop继续执行时,它将调用” ‘aiowait’’ flowop,它将暂停,直到一个或多个未完成的异步写操作完成。通过使用“aiowrite”和“aiowait”操作,工作负载模型模拟了典型oltp软件中发生的I/O与cpu处理的重叠。如果I/O快速完成,循环的进程将受到“hog”和“semblock”的flowops的限制,而如果I/O很慢,“aiowait”的flowop将限制循环的进程。
虽然每个“shadow”进程只有一个线程实例,但在默认配置中有200个进程实例,因此总共有200个线程。“shadow”线程循环中的第一个流是“read”,然后是一个“hog”流,两个“sempost”流和一个“eventlimit”流。之前已经讨论过“hog”和“evenlimit”flowops,但是“sempost”和“read”flowops为已经定义的流添加了一些新属性:

'read flowop'' ** ''filesetname''文件集的名称,本例中为数据文件。实际上,filesetname和filename
属性可以互换使用。当指定时,将导致每次后续调用访问文件集的不同文件。对于此工作负载中的默认文件数量,文件
集将包含10个文件,每个影子线程将轮流访问这些文件。

'sempost flowop'' ** ''value''每个post添加到信号量计数的数量,在这个工作负载中,两者都被设置为1。
** " 'target " '这篇文章将作用于其信号量的semblock流的名称。一个流以lgwr中的semblock流为目标,命名
为lgwr -block,另一个流以dbwr中的semblock流为目标,命名为dbwr-block。** " 'blocking " '当指定
时,表示包含该sempost流的线程必须阻塞,如果它比包含目标semblock流的线程超前太多的话。

“shadow”线程的流列表的最大执行速率受到“eventlimit”流的限制,类似于随机读工作负载的最大执行速率。然而,应该注意的是,只有一个源的事件,所以每个200影子进程的线程共享一个事件生成器,平均将为1/200的指定利率循环,当然,仍然导致了每秒循环总数等于事件生成器。另外,“read”、“hog”和“sempost”流可能会进一步限制执行速度。例如,如果“读”“流访问延迟”和“猪”“流cpu延迟”的组合超过事件周期的200倍,它们将成为限制因素。正如下面将要描述的,“sempost”flowops还可以限制“阴影”线程的执行速度。
在oltp. f在工作负载下,计数信号量用于将两个写进程的执行速率限制为读进程速率的特定分数。这是通过在每个操作中对信号量进行加减的值进行适当设置来实现的。“影子”线程中的“sempost”和“flowops”都会在每次调用时为各自的计数信号量增加1,这意味着每秒钟增加的总数等于事件生成器的速率。更有趣的是,通过在其他两个线程中每次调用“semblock”从信号量中减去的量。“lgwr”线程中的“semblock”将会阻塞,除非信号量计数至少为3200,此时它会减去3200并继续。类似地,“dbwr”线程中的“semblock”将阻塞,除非信号量计数至少为1000,此时它将继续,但减去1000。总的效果是,“lgwr”每3200经过“shadow”一次通过它的流列表,而“dbwr”每1000经过“shadow”一次通过。
虽然信号量通常被认为是一种防止落后进程超过领先进程的机制(例如,消费者超过生产者),FileBench信号量flowops还可以防止领先进程超过落后进程太远。这是通过在内部创建第二个操作系统信号量来完成的,它的计数被初始化为“highwater”值,并且它的post和block操作被交换,因此“sempost”实际上对第二个信号量执行一个block操作,而它的“semblock”实际上执行一个post操作。因此,如果信号量的计数小于“sempost”属性的值,“sempost”流程将阻塞前导进程,并且“semblock”流程将在每次执行时将其值提交给计数。因为sempost flowops配置与价值观之一,1000年的“水位最高点”设置为“lgwr”将允许阴影得到1000 flowop循环迭代之前阻止之前,和“水位最高点”设置为“2000”dbwr影子可以得到2000 flowop循环迭代之前提前阻止。因此,通过一组flowops,工作负载语言能够建模通常的情况,即由于其他依赖关系或资源限制,生产者无法真正领先消费者太远。
这里详细介绍的两个工作负载模型是为许多其他工作负载开发的典型工作负载模型。这两个示例中没有包含FileBench支持的其他流程、属性和命令,因此要了解工作负载建模语言的完整规范,请参阅其他博客页面。遵循上面示例工作负载所说明的一般方法,添加和调整流程来对应用程序进行套件,您也可以创建您喜欢的工作负载的FileBench模型。

可以通过为进程、线程和flowops提供属性来修改它们的行为。有些属性是必需的,其他属性是可选的,它们具有默认值,如果没有提供这些属性,就会使用这些默认值。有些属性是布尔值,也就是说,如果提供这些属性则为真,如果不提供则为假。其他属性采用数字或字符串值,如果没有提供值,有时使用默认值。所提供的值可以是常量字符串或整数(视情况而定),也可以是由set命令赋值的字符串或整数变量。例如,指示一个文件集预先分配其100%的文件可以通过以下任何一种方法来完成:

define fileset name=foo, prealloc

define fileset name=foo, prealloc=100

set $preallocpercent = 100 define fileset name=foo, prealloc=$preallocpercent

fd

flowop子句的fd参数用于显式地设置打开文件的文件描述符。当脚本用于模拟一个应用程序,该应用程序在不同的描述符上打开了许多文件,或者使用有限的或扩展的描述符进行打开/关闭时,这是很有用的。在该示例中,第一个流打开文件大文件集中的任意文件,并分配文件描述符1。后面的read流也引用文件描述符1,因此它将读取第一个流打开的文件。最后,closefile流将关闭文件描述符1所引用的文件。

thread name=filereaderthread,memsize=10m,instances=$nthreads 
{ 	flowop openfile  name=openfile,filesetname=bigfileset,fd=1 
	flowop read name=readfile1,fd=1 
	flowop closefile name=closefile,fd=1 
}

flowop read | aiowrite | openfile | write | writewholefile | appendfile | appendfilerand ... ,fd=

“srcfd”属性指定在调用writewholefile流程时用作“filesize”信息源的文件描述符。在下面的示例中,代码模拟了一个复制文件操作,在这个操作中,文件被读入,然后写入到一个新文件中,当然,这个新文件最终的大小将与原始文件相同。

thread name=filereaderthread,memsize=10m,instances=$nthreads 
{ 	flowop openfile name=openfile1,filesetname=bigfileset,fd=1 
	flowop readwholefile name=readfile1,fd=1 flowop createfile name=createfile2,filesetname=destfiles,fd=2 
	flowop writewholefile name=writefile2,filesetname=destfiles,fd=2,srcfd=1 
	flowop closefile name=closefile1,fd=1 
	flowop closefile name=closefile2,fd=2 
}

flowop writewholefile ... ,srcfd=
 类似资料: