虚拟机/解释器的性能提升策略?

     2023-02-17     100

关键词:

【中文标题】虚拟机/解释器的性能提升策略?【英文标题】:Performance improvement strategies for VM / interpreter? 【发布时间】:2012-07-30 11:15:03 【问题描述】:

我用 C 编写了一个简单的 VM,使用简单的指令切换,没有任何指令解码,但性能很糟糕。

对于简单的算术运算,对于相同的运算,VM 比本地 C 代码慢大约 4000 倍。我测试了一组长度为 1000 万的数组,第一个由程序指令组成,随机 + - * / 操作,2 个保存随机整数的数组,第三个数组是操作目标存储。

我原以为算术性能会下降 3-4 倍,所以 `4000x 真的让我大吃一惊。即使是最慢的解释语言似乎也能提供更高的性能。那么我的方法哪里出了问题,如何在不将 JIT 编译为机器代码的情况下提高性能?

实现是...基本上是我能想到的最简单的:

begin:
    
        switch (*(op+(c++)))
        
        case 0:
            add(in1+c, in2+c, out+c); goto begin;

        case 1:
            sub(in1+c, in2+c, out+c); goto begin;

        case 2:
            mul(in1+c, in2+c, out+c); goto begin;

        case 3:
            div(in1+c, in2+c, out+c); goto begin;

        case 4:
            cout << "end of program" << endl;
            goto end;

        default:
            cout << "ERROR!!!" << endl;

        
    

end:

更新: 当我注意到我用来分析的 QElapsedTimer 实际上被破坏时,我正在玩弄程序的长度。现在我正在使用 clock() 函数,根据它计算的 goto 实际上与本机代码运行相当,可能会低一点。这个结果合法吗???这是完整的源代码(我知道它很丑,毕竟它只是为了测试):

#include <QtGlobal>
#include <iostream>
#include <stdio.h>
#include <ctime>

using namespace std;

#define LENGTH 70000000

void add(int & a, int & b, int & r) r = a * b;
void sub(int & a, int & b, int & r) r = a - b;
void mul(int & a, int & b, int & r) r = a * b;
void div(int & a, int & b, int & r) r = a / b;

int main()

    char * op = new char[LENGTH];
    int * in1 = new int[LENGTH];
    int * in2 = new int[LENGTH];
    int * out = new int[LENGTH];

    for (int i = 0; i < LENGTH; ++i)
    
        *(op+i) = i % 4;
        *(in1+i) = qrand();
        *(in2+i) = qrand()+1;
    

    *(op+LENGTH-1) = 4; // end of program


    long long  sClock, fClock;


    unsigned int c = 0;
    sClock = clock();

    cout << "Program begins" << endl;

    static void* table[] = 
        &&do_add,
        &&do_sub,
        &&do_mul,
        &&do_div,
        &&do_end,
        &&do_err,
        &&do_fin;

#define jump() goto *table[op[c++]]

    jump();
do_add:
    add(in1[c], in2[c], out[c]); jump();
do_sub:
    sub(in1[c], in2[c], out[c]); jump();
do_mul:
    mul(in1[c], in2[c], out[c]); jump();
do_div:
    div(in1[c], in2[c], out[c]); jump();
do_end:
    cout << "end of program" << endl; goto *table[6];
do_err:
    cout << "ERROR!!!" << endl; goto *table[6];
do_fin:

    fClock = clock();
    cout << fClock - sClock << endl;

    delete [] op;
    delete [] in1;
    delete [] in2;
    delete [] out;

    in1 = new int[LENGTH];
    in2 = new int[LENGTH];
    out = new int[LENGTH];

    for (int i = 0; i < LENGTH; ++i)
    
        *(in1+i) = qrand();
        *(in2+i) = qrand()+1;
    

    cout << "Native begins" << endl;

    sClock = clock();

    for (int i = 0; i < LENGTH; i += 4)
    

        *(out+i) = *(in1+i) + *(in2+i);
        *(out+i+1) = *(in1+i+1) - *(in2+i+1);
        *(out+i+2) = *(in1+i+2) * *(in2+i+2);
        *(out+i+3) = *(in1+i+3) / *(in2+i+3);
    

    fClock = clock();
    cout << fClock - sClock << endl;

    delete [] in1;
    delete [] in2;
    delete [] out;

    return 0;

【问题讨论】:

您需要删除 Sleep(1) 您已在代码中进行调试。 ;) 说真的,你有没有机会在每次迭代期间调用任何系统函数? @avakar - 绝对没有被调用,整个程序循环仅包含一个 switch 语句,该语句调用适当的函数并递增指令指针。调试构建甚至更慢,大约 9000 倍的性能下降。它仍然非常快,这 1000 万次操作只花费了动态分配内存所需时间的一小部分,但我仍然希望有更高的性能,这似乎是可能的。 eli.thegreenplace.net/2012/07/12/… 您是否考虑向我们提供更多有关您的 VM 的信息?如何提高代码的性能,你几乎一无所知,这很难回答。 这个方法听起来很合理,所以问题可能出在你遗漏的细节上。 【参考方案1】:

Darek Mihocka 有一篇关于在便携式 C 中创建快速解释器的优秀而深入的文章:http://www.emulators.com/docs/nx25_nostradamus.htm

【讨论】:

深入理解jvm——垃圾收集策略具体解释

Java虚拟机的内存模型分为五个部分。各自是:程序计数器、Java虚拟机栈、本地方法栈、堆、方法区。这五个区域既然是存储空间,那么为了避免Java虚拟机在执行期间内存存满的情况,就必须得有一个垃圾收集者的角色。不定期... 查看详情

浅读java虚拟机

...节码的行号指示器,在虚拟机的模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、异常处理、线程恢复等基础功能都需要依赖计数器完成。2、Java虚拟机栈&... 查看详情

关于amd的虚拟化技术

如题,我想问的问题是,开启虚拟化技术后用虚拟机性能会提升吗?如果有提升,提升得大吗?我打算在Windows7下开几个XP的虚拟机,这个功能对我帮助大不大呢?我的是羿龙955,已经在BIOS中开启了VT,16G内存,从目前来说,我多开虚拟机来玩DNF... 查看详情

浅读java虚拟机

理解Java虚拟机结构是Java从业人员必备技能,下面描述Java虚拟机结构、垃圾收集器与内存分配策略,在排查java性能问题以及性能优化时大有帮助,掌握Java虚拟机20%的知识能解决工作中80%的Java性能诊断及优化(与J... 查看详情

01-jvm与java体系结构

...otSpotVM是目前市面上高性能虚拟机的代表作之一。它采用[解释器]与[即时编译器]并存的架构。解释器:保证响应时间。及时对字节码文件逐行解释执行JIT:保证性能。针对字节码指令中某些反复执行的指令(热点代码)再次编译成... 查看详情

深入理解java虚拟机-如何利用visualvm对高并发项目进行性能分析

Java虚拟机深入理解系列全部文章更新中...深入理解Java虚拟机-Java内存区域透彻分析深入理解Java虚拟机-常用vm参数分析深入理解Java虚拟机-JVM内存分配与回收策略原理,从此告别JVM内存分配文盲深入理解Java虚拟机-如何利用JDK自带... 查看详情

9.4代码缓存java性能优化节选

...域,该区域还存储属于虚拟机本身的其他原生代码,比如解释器的部分内容。代码缓存在虚拟机启动时设置了一个固定的最大值。它不能超出这个限制,所以有可能被填满。如果被填满,就不能再进行JIT编译,并且未编译的代码... 查看详情

虚拟机是怎样运行的,原理是啥?

它是通过什么方式虚拟出一个操作系统的?谢谢解答.虚拟机的运行:指通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统。原理:从最初编写的Java源文件(.java文件)是如何一步步执行的,... 查看详情

在centos中再docker一个centos会不会性能比较低

...不需要用两个内核翻译数据。虚拟机是在内核上运行一个解释器,需要进行不同的数据转换。所以虚拟机是需要转换数据来让客户系统运行的,而容器则更像是一个应用程序。所以容器的性能损耗基本可以忽略,就算是3d应用都... 查看详情

jvm-虚拟机栈简介

1.简介1.1虚拟机栈的出现背景由于跨平台性的设计,Java的指令都是根据栈来设计的。不同平台CPU架构不同,所以不能设计为基于寄存器的【如果设计成基于寄存器的,耦合度高,性能会有所提升,因为可以对具体的CPU架构进行优... 查看详情

vm虚拟机处理器设置

参考技术A由于工作原因会经常用到虚拟机,而[VMwareWorkstationPro]确实是一款非常好用的虚拟机软件。与处理器有关的就两个参数:处理器数量、每个处理器的核心数量。找了网上好多资料关于处理器设置的都介绍的不太清楚,于... 查看详情

深入理解java虚拟机-常用vm参数分析

Java虚拟机深入理解系列全部文章更新中...深入理解Java虚拟机-Java内存区域透彻分析深入理解Java虚拟机-常用vm参数分析深入理解Java虚拟机-JVM内存分配与回收策略原理,从此告别JVM内存分配文盲深入理解Java虚拟机-如何利用JDK自带... 查看详情

jvm的解释执行与编译执行

1、原理  字节码无法直接交给硬件执行需要虚拟机翻译成机器码才能执行,“翻译”的策略有两种:解释执行和编译执行又称即使编译(JIT)。解释执行是没执行一句字节码的时候把字节码翻译成机器码并执行,优点是启... 查看详情

jvm虚拟机详解+tomcat性能优化(代码片段)

...),并映射到本地的cpu的指令集或OS系统调用。  2.JVM虚拟机主要有堆、栈、本地方法栈、方法区组成注:(1)堆和栈都是一种数据项按序排列的数据结构,只能在一端对数据项进行插入和删除。  (2)在单片机应用中,堆... 查看详情

php7开启opcache和swoole哪个提升更大?性能的提升对比

参考技术A测试所用的主机为虚拟机,虚拟机配置在双核4GB的个人电脑中。虚拟机系统为linux,http服务器采用nginx,用lnmp脚本安装nginx、mysql、php。Laravel框架为7.X版本。在app/Http/Kernel文件中,关掉频率限制中间件throttle。修改php-fpm... 查看详情

虚拟机放在固态硬盘里会有提升吗

有的!虚拟机装在固态硬盘里。虚拟机系统镜像也装在固态硬盘里。你虚拟机跑的数据都在固态硬盘里。肯定比在普通硬盘快的啊!参考技术A提升软件启动速率。 参考技术B能大大加速虚拟机里的系统启动速度,你可以把虚拟机... 查看详情

java虚拟机:垃圾回收策略及算法

java虚拟机中的程序计数器区、虚拟机栈区、本地方法栈区3个区域是随着线程的创建而创建,随着线程的结束而结束时,内存自然得到回收,所以这三个区域不需要过多考虑内存的回收问题。java虚拟机中的方法区和虚拟机堆区2... 查看详情

linuxbpf学习笔记-技术背景[2](代码片段)

...(也称为BPF字节码)定义过滤器表达式,然后传递给内核以供解释器执行.这使得过滤可以在内核级别进行,而无需将每个数据包复制到用户级别的进程中,提升了tcpdump使用的数据包筛选的性能.它还提供了安全性,因为可以在... 查看详情