2021-12-31

2021年に買ったもの

Google Pixel 4a

XPERIA XZ2 Compactを使っていたのだが、3度目の修理になったタイミングでメイン端末の代わりとして購入。XPERIA XZシリーズはほんと出来が悪かったし、ドコモ経由で買ってたので、修理代が非常に安く、あれでは元を取れてないのではと思うものだった。

Googleはこのくらいのミッドレンジの端末が一番コスパいいと思うので続けてほしいと思う。そもそも昔のNexusのときと違ってAOSPそのままではなくなってるし、どれがリファレンスなんだかわからなくなってはいるが。

HiFive Unmatched

2020年にオーダーしたものだったけど、5月くらいに到着。Mini-ITXなケースと電源、AMDのPCIeなGPUを用意すると、普通にLinuxが実用速度でボートするRISC-Vボードなので、いろんなコードを試しにポートしてみた。今年くらいにリリースされるようなSoCだと今度はSIMDとかCrypto Extensionとか実装されてそうし、新しいSoCが入ったボードが出たら買うだろうな。

TP-Link 5ポート 2.5Gbps ハブ アンマネージ スイッチングハブ TL-SG105-M2

コスパはいいTP-Linkが最安クラスの2.5Gbpsハブを発売したので、早速購入。結構熱は持つけど、速度としては安定してる。そういえば、自分が100Mbpsなハブを買ったのもこのくらいの値段になったころだったなぁと思い出した。

SwitchBotスマート加湿器

部屋が乾燥してて朝起きると喉の調子がわるいので、購入。加湿器を買うんだったらくだらないものを買おうと思い、SwitchBotにした。はっきりいうと加湿器なんてずっとつけっぱなしだし、タンクの水がなくなっているという情報をスマホで見ても、だから?って感じなので、スマホとかからコントロールするような機能は改めていらないなと。

ネスカフェ ドルチェグスト MINI ME

家でコーヒーの飲む時は一杯毎ドリップして飲んでいたのだけど、面倒になって、コストコでMINI MEを購入。自分のような面倒くさがりな人にとってはこういうカプセルのものが理にかなってた。

山善 エアフライヤー YAF-C120

普通の電気フライヤーは持ってはいるのだけど、油の処理がもったいない気がしてて、エアフライヤーで代替できないかと思って購入。はっきりいうと中途半端過ぎて、代替にならなかった。200℃だと微妙に温度が足りない感。たしかにフライドポテトとかは簡単にできるのだけど、その程度かなぁ。今後も使い続けるかは微妙。

2021-11-30

Web Speech APIのSpeechSynthesisEvent.elapsedTimeは秒を返すのだけど

バグレポートを受け取って気づいたのだけど、SpeechSynthesisEvent.elapsedTimeは秒を返すのが正しい。ただほとんどのブラウザがこの値を秒で返していなかった (例外はFirefox for Linuxくらいかも)。なので、Safariも最近直っていたので、Firefox側も直した

ここまでは普通の話なのだが、バグ報告をした人がChromeでも同じ問題が起きるとしてバグを報告したのだが、このバグが滑稽。Chromeはバグを受け付けるとQAが出てくるのだけど、そのQAがまずWeb APIの仕様を理解してないし、理解しようともしない。その人を乗り越えないと、Bug Triageさえちゃんとやってくれないようで、バグを認識させるためにはそのQAが投げ出すまで付き合ってあげないといけなくて、非常に無駄なコストがかかる。google.comじゃなくてchromium.orgのメアドを使っているからどこかのベンダーなんだと予想してるのだけど、そうだったらもっとまともな会社使おうよと、Google。

そもそもWeb Platform test (wpt) でTest failure発生させられる話だったら、そういうテストケースを書いておいて、さくっとwptに入れちゃうのだけど、このissueに関してはwptを書きようがないので、まぁChromeチームはずっと放置すると読んでる。

なお、Bug Triageに関してはMozillaは詳しい人かチームマネージャがやるので、大概ちゃんとした人が見ることになることが多い。こんな感じでBug Triageをちゃんとやらない製品はバグ修正とかにコストかけない (または評価システム上、評価されない) だろうなぁと勝手に思ってる。

