没有合适的资源?快使用搜索试试~ 我知道了~
理论计算机科学电子笔记141(2005)53-73www.elsevier.com/locate/entcsJava字节码转换实现高效、便携的CPU计费沃尔特·宾德和贾勒·胡拉斯EcolePolytechniqueF′ed′eraledeLausanne(EPFL)计算机与通信科学学院CH-1015洛桑,瑞士firstname.lastname@ep.ch摘要资源管理对于构建可靠的中间件和托管可能不受信任的软件组件至关重要。资源核算允许研究和优化程序性能,并向用户收取其部署组件的资源消耗,而资源控制可以限制组件的资源消耗,以防止拒绝服务攻击。在这里介绍的方法中,程序转换使资源管理在基于Java的环境中,即使底层的运行时系统可能不会暴露有关应用程序的资源消耗的信息。我们提出了一个完全可移植的程序转换方案,以提高标准的Java运行时系统的CPU管理机制。我们实现了几个优化,以减少我们的CPU计费方案的开销。详细的性能测量量化了这种开销,并显示了各种优化的影响。关键词:Java,资源管理,字节码工程,程序转换1介绍物理资源的管理(即,会计和控制资源,如CPU和内存)是软件的一个有趣的方面提高安全性、可靠性、性能和上下文感知是更好地理解资源管理可以获得的一些好处CPU消耗的情况非常具有挑战性,因为人们无法在代码中识别显式的消耗位置,并且与其他资源相反,它被认为是连续的(这是由数量1571-0661 © 2005 Elsevier B. V.在CC BY-NC-ND许可下开放访问。doi:10.1016/j.entcs.2005.02.03754W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 141(2005)53在传统的程序设计环境中,CPU几乎不能作为第一类实体进行操作本文提出了一种解决这两个问题的方法会计和控制CPU消耗有许多有价值的应用。但目前,这种能力是由底层操作系统以特定的方式提供的。然而,更高的软件层肯定会受益于标准化的API和工具,以便在中间件或应用程序级别实现可移植和紧密集成的资源管理代码CPU核算是监控和分析的基本要素。许多先进的工具依赖于消费信息的连续收集,以自动适应和动态优化应用程序的执行,或保证计算资源池的最佳利用率。因此,监控和分析不仅可以通过专用的开发时工具来执行,而且成为运行时环境的一个组成在资源受限的嵌入式系统上运行的软件必须知道资源限制,以避免突然和异常终止的情况。这一能力包含了一个包括主动资源管理设施的方案拟订模式。类似地,新兴的面向代理的、上下文感知的应用将需要这样的设施来实现它们的自组织和自愈目标。在允许安装外部软件组件或需要移动代码的可扩展性的应用程序中,CPU管理是必需的构建块。这是因为当前的标准安全机制,如数字证书,往往过于粗粒度,遵循非常静态的方法,并专注于访问控制。它们并不涵盖纯粹的动态方面,例如最大执行速率或给定系统上允许的并发线程数然而,这些动态方面对安全与稳定至关重要。对于上述所有应用程序家族,Java和Java虚拟机(JVM)[5]代表了主要的编程语言和部署平台。然而,Java语言和标准Java运行时系统目前缺乏用于资源管理的机制,该机制可用于限制托管组件的资源消耗或针对客户端部署的组件的资源消耗向客户端收费。本文提出了一个新的,可移植的JavaCPU管理框架,称为J-RAF 2(Java资源会计框架,第2版)1。与第1http://www.jraf2.org/W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 141(2005)5355在JVM字节码级别的程序转换的帮助下,应用程序和库(包括Java开发工具包(JDK))被重写,以便公开关于它们的CPU消耗的信息系统中的每个线程记录它已执行的字节码指令的数量,并定期调用可由中间件程序员自定义也就是说,我们利用字节码指令计数作为CPU消耗的独立于平台的度量。本文的主要原创贡献是对我们的基本资源核算方案进行了几项优化,以减少CPU核算的开销。详细的性能测量说明了这些优化的影响。J-RAF 2是我们以前工作的延续[2],与之相比,我们现在已经实现了更强的可靠性,可移植性和可编程性。本文的结构如下:下一节给出了我们的便携式CPU计费方案的概述。第3节介绍了一系列有助于减少CPU记帐开销的优化,而第4节提供了详细的性能评估。第5节讨论了我们的方法的优点和局限性。最后,第6节对本文进行了总结。2便携式CPU计费在本节中,我们将解释我们的CPU计费方案。首先,重写“遗留”应用程序的字节码,以使程序的资源消耗显式。因此,重写的程序将在不知情的情况下跟踪执行的字节码指令的数量,以进行CPU核算。更准确地说,每个线程永久地计算自己的CPU消耗,将其表示为执行的JVM字节码指令的数量。这构成了一个独立于平台的测量单元,它具有一些实际优势,如第5节所述。每个线程会定期将收集到的有关其自身CPU消耗的信息汇总到一个与其他多个线程共享的帐户 我们称这种方法为自我核算。在这些信息更新例程期间,线程还将执行管理代码,例如,以确保不超过给定的资源配额通过这种方式,J-RAF2的CPU管理方案不依赖于专用的管理程序线程,因为管理活动分布在系统中的所有线程之间,从而有效地实现了一种形式的自我控制。因此,对我们来说,这是可移植性和可靠性的保证,我们不依赖于JVM提供的底层调度,Java语言中对JVM的指定很松散,可能是为了更容易实现Java56W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 141(2005)53public final class ThreadCPUAccount {public static ThreadCPUAccount getCurrentAccount();public void consume();...}在各种环境中:虽然一些JVM似乎提供了抢占式调度,确保具有高优先级的线程将在准备运行时执行,但其他JVM根本不考虑线程优先级。这与我们以前的计费方案[2]有很大的不同,以前的计费方案依赖于线程优先级进行调度。在下面的小节中,我们总结了我们的便携式CPU计费方案。低级别的实施细节见[4]。在[1]中,给出了编程API,以及从中间件开发人员的角度给出的编程示例与这些以前的出版物相比,本文侧重于优化和详细的评估。2.1将会计信息与线程关于字节码转换(或重写)方案,我们的两个主要设计目标是确保可移植性(通过严格遵守Java语言和虚拟机的规范)和性能(通过最小化由于插入到原始类中的额外指令而产生的开销每个线程都有一个关联的ThreadCPUAccount。图1总结了公共接口的一部分。方法和字段的语义将在本小节和以下小节中解释。线程与其ThreadCPUAccount的关联在线程的整个生命周期内持续存在。当一个新的线程对象被初始化时,它会自动接收一个新的ThreadCPUAccount对象。这是通过静态修改Thread类的字节码,添加一个字段来保存对线程的ThreadCPUAccount对象的引用来此外,线程构造函数被打上补丁,以便在创建线程时使用ThreadCPUAccount的新实例初始化该字段。1返回调用线程的ThreadCPUAccount图1.一、ThreadCPUAccount API的一部分W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 141(2005)53572.2字节码转换方案在正常执行期间,每个线程更新其ThreadCPUAccount的消耗计数器。为了防止消耗计数器(一个简单的32位整数)的过度溢出,并调度共享管理任务的定期激活,计数器将根据一个可调整的限制进行检查,即计费粒度(我们将在第2.4节中解释如何提供此值)。更准确地说,每次消耗计数器增加大于或等于粒度的字节码数量时,其值被注册并通过调用consume()方法重置为初始值。换句话说,当本地消耗计数器超过由记账粒度定义的特定限制时,每个线程都会调用其ThreadCPUAccount的consume()为了优化消耗计数器是否超过此限制的比较,计数器从粒度值乘以-1到零运行,当它等于或超过零时,调用consume()方法在JVM字节码中,有专门的指令用于与零进行比较因此,我们使用iflt指令,以便在消费低于零时跳过consume()为了应用这种CPU核算方案,(非原生和非抽象)方法以以下方式重写(i) 在每个方法的开始,必须使用静态方法getCurrentAccount()获取当前线程 在第3.2节中,我们将提出一个更有效的替代方案。(ii) 插入条件是为了周期性地调用consume()方法这些规则背后的基本原 理 是为 了 最 大限 度 地 减少 检 查 是 否出 于 性 能原 因 而 必须 调 用consume()的次数,但确保恶意代码在不调用consume()的情况下无法执行无限数量的字节码指令。条件(a) 在每个方法的开始。这确保了条件在递归方法的执行中存在。在第3.1节中,我们将展示如何放松这一规则以减少CPU记帐开销。(b) 在每个JVM子例程的开头。这确保了在递归JVM子例程的执行中存在(c) 在每个异常处理程序的开头(d) 在每个循环的开始。58W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 141(2005)53public void run(){ThreadCPUAccount cpu = ThreadCPUAccount.getCurrentAccount();try {.}finally {cpu.consume();}}(e) 在M axP ath字节码指令之后的每个可能的执行路径中,其中MaxP ath是传递到字节码重写工具的全局参数这意味着在计算条件之前,在一个方法中执行的最大指令数受到M axP ath的限制。因此,较大的M axPath值可以增加有效的计费粒度。(iii) 实现Runnable接口的每个类的run()方法根据图1重写2,以便在线程终止之前调用consume()线程终止后,其ThreadCPU帐户将符合垃圾回收条件。(iv) 最后,更新消耗计数器的指令插入到每个记帐块的开头。记帐块与基本代码块的概念相关,不同之处在于方法和构造函数调用可以发生在记帐块内的任何位置。有关会计区块定义的详细信息可以在[2]中找到 为了减少会计开销,之前插入的条件不被视为单独的会计块。条件求值所需的字节码指令的数量被添加到它们之前的核算块的大小中。图二. 重写run()方法。2.3重写示例图3中的示例说明了如何使用所提出的CPU计费方案来转换方法。检查消耗计数器是否达到零的条件被插入到方法的开始和循环中,而消耗变量在每个核算块中更新。这里我们不显示变量消耗递增的具体值;这些值由重写工具静态计算,代表下一个记帐块中将要执行的字节码数量22为了更好的可读性,在本文中,我们展示了Java代码或伪代码上的所有转换,而我们的实现工作在JVM字节码级别。W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 141(2005)5359public void consume(long c);public int getGranularity();...}public intfindDuplicate(intfindDuplicate){public int findDuplicate(int findDuplicate){ThreadCPUAccount cpu;System. out. println();CPU.consumption +=...;if(cup.consumption);public void run();public void run();while(x > 0){while(x > 0){CPU.consumption +=...;-->if(cup.consumption);public intfindDuplicate(){public int findDuplicate(){CPU.consumption +=...;i(x);i(x);}}CPU.consumption +=...;--x;--x;}}}}图3.第三章。重写一个CPU记帐方法2.4聚合CPU消耗通常,每个ThreadCPUAccount对象引用CPUManager的实现,该实现在属于组件的所有线程之间共享3图4显示了CPUManager界面的一部分。CPUManager实现由中间件开发人员提供,并实现实际的CPU计费和控制策略 , 例 如 , 自 定 义 调 度 方 案 。 CPUManager 接 口 的 方 法 由ThreadCPUAccount的consume()方法调用。见图4。 CPUManager接口的一部分。对于资源感知应用程序,CPUManager实现可能提供应用程序特定的接口,以访问有关组件CPU消耗的信息,安装在资源消耗达到某个阈值时触发的通知回调,或修改资源控制策略。在本文中,我们只关注所需的CPUManager接口。每当线程在其ThreadCPUAccount上调用consume()时,此方法将依次报告其收集的CPU消耗数据(存储在3在本文中,术语60W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 141(2005)53consumptionfield)到与ThreadCPUAc- count(如果有的话)关联的CPUManager。consume()也会重置消费字段。consume(long)方法实现了自定义的CPU计费和控制策略。它可以简单地聚合报告的CPU消耗(并将其写入日志文件或数据库),它可以强制绝对限制并终止超过其CPU限制的组件,或者它可以限制组件的线程的执行速率(即,如果超过给定的执行速率,则将线程暂时置于睡眠状态)。这是可能的,而不会破坏安全性假设,因为消费(长)调用是同步的(即,阻塞),并由策略所应用的线程直接执行。getGranularity ( ) 返 回 当 前 为 与 给 定 CPUManager 关 联 的ThreadCPUAccount定义的记帐粒度。它是一个可调整的值,它定义了管理活动的频率(从而间接地定义了开销):它必须适应受监督的线程数量,以防止调用consume(long)之间的过度延迟。第2.2节中重写规则(ii)(e)引入的常数M axP ath也影响了感知的会计最多可在不执行粒度检查的情况下执行M axPath个字节码指令。因此,有效的记账粒度范围在getGranularity()返回的值与总和getGranularity()+M axPath之间。3优化在本节中,我们将概述一些减少CPU记帐开销的优化技术。3.1优化叶方法根据第2.2节中的字节码转换规则(ii)(a),在每个方法的开头插入一个正确性检查。一般来说,这是必要的,以确保粒度检查将在递归方法中执行为了提高性能,如果每个可能的执行路径终止(即,返回或抛出异常)或传递另外插入的条件(例如,在循环开始时)在任何方法/构造函数调用之前。特别是,这种优化为叶方法付出了代价。然而,这种优化可能会增加会计的可性。具有少于M × Path字节码指令的叶方法L将W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 141(2005)5361void f(int x,threadCPUAccount cpu){ cpu.consumption +=.;if(cup.consumption >= 0)cup. consumption(); g(cpu);while(x > 0){ CPU.consumption +=.;if(x,x,x){CPU.consumption += ...;i(i,i);}CPU.consumption +=...;--x;}}不执行粒度检查。另一种方法可以在粒度检查将被实施之前连续调用L多达M axPath次总的来说,粒度检查可以被延迟多达M axPath2字节码指令(最坏情况)。3.2将ThreadCPUAccount作为参数传递正如我们将在第4节中展示的那样,在每个方法的开头调用ThreadCPUAccount.getCur- rentAccount()会导致很高的开销,因为它需要加载代表当前线程的Thread对象在这里,我们提出了一个优化,可以显着减少此方法的调用次数。3.2.1扩展方法签名我们扩展了方法的签名,以接受一个额外的ThreadCPUAccount参数,并将当前线程的ThreadCPUAccount对象传递给方法和构造函数调用。图5说明了这种重写方案的例子图。3 .第三章。图五.为CPU记帐重写了方法。ThreadCPUAccount作为额外参数传递。因为本机代码可以调用Java方法,而我们不修改本机代码,所以我们必须保留一个与重写之前签名相同的方法。出于这个原因,我们添加了如图6所示的包装器方法,该方法加载ThreadCPUAccount并将其传递给将ThreadCPUAccount作为额外参数的资源感知因此确保了与非重写和非重写代码的兼容性。在最好的情况下,ThreadCPUAccount.getCurrentAccount()方法只在程序启动时调用一次,然后生成的帐户将在其余的执行过程中遍历额外的参数。62W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 141(2005)53void run();public int findDuplicate(){CPU.consumption += ...; //reverse wrapper n();}public int findDuplicate(int findDuplicate){ThreadCPUAccount cpu = ThreadCPUAccount.getCurrentAccount();cpu.consumption +=.; //执行包装器f(x,cpu);}图六、带有未修改签名的包装器方法由 于 我 们 不 更 改 本 机 方 法 , 因 此 它 们 不 会 接 收 额 外 的ThreadCPUAccount参数。因为重写的Java方法将调用带有额外参数的方法,所以我们为本地方法提供了反向包装器,如图所示。7 .第一次会议。见图7。 本机方法的反向包装。由于将ThreadCPUAccount作为额外参数传递可以显著减少CPU记帐开销,因此我们希望将此技术应用于所有类,包括JDK。但是,向JDK类添加包装方法会导致一些微妙的问题。在JDK中,某些方法依赖于固定的调用序列 。 示 例 包 括 Class 、 ClassLoad-er 、 DriverManager 、 SQL 和System中的方法。这些方法检查调用方的堆栈帧以确定是否允许某个操作。如果将包装器方法(或本机方法的反向包装器)添加到JDK中,则由于调用包装器方法而产生的额外堆栈帧将违反JDK程序员关于执行堆栈的假设3.2.2在JDK类为了在调用JDK方法时不违反关于调用堆栈结构的假设,我们必须确保堆栈上没有一个简单的解决方案是根据图3所示的转换重写JDK类。然而,正如我们之前提到的,这样的重写方案可能会在某些JVM上造成很高的开销。迈向更有效解决方案的第一步是确保始终直接调用本机JDK方法也就是说,对于本机JDK方法,要避免图7中所示的反向包装器为此,我们开发了一个简单的工具来分析JDK,它给出了一个方法列表W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 141(2005)5363L不得接收包装纸。这个列表是后续重写JDK和应用程序类所必需的,因为L中方法的调用不能传递额外的ThreadCPUAccount参数。显然,L包含了所有的原生JDK方法。此外,我们必须考虑可能调用本机JDK 方 法 的 多 态 调 用 站 点 在 这 种 情 况 下 , 不 能 传 递 额 外 的ThreadCPUAccount参数,因为目标方法可能是本机方法,并且缺少反向包装。因此,如果本机方法覆盖/实现超类/接口中的方法m,则m必须包含在L中。我们使用以下简单的标记算法来计算L。(i) 计算JDK的类层次结构。对于每个类,存储类名、对超类的引用、对已实现接口的引用以及类中所有方法的签名和修改器列表。(ii) 标记所有本机方法。(iii) 在类层次结构中向上移动标记设mc是一个标记方法,它既不是静态的也不是私有的。此外,设C是定义mc的类,A是C的祖先集合,包括直接和间接超类以及所有实现的接口。对于A中的每个类或接口X,如果X定义了一个方法mx,其签名与mc相同,但它既不是静态的也不是私有的,则标记为mx。(iv) 所有标记的方法都被收集在列表L中。列表L中的JDK方法重写如下:• 本机方法不接收图中所示的反向包装器7 .第一次会议。• 抽象方法不会被修改;用额外参数扩展的签名不会被添加。• Java方法的签名也没有被触及;它们根据图1中给出的简单重写方案进行3 .第三章。到目前为止,我们已经确保了本地JDK方法总是被直接调用。然而,有些JDK方法要求它们的调用者也不通过包装器调用。为了遵守这一限制,每个JDK方法的代码不包括在L中是重复的,如图8所示。4由于JDK方法没有包装器,因此JDK中的调用序列保持不变。虽然代码近似重复(相对于应用程 序 类 的 重 写 方 案 ) , 但 执 行 性 能 可 能 会 得 到 提 高 , 因 为ThreadCPUAccount作为参数传递在这个例子中,我们假设方法g()、h(int)和i(int)不在列表L中。否则,不能将额外的参数传递给它们。64W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 141(2005)53≥≥- -只要有可能void f(int x){void f(int x,ThreadCPUAccount cpu){ ThreadCPUAccount cpu =System. out. println();CPU.consumption +=...;CPU.consumption +=...;如果(CPU消耗>= 0)如果(CPU消耗>= 0)return();return();int i(i);int i(i);while(x > 0){while(x > 0){CPU.consumption +=...;CPU.consumption +=...;如果(CPU消耗>= 0)如果(CPU消耗>= 0)return();return();public int findDuplicate(){public int findDuplicate(){CPU.consumption +=...;CPU.consumption +=...;i(i,i);i(i,i);}}CPU.consumption +=...;CPU.consumption +=...;--x;--x;}}}}图8.第八条。JDK方法的重写方案:代码重复。3.2.3改进寄存器分配将ThreadCPUAccount引用作为额外的参数传递使JVM的实时编译器能够将其保存在处理器寄存器中(过程间寄存器分配)。但是,根据方法的arity,ThreadCPUAccount引用出现在不同的参数位置,这可能导致某些JVM上的寄存器分配不理想。为了帮助寄存器分配,ThreadCPUAccount引用应该在固定的参数位置传递最初,我们试图将其作为第一个参数传递,但这并没有提高性能,并且使重写算法复杂化(检测插入指令以加载ThreadCPUAccount引用的正确位置需要控制流和堆栈分析)。因此,我们采用了不同的方法,插入了对于虚拟(静态)方法,让N虚拟0(分别Nstatic0)表示允许接收插入的ThreadCPUAccount引用的最小索引的JVM局部变量[5]对于虚方法/构造函数(分别为静态方法)需要一个虚拟(或一个静态的)JVM局部变量来接收它的参数,我们附加max(0,NvirtualAvirtual)(分别是max(0,Nstatic一个静态的、在在调用重写的方法时,空引用被传递给根据JVM规范[5],long和double arguW. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 141(2005)5365段需要2个JVM局部变量,而所有其他类型只需要一个。虚方法/构造函数在JVM局部变量0中接收this对象引用。图9示出了针对Nvirtual=Nstatic= N virtual的伪参数的插入。2. 转换后,方法1在同一个JVM局部变量中引用一曰:v()-->v(Dummy,ThreadCPU Account)第二章:v(int)-->public int findDuplicate(int i,int n)第三章:v(长)-->v(long,ThreadCPUAccount)第四章:public intfindDuplicate(int n)-->public int findDuplicate(int,int n)5:static s()-->static % s(Dummy,Dummy,ThreadCPUAccount)int n(int n)-->static % s(int,Dummy,ThreadCPUAccount)7:静态s(长)-->static % s(long,ThreadCPUAccount)8:static s(int,long)-->static % s(int,long,ThreadCPUAccount)图9.第九条。插入“dummy”参数的示例3.3控制流优化为了减少记账开销,有必要减少代码中记账站点的数量。实现这一点的一种方法是使用字节码转换来增加平均计费块大小,字节码转换可以扩大计费块或减少计费块的数量。目前,J-RAF 2支持两种这种优化。第一个优化简单的跳跃,第二个转换循环。这两种优化都在插入记帐代码之前应用。3.3.1跳转优化第一个优化旨在避免仅由单个跳转指令组成的会计块如果将核算代码添加到这样的块J,则核算跳转指令的开销将远远超过跳转本身的执行成本我们的第一个优化尝试缩短这样的跳转:首先,所有到blockJ的分支都被重定向到目标J。然后,如果J既不是方法中的第一个块,也不是异常处理程序中的第一个块,也不是JVM子例程中的第一个块,我们尝试完全删除J。如果控制不能从字节码中J之前的块转移到J块,则之前的分支重定向已经使J成为可以删除的死代码如果J之前的块没有分支(即,控制流程图仅顺序地进入J),则块J与其在控制流程图中的前趋者连接,这将导致对J及其前趋者的组合核算66W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 141(2005)53否则,如果J个分支和控制的前趋者可能流入J,则我们检查代码序列是否与图1所示的方案10,其中J之前的块分支到字节码中J之后的块这种结构经常出现在标准Java编译器生成的字节码中。在这种情况下,我们反转分支的条件,用跳转的目标替换分支目标,并删除跳转(见右图10每当我们删除一个跳转时,我们都会相应地更新所有被删除的异常处理程序。if(C)return;如果(!C)gotoElse;J:goto Else;-->然后又道:然后又道:见图10。 移除跳跃。3.3.2循环优化许多Java编译器根据图1中的方案转换while()循环十一岁左边是原始循环,而中间是编译循环的伪X和Y是记帐块。插入记账指令的结果如图11右侧所示。5也就是说,对于循环的每次迭代,会计代码执行两次,因为分支发生在C和Y的执行之间,这是单独的会计块。消费+=...;X的;X的;X的;开始:开始:消费+=...;当(C)-->如果(!C)goto End; -->如果(!C)goto End;{消费+=...;Y;Y;Y;}goto开始;goto开始;结束时间:结束时间:图十一岁编译while()循环并插入记帐指令。为了减少记账开销,可以将分支移动到循环的末尾,这相当于将while()循环转换为do-while()循环。图12示出了该转换的结果,其允许将一个核算站点移动到循环之外。此外,如果X是在结束时不改变控制流的计费块(无分支、无跳转等),如果while()循环只能通过X到达,我们可以将C的初始值的会计与5为了便于阅读,我们在这个例子中省略了粒度检查W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 141(2005)5367对于X,如图所示12向右然而,虽然这种转换能够实现更有效的计算,但它可能会增加代码大小,因为条件C的代码是重复的。消费+=...;X; X;X的;if(C){if(!C)goto End;如果(!C)goto End;do {开始:开始:-->-->消费+=...;Y; Y;Y;} while(C); if(C)goto开始;if(C)gotto开始;}结束:结束时间:图12个。编译转换后的循环并插入会计指令。在J-RAF 2中,我们实现了一个循环检测和转换算法,它适用于方法的控制流程图算法的执行我们的循环优化算法检测图中所示的循环模式图12示出了在中间的图11中示出的结构,并将其转换成在中间的图12仅当代码增加很小(例如,最大20个JVM字节码指令),以及包含分支的块是否被与跳转指令完全相同的异常处理程序集覆盖。这一点很重要,因为跳转将被替换为包括分支的块的副本。因此,此条件确保分支块的两个实例将由同一组异常处理程序管理。4评价在本节中,我们将概述为验证CPU计费方案而执行的基准测试我们在LinuxRedHat 9计算机(Intel Pentium 4,2.6 GHz,512 MB RAM)上运行SPECJVM98基准测试套件6所有的基准测试都在单用户模式下运行(无网络),我们尽可能多地删除后台进程,以获得可重现的结果。对于所有设置,整个JVM98基准测试(由几个子测试组成)运行10次,通过计算每个子测试中位数的几何平均值获得最终结果在这里,我们展示了在IBM JDK 1.4.2平台的默认example模式下以及Sun JDK 1.5.0(final)平台的“客户端”和“服务器”模式下进行的测量在我们的测试中,我们使用了一个具有简单记帐策略(仅聚合所有线程的CPU消耗)的CPU管理器6http://www.spec.org/osg/jvm98/68W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 141(2005)53在系统中)并且具有最高可能的粒度。粒度对性能影响的分析可以在[4]中找到我们测量了重写的SPEC JVM98应用程序在重写的JDK上的性能,并进行了不同的优化。图13(a)示出了当不应用优化时的开销平均而言,开销为36图图13(b)说明了我们优化的影响我们对3.1节中解释的叶方法进行了优化,并扩展了SPEC JVM 98类中所有方法的签名,以便将ThreadCPUAc-count作为额外参数传递(参见3.2节),而整个JDK则根据图1中的方案进行了重写3 .第三章。我们将这组优化称为标准优化。在这种情况下,平均开销减少到21图13(c)显示了尽可能将ThreadCPUAccount引用传递给JDK方法的影响(见图13)。8)。此外,我们还检查了在定义良好的参数位置传递ThreadCPUAccount的影响。我们评估了N virtual和N static的可能值的大量组合。对于IBM有趣的是,对于Sun的JVM,这个方案并没有提高性能(平均开销为25-31%),这可以解释如下:一方面,JDK类的重写显著增加了代码大小,因此在类加载和即时编译期间导致开销。另一方面,getCurrentAccount()的调用次数(包括对Thread.currentThread()的调用)减少了对于具有相当快的Thread.currentThread()实现的JVM,由于代码大小增加而产生的开销可能会超过较少调用Thread.currentThread()的好处。最后,我们评估了3.3节中提出的简单控制流程优化的影响(见图13(d))。我们首先应用了跳跃优化(第3.3.1节),然后应用了循环优化(第3.3.2节)。之后,类被转换为前面的优化。虽然几何平均值与前面的没有太大的不同,但一些基准测试的结果,特别是在IBM的JVM上,尽管有CPU核算,但甚至有轻微的加速(所有结果都是完全可重现的!)。这是因为SPEC JVM 98类没有使用IBM的Java编译器编译需要进一步的调查,以能够表征的代码模式,在加速和减速观察。然而,这些转变的实际价值并不完全W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 141(2005)5369Sun JDK 1.5.0,客户端模式Sun JDK 1.5.0,服务器模式IBM JDK 1.4.2,默认模式0% 20% 40% 60% 80%0% 20% 40% 60% 80%压缩机JessDB百分之十一点五百分之七点三4.5%44.5%百分之三十五点七百分之三十四点二31.1%百分之六十五点六7.2%4.7%15.0%百分之二十四点四百分之二十六点五百分之十八点一百分之十五点四百分之四十五点八javac7.0%30.1%百分之二十八点一41.9%百分之九点二30.2%24.0%22.6%mpeg-音频地铁公司杰克百分之十七点五百分之三十三点九百分之二十九点六45.3%43.3%百分之六十九点六81.6%百分之八十八点九一百二十二点二百分之二十九点三百分之二十九点二32.4%36.1%百分之二十五点二42.3%百分之二十六点五百分之二十点七百分之五十六点九Geo.是说百分之四十点五40.0%36.3%百分之二十五点七百分之二十九点三百分之二十点八(a)没有优化。(b)标准优化。0% 20% 40% 60% 80%压缩机Jess百分之六点二百分之十九点九百分之二十四点六百分之十九点三百分之二十点七44.1%-2.3%22.4%百分之二十六点五百分之十六点二百分之十四点五44.4%db4.5%百分之十二点七百分之十二点三百分之五点四javac5.7%百分之二十三点七24.2%20.0%5.0%22.1%23.0%百分之三十三点五mpeg-音频地铁公司32.0%百分之二十六点八百分之五十一点八44.0%70W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 141(2005)53百分之五十八点一百分之二十八点二百分之三十点五48.4%42.2%百分之五十七点一杰克Geo.是说百分之九点三百分之三十二点一百分之二十七点四百分之二十点九百分之二十五点二百分之三十点八百分之十七点四9.1%百分之三十三点七百分之二十四点九百分之二十五点八百分之二十三点七30.0%百分之十八点六
下载后可阅读完整内容,剩余1页未读,立即下载
cpongm
- 粉丝: 4
- 资源: 2万+
上传资源 快速赚钱
- 我的内容管理 收起
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
会员权益专享
最新资源
- 基于单片机的瓦斯监控系统硬件设计.doc
- 基于单片机的流量检测系统的设计_机电一体化毕业设计.doc
- 基于单片机的继电器设计.doc
- 基于单片机的湿度计设计.doc
- 基于单片机的流量控制系统设计.doc
- 基于单片机的火灾自动报警系统毕业设计.docx
- 基于单片机的铁路道口报警系统设计毕业设计.doc
- 基于单片机的铁路道口报警研究与设计.doc
- 基于单片机的流水灯设计.doc
- 基于单片机的时钟系统设计.doc
- 基于单片机的录音器的设计.doc
- 基于单片机的万能铣床设计设计.doc
- 基于单片机的简易安防声光报警器设计.doc
- 基于单片机的脉搏测量器设计.doc
- 基于单片机的家用防盗报警系统设计.doc
- 基于单片机的简易电子钟设计.doc
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功