Code Day's Night

ichikawayのブログ

Mac miniの温度を気にする人生に疲れてしまったので本気出す!

2019年に買ったMac miniはメモリ32GでCPUも高速で最高なのですが、唯一発熱の問題があってクーラーが効いた部屋でも結構熱くなります。

定期的にMac miniに触れて温度を確かめたりしてたのですが、それに疲れてしまったので解決することにしました。
検索すると、100円ショップの小さいメタルラックに載せてファンをあてる、という記事がたくさんでてきますが、見た目よくないし、場所取りすぎなのでとりあえずファンだけで試しました。

 

 

 買ったのはこちら。ファンは大きい方が静かなので12cm、2つあればかなり冷える、そして回転数が3段階調整できるのでこれにしました。2300円。

 

f:id:ichikaway:20200702191019j:plain

見た目はともかく、発熱の問題は解決しました!
もっと早く導入すれば良かった。

 

ファンは2つあった方が良いかと思いましたが、たぶん1つで十分だと思います。
これであれば1600円と安く、回転数も調整できるので良いかと。 

 

見た目の問題は隠せばなんとか・・w

f:id:ichikaway:20200702195510j:plain

 

gitでリモートのブランチをローカルにcheckoutする簡単な方法

結論から書くと、

git fetch
git checkout foo

これでorigin/fooのブランチがローカルにチェックアウトできます。

今までは、

git fetch
git checkout origin/foo
git checkout -b foo

というのをしていました。下記の方法の方がスタンダードかもしれません。

git checkout -b foo origin/foo

これでもfooという文字が冗長だし面倒だなと思っていたら、DQNEOさんが解決策を教えてくれました。ありがとうございました!

x86アセンブリで数字を画面表示するだけの実装が大変だった

最近お気に入りの低レイヤーガールというYoutubeチャンネルで、アセンブリでFizzBuzzを書くというのを見て自分でも実践してみました。

Youtube: FizzBuzzをアセンブリ言語で書きたい!

x86アセンブリで画面表示するには、writeのsyscallを呼び出して、標準出力に文字列のアドレスを渡せばできます。 具体的には、次のように第3引数までレジスタにセットしてsyscallを呼び出すだけです。

    mov rax, 0x1   #syscall番号
    mov rdi, 0x1   #第1引数 fd
    lea rsi, [foo]   #第2引数 文字列のアドレス
    mov rdx, 0x03   #第3引数 文字数
    syscall

raxに0x01を入れていますがこれがシステムコール番号です。 システムコールの番号と引数のレジスタの一覧表があるのでこれを見るとわかりやすいです。
LINUX SYSTEM CALL TABLE FOR X86 64

数字が・・出ない

さてFizzBuzzの文字列を出すまでは良かったのですが、試しにループしている箇所のカウンタ(rcxレジスタ)の数字を画面に出力してみるかと、rcxに入っている値を適当なメモリアドレスに入れて同じようにwriteのsyscallを呼んでみました。

結果は・・何も数字が出力されず。

色々とデバッグして辿り着いたのは、カウンタの数字(例えば3)が入ったメモリアドレスをwriteのsyscallに渡すと、charとして扱われて、0x03のAsciiコードとして画面出力に使われてたのでした。Asciiコードの0x00から0x20までは制御文字のためどれも画面に何も出力されません。。

試しに、カウンタの数字に0x30(これは文字列のゼロ)を足して表示させると、ちゃんと数字が表示されました。

長い道のり

さて、0x30を数字に足せばちゃんと数字の文字列が画面にでるところまではいけました。
問題は、2桁以上の数の場合です。例えば、16という整数を画面に表示する場合は1と6の2文字のcharとして画面表示する必要があります。そして、最初に上の桁の1を表示するという順序も重要になります。

ここまでくると、一般的な高級言語で実装されている数字を画面表示するという機能がアセンブリでは果てしなく遠いものに見えてきます。 PHPのecho()にも感謝の気持ちが湧いてくるのです。

itoaを実装するか

整数を文字列に変換する関数としてitoa()がありますが、これと同じようなことをx86アセンブリで実装しました。 やるべきことは次の通り。

  • 1桁目の数字を抜き出してAscii変換して文字にしてスタックにpush
  • 2桁目の数字を抜き出して同じことをする。これを全ての桁が終わるまで繰り返す
  • スタックに積み終わったら、popしながらメモリのアドレスに順にいれていく
  • そのメモリアドレスの先頭アドレスをwriteのsyscall の第2引数に渡す

数字を1桁ずつ抜き出すのは、div命令で割り算をして余りを使うことです。
商は残った桁数の数字のため、商が0になるまで繰り返します。
Asciiコード変換は0x30を足すか、OR命令を使うかです。(or rdx, 0x30)

感想

