在 2025 收官前,看清 Data + AI 的真实走向,点击查看 BUILD 大会精华版 了解详情
写点什么

从 C 迁移到 Rust 的挑战与经验教训

作者:Sergio De Simone

  • 2024-11-18
    北京
  • 本文字数:1595 字

    阅读完需:约 5 分钟

从 C 迁移到 Rust 的挑战与经验教训

在一个系列文章中,Immunant 软件工程师 Stephen Crane 和 Khyber Sen 讲述了他们如何将互联网安全研究小组 (ISRG) 的 VideoLAN 和 FFmpeg AV1 解码器从 C 语言移植到 Rust 语言。该系列文章详细介绍了他们如何确保不出错并优化性能。


VideoLan VLC 和 FFMpeg 中使用的 AV1 解码器 dav1d 已经开发了六年多,包含大约 5 万行 C 代码和 25 万行汇编程序。正如 Crane 所说的那样,它成熟、速度快且应用广泛。因为代码高度优化,所以它的体积小、可移植性好、速度快。因此,他们坚持要移植,而不是使用 Rust 从头开始重写。


Immunant 的工程师们首先要做的选择是,是一步一步地进行移植,还是使用 c2rust 移植整个代码库,获得一个不安全但可运行的 Rust 实现,然后再以此为基础进行重构和重写,使其变得安全而又符合 Rust 的语言习惯。最终,他们决定采用 c2rust,因为它有两大优势:一是可以在重构的同时测试移植的代码,二是降低了对专家领域知识的要求。


我们发现,在重写和改进 Rust 代码的过程中,从一开始就进行全面的 CI 测试是非常有益的。我们可以对代码库进行横向修改,并在每次提交时运行已有的 dav1d 测试。[…] 该项目的大部分团队成员都是系统编程和 Rust 方面的专家,但之前并没有 AV 编解码器方面的经验。我们的编解码器专家 Frank Bossen 为项目提供了宝贵的指导,但大部分的工作他并不需直接要参。


将移植生成的 Rust 代码重构为安全、符合语言习惯的 Rust 代码面临着许多挑战,其中一些挑战与 C 和 Rust 之间的不匹配有关,例如生命周期管理(借用)、内存所有权、缓冲指针和联合体;另一些挑战则源于 dav1d 的设计,它非常依赖于对跨线程共享可变数据的访问。


通过使用MutexRwLock加锁,并在运行时使用Mutex::try_lock()RwLock::try_read()/RwLock:: try_write()进行验证,他们确保了线程可以访问数据而且又不会引入延迟,从而解决了与共享状态相关的线程安全问题。


这种方法可以很好地处理只有一个线程需要修改跨线程共享值的情况。然而,dav1d 还依赖于多个线程对单个缓冲区的并发访问,其中每个线程访问缓冲区的特定子区域。对此,Immunant 工程师并没有使用更符合 Rust 语言习惯的方法,即使用专门分配给不同线程的不相连的区域,而是创建了一个缓冲区封装类型DisjointMut,负责处理可变借用,并确保每一个都能独占访问。


另外两个颇具挑战性的领域是自引用结构(主要用于跟踪缓冲区位置的游标以及上下文结构之间的链接)和无标签联合体。由于 Rust 不允许使用自引用结构,所以游标指针被整数索引取代,而上下文结构之间的链接被取消,并通过函数参数进行引用。在适当的时候,无标签联合体会被转换为带标签的 Rust 联合体,而在其他情况下,zerocopy crate 会在运行时将相同的字节重新解释为两种不同的类型,以避免改变联合体的表示和大小。


移植的一个主要目标是保持性能不变。因此,Immunant 的工程师在每次提交的重构阶段都会仔细监控性能回归情况。在向安全代码转换的过程中,他们意识到,性能主要是受到一些微妙因素的影响,如动态分派汇编代码、边界检查和结构初始化的成本。最后,他们进行了与分支、内联和堆栈使用相关的更细致的优化。


