Lazy Diary @ Hatena Blog

PowerShell / Java / miscellaneous things about software development, Tips & Gochas. CC BY-SA 4.0/Apache License 2.0

Get all available event IDs for each source on Windows Event Log

(Get-WinEvent -ListLog * -ErrorAction SilentlyContinue).ProviderNames |
  Sort-Object -Unique |
  ForEach-Object {
    $SourceName = $_;
    try {
      (Get-WinEvent -ListProvider $SourceName -ErrorAction SilentlyContinue).Events |
      ForEach-Object {
        $Event = $_;
        [PSCustomObject]@{
          Source = $SourceName;
          EventId = $Event.Id;
          Description = $Event.Description
        }
      }
    } catch {
      $_ | Format-List * -Force | Out-String
    }
  } | Export-Csv -Encoding UTF8 C:/tmp/Result.csv

PostgreSQLの教育にPGliteを使う

satob.hatenablog.com

SupabaseのPostgres-WASMだと、大量(1,000件)のINSERTができない等の問題があった。

最近PGliteがリリースされ、REPL環境もあるようなので試してみた。

pglite.dev

  • ファイルをアップロードして\i /mnt/foobar.sqlみたいなことはできないので、まとまったSQLはすべてコピペで実行する必要がある。
  • SQLの実行結果はHTML形式にフォーマットして出力される。ASCIIテキストにならないので、実行結果のコピペは面倒かも。
  • 1,000件のINSERT文をコピペで実行してもエラーにならない。問題なくINSERTできているように見える。
  • 統計情報はリアルタイム更新されるようだが誤差が大きい。1,000件INSERTした直後にEXPLAINするとrows=98と言われる(これはそんなもんなのか?)
  • 利用できるextensionはラジオボックスでの選択式。pg_stat_statementsなど性能関連のextensionは含まれていないので実行できない。
  • シェルにはアクセスできないのでpostgresql.confを編集して再起動とかもできない。

普通にSQLを実行している限りでエラーが出ていないとという意味では、純粋にSQLの確認するだけの環境としてはPostgres-WASMよりいいのかも。

SpotBugsのプラグインを作ったらそのライセンスは?

SpotBugs自体のライセンスはLGPL v2.1。

github.com

SpotBugsにはプラグイン(カスタムルール)を作る仕組みが用意されていて、AnnotationDetectorとかBytecodeScanningDetectorとかOpcodeStackDetectorとかを継承したクラスを作っておいて、findbugs.xmlに追加するとカスタムルールとして動作する。

spotbugs.readthedocs.io

で、このカスタムルールに適用する必要のあるライセンスって何なんだろう?という話。普通に考えるとLGPLなプログラムとリンクして動くプログラムということなので、LGPLで求められるリバースエンジニアリングの許諾さえしておけばライセンスは問わない(LGPLじゃなくてもよい)ということになると思うんだけど、実例が見当たらない。これまで見たことがあるのは「LGPLなライブラリを呼んでるプログラム」だけで、「LGPLなソフトウェアから呼ばれるプログラム」は見たことがないんだよなぁ……

SpotBugsそのもの以外でSpotBugsのプラグインを公開しているGitHubリポジトリを検索してみた*1んだけど、OWASP Find Security Bugsくらいしか見当たらなかった。これのライセンスはLGPL v3.0。

github.com

*1:"extends OpcodeStackDetector" site:github.com -site:github.com/spotbugs

-XX:+AlwaysPreTouchでJavaVM起動時に全ヒープを物理メモリに載せたらどれくらい起動が遅くなるの?

結論: ヒープサイズ4GBのときWindowsで2秒程度、WSLで3秒程度。ヒープサイズ1GBのときWindowsで1秒程度、WSLで0.5秒程度、起動時のオーバーヘッドが増える模様。

動機

JavaVMの起動時に-Xms-Xmxに同じ値を指定しても、JavaVM起動時点でそれだけの物理メモリが確保されるわけではない、という話があります。-Xms-Xmxでメモリ量を指定してJavaVMを起動した直後の状態だと、おそらくUnix系のOSならbrk(2)sbrk(2)WindowsだったらVirtualAllocあたりが呼ばれるので、この時点でプログラムブレークの位置は設定される*1 。だけど、JavaVMは確保したメモリすべてに触りにいくわけじゃないからその時点ではOSはページフォールトを発生させる理由がない。よってOSから見ると仮想メモリがコミットされるだけで物理メモリは割り当られてない、という動きになるわけです。

stackoverflow.com

それだけでもメモリ確保の都度brk(2)sbrk(2)を呼ぶ動きを抑止できるという意味で、-Xms-Xmxを同じ値に設定するのはスループットを高めるには有用と思われます*2

で、物理メモリ上に本当に領域が確保される必要はないにしても、システムのリソース設計をするときはJavaヒープが全て物理メモリに載った状態でもスワップが発生しないよう設計にしておかないと、スラッシングによる性能劣化が怖い。そういう前提でリソース設計をしてたのに、いざシステムが稼動したら設計をミスっててプロセスが仮想メモリを確保できず起動しない、という状況はテストで潰しておきたい。OSがWindowsであればOSの仕様上オーバーコミットはできないからシステム稼動中と同じようにプロセスを起動しておけばこれがテストできる*3。一方、Linuxの場合はオーバーコミットするのがOSのデフォルト設定になっているので、この目的でテストをしたければ-Xms-XmxでコミットしたメモリすべてにJavaVMが触りに行ってページフォールトを発生させないとテストができないわけです。