楽しかった!
趣味の時間なので、GDBでデバッグしたり、ロジック考えたり、期限がないので悩んでる時間も楽しかったです。

今回作ったプログラムがこちらです。
https://github.com/ichikaway/assembler-sample/blob/master/fizzbuzz/fizzbuzz.s#L69

echocount:
    push rbp
    mov rbp, rsp

    mov r13, 0 #数字の桁数
    push [nullbyte]
    mov r11, rcx

    echocount_div_again:
    # カウンタの数字の下位の桁から数字文字列変換してスタックに積む
    inc r13
    mov rdx,0 #割られる上位
    mov rax, r11 #割られる下位
    mov r12, 10 #割る数
    div r12
    mov r11, rax #商 rax
    or rdx, 0x30 #余りrdxの数字をascii文字の数字に変換
    push rdx 
    cmp rax, 0 #商 rax がゼロでなければまだ桁が残っているためループする
    jne echocount_div_again

    # nullbyteがくるまでpopして数字を文字列に変換してstr変数のアドレスにいれていく
    mov r10, 0
    echocount_pop_loop:
    pop r12
    mov [str+r10], r12 # 文字列を格納するアドレス、配列のため1文字ずつアドレスを上げていく
    inc r10
    cmp r12, [nullbyte]
    jne echocount_pop_loop

    #print
    mov rdi, r13 #文字数
    lea rsi, [str]
    call put

    mov rsp, rbp
    pop rbp
    ret

任天堂スイッチのマインクラフトをサーバに繋ぐ方法

任天堂スイッチのマイクラをネットを使ってサーバに繋ぐのに苦労したため、やり方を書いておきます。親のアカウントだけであれば問題ないですが、子供の任天堂アカウントを繋ぐのに苦労した時の解決方法です。

  1. 任天堂のスイッチオンラインに加入(複数人で使うならFamilyプランがお得)
  2. 子供の任天堂アカウントを作成してスイッチのローカルアカウントに紐付け
  3. 親のマイクロソフトアカウントを作成(年齢を20才以上にする)
  4. 子供のマイクロソフトアカウントを作成し親のアカウント配下にする
  5. 親のマイクロソフトアカウントから、子供のマイクロソフトアカウントのPrivacy設定でマルチプレイを許可する
  6. マイクラの起動画面からログインを選択し、出てきたURLにPCのブラウザからアクセスして子供のマイクロソフトアカウントでログインする

任天堂アカウント

1と2をすると基本的にはスイッチのネットワークが利用できるようになります。例えばどうぶつの森で他の人の島に遊びに行くとか。

マイクラで重要なのは、マイクロソフトアカウントが必須でこれは任天堂のアカウントとは全く別物なので注意すること。


子供用マイクロソフトアカウントの問題

マイクロソフトアカウントを作成する際に生年月日を入れますが、子供のアカウントを作成する際に本当の生年月日を入れると子供用アカウントとなり、そのアカウントからはPrivacy設定ができないこと。
私は最初に親のアカウントの配下に子供アカウントを置かず、子供アカウント単体でマイクロソフトにログインして設定画面を探しましたが、それだと永久に設定画面が出ずに、betaなんちゃらというURLにリダイレクトされます。


一番重要なポイント

親のマイクロソフトアカウントに子供のアカウントを紐付けて、親のアカウントからPrivacy設定をするのが重要なポイントです。もしすでに子供のマイクロソフトアカウントを作ってしまっても、後から親のアカウントの配下にできます。

Privacy設定は、この記事がわかりやすいです。

スイッチのマイクラで特集サーバーに入って遊ぶ方法【かなり苦労した・・・】|一路庵 BLOG

Stripeのクレジットカード入力フォームで郵便番号入力を不要にする

stripe.jsを使ったフォームを構築すると、例えばVISAのカード番号を入力した時に動的に郵便番号フィールドがでてきて、そこも必須入力欄となる。

この場合、下記のようにstripe.elements()のelements.create()のオプションに、
hidePostalCode trueを渡すと郵便番号欄はでなくなる。

var card = elements.create('card', {style: style, hidePostalCode: true});

 

このドキュメントのcardタイプのオプション指定欄に説明がある。
https://stripe.com/docs/stripe-js/reference#elements-create

 

ここにstripeのエレメントサンプル画面とコード例がある
https://stripe.dev/elements-examples/

PHPerKaigi2019で自作ファミコンエミュレータの話をしてきたら最高だった(前編)

PHPerKaigi2019で登壇してきました。全体の感想などは後編に書きます。

カンファレンスで発表するのは3年ぶりぐらい。今回はPHPのファミコンエミュレータ実装をGolangで写経してた時の話をしてきました。

 

