tech.guitarrapc.cóm

Technical updates

Directory.Build.propsで指定したPackageReferenceをプロジェクトファイルで上書きする

<PackageReference Include>は使うけど<PackageReference Update>は使わない、そう思っていた時期が私にもありました。今回は、<PackageReference Update>を使うと便利な例です。忘れそうなのでメモです。

CPMとDirectory.Build.propsで全プロジェクトにパッケージを追加

Central Package Managementを使用しているプロジェクトでDirectory.Packages.propsにてパッケージバージョンを指定し、Directory.Build.propsを使って全プロジェクトに暗黙的にパッケージ追加できます。個別のcsprojへパッケージを追加しなくていいのでかなり便利なやり方です。例えば、Microsoft.SourceLink.GitHubのバージョン8.0.0を全プロジェクトで利用したいときは、以下のようにします。

<!-- Directory.Packages.props -->
<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
    <CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
  </PropertyGroup>
  <ItemGroup>
    <PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
  </ItemGroup>
</Project>
<!-- Directory.Build.props -->
<Project>
  <ItemGroup>
    <PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="all"/>
  </ItemGroup>
</Project>

プロジェクトファイルでは、Microsoft.SourceLink.GitHubを指定しなくてもビルド時にパッケージが入ります。

<!-- Normal.csproj -->
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>
// Program.cs
Console.WriteLine("Hello, World!");
$ dotnet build
Restore complete (0.6s)
  Normal net10.0 succeeded (1.1s) → bin/Debug/net10.0/Normal.dll

Build succeeded in 2.6s

どのような時に困るのか

ただ、時々プロジェクトファイルでCPMを無効にしたくなる時があります。例えば、ライブラリ開発しているとプロジェクト参照ではなく、過去リリースしたNuGetパッケージで動作テストしたくなることがあります。この場合、プロジェクトファイルでCPMを無効にして、個別のプロジェクトファイルでPackageReferenceを追加します。

検証してみましょう。csprojをいじって、ビルド時にUseNuGetを指定するとCPMを無効にして任意のNuGetパッケージを追加するようにします。

<!-- Normal.csproj -->
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <!-- ここから追加 -->
  <PropertyGroup Condition="'$(UseNuGet)' != ''">
    <ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>
  </PropertyGroup>
  <ItemGroup Condition="'$(UseNuGet)' != ''">
    <PackageReference Include="MagicOnion.Client" Version="$(UseNuGet)"/>
  </ItemGroup>
  <!-- ここまで -->

</Project>

これをビルドするとビルドエラーが発生します。原因は、Directory.Build.propsで指定されているMicrosoft.SourceLink.GitHubが追加されますが、Directory.Build.propsではバージョンを指定していないためです。それはそう。

$ dotnet build -p:UseNuGet=6.1.4
    ./Override/Normal.csproj : error NU1015: The following PackageReference item(s) do not have a version specified: Microsoft.SourceLink.GitHub

Restore failed with 1 error(s) in 1.2s

具体的な状況はdepsファイルで確認できます。Microsoft.SourceLink.GitHubのバージョンが"version": "(, )"になっており、指定されていないことがわかります。

