シェルスクリプトで並列処理

なんだか検索件数が多いので、シェルスクリプトによるコンカレンシーのお話をしよう。

ただし、bad design (変数を書き換えるとか、相互にやりとりするとか)は除外する。

また、Zshを前提とする。

投げっぱなし

まず基本。投げっぱなしはとても簡単。

シェルスクリプトではジョブコントロールは無効になっているので、SIGHUPの送信はなされないので、さっさと終了してしまっても大丈夫。

処理の終了を待ちたい場合はwait

flock

flockを使う方法は簡単でシンプル。 ロックファイルを使ってファイルデスクリプタを開きっぱなしにし、そのファイルデスクリプタを指定してロックする。

まずファイルデスクリプタ9.lockファイルをライトモードでオープンする場合

そしてファイルデスクリプタ9を閉じる場合

これを利用するとこんな感じ。

ロックしている間に共有しているリソースの読み込み/変更を行い、ファイルデスクリプタを閉じる。

リソースを読むより簡単な方法は、ひとつのストリームを共有したファイルデスクリプタとして開き、 ロックを中に読むことである。

ワーカーを生成するサブシェルの標準入力はqueueファイルにリダイレクトされている。 そのため、ファイルデスクリプタ0queueファイルなのだが、そのサブシェルの子プロセスであるワーカープロセスはリダイレクトしていないため、このファイルデスクリプタが共有される。 結果、全てのワーカーはqueueファイルを標準入力とするのだが、ストリーム自体を共有しているため、どのワーカーが一行読んだとしてもストリームの位置が変更され、次に読み込む位置は他のワーカーにとっても変更される。実際

WORKER 1: foo
WORKER 2: bar
WORKER 3: baz

となる。

producer-consumer キュー

もっと凝ったことがしたいのであればUNIXドメインソケットを使ってproducer部分をシングルスレッド化することができる。

zsocket -lのタイミングで接続を受け付けているのだが、zsocket -lしていないタイミングでは接続しようとするプロセスをブロックするため、producer側の処理は直列に行われる。

双方向性があるときはproducerと直接やりとりできるのはメリット。

Orbit designの場合

私が採用しているOrbit designはレギュレーターはZshスクリプトなので、基本的にこのような並列化手順をとっている。 とはいえ、ものによっては直列(serial)になっていたりする。

ただ、並列化されているものが多い。ワーカープロセスは最も多いもので5。

基本的にワーカースクリプトが受け取るのは処理対象ID(ほとんどの場合ファイルパス)だけである。 それ以外の情報はスクリプト側で生成するか、別途取得するかする。

P720 (Xeon Silver 4114 * Quadro P400) を半年以上使ってのインプレッション

ざっくり印象

基本的には「あまりよくはないが不満もない」というのが印象である。

  • 体感的には速くない。実際処理時間は劇的には速くなっていない
  • だが、従来のものと比べると随所で性能差を感じる
  • 多プロセスを走らせたときでもすごく速いとは感じない。1プロセスごとに結構時間がかかるので、量を消化したいときは厳しめ
  • コンシュマーCPUと比べて優れているのかどうかはだいぶ怪しい
  • 「速くはないけど余裕はある」という不思議な挙動。フルロードでもCPUに空きがなくて処理ができないというようなことは起きない
  • ファンの回転数があまり上がらず、結構静か
  • 安定性があまりない。特にフロントUSBデバイスがごく限られた条件でした機能しないのが結構痛い
  • 再起動したときにUSBデバイスが使えなくなったり、よくわからない不具合がとても多い
  • HTTはまったくいらない。フルロードしているとき、きっかり50%になる
  • 重量はとても重いけれど、取手があるためそれほど取り回しはきつくない
  • インパクトはそれなりにある。現状、7980XEでも18コアなので、20コア40スレッドというのは「桁違い」と捉えてもらえる。しかし、2990WXが32コアであることから、「圧倒的」という感覚は相当薄れている
  • Windows 7が動く最終機という意味合いがあったため、Windows 7でASIOが動作しなかったのは致命的だった
  • 内部がhpほど整理されておらず、電源パーツなどが不足しているため拡張性はあまり高くない
  • 「良い」とはあまり思ってないけれどあまり不満はなくてそこそこ満足している

つまりコレ自体に不満はそれほどないのだが、値段的に40万円を越える程度であることから、ゲーミングPCと比べて2倍程度の価格的価値があるかというとちょっと難しい。

ただし長期運用を考えるとトラブルに対応しやすく、帯域的には拡張性が高いという点は評価できる。 ちゃんとWindows 7が動作していて、かつ拡張が楽な構造をしていたら性能の問題は「織り込み済み」だったので、なにも気にしなかったと思うのだけど…

拡張プランは延期

しかし、もともと「64GB RAM, GTX1080Ti, Xeon Gold 6138に換装」と予定されていたが、現在そのプランは延期、変更されている。

理由は、

  • 通常利用では有り余っているので強化の必要性が全くない
  • メモリを増やしてもプロセス数増加によるパフォーマンス増加がいまひとつ望めない。ディスク速度の問題もあり、それをやるならプログラム側に大改修が必要で、追いついていない
  • メモリが高い。DDR4 ECC Regメモリの高さは半端ない
  • QuadroのNVENCがそれなりの速度が出ること、画質を問題にするとNVENCならとても使っていられないことからNVENC目当てが成り立たなくなった
  • 「ゲームしようかなぁ」とか思っていたけれど、やろうとしているゲームがなくなってしまった
  • 引っ越さないことにはRCSはできない
  • まぁまぁ性能が良い割に消費電力が少ないというのにすっかりやられて、爆熱仕様にする気にならない (すでに十分熱いし)

Quadro P400はTDPが40Wとビデオカードとしては非常に消費電力が小さく、Xeon Silver 4114も85Wと控えめ。 加えて4114がコア数が多いため、「軽い処理が色々ある」という状況ではより省電力に動作することができる。 powersaveガバナーとの相性がよく、通常のデスクトップ使用で90-145Wと電力的に軽い。 これは多数のスクリプトを回していてもあまり変わらない。

TDP130Wのプロセッサを使うZ400では120-190Wとひとまわり多く電気を使う。恐らくCore XクラスのCPUでも同じような事情だろう。 TDP95WのA10-7870Kは80-140Wといったところ。性能の割にかなり電気を使う、という印象だが、それでも消費電力は少なめだ。

「性能が高い割には普通に使っていればエコで、いざとなれば高性能」というのはなかなか魅力的だ。 ただ、デュアルソケットなので素の状態でも割と消費電力は高く、ピーク性能があまりないため、Core i7と比べて良いのか、というと難しい話になってくる。 Core i7マシンでこのような細かい測定をすることがないためわからないのだが、Core i7のほうが全方位に渡って良い、という可能性は普通にある。

Xeon Gold 6138は1機30万円ほどするのだが、比較可能なベンチマークとしてはOpenSSL Signが2500を越える程度であるのに対し、Ryzen Threadripper 2990WXが5862に達している。

なお、Passmarkスコアはまるで伸びず、23927点にとどまる。 これはInterger Maths, Floating Point Mathは7980XEにダブルスコアをつける一方、Prime Number, PhysicsはRyzen 7 2700と同等以下、ということでこのスコアになっているらしい。

Cinebench R15ではXeon Gold 6138が3069点、Ryzen Threadripper 2990WXが5267点。

つまり、性能的にはXeon Gold 6138と比べても2990WXは「下手すれば倍」という性能である。 CPUを2機積んでも「倍」にはなかなかならないので、Xeon Goldに換装しても2990WXに届かない可能性は高い。

そしてお値段が、GELLERIA TRZ(2990WX + GTX1080Ti)が60万円、V-SPECではGTX1060と組み合わせて50万円、サイコムはGT710と組み合わせて42万円、2x GTX1080 SLIで60万円といったもので、「Xeon Goldへの換装をするくらいなら2990WXマシンを追加するほうが良い」という判断が働いている。

消費電力の比較

まずはP720のスペック。スピーカーやディスプレイなどのパワードデバイス、キーボードとマウスは含めていない。

P720
パーツ 使用部品
CPU 2x Intel Xeon Bronze 4114
メモリ DDR4 ECC Registered 16GB
ビデオカード Nvidia Quadro P400
ディスク NVMe SSD, SATA3 SSD, SATA3 2.5" HDD 5400rpm, SATA3 2.5" HDD 5400rpm
NIC Intel GbE(l219-LM), Intel GbE(l210)
その他 デバイス NI Audio4 DJ, TASCAM US-366
電源 900W Gold

比較対象は2015年のエントリーグレードのPCであるAMD A10-7870K (Godavari) APU搭載マシンである。

A10
パーツ 使用部品
APU AMD A10-7870K
メモリ DDR3 32GB
ビデオカード APU内蔵
ディスク SATA2 SSD, SATA2 3.5" HDD 5400rpm
NIC Atheos GbE
その他 デバイス
電源 750W Bronze

もう一台は先代メインマシンであるhp Z400 Workstation。 2010年のメインストリームワークステーションで、性能的にはA10とあまり変わらない(若干良い程度)。 CPUはXeon W3565()