ファミコンエミュレータはPHPやGolang, Rustなどたくさんの実装があり、厳密に決まってるCPUやメモリの仕様を元に実装されてます。その実装を通してコンピュータアーキテクチャの理解が進む、低レイヤーの入り口に立てる、という柱を立てて発表しました。PHPで読めて、コンピュータアーキテクチャが学べるって最高じゃないですか?

www.slideshare.net

 

登壇後は、ファミコンエミュレータに興味を持った、作ってみたいというフィードバックを頂きました。今回の発表のゴールに到達できたかと思います。

 

議論や交流が活発、これがPHPerKaigiだ!

PHPerKaigiでは、登壇後も別のホールで椅子に座って、質問やフィードバックがあれば気軽に話にいけるAsk the Speakerというシステムがあり、そこでファミコンのソフトを作ってたさっぴーさんとお話できました。

土曜日の懇親会(茶会)では、これまたファミコンのソフト制作に関わっていた郡山さんの昔話が聞けたり、それを起点にkoyhogeさんの昔話も聞けたり、最高の体験になりました。

ファミコンのソフト作ってた人が二人も会場にいるって、考えるとすごいですね。

 

PHPerKaigiは、正しいこと、完璧なことを一方的に話して終わる場ではなく、議論や交流ができることが重要というスタイルになっているので、発表者としては非常にありがたい場になります。たとえ間違ったところがあったとしても、それは問題ではなく、その後に議論ができて正しくなれば良いだけなのです。最高ですね。

そもそも、この内容で応募する時点で、私より詳しいPHPのファミコンエミュレータ作者がいるのがわかってますし、マイコンやアセンブラをバリバリやってたという方もちらほらいるので、発表するまですごく不安でしたが、発表することで私より詳しい人から色々なお話がきけて、それが共有できるのであれば、こんな素晴らしいことはありませんね。

 

登壇後も、Twitterでここがちょっと間違ってるよというツイートもありました。

色々な知見をいただけて最高でした。 
(エミュレータを作り始めた頃はハードウェアの知識がなさすぎて、このような意見をもらっても理解できなかったかもしれない)

 

スカイラブハリケーン

もう一つ、最高な体験がありました。

私の後のセッションで、 @DQNEO さんが「コンパイラ作りの魅力を語る」という話をしていました。

コンパイラ作りの魅力を語る by DQNEO | プロポーザル | PHPerKaigi 2019 - fortee.jp

私が作ってるファミコンエミュレータはGo言語で実装しています。@DQNEOさんは自作のGoコンパイラを書いてます。もうわかりますね?

懇親会で @DQNEOさんから、彼のコンパイラで私のファミコンエミュレータをコンパイルして動かしてみましょう、という夢の提案がありました。熱い!

 内部でパッケージを分けてたため、残念ながらうまくコンパイルできませんでした。まだそこが未実装だったためです。今後、そこが実装されたら動きそうなのでワクワクしますね。

こんな素敵なコラボレーションがあるとは、もう大興奮ですね。

 進捗がありました!

 

前編のまとめ

PHPerKaigiでは、議論や交流の場がうまく設けられていて、発表者としては最高の体験ができました。

私は低レイヤーの知識が乏しく、ファミコンエミュレータだって移植してみただけで、完全に理解している状態ではありませんでした。ですので登壇するまでは不安で、何度もスライド変えたり発表リハーサルしたりしました。

いま思うのは、完璧な状態や強い状態になってから登壇するよりも、ある程度の知見や経験がたまり、伝えたいという想いがあれば、とにかくピッチに立つことが大事なんだなと感じます。とくにPHPerKaigiのようなスタイルのカンファレンスには。

もし来年PHPerKaigi2020があるのであれば、絶対に登壇者応募するのをオススメします。

後半へつづく・・

 

URLにアンカーの#(シャープ)がある場合に送信されるGETリクエスト

URLに含まれる#(シャープ)は、ページ内リンクアンカー、ハッシュ、フラグメントなどの名称があるが、#が入る場合のGETリクエストはどのようになっているか。

例えば

http://example.com/foo/bar/#/1

というようなURLにGETリクエストする場合、ブラウザは#以降の文字列を付けずに

GET /foo/bar/

というURLパスでリクエストを送る。

#以降の文字列はレスポンス取得後にJavaScriptやブラウザが使うものとして扱われる。

 

curlコマンドで上記のようなURLにリクエストを送信し、tcpdumpして確認。

tcpdump -A dst host xxx.xxx.xxx.xxx

 

なるほどわからない!と実装を繰り返して楽しむ自作ファミコンエミュレータの世界

最近、趣味でファミコンエミュレータをGo言語で実装しています。

github.com

 

世の中にはたくさんのファミコンエミュレータ実装があり、golangだけでもいくつもあるため何で同じ言語で実装するのかと言われると、楽しそうだからとしか言いようがありませんが、趣味の話なので気にしないようにしましょう :)

