brly.github.io

04 May 2018 : 超技術書典4に参加した
techbook

サークルパス。当日は再入場が規制されていたので必要だった。

コミケと変わらず「 signico 」サークルで参加。 今回は思いつきで漫画で参加。筆が遅いのもあり、4コママンガ4列のみしか寄稿できなかった。原稿に割いた工数は全部で6日くらい。 今まで一日に絵を最長で書いても4,5時間くらいだったけど、最後の方は9時間とか描いていて、やる気のコントロールと背中の痛みに苦しめられていた。 技術書を書くような、ひたすらタイピングするようなものは普段の仕事と一緒だけど、絵を書くというのは日常的な作業とは異なるので、一定の「やる気」が無いと描けない。 そうして、なんとか捻出したものの姿勢が悪いために背中が痛くなって苦しめられた。 水平に iPad を置いて絵を描くと、覗き込む形で書くことになるのだが、これがどうも背中に良くなかった。 なので これ を買ってみた。

普段 iPad で絵を書く時は procreate しか使っていなかったけど、漫画となるとテキスト入力やらが必要になり、 前にインストールしていた clipstudio を使った。テキスト以外にもトーンとか貼れてなんだか楽しい。 clipstudio は procreate に比べると、とても多機能だが一方でとっつきにくさも感じた。 procreate は clipstudio に比べると機能は少ないが見た目がシンプルだし、高解像度時のお絵かき時の画面反映までのレイテンシは早く感じる。 日常のふとした「絵を描きたい」気持ちから描くような軽めのイラストは、procreate で十分事足りる。

今まで漫画を読む時は背景のトーン、ベタとかをあんまり良く見てなかったけど、意外と漫画の背景はトーンで出来ていることに驚いた。 なので、見よう見まねでトーンを貼って背景を乗り切っていた。

戦利品。写真を撮っていてダウンロードコードのやつを見てて気づいたけど、期限が切れていたのがあって、少し悲しくなった。

03 May 2018 : initial mess@ge
idolm@ster

このライブ に行ってきた話。台湾公演だったので台湾に行った。人生初台湾。

写真左上、黒松サイダー。ドクペより厳しかったけど、何回か飲んでる内に慣れた。日本で売ってたら買うかも知れない。 このサイダーにかぎらず、自販機が大抵 20 TWD (= 73円, 台湾ドル) で安い。地下鉄も大体 20 TWD 5駅くらい乗れたので事足りた。

メロンアイスは、なんだか懐かしくて買ってしまった。他にも、「海外のお菓子」と題して日本のお菓子を沢山見かけた。台湾のファミリーマートとかで。セブンイレブンもあったなぁ。

ライブ

写真はCygamesのフラスタだけど、有志が行うフラスタも日本で行われているそれと同じでなんだか感動した。写真少し撮ってくればよかった…。

TICC

会場は Taipei International Convention Center というところらしい。

TICCのサイト の写真を見てもわかるように、結構傾斜がある。

傾斜の分だけ、フラットな会場と比べて見やすかったのでは、という印象。

雑な情報

day2 の MC で観客に向けて「どこから来たんですか?」という質問があり、「台湾の人」「日本から来た人」「それ以外の人」という感じだったのだが、 台湾の人は全体の 1/5 くらい、日本の人は 2/5 くらいで、残りがそれ以外という感じを受けて驚いた。 日本以外でもやっていけそう、とふんわり思った。

ライブ初日、物販待機列に並んでみたのだけど、普通に数時間並んだ。本当に日本と変わらない。待機列の前後ろから聞こえてくる言葉も日本語だったし。

01 May 2018 : 2018 gw
idolm@ster

適当にまとめる。

4/30

某仕事が終わった後だったので、一日引き篭もって静養していた気がする。

新しくサービスが開始した「アイドルマスター シャイニーカラーズ(シャニマス)」をずっとやっていた気がする。 ゲームが中々の難易度で、やりごたえがあり面白い。ゲームシステムはパワプロライクな育成ゲーム。 live 2d のコンテンツをあんまり真面目に体験したことなかったけど中々良い。かわいい。 不自然に見えないように動かすの、結構大変そうに感じるけどどうなんだろう。

細かな話をすると、他のアイマスコンテンツの場合だといわゆる SSR レアリティのカードに限定衣装なりの差別化を図っているんだけど、 このシャニマスの場合は SR レアリティから live 2d 立ち絵の衣装が変わるようになっており、既存作品に比べて SR にも比較的付加価値がある。 キャラクター 3d モデルの限定衣装と live 2d 立ち絵の限定衣装の製作コストが違うのはもちろんあると思うけど、こういう落とし所もあるんだな、という発見があった。

