rbpf虚拟机-JIT和解释执行对比

简介: 该篇文章是记录rbpf虚拟机JIT执行和解释执行的速度对比。(学习该虚拟机的目的是为了搞懂solana合约的执行方式,solana使用的rbpf是在该虚拟机上进行扩展。)

✨重磅!盹猫的个人小站正式上线啦~诚邀各位技术大佬前来探秘!✨
—— 专为开发者打造的宝藏基地,等你来探索!
这里有:


🔥 硬核技术干货:编程技巧、开发经验、踩坑指南,带你解锁技术新姿势!
🎉 趣味开发日常:代码背后的脑洞故事、工具测评,让技术圈不再枯燥~
💎 独家资源分享:开源项目、学习资料包,助你打怪升级快人一步!


🚀 立即访问 → 盹猫猫的个人小站 ← 点击探索
🌟 说不定这里就有你寻找已久的技术秘籍哦~

Welcome to Code Block's blog

本篇文章主要介绍了
[rbpf虚拟机-JIT和解释执行对比]
❤博主广交技术好友,喜欢我的文章的可以关注一下❤

一、概述

该篇文章是记录rbpf虚拟机JIT执行和解释执行的速度对比。

(学习该虚拟机的目的是为了搞懂solana合约的执行方式,solana使用的rbpf是在该虚拟机上进行扩展。)

二、定义

2.1解释执行

代码在运行时由解释器逐行解释并执行,不需要提前编译。例如,Python、JavaScript等脚本语言通常采用解释执行。

2.2 JIT编译执行

JIT在程序运行时根据需要将部分代码(如热点代码)编译成机器码,而不是在程序运行前一次性编译所有代码。

三、测试代码

3.1解释执行

#[test]
fn test_process_time() {
     
    let start = Instant::now();
    let prog = assemble(
        "
            mov32 r0, 0        
            mov32 r1, 10000000
            add32 r0, 1
            sub32 r1, 1
            jgt r1, 0, -3
            exit             
        ",
    )
    .unwrap();
    let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
    for _i in 0..5 {
     
        assert_eq!(vm.execute_program().unwrap(), 0x989680);
    }
    let duration_with_jit = start.elapsed();
    eprintln!("未使用 JIT 的总时间: {:?}", duration_with_jit);
}

在上述代码中,使用解释执行,R0赋值为0,R1赋值为10000000,当R1不少于0时执行循环体,循环体内使R0加1,使R1减一,直到不满足循环条件时退出,此时应该返回R0的值为10000000(0x989680),该程序会被执行5次并记录时间。

通过面图片,可以看到该程序总共运行了14秒钟。

3.2 JIT执行

#[test]
fn test_jit_time() {
     
    let start = Instant::now();
    let prog = assemble(
        "
            mov32 r0, 0        
            mov32 r1, 10000000
            add32 r0, 1
            sub32 r1, 1
            jgt r1, 0, -3
            exit             
        ",
    )
    .unwrap();
    let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
    vm.jit_compile().unwrap();
    let duration_with_jit = start.elapsed();
    eprintln!("编译时间: {:?}", duration_with_jit);
    unsafe {
     
        for _i in 0..5 {
     
            assert_eq!(vm.execute_program_jit().unwrap(), 0x989680);
        }
    }
    let duration_with_jit = start.elapsed();
    eprintln!("使用 JIT 的总时间: {:?}", duration_with_jit);
}

然后使用JIT编译和运行命令,执行同样的功能代码。

可以看到执行了执行了12毫秒,也就是1.2%秒。

四、结果

​未使用 JIT 的总时间:
从第一张图片可以看到,程序在未使用 JIT 的情况下,总共运行了约 ​14 秒。这包括了五次循环执行的时间以及解释器逐行解释代码的开销。

​使用 JIT 的总时间:
第二张图片显示,使用 JIT 编译后,程序的总运行时间显著减少至 ​12 毫秒​。
考虑到 JIT 编译本身需要一定的时间(在代码中 vm.jit_compile().unwrap(); 所记录的编译时间),实际执行循环体的时间会更短。
因此,JIT 编译后的执行速度相比解释执行有显著提升。

