MailDeliver2に「確認できる着信通知」

動機

Cinnamonの通知機能は使いにくい。

通知はずっと残すか(どんどん増えて超重くなる)、表示が終了したら消すかしかない。
メールの着信通知をNotify Sendで出しているのだけれども、見逃していまうと確認しようがないと、通知が常時きてるような環境ではその時に見られないので、まず確認できない。

着信に気づいてから確認したいのだが、その機能がなかった。
そこで、かねてからの希望だった、「Systrayに常駐し、クリックするとこれまで受け取ったメールが確認できる」という機能を追加することにした。

30分くらい、と思ったが5時間ほどかかった。

苦戦

まずSystrayをどう実現するかだが、yadを使った。
Zenityのforkらしいのだけれども、なんかだいぶ違う。

yadをどう使うかというのは随分悩んだ。
yadの--commandではクォートがエスケープされてしまうため、スペースで必ず分割されてしまう。そのため、置き換えが発生する部分は別にくくりだすしかない。
--listenで実行するコマンドを随時更新できるが、ここでも同様の問題があるし、そもそも標準入力から渡す方法というのは結構限られる。

結局3つに分割している。データ整形用のスクリプト、yadのcommandになるスクリプト、そしてyad自体を起動するスクリプトだ。

当初、4つだった。一時的に保存され、通知と共に消されてしまうヘッダをとっておくためのプラグインだが、不毛なので(そしてそれが必要になるプラグインはおそらく多いので)Maildeliver本体に組み込まれ、LeaveHeadersという設定を可能にした。

時間がかかったのは細かいミスが重なったわけで、未知のエラーには遭遇していない。

いずれにせよ、これでメールを遡って確認できるようになった。ダイアログのOKでクリア、cancelで保持だ。

Yadの起動をRubyで行っている理由は結構単純で、複雑なエスケープなしにスペースやspecial characterを含むエントリを分割するために行志向にしていて、行単位でargを与えるのがRubyだと楽だから。

Yadのspecial character

結局yadでなくZenityを使っていたのは、Yadはエントリーに対して結構複雑なエスケープを必要とするためで、とりあえず手っ取り早い方法としてである。

簡単にいえば、Yadの--listでエントリが表示されなかったり、ひとつ上の内容が表示されたりしていた。
ドキュメントにないので自力で試した限り

  • <または&が含まれる場合、そのエントリはテーブル的に上の項目をクローンする
  • エスケープ方法はXML(&lt;及び&amp;)
  • ところが&rt;には対応しておらず、&が含まれるためクローンされてしまう

こういうわけのわからない仕様はやめてほしい。

シェルスクリプトで並列実行制御を行う

シェルスクリプトを書く場合において、処理を順次おこないたいことは多いはずだ。
多くのディレクトリや処理のリストなど、順に処理を適用していくケース。

まず、この設計だが、「ある特定の場所でしか実行されないスクリプト」はnoexecが指定されていない限りはそのルートに設置すべきだと思う。
対象ディレクトリごとにスクリプトが異なってくる場合はその対象ディレクトリごとにスクリプトを設置する。
もしそうでなく、その違いがディレクトリのパス自体に含まれるのであれば、単純に対象ディレクトリに空のドットファイルを置けばよいと思う。

例えば、…/.somescriptを実行するのであれば、トップに

for i in **/.somescript
do
  ( cd ${i:h}; zsh .somescript )
done

のようなスクリプトを書けば良い。Gitが「Gitを実行するディレクトリがリポジトリになる」という仕様なので、このように方法にらも随分なれてしまった。
もし、パス要素自体が重要になるのであれば、

for i in **/.target
do
  fooscript ${${i:h}:t}
done

という方法も考えられる。

それは良いとして、その各処理が時間がかかるとしたらどうだろう?
これは別にディレクトリ単位であった場合に限らない。テキストファイルに1行1エントリ形式で書いて読みながら処理する場合も同様だ。

別に最初からターゲットをグループ分けしてもいいし、xargsを使って3つずつ実行する、といったことで並列化することもできる。
だが、できれば常に3スレッドで実行する、といったモデルのほうが好ましいのではなかろうか。

これを実現するためにシェルスクリプトで並列実行制御したいのだが、残念ながらこれはかなり難しい。
Zshでもzthreadがあるような話も目にするのだが、まぁ実際はそうもいかなそうだ。