Z400
パーツ 使用部品
CPU Intel Xeon W3565
メモリ DDR3 ECC Unbuffered 24GB
ビデオカード Nvidia Quadro 2000
ディスク SATA3 SSD, SATA3 2.5" HDD 5400rpm
NIC Broadcom GbE
その他 デバイス SATA3 DVD Multi
電源 500W

実際の計測。 P720についてはデフォルトの電力プランがpowersaveで、performanceとの差が大きいため、起動後についてはperformance時のものも記載する。

消費電力(W)
条件 P720 P720 Performance A10 Z400
電源投入時 132 70 128
Grub起動時 125 148 127
Grub LUKS 耐機中 132 167 134
ログイン アイドル 76 48 84
Cinnamon アイドル 70 71 50 121
Firefox起動中 101-126 131-140 86-117 147-175
GPU Test (FurMark) 110 93-135 93 133-146
フルロード 193 192 168 219

ManjaroはGrubでLUKSを解除する仕組みだが、このときパスフレーズを入力せずに放置すると果てしなく電力を使う、ということが分かっている。

フルロードは動画ファイルをxz -t 0 -zce > /dev/nullをコア数行うという方法で試している。 CPUとGPUの両方をフルロードにするテストは、マシンへの負荷や温度的な理由からしていない。

参考として、STH(Server The Home)でXeon Gold 6138の消費電力が示されており、

  • Idle: 75W
  • 70% Load: 203W
  • 100% Load: 232W
  • Peak: 241W

とのことである。(208Vの電源を使用) 4114と比べるとだいたい倍ぐらい、という感じだろうか。STHでは4114について、最大で101Wに到達したことが書かれている。

Akiba PCの記事では Core i7-6700Kの高負荷時システム電力が128.1Wとあり、6950Xで175.1Wとのことだ。

また、Core i7-8700Kユーザーの報告で、アイドル時21W、高負荷時135Wが報告されている。

もう少し詳しい話として見るとマイナビニュースで8700Kや1800Xの計測がされていて、これを見ると80-220Wという感じだ。ちなみに、これはGTX1080を載せているらしい。

やはりメインストリームワークステーションのZ400はP720よりも一回り消費電力が大きい。 また、Z400は消費電力が上がりやすく、実用しているとだいたい130W前後で動作する。P720は85W程度であるため、結構差が大きい。

さらに、Xeon W3565のTDPが135Wなのに220Wに達するのは「TDP越えてないか?」と大変心配になる。 Z400は水冷であり、冷却容量はそれなりに余裕があるので問題になっていないが、これはきつそう。

期待したほどではないが、基本的に余裕をもってP720は常に省電力である。 Xeon Gold 6138 2x + SLI GTX1080Tiというような構成も考えていた(これだけでTDPは750Wに達する)のだが、結局900W電源は過剰だったようだ。

総括

まず、前提となるのが、P720は「仕事用」である。 継続的に、効率的に仕事ができることが大切なのだ。

だから業務継続性においてのみ重要視したWindows 7が動作しなかったのは、選択理由をそもそもゆるがすようなもので厳しい。 ワークステーションのほうが動作が安定している、といった点を重視したのだが、この点もいまひとつでこれらの「P720が期待したように動作しない」という点がなにより不満をもたらしている。 これでコンシュマークラスには到底実現できないような性能であればまだ納得するのだが、単純な性能面ではあまりアドバンテージがないため、「単純に高かった」という印象になってしまう。

しかし、それを理由に公開したり残念に思えていないのは「特に不満はない」という点が大きい。

Windows 7は結局思ったように使えなかったが、KOMPLETE 9 ULTIMATEがWindows10に対応したこと、Sonar X3 Producerが「だいたい動いた」こと、SONARが廃止になって、それに備えてAbility 2.5 Proを導入したことなどから「Windows 10でも一通り使える」状態になった。 音楽制作系以外の環境と混在させることには不安もあったが、とりあえず問題は生じていないのでこのまま使っていけそうである。

現環境においてはいくつかの不具合(特にフロントパネルのUSB問題)があるが、Linuxで運用していて致命的なわけでもない。 Windows 10のほうでもASIOドライバをインストールするとフリーズするという問題があって血の気が引いたが、こちらはWindows Updateで解消した。

通常の利用では当然ながら性能が不足するということはない。 シングルスレッド性能が非常に低いため(A10よりちょっといいくらい、コンシュマープロセッサではPentium Goldよりずっと低い)動作快適性は微妙だったりするのだが、Linuxであれば変につっかえることもないし(Windowsだと起動後しばらくや、突然はじまるWindows Updateで使い物にならないほど止まる)、私の場合は多くのプロセスを動作させるためひょんなことで一時フリーズしたりしていたのだが、それもなくなって快適になった。

もちろんリソース総量的にコンシュマーCPUで足りる可能性もあるが。

拡張性に関してもコンシュマーCPUよりは有利なのは確かで、価格差をさておけば特にコンシュマーCPUのほうが良かった、という感じはない。 価格差を含めるとCore i9-7920X+GTX1080のゲーミングPCという選択肢があったため、性能面では残念な部分もなくはない。だが、Core i9-7920Xマシンとはかなりの性能差があることはわかりきっていたので、コンシュマーCPU比では性能ではなく可用性に料金を払ったと考えて良い。

Xeon 4114の性能はおおよそ「並列化すれば最終的には速い」というまんまのもので、使いこなしは難しい。 あるひとつのことを実行したときにかかる時間は「Celeronよりはマシ」という話でしかないため、これでは速さを感じることはできない。実際にはそこまで時間がかかる処理は並列化されていることが多いためまぁまぁ速く終わるのだが、なにもかもが一瞬という速さではない。 そのため、この性能を活かすにはなるべく同時に複数の処理をし続けて、「24時間あたりの処理量は多い」というような内容になる。 ざっくり「Celeron G3920マシンを5台用意すれば1台のCore i7マシンよりたくさんタスクを消化できる」というような話だと言えば難しさが伝わるだろうか。

Celeron G3920マシンを5台用意するよりはずっと省電力なので、効率は良い。だが、その性能を生かせなければ効率などあったものではない。 普通の人には到底お勧めできるものではない。

私は近年、“Orbit”と呼ぶデザインを採用している。 これは作業概念を小さなスクリプトにし、網羅的に処理するということをタスクスケジューラによって繰り返し行うものだ。 処理自体は軽いが並行で多数の処理が走り続ける。このデザイン自体はXeon 4114プロセッサと非常に相性がいい1。だが、軽い処理では4114プロセッサを使い切ることは到底できず、かといって重い処理(例えばffmpeg)はOrbitデザインに組み込めないほど時間がかかってしまう。 また、現状ではOrbitデザインで作られているスクリプトも最大で5スレッドしか生成しないため、性能を活かし切るにはより多くのスレッド(というよりも任意の数のスレッド)が生成できるデザインに変更する必要がある。 ただ、OrbitデザインはIOの比重が高いため、あまりシークに時間のかかるHDDには向いておらず、恐らくプロセッサ性能が向上しても効率はよくならない2

Xeon 4114の真価を発揮するのはこのスクリプト群を改良してからになるだろう3

最大の誤算は「Xeon Gold 6138の2台分に匹敵するトータルパワーと、Xeon Gold 6138と同等のコアパワーを備え、1ユニットで32ものコアを持ち4、我がP720と変わらない値段で搭載機が買える」Ryzen Threadripper 2990WXの登場である。 さすがにあれと比べると何もかもがどうしようもない。

だが、2990WXが誰にでも勧められるかというとそうでもなくて、まず性能は著しく過剰だし、性能を必要とするゲームにはあまり向いていないので、ゲームではない部分で非常に高い処理性能を必要としている人のみが適する、となかなかハードルは高い。2950Xのほうなら、ゲーマーを含めた高性能PCを必要とする人に勧められるのだが。

P720、というかXeon Scalable Processor Family搭載マシンについては何度か相談されているのだが、明確に用途が答えられない人にはとても勧められないし、「速い」ことを期待しているならそれも勧められない。 クリエイター系の人についても、コア性能が低くてレスポンスがあまりよくないので勧められない。実際このマシンでGimpやShotcutなんかを動かしていると決して快適ではないと感じる。 可用性とコアの数が重要になる場合だけ、お勧めできる。


  1. Xeon 4114プロセッサは「コア数優先、コア性能はすごく低い」というプロセッサである。Orbitデザインは多くの場合処理は軽いため性能が高くても活かすことができないが、条件によってはかなりの数のプロセスが発生するためこのようなプロセッサはうってつけである

  2. ちなみに、Orbitデザインは大量のプロセスを生成するがすぐ終わってしまうため、forkにかかるコストが大きくそもそも実行効率はよくない。だが、開発やメンテナンスは容易で柔軟性が高い。

  3. なお、PureBuilder Simplyも1.6のうちに並列化スクリプトが作られる予定になっている。

  4. 32コアというのは、Xeon 4114のデュアルよりも多いのである。

ELECOM EX-G UltimateLaser MouseとLinux (未解決)

珍しく伝統的なLinux問題のお話をする。

