# 画面設計書 7-Log Profiler Sample

## 概要

本ドキュメントは、.NET WebAssembly のログプロファイラーサンプル画面「Log Profiler Sample」の設計内容を記載した画面設計書です。本画面は .NET Runtime リポジトリにおける WebAssembly のログプロファイリング機能（メモリアロケーション追跡、ヒープショット取得）をデモンストレーションするサンプルアプリケーションです。

### 本画面の処理概要

本画面は、ブラウザ上で .NET WebAssembly ランタイムのログプロファイリング機能を使用して、メモリアロケーション情報とヒープショットを収集し、プロファイルデータファイル（.mlpd）として保存するサンプルアプリケーションです。

**業務上の目的・背景**：本画面は、.NET WebAssembly アプリケーションのログプロファイリング機能を検証・デモンストレーションするために作成されました。ログプロファイラーは、メモリアロケーションの追跡、ヒープショットの取得、ガベージコレクションの分析などの機能を提供します。これにより、メモリリークの検出やメモリ使用パターンの最適化に役立つ情報を収集できます。

**画面へのアクセス方法**：ローカル開発サーバー（通常は `http://localhost:8000/`）にブラウザでアクセスすることで画面を表示できます。

**主要な操作・処理内容**：
1. 画面ロード時に JavaScript（main.js）が .NET WebAssembly ランタイムを初期化
2. logProfilerOptions でログプロファイリングを設定（アロケーション追跡）
3. `dotnet.run()` でランタイムを開始
4. C# の `TestMeaning()` メソッドを呼び出し（メモリ割り当てを生成）
5. 結果を DOM に表示
6. `TakeHeapshot()` でヒープショットを取得
7. `saveProfile()` でログプロファイルデータをファイルとしてダウンロード

**画面遷移**：本画面は単一画面のサンプルアプリケーションであり、他画面への遷移はありません。

**権限による表示制御**：本画面は認証・認可機能を持たないデモアプリケーションであり、権限による表示制御はありません。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 2 | Mono | 主機能 | WebAssembly ランタイム上でログプロファイリングを実行 |
| 59 | WebAssembly Workload | 主機能 | WebAssembly アプリケーションのビルドと実行をサポート |
| 49 | eventpipe | 補助機能 | ログプロファイリング用の診断イベントストリーミング |
| 5 | ガベージコレクター | 補助機能 | ヒープショット取得のためのメモリ管理 |

## 画面種別

プロファイリングデモ画面（単一画面）

## URL/ルーティング

- ローカル開発: `http://localhost:8000/index.html`
- 静的ファイルパス: `src/mono/sample/wasm/browser-logprofile/wwwroot/index.html`

## 入出力項目

| 項目名 | 入出力 | データ型 | 説明 |
|--------|--------|----------|------|
| - | - | - | 本画面にユーザー入力項目はありません |

## 表示項目

| 項目ID | 項目名 | 要素タイプ | 説明 |
|--------|--------|-----------|------|
| header | 画面タイトル | h3 | 「Wasm Log Profiler Sample」と表示 |
| out | 計算結果 | span | Sample.Test.TestMeaning の結果（42）を表示 |

## イベント仕様

### 1-画面ロード完了イベント

画面がロードされると、以下の処理が自動的に実行されます:

1. `main.js` がモジュールとして読み込まれる
2. `dotnet.create()` で WebAssembly ランタイムを初期化
3. `logProfilerOptions` でログプロファイリングを設定
   - `takeHeapshot`: "Sample.Test::TakeHeapshot" - ヒープショット取得トリガー
   - `configuration`: "log:alloc,output=output.mlpd" - アロケーション追跡、出力ファイル設定
4. `getAssemblyExports` で C# の公開メソッドを取得
5. `dotnet.run()` でランタイムを開始
6. `testMeaning()` を呼び出し、結果を DOM に表示
7. `takeHeapshot()` を呼び出してヒープショットを取得
8. `saveProfile(Module)` でプロファイルデータをダウンロード
9. 結果が 42 の場合は終了コード 0、それ以外は 1 で終了

### 2-プロファイルデータ保存

1. `readProfileFile(Module)` で "output.mlpd" ファイルを読み取り
2. `Module.FS.stat()` でファイルサイズを確認
3. `Module.FS.readFile()` でファイル内容を取得
4. Blob を作成し a 要素でダウンロード

## データベース更新仕様

### 操作別データベース影響一覧

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| - | - | - | 本画面はデータベースを使用しません |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|---------|
| MSG-001 | 情報 | not ready yet | ランタイム初期化中 |
| MSG-002 | 情報 | ready | ランタイム初期化完了後 |
| MSG-003 | デバッグ | ret: {value} | testMeaning 結果取得後 |
| MSG-004 | 情報 | Hello, World! | C# Main メソッド実行時 |
| MSG-005 | デバッグ | Unable to fetch the profile file {path} as it is empty | プロファイルファイルが空の場合 |

## 例外処理

| 例外種別 | 発生条件 | 対応処理 |
|---------|---------|---------|
| プロファイルファイル空 | output.mlpd が空または存在しない場合 | コンソールにデバッグメッセージ出力、null を返す |
| JavaScript エラー | ランタイム初期化失敗時 | `exit(-1, err)` で終了 |

## 備考

- `logProfilerOptions.takeHeapshot` でヒープショット取得のトリガーメソッドを指定
- `logProfilerOptions.configuration` でプロファイラー設定を指定
  - `log:alloc` - アロケーション追跡を有効化
  - `output=output.mlpd` - 出力ファイルパス