並列実行の難しさは、「同時アクセス」にある。あるリソースに同時にアクセスした場合、いろいろな形でおかしなことになる。
ファイルデスクリプタを共有すれば良いのではないかと考えたのだが、

worker() {
  workern=$1
  typeset val
  while read val
  do
    print "Worker $workern: $val"
  done
}

print -l {1..100} | (
  for n in {1..3}
  do
    worker $n &
  done
)

wait

結局read時に同時アクセスするとおかしな値を取ることになり(空文字列だったり、複数行がぐちゃぐちゃに混ざったものだったりする)、ちゃんと動作しない。

なお、ここでのポイントをまとめておこう。

  • ()はfork子プロセスを生成し、子プロセスで実行する。
  • この子プロセスに渡されたパイプは、子プロセス自体の標準入力として受け取ることになる。リダイレクトしないプロセスはこのファイルデスクリプタを共有する
  • &でバックグラウンドで実行する。子プロセスを生成したかどうかは関係がない
  • 外部コマンドはfork+execで子プロセスを生成するが、関数は生成しない
  • waitはジョブを共有待ち合わせる。引数なしですべてのジョブを待つ
  • 同じファイルデスクリプタを共有している場合、IOの位置もいずれかのプロセスが動かせばすべてのプロセスで動く

結局、アクセスしたら要素をひとつ返してくれるQueueがほしいのだ。

そこでまじめに考えてみた。一番単純なのはflockを使う方法なのだが単純にはいかない。プロセスの中で処理したければ、ファイルデスクリプタを使った、複雑な方法が必要になる。
その中で比較的スマートに処理できると考えたのがGistのスクリプトだ。

この場合、.lockは空ファイルであり、単なるロックでしかない。無駄なファイルを作るのにはちょっと抵抗があるが、方法としては比較的簡単だ。
この方法はbashでもほぼ同様に書くことができる。あまりzshらしい方法とは言えない。

なんか悔しいので、Zshらしい方法として、Socketを使うという方法を提案してみる。
UNIXドメインソケットはファイルパスを用いてプロセス間通信を行う。TCP同様、サーバーが接続を受け付け、IOを確立するものだ。

一般的にはサーバーは並列処理できるように接続の受け付けはマルチスレッドで行う。

zsocket -l foo
integer server=$REPLY
	
while zsocket -a $server
do
(
  integer io=$REPLY
  ...
) &
done

だが、シングルスレッドで行った場合はどうなるか。listenはしているがacceptはしていない状態だと接続しようとするclientはブロックされ、acceptされるまで待たされることになる。
結果的に、あるリソースにアクセスし、供給する部分がシングルスレッドになる。同時にアクセスしてもproducerはそれをブロックして順番に渡していくことになる。

これはごく普通のマルチプロセスモデルであり、Perlはthreadが非推奨で、UNIXドメインソケットの利用を推奨している。
そのため特に目新しいものではないのだが、Zshでおこなう(シェルスクリプトで行う)というとまたちょっと味があるのではないか。

Gist

メインマシンをZ400からGodavariに戻して3画面にする

変更

昨日、GodavariマシンのグラフィックドライバをプロプライエタリなCatalystからオープンソースのAMDGPUに変更したが、だいぶ安定している印象なので、メインマシンをそちらに戻した。

Z400とGodavariはマシン選択としては結構微妙で、Z400は

  • 性能が1割程度高い
  • 画像・映像処理は2-3倍くらい速い
  • 全体的に安定している
  • 全体に帯域が広い
  • Intel CPUということもありDTM環境が正常に動く

一方Godavariは

  • 3画面出力が可能
  • 規格が新しいのでUSB3.0をはじめ新しいハードウェアがサポートされている
  • 最新のRCカーネルでもCPUが機能的に対応していないと文句を言われることがない
  • Z400のドライブ数6に対して8と多い
  • インターフェイス的に拡張性で有利。外部インターフェイスそのものも多い
  • 動作音が静か

安定して動作するのであれば3画面をとってメインをGodavariにした形だ。
処理性能をうまく使って分散できると全体のパフォーマンスは向上するかもしれない。
このマシンでやらざるをえないScrubの時間が伸びるのが不安だが。

FHD 3画面

うちの環境は変則的な配置で計5画面がセットされているが、通常利用可能なディスプレイはFHDが3台だ。

  • LG 22EN33
  • LG 22EN43
  • SAMSUNG S22B300

いずれも低価格帯のものだが、21.5インチのFHDの液晶ディスプレイである。インターフェイスはLG 22EN43がHDMIを備える以外はDVI-DとVGAを備えている。