五、总结

通过对 rbpf 虚拟机中解释执行和 JIT 编译执行的对比测试,我们可以得出以下结论:

​性能提升:JIT 编译在执行速度上显著优于解释执行,适合对性能要求较高的应用场景。
​适用场景:对于需要频繁执行的热点代码,采用 JIT 编译可以带来明显的性能提升;而对于启动时间敏感或执行频率较低的场景,解释执行可能更为合适。
​权衡选择:在实际应用中,可以根据具体需求和场景,选择合适的执行方式,或者结合两者的优点,采用混合执行策略,以达到最佳的性能和用户体验。

代码来源:rbpf虚拟机
鸣谢: qmonnet 提供的开源代码.

当然,我也会将带有中文注释和自己理解的一些代码上传的我的github页面,感兴趣的朋友可以进行clone查看.

我的GitHub:forked


目录
相关文章
|
Web App开发 缓存 前端开发
LightProxy 全能代理抓包工具
LightProxy 是 IFE 团队开发的一款基于 Electron 和 whistle 的开源桌面代理软件,致力于让前端开发人员能够精确的掌握自己的开发环境,通过 HTTP 代理使用规则转发、修改每一个请求和响应的内容。
LightProxy 全能代理抓包工具
|
图形学
Unity 3D游戏-消消乐(三消类)教程和源码
Unity 消消乐教程和源码 本文提供全流程,中文翻译。Chinar坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 —— 高分辨率用户请根据需求调整网页缩放比例) ...
6842 0
|
10天前
|
存储 弹性计算 固态存储
阿里云服务器多少钱一年?2026年最新轻量38元、ECS 99元、GPU按小时、包年包月收费标准
本文详解2026年阿里云服务器最新价格:轻量应用服务器(38元/年起)、ECS包年包月/按量/抢占式计费,及GPU服务器费用;涵盖实例规格、带宽、系统盘收费标准与选型建议。
268 0
|
4月前
|
消息中间件 负载均衡 算法
大模型GPU推理队列排队治理:限流规则+优先级调度+长短拆分+集群负载指南.172
大模型推理队列是承载生成请求的缓冲调度层,用于应对GPU算力稀缺、推理耗时长且不均等特性。通过限流、优先级调度、长短请求拆分、溢出防护和集群负载均衡五大治理手段,实现削峰填谷、保障高可用与资源高效利用。
317 2
|
4月前
|
缓存 边缘计算 网络协议
阿里云国际站:CDN配置新手教程 从添加域名到CNAME解析全流程
不少开发者第一次认真研究 阿里云CDN配置新手教程,不是因为提前做好了技术规划,而是网站已经被突然涌入的流量拖到几乎打不开。加速、抗压、省带宽,这些需求推着人去搞清楚 CDN 到底是什么,以及为什么配置完域名、做完解析,效果不会立刻出现。理清核心概念,后面的操作才不容易跑偏。
819 0
|
消息中间件 数据采集 移动开发
数仓建模—埋点设计与管理
开始之前我们先看一下我们为什么要收集埋点数据,埋点都可以做什么,埋点主要用于记录用户行为,几乎是应用必不可少的功能.埋点的作用包括但不限于
1784 0
数仓建模—埋点设计与管理
|
前端开发
基于jeecgboot的flowable流程并行审批的bug修复
基于jeecgboot的flowable流程并行审批的bug修复
532 2
|
SQL 存储 数据采集
Flink CDC 在京东的探索与实践
京东资深技术专家韩飞,在 Flink Forward Asia 2022 数据集成专场的分享。
Flink CDC 在京东的探索与实践
|
算法 C++
BFS(邻接矩阵+队列)和DFS(邻接表+栈)C++实现
BFS(邻接矩阵+队列)和DFS(邻接表+栈)C++实现
784 0
BFS(邻接矩阵+队列)和DFS(邻接表+栈)C++实现