5/1

相変わらず、シャニマスをやり続けていた気がする。ちょうどやっていた信号機ユニットのイベントの難易度が比較的高くてクリアできず、ずっとやり続けていた。

@kogaki さんに誘われたので、オクトーバーフェストに行った。

そういえば、この数日前にビールに詳しい方から「オクトーバーフェストは飲み比べするにはコスパ悪いからあんまオススメせんで」と言われたばっかりだったけど…確かに若干お高めではあった。

寝る直前にシャニマスのイベントを無事終えて寝た。

5/2

DMM VR シアターに行く。

事前情報を知らなかったのだけど、主演アイドルの中の人はスタンバイされていて、MC パートとソロパートは中の人によるアドリブ・ライブ演出がなされていた。 満足度はだいぶ高かったのだけど、ちょっとお値段が張るな、という感想。

5/3

めっちゃ掃除する。使い捨て手袋が本当に役に立つ。

これ が気になっていたので、最寄りのダイソーを探してみたら豊洲のららぽーとだった。

なので豊洲のららぽーとに買い物にいく。ダイソー目的で。売っていてよかった。

ららぽーとの建物の中で、豊洲駅から反対側に位置しているのがちょっとよくない。

5/4

@soranoba 宅に映画を見に行く。シャークネード 2,3,4。 個人的にはナンバリング順にスケールがシンプルに上がっていて面白くなっていく感想。 配給アルバトロス・製作アサイラムだけど、やっぱ Z級映画ではないよなぁ。

つっても、既に通して見ているので視聴は2度目だった。いい感じに内容を忘れていたので楽しめた。

5/5

このブログ/静的サイトのデザインをいじる。 bootstrap を適当に読み込んで使っていたけど、どこかでちらっと見かけた material components for the web を使ってみることにした。

pagenation を導入した時に、記事の markdown が描画されなくて困った時に以下の issue で解決した。

https://github.com/sverrirs/jekyll-paginate-v2/issues/19

あと、タグをクリックしてそのタグを含む記事一覧、を実装したいんだけど、これが出来ない。

24 March 2018 : avx
SIMD

元ネタ

を見かけたので、自分も最適化やってみた。

atcoderの提出URL

#include <immintrin.h>
#include <cstdio>

int N;
int a[200000] __attribute__((aligned(64)));
int b[200000] __attribute__((aligned(64)));

int extract(__m128i ret) {
  __m128i t0 = _mm_shuffle_epi32(ret, 176); // [2,3,0,0]
  __m128i t1 = _mm_xor_si128(ret, t0); // [0^2,1^3,x,x]
  __m128i t2 = _mm_shuffle_epi32(t1, 64); // [1^3,x,x,x]
  __m128i t3 = _mm_xor_si128(t1, t2); // [0^2^1^3,x,x,x]
  int rl = _mm_extract_epi16(t3, 6);
  int rh = _mm_extract_epi16(t3, 7);
  return rl + (rh << 16);
}

#define process_xor(src) \
  c0 = _mm_add_epi32(a0, (src)); \
  c1 = _mm_add_epi32(a1, (src)); \
  c2 = _mm_add_epi32(a2, (src)); \
  c3 = _mm_add_epi32(a3, (src)); \
  c4 = _mm_add_epi32(a4, (src)); \
  c5 = _mm_add_epi32(a5, (src)); \
  c6 = _mm_add_epi32(a6, (src)); \
  c7 = _mm_add_epi32(a7, (src)); \
  c8 = _mm_add_epi32(a8, (src)); \
  c9 = _mm_add_epi32(a9, (src)); \
  r0 = _mm_xor_si128(r0, c0); \
  r0 = _mm_xor_si128(r0, c1); \
  r0 = _mm_xor_si128(r0, c2); \
  r0 = _mm_xor_si128(r0, c3); \
  r0 = _mm_xor_si128(r0, c4); \
  r0 = _mm_xor_si128(r0, c5); \
  r0 = _mm_xor_si128(r0, c6); \
  r0 = _mm_xor_si128(r0, c7); \
  r0 = _mm_xor_si128(r0, c8); \
  r0 = _mm_xor_si128(r0, c9);


