前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Rust日报】 2019-08-14:在Facebook上反复出现的 C++ bug

【Rust日报】 2019-08-14:在Facebook上反复出现的 C++ bug

作者头像
MikeLoveRust
发布2019-08-19 11:59:35
8260
发布2019-08-19 11:59:35
举报
文章被收录于专栏:Rust语言学习交流

VecOption: 与Vec<Option>等价但更高效的库

#StdExtend

Repo: https://github.com/sivadeilra/vec_option

Syn 和 Quote 1.0 发布

#macro #syn

Syn 和 Quote 此次 1.0 稳定,意味着API接口稳定,但是,并不代表着Rust的语法树稳定。Syn和Quote内部还是会随着Rust的变化而改动,只不过不会影响 Syn 和 Quote 的 API稳定。

注意:Syn和Quote的1.0版本最低依赖Rust 1.31版本。发布日志里还记录了一些Break change,需要注意。

Read More: https://github.com/dtolnay/syn/releases/tag/1.0.0

cargo-docset: 可以生成支持Dash和Zeal的文档集

#docs

Dash和Zeal都是著名的编程语言文档集工具

Repo: https://github.com/Robzz/cargo-docset

async-stream: 提供了stream!宏方便编写异步流

#async #stream #tokio

Repo: https://github.com/tokio-rs/async-stream

「SO问答」对超过240个元素的数组进行循环时,为什么会有很大的性能影响?

#stackoverflow

问题:

下面代码当 CAPACITY >= 240 的时候,与 CAPACITY >= 239 相比,性能慢了80倍。Rust编译器专门为240以内的长度做了优化?使用 rustc -C opt-level=3 进行编译。

代码语言:javascript
复制
use std::time::Instant;

const CAPACITY: usize = 240;
const IN_LOOPS: usize = 500000;

fn main() {
    let mut arr = [0; CAPACITY];
    for i in 0..CAPACITY {
        arr[i] = i;
    }
    let mut sum = 0;
    let now = Instant::now();
    for _ in 0..IN_LOOPS {
        let mut s = 0;
        for i in 0..arr.len() {
            s += arr[i];
        }
        sum += s;
    }
    println!("sum:{} time:{:?}", sum, now.elapsed());
}

解答:

总结:低于240,LLVM完全展开内部循环,可以优化掉重复循环,增加性能。

分析:

这是一个神奇的阈值,超过该阈值LLVM将停止执行某些优化。阈值是 8字节* 240 = 1920字节(数组是usizes数组,因此长度乘以8字节,假设 x86-64 CPU)。在该问题中的基准测试中,是仅针对长度239执行的一个特定优化,所以导致了巨大的性能差异。

比如这段代码:

代码语言:javascript
复制
pub fn foo() -> usize {
    let arr = [0; 240];
    let mut s = 0;
    for i in 0..arr.len() {
        s += arr[i];
    }
    s
}

你在 godbolt 编辑器中查看生成的汇编代码,比较240和239,会发现有很大区别。比如当239的时候生成:

代码语言:javascript
复制
movdqa  xmm1, xmmword ptr [rsp + 32]
movdqa  xmm0, xmmword ptr [rsp + 48]
paddq   xmm1, xmmword ptr [rsp]
paddq   xmm0, xmmword ptr [rsp + 16]
paddq   xmm1, xmmword ptr [rsp + 64]
; more stuff omitted here ...
paddq   xmm0, xmmword ptr [rsp + 1840]
paddq   xmm1, xmmword ptr [rsp + 1856]
paddq   xmm0, xmmword ptr [rsp + 1872]
paddq   xmm0, xmm1
pshufd  xmm1, xmm0, 78
paddq   xmm1, xmm0

就是所谓的循环展开: LLVM将循环体粘贴一段时间,以避免执行那些“循环管理指令”,即循环变量的增量,检查循环是否结束和跳转。(可以自行对比一下240的输出)。但是,即便循环不展开,也不会造成80倍的性能差异。所以,实际上那个性能测试代码嵌套循环导致的(LLVM生成的代码基本上首先只执行内部循环(计算总和),然后通过多次累加总和来模拟外部循环!)。最好要使用Rust的惯用法: arr.iter().sum(),这样就不会产生80倍的性能差异了。

Read More: https://stackoverflow.com/questions/57458460/why-is-there-a-large-performance-impact-when-looping-over-an-array-over-240-elem

Rust 1.37 预发布测试

#Stable

代码语言:javascript
复制
RUSTUP_DIST_SERVER=https://dev-static.rust-lang.org rustup update stable

新版本中有一些新特性:

  • cfgcfg_attr 中可以用泛型参数了
  • 可以对枚举值使用类型别名了
代码语言:javascript
复制
type MyOption = Option<u8>;

fn increment_or_zero(x: MyOption) -> u8 {
    match x {
        MyOption::Some(y) => y + 1,
        MyOption::None => 0,
    }
}
  • 可以用_来定义常量:const _: u32 = 5;
  • Rust 2015 edition 的宏现在支持 ?语法
  • mem::MaybeUninit和T已经实现ABI兼容,MaybeUninit共享T的大小、对齐方式和ABI。

1.37 Release Notes: https://github.com/rust-lang/rust/blob/stable/RELEASES.md#version-1370-2019-08-15

Reddit讨论:CppCon 2017 - 在Facebook上反复出现的 C++ bug

#Facebook