そのためかどうかわかりませんが、Javaには-XX:+AlwaysPreTouchという起動オプションがあって、これを指定するとJavaVM起動時に確保したメモリ(ページ)すべてに触りに行く。ただ、もちろん全メモリに触りに行くわけなので起動時のオーバーヘッドはそれなりにかかる。じゃぁどれくらいオーバーヘッドがかかるの?というのが知りたいわけです。毎分1回起動してそれなりの時間処理をするようなプロセスで、プロセス起動時のオーバーヘッドが何十秒も増えたらそれは困るので。

以下のようなプログラムを作って、-XX:+AlwaysPreTouchありとなしで差を確認してみました。

import java.lang.management.ManagementFactory;
import com.sun.management.OperatingSystemMXBean;

public class AlwaysPreTouchTest {
    public static void main(String[] main) {
        OperatingSystemMXBean osMBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
        System.out.printf("Free physical memory: %dkB\n", osMBean.getFreeMemorySize() / 1024);
        System.out.printf("Total Java Heap: %dkB\n", Runtime.getRuntime().totalMemory() / 1024);
    }
}

Windowsの場合

Windowsでの結果は以下のような感じ。ヒープ4GBで-XX:+AlwaysPreTouchを指定したときの起動時間は1秒~2秒でけっこうバラつく。

PS C:\tmp> java --version
openjdk 17.0.9 2023-10-17
OpenJDK Runtime Environment Temurin-17.0.9+9 (build 17.0.9+9)
OpenJDK 64-Bit Server VM Temurin-17.0.9+9 (build 17.0.9+9, mixed mode, sharing)

PS C:\tmp> (Measure-Command { Invoke-Expression "java.exe -Xmx4g -Xms4g AlwaysPreTouchTest" | Out-Default }).TotalSeconds
Free physical memory: 5545840kB
Total Java Heap: 4194304kB
0.3735332
PS C:\tmp> (Measure-Command { Invoke-Expression "java.exe -Xmx4g -Xms4g -XX:+AlwaysPreTouch AlwaysPreTouchTest" | Out-Default }).TotalSeconds
Free physical memory: 1208368kB
Total Java Heap: 4194304kB
2.4802916
PS C:\tmp> (Measure-Command { Invoke-Expression "java.exe -Xmx1g -Xms1g AlwaysPreTouchTest" | Out-Default }).TotalSeconds
Free physical memory: 5530976kB
Total Java Heap: 1048576kB
0.1812453
PS C:\tmp> (Measure-Command { Invoke-Expression "java.exe -Xmx1g -Xms1g -XX:+AlwaysPreTouch AlwaysPreTouchTest" | Out-Default }).TotalSeconds
Free physical memory: 4451272kB
Total Java Heap: 1048576kB
1.2108386

WSLの場合

WSLでの結果は以下のような感じ。ヒープ4GBで-XX:+AlwaysPreTouchを指定したときの起動時間は3秒程度で安定している。一方、ヒープ1GBのときのオーバーヘッドはなぜか生のWindowsより小さい。

satob:~$ java --version
openjdk 17.0.11 2024-04-16
OpenJDK Runtime Environment (build 17.0.11+9-Ubuntu-120.04.2)
OpenJDK 64-Bit Server VM (build 17.0.11+9-Ubuntu-120.04.2, mixed mode, sharing)
satob:~$ time java -Xmx4g -Xms4g AlwaysPreTouchTest
Free physical memory: 7498060kB
Total Java Heap: 4194304kB

real    0m0.091s
user    0m0.090s
sys     0m0.019s
satob:~$ time java -Xmx4g -Xms4g -XX:+AlwaysPreTouch AlwaysPreTouchTest
Free physical memory: 3159932kB
Total Java Heap: 4194304kB

real    0m0.472s
user    0m0.201s
sys     0m3.046s
satob:~$ time java -Xmx1g -Xms1g AlwaysPreTouchTest
Free physical memory: 7529068kB
Total Java Heap: 1048576kB

real    0m0.218s
user    0m0.113s
sys     0m0.135s
satob:~$ time java -Xmx1g -Xms1g -XX:+AlwaysPreTouch AlwaysPreTouchTest
Free physical memory: 6441500kB
Total Java Heap: 1048576kB

real    0m0.184s
user    0m0.096s
sys     0m0.756s

*1:WindowsであればここでパフォーマンスモニターのCommitted Bytesが増える

*2:最近のLinuxではbrk(2)もだいぶ高速化されてるという説明がmalloc動画にありましたが実態がどうかは把握していない。あと、メモリをプロセスからOSに返す際のmadvice(MADV_DONTNEED)が遅いという話がそれとは別であった気がします

*3:もちろんCommit Limitはページングファイルを含めた最大値なのでスラッシングの懸念はありますが……

「外字」とは何か?

あるシステムの設計者に「このシステムでは外字を使いますか?」と質問したとしましょう。そのとき、「はい、使います」と答えたとして、その意味として考えられるものは……

  1. 私用領域のコードポイントにある文字を、正規のデータとして処理する
  2. Windowsの日本語IMEで、変換時に「機種依存文字」と表示される文字(「髙」など)を、正規のデータとして処理する
  3. Windowsの日本語IMEで、デフォルト設定では変換候補に出てこない文字(JIS第3水準・第4水準など)を、正規のデータとして処理する
  4. 上記のような文字を日本語IMEから入力可能にするよう、ユーザ端末をキッティングする
  5. 1~4のような文字を、入力データのバリデーションで明示的に弾いたり、別の文字に置き換えたりするなど、特別扱いする処理を実装している
  6. システムのデフォルトフォントで表示できない文字を、大規模文字セット用のフォントなどをインストールして表示可能にしている
  7. JIS78やJIS90で字形が変わった文字の、古い方の字形を用意している
  8. 旧字体(「學」とか)を新字体(「学」とか)に置き換える処理をしている
  9. ユーザが業務運用中にEUDC.ttfを編集する
  10. アプリケーションが編集したEUDC.ttfを必要とする