2021-10-08

いまさらながらAndroidのAutofill Frameworkの困った話

AndroidのAutofillというのは、カスタムコントロールを使わないアプリにとっては実装は難しくはないのだが、カスタムビューを実装しているアプリでは、自分でいろいろな情報を提供しないといけない。実際には、自動入力用にアプリを最適化するに書かれているように、システムがAutofill用の情報を要求してきたら提供する、フォーカスの状態をシステムに通知するなどを追加実装する必要がある。

全部のアプリケーションでそのような実装しているとは限らないので、実装していないような昔のアプリケーション用にAndroidはおせっかいな機能を追加している。互換モードだ。これはアクセシビリティの実装を用いたautofillのエミュレーションを提供するもので、カスタムビューがアクセシビリティ機能の実装をしている場合は、それを利用してAutofill情報を設定する。そもそもアクセシビリティの実装しててAutofillの実装しないアプリがあるのかと問い詰めたいところではあるが。

この互換モードというのは自動的に切り替わるわけではなくて、Autofillサービス側で事前に設定をする。だから例えばアプリがAutofillの実装を入れたとしても、アプリ側からこの互換モードを無効にする方法は残念ながらない。この互換モードが動作してしまうと、アクセシビリティノードの走査が走ってしまうため、当然ながらパフォーマンス問題を引き起こす。アクセシビリティノードの走査はandroid.view.Viewの実装内で行われているから、該当コードを実行しないようにすれば、アクセシビリティノードの走査が実行されなくなるので、ある程度は回避可能ではある。残念ながらある程度ね。

この互換モードで実行しているかどうかは、こんな感じで調べられると思う。

public boolean isCompatibilityMode(Context context) {
  try {
    final AccessibilityManager manager =
      (AccessibilityManager) context.getSystemService(
                               Context.ACCESSIBILITY_SERVICE);
    if (manager == null) {
      return false;
    }
    final List<AccessibilityServiceInfo> serviceInfoList =
      manager.getEnabledAccessibilityServiceList(0);
    if (serviceInfoList == null) {
      return false;
    }
    for (final AccessibilityServiceInfo info : serviceInfoList) {
      if (info.getId().equals(
        "android/com.android.server.autofill.AutofillCompatAccessibilityService"
      )) {
        return true;
      }
    }
  } catch (final Exception e) {
  }
  return false;
}

アクセシビリティノードを走査させないようにしたとしても、互換モードは引き続きおせっかいなコードを実行する。この互換モードが動作する際には、CompatibilityBridgeと呼ばれるものがアクセシビリティイベントをウォッチするようになる (これについては無効にする方法はない)。そのためアクセシビリティイベントを発火させるとそれに応じて勝手にAutofillの互換コードが実行されてしまう。例えばAccessibilityEvent.TYPE_VIEW_FOCUSEDのイベントを受け取ると、AutofillManager.notifyViewEnteredを呼び指したりする。そのため内部でAutofillフォーカスがアクセシビリティノード上に移動する。たとえアプリケーションがAutofill情報を提供してたとしてもだ。AndroidのAutofillはフォーカスが移った際にAutofill用のリクエストをAutofillサービスに渡すので、互換モードでかつ、もしアプリがAutofillの実装をしてた場合、2度リクエストが飛ぶという困ったことになってる。

今どきのWebブラウザというにはOSのAPIはUI Processで実行される。Webコンテンツ内のアクセシビリティ情報をコンテンツのロード時にContent Processで集められ、集まった後UI Processへ送られる。アクセシビリティ情報の収集というのは非常に重い処理なので、UI Processへ送られるのは、ブラウザにとっては相当後になる。なので下手をするとAutofillフォーカスが予期もしてないアクセシビリティノードに奪われた状態でAutofillサービスがAutofillのUIを出したりしようとするので、ブラウザにとっては予期しない動作になりがちになる。例えば、Bug 1693152とかBug 1715549とか。

