一个不能按意愿执行的程序是没有用处的。每个程序都必须满足某组用户(有时会是一组很大且需求各不相同的用户)的需求。如果程序的性能确实不能满足那些用户中很大一部分用户的需求,则不会使用这个程序。一个不被使用的程序是不能实现预期功能的。
这种情况对经许可的软件包和用户编写的应用程序是确实存在的,尽管大多数软件包开发者意识到低性能的影响,并尽力提高程序的运行速度。不幸的是,他们不能预测程序要经历的所有环境和用途。让程序具有可接受性能的最终职责就落在了那些选择或编写、规划以及安装软件包的人身上。
本章描述程序员或系统管理员可以确保新编写或购买的程序具有可接受性能的步骤。(当程序员这个词单独出现时,它包含系统管理员和任何对程序的最终成功负责的人。)
为使程序达到可接受的性能,在工程开始时就要确定和量化可接受性,并且决不能忽视达到目标所需的方法和资源。尽管听起来这是基本方法,但一些编程工程却有意抵制它。他们采用一种清楚地描述为设计、编码、调试、可能是编写文档,有时间的话再确定其性能的策略。
为使程序运行时不仅在逻辑上,而且在时间上都是可预知的,唯一办法就是在软件规划和开发过程中对性能注意事项进行整体考虑。由于安装者较之开发者有较少的自由,所以在现有软件安装时提前规划也许就更关键了。
尽管对一个小程序来说,这个过程的细节可能看起来很繁重,但不要忘了我们还有第二个“记事本”。我们不仅必须保证新程序具有令人满意的性能,还须确保该程序对现有系统的补充部分不会降低运行于该系统的其它程序的性能。
确定工作负载的组成部分
无论程序是新编写的还是购买的、大程序还是小程序,开发者、安装者和预期用户都对程序的使用有所假设,比如:
Ø 谁使用该程序
Ø 程序在何种环境下运行
Ø 这些环境出现的频度,以及在某年某月某日某时会出现多少次
Ø 在这些环境下是否还需使用其它现有程序
Ø 程序运行于何种系统
Ø 有多少数据将要从何处进行处理
Ø 由程序或为程序创建的数据是否会在其它方面用到
除非这些想法是作为设计过程的一部分提出的,否则很可能模糊不清,并且程序员将几
乎无疑会有与预期用户不同的假设。甚至在程序员同时也是用户这样明显很普通的情况中,让假设无关会使以任何严格方式进行设计与假设的比较成为不可能。更糟的是,在对正进行的工作没有完全理解的情况下是不可能确定性能需求的。
编写性能需求文档
在确定和量化性能需求时,确定某一特殊要求背后的推理是很重要的。这是规划过程总能力的一部分。用户可能会将其需求声明基于与程序员的假设不匹配的程序逻辑的假设。性能需求集至少应记录下面几点:
1)各种特定类型的用户 — 计算机交互作用在大部分时间会经历的最佳响应时间,以及对
大部分时间的定义。响应时间从用户执行“运行”这个操作的时间直到用户从计算机接收到足够反馈以继续执行任务来衡量。这是用户的主观等待时间。它不是从一个子例程的入口到第一个写语句的时间。
2)如果用户对响应时间不感兴趣,而仅仅对结果感兴趣,您可以询问“当前独立执行时间估计值的十倍”是否可以接受。如果回答“是”,您就可以继续讨论吞吐量。否则,您可以在用户十分注意的情况下继续讨论响应时间。
3)最低程度可接受剩余时间的响应时间。较长的响应时间会使用户认为系统当机。您还需要指定剩余时间,例如,一天的高峰时刻,百分之一的交互作用。在一天的某特定时间减少响应时间很难办到,或者代价更高。
4)需要的典型吞吐量和将发生的次数。这并不是临时注意事项。例如,对一个程序的需求可能是每天运行两次:上午 10:00 和下午 3:15。如果这是一个运行 15 分钟,并且计划运行于多用户系统的有 CPU 限制的程序,则需要某种协商以便依次运行。
5)最大吞吐量周期的大小和计时。
6)综合预期请求及其如何随时间变化。
7)多用户应用程序中每台机器的用户数及总用户数。此描述应包括这些用户登录和注销的次数,以及假设的击键速率、完成的请求和思考次数。您可能想弄清楚思考次数是否随前后请求而系统地变化。
8)用户所做的关于工作负载要在其上运行的机器的任何假设。如果用户头脑中存在一台具体的机器,那么确保您早就了解它。同样,如果用户所采用的是特殊类型、大小、成本、位置、互联或任何其它变量,而这些变量将限制您满足前述需求的能力,那么假设也变为需求的一部分。满意程度可能不会在程序开发、测试或首次安装的系统上进行评估。
估计工作负载的资源需求
除非您正在购买配有详细资源需求文档的软件包,否则资源估计可能是性能规划过程中最困难的任务。造成困难有如下几个原因:
1)执行任何任务都有几种方法。您可以编写 C(或其它高级语言)程序、shell 脚本、perl 脚本、awk 脚本、sed 脚本、AIXwindows 对话等等。从性能观点看,一些看来特别适合算法和程序员生产力的技术非常昂贵。
2)有一条准则很有用,即抽象级别越高,就越要谨慎,以确保某个系统不会承受令人惊讶的性能。请仔细考虑由一些明显无害的构造所暗示的数据量大小和迭代数量。
3)单个过程的精确成本是很难确定的。困难之处不仅仅是技术上的;还有哲学上的。如果多用户运行的给定程序的多个实例正在共享程序文本页面,则哪一个进程应该负责那些内存页面呢?操作系统将最近用过的文件页面保留在内存中,以便为重新访问该数据的程序提供高速缓存的效果。重新访问数据的程序应该对用来保留数据的空间负责吗?某些评估的粒度,比如系统时钟,可以在用于同一程序连续实例的 CPU 时间上产生变化。
4)有两种方法来处理资源报告的模糊性和可变性。第一种是忽略模糊性,持续消除可变性的来源,直到评估变得可一致性接受。第二种方法是尝试让评估尽可能真实,并从统计上描述结果。注意后者产生与生产环境有某种相关性的结果。
系统很少专门运行单个程序的单个实例。存在几乎一直处于运行的守护程序、频繁的通信活动和通常来自多个用户的工作负载。这些活动很少线性增加。例如,增加给定程序的实例个数几乎没有增加使用的新程序文本页面数,因为大部分程序已存在于内存中。但是,附加的进程可能导致对处理器高速缓存的额外争用,所以,不仅其它进程不得不和新进程共享处理器时间,而且所有进程都会经历执行每条指令需要更多周期的情况。这实际上使得处理器速度减慢,结果导致更频繁的高速缓存未命中。
为使您的估计与具体情况所允许的一样真实,请使用以下准则:
ü 如果程序存在,对最类似您自己需求的现有安装进行评估。最好的方法是使用容量规划
工具,如 BEST/1。
ü 如果没有合适的安装可用,则进行试安装并对综合工作负载进行评估。
ü 如果生成与需求相匹配的综合工作负载是不实际的,则评估个体的交互作用并将结果用
作仿真输入。
ü 如果程序还不存在,查找使用同种语言和通用结构的同等程序并对其进行评估。再次强
调,语言越抽象,在确定可比性时就越需谨慎。
ü 如果同等程序不存在,则用规划的语言开发一个主要算法的原型,对这个原型进行评估
并对工作负载建模。
ü 只有当任何类型的评估都是不可能或不可行的,您才应作一个有根据的猜测。如果在规
划阶段有必要对资源需求进行猜测,则在其开发阶段尽早对实际程序进行评估是很关键的。
ü 牢记独立软件供应商(ISV)对他们的应用程序常常有可缩放的准则。
在估计资源时,我们主要对四个方面感兴趣(无特殊顺序):
l CPU 时间
l 工作负载的处理器成本
l 磁盘访问
l 工作负载产生的磁盘读写速率
l LAN 流量
l 工作负载生成的信息包数目和交换的数据字节数
l 实内存
l 工作负载所需 RAM 的大小
以下各节讨论了在各种情况下如何确定这些值。
评估工作负载资源
如果实际程序、可比程序或原型对评估都是可用的,则技术方法的选择依赖以下几点:
除了我们要评估的工作负载以外,系统是否还在处理其它工作。
我们是否有权使用会降低性能的工具(例如,系统是否处于生产中或在评估持续时间中是否为我们所专用?).
我们能够模拟或观察真实工作负载的程度。
估计新程序需要的资源
对未编写的程序进行精确估计是不可能的。编码阶段发生的创作和重新设计是难以预见的,但下面的准则可以帮助您对需求有一个全面了解。作为一个起点,最小程序需要以下条件:
大约 50 毫秒的 CPU 时间,大部分是系统时间。
实内存
一个程序文本页面大约 15 个页面(其中 2 个是暂存页面)用于工作(数据段对 libc.a 进行访问。通常这和所有其它程序共享,并当作操作系统基本成本的一部分。
大约 12 个页面调进的磁盘 I/O 操作(如果程序最近尚未编译、复制或使用)。否则什么都不需要。
除了上述一些方面,还有由设计所隐含要求的基本成本容差(给出的单元仅作示例用):
CPU 时间
不包含高级迭代或昂贵子例程调用的普通程序的 CPU 消耗小得几乎不可测量。
如果提到的程序包含计算复杂的算法,则开发一个原型,对算法进行评估。
如果提到的程序使用计算复杂的库子例程,如 X 或 Motif 构造或 printf() 子例程,则用其它小程序对它们的 CPU 消耗进行评估。
实内存
每个程序文本页面允许大约 350 行代码,其中每行大约 12 字节。不要忘了编码风格与编译器选项可在任一方面产生一两种因素的差异。该容差是针对与您典型情况相关的页面的。如果您的设计在可执行程序的结束处安插有执行次数很少的子例程,则那些页面通常不消耗实内存。
引用共享库而不是 libc.a 会增加内存需求,仅从这个意义上来说,那些库并不与其它程序或正在估计程序的实例共享。为量度这些库的大小,请编写一个长期运行的引用那些库的小程序,并对进程使用 svmon -P 命令。
估计在设计中所确定的数据结构所需存储量大小。集中到最靠近的页面。
在短时间的运行中,每一个磁盘 I/O 操作使用一个内存页面。假设页面必须已是可用的。不要假设程序会等待另一个程序的页面释放。
磁盘 I/O
对于顺序 I/O,每读或写 4096 字节导致一个 I/O 操作,除非文件最近刚被访问过并且一些页面仍留在内存中。
对于随机 I/O,每一次对不同的 4096 字节页面的访问,无论大小,都会导致一个 I/O 操作,除非文件最近刚被访问过并且一些页面仍留在内存中。
每一次对大文件进行 4 KB 页面的顺序读写会占用大约 100 个单元。每一次进行 4 KB 页面的随机读写会占用大约 300 个单元。记住实际文件不一定顺序存储在磁盘上,尽管程序对它们进行顺序写和读。因此,与顺序存取成本相比,实际磁盘存取的典型 CPU 成本与随机存取成本更接近。
通信 I/O
如果磁盘 I/O 实际上是对网络文件系统(NFS)远程安装的文件系统的,则磁盘 I/O 在服务器上执行,但客户机会承担更高的 CPU 和内存要求。
任何一种 RPC 对 CPU 负载都有非常大的贡献。设计中提出的 RPC 应该预先进行最小化、批处理、原型化和评估。
每一次进行 4 KB 页面的顺序 NFS 读或写会占用客户机大约 600 个单元。每一次进行 4 KB 页面的随机 NFS 读或写会占用客户机大约 1000 个单元。
Web 浏览和 Web 服务暗示有大量的网络 I/O,同时 TCP 连接的打开和关闭非常频繁。
变换程序级别估计为工作负载估计
估计高峰和典型资源需求的最好方法是使用排队模型,如 BEST/1。您可以使用静态模型,但有冒高估或低估高峰资源的危险。在任一情况下,从资源需求的观点出发,您都需要理解工作负载中的多个程序是如何交互的。
如果您正在构建一个静态模型,请使用时间间隔,这是对大多数频繁运行或苛求的程序(通常两者是相同的)而言可接受性最差的响应时间。决定在每个时间间隔中通常运行哪些程序,这要基于您所规划的用户数、他们的思考次数、击键输入速率以及预期的混合操作。
使用以下准则:
CPU 时间
在时间间隔中运行的所用程序的 CPU 需求总和。包括程序正要执行的磁盘和通信 I/O 的 CPU 需求。
如果在时间间隔中这个数字大于可用 CPU 时间的 75%,则应考虑减少用户数或增加 CPU。
实内存
操作系统内存需求随物理内存大小而变化。操作系统本身使用 6 到 8 MB。单机系统中该数字更小。后一个数字是对 LAN 连接以及使用 TCP/IP 和 NFS 的系统而言的。
在时间间隔中运行的程序所有实例的工作段需求总和,包括为程序数据结构所估计的空间。
即将运行的每个不同程序文本段的内存需求(一个程序文本副本为该程序所有实例服务)的总和。记住来自非共享库的任何(且仅仅)子例程将成为可执行程序的一部分,但这些库本身并不在内存中。
每一个由工作负载中任何程序使用的共享库所消耗的空间大小总和。再次强调,一个副本可供所有实例使用。
为了提供足够的空间用作某种文件高速缓存和自由列表,您的内存规划总和不应超过要使用的机器大小的 80%。
磁盘 I/O
每个程序的每个实例所暗示的 I/O 总数。分别计算小文件(或随机读写的大文件)与完全顺序读或写的大文件(大于 32 KB)的 I/O 总数。
除去那些您认为可以从内存中获得的 I/O。前一个时间间隔的任何读或写记录在当前时间间隔中很可能仍然可用。此外,检查提出的机器的大小并与机器工作负载的总 RAM 需求对比。操作系统需求与工作负载需求之外的所有剩余空间可能包含最近读或写的文件页面。如果您的应用程序设计如上面所述,那么很有可能您会重新使用最近访问过的数据,您可以针对高速缓存的效果计算容差。记住重新使用是在页面级别上,而不是记录级别上。如果重新使用一条给定记录的可能性很低,但每个页面又有大量记录,则在任何给定时间间隔中需要的一些记录可能会像最近使用过的其它记录一样落在同一页面中。
把净 I/O 需求(每张磁盘每秒钟的磁盘 I/O)与当前磁盘驱动器的近似容量相比较。如果随机或顺序需求超过要保存应用程序数据的相应的磁盘总容量的 75%,那么就有必要在应用程序运行时进行调谐(并且可能是扩展)。
通信 I/O
计算工作负载的带宽消耗。如果 LAN 上所有节点的总带宽消耗大于额定带宽的 70%(以太网中的 50%),您可能想使用带宽更高的网络。
对要加在服务器上的额外负载的 CPU、内存和 I/O 需求进行类似分析。
注:
记住只有当不可能进行综合评估时,这些准则才有用。任何可用来代替某个准则的应用程序特定的评估都会显著提高估计的精确性。
posted on 2005-12-05 10:18
咚咚咚 阅读(158)
评论(0) 编辑 收藏 引用 所属分类:
Performance Testing