# プロジェクト名がNormal.csprojなので、Normal.csproj.nuget.dgspec.jsonを見ます。
$ cat obj/Normal.csproj.nuget.dgspec.json
...省略

      "frameworks": {
        "net10.0": {
          "targetAlias": "net10.0",
          "dependencies": {
            "MagicOnion.Client": {
              "target": "Package",
              "version": "[6.1.4, )"
            },
            "Microsoft.SourceLink.GitHub": {
              "suppressParent": "All",
              "target": "Package",
              "version": "(, )"
            }
          },

...省略

一見するとNuGetパッケージを指定するときと同様に、.csprojに<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0"/> を追加すればよさそうです。が、これはDirectory.Build.propsと定義が重複するのでエラーになります。

<!-- Normal.csproj -->
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <!-- ここから追加 -->
  <PropertyGroup Condition="'$(UseNuGet)' != ''">
    <ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>
  </PropertyGroup>
  <ItemGroup Condition="'$(UseNuGet)' != ''">
    <PackageReference Include="MagicOnion.Client" Version="$(UseNuGet)"/>
    <PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0"/> <!-- ← これを追加 -->
  </ItemGroup>
  <!-- ここまで -->
</Project>

ビルドエラーからパッケージ定義が重複していることがわかります。

$ dotnet build -p:UseNuGet=6.1.4
./Bad/Normal.csproj : warning NU1504: Duplicate 'PackageReference' items found. Remove the duplicate items or use the Update functionality to ensure a consistent restore behavior. The duplicate 'PackageReference' items are: Microsoft.SourceLink.GitHub , Microsoft.SourceLink.GitHub 8.0.0.
    ./Bad/Normal.csproj : error NU1015: The following PackageReference item(s) do not have a version specified: Microsoft.SourceLink.GitHub

Restore failed with 1 error(s) and 1 warning(s) in 1.2s

Includeだと既存の定義があっても新しい定義を追加しようとするんですね。Directory.Build.propsで指定したPackageReferenceをcsprojで上書きしたいときは、<PackageReference Update="..." Version="上書きしたいバージョン" />を使います。

<!-- Normal.csproj -->
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <!-- ここから追加 -->
  <PropertyGroup Condition="'$(UseNuGet)' != ''">
    <ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>
  </PropertyGroup>
  <ItemGroup Condition="'$(UseNuGet)' != ''">
    <PackageReference Include="MagicOnion.Client" Version="$(UseNuGet)"/>
    <PackageReference Update="Microsoft.SourceLink.GitHub" Version="8.0.0"/> <!-- ← Updateを使う -->
  </ItemGroup>
  <!-- ここまで -->
</Project>

ビルドが成功していますね。

dotnet build -p:UseNuGet=6.1.4
Restore succeeded with 1 warning(s) in 2.4s
Build succeeded with 2 warning(s) in 7.5s

まとめ

もし、どこかですでに<PackageReference Include="..."/>と定義したパッケージをプロジェクトファイルで上書きしたいときは、<PackageReference Update="..." Version="X.Y.Z"/>を使うと上書きできます。

状況的に、Directory.Build.propsやカスタムprops読み込みを使っていない限りは遭遇しないでしょう。ただ、csproj管理の効率化のためにDirectory.Build.propsを使っているときは、思いがけず遭遇する可能性があります。

今ならこういうのはLLM聞けば? ってなるのですが、割とこういうファイルを探索する系はLLMもすんなり答えにたどり着かないことがあります。基礎知識ということで。なお、Microsoft Learnにはこの記載がないので、なかなか気づけないです。

参考

.NET9 SDKから dotnet add package コマンドが dotnet package add コマンドに変更された

.NET SDKを使うと、dotnetコマンドを使ってビルドやパッケージ追加、プロジェクト作成などができます。さて、パッケージ追加コマンドは.NET8までdotnet add packageでしたが、.NET9からdotnet package addにコマンドが変更されました。.NET9はSTSなので、LTSとしては.NET 10からの変更です。

今回はこの変更について見ていきます。

dotnetコマンドの一覧

dotnetコマンド体系は、基本的にdotnet [sdk-options] [command] [command-options] [arguments]の形で構成されています。1SDKから実行するビルドなどのコマンドとしては、dotnet builddotnet rundotnet testなどがあります。このコマンドは、コマンドとして実行したいbuildnewruntestは動詞として用意されていますが、他は名詞先行のコマンド体系になっています。

以下は.NET 8でのヘルプですが、パッケージ追加はdotnet add package、リファレンス追加はdotnet add referenceのように、動詞先行のコマンド体系も混じっていました。

$ dotnet --version
8.0.418

$ dotnet --help
... 省略
SDK commands:
  add               Add a package or reference to a .NET project.
  build             Build a .NET project.
  build-server      Interact with servers started by a build.
  clean             Clean build outputs of a .NET project.
  format            Apply style preferences to a project or solution.
  help              Show command line help.
  list              List project references of a .NET project.
  msbuild           Run Microsoft Build Engine (MSBuild) commands.
  new               Create a new .NET project or file.
  nuget             Provides additional NuGet commands.
  pack              Create a NuGet package.
  publish           Publish a .NET project for deployment.
  remove            Remove a package or reference from a .NET project.
  restore           Restore dependencies specified in a .NET project.
  run               Build and run a .NET project output.
  sdk               Manage .NET SDK installation.
  sln               Modify Visual Studio solution files.
  store             Store the specified assemblies in the runtime package store.
  test              Run unit tests using the test runner specified in a .NET project.
  tool              Install or manage tools that extend the .NET experience.
  vstest            Run Microsoft Test Engine (VSTest) commands.
  workload          Manage optional workloads.

.NET 9以降、先のコマンドがdotnet package adddotnet reference addのように名詞先行のコマンド体系で扱えます。

$ dotnet --version
10.0.103

$ dotnet --help
... 省略
SDK commands:
  build             Build a .NET project.
  build-server      Interact with servers started by a build.
  clean             Clean build outputs of a .NET project.
  format            Apply style preferences to a project or solution.
  help              Opens the reference page in a browser for the specified command.
  msbuild           Run Microsoft Build Engine (MSBuild) commands.
  new               Create a new .NET project or file.
  nuget             Provides additional NuGet commands.
  pack              Create a NuGet package.
  package           Search for, add, remove, or list PackageReferences for a .NET project.
  publish           Publish a .NET project for deployment.
  reference         Add, remove, or list ProjectReferences for a .NET project.
  restore           Restore dependencies specified in a .NET project.
  run               Build and run a .NET project output.
  sdk               Manage .NET SDK installation.
  solution          Modify Visual Studio solution files.
  store             Store the specified assemblies in the runtime package store.
  test              Run unit tests using the test runner specified in a .NET project.
  tool              Install or manage tools that extend the .NET experience.
  vstest            Run Microsoft Test Engine (VSTest) commands.
  workload          Manage optional workloads.

変更があったのはパッケージ関連とリファレンス関連です。例えば、パッケージ追加はdotnet package add、リファレンスの追加はdotnet reference addになっています。旧来のコマンドもエイリアスとして残っていますが、今後は新しいコマンドを使うといいでしょう。

New noun-first form (.NET9+) Alias for (.NET8-)
dotnet package add dotnet add package
dotnet package list dotnet list package
dotnet package remove dotnet remove package
dotnet reference add dotnet add reference
dotnet reference list dotnet list reference
dotnet reference remove dotnet remove reference

一般的にCLIのコマンドは名詞先行で用意されていることが多く、dotnetにおいてはdotnet adddotnet listは一意に何をするのか一貫性がないというのが起点のようです。たしかに一貫性は大事。

まとめ

dotnet packageには、add以外にlistremoveもあるので、パッケージを操作するというのが迷いにくい名詞先行になったのは悪くなさそうです。個人的には、一般的に動詞先行のCLIコマンドが多い気もするのですが、dotnetとして一貫性があればいいと感じます。

実際のところ、パッケージ追加コマンドを始めてみたときにdotnet add packageだったのは違和感がありました。慣れてしまって忘れていましたが、当時を思い返すとdotnet package ...でコマンドが統一されるのは使いやすいと感じます。はじめは戸惑いますが、エイリアスもあるので焦らず慣れていくといいでしょう。

参考

リリースノート

Issue

redditでも好みが分かれる話だったりします


  1. [sdk-options]--list-sdksとかのdotnetコマンド自体のオプションなので、ここでは省略します。

Windows 11でウィンドウスナップのサイズがおかしくなった時にリセットする

Windows 11の便利操作の1つがウィンドウスナップです。ウィンドウを画面の端にドラッグすると自動的にサイズ調整されて配置されるあの機能です。今回はこのスナップでウィンドウサイズが変になった時、スナップサイズをリセットする方法を紹介します。長年困ってました。

ウィンドウスナップとは

モニターの真ん中上にウィンドウを持っていくと、スナップ配置の選択肢が表示されます。ウィンドウスナップは、この配置にウィンドウを自動的にリサイズして配置する機能です。複数ウィンドウを並べて使うときに重宝するんですよね。

スナップの例

例えば、横ディスプレイの右上にウィンドウを持っていくと、ディスプレイを4分割した右上に配置されます。

横ディスプレイの右上スナップ例

縦ディスプレイの真ん中右ににウィンドウを持っていくと、ディスプレイを縦3分割した真ん中に配置されます。

縦ディスプレイのスナップ例

キーボード操作でWindowsキー + 矢印キーでもスナップ操作ができます。例えば、Windowsキー + 右矢印キーを押すと、ディスプレイの右半分にウィンドウがスナップされます。

Windows+右矢印でディスプレイの右半分にスナップされる

さらにもう一度右矢印キーを押すと、隣のディスプレイの左半分にスナップされます。

右にディスプレイがもう一枚ある時にさらにWindows+右矢印をすると、そのディスプレイの左半分にスナップされる

Windowsキー + 上矢印Windowsキー + 下矢印で上下のスナップができるため、キーボードだけでウィンドウを自在に配置できます。便利。

ウィンドウスナップのサイズがおかしくなった時の対処法

ウィンドウスナップは便利ですが、たまに変なサイズにスナップされることがあります。例えば、横ディスプレイの右半分にスナップしたいのに、なぜか8分の1の幅でスナップされてしまうことがあります。この症状が一度起こると、再起動しても直りません。スナップを多用しているので長い間困っていました。

Windows+右矢印のスナップサイズがおかしい

この症状を解消するには、以下の手順を行います。

  1. Settings > Multi-tasking settingsを開く
  2. Snap Windowsメニューが現在ONになっていることを確認
  3. 一度OFFに切り替える
  4. 再びONにする

これで変なウィンドウサイズにスナップされる症状が解消します。

スナップがOnになっている

スナップをOffにする

まとめ

ずっとわからないまま放置していたのですが、ふと「ウィンドウスナップが嫌だからOFFにしている」という記事を見かけて、どのような感じかとOFFにしたら不便でした。で、再度ONにしたら困っていた症状が直りました。2年前に知りたかった。

この記事が同じ症状で困っている方の参考になれば幸いです。

straceでC#のシステムコールを覗いてみる

ClassMethodsさんの記事で、C,Go,Rust,Python,Node.jsのHello Worldプログラムをstraceで覗いていたのですが、C#も気になりませんか?私は気になるので見てみましょう。

C#のビルド成果物にはJITとAOTの2種類があり、これらの言語がVMを用いないことを考えると比較するならAOTでのstraceが適切です。ただ、せっかくなので両方を見てみましょう。

結論

記事が長いので、結論を書いておきます。

システムコール数の比較は次の通りです。

実装 システムコール数
C# (JIT) 1159
C# (JIT + ICU無効) 940
C# (JIT + ICU指定) 985
C# (AOT) 470
C# (AOT + ICU無効) 228
C# (AOT + ICU指定) 290
Go 185
Go (共有ライブラリ版) 24884
Rust 63
C 34

C#の起動時のシステムコールを減らすには、ICUの使用有無を指定するのが効果的です。

  • InvariantCultureで問題ない: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
  • 多言語対応が必要: DOTNET_ICU_VERSION_OVERRIDE=<バージョン>で探索を削減

環境

今回の検証はguitarrapc/linux-straceリポジトリで公開しています。元の記事のリポジトリを参考にしつつ、C#のJIT/AOT両方や結果を記載し、再現が取れるようにコンテナで動かしています。気になる方は参照してください。

項目 バージョン
OS Ubuntu 24.04 (コンテナ)
C (gcc) 13.3.0
Rust 1.93.0
Go 1.24.1
.NET SDK 10.0.102
strace 6.8

検証

各言語でHello, Worldを書いていきます。C、Rust、Goは元記事と同じコードです。

C#

Console.WriteLine("Hello, World");

C

#include <stdio.h>

int main() {
    printf("Hello World\n");
    return 0;
}

Rust

fn main() {
    println!("Hello World");
}

Go

package main

import (
    "fmt"
)

func main() {
    fmt.Println("Hello World")
}

成果物の生成

成果物を生成する流れは本題ではないので、再現したい人向けに簡単に説明します。

C#は、JITとAOTはPublishAotの有無だけで切り替わります。publish時のパラメーターで指定してもいいのですが、わかりやすくするため、フォルダを分けて2つ用意しましょう。それぞれhello_csharp (JIT)とhello_csharp_aot (AOT)を使います。

C# (JIT)

JIT設定のhello_csharp.csprojです。ランタイムを自己完結型にして、単一ファイルにまとめる設定です。

mkdir hello_csharp
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <PublishSingleFile>true</PublishSingleFile>
    <PublishTrimmed>true</PublishTrimmed>
    <SelfContained>true</SelfContained>
  </PropertyGroup>

</Project>

成果物をリリースビルドで作成します。

dotnet publish -c Release -r linux-x64 -o ./bin hello_csharp/hello_csharp.csproj

C# (AOT)

AOT設定のhello_csharp_aot.csprojです。JITとの違いは、<PublishAot>true</PublishAot>の追加だけです。

mkdir hello_csharp_aot
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <PublishSingleFile>true</PublishSingleFile>
    <SelfContained>true</SelfContained>
    <PublishTrimmed>true</PublishTrimmed>
    <PublishAot>true</PublishAot>
  </PropertyGroup>

</Project>
dotnet publish -c Release -r linux-x64 -o ./bin hello_csharp_aot/hello_csharp_aot.csproj

C

gcc hello_c/main.c -o ./bin/hello_c

Rust

rustc hello_rust/main.rs -o ./bin/hello_rust

Go

静的リンク版(通常)と共有ライブラリ版1の2種類を作成します。

cd hello_go && go build -o ../bin/hello_go && cd ..
cd hello_go && go build -linkshared -o ../bin/hello_go_linkshared && cd ..

システムコールの統計を比較

元記事同様に、strace -cオプションでシステムコール数の統計を出します。

strace -c `./バイナリ`

使うバイナリはこちらです。各言語を見ていきましょう。

$ ls -l ./bin/hello*
-rwxrwxrwx 1 ubuntu ubuntu    15960 Feb 10 13:21 ./bin/hello_c
-rwxrwxrwx 1 ubuntu ubuntu 14853880 Feb 10 13:35 ./bin/hello_csharp
-rwxrwxrwx 1 ubuntu ubuntu  1270792 Feb 10 13:21 ./bin/hello_csharp_aot
-rwxrwxrwx 1 ubuntu ubuntu  2204715 Feb 10 13:21 ./bin/hello_go
-rwxrwxrwx 1 ubuntu ubuntu    24048 Feb 10 13:21 ./bin/hello_go_linkshared
-rwxrwxrwx 1 ubuntu ubuntu  3893728 Feb 10 13:21 ./bin/hello_rust

C

$ strace -c ./bin/hello_c
Hello World
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 32.15    0.000109          13         8           mmap
 10.62    0.000036          12         3           mprotect
  8.55    0.000029          29         1           write
  6.49    0.000022           7         3           brk
  5.31    0.000018           9         2           close
  5.31    0.000018           6         3           fstat
  5.31    0.000018           9         2           pread64
  4.42    0.000015          15         1           munmap
  4.13    0.000014           7         2           openat
  2.95    0.000010          10         1           read
  2.65    0.000009           9         1           prlimit64
  2.65    0.000009           9         1           getrandom
  2.36    0.000008           8         1           arch_prctl
  2.36    0.000008           8         1           set_tid_address
  2.36    0.000008           8         1           set_robust_list
  2.36    0.000008           8         1           rseq
  0.00    0.000000           0         1         1 access
  0.00    0.000000           0         1           execve
------ ----------- ----------- --------- --------- ----------------
100.00    0.000339           9        34         1 total

Rust

$ strace -c ./bin/hello_rust
Hello World
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ------------------
 18.45    0.000119           9        13           mmap
  9.46    0.000061          12         5           mprotect
  8.84    0.000057          11         5           read
  7.91    0.000051          12         4           close
  7.13    0.000046           9         5           rt_sigaction
  7.13    0.000046          11         4           openat
  6.67    0.000043          21         2           munmap
  4.03    0.000026           8         3           brk
  4.03    0.000026           8         3           sigaltstack
  3.72    0.000024           6         4           fstat
  3.26    0.000021          21         1           write
  3.26    0.000021          10         2           pread64
  3.26    0.000021          21         1           getrandom
  2.79    0.000018           9         2           prlimit64
  1.86    0.000012          12         1           poll
  1.55    0.000010          10         1           sched_getaffinity
  1.40    0.000009           9         1           arch_prctl
  1.40    0.000009           9         1           gettid
  1.40    0.000009           9         1           set_tid_address
  1.24    0.000008           8         1           set_robust_list
  1.24    0.000008           8         1           rseq
  0.00    0.000000           0         1         1 access
  0.00    0.000000           0         1           execve
------ ----------- ----------- --------- --------- ------------------
100.00    0.000645          10        63         1 total

Go

$ strace -c ./bin/hello_go
Hello World
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ------------------
 54.59    0.001041           9       114           rt_sigaction
 14.53    0.000277          15        18           rt_sigreturn
 10.44    0.000199          39         5         1 futex
  7.03    0.000134          67         2           clone
  4.09    0.000078          13         6           fcntl
  3.15    0.000060          10         6           rt_sigprocmask
  1.73    0.000033           1        20           mmap
  1.68    0.000032          16         2           prlimit64
  1.31    0.000025          25         1           write
  1.05    0.000020          10         2           sigaltstack
  0.42    0.000008           8         1           gettid
  0.00    0.000000           0         1           read
  0.00    0.000000           0         1           close
  0.00    0.000000           0         2           madvise
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         1           arch_prctl
  0.00    0.000000           0         1           sched_getaffinity
  0.00    0.000000           0         1           openat
------ ----------- ----------- --------- --------- ------------------
100.00    0.001907          10       185         1 total

Go (共有ライブラリ版)

$ strace -c ./bin/hello_go_linkshared
Hello World
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ------------------
 99.30    0.363647          14     24613           rt_sigreturn
  0.18    0.000676          21        31         3 futex
  0.14    0.000511          73         7           mprotect
  0.14    0.000503           4       114           rt_sigaction
  0.08    0.000307          20        15           rt_sigprocmask
  0.06    0.000234          78         3           clone
  0.05    0.000174           4        40           mmap
  0.01    0.000029           4         6           fcntl
  0.01    0.000027           4         6           read
  0.01    0.000023           2         9         4 openat
  0.00    0.000011           2         5           close
  0.00    0.000010           3         3           brk
  0.00    0.000010           5         2           sigaltstack
  0.00    0.000008           4         2           sched_getaffinity
  0.00    0.000007           7         1           munmap
  0.00    0.000007           3         2           madvise
  0.00    0.000006           2         3           prlimit64
  0.00    0.000006           6         1         1 clone3
  0.00    0.000004           1         4           fstat
  0.00    0.000004           4         1           gettid
  0.00    0.000004           4         1           getrandom
  0.00    0.000000           0         1           write
  0.00    0.000000           0         2           pread64
  0.00    0.000000           0         1         1 access
  0.00    0.000000           0         3           sched_yield
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         1           arch_prctl
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0         3         3 newfstatat
  0.00    0.000000           0         1           set_robust_list
  0.00    0.000000           0         1           rseq
------ ----------- ----------- --------- --------- ------------------
100.00    0.366208          14     24884        12 total

C# (AOT)

$ strace -c ./bin/hello_csharp_aot
Hello, World
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ------------------
 33.24    0.001192           9       129        83 openat
 14.89    0.000534           8        61           mmap
 12.97    0.000465          17        27           mprotect
  7.45    0.000267          12        22           munmap
  6.53    0.000234           5        44           fstat
  5.94    0.000213           4        45           close
  4.35    0.000156           9        16        12 newfstatat
  3.12    0.000112           2        38           read
  2.51    0.000090           5        18           rt_sigaction
  2.29    0.000082          13         6           rt_sigprocmask
  1.06    0.000038           9         4           ioctl
  0.98    0.000035          17         2           write
  0.98    0.000035          17         2           clone3
  0.70    0.000025           8         3           futex
  0.56    0.000020           1        17           madvise
  0.47    0.000017          17         1           pipe2
  0.31    0.000011          11         1           lseek
  0.28    0.000010           3         3           pread64
  0.25    0.000009           2         4           brk
  0.25    0.000009           3         3           sched_getaffinity
  0.22    0.000008           2         3           getpid
  0.22    0.000008           8         1           fcntl
  0.22    0.000008           8         1           gettid
  0.22    0.000008           2         4           prlimit64
  0.00    0.000000           0         1         1 access
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         1           sysinfo
  0.00    0.000000           0         2           statfs
  0.00    0.000000           0         1           arch_prctl
  0.00    0.000000           0         2           getdents64
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0         1           get_mempolicy
  0.00    0.000000           0         1           set_robust_list
  0.00    0.000000           0         1           getrandom
  0.00    0.000000           0         2           membarrier
  0.00    0.000000           0         1           rseq
------ ----------- ----------- --------- --------- ------------------
100.00    0.003586           7       470        96 total

C# (JIT)

$ strace -c ./bin/hello_csharp
Hello, World
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ------------------
 46.49    0.002176           6       343           mprotect
 18.44    0.000863           5       161           mmap
  9.25    0.000433           2       163        92 openat
  4.10    0.000192           5        37           munmap
  3.18    0.000149           3        38        34 readlink
  2.88    0.000135           6        21           pread64
  2.67    0.000125           1        67           fstat
  2.63    0.000123           5        22           fcntl
  2.22    0.000104           6        15           rt_sigprocmask
  1.60    0.000075           8         9           stat
  1.30    0.000061           1        61           close
  1.22    0.000057           8         7           clone3
  1.03    0.000048           2        24           rt_sigaction
  0.58    0.000027           0        58           read
  0.43    0.000020           3         6         6 access
  0.41    0.000019           1        11           brk
  0.34    0.000016           8         2           pipe2
  0.28    0.000013           1         9           futex
  0.26    0.000012           3         4           ioctl
  0.21    0.000010           2         5           getpid
  0.19    0.000009           1         8           write
  0.19    0.000009           0        23           madvise
  0.11    0.000005           5         1           lseek
  0.00    0.000000           0         1           socket
  0.00    0.000000           0         1           bind
  0.00    0.000000           0         1           listen
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         1           ftruncate
  0.00    0.000000           0         5         2 unlink
  0.00    0.000000           0         1           fchmod
  0.00    0.000000           0         2           sysinfo
  0.00    0.000000           0         1           getsid
  0.00    0.000000           0         2           sigaltstack
  0.00    0.000000           0         2           statfs
  0.00    0.000000           0         1           arch_prctl
  0.00    0.000000           0         1           gettid
  0.00    0.000000           0         4           sched_getaffinity
  0.00    0.000000           0         2           getdents64
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0         1           get_mempolicy
  0.00    0.000000           0         2           mknodat
  0.00    0.000000           0        16        12 newfstatat
  0.00    0.000000           0         1           set_robust_list
  0.00    0.000000           0        10           prlimit64
  0.00    0.000000           0         1           getrandom
  0.00    0.000000           0         1           memfd_create
  0.00    0.000000           0         4           membarrier
  0.00    0.000000           0         1           rseq
------ ----------- ----------- --------- --------- ------------------
100.00    0.004681           4      1159       146 total

元記事に比べてGoのシステムコール数が減っています。(911 -> 185前後) straceは決定論的に結果が出るわけではないので、実行ごとに多少のばらつきがありますが、明らかに違いがあります。Goのバージョンは元記事が1.24.0、今回が1.24.1なので、このような差が生まれる要因とは考えにくく、実際記事のリポジトリにあるコンテナを用いても本記事と同様の190前後でした。おや? 今回、Goの共有ライブラリ版も追加しましたが、こちらは24884回と非常に多くなっています。共有ライブラリ版は動的リンクを行うため、起動時に多くのシステムコールが発生するようです。とはいえ、さすがに多すぎる気もします。

本記事で追加したC# (JIT)とC# (AOT)ですが、JITは1159回、AOTは470回と大きな差があります。AOTはネイティブコードに変換されているので、JITのように実行時にコードを生成する必要がなく、その分システムコール数が減っています。これは、あとから見るwriteの数の違いでも分かります。

C#のopenatシステムコールとICU

C#はJITもシステムコールが多いですが、AOTにしてもまだシステムコールが多く特にopenatの数が目立ちます。openat/readlink/accessはerrorsがあるのも気になります。 straceでopenatを調べてみると、openat(…libicu*.so…)ログから、プログラムロード前にICU(国際化対応ライブラリ)のデータファイルを探しに行っていることが分かります。glibc-hwcapsバージョンごとにICUバージョンを90 > 89 > 88 ... 74と探索するため、openatが大きく増え、ICUファイルが見つからなければENOENTが出てerrorがカウントされます。最後にlibicuuc.so.74が見つかった瞬間から、libicudata.so.74libicui18n.so.74のロードに進んでいます。

結果、(候補バージョン数) × (探索ディレクトリ数) × (hwcaps分岐)でopenatもエラーが増えているわけです。

C# (AOT)のstraceログ全文(クリックで展開)

$ strace -f -e trace=openat,newfstatat,access -s 200 ./bin/hello_csharp_aot 2>&1
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/sys/devices/system/cpu/online", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/proc/self/mountinfo", O_RDONLY) = 3
openat(AT_FDCWD, "/proc/self/cgroup", O_RDONLY) = 3
openat(AT_FDCWD, "/proc/self/mountinfo", O_RDONLY) = 3
openat(AT_FDCWD, "/proc/self/cgroup", O_RDONLY) = 3
openat(AT_FDCWD, "/sys/fs/cgroup//cpu.max", O_RDONLY) = 3
strace: Process 160 attached
[pid   159] openat(AT_FDCWD, "/sys/fs/cgroup//memory.max", O_RDONLY) = 3
[pid   159] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index0/size", O_RDONLY) = 3
[pid   159] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index0/level", O_RDONLY) = 3
[pid   159] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index1/size", O_RDONLY) = 3
[pid   159] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index1/level", O_RDONLY) = 3
[pid   159] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index2/size", O_RDONLY) = 3
[pid   159] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index2/level", O_RDONLY) = 3
[pid   159] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index3/size", O_RDONLY) = 3
[pid   159] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index3/level", O_RDONLY) = 3
[pid   159] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index4/size", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/proc/meminfo", O_RDONLY) = 3
[pid   159] openat(AT_FDCWD, "/proc/self/maps", O_RDONLY|O_CLOEXEC) = 3
strace: Process 161 attached
[pid   159] openat(AT_FDCWD, "/root/.terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/root/.terminfo/78/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/etc/terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/etc/terminfo/78/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/lib/terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/lib/terminfo/78/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/share/terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = 6
[pid   159] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6
[pid   159] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v4/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] newfstatat(AT_FDCWD, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v4/", 0x7ffc1064fc30, 0) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] newfstatat(AT_FDCWD, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3/", 0x7ffc1064fc30, 0) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] newfstatat(AT_FDCWD, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2/", 0x7ffc1064fc30, 0) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] newfstatat(AT_FDCWD, "/lib/x86_64-linux-gnu/", {st_mode=S_IFDIR|0755, st_size=16384, ...}, 0) = 0
[pid   159] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v4/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] newfstatat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v4/", 0x7ffc1064fc30, 0) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] newfstatat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3/", 0x7ffc1064fc30, 0) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] newfstatat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2/", 0x7ffc1064fc30, 0) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] newfstatat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/", {st_mode=S_IFDIR|0755, st_size=16384, ...}, 0) = 0
[pid   159] openat(AT_FDCWD, "/lib/glibc-hwcaps/x86-64-v4/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] newfstatat(AT_FDCWD, "/lib/glibc-hwcaps/x86-64-v4/", 0x7ffc1064fc30, 0) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/lib/glibc-hwcaps/x86-64-v3/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] newfstatat(AT_FDCWD, "/lib/glibc-hwcaps/x86-64-v3/", 0x7ffc1064fc30, 0) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/lib/glibc-hwcaps/x86-64-v2/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] newfstatat(AT_FDCWD, "/lib/glibc-hwcaps/x86-64-v2/", 0x7ffc1064fc30, 0) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/lib/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] newfstatat(AT_FDCWD, "/lib/", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
[pid   159] openat(AT_FDCWD, "/usr/lib/glibc-hwcaps/x86-64-v4/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] newfstatat(AT_FDCWD, "/usr/lib/glibc-hwcaps/x86-64-v4/", 0x7ffc1064fc30, 0) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/glibc-hwcaps/x86-64-v3/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] newfstatat(AT_FDCWD, "/usr/lib/glibc-hwcaps/x86-64-v3/", 0x7ffc1064fc30, 0) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/glibc-hwcaps/x86-64-v2/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] newfstatat(AT_FDCWD, "/usr/lib/glibc-hwcaps/x86-64-v2/", 0x7ffc1064fc30, 0) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] newfstatat(AT_FDCWD, "/usr/lib/", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
[pid   159] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6
[pid   159] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.89", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.89", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/lib/libicuuc.so.89", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/libicuuc.so.89", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6
[pid   159] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.88", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.88", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/lib/libicuuc.so.88", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/libicuuc.so.88", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6
[pid   159] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.87", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.87", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/lib/libicuuc.so.87", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/libicuuc.so.87", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6
[pid   159] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.86", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.86", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/lib/libicuuc.so.86", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/libicuuc.so.86", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6
[pid   159] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.85", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.85", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/lib/libicuuc.so.85", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/libicuuc.so.85", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6
[pid   159] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.84", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.84", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/lib/libicuuc.so.84", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/libicuuc.so.84", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6
[pid   159] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.83", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.83", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/lib/libicuuc.so.83", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/libicuuc.so.83", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6
[pid   159] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.82", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.82", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/lib/libicuuc.so.82", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/libicuuc.so.82", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6
[pid   159] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.81", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.81", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/lib/libicuuc.so.81", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/libicuuc.so.81", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6
[pid   159] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.80", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.80", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/lib/libicuuc.so.80", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/libicuuc.so.80", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6
[pid   159] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.79", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.79", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/lib/libicuuc.so.79", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/libicuuc.so.79", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6
[pid   159] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.78", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.78", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/lib/libicuuc.so.78", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/libicuuc.so.78", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6
[pid   159] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.77", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.77", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/lib/libicuuc.so.77", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/libicuuc.so.77", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6
[pid   159] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.76", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.76", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/lib/libicuuc.so.76", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/libicuuc.so.76", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6
[pid   159] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.75", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.75", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/lib/libicuuc.so.75", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/usr/lib/libicuuc.so.75", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   159] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6
[pid   159] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.74", O_RDONLY|O_CLOEXEC) = 6
[pid   159] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicudata.so.74", O_RDONLY|O_CLOEXEC) = 6
[pid   159] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = 6
[pid   159] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 6
[pid   159] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6
[pid   159] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicui18n.so.74", O_RDONLY|O_CLOEXEC) = 6
Hello, World
[pid   161] +++ exited with 0 +++
[pid   160] +++ exited with 0 +++
+++ exited with 0 +++

C# (JIT)のstraceログ全文(クリックで展開)

$ strace -f -e trace=openat,newfstatat,access -s 200 ./bin/hello_csharp 2>&1
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/librt.so.1", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v4/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v4/", 0x7ffea13b05b0, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3/", 0x7ffea13b05b0, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2/", 0x7ffea13b05b0, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/x86_64-linux-gnu/", {st_mode=S_IFDIR|0755, st_size=16384, ...}, 0) = 0
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v4/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v4/", 0x7ffea13b05b0, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3/", 0x7ffea13b05b0, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2/", 0x7ffea13b05b0, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/", {st_mode=S_IFDIR|0755, st_size=16384, ...}, 0) = 0
openat(AT_FDCWD, "/lib/glibc-hwcaps/x86-64-v4/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/glibc-hwcaps/x86-64-v4/", 0x7ffea13b05b0, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/glibc-hwcaps/x86-64-v3/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/glibc-hwcaps/x86-64-v3/", 0x7ffea13b05b0, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/glibc-hwcaps/x86-64-v2/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/glibc-hwcaps/x86-64-v2/", 0x7ffea13b05b0, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
openat(AT_FDCWD, "/usr/lib/glibc-hwcaps/x86-64-v4/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/glibc-hwcaps/x86-64-v4/", 0x7ffea13b05b0, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/glibc-hwcaps/x86-64-v3/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/glibc-hwcaps/x86-64-v3/", 0x7ffea13b05b0, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/glibc-hwcaps/x86-64-v2/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/glibc-hwcaps/x86-64-v2/", 0x7ffea13b05b0, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 3
openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 3
openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 3
access("", F_OK)                        = -1 ENOENT (No such file or directory)
access("opt/coreservicing", F_OK)       = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 3
access("", F_OK)                        = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/proc/self/mountinfo", O_RDONLY) = 3
openat(AT_FDCWD, "/proc/self/cgroup", O_RDONLY) = 3
strace: Process 55 attached
[pid    54] openat(AT_FDCWD, "/sys/fs/cgroup//cpu.max", O_RDONLY) = 8
[pid    54] openat(AT_FDCWD, "/dev/urandom", O_RDONLY|O_CLOEXEC) = 9
[pid    54] openat(AT_FDCWD, "/proc/54/stat", O_RDONLY) = 10
strace: Process 56 attached
[pid    54] openat(AT_FDCWD, "/sys/devices/system/cpu/online", O_RDONLY|O_CLOEXEC) = 11
[pid    54] openat(AT_FDCWD, "/proc/self/mountinfo", O_RDONLY) = 11
[pid    54] openat(AT_FDCWD, "/proc/self/cgroup", O_RDONLY) = 11
[pid    54] openat(AT_FDCWD, "/proc/54/stat", O_RDONLY) = 11
[pid    54] openat(AT_FDCWD, "/proc/54/stat", O_RDONLY) = 11
strace: Process 57 attached
strace: Process 58 attached
[pid    57] openat(AT_FDCWD, "/tmp/clr-debug-pipe-54-2245245-in", O_RDONLY <unfinished ...>
[pid    54] openat(AT_FDCWD, "/proc/54/stat", O_RDONLY) = 14
[pid    54] openat(AT_FDCWD, "/dev/shm/sem.clrst00000036000000000022427d", O_RDWR|O_NOFOLLOW|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/sys/fs/cgroup//memory.max", O_RDONLY) = 12
[pid    54] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index0/size", O_RDONLY) = 12
[pid    54] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index0/level", O_RDONLY) = 12
[pid    54] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index1/size", O_RDONLY) = 12
[pid    54] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index1/level", O_RDONLY) = 12
[pid    54] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index2/size", O_RDONLY) = 12
[pid    54] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index2/level", O_RDONLY) = 12
[pid    54] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index3/size", O_RDONLY) = 12
[pid    54] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index3/level", O_RDONLY) = 12
[pid    54] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index4/size", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/proc/meminfo", O_RDONLY) = 12
[pid    54] openat(AT_FDCWD, "/proc/self/maps", O_RDONLY|O_CLOEXEC) = 12
[pid    54] openat(AT_FDCWD, "/proc/self/maps", O_RDONLY|O_CLOEXEC) = 12
strace: Process 59 attached
[pid    54] openat(AT_FDCWD, "/proc/self/task/59/comm", O_RDWR) = 14
[pid    54] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 12
strace: Process 60 attached
[pid    54] openat(AT_FDCWD, "/proc/self/task/60/comm", O_RDWR) = 16
[pid    54] access("", F_OK)            = -1 ENOENT (No such file or directory)
[pid    54] access("opt/corebreadcrumbs", F_OK) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 14
[pid    54] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 16
[pid    54] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 18
[pid    54] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 20
[pid    54] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 22
[pid    54] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 25
strace: Process 61 attached
[pid    54] openat(AT_FDCWD, "/root/.terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/root/.terminfo/78/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/etc/terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/etc/terminfo/78/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/lib/terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/lib/terminfo/78/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/share/terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = 29
[pid    54] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 30
[pid    54] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 32
[pid    54] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29
[pid    54] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/lib/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29
[pid    54] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.89", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.89", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/lib/libicuuc.so.89", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/libicuuc.so.89", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29
[pid    54] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.88", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.88", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/lib/libicuuc.so.88", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/libicuuc.so.88", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29
[pid    54] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.87", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.87", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/lib/libicuuc.so.87", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/libicuuc.so.87", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29
[pid    54] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.86", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.86", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/lib/libicuuc.so.86", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/libicuuc.so.86", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29
[pid    54] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.85", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.85", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/lib/libicuuc.so.85", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/libicuuc.so.85", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29
[pid    54] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.84", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.84", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/lib/libicuuc.so.84", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/libicuuc.so.84", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29
[pid    54] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.83", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.83", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/lib/libicuuc.so.83", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/libicuuc.so.83", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29
[pid    54] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.82", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.82", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/lib/libicuuc.so.82", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/libicuuc.so.82", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29
[pid    54] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.81", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.81", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/lib/libicuuc.so.81", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/libicuuc.so.81", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29
[pid    54] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.80", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.80", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/lib/libicuuc.so.80", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/libicuuc.so.80", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29
[pid    54] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.79", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.79", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/lib/libicuuc.so.79", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/libicuuc.so.79", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29
[pid    54] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.78", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.78", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/lib/libicuuc.so.78", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/libicuuc.so.78", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29
[pid    54] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.77", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.77", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/lib/libicuuc.so.77", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/libicuuc.so.77", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29
[pid    54] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.76", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.76", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/lib/libicuuc.so.76", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/libicuuc.so.76", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29
[pid    54] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.75", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libicuuc.so.75", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/lib/libicuuc.so.75", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/usr/lib/libicuuc.so.75", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    54] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29
[pid    54] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.74", O_RDONLY|O_CLOEXEC) = 29
[pid    54] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicudata.so.74", O_RDONLY|O_CLOEXEC) = 29
[pid    54] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29
[pid    54] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicui18n.so.74", O_RDONLY|O_CLOEXEC) = 29
Hello, World
[pid    57] <... openat resumed>)       = ?
[pid    60] +++ exited with 0 +++
[pid    61] +++ exited with 0 +++
[pid    59] +++ exited with 0 +++
[pid    58] +++ exited with 0 +++
[pid    57] +++ exited with 0 +++
[pid    56] +++ exited with 0 +++
[pid    55] +++ exited with 0 +++
+++ exited with 0 +++

ICUの読み込みを無効化する

DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1を指定するとICUの読み込みを無効化できます。この状態でstraceを取ると、C# AOT、JIT共にopenatが減っています。

  • C# AOT: 全体の数が470から228へ、openatの数が129 (83)から28 (7)へ減少
  • C# JIT: 全体の数が1159から940へ、openatの数が163 (92)から77 (28)へ減少

C# (AOT)

$ DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 strace -c ./bin/hello_csharp_aot
Hello, World
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ------------------
 18.23    0.000144           5        28         7 openat
 14.18    0.000112           6        18           rt_sigaction
 14.05    0.000111          55         2           clone
  8.48    0.000067           2        30           read
  6.84    0.000054          13         4           ioctl
  6.46    0.000051           2        22           mprotect
  4.81    0.000038           6         6           rt_sigprocmask
  4.68    0.000037          18         2           write
  3.16    0.000025           1        20           mmap
  2.78    0.000022           1        21           close
  2.78    0.000022           1        17           madvise
  2.53    0.000020           1        20           fstat
  2.28    0.000018          18         1           pipe2
  1.65    0.000013           4         3           pread64
  1.39    0.000011           3         3           sched_getaffinity
  1.27    0.000010          10         1           fcntl
  1.14    0.000009           9         1           lseek
  1.14    0.000009           3         3           getpid
  1.14    0.000009           2         4           prlimit64
  1.01    0.000008           8         1           gettid
  0.00    0.000000           0         4           munmap
  0.00    0.000000           0         3           brk
  0.00    0.000000           0         1         1 access
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         1           sysinfo
  0.00    0.000000           0         2           statfs
  0.00    0.000000           0         1           arch_prctl
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0         1         1 get_mempolicy
  0.00    0.000000           0         1           set_robust_list
  0.00    0.000000           0         1           getrandom
  0.00    0.000000           0         2           membarrier
  0.00    0.000000           0         1           rseq
  0.00    0.000000           0         1         1 clone3
------ ----------- ----------- --------- --------- ------------------
100.00    0.000790           3       228        10 total

C# (JIT)

$ DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 strace -c ./bin/hello_csharp
Hello, World
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ------------------
 22.62    0.002220           7       314           mprotect
 14.36    0.001410          11       128           mmap
 12.74    0.001251          16        77        28 openat
  7.71    0.000757          14        52           read
  4.49    0.000441           9        45           fstat
  3.95    0.000388          55         7           clone
  3.80    0.000373           9        38        34 readlink
  3.50    0.000344          18        19           munmap
  3.48    0.000342           8        39           close
  3.28    0.000322          21        15           rt_sigprocmask
  2.56    0.000251          11        21           pread64
  2.07    0.000203           8        23           madvise
  1.79    0.000176          11        16        12 newfstatat
  1.78    0.000175           7        24           rt_sigaction
  1.34    0.000132           6        22           fcntl
  1.07    0.000105          11         9           stat
  1.03    0.000101          10        10           prlimit64
  0.99    0.000097          97         1           bind
  0.69    0.000068           6        10           brk
  0.68    0.000067          11         6         6 access
  0.57    0.000056          28         2           mknodat
  0.52    0.000051           6         8           write
  0.37    0.000036           7         5         2 unlink
  0.35    0.000034           4         8           futex
  0.34    0.000033          16         2           pipe2
  0.34    0.000033           8         4           membarrier
  0.33    0.000032          32         1           socket
  0.32    0.000031           7         4           sched_getaffinity
  0.31    0.000030           6         5           getpid
  0.31    0.000030          15         2           sysinfo
  0.31    0.000030          15         2           statfs
  0.22    0.000022          22         1           gettid
  0.21    0.000021           5         4           ioctl
  0.20    0.000020          10         2           sigaltstack
  0.18    0.000018          18         1           memfd_create
  0.12    0.000012          12         1           ftruncate
  0.12    0.000012          12         1           fchmod
  0.12    0.000012          12         1         1 clone3
  0.11    0.000011          11         1           listen
  0.10    0.000010          10         1           set_tid_address
  0.09    0.000009           9         1           getsid
  0.09    0.000009           9         1         1 get_mempolicy
  0.09    0.000009           9         1           set_robust_list
  0.09    0.000009           9         1           getrandom
  0.08    0.000008           8         1           arch_prctl
  0.08    0.000008           8         1           rseq
  0.07    0.000007           7         1           lseek
  0.00    0.000000           0         1           execve
------ ----------- ----------- --------- --------- ------------------
100.00    0.009816          10       940        84 total

openatの呼び出しログからもICU探索ブロックが丸ごと消えています。

C# (AOT)

$ DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 strace -f -e trace=openat,newfstatat,access -s 200 ./bin/hello_csharp_aot 2>&1
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/sys/devices/system/cpu/online", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/proc/self/mountinfo", O_RDONLY) = 3
openat(AT_FDCWD, "/proc/self/cgroup", O_RDONLY) = 3
openat(AT_FDCWD, "/proc/self/mountinfo", O_RDONLY) = 3
openat(AT_FDCWD, "/proc/self/cgroup", O_RDONLY) = 3
openat(AT_FDCWD, "/sys/fs/cgroup//cpu.max", O_RDONLY) = 3
strace: Process 187 attached
[pid   186] openat(AT_FDCWD, "/sys/fs/cgroup//memory.max", O_RDONLY) = 3
[pid   186] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index0/size", O_RDONLY) = 3
[pid   186] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index0/level", O_RDONLY) = 3
[pid   186] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index1/size", O_RDONLY) = 3
[pid   186] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index1/level", O_RDONLY) = 3
[pid   186] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index2/size", O_RDONLY) = 3
[pid   186] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index2/level", O_RDONLY) = 3
[pid   186] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index3/size", O_RDONLY) = 3
[pid   186] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index3/level", O_RDONLY) = 3
[pid   186] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index4/size", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid   186] openat(AT_FDCWD, "/proc/meminfo", O_RDONLY) = 3
[pid   186] openat(AT_FDCWD, "/proc/self/maps", O_RDONLY|O_CLOEXEC) = 3
strace: Process 188 attached
[pid   186] openat(AT_FDCWD, "/root/.terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   186] openat(AT_FDCWD, "/root/.terminfo/78/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   186] openat(AT_FDCWD, "/etc/terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   186] openat(AT_FDCWD, "/etc/terminfo/78/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   186] openat(AT_FDCWD, "/lib/terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   186] openat(AT_FDCWD, "/lib/terminfo/78/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   186] openat(AT_FDCWD, "/usr/share/terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = 6
Hello, World
[pid   188] +++ exited with 0 +++
[pid   187] +++ exited with 0 +++
+++ exited with 0 +++

C# (JIT)のstraceログ全文(クリックで展開)

$ DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 strace -f -e trace=openat,newfstatat,access -s 200 ./bin/hello_csharp 2>&1
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/librt.so.1", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v4/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v4/", 0x7fff38292300, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3/", 0x7fff38292300, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2/", 0x7fff38292300, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/x86_64-linux-gnu/", {st_mode=S_IFDIR|0755, st_size=16384, ...}, 0) = 0
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v4/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v4/", 0x7fff38292300, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3/", 0x7fff38292300, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2/", 0x7fff38292300, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/", {st_mode=S_IFDIR|0755, st_size=16384, ...}, 0) = 0
openat(AT_FDCWD, "/lib/glibc-hwcaps/x86-64-v4/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/glibc-hwcaps/x86-64-v4/", 0x7fff38292300, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/glibc-hwcaps/x86-64-v3/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/glibc-hwcaps/x86-64-v3/", 0x7fff38292300, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/glibc-hwcaps/x86-64-v2/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/glibc-hwcaps/x86-64-v2/", 0x7fff38292300, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
openat(AT_FDCWD, "/usr/lib/glibc-hwcaps/x86-64-v4/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/glibc-hwcaps/x86-64-v4/", 0x7fff38292300, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/glibc-hwcaps/x86-64-v3/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/glibc-hwcaps/x86-64-v3/", 0x7fff38292300, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/glibc-hwcaps/x86-64-v2/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/glibc-hwcaps/x86-64-v2/", 0x7fff38292300, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 3
openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 3
openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 3
access("", F_OK)                        = -1 ENOENT (No such file or directory)
access("opt/coreservicing", F_OK)       = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 3
access("", F_OK)                        = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/proc/self/mountinfo", O_RDONLY) = 3
openat(AT_FDCWD, "/proc/self/cgroup", O_RDONLY) = 3
strace: Process 128 attached
[pid   127] openat(AT_FDCWD, "/sys/fs/cgroup//cpu.max", O_RDONLY) = 8
[pid   127] openat(AT_FDCWD, "/dev/urandom", O_RDONLY|O_CLOEXEC) = 9
[pid   127] openat(AT_FDCWD, "/proc/127/stat", O_RDONLY) = 10
strace: Process 129 attached
[pid   127] openat(AT_FDCWD, "/sys/devices/system/cpu/online", O_RDONLY|O_CLOEXEC) = 11
[pid   127] openat(AT_FDCWD, "/proc/self/mountinfo", O_RDONLY) = 11
[pid   127] openat(AT_FDCWD, "/proc/self/cgroup", O_RDONLY) = 11
[pid   127] openat(AT_FDCWD, "/proc/127/stat", O_RDONLY) = 11
[pid   127] openat(AT_FDCWD, "/proc/127/stat", O_RDONLY) = 11
strace: Process 130 attached
[pid   130] openat(AT_FDCWD, "/tmp/clr-debug-pipe-127-2260796-in", O_RDONLYstrace: Process 131 attached
 <unfinished ...>
[pid   127] openat(AT_FDCWD, "/proc/127/stat", O_RDONLY) = 14
[pid   127] openat(AT_FDCWD, "/dev/shm/sem.clrst0000007f0000000000227f3c", O_RDWR|O_NOFOLLOW|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   127] openat(AT_FDCWD, "/sys/fs/cgroup//memory.max", O_RDONLY) = 12
[pid   127] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index0/size", O_RDONLY) = 12
[pid   127] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index0/level", O_RDONLY) = 12
[pid   127] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index1/size", O_RDONLY) = 12
[pid   127] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index1/level", O_RDONLY) = 12
[pid   127] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index2/size", O_RDONLY) = 12
[pid   127] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index2/level", O_RDONLY) = 12
[pid   127] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index3/size", O_RDONLY) = 12
[pid   127] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index3/level", O_RDONLY) = 12
[pid   127] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index4/size", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid   127] openat(AT_FDCWD, "/proc/meminfo", O_RDONLY) = 12
[pid   127] openat(AT_FDCWD, "/proc/self/maps", O_RDONLY|O_CLOEXEC) = 12
[pid   127] openat(AT_FDCWD, "/proc/self/maps", O_RDONLY|O_CLOEXEC) = 12
strace: Process 132 attached
[pid   127] openat(AT_FDCWD, "/proc/self/task/132/comm", O_RDWR) = 14
[pid   127] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 12
strace: Process 133 attached
[pid   127] openat(AT_FDCWD, "/proc/self/task/133/comm", O_RDWR) = 16
[pid   127] access("", F_OK)            = -1 ENOENT (No such file or directory)
[pid   127] access("opt/corebreadcrumbs", F_OK) = -1 ENOENT (No such file or directory)
[pid   127] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 14
[pid   127] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 16
[pid   127] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 18
[pid   127] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 20
[pid   127] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 22
[pid   127] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 25
strace: Process 134 attached
[pid   127] openat(AT_FDCWD, "/root/.terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   127] openat(AT_FDCWD, "/root/.terminfo/78/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   127] openat(AT_FDCWD, "/etc/terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   127] openat(AT_FDCWD, "/etc/terminfo/78/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   127] openat(AT_FDCWD, "/lib/terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   127] openat(AT_FDCWD, "/lib/terminfo/78/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   127] openat(AT_FDCWD, "/usr/share/terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = 29
[pid   127] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 30
[pid   127] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 32
Hello, World
[pid   130] <... openat resumed>)       = ?
[pid   133] +++ exited with 0 +++
[pid   132] +++ exited with 0 +++
[pid   131] +++ exited with 0 +++
[pid   130] +++ exited with 0 +++
[pid   129] +++ exited with 0 +++
[pid   128] +++ exited with 0 +++
[pid   134] +++ exited with 0 +++
+++ exited with 0 +++

ICUバージョンを指定する

ICU探索が重いからと言って、グローバリゼーションを無効にしてもいいアプリケーションばかりではありません。当然多言語対応が必要な場合もあります。この場合、ICUライブラリバージョンを指定するか、アプリに同梱する手があります。DOTNET_ICU_VERSION_OVERRIDE=74でICUバージョンを指定でき、該当バージョンのICUライブラリだけを探索するようになります。この状態でstraceを取ると、C# AOT、JIT共にopenatが減っています。

  • C# (AOT): 全体の数が470から290 (無効だと228)へ、openatの数が129 (83)から35(7)(無効だと28 (7))へ減少
  • C# (JIT): 全体の数が1159から985 (無効だと940)へ、openatの数が163 (92)から82(28)(無効だと77 (28))へ減少

C# (AOT)

$ DOTNET_ICU_VERSION_OVERRIDE=74 strace -c ./bin/hello_csharp_aot
Hello, World
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ------------------
 22.68    0.000414           9        45           mmap
 13.86    0.000253           7        35         7 openat
 11.45    0.000209           7        27           mprotect
  7.07    0.000129           3        35           read
  5.37    0.000098           3        28           close
  5.37    0.000098           5        17           madvise
  5.26    0.000096           5        18           rt_sigaction
  5.15    0.000094           3        27           fstat
  4.66    0.000085          14         6           rt_sigprocmask
  3.67    0.000067          33         2           clone
  3.34    0.000061          10         6           munmap
  2.74    0.000050          12         4           ioctl
  2.03    0.000037          18         2           write
  1.48    0.000027           9         3           futex
  1.04    0.000019          19         1           pipe2
  0.77    0.000014           4         3           sched_getaffinity
  0.77    0.000014           3         4           prlimit64
  0.66    0.000012           4         3           pread64
  0.60    0.000011           2         4           brk
  0.55    0.000010          10         1           fcntl
  0.49    0.000009           9         1           lseek
  0.49    0.000009           3         3           getpid
  0.49    0.000009           9         1           gettid
  0.00    0.000000           0         1         1 access
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         1           sysinfo
  0.00    0.000000           0         2           statfs
  0.00    0.000000           0         1           arch_prctl
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0         1         1 get_mempolicy
  0.00    0.000000           0         1           set_robust_list
  0.00    0.000000           0         1           getrandom
  0.00    0.000000           0         2           membarrier
  0.00    0.000000           0         1           rseq
  0.00    0.000000           0         1         1 clone3
------ ----------- ----------- --------- --------- ------------------
100.00    0.001825           6       290        10 total

C# (JIT)

$ DOTNET_ICU_VERSION_OVERRIDE=74 strace -c ./bin/hello_csharp
Hello, World
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ------------------
 38.07    0.003370          10       322           mprotect
 16.23    0.001437           9       144           mmap
  9.27    0.000821          10        82        28 openat
  4.80    0.000425           7        55           read
  4.06    0.000359          51         7           clone
  3.66    0.000324           6        50           fstat
  3.28    0.000290          13        21           pread64
  2.64    0.000234           5        44           close
  2.04    0.000181           7        23           madvise
  2.01    0.000178           4        38        34 readlink
  1.86    0.000165          18         9           stat
  1.82    0.000161           7        21           munmap
  1.69    0.000150          18         8           write
  1.66    0.000147           6        22           fcntl
  1.60    0.000142           9        15           rt_sigprocmask
  1.17    0.000104           4        24           rt_sigaction
  1.01    0.000089           9         9           futex
  0.66    0.000058           5        10           brk
  0.59    0.000052          13         4           ioctl
  0.51    0.000045           9         5         2 unlink
  0.40    0.000035           3        10           prlimit64
  0.28    0.000025           5         5           getpid
  0.23    0.000020           5         4           sched_getaffinity
  0.21    0.000019           3         6         6 access
  0.14    0.000012           6         2           pipe2
  0.11    0.000010          10         1           lseek
  0.00    0.000000           0         1           socket
  0.00    0.000000           0         1           bind
  0.00    0.000000           0         1           listen
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         1           ftruncate
  0.00    0.000000           0         1           fchmod
  0.00    0.000000           0         2           sysinfo
  0.00    0.000000           0         1           getsid
  0.00    0.000000           0         2           sigaltstack
  0.00    0.000000           0         2           statfs
  0.00    0.000000           0         1           arch_prctl
  0.00    0.000000           0         1           gettid
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0         1         1 get_mempolicy
  0.00    0.000000           0         2           mknodat
  0.00    0.000000           0        16        12 newfstatat
  0.00    0.000000           0         1           set_robust_list
  0.00    0.000000           0         1           getrandom
  0.00    0.000000           0         1           memfd_create
  0.00    0.000000           0         4           membarrier
  0.00    0.000000           0         1           rseq
  0.00    0.000000           0         1         1 clone3
------ ----------- ----------- --------- --------- ------------------
100.00    0.008853           8       985        84 total

straceでopenatの呼び出しログを見ると、ICU探索ブロックが期待通り1つだけ存在し、ENOENTも発生していません。

$ DOTNET_ICU_VERSION_OVERRIDE=74 strace -f -e trace=openat,newfstatat,access -s 200 ./bin/hello_csharp_aot
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/sys/devices/system/cpu/online", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/proc/self/mountinfo", O_RDONLY) = 3
openat(AT_FDCWD, "/proc/self/cgroup", O_RDONLY) = 3
openat(AT_FDCWD, "/proc/self/mountinfo", O_RDONLY) = 3
openat(AT_FDCWD, "/proc/self/cgroup", O_RDONLY) = 3
openat(AT_FDCWD, "/sys/fs/cgroup//cpu.max", O_RDONLY) = 3
strace: Process 175 attached
[pid   174] openat(AT_FDCWD, "/sys/fs/cgroup//memory.max", O_RDONLY) = 3
[pid   174] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index0/size", O_RDONLY) = 3
[pid   174] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index0/level", O_RDONLY) = 3
[pid   174] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index1/size", O_RDONLY) = 3
[pid   174] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index1/level", O_RDONLY) = 3
[pid   174] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index2/size", O_RDONLY) = 3
[pid   174] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index2/level", O_RDONLY) = 3
[pid   174] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index3/size", O_RDONLY) = 3
[pid   174] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index3/level", O_RDONLY) = 3
[pid   174] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index4/size", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid   174] openat(AT_FDCWD, "/proc/meminfo", O_RDONLY) = 3
[pid   174] openat(AT_FDCWD, "/proc/self/maps", O_RDONLY|O_CLOEXEC) = 3
strace: Process 176 attached
[pid   174] openat(AT_FDCWD, "/root/.terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   174] openat(AT_FDCWD, "/root/.terminfo/78/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   174] openat(AT_FDCWD, "/etc/terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   174] openat(AT_FDCWD, "/etc/terminfo/78/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   174] openat(AT_FDCWD, "/lib/terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   174] openat(AT_FDCWD, "/lib/terminfo/78/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   174] openat(AT_FDCWD, "/usr/share/terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = 6
[pid   174] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6
[pid   174] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.74", O_RDONLY|O_CLOEXEC) = 6
[pid   174] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicudata.so.74", O_RDONLY|O_CLOEXEC) = 6
[pid   174] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = 6
[pid   174] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 6
[pid   174] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6
[pid   174] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicui18n.so.74", O_RDONLY|O_CLOEXEC) = 6
Hello, World
[pid   176] +++ exited with 0 +++
[pid   175] +++ exited with 0 +++
+++ exited with 0 +++

C# (JIT)のstraceログ全文(クリックで展開)

$ DOTNET_ICU_VERSION_OVERRIDE=74 strace -f -e trace=openat,newfstatat,access -s 200 ./bin/hello_csharp 2>&1
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/librt.so.1", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v4/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v4/", 0x7fffa888a720, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3/", 0x7fffa888a720, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2/", 0x7fffa888a720, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/x86_64-linux-gnu/", {st_mode=S_IFDIR|0755, st_size=16384, ...}, 0) = 0
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v4/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v4/", 0x7fffa888a720, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3/", 0x7fffa888a720, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2/", 0x7fffa888a720, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/", {st_mode=S_IFDIR|0755, st_size=16384, ...}, 0) = 0
openat(AT_FDCWD, "/lib/glibc-hwcaps/x86-64-v4/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/glibc-hwcaps/x86-64-v4/", 0x7fffa888a720, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/glibc-hwcaps/x86-64-v3/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/glibc-hwcaps/x86-64-v3/", 0x7fffa888a720, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/glibc-hwcaps/x86-64-v2/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/glibc-hwcaps/x86-64-v2/", 0x7fffa888a720, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/lib/", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
openat(AT_FDCWD, "/usr/lib/glibc-hwcaps/x86-64-v4/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/glibc-hwcaps/x86-64-v4/", 0x7fffa888a720, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/glibc-hwcaps/x86-64-v3/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/glibc-hwcaps/x86-64-v3/", 0x7fffa888a720, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/glibc-hwcaps/x86-64-v2/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/glibc-hwcaps/x86-64-v2/", 0x7fffa888a720, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(AT_FDCWD, "/usr/lib/", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/lib/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 3
openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 3
openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 3
access("", F_OK)                        = -1 ENOENT (No such file or directory)
access("opt/coreservicing", F_OK)       = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 3
access("", F_OK)                        = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/proc/self/mountinfo", O_RDONLY) = 3
openat(AT_FDCWD, "/proc/self/cgroup", O_RDONLY) = 3
strace: Process 92 attached
[pid    91] openat(AT_FDCWD, "/sys/fs/cgroup//cpu.max", O_RDONLY) = 8
[pid    91] openat(AT_FDCWD, "/dev/urandom", O_RDONLY|O_CLOEXEC) = 9
[pid    91] openat(AT_FDCWD, "/proc/91/stat", O_RDONLY) = 10
strace: Process 93 attached
[pid    91] openat(AT_FDCWD, "/sys/devices/system/cpu/online", O_RDONLY|O_CLOEXEC) = 11
[pid    91] openat(AT_FDCWD, "/proc/self/mountinfo", O_RDONLY) = 11
[pid    91] openat(AT_FDCWD, "/proc/self/cgroup", O_RDONLY) = 11
[pid    91] openat(AT_FDCWD, "/proc/91/stat", O_RDONLY) = 11
[pid    91] openat(AT_FDCWD, "/proc/91/stat", O_RDONLY) = 11
strace: Process 94 attached
[pid    94] openat(AT_FDCWD, "/tmp/clr-debug-pipe-91-2255926-in", O_RDONLYstrace: Process 95 attached
 <unfinished ...>
[pid    91] openat(AT_FDCWD, "/proc/91/stat", O_RDONLY) = 14
[pid    91] openat(AT_FDCWD, "/dev/shm/sem.clrst0000005b0000000000226c36", O_RDWR|O_NOFOLLOW|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    91] openat(AT_FDCWD, "/sys/fs/cgroup//memory.max", O_RDONLY) = 12
[pid    91] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index0/size", O_RDONLY) = 12
[pid    91] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index0/level", O_RDONLY) = 12
[pid    91] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index1/size", O_RDONLY) = 12
[pid    91] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index1/level", O_RDONLY) = 12
[pid    91] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index2/size", O_RDONLY) = 12
[pid    91] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index2/level", O_RDONLY) = 12
[pid    91] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index3/size", O_RDONLY) = 12
[pid    91] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index3/level", O_RDONLY) = 12
[pid    91] openat(AT_FDCWD, "/sys/devices/system/cpu/cpu0/cache/index4/size", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid    91] openat(AT_FDCWD, "/proc/meminfo", O_RDONLY) = 12
[pid    91] openat(AT_FDCWD, "/proc/self/maps", O_RDONLY|O_CLOEXEC) = 12
[pid    91] openat(AT_FDCWD, "/proc/self/maps", O_RDONLY|O_CLOEXEC) = 12
strace: Process 96 attached
[pid    91] openat(AT_FDCWD, "/proc/self/task/96/comm", O_RDWR) = 14
[pid    91] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 12
strace: Process 97 attached
[pid    91] openat(AT_FDCWD, "/proc/self/task/97/comm", O_RDWR) = 16
[pid    91] access("", F_OK)            = -1 ENOENT (No such file or directory)
[pid    91] access("opt/corebreadcrumbs", F_OK) = -1 ENOENT (No such file or directory)
[pid    91] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 14
[pid    91] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 16
[pid    91] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 18
[pid    91] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 20
[pid    91] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 22
[pid    91] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 25
strace: Process 98 attached
[pid    91] openat(AT_FDCWD, "/root/.terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    91] openat(AT_FDCWD, "/root/.terminfo/78/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    91] openat(AT_FDCWD, "/etc/terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    91] openat(AT_FDCWD, "/etc/terminfo/78/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    91] openat(AT_FDCWD, "/lib/terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    91] openat(AT_FDCWD, "/lib/terminfo/78/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid    91] openat(AT_FDCWD, "/usr/share/terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = 29
[pid    91] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 30
[pid    91] openat(AT_FDCWD, "/workspace/bin/hello_csharp", O_RDONLY) = 32
[pid    91] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29
[pid    91] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicuuc.so.74", O_RDONLY|O_CLOEXEC) = 29
[pid    91] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicudata.so.74", O_RDONLY|O_CLOEXEC) = 29
[pid    91] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29
[pid    91] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libicui18n.so.74", O_RDONLY|O_CLOEXEC) = 29
Hello, World
[pid    94] <... openat resumed>)       = ?
[pid    97] +++ exited with 0 +++
[pid    96] +++ exited with 0 +++
[pid    95] +++ exited with 0 +++
[pid    94] +++ exited with 0 +++
[pid    93] +++ exited with 0 +++
[pid    92] +++ exited with 0 +++
[pid    98] +++ exited with 0 +++
+++ exited with 0 +++

ICUを指定するためには、対象環境に入っているICUライブラリのバージョンを知る必要があります。これはldconfig -pで確認できます。

$ ldconfig -p | grep -E 'libicu(uc|i18n)\.so' | head -n 50
        libicuuc.so.74 (libc6,x86-64) => /lib/x86_64-linux-gnu/libicuuc.so.74
        libicui18n.so.74 (libc6,x86-64) => /lib/x86_64-linux-gnu/libicui18n.so.74

あるいはアプリケーションでICUバージョンを指定できるので、いずれかを使うと良いでしょう。

InvariantCultureを使えればいいのですが、そうでない場合はICUバージョン指定で起動時間を改善できるのはなるほどです。

C# AOTのopenatシステムコール

他のopenat呼び出しも見てみましょう。straceログから、ICUを除いたopenatの呼び出しは以下だけに限定されています。2

  • /sys/devices/system/cpu/...
  • /proc/self/mountinfo, /proc/self/cgroup
  • /sys/fs/cgroup/.../cpu.max, memory.max
  • /proc/meminfo, /proc/self/maps
  • /dev/urandom
  • terminfo探索

他言語を見てみると、CとRustはlibcを通じて同様の情報を取得しているようです。Goはランタイムが独自に実装しているため、プロセスを複数生成して情報を集めています。こうやって見ると、C#の追加分は、いくつかシステムファイルを読んだり、icu、terminfoを読んだりしているためとわかります。

C

$ strace -f -e trace=openat,newfstatat,access -s 200 ./bin/hello_c 2>&1
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
Hello World
+++ exited with 0 +++

Rust

$ strace -f -e trace=openat,newfstatat,access -s 200 ./bin/hello_rust 2>&1
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/proc/self/maps", O_RDONLY|O_CLOEXEC) = 3
Hello World
+++ exited with 0 +++

Go

$ strace -f -e trace=openat,newfstatat,access -s 200 ./bin/hello_go 2>&1
openat(AT_FDCWD, "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size", O_RDONLY) = 3
strace: Process 239 attached
strace: Process 240 attached
[pid   238] --- SIGURG {si_signo=SIGURG, si_code=SI_TKILL, si_pid=238, si_uid=0} ---
strace: Process 241 attached
strace: Process 242 attached
strace: Process 243 attached
Hello World
[pid   243] +++ exited with 0 +++
[pid   242] +++ exited with 0 +++
[pid   241] +++ exited with 0 +++
[pid   240] +++ exited with 0 +++
[pid   239] +++ exited with 0 +++
+++ exited with 0 +++

C#ランタイムが読むシステムファイルの意味

C#が/sys,/procを色々読んでいるのは、dotnetランタイムがコンテナ/CPU/メモリのチューニングに必要なためです。index4ENOENTなのは単にそのCPUにindex4が無いので、最後まで試しているだけです。環境検出(CPU/NUMA/キャッシュ)、制限検出(cgroup)、メモリ検出、乱数、Console(terminfo)の5系統しかなく、パスが固定なので、起動時決め打ちの必要な情報を取っているように見えます。

他言語より多いものの、むしろC/Rustは最低限の情報しか取っていないとも言えます。

コンテナリソース制限(cgroup)検出

これらはdotnetランタイムがコンテナ内のCPU quotaやメモリ上限を読むためのものです。実際、dotnetランタイムのGCはコンテナリソース制限を考慮して動作するため必要な情報です。

  • /proc/self/mountinfo
  • /proc/self/cgroup:
  • /sys/fs/cgroup/.../cpu.max
  • /sys/fs/cgroup/.../memory.max

CPU情報

CPUトポロジ/キャッシュ階層を取得しています。dotnetランタイムが、GCのセグメント/ヒープ構成やスレッドプールや初期パラメーターに必要な情報です。

  • /sys/devices/system/cpu/online
  • cpu0/cache/index*/{size,level}

メモリ情報・自己マップ

物理メモリ等、自プロセスのマップ(保護設定、診断、アンワインド/例外、スタック関連など)でランタイム起動時に必要な情報です。

  • /proc/meminfo
  • /proc/self/maps:

乱数

ハッシュのランダム化やセキュリティ機能のために乱数を取得します。

  • /dev/urandom

terminfo

TERM=dumbにしても1しか減らないことから、Console周りがterminfoをスキップしない、あるいはTERM=dumbでも最低限の確認をしているようです。terminfoで6回ENOENTが出ているのは嫌ですが、まぁ仕方ないでしょう。

  • ~/.terminfo/
  • /etc/terminfo/
  • /lib/terminfo/
  • /usr/share/terminfo

C#のwriteシステムコール

ここまでopenatを見てきましたが、writeシステムコールが他言語は標準出力の1回だけなのに対して、C# AOTは2回、JITは8回呼ばれています。これは割と特徴的なのでwriteシステムコールを深堀りしてみましょう。strace -e writeを実行した結果が以下です。

C

$ strace -e write ./bin/hello_c > /dev/null
write(1, "Hello World\n", 12)           = 12
+++ exited with 0 +++

Rust

$ strace -e write ./bin/hello_rust > /dev/null
write(1, "Hello World\n", 12)           = 12
+++ exited with 0 +++

Go

$ strace -e write ./bin/hello_go > /dev/null
--- SIGURG {si_signo=SIGURG, si_code=SI_TKILL, si_pid=5462, si_uid=0} ---
--- SIGURG {si_signo=SIGURG, si_code=SI_TKILL, si_pid=5462, si_uid=0} ---
--- SIGURG {si_signo=SIGURG, si_code=SI_TKILL, si_pid=5462, si_uid=0} ---
write(1, "Hello World\n", 12)           = 12
+++ exited with 0 +++

C# AOT

$ strace -e write ./bin/hello_csharp_aot > /dev/null
write(0, "\33[?1h\33=", 7)              = 7
write(3, "Hello, World\n", 13)          = 13
+++ exited with 0 +++

C# JIT

$ strace -e write ./bin/hello_csharp > /dev/null
write(13, "*", 1)                       = 1
write(14, ".NET Finalizer", 14)         = 14
write(13, "*", 1)                       = 1
write(16, ".NET Tiered Com", 15)        = 15
write(15, "*", 1)                       = 1
write(0, "\33[?1h\33=", 7)              = 7
write(24, "Hello, World\n", 13)         = 13
write(4, "\1", 1)                       = 1
+++ exited with 0 +++

C、Rust、Goは標準出力への1回のwriteだけですが、C# AOTでは端末制御シーケンスを書き込んでから標準出力へ書き込んでいます。JITではさらにソケット作成のため書き込みしています。C# AOTとJITを詳しく見てみましょう。

C# AOTのwriteシステムコール

straceのオプションを追加して、タイムスタンプ、File descriptor(FD)のパス、バッファ内容を表示します。

$ strace -f -ttt -e trace=write,writev -s 200 -yy -xx ./bin/hello_csharp_aot
strace: Process 13 attached
strace: Process 14 attached
[pid    12] 1770645277.828800 write(1<\x2f\x64\x65\x76\x2f\x70\x74\x73\x2f\x30<char 136:0>>, "\x1b\x5b\x3f\x31\x68\x1b\x3d", 7) = 7
[pid    12] 1770645277.830239 write(3<\x2f\x64\x65\x76\x2f\x70\x74\x73\x2f\x30<char 136:0>>, "\x48\x65\x6c\x6c\x6f\x2c\x20\x57\x6f\x72\x6c\x64\x0a", 13Hello, World
) = 13
[pid    14] 1770645277.830626 +++ exited with 0 +++
[pid    13] 1770645277.830656 +++ exited with 0 +++
1770645277.831918 +++ exited with 0 +++

$ strace -f -ttt -e trace=write,writev -s 200 -yy ./bin/hello_csharp_aot
strace: Process 31 attached
strace: Process 32 attached
[pid    30] 1770646142.571391 write(1</dev/pts/0<char 136:0>>, "\33[?1h\33=", 7) = 7
[pid    30] 1770646142.572052 write(3</dev/pts/0<char 136:0>>, "Hello, World\n", 13Hello, World
) = 13
[pid    32] 1770646142.573542 +++ exited with 0 +++
[pid    31] 1770646142.573563 +++ exited with 0 +++
1770646142.574448 +++ exited with 0 +++

1回目のwriteで端末のモード切り替え(ANSIエスケープ)を流し、それからFD 3へ"Hello, World\n"を書き込んでいます。FD 3はstraceの-yyオプションでパスを表示させたところ、/dev/pts/0となっており、標準出力が端末に接続されている場合に割り当てられる擬似端末デバイスです。つまり、C# AOTでは標準出力に直接書き込むのではなく、擬似端末デバイスに書き込んでから端末に出力していることになります。

1回目のwrite

端末のモード切り替えは以下の処理で、DECCKM: cursor keys modeDECKPAM(Keypad Application Modeを設定しています。

  • \x1b = ESC
  • \x1b\x5b\x3f\x31\x68 = ESC [ ? 1 h = DEC Private Mode Set 1 (DECCKM: cursor keys mode)
  • \x1b\x3d = ESC = DECKPAM(Keypad Application Mode)
write(1<\x2f\x64\x65\x76\x2f\x70\x74\x73\x2f\x30<char 136:0>>, "\x1b\x5b\x3f\x31\x68\x1b\x3d", 7) = 7

あるいは、エスケープシーケンスを可読化すると以下のようになります。

write(1</dev/pts/0<char 136:0>>, "\33[?1h\33=", 7) = 7

dotnet/runtimeのどこで処理されているかというと、src/libraries/System.Console/src/System/ConsolePal.Unix.csのEnsureConsoleInitialized関数にて、Interop.Sys.SetKeypadXmit(s_terminalHandle, keypadXmit);で端末のモード切替をしています。

private static unsafe void EnsureInitializedCore()
{
    lock (Console.Out) // ensure that writing the ANSI string and setting initialized to true are done atomically
    {
        if (!s_initialized)
        {
            // Do this even when redirected to make CancelKeyPress works.
            if (!Interop.Sys.InitializeTerminalAndSignalHandling())
            {
                throw new Win32Exception();
            }
            // InitializeTerminalAndSignalHandling will reset the terminal on a normal exit.
            // This also resets it for termination due to an unhandled exception.
            AppDomain.CurrentDomain.UnhandledException += (_, _) => { Interop.Sys.UninitializeTerminal(); };

            s_terminalHandle = !Console.IsOutputRedirected ? OpenStandardOutputHandle() :
                                !Console.IsInputRedirected  ? OpenStandardInputHandle() :
                                null;

            // Provide the native lib with the correct code from the terminfo to transition us into
            // "application mode".  This will both transition it immediately, as well as allow
            // the native lib later to handle signals that require re-entering the mode.
            if (s_terminalHandle != null &&
                TerminalFormatStringsInstance.KeypadXmit is string keypadXmit)
            {
                Interop.Sys.SetKeypadXmit(s_terminalHandle, keypadXmit);
            }

2回目のwriteはなぜFD3なのか

Hello, World\nを出力していますが、FD 3へ書き込んでいます。

write(3<\x2f\x64\x65\x76\x2f\x70\x74\x73\x2f\x30<char 136:0>>, "\x48\x65\x6c\x6c\x6f\x2c\x20\x57\x6f\x72\x6c\x64\x0a", 13Hello, World

エスケープシーケンスを可読化すると以下のようになります。

write(3</dev/pts/0<char 136:0>>, "Hello, World\n", 13Hello, World

CやRust、Goは標準出力FD 1へ直接書き込んでいるのに対して、C# AOTは擬似端末デバイスFD 3へ書き込んでいる点は不思議ですね。

# C
$ strace -f -ttt -e trace=write,writev -s 200 -yy ./bin/hello_c
write(1</dev/pts/0<char 136:0>>, "Hello World\n", 12Hello World

# Rust
$ strace -f -ttt -e trace=write,writev -s 200 -yy ./bin/hello_rust
write(1</dev/pts/0<char 136:0>>, "Hello World\n", 12Hello World

# Go
$ strace -f -ttt -e trace=write,writev -s 200 -yy ./bin/hello_go
write(1</dev/pts/0<char 136:0>>, "Hello World\n", 12Hello World

書き込みを追ってみましょう。

C# AOTのwriteシステムコール追跡 (クリックで展開)

$ strace -f -ttt -e trace=dup,dup2,dup3,fcntl,openat,close,write -s 200 -yy ./bin/hello_csharp_aot
1770646837.538617 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3</etc/ld.so.cache>
1770646837.538979 close(3</etc/ld.so.cache>) = 0
1770646837.539104 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libm.so.6", O_RDONLY|O_CLOEXEC) = 3</usr/lib/x86_64-linux-gnu/libm.so.6>
1770646837.539803 close(3</usr/lib/x86_64-linux-gnu/libm.so.6>) = 0
1770646837.539917 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3</usr/lib/x86_64-linux-gnu/libc.so.6>
1770646837.540707 close(3</usr/lib/x86_64-linux-gnu/libc.so.6>) = 0
1770646837.543771 openat(AT_FDCWD</workspace>, "/sys/devices/system/cpu/online", O_RDONLY|O_CLOEXEC) = 3</sys/devices/system/cpu/online>
1770646837.544000 close(3</sys/devices/system/cpu/online>) = 0
1770646837.544644 openat(AT_FDCWD</workspace>, "/proc/self/mountinfo", O_RDONLY) = 3</proc/137/mountinfo>
1770646837.545334 close(3</proc/137/mountinfo>) = 0
1770646837.545512 openat(AT_FDCWD</workspace>, "/proc/self/cgroup", O_RDONLY) = 3</proc/137/cgroup>
1770646837.545820 close(3</proc/137/cgroup>) = 0
1770646837.546360 openat(AT_FDCWD</workspace>, "/proc/self/mountinfo", O_RDONLY) = 3</proc/137/mountinfo>
1770646837.546940 close(3</proc/137/mountinfo>) = 0
1770646837.547053 openat(AT_FDCWD</workspace>, "/proc/self/cgroup", O_RDONLY) = 3</proc/137/cgroup>
1770646837.547324 close(3</proc/137/cgroup>) = 0
1770646837.547582 openat(AT_FDCWD</workspace>, "/sys/fs/cgroup//cpu.max", O_RDONLY) = 3</sys/fs/cgroup/cpu.max>
1770646837.547895 close(3</sys/fs/cgroup/cpu.max>) = 0
strace: Process 138 attached
[pid   137] 1770646837.549562 openat(AT_FDCWD</workspace>, "/sys/fs/cgroup//memory.max", O_RDONLY) = 3</sys/fs/cgroup/memory.max>
[pid   137] 1770646837.549880 close(3</sys/fs/cgroup/memory.max>) = 0
[pid   137] 1770646837.550374 openat(AT_FDCWD</workspace>, "/sys/devices/system/cpu/cpu0/cache/index0/size", O_RDONLY) = 3</sys/devices/system/cpu/cpu0/cache/index0/size>
[pid   137] 1770646837.550791 close(3</sys/devices/system/cpu/cpu0/cache/index0/size>) = 0
[pid   137] 1770646837.550911 openat(AT_FDCWD</workspace>, "/sys/devices/system/cpu/cpu0/cache/index0/level", O_RDONLY) = 3</sys/devices/system/cpu/cpu0/cache/index0/level>
[pid   137] 1770646837.551252 close(3</sys/devices/system/cpu/cpu0/cache/index0/level>) = 0
[pid   137] 1770646837.551367 openat(AT_FDCWD</workspace>, "/sys/devices/system/cpu/cpu0/cache/index1/size", O_RDONLY) = 3</sys/devices/system/cpu/cpu0/cache/index1/size>
[pid   137] 1770646837.551765 close(3</sys/devices/system/cpu/cpu0/cache/index1/size>) = 0
[pid   137] 1770646837.551889 openat(AT_FDCWD</workspace>, "/sys/devices/system/cpu/cpu0/cache/index1/level", O_RDONLY) = 3</sys/devices/system/cpu/cpu0/cache/index1/level>
[pid   137] 1770646837.552238 close(3</sys/devices/system/cpu/cpu0/cache/index1/level>) = 0
[pid   137] 1770646837.552360 openat(AT_FDCWD</workspace>, "/sys/devices/system/cpu/cpu0/cache/index2/size", O_RDONLY) = 3</sys/devices/system/cpu/cpu0/cache/index2/size>
[pid   137] 1770646837.552654 close(3</sys/devices/system/cpu/cpu0/cache/index2/size>) = 0
[pid   137] 1770646837.552790 openat(AT_FDCWD</workspace>, "/sys/devices/system/cpu/cpu0/cache/index2/level", O_RDONLY) = 3</sys/devices/system/cpu/cpu0/cache/index2/level>
[pid   137] 1770646837.553103 close(3</sys/devices/system/cpu/cpu0/cache/index2/level>) = 0
[pid   137] 1770646837.553222 openat(AT_FDCWD</workspace>, "/sys/devices/system/cpu/cpu0/cache/index3/size", O_RDONLY) = 3</sys/devices/system/cpu/cpu0/cache/index3/size>
[pid   137] 1770646837.553513 close(3</sys/devices/system/cpu/cpu0/cache/index3/size>) = 0
[pid   137] 1770646837.553629 openat(AT_FDCWD</workspace>, "/sys/devices/system/cpu/cpu0/cache/index3/level", O_RDONLY) = 3</sys/devices/system/cpu/cpu0/cache/index3/level>
[pid   137] 1770646837.553912 close(3</sys/devices/system/cpu/cpu0/cache/index3/level>) = 0
[pid   137] 1770646837.554043 openat(AT_FDCWD</workspace>, "/sys/devices/system/cpu/cpu0/cache/index4/size", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.555098 openat(AT_FDCWD</workspace>, "/proc/meminfo", O_RDONLY) = 3</proc/meminfo>
[pid   137] 1770646837.555372 close(3</proc/meminfo>) = 0
[pid   137] 1770646837.557397 openat(AT_FDCWD</workspace>, "/proc/self/maps", O_RDONLY|O_CLOEXEC) = 3</proc/137/maps>
[pid   137] 1770646837.558138 close(3</proc/137/maps>) = 0
[pid   137] 1770646837.561204 fcntl(1</dev/pts/0<char 136:0>>, F_DUPFD_CLOEXEC, 0) = 3</dev/pts/0<char 136:0>>
strace: Process 139 attached
[pid   137] 1770646837.562720 openat(AT_FDCWD</workspace>, "/root/.terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.562981 openat(AT_FDCWD</workspace>, "/root/.terminfo/78/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.563093 openat(AT_FDCWD</workspace>, "/etc/terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.563212 openat(AT_FDCWD</workspace>, "/etc/terminfo/78/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.563341 openat(AT_FDCWD</workspace>, "/lib/terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.563475 openat(AT_FDCWD</workspace>, "/lib/terminfo/78/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.563648 openat(AT_FDCWD</workspace>, "/usr/share/terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = 6</usr/share/terminfo/x/xterm>
[pid   137] 1770646837.564125 close(6</usr/share/terminfo/x/xterm>) = 0
[pid   137] 1770646837.564249 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6</etc/ld.so.cache>
[pid   137] 1770646837.564534 close(6</etc/ld.so.cache>) = 0
[pid   137] 1770646837.564700 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v4/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.564886 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.565197 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.565444 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.565722 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v4/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.565980 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.566227 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.566497 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.566767 openat(AT_FDCWD</workspace>, "/lib/glibc-hwcaps/x86-64-v4/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.567001 openat(AT_FDCWD</workspace>, "/lib/glibc-hwcaps/x86-64-v3/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.567277 openat(AT_FDCWD</workspace>, "/lib/glibc-hwcaps/x86-64-v2/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.567554 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.567779 openat(AT_FDCWD</workspace>, "/usr/lib/glibc-hwcaps/x86-64-v4/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.567974 openat(AT_FDCWD</workspace>, "/usr/lib/glibc-hwcaps/x86-64-v3/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.568192 openat(AT_FDCWD</workspace>, "/usr/lib/glibc-hwcaps/x86-64-v2/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.568404 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.568702 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6</etc/ld.so.cache>
[pid   137] 1770646837.569027 close(6</etc/ld.so.cache>) = 0
[pid   137] 1770646837.569146 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.89", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.569274 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.89", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.569402 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.89", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.569532 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.89", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.569740 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6</etc/ld.so.cache>
[pid   137] 1770646837.570007 close(6</etc/ld.so.cache>) = 0
[pid   137] 1770646837.570137 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.88", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.570305 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.88", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.570443 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.88", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.570583 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.88", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.570792 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6</etc/ld.so.cache>
[pid   137] 1770646837.571078 close(6</etc/ld.so.cache>) = 0
[pid   137] 1770646837.571184 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.87", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.571303 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.87", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.571408 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.87", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.571549 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.87", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.571828 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6</etc/ld.so.cache>
[pid   137] 1770646837.572099 close(6</etc/ld.so.cache>) = 0
[pid   137] 1770646837.572216 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.86", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.572358 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.86", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.572511 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.86", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.572662 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.86", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.572861 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6</etc/ld.so.cache>
[pid   137] 1770646837.573188 close(6</etc/ld.so.cache>) = 0
[pid   137] 1770646837.573420 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.85", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.573612 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.85", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.573790 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.85", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.574000 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.85", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.574299 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6</etc/ld.so.cache>
[pid   137] 1770646837.574644 close(6</etc/ld.so.cache>) = 0
[pid   137] 1770646837.574781 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.84", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.574940 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.84", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.575085 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.84", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.575207 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.84", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.575539 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6</etc/ld.so.cache>
[pid   137] 1770646837.575823 close(6</etc/ld.so.cache>) = 0
[pid   137] 1770646837.575963 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.83", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.576089 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.83", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.576212 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.83", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.576351 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.83", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.576564 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6</etc/ld.so.cache>
[pid   137] 1770646837.576850 close(6</etc/ld.so.cache>) = 0
[pid   137] 1770646837.576976 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.82", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.577100 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.82", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.577265 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.82", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.577408 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.82", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.577682 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6</etc/ld.so.cache>
[pid   137] 1770646837.578019 close(6</etc/ld.so.cache>) = 0
[pid   137] 1770646837.578130 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.81", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.578248 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.81", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.578374 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.81", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.578507 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.81", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.578751 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6</etc/ld.so.cache>
[pid   137] 1770646837.579075 close(6</etc/ld.so.cache>) = 0
[pid   137] 1770646837.579186 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.80", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.579302 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.80", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.579457 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.80", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.579541 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.80", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.579801 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6</etc/ld.so.cache>
[pid   137] 1770646837.580128 close(6</etc/ld.so.cache>) = 0
[pid   137] 1770646837.580244 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.79", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.580403 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.79", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.580520 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.79", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.580683 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.79", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.580877 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6</etc/ld.so.cache>
[pid   137] 1770646837.581203 close(6</etc/ld.so.cache>) = 0
[pid   137] 1770646837.581383 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.78", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.581544 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.78", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.581703 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.78", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.581872 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.78", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.582150 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6</etc/ld.so.cache>
[pid   137] 1770646837.582529 close(6</etc/ld.so.cache>) = 0
[pid   137] 1770646837.582696 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.77", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.582857 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.77", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.583033 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.77", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.583186 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.77", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.583474 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6</etc/ld.so.cache>
[pid   137] 1770646837.583801 close(6</etc/ld.so.cache>) = 0
[pid   137] 1770646837.583913 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.76", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.584040 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.76", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.584172 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.76", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.584351 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.76", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.584607 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6</etc/ld.so.cache>
[pid   137] 1770646837.584878 close(6</etc/ld.so.cache>) = 0
[pid   137] 1770646837.584988 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.75", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.585114 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.75", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.585244 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.75", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.585410 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.75", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   137] 1770646837.585664 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6</etc/ld.so.cache>
[pid   137] 1770646837.585977 close(6</etc/ld.so.cache>) = 0
[pid   137] 1770646837.586087 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.74", O_RDONLY|O_CLOEXEC) = 6</usr/lib/x86_64-linux-gnu/libicuuc.so.74.2>
[pid   137] 1770646837.586809 close(6</usr/lib/x86_64-linux-gnu/libicuuc.so.74.2>) = 0
[pid   137] 1770646837.586925 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicudata.so.74", O_RDONLY|O_CLOEXEC) = 6</usr/lib/x86_64-linux-gnu/libicudata.so.74.2>
[pid   137] 1770646837.587485 close(6</usr/lib/x86_64-linux-gnu/libicudata.so.74.2>) = 0
[pid   137] 1770646837.587587 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = 6</usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.33>
[pid   137] 1770646837.588280 close(6</usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.33>) = 0
[pid   137] 1770646837.588404 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 6</usr/lib/x86_64-linux-gnu/libgcc_s.so.1>
[pid   137] 1770646837.588959 close(6</usr/lib/x86_64-linux-gnu/libgcc_s.so.1>) = 0
[pid   137] 1770646837.590298 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 6</etc/ld.so.cache>
[pid   137] 1770646837.590678 close(6</etc/ld.so.cache>) = 0
[pid   137] 1770646837.590820 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicui18n.so.74", O_RDONLY|O_CLOEXEC) = 6</usr/lib/x86_64-linux-gnu/libicui18n.so.74.2>
[pid   137] 1770646837.591551 close(6</usr/lib/x86_64-linux-gnu/libicui18n.so.74.2>) = 0
[pid   137] 1770646837.592432 write(1</dev/pts/0<char 136:0>>, "\33[?1h\33=", 7) = 7
[pid   137] 1770646837.592944 write(3</dev/pts/0<char 136:0>>, "Hello, World\n", 13Hello, World
) = 13
[pid   139] 1770646837.593311 +++ exited with 0 +++
[pid   138] 1770646837.593343 +++ exited with 0 +++
1770646837.594304 +++ exited with 0 +++

以下のfd=3はstdout(1)の複製(CLOEXEC付き)を示しており、dotnetランタイムは起動時にstdoutFD=1F_DUPFD_CLOEXECFD=3dup(close-on-exec 付き)していることが分かります。

fcntl(1</dev/pts/0<char 136:0>>, F_DUPFD_CLOEXEC, 0) = 3</dev/pts/0<char 136:0>>

dotnet/runtimeを確認すると、src/coreclr/pal/src/file/file.cppのinit_std_handle関数にて、以下のようにF_DUPFD_CLOEXECでdupしていることが分かります。コメントに元のFILE*(= stdoutなど)をfcloseしても、元のfd(1) を閉じないためにdupして別fdを持つと書かれているので、まさにstrace結果と一致します。

static HANDLE init_std_handle(HANDLE * pStd, FILE *stream)
{
    CPalThread *pThread = InternalGetCurrentThread();
    PAL_ERROR palError = NO_ERROR;
    IPalObject *pFileObject = NULL;
    IPalObject *pRegisteredFile = NULL;
    IDataLock *pDataLock = NULL;
    CFileProcessLocalData *pLocalData = NULL;
    CObjectAttributes oa;

    HANDLE hFile = INVALID_HANDLE_VALUE;
    int new_fd = -1;

    /* duplicate the FILE *, so that we can fclose() in FILECloseHandle without
       closing the original */
    new_fd = fcntl(fileno(stream), F_DUPFD_CLOEXEC, 0); // dup, but with CLOEXEC
    if(-1 == new_fd)
    {
        ERROR("dup() failed; errno is %d (%s)\n", errno, strerror(errno));
        goto done;
    }

System.Nativeでも意図的にF_DUPFD_CLOEXECでdupしており、dotnetランタイム全体でこの方法を採用していることが分かります。

intptr_t SystemNative_Dup(intptr_t oldfd)
{
    int result;
#if HAVE_F_DUPFD_CLOEXEC
    while ((result = fcntl(ToFileDescriptor(oldfd), F_DUPFD_CLOEXEC, 0)) < 0 && errno == EINTR);
#elif HAVE_F_DUPFD
    while ((result = fcntl(ToFileDescriptor(oldfd), F_DUPFD, 0)) < 0 && errno == EINTR);
    // do CLOEXEC here too
    fcntl(result, F_SETFD, FD_CLOEXEC);
#else
    // The main use cases for dup are setting up the classic Unix dance of setting up file descriptors in advance of performing a fork. Since WASI has no fork, these don't apply.
    // https://github.com/bytecodealliance/wasmtime/blob/b2fefe77148582a9b8013e34fe5808ada82b6efc/docs/WASI-rationale.md#why-no-dup
    result = oldfd;
#endif
    return result;
}

int32_t SystemNative_Unlink(const char* path)
{
    int32_t result;
    while ((result = unlink(path)) < 0 && errno == EINTR);
    return result;
}

#ifdef __NR_memfd_create
#ifndef MFD_CLOEXEC
#define MFD_CLOEXEC 0x0001U
#endif
#ifndef MFD_ALLOW_SEALING
#define MFD_ALLOW_SEALING 0x0002U
#endif
#ifndef F_ADD_SEALS
#define F_ADD_SEALS (1024 + 9)
#endif
#ifndef F_SEAL_WRITE
#define F_SEAL_WRITE 0x0008
#endif
#endif

C# JITのwriteシステムコール

C# JITコンパイラが動作しているときのwriteシステムコールを見てみます。以下は、dotnet runでJITコンパイルを行いながらHello Worldを出力したときのstrace結果です。制御コードやHello Worldの出力回りはAOTと同様なのでおいておきましょう。

$ strace -e write ./bin/hello_csharp > /dev/null
write(13, "*", 1)                       = 1
write(14, ".NET Finalizer", 14)         = 14
write(13, "*", 1)                       = 1
write(16, ".NET Tiered Com", 15)        = 15
write(15, "*", 1)                       = 1
write(0, "\33[?1h\33=", 7)              = 7
write(24, "Hello, World\n", 13)         = 13
write(4, "\1", 1)                       = 1
+++ exited with 0 +++

気になるのが、.NET Finalizer.NET Tiered Comなどの文字列がwriteシステムコールです。これは.NETがスレッドを作って名前を付けているのがwrite()として見えています。Linuxのスレッド名は15文字まで(終端NULを含めて16バイト制限)なので、次のような名前になります。

  • .NET Finalizer: 14字なのでそのまま
  • .NET Tiered Com: .NET Tiered Compilationですが、先頭15文字だけなので切り詰められる

.NET FinalizerはGCのファイナライザースレッドであり、ランタイムとしていつでもファイナライズできる状態を作るために起動します。.NET Tiered CompilationはJITコンパイラのTiered PGO最適化を担当するスレッドです。なお、NativeAOTではJITがなく、またTiered PGO最適化は行われないため、これらスレッドは起動せずwriteシステムコールも発生しません。

この辺りはstraceでログを見ると、もう少し詳しくわかります。

C# JITのwriteシステムコールのstrace結果(クリックして展開)

$ strace -f -ttt -e trace=openat,close,fcntl,write -yy -s 200 ./bin/hello_csharp
1770651503.638424 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3</etc/ld.so.cache>
1770651503.638872 close(3</etc/ld.so.cache>) = 0
1770651503.639013 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3</usr/lib/x86_64-linux-gnu/libdl.so.2>
1770651503.639668 close(3</usr/lib/x86_64-linux-gnu/libdl.so.2>) = 0
1770651503.639779 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/librt.so.1", O_RDONLY|O_CLOEXEC) = 3</usr/lib/x86_64-linux-gnu/librt.so.1>
1770651503.640466 close(3</usr/lib/x86_64-linux-gnu/librt.so.1>) = 0
1770651503.640575 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3</usr/lib/x86_64-linux-gnu/libgcc_s.so.1>
1770651503.641275 close(3</usr/lib/x86_64-linux-gnu/libgcc_s.so.1>) = 0
1770651503.641383 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3</usr/lib/x86_64-linux-gnu/libpthread.so.0>
1770651503.642019 close(3</usr/lib/x86_64-linux-gnu/libpthread.so.0>) = 0
1770651503.642173 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libm.so.6", O_RDONLY|O_CLOEXEC) = 3</usr/lib/x86_64-linux-gnu/libm.so.6>
1770651503.642672 close(3</usr/lib/x86_64-linux-gnu/libm.so.6>) = 0
1770651503.642775 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = 3</usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.33>
1770651503.643511 close(3</usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.33>) = 0
1770651503.643629 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3</usr/lib/x86_64-linux-gnu/libc.so.6>
1770651503.644728 close(3</usr/lib/x86_64-linux-gnu/libc.so.6>) = 0
1770651503.659843 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3</etc/ld.so.cache>
1770651503.660212 close(3</etc/ld.so.cache>) = 0
1770651503.660343 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v4/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
1770651503.660624 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
1770651503.660899 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
1770651503.661116 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
1770651503.661325 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v4/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
1770651503.661507 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v3/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
1770651503.661742 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/glibc-hwcaps/x86-64-v2/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
1770651503.661973 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
1770651503.662165 openat(AT_FDCWD</workspace>, "/lib/glibc-hwcaps/x86-64-v4/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
1770651503.662366 openat(AT_FDCWD</workspace>, "/lib/glibc-hwcaps/x86-64-v3/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
1770651503.662548 openat(AT_FDCWD</workspace>, "/lib/glibc-hwcaps/x86-64-v2/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
1770651503.662759 openat(AT_FDCWD</workspace>, "/lib/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
1770651503.662937 openat(AT_FDCWD</workspace>, "/usr/lib/glibc-hwcaps/x86-64-v4/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
1770651503.663160 openat(AT_FDCWD</workspace>, "/usr/lib/glibc-hwcaps/x86-64-v3/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
1770651503.663372 openat(AT_FDCWD</workspace>, "/usr/lib/glibc-hwcaps/x86-64-v2/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
1770651503.663581 openat(AT_FDCWD</workspace>, "/usr/lib/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
1770651503.663842 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3</etc/ld.so.cache>
1770651503.664154 close(3</etc/ld.so.cache>) = 0
1770651503.664265 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
1770651503.664416 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
1770651503.664611 openat(AT_FDCWD</workspace>, "/lib/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
1770651503.664714 openat(AT_FDCWD</workspace>, "/usr/lib/liblttng-ust-tracepoint.so.0", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
1770651503.666744 openat(AT_FDCWD</workspace>, "/workspace/bin/hello_csharp", O_RDONLY) = 3</workspace/bin/hello_csharp>
1770651503.667483 close(3</workspace/bin/hello_csharp>) = 0
1770651503.668334 openat(AT_FDCWD</workspace>, "/workspace/bin/hello_csharp", O_RDONLY) = 3</workspace/bin/hello_csharp>
1770651503.668997 close(3</workspace/bin/hello_csharp>) = 0
1770651503.669736 openat(AT_FDCWD</workspace>, "/workspace/bin/hello_csharp", O_RDONLY) = 3</workspace/bin/hello_csharp>
1770651503.670377 close(3</workspace/bin/hello_csharp>) = 0
1770651503.671028 openat(AT_FDCWD</workspace>, "/workspace/bin/hello_csharp", O_RDONLY) = 3</workspace/bin/hello_csharp>
1770651503.671721 close(3</workspace/bin/hello_csharp>) = 0
1770651503.673748 openat(AT_FDCWD</workspace>, "/proc/self/mountinfo", O_RDONLY) = 3</proc/143/mountinfo>
1770651503.674430 close(3</proc/143/mountinfo>) = 0
1770651503.674546 openat(AT_FDCWD</workspace>, "/proc/self/cgroup", O_RDONLY) = 3</proc/143/cgroup>
1770651503.674831 close(3</proc/143/cgroup>) = 0
strace: Process 144 attached
[pid   143] 1770651503.677794 fcntl(0</dev/pts/0<char 136:0>>, F_DUPFD_CLOEXEC, 0) = 5</dev/pts/0<char 136:0>>
[pid   143] 1770651503.677926 fcntl(1</dev/pts/0<char 136:0>>, F_DUPFD_CLOEXEC, 0) = 6</dev/pts/0<char 136:0>>
[pid   143] 1770651503.678068 fcntl(2</dev/pts/0<char 136:0>>, F_DUPFD_CLOEXEC, 0) = 7</dev/pts/0<char 136:0>>
[pid   143] 1770651503.679079 openat(AT_FDCWD</workspace>, "/sys/fs/cgroup//cpu.max", O_RDONLY) = 8</sys/fs/cgroup/cpu.max>
[pid   143] 1770651503.679363 close(8</sys/fs/cgroup/cpu.max>) = 0
[pid   143] 1770651503.683922 openat(AT_FDCWD</workspace>, "/dev/urandom", O_RDONLY|O_CLOEXEC) = 9</dev/urandom<char 1:9>>
[pid   143] 1770651503.684119 openat(AT_FDCWD</workspace>, "/proc/143/stat", O_RDONLY) = 10</proc/143/stat>
[pid   143] 1770651503.684495 close(10</proc/143/stat>) = 0
strace: Process 145 attached
[pid   143] 1770651503.687465 openat(AT_FDCWD</workspace>, "/sys/devices/system/cpu/online", O_RDONLY|O_CLOEXEC) = 11</sys/devices/system/cpu/online>
[pid   143] 1770651503.687648 close(11</sys/devices/system/cpu/online>) = 0
[pid   143] 1770651503.688005 openat(AT_FDCWD</workspace>, "/proc/self/mountinfo", O_RDONLY) = 11</proc/143/mountinfo>
[pid   143] 1770651503.688585 close(11</proc/143/mountinfo>) = 0
[pid   143] 1770651503.688690 openat(AT_FDCWD</workspace>, "/proc/self/cgroup", O_RDONLY) = 11</proc/143/cgroup>
[pid   143] 1770651503.688925 close(11</proc/143/cgroup>) = 0
[pid   143] 1770651503.691797 openat(AT_FDCWD</workspace>, "/proc/143/stat", O_RDONLY) = 11</proc/143/stat>
[pid   143] 1770651503.692066 close(11</proc/143/stat>) = 0
[pid   143] 1770651503.692179 openat(AT_FDCWD</workspace>, "/proc/143/stat", O_RDONLY) = 11</proc/143/stat>
[pid   143] 1770651503.692478 close(11</proc/143/stat>) = 0
strace: Process 146 attached
[pid   146] 1770651503.694266 openat(AT_FDCWD</workspace>, "/tmp/clr-debug-pipe-143-4092879-in", O_RDONLYstrace: Process 147 attached
 <unfinished ...>
[pid   143] 1770651503.695169 write(13<pipe:[654821]>, "*", 1) = 1
[pid   143] 1770651503.695294 openat(AT_FDCWD</workspace>, "/proc/143/stat", O_RDONLY <unfinished ...>
[pid   147] 1770651503.695332 close(12<pipe:[654821]> <unfinished ...>
[pid   143] 1770651503.695361 <... openat resumed>) = 14</proc/143/stat>
[pid   147] 1770651503.695388 <... close resumed>) = 0
[pid   147] 1770651503.695429 close(13<pipe:[654821]>) = 0
[pid   143] 1770651503.695560 close(14</proc/143/stat>) = 0
[pid   143] 1770651503.695670 openat(AT_FDCWD</workspace>, "/dev/shm/sem.clrst0000008f00000000003e73cf", O_RDWR|O_NOFOLLOW|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.696489 openat(AT_FDCWD</workspace>, "/sys/fs/cgroup//memory.max", O_RDONLY) = 12</sys/fs/cgroup/memory.max>
[pid   143] 1770651503.696794 close(12</sys/fs/cgroup/memory.max>) = 0
[pid   143] 1770651503.697425 openat(AT_FDCWD</workspace>, "/sys/devices/system/cpu/cpu0/cache/index0/size", O_RDONLY) = 12</sys/devices/system/cpu/cpu0/cache/index0/size>
[pid   143] 1770651503.697800 close(12</sys/devices/system/cpu/cpu0/cache/index0/size>) = 0
[pid   143] 1770651503.697912 openat(AT_FDCWD</workspace>, "/sys/devices/system/cpu/cpu0/cache/index0/level", O_RDONLY) = 12</sys/devices/system/cpu/cpu0/cache/index0/level>
[pid   143] 1770651503.698353 close(12</sys/devices/system/cpu/cpu0/cache/index0/level>) = 0
[pid   143] 1770651503.698491 openat(AT_FDCWD</workspace>, "/sys/devices/system/cpu/cpu0/cache/index1/size", O_RDONLY) = 12</sys/devices/system/cpu/cpu0/cache/index1/size>
[pid   143] 1770651503.698789 close(12</sys/devices/system/cpu/cpu0/cache/index1/size>) = 0
[pid   143] 1770651503.698909 openat(AT_FDCWD</workspace>, "/sys/devices/system/cpu/cpu0/cache/index1/level", O_RDONLY) = 12</sys/devices/system/cpu/cpu0/cache/index1/level>
[pid   143] 1770651503.699260 close(12</sys/devices/system/cpu/cpu0/cache/index1/level>) = 0
[pid   143] 1770651503.699371 openat(AT_FDCWD</workspace>, "/sys/devices/system/cpu/cpu0/cache/index2/size", O_RDONLY) = 12</sys/devices/system/cpu/cpu0/cache/index2/size>
[pid   143] 1770651503.699689 close(12</sys/devices/system/cpu/cpu0/cache/index2/size>) = 0
[pid   143] 1770651503.699824 openat(AT_FDCWD</workspace>, "/sys/devices/system/cpu/cpu0/cache/index2/level", O_RDONLY) = 12</sys/devices/system/cpu/cpu0/cache/index2/level>
[pid   143] 1770651503.700127 close(12</sys/devices/system/cpu/cpu0/cache/index2/level>) = 0
[pid   143] 1770651503.700243 openat(AT_FDCWD</workspace>, "/sys/devices/system/cpu/cpu0/cache/index3/size", O_RDONLY) = 12</sys/devices/system/cpu/cpu0/cache/index3/size>
[pid   143] 1770651503.700559 close(12</sys/devices/system/cpu/cpu0/cache/index3/size>) = 0
[pid   143] 1770651503.700679 openat(AT_FDCWD</workspace>, "/sys/devices/system/cpu/cpu0/cache/index3/level", O_RDONLY) = 12</sys/devices/system/cpu/cpu0/cache/index3/level>
[pid   143] 1770651503.700997 close(12</sys/devices/system/cpu/cpu0/cache/index3/level>) = 0
[pid   143] 1770651503.701105 openat(AT_FDCWD</workspace>, "/sys/devices/system/cpu/cpu0/cache/index4/size", O_RDONLY) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.702578 openat(AT_FDCWD</workspace>, "/proc/meminfo", O_RDONLY) = 12</proc/meminfo>
[pid   143] 1770651503.702830 close(12</proc/meminfo>) = 0
[pid   143] 1770651503.703978 openat(AT_FDCWD</workspace>, "/proc/self/maps", O_RDONLY|O_CLOEXEC) = 12</proc/143/maps>
[pid   143] 1770651503.704811 close(12</proc/143/maps>) = 0
[pid   143] 1770651503.704991 openat(AT_FDCWD</workspace>, "/proc/self/maps", O_RDONLY|O_CLOEXEC) = 12</proc/143/maps>
[pid   143] 1770651503.706019 close(12</proc/143/maps>) = 0
strace: Process 148 attached
[pid   143] 1770651503.707664 openat(AT_FDCWD</workspace>, "/proc/self/task/148/comm", O_RDWR) = 14</proc/143/task/148/comm>
[pid   143] 1770651503.707795 write(14</proc/143/task/148/comm>, ".NET Finalizer", 14) = 14
[pid   143] 1770651503.707905 close(14</proc/143/task/148/comm>) = 0
[pid   143] 1770651503.708034 write(13<pipe:[656760]>, "*", 1) = 1
[pid   148] 1770651503.708204 close(12<pipe:[656760]>) = 0
[pid   148] 1770651503.708355 close(13<pipe:[656760]>) = 0
[pid   143] 1770651503.708851 openat(AT_FDCWD</workspace>, "/workspace/bin/hello_csharp", O_RDONLY) = 12</workspace/bin/hello_csharp>
[pid   143] 1770651503.709311 fcntl(12</workspace/bin/hello_csharp>, F_SETFD, FD_CLOEXEC) = 0
[pid   143] 1770651503.709529 fcntl(12</workspace/bin/hello_csharp>, F_DUPFD_CLOEXEC, 0) = 13</workspace/bin/hello_csharp>
strace: Process 149 attached
[pid   143] 1770651503.739900 openat(AT_FDCWD</workspace>, "/proc/self/task/149/comm", O_RDWR) = 16</proc/143/task/149/comm>
[pid   143] 1770651503.740087 write(16</proc/143/task/149/comm>, ".NET Tiered Com", 15) = 15
[pid   143] 1770651503.740251 close(16</proc/143/task/149/comm>) = 0
[pid   143] 1770651503.740380 write(15<pipe:[654827]>, "*", 1) = 1
[pid   149] 1770651503.740714 close(14<pipe:[654827]>) = 0
[pid   149] 1770651503.740860 close(15<pipe:[654827]>) = 0
[pid   143] 1770651503.759910 openat(AT_FDCWD</workspace>, "/workspace/bin/hello_csharp", O_RDONLY) = 14</workspace/bin/hello_csharp>
[pid   143] 1770651503.760370 fcntl(14</workspace/bin/hello_csharp>, F_SETFD, FD_CLOEXEC) = 0
[pid   143] 1770651503.760596 fcntl(14</workspace/bin/hello_csharp>, F_DUPFD_CLOEXEC, 0) = 15</workspace/bin/hello_csharp>
[pid   143] 1770651503.762460 openat(AT_FDCWD</workspace>, "/workspace/bin/hello_csharp", O_RDONLY) = 16</workspace/bin/hello_csharp>
[pid   143] 1770651503.762883 fcntl(16</workspace/bin/hello_csharp>, F_SETFD, FD_CLOEXEC) = 0
[pid   143] 1770651503.763136 fcntl(16</workspace/bin/hello_csharp>, F_DUPFD_CLOEXEC, 0) = 17</workspace/bin/hello_csharp>
[pid   143] 1770651503.769514 openat(AT_FDCWD</workspace>, "/workspace/bin/hello_csharp", O_RDONLY) = 18</workspace/bin/hello_csharp>
[pid   143] 1770651503.770035 fcntl(18</workspace/bin/hello_csharp>, F_SETFD, FD_CLOEXEC) = 0
[pid   143] 1770651503.770286 fcntl(18</workspace/bin/hello_csharp>, F_DUPFD_CLOEXEC, 0) = 19</workspace/bin/hello_csharp>
[pid   143] 1770651503.779217 openat(AT_FDCWD</workspace>, "/workspace/bin/hello_csharp", O_RDONLY) = 20</workspace/bin/hello_csharp>
[pid   143] 1770651503.779738 fcntl(20</workspace/bin/hello_csharp>, F_SETFD, FD_CLOEXEC) = 0
[pid   143] 1770651503.780015 fcntl(20</workspace/bin/hello_csharp>, F_DUPFD_CLOEXEC, 0) = 21</workspace/bin/hello_csharp>
[pid   143] 1770651503.786433 openat(AT_FDCWD</workspace>, "/workspace/bin/hello_csharp", O_RDONLY) = 22</workspace/bin/hello_csharp>
[pid   143] 1770651503.786897 fcntl(22</workspace/bin/hello_csharp>, F_SETFD, FD_CLOEXEC) = 0
[pid   143] 1770651503.787267 fcntl(22</workspace/bin/hello_csharp>, F_DUPFD_CLOEXEC, 0) = 23</workspace/bin/hello_csharp>
[pid   143] 1770651503.790962 fcntl(1</dev/pts/0<char 136:0>>, F_DUPFD_CLOEXEC, 0) = 24</dev/pts/0<char 136:0>>
[pid   143] 1770651503.799356 openat(AT_FDCWD</workspace>, "/workspace/bin/hello_csharp", O_RDONLY) = 25</workspace/bin/hello_csharp>
[pid   143] 1770651503.799878 fcntl(25</workspace/bin/hello_csharp>, F_SETFD, FD_CLOEXEC) = 0
[pid   143] 1770651503.800107 fcntl(25</workspace/bin/hello_csharp>, F_DUPFD_CLOEXEC, 0) = 26</workspace/bin/hello_csharp>
strace: Process 150 attached
[pid   143] 1770651503.804328 openat(AT_FDCWD</workspace>, "/root/.terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.805457 openat(AT_FDCWD</workspace>, "/root/.terminfo/78/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.805598 openat(AT_FDCWD</workspace>, "/etc/terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.805738 openat(AT_FDCWD</workspace>, "/etc/terminfo/78/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.805889 openat(AT_FDCWD</workspace>, "/lib/terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.806050 openat(AT_FDCWD</workspace>, "/lib/terminfo/78/xterm", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.806268 openat(AT_FDCWD</workspace>, "/usr/share/terminfo/x/xterm", O_RDONLY|O_CLOEXEC) = 29</usr/share/terminfo/x/xterm>
[pid   143] 1770651503.807384 openat(AT_FDCWD</workspace>, "/workspace/bin/hello_csharp", O_RDONLY) = 30</workspace/bin/hello_csharp>
[pid   143] 1770651503.807820 fcntl(30</workspace/bin/hello_csharp>, F_SETFD, FD_CLOEXEC) = 0
[pid   143] 1770651503.808029 fcntl(30</workspace/bin/hello_csharp>, F_DUPFD_CLOEXEC, 0) = 31</workspace/bin/hello_csharp>
[pid   143] 1770651503.811379 openat(AT_FDCWD</workspace>, "/workspace/bin/hello_csharp", O_RDONLY) = 32</workspace/bin/hello_csharp>
[pid   143] 1770651503.811898 fcntl(32</workspace/bin/hello_csharp>, F_SETFD, FD_CLOEXEC) = 0
[pid   143] 1770651503.812202 fcntl(32</workspace/bin/hello_csharp>, F_DUPFD_CLOEXEC, 0) = 33</workspace/bin/hello_csharp>
[pid   143] 1770651503.819234 close(29</usr/share/terminfo/x/xterm>) = 0
[pid   143] 1770651503.821484 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29</etc/ld.so.cache>
[pid   143] 1770651503.821744 close(29</etc/ld.so.cache>) = 0
[pid   143] 1770651503.821877 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.822027 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.822180 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.822296 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.90", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.822496 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29</etc/ld.so.cache>
[pid   143] 1770651503.822790 close(29</etc/ld.so.cache>) = 0
[pid   143] 1770651503.822908 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.89", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.823061 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.89", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.823191 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.89", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.823323 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.89", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.823533 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29</etc/ld.so.cache>
[pid   143] 1770651503.823862 close(29</etc/ld.so.cache>) = 0
[pid   143] 1770651503.823971 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.88", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.824115 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.88", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.824245 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.88", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.824350 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.88", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.824537 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29</etc/ld.so.cache>
[pid   143] 1770651503.824873 close(29</etc/ld.so.cache>) = 0
[pid   143] 1770651503.824996 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.87", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.825210 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.87", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.825320 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.87", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.825400 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.87", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.825577 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29</etc/ld.so.cache>
[pid   143] 1770651503.825921 close(29</etc/ld.so.cache>) = 0
[pid   143] 1770651503.826037 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.86", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.826181 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.86", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.826345 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.86", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.826517 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.86", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.826743 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29</etc/ld.so.cache>
[pid   143] 1770651503.827013 close(29</etc/ld.so.cache>) = 0
[pid   143] 1770651503.827184 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.85", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.827308 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.85", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.827414 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.85", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.827546 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.85", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.827743 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29</etc/ld.so.cache>
[pid   143] 1770651503.828080 close(29</etc/ld.so.cache>) = 0
[pid   143] 1770651503.828260 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.84", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.828410 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.84", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.828527 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.84", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.828655 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.84", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.828891 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29</etc/ld.so.cache>
[pid   143] 1770651503.829219 close(29</etc/ld.so.cache>) = 0
[pid   143] 1770651503.829330 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.83", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.829457 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.83", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.829600 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.83", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.829721 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.83", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.829992 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29</etc/ld.so.cache>
[pid   143] 1770651503.830294 close(29</etc/ld.so.cache>) = 0
[pid   143] 1770651503.830407 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.82", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.830538 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.82", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.830661 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.82", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.830761 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.82", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.830942 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29</etc/ld.so.cache>
[pid   143] 1770651503.831250 close(29</etc/ld.so.cache>) = 0
[pid   143] 1770651503.831386 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.81", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.831513 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.81", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.831643 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.81", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.831818 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.81", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.832110 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29</etc/ld.so.cache>
[pid   143] 1770651503.832416 close(29</etc/ld.so.cache>) = 0
[pid   143] 1770651503.832537 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.80", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.832691 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.80", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.832827 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.80", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.832943 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.80", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.833210 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29</etc/ld.so.cache>
[pid   143] 1770651503.833542 close(29</etc/ld.so.cache>) = 0
[pid   143] 1770651503.833681 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.79", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.833836 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.79", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.833988 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.79", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.834114 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.79", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.834362 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29</etc/ld.so.cache>
[pid   143] 1770651503.834618 close(29</etc/ld.so.cache>) = 0
[pid   143] 1770651503.834710 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.78", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.834952 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.78", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.835083 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.78", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.835207 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.78", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.835438 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29</etc/ld.so.cache>
[pid   143] 1770651503.835794 close(29</etc/ld.so.cache>) = 0
[pid   143] 1770651503.835904 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.77", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.836046 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.77", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.836204 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.77", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.836366 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.77", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.836645 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29</etc/ld.so.cache>
[pid   143] 1770651503.836936 close(29</etc/ld.so.cache>) = 0
[pid   143] 1770651503.837088 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.76", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.837257 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.76", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.837387 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.76", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.837559 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.76", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.837851 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29</etc/ld.so.cache>
[pid   143] 1770651503.838170 close(29</etc/ld.so.cache>) = 0
[pid   143] 1770651503.838272 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.75", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.838409 openat(AT_FDCWD</workspace>, "/usr/lib/x86_64-linux-gnu/libicuuc.so.75", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.838562 openat(AT_FDCWD</workspace>, "/lib/libicuuc.so.75", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.838724 openat(AT_FDCWD</workspace>, "/usr/lib/libicuuc.so.75", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
[pid   143] 1770651503.838965 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29</etc/ld.so.cache>
[pid   143] 1770651503.839287 close(29</etc/ld.so.cache>) = 0
[pid   143] 1770651503.839394 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicuuc.so.74", O_RDONLY|O_CLOEXEC) = 29</usr/lib/x86_64-linux-gnu/libicuuc.so.74.2>
[pid   143] 1770651503.840074 close(29</usr/lib/x86_64-linux-gnu/libicuuc.so.74.2>) = 0
[pid   143] 1770651503.840189 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicudata.so.74", O_RDONLY|O_CLOEXEC) = 29</usr/lib/x86_64-linux-gnu/libicudata.so.74.2>
[pid   143] 1770651503.840985 close(29</usr/lib/x86_64-linux-gnu/libicudata.so.74.2>) = 0
[pid   143] 1770651503.841575 openat(AT_FDCWD</workspace>, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 29</etc/ld.so.cache>
[pid   143] 1770651503.841994 close(29</etc/ld.so.cache>) = 0
[pid   143] 1770651503.842160 openat(AT_FDCWD</workspace>, "/lib/x86_64-linux-gnu/libicui18n.so.74", O_RDONLY|O_CLOEXEC) = 29</usr/lib/x86_64-linux-gnu/libicui18n.so.74.2>
[pid   143] 1770651503.842904 close(29</usr/lib/x86_64-linux-gnu/libicui18n.so.74.2>) = 0
[pid   143] 1770651503.847992 write(1</dev/pts/0<char 136:0>>, "\33[?1h\33=", 7) = 7
[pid   143] 1770651503.848572 write(24</dev/pts/0<char 136:0>>, "Hello, World\n", 13Hello, World
) = 13
[pid   143] 1770651503.850376 write(4<pipe:[653798]>, "\1", 1) = 1
[pid   144] 1770651503.850599 close(4<pipe:[653798]>) = 0
[pid   146] 1770651503.851271 <... openat resumed>) = ?
[pid   150] 1770651503.851382 +++ exited with 0 +++
[pid   149] 1770651503.851403 +++ exited with 0 +++
[pid   148] 1770651503.851425 +++ exited with 0 +++
[pid   147] 1770651503.851445 +++ exited with 0 +++
[pid   146] 1770651503.851456 +++ exited with 0 +++
[pid   145] 1770651503.851479 +++ exited with 0 +++
[pid   144] 1770651503.856690 +++ exited with 0 +++
1770651503.856716 +++ exited with 0 +++

ログを見ているとclr-debug-pipeというパイプで診断情報をやり取りしていますが、これは診断用でDOTNET_EnableDiagnostics=0を指定すれば止められます。診断情報を止めた状態でstraceを取ると、clr-debug-pipeがなくなります。システムコール的には1つ減るだけですが、診断情報は不要なら止める判断もありでしょう。

$ DOTNET_EnableDiagnostics=0 strace -f -ttt -e trace=openat,close,fcntl,write -yy -s 200 ./bin/hello_csharp

まとめ

C#のstraceを追いかけてみましたが、面白かったです。こうやってみていくとstraceのシステムコールが少ないからよい、とは一概には言えないと感じます。

C#のdotnetランタイム(CoreCLR)は、GC最適化やJITコンパイラのために環境情報を収集しており、これにより実行時のパフォーマンスを向上させています。仮にdotnetランタイムが/proc/sysを見に行くシステムコールをしていない場合、それはGC、JITコンパイラのTiered PGO最適化、その他ランタイム最適化のための情報を取得できないことを意味します。CやRustのように、メモリ管理や最適化を手動で行う言語と異なり、C#などのマネージドランタイムは、ランタイムがシステムの状態を把握して最適化を行うことに依存しています。したがって、必要なシステムコールはある程度存在するでしょう。

一方で、C# AOTのシステムコールは起動時のシステムコールを最小限に抑えつつ、必要な最適化情報を取得するよう設計されています。straceで追いかけていて無駄だなーと感じるポイントが少なく、だいぶん頑張っているなーという印象です。このあたりは、AOTとJITの違いがよく出ていますね。

参考

元記事

本記事の再現をGitHub


  1. 共有ライブラリビルドをするには、go install -buildmode=shared stdが必要です。
  2. ちなみにDOTNET_EnableDiagnostics=0で診断系を止めても、strace上は変化がありません。

GitHub Actionsで他のワークフローやリポジトリのアーティファクトをダウンロードする

GitHub Actionsでアーティファクトのアップロードはactions/upload-artifact、ダウンロードはactions/download-artifactで行います。普段は同一ワークフローのジョブ間でアーティファクトを受け渡すのに使っていますが、他のワークフローやリポジトリのアーティファクトをダウンロードしたい場合もあります。

例えば、あるワークフローでネイティブビルドを行っていて10分かかります。そのビルド成果物を別のワークフローで使い回したいときに、改めてビルドすることなくダウンロードできます。ビルドで一番つらいのは時間がかかることなので、ビルド成果物を使い回せると助かりますよね。

今回は、actions/download-artifactでワークフローやリポジトリを跨いで、アーティファクトをダウンロードできるという話です。シラナカッタ。

何ができるのか

actions/download-artifact(v4以降/v3とv4の差分)を使って、他のワークフローやリポジトリのアーティファクトをダウンロードできます。例えば次のように書くと、run-idで指定した別ワークフローの実行履歴11100002222でアップロードされたすべてのアーティファクトを、今のワークフローにダウンロードします。

- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
  with:
    run-id: "11100002222"
    github-token: ${{ github.token }}
  • run-id: 対象ワークフローの履歴ページURLの末尾にある数字列。例えば、https://github.com/<ORG>/<REPO>/actions/runs/123456789なら123456789
  • github-token: アクセス権限のあるGitHubトークン。同一リポジトリなら${{ github.token }}を指定すればOK。通常は無指定なので、指定必須
  • name: 省略するとすべてのアーティファクトをダウンロード、特定の名前のアーティファクトだけ欲しい場合は指定

なお、ドキュメントにはactions: read権限をジョブにつけるように書かれていますが、同一リポジトリの場合は権限を指定しなくてもダウンロードできます。

使い方

私のリポジトリguitarrapc/githubactions-labを使って実際の挙動を見つつ使い方を確認しましょう。 今回は、同一リポジトリ内の他ワークフローからアーティファクトをダウンロードします。

アーティファクトをアップロードするワークフローを用意する

まずは、actions/upload-artifactでアップロードするワークフローartifacts-targz.yamlを用意して実行します。(artifacts (tar.gz) #378)

URLから、この時のrun-id21203098493とわかります。

ワークフロー実行結果にoutput.tar.gzが添付されている

name: artifacts (tar.gz)
on:
  workflow_dispatch:
  pull_request:
    branches: [main]
  push:
    branches: [main]

jobs:
  # tar.gz
  upload-targz:
    permissions:
      contents: read
    runs-on: ubuntu-24.04
    timeout-minutes: 3
    steps:
      - name: output
        run: |
          mkdir -p ./output/bin
          echo "hoge" > ./output/hoge.txt
          echo "fuga" > ./output/fuga.txt
          echo "foo" > ./output/bin/foo.txt
          echo "bar" > ./output/bin/bar.txt
          tar -zcvf output.tar.gz ./output/
      - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
        with:
          name: output.tar.gz
          path: ./output.tar.gz
          retention-days: 1

  download-targz:
    needs: [upload-targz]
    # ... ただのアップロード確認なので省略

アップロードができたら、次に他のワークフローからダウンロードしてみましょう。

他のワークフローのアーティファクトをダウンロードする

次に、上記ワークフローでアップロードしたアーティファクトをダウンロードするワークフローartifacts-other-workflow.yamlを用意します。 run-idを指定した場合は「run-idの履歴」から、指定しなかった場合は「最新の成功ビルド履歴」からアーティファクトをダウンロードします。

name: artifacts (other workflow)
on:
  workflow_dispatch:
    inputs:
      workflow-name:
        description: "Workflow name to download artifacts from"
        required: true
        default: "artifacts-targz.yaml"
      run-id:
        description: "Run ID to download artifacts from (optional)"
        required: false
        default: ""

jobs:
  download-directory:
    permissions:
      contents: read
    runs-on: ubuntu-24.04
    timeout-minutes: 3
    steps:
      - name: List Run Ids of specified workflow
        run: gh run list -w ${{ inputs.workflow-name }} --status completed --limit 5
        env:
          GH_REPO: ${{ github.repository }}
          GH_TOKEN: ${{ github.token }}
      - name: Get latest Run Id of specified workflow
        if: ${{ inputs.run-id == '' }}
        id: get-run-id
        run: |
          run_id=$(gh run list -w ${{ inputs.workflow-name }} --status completed --limit 1 --json databaseId --jq ".[].databaseId")
          echo "run_id=$run_id" | tee -a "$GITHUB_OUTPUT"
        env:
          GH_REPO: ${{ github.repository }}
          GH_TOKEN: ${{ github.token }}
      - name: Get run details
        run: gh run view ${{ inputs.run-id || steps.get-run-id.outputs.run_id }}
        env:
          GH_REPO: ${{ github.repository }}
          GH_TOKEN: ${{ github.token }}
      - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
        with:
          run-id: ${{ inputs.run-id || steps.get-run-id.outputs.run_id }}
          github-token: ${{ github.token }}
      - name: ls
        run: ls -lR

実行してみましょう。run-idを指定してもいいですが、今回は空にして最新のビルドからダウンロードさせます。

workflow_dispatchで実行する

実行履歴をみると、指定したワークフローの最新成功ビルド履歴のrun-id21203098493からダウンロードできています。

actions/download-artifactで他ワークフローのアーティファクトをダウンロードできている

Run actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131
  with:
    run-id: 21203098493
    github-token: ***
    merge-multiple: false
    repository: guitarrapc/githubactions-lab
Fetching artifact list for workflow run 21203098493 in repository guitarrapc/githubactions-lab
Found 1 artifact(s)
No input name, artifact-ids or pattern filtered specified, downloading all artifacts
An extra directory with the artifact name will be created for each download
Preparing to download the following artifacts:
- output.tar.gz (ID: 5201415391, Size: 379, Expected Digest: sha256:81f29b05074a1ed328654302ee20a68e087f13788371ad1ef3cdeb2ddf4c0972)
Downloading artifact '5201415391' from 'guitarrapc/githubactions-lab'
Redirecting to blob download url: https://productionresultssa10.blob.core.windows.net/actions-results/751cc8ca-c811-458d-9fb6-fb2a0a957314/workflow-job-run-a66f81bc-92fb-527d-84b2-0d7efafd23ba/artifacts/3dcf0ac43e2ba1e4dda83cc9cad71ef1586214d36718776b88b6e1d93987cce0.zip
Starting download of artifact to: /home/runner/work/githubactions-lab/githubactions-lab
(node:2030) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
SHA256 digest of downloaded artifact is 81f29b05074a1ed328654302ee20a68e087f13788371ad1ef3cdeb2ddf4c0972
Artifact download completed successfully.
Total of 1 artifact(s) downloaded
Download artifact has finished successfully

ワークフローを跨いでアーティファクトをダウンロードできるんですねー!

トラブルシュート

いくつか遭遇したトラブルとその対処法を紹介します。

run-idを指定したのにアーティファクトが見つからない

デフォルトのactions/download-artifactは、github-tokenが空のためrun-idだけ指定してもアーティファクトが見つからないと出ます。

例えば、次の設定だとgithub-tokenが無指定なのでアーティファクトが見つかりません。エラーログからはトークンがないことためと分からないのでハマりやすいです。ハマった。

# ❌
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
  with:
    run-id: 1234
Found 0 artifact(s)
No input name, artifact-ids or pattern filtered specified, downloading all artifacts
An extra directory with the artifact name will be created for each download
Total of 0 artifact(s) downloaded
Download artifact has finished successfully

この場合、github-token${{ github.token }}やPATを指定しましょう。

# OK
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
  with:
    run-id: 1234
    github-token: ${{ github.token }}

github-tokenとrun-idを指定したのにアーティファクトが見つからない

別のリポジトリの場合、ワークフローで自動発行されるトークン${{ github.token }}ではアクセスできません。

# ❌
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
  with:
    run-id: 9876
    repository: some/other-repo
    github-token: ${{ github.token }}

この場合、PATかGitHub Appのインストールアクセストークンを使う必要があります。

# OK
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
  with:
    run-id: 9876
    repository: some/other-repo
    github-token: ${{ secrets.YOUR_PAT }}

また、PATにはactions: read権限が必要です。

To elevate permissions for this scenario, you can specify a github-token along with other repository and run identifiers:

公式の案内でactions:read権限が必要と明記されている

権限に問題がないがアーティファクトが見つからない

actions/upload-artifactでアーティファクトをアップロードしたアーティファクトは、一定の期間だけ保持されます。デフォルトで特に指定なければ90日間ですが、ワークフローでretention-daysを指定している場合はその日数になります。

私はよくretention-days: 1にしているため、翌日にはアーティファクトが消えていて見つからなくなります。アーティファクトが見つからない場合は、対象のrun-idのアーティファクトがまだ存在しているか確認してください。

期限が切れている場合、次のようにExpiredと表示されます。

アーティファクトの期限が切れてExpiredと表示されている

まとめ

actions/download-artifact@v3までは同一ワークフローからしか取得できなかったので、てっきり今もかと考えていましたが、v4(2023年12月15日リリース)以降は他のワークフローやリポジトリのアーティファクトもダウンロードできます。

中にはGitHub APIを駆使して取得する例もありますが、アーティファクトをAPIで触るのは割と面倒です。actions/download-artifactを使えるシーンでは積極的に使っていきましょう。

参考