{"id":34837022,"url":"https://github.com/modelingevolution/blazor-perfmon","last_synced_at":"2025-12-25T16:08:17.845Z","repository":{"id":325639405,"uuid":"1101927263","full_name":"modelingevolution/blazor-perfmon","owner":"modelingevolution","description":null,"archived":false,"fork":false,"pushed_at":"2025-12-14T20:23:31.000Z","size":26870,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-12-17T08:27:02.649Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/modelingevolution.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-22T13:55:29.000Z","updated_at":"2025-12-14T20:23:25.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/modelingevolution/blazor-perfmon","commit_stats":null,"previous_names":["modelingevolution/blazor-perfmon"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/modelingevolution/blazor-perfmon","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/modelingevolution%2Fblazor-perfmon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/modelingevolution%2Fblazor-perfmon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/modelingevolution%2Fblazor-perfmon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/modelingevolution%2Fblazor-perfmon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/modelingevolution","download_url":"https://codeload.github.com/modelingevolution/blazor-perfmon/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/modelingevolution%2Fblazor-perfmon/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28032370,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-25T02:00:05.988Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-12-25T16:06:47.186Z","updated_at":"2025-12-25T16:08:17.836Z","avatar_url":"https://github.com/modelingevolution.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Blazor Performance Monitor\n\n[![NuGet Server](https://img.shields.io/nuget/v/ModelingEvolution.PerformanceMonitor.Server.svg)](https://www.nuget.org/packages/ModelingEvolution.PerformanceMonitor.Server/)\n[![NuGet Client](https://img.shields.io/nuget/v/ModelingEvolution.PerformanceMonitor.Client.svg)](https://www.nuget.org/packages/ModelingEvolution.PerformanceMonitor.Client/)\n[![NuGet Shared](https://img.shields.io/nuget/v/ModelingEvolution.PerformanceMonitor.Shared.svg)](https://www.nuget.org/packages/ModelingEvolution.PerformanceMonitor.Shared/)\n\nReal-time comprehensive performance monitoring system with Blazor WebAssembly frontend and SkiaSharp rendering.\n\n## Current Status: Multi-Metric Monitoring System ✓\n\n**Comprehensive System Monitoring** - FULLY IMPLEMENTED\n\n- ✅ CPU monitoring (multi-core bar charts and time-series)\n- ✅ GPU monitoring (NVIDIA multi-GPU support with bar charts)\n- ✅ **NVIDIA Jetson Tegra support** (tegrastats-based monitoring)\n- ✅ **Temperature monitoring** (multi-sensor visualization with min/max tracking)\n- ✅ Network monitoring (multi-interface RX/TX tracking)\n- ✅ Disk I/O monitoring (read/write operations)\n- ✅ Docker container monitoring (CPU % and memory usage with unified colors)\n- ✅ RAM monitoring with time-series visualization\n- ✅ **Client-server timestamp synchronization** (automatic clock skew correction)\n- ✅ WebSocket streaming with MessagePack serialization\n- ✅ Blazor WASM frontend with SkiaSharp hardware-accelerated rendering\n- ✅ Immutable circular buffers for thread-safe data storage\n- ✅ Auto-reconnect on disconnect\n- ✅ **Unified color scheme** across all charts (RAM: blue, CPU: green)\n\n## Architecture\n\n### Backend (.NET 10)\n- **Metrics Collectors**:\n  - **CpuCollector**: Reads `/proc/stat`, calculates per-core load\n  - **GpuCollector**: NVIDIA GPU monitoring via `nvidia-smi`\n  - **NetworkCollector**: Multi-interface network statistics from `/proc/net/dev`\n  - **DiskCollector**: Disk I/O metrics from `/proc/diskstats`\n  - **DockerCollector**: Container metrics via Docker API\n- **Multiplex Service**: TPL Dataflow pipeline with configurable timer\n- **WebSocket Service**: Binary MessagePack streaming\n\n### Frontend (Blazor WASM + SkiaSharp)\n- **WebSocket Client**: Auto-reconnect with 5-second retry\n- **Metrics Store**: ImmutableCircularBuffer for thread-safe 60-second rolling window\n- **Chart Renderers**: Hardware-accelerated SkiaSharp canvas with multiple chart types:\n  - **BarChart**: Generic bar chart with customizable colors\n  - **CpuBarChart**: Per-core CPU load visualization\n  - **GpuBarChart**: Per-GPU load visualization\n  - **TimeSeriesChart**: Time-based line charts with dynamic scaling\n  - **NetworkChart**: Network RX/TX time-series\n  - **DiskChart**: Disk I/O time-series\n  - **DockerContainersChart**: Double-bar visualization (memory + CPU)\n  - **ComputeLoadChart**: Overall system compute load\n- **Brushes**: Static reusable SKPaint objects to avoid allocations in hot rendering paths\n\n## Build and Run\n\n### Prerequisites\n- .NET 10 SDK\n- Linux (for /proc access to system metrics)\n- NVIDIA GPU with `nvidia-smi` (optional, for GPU monitoring)\n- Docker (optional, for container monitoring)\n\n### Build\n```bash\ndotnet build BlazorPerfMon.sln\n```\n\n### Run\n```bash\ncd src/ModelingEvolution.BlazorPerfMon.Server\ndotnet run\n```\n\nAccess at: `http://localhost:5000`\n\nWebSocket endpoint: `ws://localhost:5000/ws`\n\n## Using the Client Library\n\n### Blazor WebAssembly Setup\n\nTo integrate the Performance Monitor client into your Blazor WASM application:\n\n1. **Install the NuGet package**:\n```bash\ndotnet add package ModelingEvolution.PerformanceMonitor.Client\n```\n\n2. **Register the client services** in `Program.cs`:\n```csharp\nusing Microsoft.AspNetCore.Components.WebAssembly.Hosting;\nusing ModelingEvolution.BlazorPerfMon.Client.Extensions;\n\nvar builder = WebAssemblyHostBuilder.CreateDefault(args);\n\n// Calculate WebSocket URL from base address\nstring wsUrl = builder.HostEnvironment.BaseAddress\n    .Replace(\"http://\", \"ws://\")\n    .Replace(\"https://\", \"wss://\") + \"ws\";\n\n// Register Performance Monitor client\nbuilder.Services.AddPerformanceMonitorClient(wsUrl, dataPointsToKeep: 120);\n\nawait builder.Build().RunAsync();\n```\n\n3. **Add the component** to your page:\n```razor\n@page \"/\"\n@using ModelingEvolution.BlazorPerfMon.Client.Components\n\n\u003cPerformanceMonitorCanvas /\u003e\n```\n\n### Component Features\n\n- **Automatic reconnection**: Component handles WebSocket disconnections and reconnects automatically\n- **Component lifecycle**: Each component instance creates its own WebSocket connection and metrics store\n- **Disposal support**: Components can be disposed and recreated without issues\n- **Multiple instances**: Multiple monitor components can coexist in the same application\n\n### Component Parameters\n\n- `ServerUrl` (optional): Override the default WebSocket URL for this component instance\n- `ShowStatusIndicator` (default: true): Show/hide the connection status indicator (green/yellow/red dot)\n\nExample with custom parameters:\n```razor\n\u003cPerformanceMonitorCanvas ServerUrl=\"ws://custom-server:5000/ws\" ShowStatusIndicator=\"true\" /\u003e\n```\n\n## Implementation Details\n\n### Metrics Collection\n- **Rate**: Configurable (default 500ms interval)\n- **CPU**: Multi-core support with per-core load calculation\n- **GPU**: NVIDIA multi-GPU support via nvidia-smi\n- **Network**: Multi-interface support (configurable via settings)\n- **Disk**: Multi-disk I/O monitoring\n- **Docker**: Container-level CPU and memory tracking\n- **Sources**: `/proc/stat`, `/proc/net/dev`, `/proc/diskstats`, nvidia-smi, Docker API\n\n### Data Pipeline\n```\nTimer (configurable interval)\n  ↓\nParallel Collectors → MetricSample\n  ├─ CpuCollector.Collect() → float[]\n  ├─ GpuCollector.Collect() → GpuMetric[]\n  ├─ NetworkCollector.Collect() → NetworkMetric[]\n  ├─ DiskCollector.Collect() → DiskMetric[]\n  └─ DockerCollector.Collect() → DockerContainerMetric[]\n  ↓\nBufferBlock\u003cMetricSample\u003e (capacity: configurable)\n  ↓\nTransformBlock → MessagePack serialize\n  ↓\nBroadcastBlock → All connected WebSocket clients\n  ↓\nActionBlock per client → WebSocket.SendAsync\n```\n\n### Frontend Rendering\n- **Canvas**: Responsive sizing\n- **Data Storage**: ImmutableCircularBuffer for thread-safe rolling window\n- **Chart Types**: Bar charts, time-series line charts with fill\n- **Performance Optimizations**:\n  - Reusable Brushes (SKPaint objects)\n  - Zero-allocation rendering after warmup\n  - Hardware-accelerated SkiaSharp\n  - Efficient time-based rendering with interpolation\n  - Dynamic scaling with min/max tracking\n\n## Performance Targets\n\nAchieved:\n- Backend CPU usage: \u003c5% with all collectors enabled ✓\n- WebSocket message size: Compact MessagePack binary format ✓\n- Frontend rendering: Hardware-accelerated SkiaSharp ✓\n- Zero allocations per render after warmup (via reusable Brushes) ✓\n- Thread-safe data access without locks (via ImmutableCircularBuffer) ✓\n- Smooth time-series rendering with interpolation ✓\n\n## Project Structure\n\n```\nsrc/\n  ModelingEvolution.BlazorPerfMon.Server/\n    Core/                        - Interfaces (IMetricsCollector)\n    Collectors/                  - All metrics collectors\n      ├─ CpuCollector.cs        - CPU per-core load\n      ├─ GpuCollector.cs        - NVIDIA GPU monitoring\n      ├─ NetworkCollector.cs    - Network interface stats\n      ├─ DiskCollector.cs       - Disk I/O metrics\n      └─ DockerCollector.cs     - Container monitoring\n    Services/                    - MultiplexService, WebSocketService\n    Program.cs                   - Main entry point\n\n  ModelingEvolution.BlazorPerfMon.Client/\n    Models/                      - MetricSample, CircularBuffer\n    Collections/                 - ImmutableCircularBuffer\n    Services/                    - WebSocketClient, MetricsStore\n    Rendering/                   - All chart renderers\n      ├─ IChart.cs              - Chart interface\n      ├─ Brushes.cs             - Reusable SKPaint objects\n      ├─ BarChart.cs            - Generic bar chart\n      ├─ CpuBarChart.cs         - CPU bar visualization\n      ├─ GpuBarChart.cs         - GPU bar visualization\n      ├─ TimeSeriesChart.cs     - Time-series line charts\n      ├─ NetworkChart.cs        - Network RX/TX charts\n      ├─ DiskChart.cs           - Disk I/O charts\n      ├─ DockerContainersChart.cs - Docker visualization\n      └─ ComputeLoadChart.cs    - Overall compute load\n    Pages/                       - Blazor pages\n\n  ModelingEvolution.BlazorPerfMon.Shared/\n    Models/                      - Shared DTOs and models\n\nexamples/\n  ModelingEvolution.BlazorPerfMon.Example/\n                                - Example implementation\n```\n\n## Technical Decisions\n\n1. **MessagePack over JSON**: 30-40% smaller payload for efficient binary streaming\n2. **TPL Dataflow**: Built-in backpressure, thread-safe pipeline architecture\n3. **SkiaSharp**: Hardware-accelerated, WASM-optimized 2D graphics\n4. **ImmutableCircularBuffer**: Lock-free thread-safety via immutable collections\n   - Eliminates lock contention between collection thread and UI render loop (60 FPS)\n   - Trade-off: GC pressure from allocations vs. lock contention in hot path\n5. **Reusable Brushes**: Static SKPaint objects to avoid allocations during rendering\n6. **IChart Interface**: Uniform chart rendering at (0,0) with canvas transforms\n7. **Time-based Rendering**: Charts render based on timestamps, not data points\n8. **Smooth Interpolation**: Left/right edge clipping with interpolated boundaries\n9. **Dynamic Scaling**: Automatic min/max calculation with 10% padding\n10. **Multi-collector Architecture**: Parallel collection of different metric types\n\n## Key Features\n\n### Docker Container Monitoring\n- Real-time container metrics (CPU %, memory usage)\n- Double-bar visualization: memory bar with CPU overlay\n- Min/Max RAM tracking per container with dotted lines\n- Dynamic scaling based on system RAM\n- Container name truncation for compact display\n\n### Time-Series Charts\n- Timestamp-based rendering (independent of data point count)\n- Smooth left/right edge clipping with interpolation\n- Dynamic Y-axis scaling with configurable ranges\n- Fill gradients under line graphs\n- Configurable time windows (default 60 seconds)\n\n### Network Monitoring\n- Multi-interface support (configurable)\n- RX/TX bytes per second tracking\n- Delta calculation for accurate throughput\n\n### GPU Monitoring\n- Multi-GPU support via NVIDIA nvidia-smi\n- Per-GPU load percentage\n- Temperature and memory tracking\n\n## Testing\n\nRun tests:\n```bash\ndotnet test\n```\n\n## Configuration\n\nConfigure monitoring in `appsettings.json` or `appsettings.{environment}.json`:\n\n### MonitorSettings\n\n```json\n{\n  \"MonitorSettings\": {\n    \"NetworkInterface\": \"eth0\",\n    \"DiskDevice\": \"sda\",\n    \"CollectionIntervalMs\": 500,\n    \"DataPointsToKeep\": 120,\n    \"GpuCollectorType\": \"NvSmi\",\n    \"Layout\": [\n      [ \"CPU/16\", \"GPU/1\", \"Docker\", \"ComputeLoad/3|col-span:2\" ],\n      [ \"Network:eth0/2\", \"Disk:sda/2\" ]\n    ]\n  }\n}\n```\n\n### Configuration Options\n\n- **NetworkInterface**: Network interface to monitor (e.g., `eth0`, `ether4`)\n- **DiskDevice**: Disk device to monitor (e.g., `sda`, `mmcblk0`)\n- **CollectionIntervalMs**: Metrics collection interval in milliseconds (default: 500)\n- **DataPointsToKeep**: Number of data points to retain in rolling window (default: 120)\n- **GpuCollectorType**: GPU collector implementation\n  - `NvSmi`: Standard NVIDIA GPU monitoring via nvidia-smi\n  - `NvTegra`: NVIDIA Jetson Tegra monitoring via tegrastats\n- **Layout**: Grid layout configuration (see Layout Syntax below)\n\n### Layout Syntax\n\nThe Layout property defines how charts are arranged in a responsive grid. Each row is an array of chart specifications.\n\n**Chart Specification Format:**\n```\nChartType[:Identifier]/Count[|col-span:N]\n```\n\n**Components:**\n- `ChartType`: Type of chart (CPU, GPU, RAM, Network, Disk, Docker, ComputeLoad, Temperature)\n- `:Identifier`: Optional identifier for the specific instance (e.g., network interface name, disk device)\n- `/Count`: Number of data points for this metric (e.g., 16 CPU cores, 2 GPUs)\n- `|col-span:N`: Optional column span for proportional width (default: 1, range: 1-12)\n\n**Examples:**\n- `\"CPU/8\"` - CPU chart with 8 cores, spans 1 column\n- `\"Network:eth0/2\"` - Network chart for eth0 interface with 2 data points (RX/TX)\n- `\"Disk:sda/2\"` - Disk chart for sda device with 2 data points (read/write)\n- `\"ComputeLoad/3|col-span:2\"` - Compute load chart with 3 data points, spans 2 columns\n- `\"Temperature/9|col-span:5\"` - Temperature chart with 9 sensors, spans 5 columns\n\n**Layout Calculation:**\n- Each row's total width = sum of all col-span values in that row\n- Chart proportional width = col-span / total row width\n- Example: `[\"CPU/8\", \"Docker\", \"ComputeLoad/3|col-span:2\"]`\n  - Total: 1 + 1 + 2 = 4\n  - Widths: CPU=1/4 (25%), Docker=1/4 (25%), ComputeLoad=2/4 (50%)\n\n### Example: NVIDIA Jetson Tegra Configuration\n\n```json\n{\n  \"MonitorSettings\": {\n    \"NetworkInterface\": \"ether4\",\n    \"DiskDevice\": \"mmcblk0\",\n    \"CollectionIntervalMs\": 500,\n    \"DataPointsToKeep\": 120,\n    \"GpuCollectorType\": \"NvTegra\",\n    \"Layout\": [\n      [ \"CPU/8\", \"Docker\", \"ComputeLoad/3|col-span:2\" ],\n      [ \"Network:ether4/2\", \"Disk:mmcblk0/2\" ],\n      [ \"Temperature/9|col-span:5\" ]\n    ]\n  }\n}\n```\n\n### Example: Standard x86 Configuration\n\n```json\n{\n  \"MonitorSettings\": {\n    \"NetworkInterface\": \"eth0\",\n    \"DiskDevice\": \"sda\",\n    \"CollectionIntervalMs\": 500,\n    \"DataPointsToKeep\": 120,\n    \"GpuCollectorType\": \"NvSmi\",\n    \"Layout\": [\n      [ \"CPU/16\", \"GPU/1\", \"Docker\", \"ComputeLoad/3|col-span:2\" ],\n      [ \"Network:eth0/2\", \"Disk:sda/2\" ]\n    ]\n  }\n}\n```\n\n## Publishing NuGet Packages\n\nThe project is set up to automatically publish NuGet packages to NuGet.org via GitHub Actions.\n\n### Quick Release\n\nUse the provided release script:\n\n```bash\n./release.sh 1.0.0\n```\n\nThis will:\n1. Create a git tag `perfmon/1.0.0`\n2. Push the tag to GitHub\n3. Trigger automatic NuGet package publishing\n\n### Manual Release\n\nAlternatively, create and push a tag manually:\n\n```bash\ngit tag perfmon/1.0.0\ngit push origin perfmon/1.0.0\n```\n\n### Published Packages\n\n- **ModelingEvolution.PerformanceMonitor.Shared** - Shared models and DTOs\n- **ModelingEvolution.PerformanceMonitor.Server** - Server-side metrics collection\n- **ModelingEvolution.PerformanceMonitor.Client** - Blazor WASM client with SkiaSharp rendering\n\n## License\n\nSee SPEC.md for detailed implementation specification.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmodelingevolution%2Fblazor-perfmon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmodelingevolution%2Fblazor-perfmon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmodelingevolution%2Fblazor-perfmon/lists"}