e-tipsmemo

ごった煮

Rustでマルチスレッド 試用

rustbyexample.com

ここを参考に
e-tipsmemo.hatenablog.com
をマルチスレッド化してみる。
ついでに積分計算は台形で行うように変更した。

extern crate test;

use std::thread;

#[derive(Debug, Copy, Clone)]
struct Fx {
    a: f64,
    b: f64,
    step: u64,
    f: fn(f64) -> f64,
}

impl Fx {
    fn new(a: f64, b: f64, step: u64, f: fn(f64) -> f64) -> Fx {
        Fx {
            a: a,
            b: b,
            step: step,
            f: f,
        }
    }
}

fn integral(p: &Fx) -> f64 {
    let dx = (p.b - p.a) / (p.step as f64);

    let mut sum = 0.0;

    for n in 0..p.step {
        let x = p.a + dx * (n as f64);
        let bar = ((p.f)(x) + (p.f)(x + dx)) * dx / 2.0;
        sum = sum + bar;
    }
    sum
}

#[cfg(test)]
mod tests {
    use super::*;

    const a: f64 = 0.0;
    const b: f64 = 1.0;
    const thread: u64 = 4;
    const onestep: u64 = 10000000;

    fn f(x: f64) -> f64 {
        x * x + 1.0
    }

    #[test]
    fn int_test() {
        let prim = Fx::new(a, b, thread * onestep, f);
        println!("single:{:?}", integral(&prim));
    }

    #[test]
    fn int_thread_test {
        let mut pvec = vec![];
        let x = (b - a) / (thread as f64);
        let ti = thread as usize;

        for t in 0..thread {
            let at = a + x * (t as f64);
            let bt = a + x * (t as f64) + x;
            let prim = Fx::new(at, bt, onestep, f);
            pvec.push(prim);
        }

        let mut children = vec![];
        let mut data = vec![];

        for i in 0..ti {
            let p = pvec[i];
            children.push(thread::spawn(move || integral(&p)));
        }

        for child in children {
            data.push(child.join().unwrap());
        }

        let res = data.iter().fold(0.0, |s, &t| s + t);
        println!("{:?}", data);
        println!("multi:{:?}", res);
    }
}

fn main() {
    let handle = thread::spawn(|| {
        println!("Hello, thread World!");
    });

    let _ = handle.join();
}

雰囲気で書いたがうまく書かないとマルチスレッドで速くなるとは限らない?

実行

$ cargo test
.....
    Finished dev [unoptimized + debuginfo] target(s) in 1.4 secs
     Running target/debug/deps/multi-eddd85052ba1c1ac

running 2 tests
[0.25520833333333814, 0.28645833333335946, 0.3489583333333194, 0.44270833333336124]
multi:1.3333333333333783
.single:1.3333333333332258
.
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured

値が少しだけ大きい。どこか足しすぎてるか?

Programming Rust: Fast, Safe Systems Development

Programming Rust: Fast, Safe Systems Development

ElecrowとPCBGOGOの比較

パターンミスのために
基板製造を二回したので
ElecrowとPCBGOGOでそれぞれ行い、
主観的な比較を行った。

基板サイズは約50mmX50mmで色は白

製造した基板
f:id:katakanan:20171221105235j:plain:w600

左がPCBGOGO
右がElecrow

Elecrow

  • 少し黄ばんでいる(白だと気になるかもしれない)
  • 担当者によるチェックがない
  • 箱が汚い(手触りがちょっと粉っぽい・・)
  • Elecrowストアで変なものが買える

www.elecrow.com

  • 3万円以上注文で送料無料

PCBGOGO

  • Elecrowより少し速い(ような気がする)
  • 箱がついてくるのが良い。

f:id:katakanan:20171221110300j:plain:w150
50mmX50mmの基板ぐらいだとこの箱の体積比4倍の箱で送られてきたが
20mmX30mmの基板ぐらいだとこのサイズ(100mmX100mmX40mmぐらい)の箱で送ってくる。
収納に便利。

  • 発注時に付与される基板製造番号が勝手に印刷される。(画像の黒い場所)
  • 製造前にチェックがある

(フォーマットチェックぐらいでP板のようなパターン内容までチェックしてくれているわけではないと思う)

  • (2層基板だと)製造工程がわかる(元祖)

4層以上は工場違うらしく、また基板チェックも製造も結構時間がかかる。

  • 無料のユニバーサル基板を貰える

共通

  • 休日を挟むと製造が止まる
  • 送料は1500円前後
  • ステンシルを注文できる
  • Paypal経由で支払う事ができる。
  • 指定できる色の種類
  • 実装サービス(使ったことはない)

最近のElecrowのリニューアルで製造工程がわかるようになっているらしい