LGのものは画質も悪く、INPUT切り替えが極めて遅い(特に信号がないチャンネルを経由する場合はものすごく遅い)。ついでにいうとサポートの対応が極めて悪い。視野角も狭く、色も明らかにおかしい。はっきりいって、とても気に入らない。

サムスンのものは、視野角が広く色味も良い。画面は綺麗だし、最低限の機能ではあるが、使いやすい。
ただし、スタンドは完全な固定で、しかもVESAマウントもないためアームも使えない。

これまでは左右で(DVIと、DP-DVI)左がプライマリだった。
基本的にどのような配置にしても、結局左側ばかり見てしまう。左右均一に見られるようになるまでは結構なトレーニングが必要だ。

トリプルにした場合、左をプライマリにすると間違いなく右ディスプレイは見られない。
真ん中(サムスン)をプライマリにするしかないが、ここで思わぬ問題。

FM2+Killerのディスプレイ出力はHDMI, VGA, DVI-Iで、かなり配置は固定されてしまう。
この都合でサムスンはVGA接続なのだが、もともと画面がゆるめなサムスン、VGA接続だとすごく滲む。
プライマリが滲むというのは、ものすごく気になる。結局、Z400のディスプレイが真ん中をとばして左右になってしまうが、サムスンと22EN33の接続を両方とも入れ替えた。

トリプルってどうなの

一言でいえば難しい。
プライマリディスプレイが正面にあるわけで、今までよりも左右どちらも見えなくなった。

隠さなくても切り替えて使えるというメリットはもちろんあるのだが、一覧できる情報量は減ってしまった。

また、配置についても、頭を囲むように角度をつけて配置したほうが一覧性が上がる、と考えていたのだが、実際はフラットに近づけるほうが情報を把握できる。

当たり前だが、画面に接近するほど視野は狭くなり一度に入る情報量は減る。

そう考えると、一覧性からいえばウルトラワイドディスプレイが良さそうに思える。
あちらは縦はFHD相当だが、横はFHDの2倍ある(4kと同じ)。
幅が随分と必要になるが、ウルトラワイドディスプレイ2枚というのも選択肢なのかもしれない。

もし、並列作業があまり得意ではないが情報の一覧性を向上させたいのであれば、マルチディスプレイよりも4k1枚にしたほうが明らかに捗る。

もし、FHDから4kにした場合に液晶一辺の長さも倍になるのであれば、情報量は単純に4倍と考えていい。
しかし、そうでないのであれば4倍には到達しない可能性が高い。それでも、ひとつの画面となり、見やすくなることでデュアルディスプレイよりも情報量は増えたと感じるのが一般的であるようだ。

もちろん、この問題はコンテキストスイッチとは別に考えなくてはいけない。

例えば資料をみながら作業をするような場合に、作業側をみなくてもブラインドでできるが、資料は見なくてはいけない状態だとしても、単一のディスプレイで資料だけを広げていると(Windows、あるいはそれに類する挙動を示すウィンドウマネージャでは)資料を最大化して上にしたままでは作業することができない。
さらに、トレーダーがよく行うように複数の情報を監視しながら作業するのであれば多数の情報が一覧できる状態でなくてはならない。こうしたことが並列性としてのニーズであり、実際にアクティブに利用されている「作業空間」として使用するためには訓練が必要になる。

一方、単純に複数の情報を切り替えながら行うために、ウィンドウ出し入れの切り替えではなく視線移動で行うことで効率化したいというのがコンテキストスイッチだ。例えば、ニコニコ生放送をみながらツイッターしたい…といったことでもそうだ。典型的にはドキュメントを開いたままプログラミングというのがある。
切り替え時間がつまり、またその際に目に入れておくことができることで情報をロストしにくく、結果的に効率をあげることができる。
ウィンドウが増えればスイッチのコストがあがるため、余計に大きくなる。

つまり、必ずしも同時に視界に入っている必要はないのだが、意識されていないと同じディスプレイでのウィンドウスイッチで済ませてしまい、切り替えるのにもそれなりに慣れが必要になる。

いずれにせよ、枚数が増えるというのは結構な難易度増であり、シングル→デュアル→トリプルと増えるにつ違って著しく使いこなすのが難しくなる。
ただし、定期的にアクセスしている、あるいは状態を確認する必要のために結局常にひらいておきたいウィンドウというのはあるわけで、そのためにウィンドウが一枚使われてしまい、そのウィンドウに専有されないことで作業効率が上がったりもする。