このように残念な互換モードを使っているAutofillサービスで有名なのはBitwarden。昔Bitwardenの開発者になんで互換モードに設定しているの?って聞いたけどよくわからない答えを返してきたので、今度こそどうにか止めさせるつもり。このような問題に引っかかるのはたぶん自分だけだと思いたいし、Androidはこの互換モードをアプリ側から止める方法を提供してほしかった。

なお、Bitwardenを使ってて、たまにChromeとかでもAutofillが動かないという話があれば、おそらくこのパターンの話。

2021-09-02

OSのIME関連APIとWebブラウザは相性が悪い

今どきのWebブラウザは複数のプロセスで動くことが前提になっている。Chromeで言えば、メイン(UI)プロセスとレンダラープロセス。Firefox用語であればChromeプロセスとコンテンツプロセスという感じで別れて動作している。Webコンテンツはコンテンツ用のプロセスで表示され、文字入力はUI用プロセスで動作している。だから入力された文字はコンテンツ用のプロセスへプロセス間通信で送られ、コンテンツ用プロセスで内部的に描画されるいることになる (実際に画面上に描画されるのがGPUプロセスだったりUIプロセスだったりするけど)。

今どきのOSで使われるIMEのためのAPIは入力された文字をただアプリケーションに渡すだけではなく、様々なことを要求してくる。例えば文字変換の精度を上げるために現在入力している場所周辺の文字情報をアプリケーションへ要求したり、文字変換用パネルウィンドウの表示位置を決定するために、アプリケーションが文字入力している表示座標の問い合わせをアプリケーションへ行ったりする。

Webブラウザは反応速度を上げるため、基本的にはブロッキングするようなプロセス間通信を許可しない (もちろん例外がないわけではないが)。プロセス間通信は基本的に非同期で行われてる。たとえば、コンテンツ用プロセスがビジーな状況というのは結構ありがちな状況で、その状況下で同期モデルなプロセス間通信を使うと、当然のことながら、そのプロセス間通信が正常終了するまでに長い時間がかかり、反応速度が非常に悪くなる。なので基本的には非同期なプロセス間通信を利用している。

この非同期なプロセス間通信のみを許可するというところが、非常にIME関連APIとの相性を悪くしている。なぜなら多くのケースでこれらのAPIが非同期API (例えば引数で渡されたコールバック関数経由で値を渡す) ではなくて、同期APIになってたりする。または、非同期的なレスポンス (エラーコードとして、今はPendingだからまた問い合わせてねというものを返す) を返すことが可能であっても、そのエラーコードを見てくれなかったりなど、まぁWebブラウザがこういうモデルを要求しているというニーズにIME関連APIがマッチしてない。APIデザインが最後発であるAndroidでさえ、残念ながらここらがすべて非同期になってない。

そんなこと言っていても、OS側がこちらの欲しいAPIを実装してくれるわけでもないので、ChromeもFirefoxもいろんな手を使ってこの状況下でもIMEを動かすようにしている。ただうまく行かないケースになった場合、例えばIMEの候補ウィンドウが間違った場所に表示されてしまったりするのは、これらのブラウザ側のハックがうまく動かなかったケースになる。Android版になると、メインプロセス内でもブラウザのメインスレッドとAndroidのUIスレッドが別になるので、より複雑さを増したりする。

なお、Apple (macOS) はWebKit2のときにこの問題を解決するめに非公開の非同期API群を作って対処した。Appleズルい

2021-07-02

Firefox on Linux/riscv64

This step is out of date since I have merged all patches to trunk. Please read How to build Firefox for Linux/riscv64 on Ubuntu 22.10 + Unmatched instead.

Although I don't land all patches to mozilla-central yet, source code is https://github.com/makotokato/gecko-dev/tree/riscv64.

To build this, you have to build nodejs v16.0 since Firefox build sytem requires it. So I recommend that you setup cross compile environemnt instead of building on Unmatched board host.

Also, this is .mozconfig sample.

mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir
mk_add_options AUTOCLOBBER=1
ac_add_options NODEJS=/home/makoto/node-v16/bin/node

ac_add_options --enable-application=browser
ac_add_options --disable-debug
ac_add_options --enable-optimize