KICADは微妙だが、
もし、KiCADでPCBを作るならこの本がとても参考になる

STM32マイコン徹底入門 (TECH I Processor)

STM32マイコン徹底入門 (TECH I Processor)

Rust bench 実行時間測定

rustである関数の実行時間を測定したいときがあったのでメモ

環境
rustc --version
rustc 1.24.0-nightly (f8af59d95 2017-12-13)

rustc-testクレートが必要なのでCargo.tomlに記述する。

extern crate test;

use test::test::Bencher;

struct Fx {
    a: f64,
    b: f64,
    dx: f64,
    f: fn(f64) -> f64,
}

impl Fx {
    fn new(a: f64, b: f64, step: u64, f: fn(f64) -> f64) -> Fx {
        Fx {
            a: a,
            b: b,
            dx: (b - a) / (step as f64),
            f: f,
        }
    }
}

fn integral(prim: &Fx) -> f64 {
    let a = prim.a;
    let b = prim.b;
    let dx = prim.dx;
    let f = prim.f;
    let step = ((b - a) / dx) as u32;

    let mut sum = 0.0;

    for n in 0..step {
        let x = a + dx * (n as f64);
        let bar = f(x) * dx;
        sum = sum + bar;
    }
    sum
}

#[cfg(test)]
mod tests {
    use super::*;

    fn f(x: f64) -> f64 {
        x * x + 1.0
    }

    #[test]
    fn int_test() {
        let f = f;
        let prim = Fx::new(0.0, 1.0, 1000000, f);
        println!("{}", integral(&prim));
    }

    #[bench]
    fn int_bench(b: &mut Bencher) {
        let f = f;
        let prim = Fx::new(0.0, 1.0, 1000000, f);

        b.iter(|| {
            let p = test::black_box(&prim);
            integral(p);
        });
    }
}

fn main() {
        println!("Hello, thread World!");
}

雑に積分をする。
Bencherのiterに渡したクロージャ-を含む関数を何回も実行して(int_bench)
実際のクロージャーの実行にかかった時間を平均しているようだ。

しかし最適化によって実行結果がすでに計算されていたりすると、
実行時間が0nsと出てしまうので
black_boxで値を渡すことによってコンパイル時に計算する程度の最適化を抑制する。

実行

テストを実行するなら

cargo test

ベンチマークを実行するなら

cargo bench

Programming Rust: Fast, Safe Systems Development

Programming Rust: Fast, Safe Systems Development

Verilog ビデオ信号出力(Transition Minimized Differential Signaling)

いわゆるHDMIのV1.0でDVI-Dと互換のデータ形式

e-tipsmemo.hatenablog.com
の続き。
といっても
e-tipsmemo.hatenablog.com
Verilogにするだけ