私は下記のPHP実装のファミコンエミュレータを読んで、PHPなら読める・・読めるぞ!と思って写経しています。せっかくなので勉強し始めたgolangで実装をしています。

www.hasegawa-tomoki.com

 

ここ1ヶ月ぐらい、毎朝20分ほどファミコンの仕様を読みつつPHPのコードを読みつつgolangに移植しているのですが、まだHello Worldが出力できていませんw

そんな時間のかかるHello Worldですが、そこにたどり着くまでにファミコンのROMデータのロード、CPU命令の実装、PPU命令の実装までをやる必要があります。気の遠くなる話ですね・・だが楽しい! プラモデルを毎日コツコツ作っている感覚です。

 

今はPHP実装をgolangに移植してるのですが、PHPの場合は8bit intでも16bit intでもすべてint型になっています。そのため細かい型のところや、書いている内容がわからない場合は他の言語実装も読みます。一番読んでるのはRust実装のこれです。

github.com

 

Rustの文法は知らないし、コードも読んだことなかったのですが、問題なく読めました。ファミコンエミュレータに使われるコードはビットの演算やデータの管理(クラス・構造体)、バイト列の操作、条件分岐がメインになるため基本的な言語文法のみが使われているためです。

ちなみに、ファミコンは海外ではNESと呼ばれていますので、検索する場合はNES Emulator というキーワードを組み合わせると便利です。

 

golangで書いてても使っているのは、構造体、レシーバ、ビット演算、条件分岐、byte操作ぐらいです。ですので、新しいプログラミング言語を覚えるのにファミコンエミュレータを実装するのは良い練習になります。

CPUやメモリのこと、アセンブラのこと、写経しながらこれらも学んでいけますので、ハードに近い場所での操作がどうなっているか体験できるのは面白いですね。いままでアセンブラとか避けてきていたので・・

 

Hello Worldを出力するまでは、まずはこの記事を読むべしという感じです。

qiita.com

私はもう何回も読んで、毎回、なるほどわからん!って感じを繰り返してます。 今はプリンタで印刷してカバンにいれて暇な時に読んでます。
それでもわからないまま写経しながら実装してると、だんだんとわからん!の範囲が小さくなっていきます。この感覚は楽しいですね。

1ヶ月以上も実装しつつ、わからないことが多いですが、最近このように分からないものに長い時間をかけて挑戦することがしたくて、ファミコンエミュレータは良い題材となってます。

 

dockerコマンドでよく使うもの amazonlinuxベース

普段はdocker-composeで操作していても、たまに使い捨てコンテナを扱いたい時がある。
そんな時にdockerコマンドだけで済ませる方法。
dockerイメージの作成、コンテナ起動、コンテナのシェル操作、コンテナ削除の説明。

Dockerfile

amazonlinuxの最新を取得して、最低限のコマンドを入れる

FROM amazonlinux:latest

RUN yum update -y && yum install -y \
less \
procps \
net-tools 

build

Dockerfileを置いて、それを元にタグ名 ichi/awslinux を起動

docker build -t ichi/awslinux:1.0 .

コンテナ起動

nameオプションでコンテナの名前をつける。 最後にプロセスが終了しないようにtail -fを使ってコンテナを起動し続ける。

docker run -d --name ichi-awstest ichi/awslinux:1.0  tail -f /dev/null

docker ps

動いているコンテナを表示するには、 docker ps を使う。
ビルドして動作していない、もしくは動作終了したコンテナまで表示するには docker ps -a を使う。

コンテナにログイン

コンテナ名を指定してbashを起動する。これでコンテナの中のシェルが操作できる。

docker exec -it ichi-awstest bash

コンテナ削除

コンテナを停止し、docker rmでコンテナ削除。 image rmでビルドしたイメージを削除。

docker stop ichi-awstest
docker rm ichi-awstest
docker images
docker image rm ichi/awslinux:1.0

Dockerfileを使わない場合

docker pull node:8.9.4-alpine

docker run -d --name node-alpine -it node:8.9.4-alpine

上記--nameでコンテナ名を指定していない場合は自動で付与されるため
docker ps のNAMESにある名前を使う

docker exec -it node-alpine /bin/sh

SQLでdatetimeの差を秒の整数で取得

MySQLのDATETIMEカラムの差を秒で取得する方法

startとendというカラムがDATETIMEだった場合、時間の差は

select TIMEDIFF(`end`, `start`) 

で取得できる。この時、 00:12:13のようなフォーマットで返る

これをさらにtime_to_sec関数で整数値の秒にする。

select TIME_TO_SEC( TIMEDIFF(`end`, `start`) ) 

この時間の平均が出したければ、下記のようにすればよい

select AVG( TIME_TO_SEC( TIMEDIFF(`end`, `start`) ) )