export CC=gcc
export CXX=g++

If using corss compile,

mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir
mk_add_options AUTOCLOBBER=1

ac_add_options --enable-application=browser
ac_add_options --disable-debug
ac_add_options --enable-optimize

ac_add_options --target=riscv64
export CC=riscv64-linux-gnu-gcc
export CXX=riscv64-linux-gnu-g++
export HOST_CC=gcc
export HOST_CXX=g++

2021-06-07

HiFive Unmatched にUbuntuをインストールする

デフォルトのSDカードには、OpenEmbededな環境のLinuxがインストールされているのだが、いろいろパッケージをアップデートしたいので、NVMeを取り付けて、そこにUbuntuをインストールした。

Install Ubuntu on HiFive Unmatchedに方法が書いてあるのだが、この方法だと実はブートしない。

u-boot-update

した後、

/boot/extlinux/extlinux.confを直接編集して、以下のようにfdt行を追加してdtbファイルを指定しないといけない。

label l0
  menu label Ubuntu 21.04 5.11.0-1007-generic
  linux /boot/vmlinuz-5.11.0-1007-generic
  initrd /boot/initrd.img-5.11.0-1007-generic
  fdt /lib/firmware/5.11.0-1007-generic/device-tree/sifive/hifive-unmatched-a00.dtb
  append root=LABEL=cloudimg-rootfs ro earlycon

2021-05-31

HiFive Unmatchedが届いた

RISC-Vの話は、実際のシリコンでの話は少く、大概エミュレーター作ったとかFPGAに実装してみてるとかが多く、(FPGAじゃない) 実際のシリコンでの話ってのは少ない。シリコンのデザインをしてる会社のプレゼンテーションを見ると大体このくらいのパフォーマンスという話は出ているが、実シリコンの話はプレゼンテーションの中の(都合のよい)話でしかなく、ソフトウェアエンジニアであれば、実際のシリコン上での動作を見てみたいものだ。

ということで、半年前くらいにオーダーしてたHiFive Unmatchedが届いた。このボードはSiFiveのSoC (SiFive Freedom U740) を載せており、しかもPCIe、NVMeスロット付という自分が待ち望んでいた感じのもの。ただしお値段は$679+4,200円。Mac Mini買える値段。

簡単にUNIX Benchmarks走らせた結果。RasPi3クラスかなって程度だが、コンパイラ自体の成熟度が増せばいろいろ違うだろうし、そもそもこのテストはSDカード上で行っているので、ストレージをSDカードからNVMeに変更すればまた違う

   BYTE UNIX Benchmarks (Version 5.1.3)

   System: unmatched: GNU/Linux
   OS: GNU/Linux -- 5.11.10 -- #1 SMP Wed Apr 7 17:37:34 UTC 2021
   Machine: riscv64 (riscv64)
   Language: en_US.utf8 (charmap="UTF-8", collate="UTF-8")
   08:19:19 up 16 min,  1 user,  load average: 0.32, 0.23, 0.21; runlevel 2020-12-17

------------------------------------------------------------------------
Benchmark Run: Mon May 31 2021 08:19:19 - 08:47:43
4 CPUs in system; running 1 parallel copy of tests

Dhrystone 2 using register variables        4443367.3 lps   (10.0 s, 7 samples)
Double-Precision Whetstone                     1189.1 MWIPS (9.8 s, 7 samples)
Execl Throughput                               1502.3 lps   (29.9 s, 2 samples)
File Copy 1024 bufsize 2000 maxblocks         85504.8 KBps  (30.0 s, 2 samples)
File Copy 256 bufsize 500 maxblocks           40618.3 KBps  (30.0 s, 2 samples)
File Copy 4096 bufsize 8000 maxblocks        116919.4 KBps  (30.0 s, 2 samples)
Pipe Throughput                              299710.9 lps   (10.0 s, 7 samples)
Pipe-based Context Switching                  54294.3 lps   (10.0 s, 7 samples)
Process Creation                               2426.7 lps   (30.0 s, 2 samples)
Shell Scripts (1 concurrent)                    905.7 lpm   (60.1 s, 2 samples)
Shell Scripts (8 concurrent)                    358.4 lpm   (60.1 s, 2 samples)
System Call Overhead                         586221.6 lps   (10.0 s, 7 samples)