module encoding(
    input clk,
    input resetn,
    input [7:0] din,
    output [9:0] dout,
    input disp_area,
    input c0,
    input c1
    );
    
    function [3:0] ones(input [7:0] in);
        begin
            ones = {3'b0,in[7]}+{3'b0,in[6]}+{3'b0,in[5]}+{3'b0,in[4]}+{3'b0,in[3]}+{3'b0,in[2]}+{3'b0,in[1]}+{3'b0,in[0]};   
        end
    endfunction
    
    function [3:0] zeros(input [7:0] in);
        begin
            zeros = 4'd8 - {3'b0,in[7]}+{3'b0,in[6]}+{3'b0,in[5]}+{3'b0,in[4]}+{3'b0,in[3]}+{3'b0,in[2]}+{3'b0,in[1]}+{3'b0,in[0]};   
        end
    endfunction
    
    function [9:0] xor_out(input [7:0] in);
        begin
            xor_out[0] = in[0];
            xor_out[1] = in[1]^xor_out[0];
            xor_out[2] = in[2]^xor_out[1];
            xor_out[3] = in[3]^xor_out[2];
            xor_out[4] = in[4]^xor_out[3];
            xor_out[5] = in[5]^xor_out[4];
            xor_out[6] = in[6]^xor_out[5];
            xor_out[7] = in[7]^xor_out[6];
            xor_out[8] = 1;
            xor_out[9] = 0;           
        end
    endfunction
    
    function [9:0] xnor_out(input [7:0] in);
        begin
            xnor_out[0] = in[0];
            xnor_out[1] = ~(in[1]^xnor_out[0]);
            xnor_out[2] = ~(in[2]^xnor_out[1]);
            xnor_out[3] = ~(in[3]^xnor_out[2]);
            xnor_out[4] = ~(in[4]^xnor_out[3]);
            xnor_out[5] = ~(in[5]^xnor_out[4]);
            xnor_out[6] = ~(in[6]^xnor_out[5]);
            xnor_out[7] = ~(in[7]^xnor_out[6]);
            xnor_out[8] = 0;
            xnor_out[9] = 0;           
        end
    endfunction
    
    reg[9:0] d00 = 10'b1101010100;
    reg[9:0] d01 = 10'b0010101011;
    reg[9:0] d10 = 10'b0101010100;
    reg[9:0] d11 = 10'b1010101011;
    
    wire clk;
    wire resetn;
    wire[7:0] din;
    
    reg[9:0] dout;
    reg[9:0] dout1;
    wire disp_area;
    wire c0;
    wire c1;
    reg c0_d;
    reg c1_d;
    reg disp_d;
    reg disp_dd;
    
    wire[3:0] dones;
    assign dones = ones(din);
    
    always@(posedge clk)begin
        if(resetn == 1'b0)begin
            disp_d <= 1'b0;
            dout1 <= 10'b0;
            c0_d <= 1'b0;
            c1_d <= 1'b0;
        end
        else begin
            disp_d <= disp_area;

            
            if(disp_area == 1'b1)begin
                if((dones >= 4'd5)||((dones == 4'd4)&&(din[0] == 1'b0)))begin
                    dout1 <= xnor_out(din);
                end 
                else begin
                    dout1 <= xor_out(din);
                end
            end
            else begin
                dout1 <= 10'b0;
                c0_d <= c0;
                c1_d <= c1;
            end 
        
    
        end
    end
    
    reg signed [4:0] cnt;
    wire[3:0] n1;
    wire[3:0] n0;
    
    assign n1 = ones(dout1[7:0]);
    assign n0 = 4'd8 - n1;
        
    always@(posedge clk)begin
        if(resetn == 1'b0)begin
             disp_dd <= 1'b0;;
             dout <= 10'b0;
        end
        else begin
             disp_dd <= disp_d;
             if(disp_dd == 1'b0 && disp_d == 1'b1)begin
                cnt <= 0;
             end
             
             if(disp_d == 1'b1) begin
                 if(disp_d == 1'b1)begin
                    if((cnt == 5'b0)||(n1 == 4'd4))begin
                        dout[9] <= ~dout1[8];
                        dout[8] <= dout1[8];
                        if(dout1[8] == 1'b0)begin
                            dout[7:0] <= ~dout1[7:0];
                            cnt <= cnt + n0 - n1;
                        end
                        else begin
                            dout[7:0] <= dout1[7:0];
                            cnt <= cnt + n1 - n0;
                        end
                    end 
                    else begin
                        if(((cnt > 0)&&(n1 > 4))||((cnt < 0)&&(n1 < 4)))begin
                            dout[9] <= 1'b1;
                            dout[8] <= dout1[8];
                            dout[7:0] <= ~dout1[7:0];
                            
                            if(dout1[8] == 1'b0)begin
                               cnt <= cnt + n0 - n1; 
                            end
                            else begin
                                cnt <= cnt + n0 - n1 + 2;
                            end
                        end
                        else begin
                            dout[9] <= 1'b0;
                            dout[8:0] <= dout1[8:0];
                            
                            if(dout1[8] == 1'b0)begin
                                cnt <= cnt + (n1 - n0) - 2;
                            end
                            else begin
                                cnt <= cnt + n1 - n0;
                            end
                        end
                    end
                 end
             end
             else begin
                case({c1_d,c0_d})
                    2'b00 : begin
                                dout <= d00;
                            end 
                    2'b01 : begin
                                dout <= d01;
                            end 
                    2'b10 : begin
                                dout <= d10;
                            end 
                    2'b11 : begin
                                dout <= d11;
                            end 
                endcase
             end
        end
    end
    
endmodule


V1.2?以上に必要となるガードバンドなどはここでタイミングを制御するべきであろうか

objcopyで textセクションの抽出

諸事情があって自分の書いたMIPSアセンブリを純粋に機械語に変換しただけの16進数表示のテキストが
ほしいという状況になった。
今回はMIPSでそういう状況だったがgccを使っているのでアセンブラのところを切り替えれば
x86でもx64でもarmでもなんでも同様の手順でできると思う。

準備

UbuntuやWSLなどを想定している。

$ sudo apt-get install gcc-mips-linux-gnu

50MB近くあるので待つ。

アセンブリコードを用意する。

ラベルも追加しておけばループできる

addi $3, $0, 5
addi $4, $0, 0
L: addi $4, $4, 1
BNE $3, $4, L
nop
nop
nop
....

nopは00000000となる

アセンブラする
$ mips-linux-gnu-as source.s -o source

これは色々と別のセクションやelfヘッダもくっついている

$ mips-linux-gnu-objdump source -h
Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00004010  00000000  00000000  00000040  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000000  00000000  00000000  00004050  2**4
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  00000000  00000000  00004050  2**4
                  ALLOC
  3 .reginfo      00000018  00000000  00000000  00004050  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA, LINK_ONCE_SAME_SIZE
  4 .MIPS.abiflags 00000018  00000000  00000000  00004068  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA, LINK_ONCE_SAME_SIZE
  5 .pdr          00000000  00000000  00000000  00004080  2**2
                  CONTENTS, READONLY
  6 .gnu.attributes 00000010  00000000  00000000  00004080  2**0
                  CONTENTS, READONLY

バイナリを直接表示

$ xxd source
textセクション抽出
$ mips-linux-gnu-objcopy -O binary --only-section=.text ./source ./source.bin
$ xxd source.bin
16進数テキストにする

出力したいフォーマットによってオプションの数字を変える必要がある。

$ xxd -ps -c 4 source.bin > program.hex

-c 4.. 4byte(32bit)単位で表示

$ cat program.hex | head
20030005
20040000
20840001
1464fffe
00000000
00000000
00000000
00000000
00000000
00000000

Rust入門 セットアップ

Bash On Windowsをインストールし直すたびにこれも検索し直しているのは時間がかかって仕方がないのでメモ(2017/12)

WSL上でRust install

$ curl https://sh.rustup.rs -sSf | sh
Current installation options:

   default host triple: x86_64-apple-darwin
     default toolchain: stable
  modify PATH variable: yes

1) Proceed with installation (default)
2) Customize installation
3) Cancel installation

ここではdefaultで、あとで変える。

source $HOME/.cargo/env

を.bashrcにでも.zshrcにでもconfig.fishにでも入れる。

Rust.vimのためにdein.vimを入れる

$ mkdir ~/.cache/dein
$ cd ~/.cache/dein
$ curl https://raw.githubusercontent.com/Shougo/dein.vim/master/bin/installer.sh > installer.sh
$ sh ./installer.sh ~/.cache/dein

.vimrcにRust.vimを追加

" Add or remove your plugins here:
...
call dein#add('rust-lang/rust.vim')

この状態でvimを起動すると、(start時のプラグインチェックが有効になっていれば)
初回起動時に勝手にrust.vimを入れてくれる。

Rust fmtのインストール
だいたいココらへんなのだが
github.com
(nightlyじゃないと動かない?)

$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install build-essential
$ rustup install nightly
$ rustup default nightly
$ cargo install rustfmt-nightly

nightlyをデフォルトにしたくなかったらnightlyのライブラリをインストールしたあとに

export LD_LIBRARY_PATH=$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH

を追加すれば良い気がする。

その後。
.vimrcで

let g:rustfmt_autosave = 1
let g:rustfmt_command = '$HOME/.cargo/bin/rustfmt'

とすれば保存時にフォーマッティングシてくれるらしいが、
:RustFmtを実行すると
シンタックスハイライトが消えてカーソルが下まで降りるという現象になった。

以下のようにすれば良いらしい
github.com
よって
.vimrcは

let g:rustfmt_autosave = 1
let g:rustfmt_command = 'cargo fmt -- '

とした。

rust/vim-racerのインストール
github.com

vimプラグインに追加する。

call dein#add('racer-rust/vim-racer')

補完プログラムインストール

$ cargo install racer

補完のためのソースコードをもらう

$ rustup component add rust-src
$ rustc --print sysroot
$(rustc --print sysroot)/lib/rustlib/src/rust/src

が保存されている場所。
このパスを
bashrcなりzshrcなりのRUST_SRC_PATHとしてexportする。
fishなら

set -gx RUST_SRC_PATH $HOME/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src

のような感じ。

補完したい場所で
insert modeのまま
Ctrl+x -> Ctrl+o
とすると
f:id:katakanan:20171128213137p:plain
補完候補が出る。

WSL(Bash On Windows)を再セットアップ

色々とめんどくさくなったときに再設定するためのメモ

cmd.exeから

オプションなしの削除

>lxrun /uninstall

すべて削除

>lxrun /uninstall /full

最近のWindowsのアップデートでWSLが標準機能になったのでストアからインストール
www.microsoft.com

起動するとroot passwordを設定する。

WSLで
ユーザーの追加 (rootで実行)
(同時にホームディレクトリ作成)

$adduser (new_user)

パスワード設定

$passwd (new_user)

sudoに追加

$usermod -G sudo (new_user)

最後に
cmd.exeから

>ubuntu config --default-user (new_user)

として、ログインユーザーを変更する。

fishをインストールする。
e-tipsmemo.hatenablog.com