私はELECOMのEX-G UltimateLaser Mouseを愛用している。

EX-Gシリーズは10個のボタンがあり、10番目はDPI変更ボタンになっているのだが、Ultimate Laser Mouseだけはファンクションボタンが3つある12ボタンマウスになっている。

せっかくなので、というか使いたい意図があって残り3つのボタンを使おうとしたのだが、 xevで見るとファンクションボタンが全部button 9になっている。 button 9は進むボタンに当てられていて、実際進むボタンとして機能する。

しかし、これでは困る。ドライバが間違っているのだろうか。 まずはデバイスがどう認識されているのか確認する。

I: Bus=0003 Vendor=056e Product=00d3 Version=0100
N: Name="ELECOM ELECOM UltimateLaser Mouse"
P: Phys=usb-0000:00:14.0-14.1/input0
S: Sysfs=/devices/pci0000:00/0000:00:14.0/usb1/1-14/1-14.1/1-14.1:1.0/0003:056E:00D3.0003/input/input4
U: Uniq=
H: Handlers=event4 mouse0 
B: PROP=0
B: EV=17
B: KEY=1f0000 0 0 0 0
B: REL=143
B: MSC=10
Bus 001 Device 010: ID 056e:00d3 Elecom Co., Ltd 
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            0 
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0         8
  idVendor           0x056e Elecom Co., Ltd
  idProduct          0x00d3 
  bcdDevice            0.01
  iManufacturer           1 ELECOM
  iProduct                2 ELECOM UltimateLaser Mouse
  iSerial                 0 
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength       0x003b
    bNumInterfaces          2
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0xa0
      (Bus Powered)
      Remote Wakeup
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      1 Boot Interface Subclass
      bInterfaceProtocol      2 Mouse
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.00
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      89
         Report Descriptors: 
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval              10
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 
      bInterfaceProtocol      0 
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.00
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      46
         Report Descriptors: 
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x82  EP 2 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval              10
can't get debug descriptor: Resource temporarily unavailable
Device Status:     0x0000
  (Bus Powered)

うぅむ、正しく認識されているようだ。 ドライバはどうなっているのだろう。

[    16.960] (**) ELECOM ELECOM UltimateLaser Mouse: Applying InputClass "evdev pointer catchall"
[    16.960] (**) ELECOM ELECOM UltimateLaser Mouse: Applying InputClass "libinput pointer catchall"
[    16.960] (II) Using input driver 'libinput' for 'ELECOM ELECOM UltimateLaser Mouse'
[    16.960] (**) ELECOM ELECOM UltimateLaser Mouse: always reports core events
[    16.960] (**) Option "Device" "/dev/input/event4"
[    16.960] (**) Option "_source" "server/udev"
[    17.017] (II) event4  - ELECOM ELECOM UltimateLaser Mouse: is tagged by udev as: Mouse
[    17.017] (II) event4  - ELECOM ELECOM UltimateLaser Mouse: device is a pointer
[    17.017] (II) event4  - ELECOM ELECOM UltimateLaser Mouse: device removed
[    17.076] (**) Option "config_info" "udev:/sys/devices/pci0000:00/0000:00:14.0/usb1/1-14/1-14.1/1-14.1:1.0/0003:056E:00D3.0003/input/input4/event4"
[    17.076] (II) XINPUT: Adding extended input device "ELECOM ELECOM UltimateLaser Mouse" (type: MOUSE, id 9)
[    17.077] (**) Option "AccelerationScheme" "none"
[    17.077] (**) ELECOM ELECOM UltimateLaser Mouse: (accel) selected scheme none/0
[    17.077] (**) ELECOM ELECOM UltimateLaser Mouse: (accel) acceleration factor: 2.000
[    17.077] (**) ELECOM ELECOM UltimateLaser Mouse: (accel) acceleration threshold: 4
[    17.134] (II) event4  - ELECOM ELECOM UltimateLaser Mouse: is tagged by udev as: Mouse
[    17.134] (II) event4  - ELECOM ELECOM UltimateLaser Mouse: device is a pointer
[    17.135] (II) config/udev: Adding input device ELECOM ELECOM UltimateLaser Mouse (/dev/input/mouse0)

Using input driver 'libinput' for 'ELECOM ELECOM UltimateLaser Mouse' …あぁ、そういえばManjaroはlibinputに移行していたなぁ…