- プロファイルデータは Emscripten ファイルシステム（Module.FS）に書き込まれる
- ダウンロードされるファイル名は "output.mlpd"
- TestMeaning 内で 100 回のループで int[1000] を生成（メモリアロケーションのテスト）

---

## コードリーディングガイド

本画面を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、ログプロファイリングの設定とデータ構造を理解することが重要です。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | main.js | `src/mono/sample/wasm/browser-logprofile/wwwroot/main.js` | logProfilerOptions の設定を確認 |
| 1-2 | Program.cs | `src/mono/sample/wasm/browser-logprofile/Program.cs` | JSExport メソッドとメモリアロケーション生成を確認 |

**読解のコツ**: `logProfilerOptions` の `takeHeapshot` と `configuration` がログプロファイリングの動作を決定します。

#### Step 2: エントリーポイントを理解する

処理の起点となるファイル・関数を特定します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.html | `src/mono/sample/wasm/browser-logprofile/wwwroot/index.html` | HTML 構造を確認 |
| 2-2 | main.js | `src/mono/sample/wasm/browser-logprofile/wwwroot/main.js` | プロファイリング処理フローを確認 |

**主要処理フロー (main.js)**:
1. **6-19行目**: `saveProfile` 関数 - ログプロファイルデータをファイルとしてダウンロード
2. **21-33行目**: `readProfileFile` 関数 - Emscripten FS からプロファイルファイルを読み取り
3. **35-46行目**: `dotnet.create()` でランタイム初期化（logProfilerOptions 設定）
4. **48-52行目**: C# メソッドの取得と変数への格納
5. **54行目**: `dotnet.run()` でランタイム開始
6. **56-58行目**: `testMeaning()` 呼び出しと DOM 更新
7. **60-61行目**: `takeHeapshot()` 呼び出しとプロファイルデータ保存

#### Step 3: C# 側のプロファイリング対象を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Program.cs | `src/mono/sample/wasm/browser-logprofile/Program.cs` | TestMeaning でのメモリアロケーションと TakeHeapshot を確認 |

**主要処理フロー (Program.cs)**:
- **12-15行目**: `Main` - Hello, World! 出力
- **17-19行目**: `TakeHeapshot` - ヒープショット取得トリガー（NoInlining 属性付き空実装）
- **21-29行目**: `TestMeaning` - 100 回ループで int[1000] を生成し、42 を返す

### プログラム呼び出し階層図

```
[Browser] index.html 読み込み
    |
    +-- [JavaScript] main.js 実行
            |
            +-- dotnet.create() - WebAssembly ランタイム初期化
            |       |
            |       +-- logProfilerOptions 設定
            |               |
            |               +-- takeHeapshot: "Sample.Test::TakeHeapshot"
            |               +-- configuration: "log:alloc,output=output.mlpd"
            |
            +-- getAssemblyExports() - C# メソッドを取得
            |
            +-- dotnet.run() - ランタイム開始
            |
            +-- testMeaning() 呼び出し
            |       |
            |       +-- [C#] TestMeaning() 実行
            |               |
            |               +-- for (100回) { new int[1000] }
            |               +-- return 42
            |
            +-- DOM 更新 (#out に 42 を表示)
            |
            +-- takeHeapshot() 呼び出し
            |       |
            |       +-- [C#] TakeHeapshot() 実行
            |               |
            |               +-- (ヒープショット取得トリガー)
            |               +-- output.mlpd に書き込み
            |
            +-- saveProfile(Module)
                    |
                    +-- readProfileFile(Module)
                    |       |
                    |       +-- Module.FS.stat("output.mlpd")
                    |       +-- Module.FS.readFile("output.mlpd")
                    |
                    +-- Blob 作成
                    +-- a 要素でダウンロード
                    +-- "output.mlpd" として保存
```

### データフロー図

```
[入力]                      [処理]                           [出力]

                     +-- dotnet.create() ----+
                     |   logProfilerOptions  |
                     +----------+-----------+
                                |
                                v
                     +-- dotnet.run() ----+
                     |   ランタイム開始     |
                     +----------+-----------+
                                |
                                v
                     +-- TestMeaning() ----+
                     |   メモリアロケーション  |
                     |   for (100回) {       |
                     |     new int[1000]    |
                     |   }                   |
                     +----------+-----------+
                                |
                                v
                     document.getElementById("out")
                        .innerHTML = "42"
                              |
                              v
                     +-- TakeHeapshot() ----+
                     |   (ヒープショット取得)   |
                     +----------+-----------+
                                |
                                v
                     [Emscripten FS]
                     output.mlpd ファイル
                                |
                                v
                     +-- readProfileFile() ----+
                     |   Module.FS.readFile()  |
                     +----------+-----------+
                                |
                                v
                     +-- saveProfile() ----+
                     |   Blob 作成 & DL     |
                     +----------+-----------+
                                |
                                v
                     "output.mlpd" ファイル
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.html | `src/mono/sample/wasm/browser-logprofile/wwwroot/index.html` | テンプレート | HTML エントリーポイント |
| main.js | `src/mono/sample/wasm/browser-logprofile/wwwroot/main.js` | ソース | JavaScript エントリーポイント、プロファイリング処理 |
| Program.cs | `src/mono/sample/wasm/browser-logprofile/Program.cs` | ソース | C# メインロジック、メモリアロケーション生成 |
| dotnet.js | `_framework/dotnet.js` | ランタイム | .NET WebAssembly ランタイムローダー（ビルド時生成） |