System Benchmarks Index Values               BASELINE       RESULT    INDEX
Dhrystone 2 using register variables         116700.0    4443367.3    380.8
Double-Precision Whetstone                       55.0       1189.1    216.2
Execl Throughput                                 43.0       1502.3    349.4
File Copy 1024 bufsize 2000 maxblocks          3960.0      85504.8    215.9
File Copy 256 bufsize 500 maxblocks            1655.0      40618.3    245.4
File Copy 4096 bufsize 8000 maxblocks          5800.0     116919.4    201.6
Pipe Throughput                               12440.0     299710.9    240.9
Pipe-based Context Switching                   4000.0      54294.3    135.7
Process Creation                                126.0       2426.7    192.6
Shell Scripts (1 concurrent)                     42.4        905.7    213.6
Shell Scripts (8 concurrent)                      6.0        358.4    597.3
System Call Overhead                          15000.0     586221.6    390.8
                                                                   ========
System Benchmarks Index Score                                         260.2

------------------------------------------------------------------------
Benchmark Run: Mon May 31 2021 08:47:43 - 09:16:48
4 CPUs in system; running 4 parallel copies of tests   

Dhrystone 2 using register variables       17753848.1 lps   (10.0 s, 7 samples)
Double-Precision Whetstone                     4712.2 MWIPS (9.9 s, 7 samples)
Execl Throughput                               5703.9 lps   (29.9 s, 2 samples)
File Copy 1024 bufsize 2000 maxblocks        159065.0 KBps  (30.0 s, 2 samples)
File Copy 256 bufsize 500 maxblocks           65531.5 KBps  (30.0 s, 2 samples)
File Copy 4096 bufsize 8000 maxblocks        208282.9 KBps  (30.2 s, 2 samples)
Pipe Throughput                             1179603.9 lps   (10.0 s, 7 samples)
Pipe-based Context Switching                 248734.2 lps   (10.0 s, 7 samples)
Process Creation                               9186.8 lps   (30.0 s, 2 samples)
Shell Scripts (1 concurrent)                   2695.8 lpm   (60.1 s, 2 samples)
Shell Scripts (8 concurrent)                    395.6 lpm   (60.1 s, 2 samples)
System Call Overhead                        2176448.1 lps   (10.0 s, 7 samples)

System Benchmarks Index Values               BASELINE       RESULT    INDEX
Dhrystone 2 using register variables         116700.0   17753848.1   1521.3
Double-Precision Whetstone                       55.0       4712.2    856.8
Execl Throughput                                 43.0       5703.9   1326.5
File Copy 1024 bufsize 2000 maxblocks          3960.0     159065.0    401.7
File Copy 256 bufsize 500 maxblocks            1655.0      65531.5    396.0
File Copy 4096 bufsize 8000 maxblocks          5800.0     208282.9    359.1
Pipe Throughput                               12440.0    1179603.9    948.2
Pipe-based Context Switching                   4000.0     248734.2    621.8
Process Creation                                126.0       9186.8    729.1
Shell Scripts (1 concurrent)                     42.4       2695.8    635.8
Shell Scripts (8 concurrent)                      6.0        395.6    659.3
System Call Overhead                          15000.0    2176448.1   1451.0
                                                                   ========
System Benchmarks Index Score                                         737.3

Windows 10Xがなくなった今、今年最大のオモチャかも

2021-05-21

サードパーティ製IMEは、Web Browserのプライベート・シークレットウィンドウなんて考えてくれない

最近のブラウザは、プライベート・シークレットモードが搭載されている。このモードになれば、ブラウザはCookieを保存しないとかいろいろプライバシーを考慮された動作になる。 ただ、いくつかの言語 (とAndroidのようなソフトウェアキーボードを使う場合)、IMEというものを仲介して文字を入力するため、プライベートモードであっても入力履歴はIMEが保存してしまうかもしれない。そのため、入力履歴を学習しないようにするのを通知する機能というのがある。