⎡ Virtual core pointer                          id=2    [master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer                id=4    [slave  pointer  (2)]
⎜   ↳ ELECOM ELECOM UltimateLaser Mouse         id=9    [slave  pointer  (2)]
⎣ Virtual core keyboard                         id=3    [master keyboard (2)]
    ↳ Virtual core XTEST keyboard               id=5    [slave  keyboard (3)]
    ↳ Power Button                              id=6    [slave  keyboard (3)]
    ↳ Power Button                              id=7    [slave  keyboard (3)]
    ↳ FCL USB Keyboard                          id=8    [slave  keyboard (3)]
Device 'ELECOM ELECOM UltimateLaser Mouse':
        Device Enabled (151):   1
        Coordinate Transformation Matrix (153): 1.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 1.000000
        libinput Natural Scrolling Enabled (288):       0
        libinput Natural Scrolling Enabled Default (289):       0
        libinput Scroll Methods Available (290):        0, 0, 1
        libinput Scroll Method Enabled (291):   0, 0, 0
        libinput Scroll Method Enabled Default (292):   0, 0, 0
        libinput Button Scrolling Button (293): 2
        libinput Button Scrolling Button Default (294): 2
        libinput Middle Emulation Enabled (295):        1
        libinput Middle Emulation Enabled Default (296):        0
        libinput Accel Speed (297):     0.000000
        libinput Accel Speed Default (298):     0.000000
        libinput Accel Profiles Available (299):        1, 1
        libinput Accel Profile Enabled (300):   1, 0
        libinput Accel Profile Enabled Default (301):   1, 0
        libinput Left Handed Enabled (302):     0
        libinput Left Handed Enabled Default (303):     0
        libinput Send Events Modes Available (273):     1, 0
        libinput Send Events Mode Enabled (274):        0, 0
        libinput Send Events Mode Enabled Default (275):        0, 0
        Device Node (276):      "/dev/input/event4"
        Device Product ID (277):        1390, 211
        libinput Drag Lock Buttons (304):       <no items>
        libinput Horizontal Scroll Enabled (305):       1

やはり正しく認識されているけれど、ボタンの数は9だと思われている。

1 2 3 4 5 6 7 8 9 

しかしxmodmapでは10ボタンだと思われている。

There are 10 pointer buttons defined.

    Physical        Button
     Button          Code
        1              1
        2              2
        3              3
        4              4
        5              5
        6              6
        7              7
        8              8
        9              9
       10             10

何度も言うが、 Ultimate Laser Mouse は12ボタンである

自力解決できず、フォーラムに質問してみたのだが、回答はつかなかった。 (解決した場合はこの記事を撤回し、投稿し直す予定)

【まとめ特集記事】 ビデオカード * VDPAU / VA-API * ffmpeg

パッケージ名などはArch Linux/Manjaro Linux準拠である。

PRIME(異なるメーカーのビデオカード混合)の話はしていない。 (持っていないので) そのうちするかもしれない。

ffmpeg周りに関しては過去の記事には載せてなかった話も色々書いた大作になっている。 (特にAMD関連の情報やVDPAUなんかはドキュメントが少ないので有益なはず)

ビデオカードとドライバ

現在使用されているビデオカードは次の3メーカー。

  • Intel
  • Nvidia
  • AMD

Intelはコンシュマー向けIntel CPUに内蔵されているビデオカードである。 Intel CPUでもごく一部AMDビデオカードを内蔵したものもある。

NvidiaはGeForce/Quadro/Teslaビデオカード、AMDはRadeonビデオカード(AMD APU内蔵のものを含む)のことである。

ビデオカード ドライバー タイプ 現状
Intel intel free Supported
Nvidia nvidia non-free Supported
Nvidia nvidia-tesla non-free Supported
Nvidia nouveau free Supported
Nvidia nv free Deprected in 2010
AMD AMDGPU free Supported
AMD Catalyst non-free Legacy
AMD ATI/Radeon free Legacy
AMD radeonhd free Obsolated?
  • IntelとAMDのオープンソースドライバはメーカー協力のもと作られており、現状唯一の選択肢
  • AMDGPUは新しいドライバで新しいカードしかサポートしておらず、それ以前のものはATI及びRadeonドライバのサポート
  • プロプライエタリのCatalystドライバも更新されておらず、古いカード向け
  • nouveauドライバはメーカーサポートがないリバースエンジニアリングの賜物

ハードウェアビデオアクセラレーション

ハードウェア搭載機能

Intel

IntelはQSV(Quick Sync Video)という補助機能を搭載。 割とビデオが重かった時代から、ビデオを快適に再生できるようにビデオカードの力を借りて再生するものである。

そのため、QSVはビデオカードだけでなくCPUパワーも併用する。

NvidiaやAMDよりも非力だが、サポートしている形式が多く、意外と使いやすい。 また、画質がちょこっとだけいい。

Nvidia

Nvidiaはエンコード用のNVENCとデコード用のNVDECという2つの専用チップを搭載。 CUDAコアは利用していない。

IntelやNvidiaと比べ桁違いに高速。 GTX1080でFHD動画をH.264で1300FPS、H.265でも650FPSで処理できるという。

AMD

AMDはエンコード用のVCE(Video Coding Engine)、デコード用のUVD(Universal VideoDecorder)を搭載。 AMDも全然宣伝していなくて、情報がとにかく少ない。

VCEの速度的にはライバルNvidiaカードのNVENCの半分くらいが相場…らしい。 また、サポートしているフォーマットが結構少ない。あとからアップデートでサポートされたりもしているが。

Linux用のAPI

VDPAUはNvidia主導の、VA-APIはIntel主導のAPI。

VDPAUは再生のみ。VA-APIはエンコードもできる。

API エンコード デコード
VDPAU x o
VA-API o o

当然NvidiaはVDPAU、IntelはVA-APIをサポート。AMDはオープンソースドライバーでは両方サポート、CatalystはVA-APIのみ。

カード VDPAU VA-API
Intel x o
Nvidia o x
AMD non-free x o
AMD free o o

それぞれアダプタを使用してVDPAUをラップしてVA-APIで処理する方法や、VA-APIをラップしてVDPAUで処理する方法がある。 (libvdpau-va-gl及びlibva-vdpau-driver) これによってIntelでVDPAUを、NvidiaでVA-APIを処理できる。

VDPAUアダプタを使う場合、環境変数としてVDPAU_DRIVER=va_glする必要がある。

AMDの場合VA-APIとVDPAU両方をアダプタにすることが可能だが、それをするとエラーになる。 また、このVDPAUに対応させ、VA-APIをアダプタにするとエンコードはできなくなる。

nouveauドライバの注意点

nouveauドライバでVDPAUを使うにはプロプライエタリドライバのフォームウェアを流用したバージョンが必要で、 NVENCは利用することができない。

プレイヤーでデコード

VLC

ツール → 設定 → ビデオ → ディスプレイ → アウトプット → VDPAU出力 (もしくは自動)

ツール → 設定 → 入力 / コーデック → Hardware-accelerated decoding → VDPAUビデオエンコーダー or VA-APIビデオエンコーダー

SMPlayer

オプション → 環境設定 → 全般 → ビデオ → 出力ドライバー → vdpau or vaapi

GStreamer

gstreamer-vaapi (VA-API) 及び gst-plugins-bad (VDPAU) パッケージを導入

mpv

または

mpvの場合NVDECを直接叩くこともできる。

さらにCUDAも使える。

MPlayer

VDPAUの場合

VA-APIはフォークでサポート。mpvのほうがおすすめ

Xine

詳しくは

Dragon Player

できないっぽい。

Kaffeine

多分できない。

もしVLCがコマンドラインでVDPAUあるいはVA-APIの使用を受け入れるならなんとかなる。

FFMpeg

基本編

マルチメディアフレームワークffmpeg。だいたい動画を操作するときはスイスナイフのように使える。

まずは基本

ffmpegは出力の拡張子を見る。なのでちゃんと指定することが必要。

オプション指定は順序が決まっている。

ffmpeg [global_options] {[input_file_options] -i input_url} ... {[output_file_options] output_url} ...

おおまかなグループで間違えなければ大丈夫そうだけれども、順番が問題になることは覚えておくといいかもしれない。

それでは古いreal mediaを今風にH.264+aacのmp4にしてみる。

-c:v = -vcodec (video codec)で、 -c:a = -acodec (audio codec)。

これでは品質指定ができないので、ビットレートを指定してみる。

H.264で色々する

H.264はだいたい標準的なビデオフォーマット。 標準のソフトウェアビデオコーデックはlibx264。

libx264はビットレートではなく品質で固定する-crfオプションが利用できる。

-crfしていてもオーディオは固定することもできる。

速度が問題になるケースでは-presetが有効。 選択肢はx264 --helpで確認可能。

あまり使われないけれども有用なオプションとして-tuneがある。 主には実写用のfilmとアニメーション用のanimationを使うことになるだろう。 フィルムグレインを損なわないためにgrainを使うことも考えられる。

また配信用にはzerolatencyも有効だ。

2-passエンコーディングで画質が〜と言っている人がいるが、基本的に2-passエンコーディングはファイルサイズをより正確にするためのものである。 詳しくはこの日本語訳あたりを。

x265もだいたい同じような感じで使える。

さらに色々する

動画から先頭4秒を切り出す

開始30秒のところから5秒切り出す

以前は-ss-iより後のほうがよかったらしい。 また、エンコードしないと不具合が出るので-c:v copyはできない。

動画の開始10秒から10秒分を1秒あたり2枚で静止画に切り出す

動画をリサイズする

動画をクロップする

左上から200×200の座標を起点に、1600×900の動画で切り出す。

連番動画からGIF動画を生成

フレームレートは5FPSで作ってみる。

音声を遅らせる(早める)

音ズレを解消する。

次の例では音声を1.5秒遅らせる。

逆にビデオを1.5秒遅らせる

これは理解が難しいので解説。

-itsoffset 1.5 でその入力ストリームを1.5秒遅らせている。 2つ指定している入力ストリームが両方同じファイルなので、同じファイルがソースになっているのだけど、

  • 入力0は1.5秒遅れたinvideo.mp4
  • 入力1はそのままのinvideo.mp4

になる。

この入力0, 1, 2, 3…はあくまで入力ソースなので、これ自体は特にその動画のなにを使うということに影響はない。

ffmpegは複数の指定した入力ストリームをマージする。 単純に複数の-iを並べた場合、どうなるかはいまいち制御できないようだ。確かなのは、オーディオチャンネルのないビデオと、オーディオを入力ストリームとした場合、確実にそのビデオとオーディオが合成される。

基本的にはffmpegは#:0にビデオ、#:1にオーディオというファイルを作るようだ。 これは3つ以上のファイルをマージした場合でもである。

そして複数のビデオトラック、あるいはオーディオトラックを持たせるには-mapを使う。 例えば音声のないビデオinvideo.mp4とオーディオinaudio1.aac, inaudio2.aacがあったとして

では単純にinvideo.mp4のビデオとinaudio1.aacのオーディオが合成され、inaudio2.aacは無視される。 invideo.mp4が音声を持っていた場合はinaudio1.aacも無視される。

ここで-mapを使い

  • 入力0のストリーム0
  • 入力1のストリーム0
  • 入力2のストリーム0

を合成させる

ここで-map 0:0 -map 0:1 -map 1:0として、オリジナルのビデオに追加のオーディオトラックを合成する、というようなことも可能だ。

ソースは複数のストリームを持てるので、何番のストリームに何が入っているかはffprobe fileとすることで知ることができる。

さて、元の話に戻ろう。#:0がビデオ、#:1がオーディオの一般的なビデオファイルであるならば、同じビデオファイルをソースとする「1.5秒遅れた入力0」と「そのままの入力1」を合成したとき、入力0のストリーム0と入力1のストリーム1を合成すればビデオが遅れるし、入力0のストリーム1と入力1のストリーム0を合成すれば音声が遅れるわけである。

コントラストを上げる

mpvで2を押すほうが簡単なのであまり使わないけど、暗いところで撮影した動画をupする場合などには少しコントラストを上げたほうが見やすい動画になる。

さらにブライトネスもちょっと上げたいなと思ったらこんな感じ。

お手軽にビデオ/オーディオをなしにする

ノイズを避ける場合や抽出したい場合に使える。

ビデオなしのオプションは-vn、オーディオなしのオプションは-an。 サブタイトルなしの-snもある。

VDPAU/VA-API/NVENC

再生支援

VDPAUの場合。これはあまり資料がない。単純には

並列で複数のストリームを扱う場合は名前をつけよう。ここではvdpauストリームにfooという名前をつけて扱っている。

VA-APIの場合も同じ感じ。ただ、VA-APIデバイスの指定が必要。

複数扱えるようにするには名前をつける。

エンコード支援

VA-APIでは同じようにデバイスを指定し、ビデオフィルタでVA-APIにアップロードし、VA-APIハードウェアコーデックでエンコードする。

コーデックは「エンコードに何を使うか」なので、libx264を指定すればソフトウェアコーデックであるx264が使われる。 ここではVA-APIのハードウェアコーデックを使用する。

なお、A10-7870K (Radeon R7)をAMDGPUで使ったときは、-profile 578してあげないとうまくいかなかった。

VA-APIで利用できるコーデックはこんな感じ。もちろん、ハードウェアとドライバが対応していればの話。

フォーマット VA-APIコーデック
H.262 / MPEG-2 part 2 mpeg2_vaapi
H.264 / MPEG-4 part 10 (AVC) h264_vaapi
H.265 / MPEG-H part 2 (HEVC) hevc_vaapi
MJPEG / JPEG mjpeg_vaapi
VP8 vp8_vaapi
VP9 vp9_vaapi

VDPAUはデコード専用でエンコードには使えない。 Nvidiaビデオカードの場合、ffmpegからNVENCが利用できる。ただし、nouveauドライバでは不可。

H.265(HEVC)の場合はhevc_nvenc。オプションがちょっと違ったりする。

再生もエンコードも支援

VA-APIの場合は結構使うようだ。

基本的には組み合わせなのだけれど、出力フォーマットにvaapiを指定する必要があり、項目は2つ増えている。これはちょっと複雑。

NvidiaのVDPAU+NVENCはほとんど見かけないけれども、NVENCの使い方が単純にNVENCハードウェアコーデックを指定するだけなので、単純な組み合わせになる。

他のコーデックを使う

コピー

copyはビデオ、オーディオともに利用でき、エンコードを行わず単純にストリームをコピーする。

エンコードを行わないので劣化が発生しない。 「ビデオだけ加工したい」といった場合に多用する。

ビデオ

H.265(HEVC)

H.264よりもファイルサイズあたりの品質がいい。 特許問題でものすごくドロドロしているけれども、今のところ主流である。

ソフトウェアコーデックとしてはx265があり、libx265として利用可能。 オプションはほぼlibx264と同じ。

主流だけあって最新のハードウェアなら3メーカーともサポートしており、hevc_vaapihevc_nvencが用意されている。

コンテナは主にはAACと組み合わせて.mp4。それ以外を使うなら.mkv

VP8

Googleが推進していた、全然流行らなかったコーデック。

コンテナはOgg Vorbisと組み合わせてWebM。 品質はあまりよくない。

VP9

Googleが推進するコーデック。 H.265がドロドロしすぎているので、配信なんかでは結構使われている。YouTubeでも使われている。

指定方法がVP8と全然違う。 この方法だと変な品質のができるので

こっちのほうが安全。

画質はなぜか相当粗い。そしてサイズが非常に大きい。 あと、めちゃくちゃ遅い。なかなか思うようにコントロールできない。

コアあたりの速い16コアまでのCPU(具体的にはCore i7あたり)で、-thread 16 -speed 8とかやれば、耐えられないこともないかもしれない。

H.264のライバルらしいけれど、これをライバルと呼ぶのはちょっと無理がありすぎる。 特に低ビットレートになると差は歴然である。 高ビットレートなら意外といけるらしいが、今度は時間が耐え難い。

Intel QSVがVP9エンコーダを搭載しているのだけど、そっちを使うとさらにひどいことになる。

AV1

待望のH.265のライバルであるフリーなコーデック。

ffmpeg 4.0からついに投入されたのだけれど、私の手元では耐えるのは不可能な速度だったので、現実味はまったくなかった。 どうもlibx265と比べても時間は10倍ではきかない感じだ。 デコードも超重いらしい。

生ビデオにしてからaomencでやることはできた。 …といってもだ。

Pass 1/2 frame 3219/3220  618240B    1536b/f   23040b/s  207846 ms (15.49 fps)
Pass 2/2 frame   20/1      41244B  212969 ms 5.63 fpm [ETA 190:22:59] 1.771 40.510 45.055 49.142   41244F

このくっそ軽い動画で、5.63fpm(fpsではない。fpmである)。 190時間エンコードにかけるという。仮にも20コアXeonでだ。(aomencのマルチスレッドはゴミのようなものだが)

ふざけているのだろうか… libx265の10倍遅い、と言われているが、10倍どころではないだろう。だって、このマシンはlibx265でもだいたい30fpsくらい出るのだから。5fpmといったら、1/360のスピードである。

最終的には18fpm程度になり、3000フレームほどの動画を約4時間で済ませた(平均0.28fps)。

画質は明らかに粗い。とはいえVP9よりはマシ。 今更これを出されても、しかもこんなに重いのでは話にならない…という気がする。 100倍速ければ使う、という感じ。(平均すれば30fps出る程度)

オーディオ

mp3

品質は高くないけれど便利なMP3。

192kbpsのmp3を作る場合

-q:aするとVBRになる。小さいほうが高品位。

Ogg Vorbis

高品位かつフリーなコーデックとして人気のOgg Vorbis。 サポートされていることも多いので有力。vorbisよりlibvorbisのほうが高品位。

-qファクターは大きいほうが高品位。これはogenc-qにそのまま渡されるらしい。

ポータブルオーディオにはこれが良い。

Ogg FLAC

こちらもサポートされていることが多いロスレスのオーディオフォーマット。 ロスレスなので音質は損失しない。

CPUをたくさん使ってより圧縮することができる。 この圧縮レベルは音質には影響しないが、サイズの差は小さい。

容量に余裕があるなら使っていきたい。

Opus

SILK+CELTがベースになっていて低ビットレートではSILKのようにスピーチ用に可聴音域に特化し、高ビットレートではSILKベースのレイヤーを省いて高品位に再生するオーディオコーデック。

Opusは低ビットレートのHE-AAC、中ビットレートのAAC、高ビットレートのVorbis, AACと比べてより良い品質を提供する。 しかもフリーである。

素晴らしいのだけれど、動画では使いようがあるのに対して音声だと再生できるプレイヤーが割と少なくて困る。 WebMが標準でOpusをサポートしているのにAndroidがOpusをサポートしてないあたりもまた困る。

このため、Opusの出番は

  • ヴォイスレコーディング。 だいたい64kか92k。
  • もともと品質の高くないlossy audioの再変換。同ビットレートなら損失は微々たるもの
  • WebM。VP9との組み合わせが一般的。
  • H.264やH.265と組み合わせ、コンテナをMKVにする

H.265 + Opus の MKV は私の最近のお気に入り。 (ウェブカムのところを見て欲しい)

録音 with Pulse/ALSA

ffmpegがALSAに対応しているので簡単。

レコーディングするデバイスや調整はpavucontrolなどのPulseAudioミキサーでやると便利。

ウェブカム録画

Video4Linux2を使ってウェブカムからの録画が可能。 次の例ではウェブカメラデバイス/dev/video0から録画している。

音声も録音したいなら組み合わせ

カメラの場合はカメラが撮れるフォーマットでしか撮れない。 まずは確認する。以下は定番のLogicool C270。

$ v4l2-ctl --list-formats
ioctl: VIDIOC_ENUM_FMT
        Index       : 0
        Type        : Video Capture
        Pixel Format: 'YUYV'
        Name        : YUYV 4:2:2

        Index       : 1
        Type        : Video Capture
        Pixel Format: 'MJPG' (compressed)
        Name        : Motion-JPEG
% v4l2-ctl --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
        Index       : 0
        Type        : Video Capture
        Pixel Format: 'YUYV'
        Name        : YUYV 4:2:2
                Size: Discrete 640x480
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 160x120
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 176x144
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 320x176
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 320x240
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 352x288
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 432x240
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 544x288
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 640x360
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 752x416
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 800x448
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 800x600
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 864x480
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 960x544
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 960x720
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 1024x576
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 1184x656
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 1280x720
                        Interval: Discrete 0.133s (7.500 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 1280x960
                        Interval: Discrete 0.133s (7.500 fps)
                        Interval: Discrete 0.200s (5.000 fps)

        Index       : 1
        Type        : Video Capture
        Pixel Format: 'MJPG' (compressed)
        Name        : Motion-JPEG
                Size: Discrete 640x480
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 160x120
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 176x144
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 320x176
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 320x240
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 352x288
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 432x240
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 544x288
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 640x360
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 752x416
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 800x448
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 800x600
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 864x480
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 960x544
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 960x720
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 1024x576
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 1184x656
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 1280x720
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 1280x960
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)

センサー自体が4:3なので、一応仕様上は1280×720のカメラだと謳っているけれども、最大は1280×960。

画質をとってrawvideoの752×416

あるいは画質は劣悪だけれどもピクセル数重視でMotionJPEG。 もともとデータがMotionJPEGで送られてくるので再エンコードはいらない。

音声も録音するならOpusでMKVかな

スクリーンキャスティング (X server)

XのAPIを使って画面の録画ができる。

300×300のウィンドウを左上から200×200のオフセットで録画する場合

さらに録画領域を表示する場合

クリックしたウィンドウを録画する(zshスクリプト)。 さらにマイク録音も加えた。

コンピュータの音とマイクの音両方を録音したい場合。 環境に依存する箇所が多いので注意。

まずは確認。

$ pacmd list-sources

あとはこんな感じ

$ pacmd load-module module-null-sink sink_name=mixmic
$ pacmd load-module module-loopback source=alsa_output.pci-0000_00_1f.3.analog-stereo.monitor sink=mixmic
$ pacmd load-module module-loopback source=alsa_input.usb-046d_0825_D457DB60-02.analog-mono sink=mixmic

スクリーンキャスティングしている内容を仮想カメラにする (v4l2 loopback)

スクリーンキャスティング機能のないメッセンジャーで通話しているときにカメラとして使えることでスクリーンを写せるというメリットがある。

要v4l2loopback カーネルモジュール。

$ sudo modprobe v4l2 video_nr=1
$ ffmpeg -re -f x11grab -video_size hd1080 -i $DISPLAY -f v4l2 -r 60 -vcodec rawvideo -pix_fmt yuv420p /dev/video1

video_nrで作成するデバイス番号を指定している。 video_nr=1なので/dev/video1。4から6を作成したいなら video_nr=4,5,6

hd1080ってなんぞ、ということについては公式ドキュメント参照のこと

AMD APU (A10-7870K Godavari) * Radeon VCE * AMDGPU * VA-API * ffmpeg

理屈としては解説してきたものの、実際にVA-APIでVCEを叩いたことがなかったのでやってみた。 ついでなので、qsvやnvenc、あるいはlibx264などでも応用できるウェブカメラとスクリーンキャスティングの話もしておく。

基本的な手順は単純で、AMDGPU(事実上現在唯一となったAMDビデオドライバ)を選択した上で、 VA-APIを有効にし、VA-API経由でエンコーディングを行う。

注意点としては古くなったプロプライエタリドライバ(Catalyst)ではなく、AMDGPUドライバーを使用することと、 MESA VAドライバを使用することである。

RadeonはVA-API/VDPAUの両方をサポートしており、NvidiaのようにVDPAUドライバをインストールし、VA VDPAUアダプタを使用するという方法(libva-dvpau-driver)も成立してしまう。 しかし、この場合は動作しなくなるので、必ずMESA VAドライバ(libva-mesa-driver)を使用する必要がある。

その上で基本はこんな感じ。 (Arch/ManjaroのffmpegはVA-APIを含んでいるのでffmpeg云々の話はない)

$ ffmpeg -vaapi_device /dev/dri/renderD128 -i source.avi -vf 'format=nv12,hwupload' -c:v h264_vaapi -qp 24 -c:a copy outfile.mp4

ffmpeg上でのVA-APIは公式にドキュメントがある

ソースファイルがビデオアクセラレーションが効くのであればUVDをVA-API経由で叩いてデコードすることもできる。

$ ffmpeg -vaapi_device /dev/dri/renderD128 -hwaccel vaapi -hwaccel_output_format vaapi -i source.avi -vf 'format=nv12,hwupload' -c:v h264_vaapi -qp 24 -c:a copy outfile.mp4

ところがこれではうまくいかなかった。 一件成功しているように見えるのだが、フレームの全くないビデオファイルが出来上がってしまい再生できない。

多分、新しいRadeonだとそんなことはないのだろうと思うけれども、Godavari(2015年)のR7グラフィックスでは問題があったため、-profile 578を指定すると解決した。

$ ffmpeg -vaapi_device /dev/dri/renderD128 -i source.avi -vf 'format=nv12,hwupload' -c:v h264_vaapi -profile 578 -bf 0 -qp 24 -c:a copy outfile.mp4

ウェブカムからキャプチャする場合はエンコードのみ、入力はv4l2:

$ ffmpeg -vaapi_device /dev/dri/renderD128 -f v4l2 -i /dev/video0 -vf 'format=nv12,hwupload' -c:v h264_vaapi -profile 578 -qp 24 outfile.mp4

さらにマイクをPulseAudio経由で拾う場合。音声は192k AAC:

$ ffmpeg -vaapi_device /dev/dri/renderD128 -f v4l2 -i /dev/video0 -vf 'format=nv12,hwupload' -c:v h264_vaapi -profile 578 -qp 24 -f alsa -i pulse -c:a aac -b:a 192k outfile.mp4

X11のスクリーンキャスティング 音声つき。 A10-7870Kだとh264_vaapiは34fpsくらいなので、60fpsはフレーム落ちばかりになる。30fpsも無理で24fpsがドロップしない限界。 ultrafastにした場合は30fpsは可能だけれど60fpsは無理。

$ ffmpeg -vaapi_device /dev/dri/renderD128 -f x11grab -framerate 24 -video_size 1920x1080 -i $DISPLAY -vf 'format=nv12,hwupload' -c:v h264_vaapi -profile 578 -qp 24 -f alsa -i pulse -c:a aac -b:a 192k outfile.mp4

ultrafastで30fps:

$ ffmpeg -vaapi_device /dev/dri/renderD128 -f x11grab -framerate 30 -video_size 1920x1080 -i $DISPLAY -vf 'format=nv12,hwupload' -c:v h264_vaapi -profile 578 -preset ultrafast -qp 24 -f alsa -i pulse -c:a aac -b:a 192k outfile.mp4

なお、-video_size-iよりも先に指定することが必須である。基本的にffmpegはオプションは順番に厳しい。

300×300のウィンドウを左上から200×200のオフセットで録画する場合

$ ffmpeg -vaapi_device /dev/dri/renderD128 -f x11grab -framerate 30 -video_size 300x300 -i $DISPLAY+200,200 -vf 'format=nv12,hwupload' -c:v h264_vaapi -profile 578 -preset ultrafast -qp 24 -f alsa -i pulse -c:a aac -b:a 192k outfile.mp4

-video_sizeの指定方法は色々あって、公式ドキュメントで解説されている。 なので、-video_size 1920x1080ならば-video_size hd1080とも書ける。

録画領域を表示するには-show_region 1

$ ffmpeg -show_region 1 -vaapi_device /dev/dri/renderD128 -f x11grab -framerate 30 -video_size hd1080 -i $DISPLAY -vf 'format=nv12,hwupload' -c:v h264_vaapi -profile 578 -preset ultrafast -qp 24 -f alsa -i pulse -c:a aac -b:a 192k outfile.mp4

NVENCだとmkvにもできるので音声はFLACやOpusで撮ることもできるのだけど、AMDGPU VA-APIはmp4だけ

使ってみた感想としては、QSVと違ってCPUがあくのは良いけれど、R7の速度自体がCPUと大差ない(libx264でやったのと同程度)であるため、ちょっと微妙かもしれない。 A10でもスクリーンキャスティングしながら配信みたいなことができるというメリットはあるけれども。

(Linuxにおける) シャットダウンとリブートの違い

Twitterで、「Linuxでもシャットダウンとリブートは違うよ」という話をしたら、若干の反響があったので、軽く解説。

なお、私はこのあたりのことはそこまで詳しくないので、詳しい解説をすると多分間違えることからほどほどにしておく。

Linux上の仕組み

実は私が行っているのはLinux上でどうこうということではなかったりするのだけど、けれど若干違いはある。

Systemdの場合はsystemd-reboot.service

After=shutdown.target umount.target final.target

となっており、reboot.target

After=systemd-reboot.service

となっている。 でもって、じゃあsystemd-reboot.serviceはなにをしているかというと…

ExecStart=/usr/bin/systemctl --force reboot

そう、再起動はSystemdの場合組み込みである。

shutdownのほうは割と単純で、Conflicts=shutdown.targetBefore=shutdown.targetがあるので色々終了処理を行う。 shutdown.targetはそれだけの存在で、shutdown.servicesystemd-shutdown.serviceはない。

シャットダウン自体はSystemdに組み込みで存在し、reboot同様systemctl shutdownで良い。

ただ少なくとも、rebootとshutdownが分けられている、というのはわかる。

ハードウェア的に

ここからが私が言っていた話になる。

実際に再起動してみるとわかると思うのだが、普通のパソコンでは再起動しても電源が切れることはない。 そして、電源を入れるのと比べて速く立ち上がる。

ワークステーションや、一部の業務用PC(法人向けのモデル)だと再起動時に電源を切ったりするのだが。

そもそもシャットダウンした時点でプロセスはほとんど残っていないのだから、OS側から「電源を切ったら起動する」のような制御をすることはできない。 当然ながらこれはファームウェア的な動作であり、ファームウェア的にシャットダウンの状態とリブートの状態を分けていることがわかる。

一般的には再起動時はPOSTが省略される。 そのため、デバイス認識がバグっている状態(例えば接続されているキーボードが認識されていないとか)では再起動では修復されなかったりする。

ただし、BIOS/UEFI設定に言ってsave changesした場合は(通常は変更があったかどうかにかかわらず)POSTからやり直すようになっている。

電源を切るかどうかについては、メモリ(DIMMに限らず)に影響を及ぼすことから、違いがでる、かもしれない。

英語で、ものすごーーーーく詳しい説明を見つけたのだけど、再度見つけることができず掲載できない。

「LinuxにはIntel*Nvidia」は終わり、時代はAMDに

安定してきたAMD Linux

LinuxにおいてはCPUもビデオカードもAMDは非常に安定性がなく、「LinuxではAMDはリスキー、IntelとNvidiaが鉄板」という時代が非常に長かった。

これはWindowsにおいてもそんなものだとは言えるが、どちらかといえば性能とか好みとか思想の問題であり、AMDだと困るという要素は少なかったのだが、Linuxにおいては動作安定性という意味でもAMDは避けたい、という状況があった。

大きな問題としてはCatalystドライバのデキの悪さがあった。プロプライエタリドライバーとしてもNvidiaよりも後にサポートされてきたCatalyst(flgrx)ドライバーだが、様々な問題が発生していた。私が利用している限りでもXサーバーのフリーズ、マウスカーソルの文字化け、ティアリング、画面化け、X再起動の失敗、などなど枚挙に暇がない。

AMDがLinuxに力を入れるという選言をしたのは、Linux 4.6の頃であったと思う。 そしてAMDGPUドライバーが誕生したわけだが、実際安定性は高いものの性能はいまひとつであった。

そこから3年ほどが経過している。 Linux 4.18ではAMDGPUの改善が進んだ。Vega 20や、Intel Kabylake-Gプロセッサ(IntelのプロセッサにAMDのビデオカードが内蔵されている!!)といったデバイスサポートが主だが、AMDGPUドライバーそのものの改善も結構手を入れていた印象だ。 その結果AMDGPUドライバーは4.18の初期には性能が従来よりも低下していた(!)

AMD APU(Godavari)マシンに4.18を導入してみて驚いた。 アップデートごとにどんどんよくなっていたAMD環境だが、4.18は明らかに描画がスムーズになった。 ビデオ性能に関していえばNvidiaのほうが(私の手持ちでは)良いのだが、結局のところLinux利用の上での快適性は画面のちらつきや、フリーズの有無、あるいはビデオ再生に支障があるか…といったことに左右される。

結果的に性能は圧倒的に低いのだが、そうしたエラーが少ないAMDGPU環境が非常に快適に感じられてしまうのだ。 実際、ビデオ再生に関してもLinux 3.17あたりの再生と比べて明らかに快適になった。

現状、ビデオドライバーから見れば「AMDGPU > Intel > nouveau > nvidia」という状況になっている。 本当に力を入れてきたAMDドライバーの成果が、「とりあえずIntel安牌」という状況を靴替えしている。Nouveauもそれなりに安定しているのだが、基本的にはメーカー協力のない、リバースエンジニアリングの成果物であること、またNvidiaはLinuxドライバーにあまり力を入れていないことからこの滋養今日が生まれているのだろう。

実際にPhoronixのベンチマークを見るとRX580がGTX1060よりも良い結果を出していたりする。 (まぁ、一方でVega56がGTX1070に全然勝てていなかったりするのでドライバーの優劣を反映しているようにも見えないが)

現状、Nvidiaドライバーでの問題と言えば

  • Google Chromeはウィンドウ移動時にマルチディスプレイでは座標がずれる
  • 画面が激しく点滅することがある
  • ffmpegでの録画時にちらつく。Allow Flippingを無効にしてもまだちらつく
  • Wineが条件によって問題を起こす (nouveauでも)

あたりである。このほか、Xサーバーのrespawnの失敗、Blink系ブラウザにおいてコンソールと行き来したり状況によってはフリーズする、デスクトップエフェクトの反応が悪い、などがある。

そしてCPUもしっかりとパフォーマンスを発揮するようになっていて、4.18においてはXeon Silver 4114のpowersave governorよりもA10-7870KのほうがChromiumで高速に描画できる(シングルスレッド性能の差だ)。

性能と選択肢の改善

Ryzenによって向上した選択価値

A10-7870Kシステムを組んだときには随分と後悔したものだが、Linux側の改善によって随分と快適なシステムに進化してきた。 従来のAMD APUは使い勝手は良いもののその性能は悲しいほどしょうもなかった。

A10はAMD APUでも上級グレードだが、その性能はIntel Core i3に及ばない。 PentiumやCeleronよりは良いのだが、現在はPentium Goldに抜かれてしまっているほどだ。

AMDはAシリーズの上はゲーム向けとしてビデオカードを内蔵しないFXシリーズをラインナップしていた。 だかいくらなんでも「Aシリーズの上はゲーム用」というのはちょっと乱暴である。一般用途で確実に十分であるほどにはA10は性能はよくない(ただし、恐らく十分である程度には高い)。

ところが、現在はRyzen Gシリーズがある。 これは従来のAPU (Aシリーズ)を置き換える新しいAPUである。

少し複雑なので説明すると、第二世代Ryzenには、第一世代Ryzenと同じくビデオカードを持たないモデル、 つまり従来のFXと同じ「ゲーマー向け高性能プロセッサ」という位置づけだった。

しかし、Ryzen3/5/7というネーミングの通り、Core i3/5/7の直接的なライバルとなるラインナップであり、 Core i3をゲーマー向けプロセッサとするのは無理がある通り、AMDも考えを改めた。 さらにいえば、Aシリーズの不評っぷり(性能がとても低く、そのくせ消費電力は大きい)とRyzenの好評っぷり(いままでのAMDが嘘のようだ)を踏まえてもAシリーズを継続させていくよりさっさと仕舞にしたほうが良いと考えたのだろう。 結果RyzenシリーズはAMDの主力プロセッサシリーズへと転身した。

しかし、それはそれでややこしいことになった。 AMDの場合、Ryzenにはビデオカードを内蔵するGシリーズと、そうでないSTD/Xシリーズの2系統がある。 さすがにゲーマーはRyzen3を使わないと悟ったのか、Ryzen3はGのみ、一方ゲーマーでもなければRyzen7は使わないだろうと考えているらしくRyzen7はSTD/Xのみ、一方Ryzen5は両方ある。1

単にビデオカードの有無かというとそんなことはなく、Passmarkで見てみると

CPU Score Intel rival Rival score
Ryzen 7 2700X 16882 Core i7-8700K 15975
Ryzen 7 2700 15087 Core i7-8700 15217
Ryzen 5 2600X 14448 Core i5-8600K 12805
Ryzen 5 2600 13523
Ryzen 5 2400G 9264 Core i5-8500 12060
Ryzen 5 2400GE 8513 Core i5-8400T 9672
Ryzen 3 2200G 7331 Core i3-8100 8086
Ryzen 3 2200GE 7229 Core i3-8100T 7532
Ryzen 3 2300U 7172

RyzenのGEやU、またIntelのH/T/Uについては後述する。

また、Ryzen Proというのはセキュリティの追加機能があるものである。

このようにRyzen5 2400GはRyzen5 2600よりも下位グレードという扱いになっていて、Core i5と勝負できるのはビデオカードなしモデル、ということになっている。お値段的にもちょこっと2400Gのほうが安い。

この中でRyzen5 2400G及びRyzen3 2200Gは非常に魅力的である。

そもそもAPUという発想は悪くなかった。「別にそんなにCPUパワーはいらないだろうけど、動画見たり、たまにはゲームもするだろうし、ビデオ性能はそれなりに高いほうがいいだろう?」という考え方にはとても同意できたのだ。だが、Aシリーズは「そんなにない」というか「あまりにもない」というのが現実であって机上の空論に終わっていたのだ。

ざっくり、RyzenになってAPUは「2倍のパワーになった」と考えれば良い。さすがに2倍も速いと話は変わってくる。 HEVCのエンコードにも対応した最新ビデオカード(後述するvegaである)を搭載しながら、2倍速くなったAPUは普通の人にとって本当にいいバランスになっている。

普通の作業にはRyzen5 2400Gのパワーは十分だし、軽作業ならRyzen3 2200Gは悪くない。そしてビデオ性能のほうはIntelはいささか不足気味だ。 大きなポイントとしては、IntelのQSVはCPUパワーをかなり使う。これは動画見ながら作業することは考えにくいラップトップではあまり気にならないが、デスクトップの場合、特にマルチディスプレイ環境では足かせになる。 また、コンシュマークラスのIntel CPUの場合依然として「動画エンコード中は他の作業が難しい」という状況が発生する。 人によっては些細な違いに思えるかもしれないが、実際は使い心地に影響を及ぼす可能性がある。

また、自作する場合はAMDのマザーボードは非常に高機能なものや安価なものが揃うという点も見逃せない。 実際、私のA10システムは豊富なUSBサポート、8つのSATA、S/SPIF端子を持つオーディオなど豊富な機能によってデスクトップユースで一線級ではなくなったとしても様々な使い途が残る。

強力なシステムも組めるようになった

Core iと比べたとき必ずしもRyzenは魅力的なわけではないが、AMDのプロセッサの性能が大幅に上がったために、高性能が求められる局面でもAMDという選択肢が加わった、という点が大きい。

さらにThreadripperに至っては文句なしに強力である。

だが、CPUに関してはあからさまにLinuxにおける利があるわけではない。 ビデオカードの話をしよう。

現在のAMDのビデオカードラインナップはちょっと複雑で、やや古いRX 400シリーズはPolaris10, メインストリームのRX500シリーズはPolaris20、ハイクラスのRX VegaはVegaと設計が異なる。 さらにメインストリームはVegaにならずPolaris30になり、ゲーム用はVega20になってからメインストリームがNaviに、ハイクラスはNavi20になる、と噂されている。 (つまり、Navi登場までの間をメインストリームはPolaris、ハイクラスはVegaのままプロセス微細化されたものでつなぐらしい)

ところがAPUに搭載されているのはVega。Vegaのほうが新しい。取り残されているRX500がすごくいまいちに思えてしまう。

しかしここには罠があって、Linuxでは(Windowsと比べても)性能的にVegaがいまいち振るわず、Polarisのほうが良い結果を残している。 AMDGPUドライバが新しいVegaの性能を発揮できていないのかもしれない。

ともかく、Ryzen 7 2700X + Radeon RX580, Ryzen Threadripper 2950X + Radeon RX Vega 56, Ryzen Threadripper 2990WX + Radeon Pro WX 8200のような強力なシステムを組めるようになったわけだ。

Radeonの重大な欠点だったHEVCエンコードも対応しており、NVENCほどではないもののVCE/VA-APIでかなり高速にエンコードができる。

APUによる省コストなシステムだけでなく、パワーを必要とするシステムにおいてRadeonを使う、ということが現実的になったのだ。 もちろん、これはIntelプロセッサと組み合わせても構わない。

省電力システム

AMDはいつの時代も電気を食うものだった。 さすがにそれが終わりを告げた、とまでは言わないが、Intelの高性能プロセッサがTDPを越える電気を使ってしまう中、 Threadripperは実質的なワットパフォーマンスでの逆転を見せた。

そんな新時代のAMDとして推したいのがRyzen 5 2400GEである。

Intelの場合H(省電力), T(超省電力), U(超低消費電力)とラインナップされていたりするのだけど、AMDの場合GEはT相当と考えてよさそうだ。

2400GもcTDPで35W/45W/65Wということらしいけれど、そんなややこしいことは置いといて、2400GEは35Wである。 35Wだけどベースクロックは3.2GHz。ここらへんのCPUは割と容赦なく電気を使うので、まったり処理してほしい低消費電力システム(特にホームサーバー)ではすごく便利だ。

それだったらIntelのTでも良さそうに思えるけれども、前述のようにビデオカードが強力である。 ホームサーバーとして使うなら動画処理性能は重要な項目となりえるし、デスクトップとして使うなら描画環境は重要であり、AMDのほうが快適である。

もちろん、これは「Linuxで使うラップトップでAMD優位」という状況でもあると言える。 (もっとも、絶対的な消費電力の問題があるから話はそう簡単ではなくなってしまうが)


  1. この考えはとても正しい。多くの人はCore i3で満足できるが、ゲーマーはCore i3では足りない。一方、多くの人はCore i7を必要としていない。

Pandoc Markdownで任意の要素にクラス/IDを指定する

2017年初頭に追加されたがPandoc ユーザーズガイド (日本語版) には反映されていない機能。

従来もヘッダー及びフェンスコードブロックにはクラスやIDを書くことができたが、汎用のdiv/spanで書けるようになっている。

任意のブロック (div)

次のように書くことでdivで囲んで someclass クラスを付与することができる。

また、次のようにして someId IDを付与することができる。

クラスとIDの両方をつけることもできる。

任意のインライン要素 (span)

同様にインラインでもつけることができる。

インラインコード

インラインコードでもつけられるようになった。

蘇ったFreetype2 Infinality

Archの人たちは本当に熱心だ。

Infinalityといえば、フォントの美しさにこだわるLinuxerにとってかけがえのないキーワードであり、定番テクニックだった。

FreeType2が2.7になったとき、同時にInfinalityも消滅した。

これは、FreeType2がInfinality相当のフォントレンダリングを取り込んだから…でもあるが、実は作者失踪のため、でもある。 FreeType2がInfinality相当のサブピクセル計算方法を取り込んだから十分だと考えたのか、それともやる気を失ったのか、いずれにせよ公式にInfinalityの役割を終了することなく…つまり、Infinalityのまざまな機能は取り込まれなかったが計算式だけは取り込まれる形でInfinalityは消滅した。 もちろん、Infinalityはそれ以前に終わっていたのだが、FreeType 2.6の間は機能していた。2.7になって互換性がなくなり、機能しなくなったのだ。

これに対して不満を持つ人は多かった。

まず、Infinalityが終了したことに気づかず、トラブルに巻き込まれた人、というのがとても多い。

そして次に、FREETYPE_PROPERTIES="truetype:interpreter-version=38"は十分ではないと考えた人もまた、いたのだ。

実際、私もFreeType 2.6 InfinalityからFreeType 2.7になってフォントレンダリングの質は落ちた、と感じた。 だが、upstreamの方針ならそれもまた致し方なし…と考えたのだ。

しかし、そうではなかった。 FreeTypeはInfinalityの機能を取り入れる予定はなかったし、別にInfinalityパッチが不要のものになったわけでもなかった。

そしてついにFreeTypeパッチは蘇った。

AURにあるfreetype2-infinalityはFreeType 2.9に対応した新しいInfinalityパッチつきFreeTypeである。 cairo-infinality-ultimate, fontconfig-infinality-ultimateが新たなる対応ソフトウェアとして登場している。 なお、Java用のInfinalityパッチとlib32のFreetypeパッチは投げ捨てられたままだ。

freetype-ultiamte5はInfinalityではない、さらに別のパッチである。 TomaszGasior氏の作で、Infinalityを使わず、直接にFreeTypeにパッチを当て、Infinality Ultimate5相当のレンダリングを得ているという。 fontconfigやcairoにinfinalityパッチを当てる必要もない、なかなか効率的なパッチだ。

FreeTypeはClearTypeのフォントレンダリングを取り込もうとしているらしい。 だが、特許上の問題から今のところ難しいらしい。

この機能自体は実装はされていて、しかし有効にできないオプションとなっている。

Technically, no. The patents cover the whole process of generating and displaying sub-pixel images. Since the font engine doesn’t do the display part, it cannot infringe. Apart from that, FreeType has provided the capability of converting vector shapes into un-filtered sub-pixel images for a long time.

By default, FreeType’s scan-line converter returns ‘gray’ sub-pixel images, where for each pixel the color components are equal (this is, R=G=B). The result is visually identical to gray anti-aliasing and cannot infringe any of the ClearType patents.

Similarly, the LCD-specific filtering API is disabled by default, which means that it returns an error and doesn’t alter sub-pixel images.

You can override these limitations by activating option FT_CONFIG_OPTION_SUBPIXEL_RENDERING in FreeType’s ftoption.h configuration file, but you should do that at your own risk.

この機能を(自己責任において)有効にした状態でビルドしたものがfreetype2-cleartypeである。

そしてこのいずれも、最も劣悪にまで落ちてしまったLinuxのフォントレンダリングを改善してくれる。

リスク順に考えてみよう。

freetype2-cleartype

特許上の問題がある。設定オプションを変更しているだけなので、Infinalityパッチ環境で2.7に上がったときのような問題は起きないと思われる。

技術的には最も安全。特許状の問題は、個々の環境で有効にする分には問題はない…?

freetype2-ultimate5

小規模なパッチで、取り残される心配は作者が投げない限りはなさそう。

動作もinfinalityに比べれば軽く、戻すのも比較的簡単。 ぜひともupstreamに取り込んで欲しい逸品。

freetype2-infinality

fontconfigとcairoにも依然としてパッチを当てる1必要がある。 動作も重く、やや不安定。

現状では問題なく動作しているが、リスクは最も高いように思われる。

freetype2-ultimate5とinfinalityパッチは関係がないはずだか、freetype-ultiamte5 + fonconfig-infinality-ultimate のほうが美しいように感じた。

なお、これらのパッケージはAURのものであり、Arch、あるいはAURを利用する他のディストーション(Anterogos, Manjaro)以外においては導入は難しいかもしれない。


追記。実際に比較してみた。

設定を全くせずにインストールだけするとfreetype2, freetype2-cleartype, freetype2-infinalityの結果は全く同じだった (composite -compose Difference afile bfile difffileidentify -format "%[mean]" difffileで確認)。

freetype2-ultimate5は異なるレンダリングをしている(見た目にも明らかに濃い)が、fontconfig-infinality-ultimateによる違いはなかった。

繰り返すが、これはあくまで「設定は一切せずに」比較している。

ただ、結局はfreetype2-ultimate5がよさそうだという感触なのだが。

FreeType2 ClearType option
FreeType2 Ultimate5 patched

  1. FontConfigのほうはpatchというか、/etc/fonts/conf.avail.infinalityを作ってこれにリンクを張るものだけれども

Webページを単一のHTML (data, BASE64形式) に保存する

webページを保存するのにwgetは便利なのだけど、最近のウェブページは非常に複雑なので大量のファイルが生成されることがある。

もちろん、単純には

$ wget -p -k -E URL

でいいのだけど、ちょっと使いづらい。 単純にページを保存したい場合には、「そうじゃないんだよなぁ」と思うことがある。

あるいはテキストページなら

$ w3m -dump URL > file

という手もあるけど、これも画像が入っていたりレイアウトされていたりすると「そうじゃない」となる。

mhtmlは扱いづらいし、せっかくdata形式で埋め込めるのだから、画像やCSSを埋め込んだHTMLファイルを作ってほしい。

なんかないものかと探したところ、zTrix氏によるwebpage2htmlというプログラムが見つかった。

これがなかなか秀逸。

python webpage2html URL > file

でいいので話が早い。依存関係もpipで解消できる。 (requirements.txtも用意されている)

自動化が困難な場合にはwgetと組み合わせて二手間ほどかければ大丈夫だろう。

完成度はそこそこ。 今わかっている問題としては、サーバー側でcharsetを返さない場合、HTML内に書かれていたとしても文字エンコーディングを識別できず文字化けする。 指定もできない。

Pythonは内部文字エンコーディングに変換するため、ここでバグってしまうのだろう。 やっぱりwgetで落としてきて自前ウェブサーバーで指定するような手間が必要になる。

すごくいいツールなので、ぜひ育てていってほしいところ