The King's Museum

ソフトウェアエンジニアのブログ。

ISUCON 7 で予選敗退した

ISUCON というプログラミングコンテストに参加し予選敗退した(100位近辺でした)。

isucon.net

準備

予選の一ヶ月くらい前に、会社の同僚から「今度 ISUCON に参加しません?」という話があって、会社のメンバー三人で参加することにした。

準備として、

  • Go を読み書きできるように Go Tour をやった
  • 2~3日使って ISUCON 6 の予選を一人で解いてみた
  • 同僚と ISUCON 6 の予選を議論した
  • 当日のサーバーセットアップの準備(これは僕じゃなくて同僚がやったのだけど)

あたりをやった。

予選問題をやった感想としては、プログラムとかサーバー構成はかなり簡素だなぁと思った。 デフォルト実装はかなり荒い感じ。 だからこそ、高速化する余地あるということなんだろうけど。

ただ、競技時間8時間という時間制限はなかなかシビアだなぁと思った。

当日

予選は初日に参加。奥さんに子供の世話を頼んで、朝から会社に行った

気合い入れて 9:00 に会社に行ったら開始時間延期になって 12:00 開始の予定と言われ、暇を持て余してしまった。結局、さらに遅れて最終的に始まったのは 13:10 くらいかな。 (二日目も遅れたのはさすがに…)

競技開始直後は、3 台あるサーバーの設定を同僚にまかせて、コードを見つつ高速化ポイントを探す。

お題の Web アプリにブラウザからアクセスしてみるとアイコン画像のロードが明らかに遅い。 MySQL に画像データ入っていて毎回クエリで取り出してるようだ。それは遅いわ。

データをファイルにエクスポートし Nginx で裁くように変更。 ついでにサーバー設定も見直して 50000 点くらいになった。 ここで3時間くらい経過だったかな。