ディスプレイ枚数を増やすと即ち作業効率があがるということはなく、PCの性能同様、それを使いこなすだけの腕があるかという問題が生じる。だから、それを踏まえてサイズと解像度を選択するほうが効率は簡単に上がる(もちろん、ウィンドウを並べるくらいのスキルはある前提だ)。

VGA

VGAは長らくコンピュータで使われてきたアナログ端子である。

デジタル表示を行う液晶ディスプレイにアナログインターフェイスをもちいるというのはかなり理解に苦しむ。そもそもディスプレイ描画はデジタルで行っているわけで、アナログインターフェイスで出力するからにはD/A変換を行っているわけだ。CRT(ブラウン管)なら表示がアナログなので、アナログ信号をそのまま表示にすればよく、取り扱いが簡単なのでそれで良いとしても、液晶の場合点描であるから結局A/D変換が必要になる。

最初から最後までデジタルなら別に変換がいらないのに、途中をアナログにするせいで2回変換するので非常に無駄だ。もちろん、液晶ディスプレイ普及とともにDVIが一般化したのだが、なぜか根強く残ってしまい、残っているからには対応せざるをえないということで、DVI2個にしてくれれば良いものをDVI+VGAにしたりして苦慮させられている。

2015年に終了した、レガシーインターフェイスである。

さて、VGAについてだが、多かれ少なかれ液晶に表示してもCRTのようなぼやっとした画面になる。ディスプレイによってその度合いは大きくことなり、今回の場合はサムスンのディスプレイはVGA入力ではにじみがひどく、文字が読みづらいレベル。LGのものはそこまで気にならない。

ビデオを表示している分にはVGAのみづらさというのはそこまで目立たないし、TVを観るためという人にとってはそれほど重要ではいなのかもしれないが、文字をみる時にはVGAは明らかに読みづらい。高解像ディスプレイで文字を小さくしている人にとっては、一段とその読みづらさが目立つ。

ビジネス用コンピュータではずっとVGAのみ採用ということが続いてきたが(NVSで、変換アダプタはVGA*2という状況)、VGAで事務作業はものすごく向いていないと思う。

学び

  • ディスプレイ解像度の向上は多かれ少なかれ作業効率に寄与するが、その度合いは条件による
  • ディスプレイサイズの向上の作業効率への影響は条件による
  • ディスプレイの枚数増は使いこなすのにスキルが必要。トリプルになるとかなり難しい
  • ディスプレイ枚数を増やすよりはより大きくドット数の多いディスプレイにかえるほうが有効
  • 特に文字作業の場合はVGA接続をやめるだけでも効率あがるかもしれない
  • ディスプレイの配置は大事。作業効率に影響する。マルチディスプレイならなるべく視線にフラットなほうがいい
  • 安いディスプレイと高いディスプレイにはかなりの差がある
  • LGはやめておこう

AMDGPUドライバーを試す

AMDGPU

Catalystドライバーの出来がよくないので、そして一向によくならないので、デキが良いと評判のamdgpuドライバーを使ってみることにした。

AMDGPUドライバーは、mesa上で動作するオープンソースドライバーであり、ベンチマークテストではCatalystには及ばないが良好な成績を収めている。
実験的だが、AMDGPUドライバー上でカーネル/Xバイナリに依存しないプロプライエタリドライバーを使用するAMDGPU PROドライバーも存在する。

インストール

Manjaroではcoreにmhwd-amdgpuが含まれているが、本体はextraにあるxf86-video-amdgpu。

なお、AURにあるAMDGPU PROは軒並みOUT OF DATEになっている。

VDPAUおよびVA-API

勝手に有効化されるため、$VDPAU_DRIVERは無効化する。

VA-API設定は環境変数として

LIBVA_DRIVER_NAME=gallium

VLCでは出力設定をVDPAUではなく、OpenGL GLXビデオ出力(XCB)に設定しないとビデオによってはエラーを吐き、動作しない。
画像が乱れる場合もあるが、VLCではありがちなことと理解している(Quadro+nVidiaでも同じだから)。

Flashのアクセラレーションも/etc/adobe/mms.cfgの

EnableLinuxHWVideoDecode=1

で動作する。

Cinnamon 3D

特に設定しなくても問題なく動作する。

マルチモニター

テストの限りではカーソルの歪みはない

Skype

テストできず。