LoginSignup
1
0

More than 1 year has passed since last update.

RustのPlottersがSSE4を使えない環境で Illegal instruction となる問題を回避する

Posted at

概要

Plotters は環境によっては次のように Illegal instruction でクラッシュする。今回は sse41 のCPU命令が使えない環境であることが原因だった。

$ cargo run
...
   Compiling pathfinder_simd v0.5.1
   Compiling pathfinder_geometry v0.5.1
   Compiling font-kit v0.10.1
   Compiling plotters v0.3.1
   Compiling quick-start v0.1.0 (.../quick-start)
    Finished dev [unoptimized + debuginfo] target(s) in 26.58s
     Running `target/debug/quick-start`
Illegal instruction (core dumped)

環境

  • CPU ... AMD Phenom(tm) II X4 910e Processor
  • WSL (Ubuntu 18.04 LTS)
    • rustc 1.57.0
    • plotters v0.3.1
    • pathfinder_geometry v0.5.1
    • pathfinder_simd v0.5.1

回避方法

Cargo.toml の pathfinder_simd のクレートに対して pf-no-simd を指定する。

@@ -1,7 +1,8 @@
 [package]
 name = "quick-start"
 version = "0.1.0"
 edition = "2021"

 [dependencies]
+pathfinder_simd = { version = "0.5", features = ["pf-no-simd"] }
 plotters = "0.3"

解説

  • plotterspathfinder_geometry を依存関係に持つ
  • pathfinder_geometrypathfinder_simd の v0.5を依存関係にもつ
  • pathfinder_simd は何も指定しない場合は sse41 のCPU命令を含む形でビルドする
    pathfinder_simd のソースコードを見るに pf-no-simd の feature でこの動作を変えられる。
    ただ、Crate pathfinder_geometryCrate pathfinder_simd のサイトにはそんな解説はないので、隠し機能的な扱いと思われる。

GitHub の pathfinder/simd/Cargo.toml のCargo.toml をみると pf-no-simd という features があることが分かる。

[package]
name = "pathfinder_simd"
...

[features]
pf-no-simd = []

...

また、 GitHub の pathfinder/geometry/Cargo.toml からは、バージョン 0.5 を依存関係にもつので同じバージョンで pf-no-simd を指定してビルドすればよいと推測できる。

[package]
name = "pathfinder_geometry"
...

[dependencies.pathfinder_simd]
path = "../simd"
version = "0.5"

参考: 調べ方

参考1: Illegal instruction がどのクレートで発生したのか確認する方法

cargo buildcargo run はデバッグモードでコンパイルされているので、 gdb を使えば調べることができる。

gdb に深い意味はない。Rust流のもっと適した方法があるはずだが、これを調べた時点では知らないので今ある知識を活用する意図で gdb を使った。

bt でバックトレースが確認できるが #0sse41 に関する命令が原因と推測できるし、 #1 でそれが pathfinder_simd によって呼び出されたことが分かる。

$ gdb target/debug/quick-start
...
(gdb) run
...
(gdb) bt
#0  0x00000000080dc4f5 in core::core_arch::x86::sse41::_mm_max_epi32 (a=..., b=...)
    at /rustc/f1edd0429582dd29cccacaf50fd134b05593bd9c/library/core/src/../../stdarch/crates/core_arch/src/x86/sse41.rs:287
#1  0x00000000080db055 in pathfinder_simd::x86::I32x4::max (self=..., other=...)
...

参考2: CPUのサポートする命令の確認方法

cat /proc/cpuinfolshw を使って sse41 の有無を確認できる。

  • /proc/cpuinfo を使う方法
   $ grep flags /proc/cpuinfo
   flags           : fpu vme de pse tsc msr ... sse sse2 ... sse4a ...
  • lshw を使う方法
   $ sudo lshw -class processor
   [sudo] password for ********:
     *-cpu
          ...
          capabilities: fpu fpu_exception wp vme de pse tsc msr 
   ... sse sse2 ... sse4a ...

参考3: 事例で調べる

CPU名が分れば、カタログスペックやらで確認出来たりもする。
以下、「amd phenom sse」あたりで検索して出てきたサイトで SIMD 命令の対応状況が表にまとめられている。

参考: 検証に使ったソース

Crate plotters > Quick startにあるそのままのコードです。 plotters-doc-data/ のディレクトリは事前に作っておく必要がありそう。

use plotters::prelude::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let root = BitMapBackend::new("plotters-doc-data/0.png", (640, 480)).into_drawing_area();
    root.fill(&WHITE)?;
    let mut chart = ChartBuilder::on(&root)
        .caption("y=x^2", ("sans-serif", 50).into_font())
        .margin(5)
        .x_label_area_size(30)
        .y_label_area_size(30)
        .build_cartesian_2d(-1f32..1f32, -0.1f32..1f32)?;

    chart.configure_mesh().draw()?;

    chart
        .draw_series(LineSeries::new(
            (-50..=50).map(|x| x as f32 / 50.0).map(|x| (x, x * x)),
            &RED,
        ))?
        .label("y = x^2")
        .legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], &RED));

    chart
        .configure_series_labels()
        .background_style(&WHITE.mix(0.8))
        .border_style(&BLACK)
        .draw()?;

    Ok(())
}

実行結果

0.png

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0