Raspberry pi 3 にシリアルで接続できるようにしてみる
Raspberry PiからでているHDMIとUSBキーボードのケーブルが邪魔なので、シリアル接続できるようにしてみる。
ちょうど他の用途で、3.3VのUSBシリアル変換基板を買っていたので流用する。
FT231X USBシリアル変換モジュール: 半導体 秋月電子通商 電子部品 ネット通販
Physical Computing Labでかったラズパイには丁寧にもGPIOカードなるものが付属してくるので、この図面通りにRX、TX、GNDを接続する。
Macには事前にUSBシリアル変換チップのドライバを入れておく。
Virtual COM Port Drivers
MacのTerminalからscreenコマンドでつないでみるが、つながらない。。。なぜだ?
ググると、古いファームだとシリアル接続にバグがあるらしい。apt-get upgradeでプログラムを、rpi-updateでファームの最新にしろと書いていあるので、その通りにしてみる。(rpi-updateはデフォルトではインストールされていないのでapt-getで入れる)
UART for Serial Console or HAT on Raspberry Pi 3 - Hackster.io
バージョンはLinux Raspberry 4.1.19-v7から4.4.7-v7にあがった。
あと、/boot/config.txtにenable_uart=1を追記しろとのことなのでこれもやってみたところ、無事にシリアルで接続できるようになった。
UnixBenchでいろいろベンチマーク(さくらVPS、raspberry pi 3、ローカルPC)
使える計算機環境が増えたのでそれぞれのベンチマークをとってみる。
ベンチマークソフトはUnixBenchを使う。
さくらVPS
Ubuntuをインストールしてあるので、aptでビルド環境を入れた後、UnixBenchをビルドして使う。
ビルドツールを入れる。
$ sudo apt-get update $ sudo apt-get install build-essential
UnixBenchはGitHubで公開されているので取ってこれるようにgitツールも入れる。
$sudo apt-get install git
git cloneする
$ mkdir unixbench $ cd unixbench $ git clone https://github.com/kdlucas/byte-unixbench.git .
あとはRunするだけで、必要なソースコードのビルドからベンチマークの実行までやってくれる。
$ cd UnixBench $ ./Run
raspberry pi 3
Raspberry pi 3、まずはOSのインストールから。
OSイメージを下記のページからダウンロードする。
https://www.raspberrypi.org/downloads/raspbian/
RasbianかUbuntu MATEか迷ったけれど、まずはスタンダードなRasbianを入れてみた。
RasbianもDebian系なのでコマンドラインから使う分にはUbuntuと同じような使い勝手なはず。
イメージは最小構成の方を選択。RASPBIAN JESSIE LITE。
イメージの焼き方は
https://www.raspberrypi.org/documentation/installation/installing-images/mac.md
diskutilでSDカードのデバイス名を確認して、(dfでもいいけど)
$ diskutil list /dev/disk3 (internal, physical): #: TYPE NAME SIZE IDENTIFIER 0: FDisk_partition_scheme *1.1 GB disk3 1: Windows_FAT_32 SERVICEV001 75.5 MB disk3s1 2: Linux 998.2 MB disk3s2
マウントされている場合はアンマウントして、
diskutil unmount /dev/disk3s1
ddでイメージを書き込む
$ sudo dd bs=1m of=/dev/disk3 if=/Users/shizuku/Downloads/2016-03-18-raspbian-jessie-lite.img
途中で進捗が見たい場合は、ctrl-Tでddにシグナルを送ると教えてくれる。
書き込むサイズはraspbain-jessie-liteで1.3GBとちょっと。
起動させるとlite版なのでGUIではなくCUIで起動。
デフォルトで用意されているpiユーザでログイン。
TIMEZONEとキーボードレイアウトを変更するためにraspi-configのInternationalisation Optionsを実行。当面は日本語フォントを入れるつもりはないのでLOCALEはCにしておく。
SDカードの全領域を使えるように、rasps-configのExpand Filesystemを実行。
あとは、いつもどおりapt-getで必要なツール群をインストールした後で、UnixBenchをとってきて、Run。raspbian jessie liteのイメージの場合、すでにbuild-essentialはインストールされていた。ので、gitだけapt-get installしてこればOK。
ローカルPC (MacBook Air, Mid 2011)
MacOSでも同じようにUnixBenchをgitから取得して実行してみる。
Runを実行すると、ビルドはうまくいってベンチマークもはじまるものの、途中で下記のエラーがでて中断してしまった。
Run: "Pipe-based Context Switching": slave read failed: Invalid argument; aborting
ちょっとググったら、パッチが提供されていることが分かったので、もらってきてあててみる。
https://gist.github.com/barusan/11033924
UnixBench5.1.3.mavericks.patch
$ cd UnixBench $ ~/download/UnixBench5.1.3.mavericks.patch . $ patch -p1 < UnixBench5.1.3.mavericks.patch $ make clean $ make $ ./Run
UnixBenchの結果の比較
こんな感じの結果になった。(single)はシングルコア向けテストの結果。(multi)はマルチコア向け。
さくらVPSのXeon E5-2650とMacBook AirのCore i5-2557Mは同じSandy Bridge世代だけど、さすがにサーバ向けCPUは早い。
raspberry pi 3 は4コアフルに使って、Corei5-2557Mの1コア。ただ、raspiは消費電力が最大で12.5Wってことを考えるとかなり頑張っている。
spec | raspi 3 | MacBook Air (Mid 2011) | SAKURA VPS |
---|---|---|---|
CPU | ARM Cortex-A53 @ 1.2GHz | Intel Core i5-2557M @ 1.7GHz | Xeon CPU E5-2650 v2 @ 2.60GHz |
num of cores | 4 | 2 (HT) | 2 |
RAM | 1GB | 4GB | 1GB |
Main Storage | SDカード | SSD | SSD |
OS | Raspbian 4.1.19 | OS X 10.11.4 (EI Capitan) | Ubuntu 14.04.4 LTS |
参考
個々のベンチマーク結果は下記。
さくらVPS
さくらVPSを契約してみた。お試し期間2週間。
CPU 2コア、メモリ 1GB、SSD 30GB で月980円。
契約後、早速インスタンスを起動してみたけれど、なぜかsshで接続ができない。
さくらVPSの管理サイトからVNCコンソールで接続してログを見てみると、起動途中でカーネルパニックを起こしている様子。。。なんで?
仕方がないので、OSの再インストールをしてみた。せっかくだから慣れてるUbuntuをインストール。(さくらVPNのデフォルトはCentOS)
インストール手順はかなり詳しく説明があるので迷わずできた。
https://help.sakura.ad.jp/app/answers/detail/a_id/2403
さあ、まともに動作するようになるかな?
WekaをMacで使うための環境構築
「体験する機械学習」で説明されている内容をMac環境で実行するために準備したことをメモしておく。
http://www.amazon.co.jp/dp/B018VAV29I/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1
wekaの設定
wekaでutf-8形式のファイルが読み込めるようにする。
http://qiita.com/yuichy/items/8031dd7603964ed817f3
gccのかわりにclangを使ってみる
clangの場合、ライブラリ系がどうな感じになるか気になったので調べてみた。
ubuntu環境にclangをインストールする。
sudo apt-get install clang
標準Cライブラリを使うようなCプログラムをgccとclangでコンパイルしてみる。
#include <stdio.h> #include <string.h> int main(int argc, char* argv[]){ const char *hello = "hello"; char buff[128]; memset(buff, 0, sizeof(buff)); sprintf(buff, "%s,%s.", hello, argv[1]); printf("%s\n", buff); return 0; }
$ gcc -o hello_by_gcc hello.c $ clang -o hello_by_clang hello.c
サイズを比べてみる。ちょっとだけちがう。
$ ls -al hello_* -rwxrwxr-x 1 8647 Apr 1 00:50 hello_by_clang -rwxrwxr-x 1 8871 Apr 1 00:47 hello_by_gcc
リンクされている標準ライブラリを見てみる。どちらも同じ。glibc。clang独自で標準Cライブラリを持っているわけではないらしい。
$ ldd hello_by_gcc linux-vdso.so.1 => (0x00007fff40b3e000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5c5c0e2000) /lib64/ld-linux-x86-64.so.2 (0x00007f5c5c4b1000) $ ldd hello_by_clang linux-vdso.so.1 => (0x00007fff1cbff000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0bafa33000) /lib64/ld-linux-x86-64.so.2 (0x00007f0bafe02000)
C++でも試したみたが、参照する標準C++ライブラリも一緒。
#include <iostream> using namespace std; int main(int argc, char* argv[]) { cout << "Hello, " << argv[1] << endl; return 0; }
$ g++ -o hello_cpp_by_g++ ./hello.cpp $ clang++ -o hello_cpp_by_clang++ ./hello.cpp $ ldd ./hello_cpp_by_g++ linux-vdso.so.1 => (0x00007fff4a7ff000) libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f8b56237000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8b55e77000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f8b55b7a000) /lib64/ld-linux-x86-64.so.2 (0x00007f8b56549000) libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f8b55964000) $ ldd ./hello_cpp_by_clang++ linux-vdso.so.1 => (0x00007fff9892e000) libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f82ec798000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f82ec3d8000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f82ec0db000) /lib64/ld-linux-x86-64.so.2 (0x00007f82ecaaa000) libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f82ebec5000)
gdbでデバッグ 〜stripとか-gオプションとか〜
gオプションをつけると生成されるバイナリにデバッグ情報が付加される。デバッグ情報とは、ソースコードへのパスやソースコード上の行番号。gdb上で行単位で実行をトレースすることができるようになる。
gオプションがないとgdbでデバッグできないわけではない、ただ表示される情報がシンボル単位になるだけ。
オブジェクトのシンボル情報は、リンクした後は削除することができる。stripコマンドを使ったり、-Wl,-sオプション付きでリンカをうごかしたりするとシンボルが削除される。オブジェクトファイルのサイズを縮小する目的で行われるが、これらのオブジェクトをgdbでデバッグしようとすると、表示される情報がライブラリ単位にまでさがる。
stripは実行形式のファイルに対して通常行うが、リンクする前のオブジェクトファイルに対しても行うことができる。ただ、リンクに必要なシンボル情報まで消えてしまうため、まともにリンクができなくなる。
stripをかけた後の実行形式ファイルにおいてもシンボルが全くなくなるわけではない。動的リンクに必要なシンボル情報は削除されずに残る。
usethread.c
#include <pthread.h> #include <unistd.h> #include <stdio.h> void* thread_func(void *param){ printf("start thread\n"); sleep(10); printf("end thread\n"); } void start_thread(){ pthread_t thread; pthread_create(&thread, NULL, thread_func, NULL); pthread_join(thread, NULL); } int main(void){ start_thread(); return 0; }
strip版
quetzal:~/binary$ readelf -s usethread_strip Symbol table '.dynsym' contains 8 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND pthread_create@GLIBC_2.2.5 (2) 2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.2.5 (3) 3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (3) 4: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND pthread_join@GLIBC_2.2.5 (2) 6: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND sleep@GLIBC_2.2.5 (3)
オリジナル版
quetzal:~/binary$ readelf -s usethread Symbol table '.dynsym' contains 8 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND pthread_create@GLIBC_2.2.5 (2) 2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.2.5 (3) 3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (3) 4: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND pthread_join@GLIBC_2.2.5 (2) 6: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND sleep@GLIBC_2.2.5 (3) Symbol table '.symtab' contains 78 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000400238 0 SECTION LOCAL DEFAULT 1 2: 0000000000400254 0 SECTION LOCAL DEFAULT 2 3: 0000000000400274 0 SECTION LOCAL DEFAULT 3 4: 0000000000400298 0 SECTION LOCAL DEFAULT 4 5: 00000000004002b8 0 SECTION LOCAL DEFAULT 5 6: 0000000000400378 0 SECTION LOCAL DEFAULT 6 7: 00000000004003fc 0 SECTION LOCAL DEFAULT 7 8: 0000000000400410 0 SECTION LOCAL DEFAULT 8 9: 0000000000400450 0 SECTION LOCAL DEFAULT 9 10: 0000000000400468 0 SECTION LOCAL DEFAULT 10 11: 00000000004004e0 0 SECTION LOCAL DEFAULT 11 12: 00000000004004f0 0 SECTION LOCAL DEFAULT 12 13: 0000000000400550 0 SECTION LOCAL DEFAULT 13 14: 0000000000400774 0 SECTION LOCAL DEFAULT 14 15: 0000000000400780 0 SECTION LOCAL DEFAULT 15 16: 00000000004007a0 0 SECTION LOCAL DEFAULT 16 17: 00000000004007e0 0 SECTION LOCAL DEFAULT 17 18: 0000000000600e00 0 SECTION LOCAL DEFAULT 18 19: 0000000000600e08 0 SECTION LOCAL DEFAULT 19 20: 0000000000600e10 0 SECTION LOCAL DEFAULT 20 21: 0000000000600e18 0 SECTION LOCAL DEFAULT 21 22: 0000000000600ff8 0 SECTION LOCAL DEFAULT 22 23: 0000000000601000 0 SECTION LOCAL DEFAULT 23 24: 0000000000601040 0 SECTION LOCAL DEFAULT 24 25: 0000000000601050 0 SECTION LOCAL DEFAULT 25 26: 0000000000000000 0 SECTION LOCAL DEFAULT 26 27: 0000000000000000 0 SECTION LOCAL DEFAULT 27 28: 0000000000000000 0 SECTION LOCAL DEFAULT 28 29: 0000000000000000 0 SECTION LOCAL DEFAULT 29 30: 0000000000000000 0 SECTION LOCAL DEFAULT 30 31: 0000000000000000 0 SECTION LOCAL DEFAULT 31 32: 0000000000000000 0 SECTION LOCAL DEFAULT 32 33: 0000000000000000 0 FILE LOCAL DEFAULT ABS /usr/lib/gcc/x86_64-linux 34: 000000000040057c 0 FUNC LOCAL DEFAULT 13 call_gmon_start 35: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c 36: 0000000000600e10 0 OBJECT LOCAL DEFAULT 20 __JCR_LIST__ 37: 00000000004005a0 0 FUNC LOCAL DEFAULT 13 deregister_tm_clones 38: 00000000004005d0 0 FUNC LOCAL DEFAULT 13 register_tm_clones 39: 0000000000400610 0 FUNC LOCAL DEFAULT 13 __do_global_dtors_aux 40: 0000000000601050 1 OBJECT LOCAL DEFAULT 25 completed.6744 41: 0000000000600e08 0 OBJECT LOCAL DEFAULT 19 __do_global_dtors_aux_fin 42: 0000000000400630 0 FUNC LOCAL DEFAULT 13 frame_dummy 43: 0000000000600e00 0 OBJECT LOCAL DEFAULT 18 __frame_dummy_init_array_ 44: 0000000000000000 0 FILE LOCAL DEFAULT ABS usethread.c 45: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c 46: 00000000004008c0 0 OBJECT LOCAL DEFAULT 17 __FRAME_END__ 47: 0000000000600e10 0 OBJECT LOCAL DEFAULT 20 __JCR_END__ 48: 0000000000000000 0 FILE LOCAL DEFAULT ABS 49: 0000000000600e08 0 NOTYPE LOCAL DEFAULT 18 __init_array_end 50: 0000000000600e18 0 OBJECT LOCAL DEFAULT 21 _DYNAMIC 51: 0000000000600e00 0 NOTYPE LOCAL DEFAULT 18 __init_array_start 52: 0000000000601000 0 OBJECT LOCAL DEFAULT 23 _GLOBAL_OFFSET_TABLE_ 53: 0000000000400770 2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini 54: 0000000000000000 0 FUNC GLOBAL DEFAULT UND pthread_create@@GLIBC_2.2 55: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab 56: 0000000000601040 0 NOTYPE WEAK DEFAULT 24 data_start 57: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@@GLIBC_2.2.5 58: 0000000000601050 0 NOTYPE GLOBAL DEFAULT 24 _edata 59: 0000000000400774 0 FUNC GLOBAL DEFAULT 14 _fini 60: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_ 61: 0000000000400688 54 FUNC GLOBAL DEFAULT 13 start_thread 62: 0000000000601040 0 NOTYPE GLOBAL DEFAULT 24 __data_start 63: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 64: 0000000000601048 0 OBJECT GLOBAL HIDDEN 24 __dso_handle 65: 0000000000400780 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used 66: 00000000004006e0 137 FUNC GLOBAL DEFAULT 13 __libc_csu_init 67: 0000000000601058 0 NOTYPE GLOBAL DEFAULT 25 _end 68: 0000000000400550 0 FUNC GLOBAL DEFAULT 13 _start 69: 000000000040065c 44 FUNC GLOBAL DEFAULT 13 thread_func 70: 0000000000601050 0 NOTYPE GLOBAL DEFAULT 25 __bss_start 71: 00000000004006be 21 FUNC GLOBAL DEFAULT 13 main 72: 0000000000000000 0 FUNC GLOBAL DEFAULT UND pthread_join@@GLIBC_2.2.5 73: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses 74: 0000000000601050 0 OBJECT GLOBAL HIDDEN 24 __TMC_END__ 75: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable 76: 0000000000000000 0 FUNC GLOBAL DEFAULT UND sleep@@GLIBC_2.2.5 77: 00000000004004e0 0 FUNC GLOBAL DEFAULT 11 _init
リンクする前にオブジェクトからシンボルを削除すると、リンクできなくなる。
quetzal:~/binary$ gcc -c usethread.c -o usethread.obj -g quetzal:~/binary$ strip usethread.obj quetzal:~/binary$ readelf -s usethread.obj quetzal:~/binary$ gcc -o usethread usethread.obj -lpthread /usr/bin/ld: error in usethread.obj(.eh_frame); no .eh_frame_hdr table will be created. /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 0 has invalid symbol index 10 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 1 has invalid symbol index 11 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 2 has invalid symbol index 2 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 3 has invalid symbol index 2 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 4 has invalid symbol index 10 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 5 has invalid symbol index 12 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 6 has invalid symbol index 12 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 7 has invalid symbol index 12 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 8 has invalid symbol index 2 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 9 has invalid symbol index 2 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 10 has invalid symbol index 11 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 11 has invalid symbol index 12 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 12 has invalid symbol index 12 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 13 has invalid symbol index 12 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 14 has invalid symbol index 12 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 15 has invalid symbol index 12 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 16 has invalid symbol index 12 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 17 has invalid symbol index 12 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 18 has invalid symbol index 12 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 19 has invalid symbol index 12 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_info): relocation 20 has invalid symbol index 20 /usr/bin/ld: /usr/lib/debug/usr/lib/x86_64-linux-gnu/crt1.o(.debug_line): relocation 0 has invalid symbol index 2 /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../x86_64-linux-gnu/crt1.o: In function `_start': (.text+0x20): undefined reference to `main' collect2: error: ld returned 1 exit status