int solve() {
  // port0 vec alu,
  // port1 vec alu, vec shuf
  // port5 vec alu, vec shuf
  // port2, port3 load
  __m128i r0 = _mm_setzero_si128(); // pxor 1l/3t
  int ri = 0;

  int DI = 10;
  int DJ = 24;
  int NI = N / DI * DI;
  int NJ = N / DJ * DJ;

  for(int i=0;i<NI;i+=DI) {
    int aa = a[i];
    int ab = a[i+1];
    int ac = a[i+2];
    int ad = a[i+3];
    int ae = a[i+4];
    int af = a[i+5];
    int ag = a[i+6];
    int ah = a[i+7];
    int ai = a[i+8];
    int aj = a[i+9];

    __m128i a0 = _mm_set_epi32(aa, aa, aa, aa); // movd, pshufd
    __m128i a1 = _mm_set_epi32(ab, ab, ab, ab);
    __m128i a2 = _mm_set_epi32(ac, ac, ac, ac);
    __m128i a3 = _mm_set_epi32(ad, ad, ad, ad);
    __m128i a4 = _mm_set_epi32(ae, ae, ae, ae);
    __m128i a5 = _mm_set_epi32(af, af, af, af);
    __m128i a6 = _mm_set_epi32(ag, ag, ag, ag);
    __m128i a7 = _mm_set_epi32(ah, ah, ah, ah);
    __m128i a8 = _mm_set_epi32(ai, ai, ai, ai);
    __m128i a9 = _mm_set_epi32(aj, aj, aj, aj);

    for(int j=0;j<NJ;j+=DJ) {
      __m128i b0, b1, b2, b3, b4, b5;
      __m128i c0, c1, c2, c3, c4, c5, c6, c7, c8, c9;
      b0 = _mm_load_si128((__m128i *const)&b[j]); // movdqa 1l/2t
      b1 = _mm_load_si128((__m128i *const)&b[j+4]); // movdqa 1l/2t
      b2 = _mm_load_si128((__m128i *const)&b[j+8]); // movdqa 1l/2t
      b3 = _mm_load_si128((__m128i *const)&b[j+12]); // movdqa 1l/2t
      b4 = _mm_load_si128((__m128i *const)&b[j+16]); // movdqa 1l/2t
      b5 = _mm_load_si128((__m128i *const)&b[j+20]); // movdqa 1l/2t
      process_xor(b0);
      process_xor(b1);
      process_xor(b2);
      process_xor(b3);
      process_xor(b4);
      process_xor(b5);
    }

    for(int j=NJ;j<N;j++) {
      ri ^= aa + b[j];
      ri ^= ab + b[j];
      ri ^= ac + b[j];
      ri ^= ad + b[j];
      ri ^= ae + b[j];
      ri ^= af + b[j];
      ri ^= ag + b[j];
      ri ^= ah + b[j];
      ri ^= ai + b[j];
      ri ^= aj + b[j];
    }

  }

  for(int i=NI;i<N;i++)
    for(int j=0;j<N;j++)
      ri ^= a[i] + b[j];

  return ri ^ extract(r0);
}

int main() {
  scanf("%d", &N);
  for(int i=0;i<N;i++) {
    scanf("%d", a+i);
  }
  for(int i=0;i<N;i++) {
    scanf("%d", b+i);
  }
  int ans = solve();
  printf("%d\n", ans);
  return 0;
}

atcoder のジャッジシステムで実際にプログラムが動作するのは aws で、CPU のアーキテクチャが IvyBridge になっていた。 なので、SIMD は AVX の浮動小数点演算が使えるに留まる。整数演算(AVX2) は使えない。 さらにコンパイラが SSE 3 だか 4 までしか使えないので、256bit の ymm レジスタはあるものの、結局オペランドには xmm レジスタが取れるやつしか使わなかった。 なんかインラインアセンブラで適当にやれば出来る気がしたんだけど、途中でめんどくさくなってやめてしまった。

書いたコードを今見直してみると、何考えてたのか思い出せない。

適当に眺めてみると、とりあえずメモリ演算比を高くしようとしているのは見える。 配列Aは 10 要素、配列B は 24 要素ずつ処理しようとしている。なぜだかは分からない..。 適当にローカルで動かしていた感じ、これくらいにしたら良い感じに xmm レジスタを使い切っていたのでしょう。おそらく。

命令のスループット、レイテンシーをコメントに書いてるけど、多分あまり活かせなかったんだろう。

19 March 2018 : demand miss rate
Memory

demand miss rate とは software prefetch のことらしい。しらなんだ。

よく考えたら demand するのはコード書いた人だし、分かる気もしてきた。