この時、ファイル名はデータの sha1 だからアイコン変更があってもキャッシュ破棄しなくていいですねーとかって話は出てたんだけど、実はうまく 304 が返ってなかったようだ。これをちゃんと 304 を返せるようになってれば高いスコアが出たらしい(検証してないから分からんけど

この後の次の一手がなかなか決まらなくて時間を浪費してしまった。 結局、「グローバルなキャッシュが欲しいよね」という話になって、急遽触ったことのない Redis を導入することに(サーバーが1台なら concurrent-map とか使うだけだけどね)。 「まぁ、Get と Set と Delete さえやっとけば大丈夫でしょ」みたいなノリでがりがり実装開始。

結局、導入したけどバグ取りに追われて気がつけば残り時間わずか。 残り10分くらいになって諦めかけたていたところ、奇跡的にバグの原因を見つける。

「これはまさか奇跡の逆転勝利ってやつかな?」と脳内で盛り上がったが、ベンチマークしてみたらスコアが下がって 40000 点くらいで FINISH でした。

よかったこと

目標は予選突破だったから「結果は出ませんでした」なんだけど、いくつかポジティブな面もあったかな。

「バグでスコア 0 点でした〜」ではなかったし、画像ファイルをエクスポートするところまでの流れは良かったと思う。

特に触ったことない Redis を導入するって決断ができたのも個人的にはよかった。 こういう思い切ったチャレンジを本番でやって、一応導入まで持っていけたっていうのは結構満足している。

こういったチャレンジがきっといつか身を結ぶのかなーなんて思ったり。

わるかったこと

二手目の Redis 導入が大した根拠なく進めてしまったのはよくなかった。

プロファイルをちゃんと見たり、スコアの計算方法を見直したり、やるべきことは沢山あった。 プロファイル用の Go ライブラリも調べてはいたけれど、今回のデフォルト実装で使ってたフレームワークと合わなくて導入を諦めてしまった。 もう少し時間を使ってでも導入するべきだったな。

スコアに反映されないのに無意味に /fetch を高速化してしまったりしたのは典型的なダメパターンなのでかなり反省した。

最後の方はさすがに疲れてしまって明らかに頭が働いてない感じがあった。 いい仕事をするためには疲労は大敵だなーというのは改めて感じた。体力やエネルギーはうまく使わないと…。

あと、開始時間のズレとかで一人参加できなくなってしまって二人だけでやるのはちょっと辛かった面があったかな。

おわりに

結局、技術的なことぜんぜん書いてないが Technical な面はちゃんと書かれたブログが他にたくさんありますからね・・・。

とりあえず、ちゃんと 304 が返ってるかはきちんと確認しようね、っていうのは大事だなと思いました。

45年間で東京23区の若年層人口が半減して、高齢者人口は3倍になったという話

IT と全然関係ない話。

たまーに「このニュースのこの数字は覚えておきたいなー」と思うことがあって、そういう時どうしようかなーと思ってたけど、ささっとブログに書いておくことにした(ブログ更新頻度維持のためにも)。

今回はこのニュース。

www.nli-research.co.jp

まとめると、

  1. 1970 年と比較して、2015 年における東京都区部の 15~29 歳の人口は 52.3% 減少
  2. 同じ条件で 65 歳以上の人口は 322.1% 増加
  3. 2016 年の東京都区部の人口増加のうち 33% は外国人。(20~24歳 の増加分に限っていえば 51.5% が外国人)

という話。

1 番目も 2 番目もそれなりにインパクトあるなぁ、と思ってたけど、3 番目は特に印象深い感じ。

確かに都内のコンビニやファストフード店のバイトの人ってほとんど外国人だもんね。

go build -gcflags '-N -l' とは何か

Go を触っててデバッグビルドしようと思って調べる。 いたるところで次のようにしろ出てくる。

go build -gcflags '-N -l' ...

で、この -gclags-N-l は何なのか。

-gcflags

コンパイルツールに渡す引数を指定できるフラグ

-gcflags 'arg list'

arguments to pass on each go tool compile invocation.

ref: go - The Go Programming Language

'-N -l'

それぞれの意味は次の通り。

  • -N: 最適化オフ
  • -l: インライン化オフ

-N

Disable optimizations.

-l

Disable inlining.

ref: compile - The Go Programming Language

『Androidを支える技術〈Ⅰ〉 ~ 60fps を達成するモダンな GUI システム』を読んで

『Androidを支える技術〈Ⅰ〉 ~ 60fps を達成するモダンな GUI システム』を読みました。

Androidを支える技術〈I〉──60fpsを達成するモダンなGUIシステム (WEB+DB PRESS plus)

Androidを支える技術〈I〉──60fpsを達成するモダンなGUIシステム (WEB+DB PRESS plus)

感想

単純にとても面白かったです。

昔、Web ブラウザのレンダリングエンジンをいじっていた頃があって、ちょっとだけそのときのことを思い出した。 ツリーがあって、それをレイアウトして、描画ライブラリに投げて、その先が GPU で、っていう一連の処理とか。(ブラウザだと DOM Tree と Render Tree が別だったりしたね)。 大して理解もしないままその世界から離れてしまったけども。

思い出話は置いておいて、この本の何がすごいかというと、

  • 上は View ツリーの話から、下はシステムコールの話まで書いてある
  • 豊富な図解と分かりやすい説明
  • 現実のコードをベースにした展開
  • 著者が中の人じゃない

というところ。

知識を文字にする時って、実際にアウトプットすることの数倍の知識が必要だと思う。 だから、この筆者はこの本に書かれた数倍の知識を持ってるんだよなーと思って、すごいなーと思った(小並感)。 というか、書籍にまとめるレベルになると10倍くらい必要かもね、、、

感心したところ

HWC と GPU 周りはとても感心して、とくに SurfaceView の仕組みはなるほどーと思った。

  • SurfaceView の View としての特性は「単に領域に穴をあける」だけ(下の描画結果を透過する)
  • アプリレイヤでは SurfaceView.getHolder().getSurface() で Surface が取得できる
    • Surface というのは gralloc() で確保したメモリ領域へのハンドラ。
    • gralloc() は端末ベンダーによって実装される。大抵は描画ハードウェア(GPU や HWC)に近いメモリに置かれる。
  • アプリレイヤで取得したこの Surface を、メディアコーデックに渡す。
    • 結果、コーデックチップが Surface が指す先のメモリに直接結果を書くことができる、
    • そすうれば CPU を使う必要がなくて電池も消費しないしハッピー。
    • さらにいうと、合成に HWC が使えるなら GPU も使わなくていい!

図にするとこんな感じ(本から引用) ^(1)

f:id:hjm333:20170905223646p:plain

うーん、仕組みもよくできているし説明もすごく分かりやすかった。 (gralloc とかなんだよって話だけど、それは本書を読んでください)

(1): 有野和真.『Androidを支える技術〈Ⅰ〉~ 60fps を達成するモダンな GUI システム』,技術評論社,2017.図 6.16(p.250).

得られたもの

この本を読むとなんとなく Android が理解できた気分になれる。

結局、得られるのは気分だけなんだよね。 当たり前だけど。 実際に自分でコードを追ってデバッグしてってやらないと本当に使える知識/技術にはならない(少なくとも自分にとってはね)

だけども、このなんとなく理解出来た気になるのはけっこう重要かなぁという気もしている。 どこかに誰かも書いていたけど、例えばクラッシュログを見ていて、

うーん、この ViewRootImpl.java ってシステム側だからなぁ、、、とりあえずクローズかな、、、

と思っていたのが

そういえば、ここらへん本に出てたし、ちょっと見てみるかな(キリッ

という根拠のない自信に変わったりする。

そう思ってコードを読んだところで、なかなか結果は変わらないんだけど(だって変化したのは気分だけだからね)、こういう姿勢の変化は結構重要だったりする。 めげずにコード読んでるとたまーに結果が出て幸せになれたり、そもそも実際に読んでみないことには知識も得られないままだからね。

Android に対して「まあ、ちょっとコード読んでみるか」というメンタリティが持てるようになったことが、この本を読んで得られた最大のポイントかな。 あとは普通に読んでて楽しかったです(2回目)

Vol. 2 も出ていて、話題的にはこちらの方が興味があるので読むのが楽しみー。

Androidを支える技術〈II〉──真のマルチタスクに挑んだモバイルOSの心臓部 (WEB+DB PRESS plus)

Androidを支える技術〈II〉──真のマルチタスクに挑んだモバイルOSの心臓部 (WEB+DB PRESS plus)

Chapter 8 Pragmatic Projects【The Pragmatic Programmer】

The Pragmatic Programmer の Chapter 8. Pragmatic Project を読んだ。内容は次の通り。

  • 41 Pragmatic Teams
  • 42 Ubiquitous Automation
  • 43 Ruthless Testing
  • 44 It’s All Writing
  • 45 Great Expectations
  • 46 Pride and Prejudice

Great Expectation

他人の期待を正しく理解することが非常に重要という話。結局、プロジェクトは誰かの期待に応えられているかどうかで判断されるわけで。

コンサルタント業界では "Expectation Management" なんて言葉もあるようだ。この本では「俺たちはそこまでしろと言ってるわけじゃない。ただ、顧客の期待を正しく理解しよう」と説いている。

Tip 69 Gently Exceed Your Users' Expectation

そして、できればその期待を少しだけ上回ろう。Gently というのはとても絶妙な表現なんじゃないかなと思った。それくらいなら、勘違いしてユーザーの期待から大きく離れてしまうこともないだろうからね。

おわりに

今年の頭くらいから読み始めて、中断して、帰りの電車でちょっとずつ読み進めてよーやく読み終わった。やはり英語の本を読むのは時間がかかる…。

全体を読んだ感想としては、こんなに頑張って読まなくてもよかったかな、という感じ。日本語版をぱらぱらと一週間くらいで読めば十分、という感覚ですね。

Chapter 7 Before the Project【The Pragmatic Programmer】

The Pragmatic Programmer の Chapter 7. Before the Project を読んだ。内容は次の通り。

  • 36 The Requirements Pit
  • 37 Solving Impossible Puzzles
  • 38 Not Until You’re Ready
  • 39 The Specification Trap
  • 40 Circles and Arrows

2つほど面白い章があったので感想を書いておこう。

37. Solving Impossible Puzzles

解くことが不可能に見える問題も、正しく制約を理解すれば簡単に解けることもあるよ、っていう話。

ここでのポイントは課された制約をきちんと認識して分類すること。分類は、

  • 必ず守らなければならない制約
  • 必ずしも守らなくてもよい制約

という単純な二種類で充分。私たちは「必ずしも守らなくてもよい制約」を「必ず守らなければならないもの」だと誤認してしまうことが多い。この誤認に気づくと、問題が一気に解決することがある。

38. Not Until You’re Ready

闇雲に何かを始めるのではなく、始めるタイミングを見計ろう、という話。

プロの曲芸師は自分のタイミングを知り尽くしていて、すべての条件が揃うまで静かに待っている。そして、タイミングが来たと感じたら一気に勝負に出る。プログラマも何かの作業をする時はタイミングを見計らうべきだし、また、その直感を鍛えるといい。

「タイミングを見計らう」っていうのは正しく準備することにも繋がるかなぁと思った。何かに向けて準備することはとても大事だなぁ、と最近強く感じる。

いつかだったか、テレビで凄腕の心臓外科医が、手術のヤマとなる血管を切り取る場面で「ここにたどり着いた時点で、僕の勝ちは決まってるんですよ。ここにたどり着くまでが仕事なんですよね。」と言っていて、たしかになーとは思った。

CODE COMPLETE にも、

ニ回測って、一度で切る

という格言が紹介されていて、コーディングにも似た側面はあるんじゃないかなーと思った。

Chapter 6. While You Are Coding【The Pragmatic Programmer】

The Pragmatic Programmer の Chapter6. While You Are Coding を読んだ。 内容は次の通り。

  • 31 Programming by Coincidence
  • 32 Algorithm Speed
  • 33 Refactoring
  • 34 Code That’s Easy to Test
  • 35 Evil Wizards

印象に残る章がいくつかあったので書き残しておこう。

31. Programming by Coincidence

この章は、「自分が書いてるコードをちゃんと理解していますか」というような内容だった。

最近、以前よりも自分の書いたコードに自信が持てるようになったなー、と思っていて、『コンパイルする回数が減った』とか『一発でうまく動くことが増えた』とか、そういうところで開発に効いてきている。

いくつか要因はあると思うけど、大事なことの1つは「何を期待して目の前のコード片を書いているのかを常に意識する」ということだろう。プログラマは何かしらの『期待』を持っていて、それを実現するためにコードを書くわけだけど、どのコードが何の期待を満たすのか、自分の中でちゃんとマッピングさせておくのがとてもよい。コードに自信が持てるし、コードの理解につながる。

これには別の効果もあって、自分の『期待』をただしく理解しておくと、すごくデバッグが捗る。バグはたいていの場合、何らかの『期待』と異なる挙動をしているから発生する。だから、『期待』とコードのマッピングを持っておけば、必ず最後にはバグの原因にたどり着ける。まあ、たまに期待自体が間違ってたりするし、現実はそんなうまくいかないけど、バグ解決の確率はだいぶ高まる。

あとは、この『期待』と『コード』のマッピングはなるべく小さく保っておいて、それをベースにして大きなビルディングブロックを作ってくと、とてもいいコードが書けるんじゃないかなぁと感じている。

この『期待』ってのは『意図』とも言い換えられるかなーと思ったりして、そうするとこの章の言いたいこととつながるよなーと思った。

35. Evil Wizards

これは「ウィザードで生成されたコード使うならちゃんと中身読もうね」という話で、とても説得力があった。

ライブラリの場合、ライブラリ側のコード把握する必要はない。正しいインタフェースが切られていて境界がはっきりしてるからだ。

一方、ウィザードによって生成されたコードは、私たちのコードに直接入り込んでくる。「すぐにウィザードで生成されたコードをいじることになるから、理解してないとひどいことになるよ」というのはその通りだと思った。

(c) The King's Museum