「開発スピードと品質の両立実践法」登壇

先日、アイティメディア主催の「開発スピードと品質の両立実践法」というイベントにて、インタビュー形式の基調講演と、パネルディスカッションに登壇させていただきました。
https://itmedia.smartseminar.jp/public/seminar/view/723

イベントのテーマは「品質とスピードを両立するためには」「リリースでトラブルを起こさないためには」といった普遍的なもので、フロントローディングの話、反復開発での計画作りとベロシティ最適化の話、エンジニア個々人が地力を高めていきましょうといった話をさせていただきました。
(企業セミナーではツール、プロセス、具体的なプラクティスと、属人性の少ない手法や技術が多い印象ですので、他の登壇者との差別化として、あえて当たり前というか、忘れてはならない現場の基礎的な話にフォーカスさせていただきました)

なお今回はディスカッションなどでツールベンダやツール導入コンサルのお話も直接聞け、大変有意義な機会となりました。
声をかけていただいたアイティメディア様、またその他開催関係者や参加者の方々に深くお礼申し上げます。

VimでVerilogのコーディング環境を確保

VimにおけるVerilog開発環境については、ここ数年で色々なプラグインが標準サポートしてきた。
整理のために、今回はVerilog関連のプラグインの設定を少しまとめたいと思う。

スニペット

今年になって、neosnippetsがVerilogを標準サポートしている。
neosnippet-snippets/verilog.snip at master · Shougo/neosnippet-snippets · GitHub
そのためNeoBundle等でneosnippetsを入れると、そのままVerilog用のスニペットを利用できるようになる。

構文チェック

Verilogの構文チェックについては、syntasticが少し前から標準サポートしている。
NeoBundleでsyntasticを入れる場合は以下を.vimrcへ。

NeoBundle 'scrooloose/syntastic'

またこのVerilogの構文チェックを有効化するにはVerilatorのインストールが必要になる。
homebrew経由だと以下でインストール。

brew install verilator

なおこのsyntastic & verilatorのサポートは結構強力で、入れた時は最強のVerilogエディター誕生みたいな気分になれる。
以下はファイル保存時に表示される構文チェックの結果例。異常な構文の箇所に「>>」赤文字が、最下部に何が異常かの警告が出る。

f:id:goyoki:20150625220954p:plain

f:id:goyoki:20150625221012p:plain

ブロック間のジャンプ

matchit.vimを有効にすると、そのままbegin〜end、module〜endmoduleなどVerilogのブロック間を%でジャンプできるようになる。またhl_matchit.vimなども普通に動く。
matchit.vimはデフォルトで格納されているので、有効化は.vimrcに以下を挿入すればできる。

:source $VIMRUNTIME/macros/matchit.vim

入力補完

verilog.dict vimrc」などでウェブ検索すると、Verilog固有の辞書ファイルが見つかる。参考にして自作したり、ライセンスの範囲内で流用したりして、neocomplcache・neocompleteなどに登録すれば、Verilogの入力補完ができるようになる。

PyAutoGUIでGUIの自動操作

 PyAutoGUIがシンプルでかなり使いやすかったのでメモ。
 PyAutoGUIは、GUIの自動操作をサポートするPython用ライブラリ。マウス操作、キーボード操作、スクリーンキャプチャ、指定した画像のマッチングと座標取得などの機能を提供する。シンプルだけれど、自動操作に必要な機能がひと通り揃っている。

 使用例として、GUI縛りのツールを自動操作させ、結果が得られたらその画面キャプチャを保存するスクリプトを載せる。

#-*- coding: utf-8 -*-
#run_and_capture.py
import pyautogui, time
from datetime import datetime

# 処理開始ボタンを探してクリックする
position = pyautogui.locateCenterOnScreen('startbutton.png') #startbutton.pngは処理開始ボタンのキャプチャ画像
pyautogui.click(position, duration = 0.2)

nsec = 0
while True:
	posPassInfo = pyautogui.locateOnScreen('pass.png') #pass.pngは成功時表示のキャプチャ画像
	posFailInfo = pyautogui.locateOnScreen('fail.png') #fail.pngは失敗時表示のキャプチャ画像
	if posPassInfo is not None or posFailInfo is not None:
		# 成功あるいは失敗表示を確認できたら、日付名でスクリーンショットを保存
		filename = datetime.now().strftime("%Y%m%d_%H%M%S") + ".png"
		s = pyautogui.screenshot()
		s.save(filename)
		break
	time.sleep(1)
	nsec += 1
	if nsec > 5:
		print("timeout") #処理操作開始後、5s以上経過するまで結果表示を得られなかったらタイムアウトで終了
		break

MPLABシミュレータでのSCLによるソフトウェアの自動操作