该贴主提到,他看了Facebook工程总监在CppCon 2017的分享,其中谈到Facebook中经常出现的Bug,他认为,这些Bug是用Safe Rust完全不会写出来的Bug。

以下是这些bug的概述:

  • Bug #1: 越界访问。C++的std::vector的索引运算符不进行边界检查。演讲者称之为“可能是每个代码库中问题的最大原因”。Rust's Vec总是进行边界检查,除非您使用Unsafe。
  • Bug #2: 如果你搜索的关键字不在map中,那么std::map的索引运算符将创建一个默认元素。真奇怪。Facebook发生了两起重大事故,Map显示了一些设置,打印设置时偷偷插入了值为0的新设置。Rust的哈希映射不可能做到这一点。要在Rust中获得这样的行为,您必须使用entry() API对其进行显式编程。
  • Bug #3: 试图避免不必要的复制通常会导致对已经不存在的临时成员的引用(悬垂指针)。C++没有借用检查器来检测这一点。Rust会。
  • Bug 4: volatile。它不会使代码线程安全,但是人们还是这样使用它。Safe Rust根本没有volatile。
  • Bug 5: std::shared_ptr线程安全吗?是像Rc还是像Arc?嗯,这很复杂。它很像Arc,但是如果你实际上在多线程环境中使用它,你仍然有可能出错。Rust既有rc又有Arc,它会阻止你将Rc发送到不同的线程。
  • 赠送的Bug : 人们经常解引用std::shared_ptr,并在不保留std::shared_ptr的情况下对结果进行引用。Rust的借用检查在这里拦住你。
  • Bug #6: 由于C++语法中的一个怪癖,很容易编写看起来像std::mutex的代码,但是实际上它正在创建一个与std::mutex同名的std::unique_lock,隐藏它但不锁定它。这里真正的问题是,在C++中,std::mutex没有连接到它所保护的数据,而在Rust中,如果不锁定它,就根本不可能访问受Mutex<T>保护的数据。
  • 附送的Bug : 在C++中,很容易意外地对事物进行深度复制(Clone)。演讲者和听众中的一个人理所当然地指出,这真的没什么大不了的,事实上,许多bug(见bug #3)都是通过避免不必要的拷贝而引入的。尽管如此,Rust在这里对你也有帮助,因为如果你想克隆一些东西,你通常需要显式地做。
  • 附送的又一个bug:“我们有很多与异步编程相关的生命周期问题,”演讲者说。他称之为“非常关键”和“最重要的缺陷之一”。如果说Rust擅长什么,那就是“与异步编程相关的生命周期问题”。

演讲中从未提到Rust,但如果里面提到Rust的话,该演讲就是Rust最好的广告了 :D

(Libra 选择 Rust,某种意义上,可能也是苦C++久矣)

  • Read More: https://www.reddit.com/r/rust/comments/cq9rco/cppcon_2017_curiously_recurring_c_bugs_at_facebook/
  • CppCon 2017 视频 :https://www.youtube.com/watch?v=lkgszkPnV8g

tnef: 一个纯Rust的 TNEF 解析器

#tnef

TNEF 以 application/ms-tnef 类型的 MIME 附件的形式出现在邮件中。

Repo: https://github.com/newpavlov/tnef

「非官方」Google Play市场的 Crates.io 安卓App 已经更新到了1.5版本

#android

头一次知道还有这个App

Read More: https://play.google.com/store/apps/details?id=com.bmco.cratesiounofficial&hl=en_us

Rust异步编程尝试:GitHub star计数工具

#async

供学习使用

Repo: https://github.com/Byron/github-star-counter

Jilu: 根据Git仓库的状态生成改变日志

#git

自动生成 CHANGELOG.md

Repo: https://github.com/rustic-games/jilu

tokio-i3ipc更新到了async/await

#tokio

tokio-i3ipc的作者写了篇文章记录了此事,也算是一个升级参考。

  • Read More: https://leshow.github.io/post/async_await/
  • Repo: https://github.com/leshow/tokio-i3ipc/

static-assertions-rs 发布 0.3.4 版本

#assert

该库可以实现编译时断言。

Repo: https://github.com/nvzqz/static-assertions-rs


From 日报小组 Chaos

日报订阅地址:

独立日报订阅地址:

  • Telgram Channel
  • 阿里云语雀订阅
  • Steemit
  • GitHub

社区学习交流平台订阅:

  • Rust.cc 论坛: 支持 rss
  • Rust Force: 支持 rss
  • 微信公众号:Rust 语言学习交流
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-08-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Rust语言学习交流 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • VecOption: 与Vec<Option>等价但更高效的库
  • Syn 和 Quote 1.0 发布
  • cargo-docset: 可以生成支持Dash和Zeal的文档集
  • async-stream: 提供了stream!宏方便编写异步流
  • 「SO问答」对超过240个元素的数组进行循环时,为什么会有很大的性能影响?
  • Rust 1.37 预发布测试
  • Reddit讨论:CppCon 2017 - 在Facebook上反复出现的 C++ bug
  • tnef: 一个纯Rust的 TNEF 解析器
  • 「非官方」Google Play市场的 Crates.io 安卓App 已经更新到了1.5版本
  • Rust异步编程尝试:GitHub star计数工具
  • Jilu: 根据Git仓库的状态生成改变日志
  • tokio-i3ipc更新到了async/await
  • static-assertions-rs 发布 0.3.4 版本
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档