Androidで言えば、InputMethods.IME_FLAG_NO_PERSONALIZED_LEARNING、Windows 10 20H1以降のText Service FrameでのIS_PRIVATEがそれだ (IS_PRIVATEの話は以前のブログ参照)。なお、GTKも4以降で機能を追加してもらった。この機能を使うことでプライベートモードであれば入力履歴を学習しないようになる。ChromiumやFirefoxではこれを使っているのでプライベートモードでは学習しないようにしてる。

ただ、この機能が動作する条件がもう一つあって、IME側でも対処が必要であるということ。この機能をちゃんと使うのは純正IME (Androidで言えばGBoardとかGooglen日本語入力、Windowsで言えばMicrosoft IME) くらいしかない。Androidの場合だとサードパーティ製IMEでこれを使っているのはあるかもしれないけど、どうも徳島にある某社のATOK (Windows版、Android版) はこの機能を使ってない模様。自分としては (毎月330円払っているユーザーとして)直してほしいのだけど、彼等はこういうところに興味がないから言ったとしても難しそうな気がする。

なお、ここで触れてない (本社がクパチーノにある) 某OS は未だに存在しない機能の模様なのだが、プライバシーとかを最近重視しているのであれば、実装してほしい。

CSS疑似クラスの:read-onlyと:read-writeが仕様通りに実装されることになった

いろんなやりとりを仕事がらするのだけど、自分のイメージ的には、WebKitは仕様上間違ってるという話を振れば、直してくれることが多くて、BlinkはQAが変な方向に持っていくか、開発者が斜め上の方向の話にしてしまいwontfix扱いになるということが多々ある。

最近やっと直す方向になった、CSS疑似クラスの:read-only / :read-writeがそのパターン。

元々は、Geckoが-moz-プレフィックス付きで実装してたものの一つで、その後、WebKit (確かBlinkに分かれる前) に実装されてた。しかもプレフィックスなしで。実装されたとしても、そもそも仕様として固まっていないものだったので、いろいろと差異が出るので、ちゃんと仕様として書かれたのだが、それが今回の発端である。

仕様がそもそもその時点のブラウザとは違う定義をしていたので (プレフィックスがあれば、別にいいやとは思うのだが、特にWebKitとBlinkがプレフィックスなし)、「これどういうこと?」と思い、WebKitとBlinkに対してバグを登録した。仕様自体を変更するという議論もありだと思っていたので、それぞれ (AppleとかGoogle) がやってくれるでしょ?ってことだしね。

WebKitは、さくっとこのバグを修正。エッジケースでまだ間違ってることはあるだろうけど、こっちが指摘した動作に関しては修正してくれた。

で一方、Blinkはというと、「これGeckoとかと同じ動作にしたからこういう動作なんでwontfix」。という結論に。個人的には「え?ならCSSWGで議論してよ」と。なぜ彼らはwontfixにする際に仕様に対してのコントリビュートとかWeb Platform Tests書くとかしないのかなぁと。たぶん人によるのだけど、残念ながら個人的にはよくあるパターン。

こういう状況だとGecko側もどうしようもないので (しかもGeckoだけプレフィックス付きだし、プレフィックス外すのだったらこれ結論必要だから) 困ると。ということで、CSSWG行きになった。(wontfixと言った張本人がなぜそっちに議論を移さないのかと本当に思うんだが)そこで議論のやり直しが発生した。

結論書くと、結果としては仕様を変えないということになり、emilioがGecko側をプレフィックス削除とともに仕様通りに修正を行った。

さて、問題はwontfixにしてしまっているBlink側ということになる。emilioがそのバグを再オープンし直したが、つい先日やっと直すことになったようで、そろそろBlinkでも直りそうということに。やれやれ。

そもそもBlinkは他の2つ (Gecko、WebKit) に比べて圧倒的な人的リソースを持っているわけだし、シェアも圧倒的なのだから、こういう仕様とは異なる動作の修正にリソースを割いてほしいと思うのだけど。。。。無理かなぁ。。。