MPLABでシミュレータを自動操作する手段にSCL(Stimulus Control Language)のスクリプトがある。
このスクリプトIDEで設定して自動生成することが多いけれど、手書きで作成することも可能だ。

スクリプトの記述力は十分とは言えないものの、ファイル操作・文字列検索のAPIや、標準出力(SimulatorのOutput)を操作するreport()のAPIなど、最低限の機能が揃っている。UARTやテスト用IFがなくとも、シミュレータ上のソフトウェアを自動操作し出力を比較検証することが可能となっており、自動テストにも使えるので、簡単に例をメモ。

記述例

例えばPICで動作するソフトウェアを対象として、UARTでデジタル出力を操作し、その結果を評価するスクリプトならば、以下のようになる。

testbench for "pic12f1822" is
    begin
        process is
            begin
                report("start");
                RCREG <= 16#E2#;
                wait for 10 ms; 
                if RA0 == '1' then
                    report("ra0-0 fail");
                else
                    report("pass");
                end if;
                if RA1 == '0' then
                    report("ra1-1 fail");
                else
                    report("pass");
                end if;
                wait;
        end process;
    end testbench;

また複雑なスクリプトは、MPLABで生成して、手描きで追加編集すると作りやすい。
例えばファイルでリストアップした文字列をUART入力する処理をSCL化すると、以下の様なスクリプトが生成される。
これに「elsif match(〜」の行を追加してオリジナルのイベント命令を追加したり、report()を挿入したりすれば、それなりの自動テストのスクリプトに組み替えられると思う。

〜
        file_open(status_RCREG, data_file_RCREG, "input_data.txt", read_mode);
        if status_RCREG == open_ok then
            while endfile(data_file_RCREG) == false loop
                readline(data_file_RCREG, pkt_line_RCREG);
                // skip empty line and comment line
                if match(pkt_line_RCREG, "") == true then // do nothing
                elsif match(pkt_line_RCREG, "//") == true then // do nothing
                else
                    if match(pkt_line_RCREG, "wait ") == true then
                        read(pkt_line_RCREG, dummy_RCREG); // to consume 'wait' command
                        read(pkt_line_RCREG, waitime_RCREG);
                        wait for waitime_RCREG;
                        new_packet_RCREG := true;
                    elsif match(pkt_line_RCREG, "rand ") == true then
                        read(pkt_line_RCREG, dummy_RCREG); // to consume 'rand' command
                        read(pkt_line_RCREG, rand_lower_RCREG);
                        read(pkt_line_RCREG, rand_upper_RCREG);
                        read(pkt_line_RCREG, rand_unit_RCREG);
                        random_time(rand_lower_RCREG, rand_upper_RCREG, rand_unit_RCREG,
                                    rand_seed1_RCREG, rand_seed2_RCREG, randime_RCREG);
                        wait for randime_RCREG;
                        new_packet_RCREG := true;
                    else
                        if new_packet_RCREG == true then
                            packetin(pkt_line_RCREG, RCREG, false); // new packet
                            wait until RCREG_packet_done;
                            new_packet_RCREG := false;
                        else
                            packetin(pkt_line_RCREG, RCREG, true); // append to previous
                            wait until RCREG_packet_done;
                        end if;
                    end if;
                end if;
            end loop;
        else
            file_close(data_file_RCREG);
            wait;
        end if;
        file_close(data_file_RCREG);
〜

MacSpiceでのLPF回路のシミュレーション

Mac向けのSPICEとしてMacSpiceというものがあるが、これが結構良かったので使い方を簡単にまとめたい。
題材として今回はローパスフィルタ回路のシミュレーションをする。

題材

今回はローパスフィルタ回路として、単純なRC回路とRLC回路を対象に、周波数特性とステップ入力時の動きをシミュレーションする。

回路記述

まずはSPICE用に回路を記述する。
題材用に書いた回路記述は以下。これを「lpf.CIR」として保存する。

ローパスフィルタ評価用
*** circuit definition
** RC LPF
R0 in out 20
C0 out 0 500n
** RLC LPF
* R0 in X 20
* L0 X out 22uH
* C0 out 0 500n
** Vin
Vin in 0 DC 0.0 AC 1.0 0.0 PULSE( 0.0 1.0 1ms )

*** sim commands
.control
* AC analysis
ac dec 50 10Hz 100kHz
echo "$curplot:AC analysis"
* transient analysis
tran 20us 2ms 0ms 20us
echo "$curplot:transient analysis"
.endc
.END

手動になるが、シミュレート時は冒頭の方の「** RC LPF」と「** RLC LPF」のコメントアウトを修正してRC回路かLRC回路かを切り替える。

シミュレーション

以下のコマンドを実行すると、シミューレーションを実行し、結果をグラフとして表示する。

source lpf.CIR
【結果が出力される】
setplot 【AC analysisと表示されたグラフ名ac*を入力】
plot db(out)
setplot 【transient analysisと表示されたグラフ名tran*を入力】

結果

RC回路

f:id:goyoki:20150315173317p:plain

f:id:goyoki:20150315173330p:plain

RLC回路

f:id:goyoki:20150315173606p:plain

f:id:goyoki:20150315173617p:plain

Pythonを使った対数を含む単回帰分析

Pythonでのやや複雑な単回帰分析について。今回は書籍「データ指向のソフトウェア品質マネジメント」を題材にやってみる。Pythonでの記述はを参考にした
分析データとしては、書籍での「テスト工程での不具合検出数の予測」にて提供されているCSVデータを「data.csv」に保存して使用する。

分析内容

分析では、不具合検出に関わるデータの相関性を評価して、不具合数の予測に使える回帰モデルを構築することを目指している。

データの俯瞰と相関性の評価

まずデータを俯瞰した上で、分析対象とするFailures(障害数)とKLOC(テスト対象規模)の相関を評価する。

●グラフ化

グラフで全体の傾向を主観的に把握する。

スクリプト
# -*- coding: utf-8 -*-
import matplotlib.pyplot as plt
import pandas as pd

prj_data = pd.read_csv("data.csv", sep="\t")
# 使用しない行を削除
del prj_data['Prj']
# 欠損を削除
prj_data = prj_data.dropna()

# 散布図で見る
plt.scatter(prj_data['Failures'], prj_data['KLOC'])
plt.show()

# ヒストグラムで見る
plt.figure()
plt.hist(prj_data["Failures"])
plt.xlabel("Failures")
plt.ylabel("Number")
plt.show()
出力

f:id:goyoki:20150304014841p:plain

f:id:goyoki:20150304014835p:plain

●相関係数の評価

相関係数を評価して、正の相関があることを確認する。

スクリプト
〜上の続き〜
print prj_data.corr()
出力
          Failures      KLOC
Failures  1.000000  0.883083
KLOC      0.883083  1.000000

単回帰分析

回帰分析ではデータの分布から推測して、対数を用いた以下のモデルを用いる。
log (Failures) = X * log(KLOC) + Y
対数が含まれるため、文字列で回帰モデルを簡単に記述できるstatsmodelsを使用する。

スクリプト
# -*- coding: utf-8 -*-
import pandas as pd
import numpy as np
import statsmodels.formula.api as sm

prj_data = pd.read_csv("data.csv", sep="\t")
del prj_data['Prj']
prj_data = prj_data.dropna()

result = sm.ols(formula="np.log(Failures) ~ np.log(KLOC)", data=prj_data).fit()

# 概要だけ
print result.params
# 分析データ含めて表示
print result.summary()
出力(paramsの表示)

題材の書籍と概ね同じ値を出力できている。

Intercept       2.460562
np.log(KLOC)    0.956357
dtype: float64
出力(summaryの表示)

P値、R-squaredの値を含め、題材書籍と同じ分析結果になっており、概ね適用可能な回帰モデルとなっていると判断できる。

                            OLS Regression Results                            
==============================================================================
Dep. Variable:       np.log(Failures)   R-squared:                       0.779
Model:                            OLS   Adj. R-squared:                  0.771
Method:                 Least Squares   F-statistic:                     95.38
Date:                Wed, 04 Mar 2015   Prob (F-statistic):           2.35e-10
Time:                        01:40:49   Log-Likelihood:                -29.481
No. Observations:                  29   AIC:                             62.96
Df Residuals:                      27   BIC:                             65.70
Df Model:                           1                                         
Covariance Type:            nonrobust                                         
================================================================================
                   coef    std err          t      P>|t|      [95.0% Conf. Int.]
--------------------------------------------------------------------------------
Intercept        2.4606      0.325      7.578      0.000         1.794     3.127
np.log(KLOC)     0.9564      0.098      9.766      0.000         0.755     1.157
==============================================================================
Omnibus:                        5.037   Durbin-Watson:                   2.194
Prob(Omnibus):                  0.081   Jarque-Bera (JB):                1.856
Skew:                          -0.181   Prob(JB):                        0.395
Kurtosis:                       1.815   Cond. No.                         9.02
==============================================================================

クラシフィケーションツリー法入門

先日、WACATE2014冬というテストの合宿勉強会にて、テスト設計手法の一つであるクラシフィケーションツリー法を解説させていただきました。

クラシフィケーションツリー法は国内ではあまり知られていない手法であるものの、割と汎用的で気軽に使える手法です。例えば、組み合わせテストで因子水準の洗い出しに使う、マインドマップでテストを考える際の手順として参考にする、といった場面で有効になります。
今回の資料が、あまり知られていない現状の改善の一助になれば幸いです。