性能优化工作显著降低了移植带来的开销,从 11% 降至 6%。按照 Crane 的说法,总体上,将 dav1d 移植到 rav1d 花费了三个开发人员 20 多个月的时间,所耗费的人工比最初预计的要多。但这也表明,将现有的 C 代码重写为安全、高性能的 Rust 代码并解决所有线程和借用难题是可能的。


对特别注重安全性的应用程序,rav1d 提供了一个内存安全的实现,而且不会因为沙箱等风险缓解措施而额外增加开支。我们相信,通过不断地优化和改进,在任何情况下,Rust 实现都可以与 C 语言实现相媲美,同时还能提供内存安全性。


他们从 rav1d 的诞生过程中学到的东西远不止这些,如果想了解更多信息,请阅读原文。


查看原文链接:

https://www.infoq.com/news/2024/10/porting-av1-decoder-rust/

2024-11-18 08:107201

评论

发布
暂无评论
发现更多内容

力扣每日一练之二维数组上篇Day4

京与旧铺

6月月更

盘点一些好用且小众的 Markdown 编辑器

宇宙之一粟

markdown编辑器 6月月更

“多元化”通证经济模型:DAO的神经和血液

CECBC

一款可以实现内网脱机分享文档的接口测试软件

Xd

Java 数据库 后端 API 接口测试软件

元宇宙来袭的五个趋势

CECBC

阿里云智能编码插件进行了一个上新大动作

阿里云云效

云计算 阿里云 云原生 代码

一文带你认识HTML

未见花闻

6月月更

研究uni-app的第五天

恒山其若陋兮

6月月更

揭秘攻防演练中红队需要什么样的人才

穿过生命散发芬芳

6月月更 攻防演练

数字人民币预付式消费的监管之道,智能合约能不能解决所有问题?

CECBC

如何防止NFT行业被污名化?

CECBC

官宣!Apache Doris 从 Apache 基金会毕业,正式成为 Apache 顶级项目!

SelectDB

Apache 数据库 apache doris

linux之我常用的系统重要文件备份命令

入门小站

Linux

【LeetCode】数组中的 k-diff 数对Java题解

Albert

LeetCode 6月月更

vue prop传递数据

小恺

6月月更

leetcode 198. House Robber 打家劫舍(中等)

okokabcd

LeetCode 动态规划 数据结构与算法

数据库每日一题---第14天:用户推荐人

知心宝贝

数据库 云计算 前端 后端 6月月更

DevStream 成为 CNCF Sandbox 项目啦!- 锣鼓喧天、鞭炮齐鸣、红旗招展、忘词了。

胡说云原生

开源 cncf DevStream

Java的面试技术点

卢卡多多

Java 面试官 6月月更

IP核是什么?有什么类型?半导体IP核全攻略

龙智—DevSecOps解决方案

知识产权 半导体 芯片开发 半导体IP核 IP核管理

95后阿里P7晒出工资单:狠补了这些个技术栈,真的香啊

Java全栈架构师

Java 程序员 面试 架构师 Java面试题

V1签名校验

北洋

Andriod 6月月更

八大误区,逐个击破(3):在云上,变更和数据的管理都不足为虑

龙智—DevSecOps解决方案

atlassian云版 版本选择 迁移上云

通过DAO的现状,看Web3最具影响力的基础设施M-DAO

小哈区块

频频破圈,走向百业:大模型的毕业季

脑极体

转转统一权限系统的设计与实现(设计篇)

转转技术团队

权限系统 rbac

数据质量管理

奔向架构师

数据治理 数据管理 6月月更

再仿个人主页来看 GetX 和 Provider 之间的 PK

岛上码农

flutter ios 前端 安卓 6月月更

Java Core 「9」J.U.C 同步工具类-1

Samson

学习笔记 Java core 6月月更

微服务如何拆分

阿泽🧸

微服务 6月月更

从 C 迁移到 Rust 的挑战与经验教训_编程语言_InfoQ精选文章