Big.Little Sucks (or Not)

ARM の Big.Little いまいちじゃね?と思うのだが世間の人々はどう評価しているのだろうな。

Pixel2 とかは Big x4, Little x4 の CPU が載っている。仕事でやっている CPU intensive なアプリだと、なにかと処理を並列化していくのでけっこう CPU は使い切る、のはピークの瞬間だけだけれどもたとえばアプリ起動時で 4 コアくらいは使い切る。

そういう高負荷時の Systrace をみると, Big コアのロードが真っ先に埋まっている。そこから更に負荷が上がると残りの Little コアも埋まっていく。この挙動が妥当かどうかはさておき、アプリは自分のスレッドがどのコアに割り振られるかはわからないので性能を予想しづらい。スレッドの特定のコアを指定する API も少なくとも Java レイヤにはない。ベンチマークのスコアもいまいち安定しない。(なので言語処理系とかで本気の厳密なベンチマークをしたい人たちは遅いコアを全部殺したうえで計測したりする。ついでに thermal governor も殺してクロックも固定する。電話機が熱で溶けないのか心配。)

たとえば Halide みたいな data parallel なコードが「よし 8 コアあるぞ!」とスレッドを 8 個起動したとする。しかしそれらの並列処理は速度が揃わない。他プロセスの影響だの cache coherency だの言い出すまでもなく CPU が違うから。そりゃタスク粒度をあげて細かく worker に振り分けていけば unevenness は隠せるし、そうでなくても速い CPU が空き次第スケジューラが遅い CPU からスレッドを migrate してくれればいいっちゃいいのだが・・・それよか 8 個の並列処理がだいたい同じ速さで終わると思ってfork-join をかける方が簡単じゃね?

そしてアプリのスレッドを速いコアから順に割り振るのはいいのか?省電力とかいう話はどこいった?画面が消えているときはモードが変わって速いコアを止めているのだろうか。

など色々自明でないことが多すぎて、アプリプログラマには手に負えない。それよか速いコアだけ 6 個、とかにした方がよかったんじゃないのかなあ。遅いコア2つ速いコアを1つ買えるという計算があってるのかはわからないが・・・。 LWN の記事を読んでも辛いという気持ちしにかならない。

最初の記事では Big と Little の CPU を排他的に使う (Big だけで動くモードと Little だけで動くモードをスイッチする) ということが書いてあり、マジかと思う。まあこれは 2012 年に書かれた記事で自分の Systrace などの観察とは一致していないので、少なくともいまは違うのだろう。

Apple はどうしてるのかと Wikipedia を眺めていたら、どうも彼らの CPU も Big.Little 類似のアーキテクチャを採用しており、しかも A10 くらいまでは LWN にあるような Big/Little 排他動作のアプローチだったらしい。まじか。でもたしかに iPhone のコア数って 2-3 くらいと伝え聞いていたので、整合性はある。そして A11 からはでかいのと小さいのを同時に使えるようになったと書いてある。そりゃ iPhone X 速くなるわけだわ。

むー。Big.Little は失敗におわった実験かと思ってたけど、全部自前でやりたい放題かつ実際にベンチマークでは Snapdragon 勢に圧勝している Apple の CPU が同じことをしているとなると、自分の脊髄反射とは裏腹にそれなりに成功したアーキテクチャーなのかなあ。ぜんぜん納得行かないが・・・。

探すと関連論文ちょこちょこあるね。ちらっと読んでみようかなあ。