Restructure repo (#251)
* refactor: restructure src/ into modules/, scripts/, and build/ - src/nag_screen/ and src/node_info/ -> src/modules/ (mods grouped explicitly) - src/Scripts/ -> src/scripts/ (lowercase, consistent) - src/gen-rules.sh -> build/ (build tool separated from source) Update all references: debian/rules, .github/workflows/*, build/gen-rules.sh, src/scripts/test/test-syntax.sh (SRC_DIR now points to src/modules/), src/scripts/test/test-patches.sh, and files.list comments. * refactor: move CI test scripts from src/scripts/test/ to build/test/ Test scripts are not installed — they are CI/dev tooling and belong alongside build/gen-rules.sh. Update workflow references and fix the SRC_DIR path depth in build/test/test-syntax.sh (../ -> ../..). * d --------- Co-authored-by: Meliox <na>
This commit is contained in:
1 parent
3db6a010df
commit
6585849459
44 files changed
+342
-30
No files matched your search
@@ -0,0 +1,226 @@
|
||||
package PVE::PVEMod::Collector::Intel;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Exporter 'import';
|
||||
|
||||
use PVE::PVEMod::Config qw(%config $process_type $pve_mod_working_dir);
|
||||
use PVE::PVEMod::Utils qw(debug check_executable setup_collector_signals safe_write_json);
|
||||
use PVE::PVEMod::Store qw(update_intel_gpu_rrd);
|
||||
|
||||
our @EXPORT_OK = qw(
|
||||
get_intel_gpu_devices
|
||||
collector_for_intel_device
|
||||
);
|
||||
|
||||
# ============================================================================
|
||||
# Intel GPU — device discovery
|
||||
# ============================================================================
|
||||
|
||||
sub get_intel_gpu_devices {
|
||||
my @devices = ();
|
||||
my $fh;
|
||||
|
||||
# Parse: "card0 Intel Alderlake_n (Gen12) pci:vendor=8086,device=46D0,card=0"
|
||||
# or: "card0 Intel Alderlake_n (Gen12) pci:0000:00:02.0"
|
||||
|
||||
if ($config{debug}{intel_mode} && -f $config{debug}{intel_devices_file}) {
|
||||
my $file = $config{debug}{intel_devices_file};
|
||||
debug(__LINE__, "Debug mode: reading Intel GPU devices from $file");
|
||||
unless (open $fh, '<', $file) {
|
||||
debug(__LINE__, "Failed to open debug file $file: $!");
|
||||
return @devices;
|
||||
}
|
||||
} else {
|
||||
debug(__LINE__, "Getting Intel GPU devices");
|
||||
unless (open $fh, '-|', 'intel_gpu_top -L') {
|
||||
debug(__LINE__, "Failed to run intel_gpu_top -L: $!");
|
||||
return @devices;
|
||||
}
|
||||
}
|
||||
|
||||
while (<$fh>) {
|
||||
chomp;
|
||||
if (/^(card\d+)\s+(.+?)\s+(pci:[^\s]+)/) {
|
||||
my ($card, $name, $path) = ($1, $2, $3);
|
||||
push @devices, {
|
||||
card => $card,
|
||||
name => $name,
|
||||
path => $path,
|
||||
drm_path => "/dev/dri/$card",
|
||||
};
|
||||
debug(__LINE__, "Found Intel device: $card -> $name ($path)");
|
||||
}
|
||||
}
|
||||
close $fh;
|
||||
|
||||
return @devices;
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Intel GPU — data parsing
|
||||
# ============================================================================
|
||||
|
||||
sub _parse_intel_gpu_line {
|
||||
my ($line) = @_;
|
||||
|
||||
# Expected format (whitespace-aligned columns):
|
||||
# Freq MHz IRQ RC6 Power W RCS BCS VCS VECS
|
||||
# req act /s % gpu pkg % se wa % se wa % se wa % se wa
|
||||
# 0 0 0 0 0.00 7.47 0.00 0 0 0.00 0 0 0.00 0 0 0.00 0 0
|
||||
|
||||
$line =~ s/^\s+|\s+$//g;
|
||||
my @values = grep { $_ ne '' } split(/\s+/, $line);
|
||||
|
||||
return unless @values >= 18;
|
||||
|
||||
return {
|
||||
frequency => {
|
||||
requested => $values[0] + 0.0,
|
||||
actual => $values[1] + 0.0,
|
||||
unit => "MHz",
|
||||
},
|
||||
interrupts => {
|
||||
count => $values[2] + 0.0,
|
||||
unit => "irq/s",
|
||||
},
|
||||
rc6 => {
|
||||
value => $values[3] + 0.0,
|
||||
unit => "%",
|
||||
},
|
||||
power => {
|
||||
GPU => $values[4] + 0.0,
|
||||
Package => $values[5] + 0.0,
|
||||
unit => "W",
|
||||
},
|
||||
engines => {
|
||||
'Render/3D' => {
|
||||
busy => $values[6] + 0.0,
|
||||
sema => $values[7] + 0.0,
|
||||
wait => $values[8] + 0.0,
|
||||
unit => "%",
|
||||
},
|
||||
Blitter => {
|
||||
busy => $values[9] + 0.0,
|
||||
sema => $values[10] + 0.0,
|
||||
wait => $values[11] + 0.0,
|
||||
unit => "%",
|
||||
},
|
||||
Video => {
|
||||
busy => $values[12] + 0.0,
|
||||
sema => $values[13] + 0.0,
|
||||
wait => $values[14] + 0.0,
|
||||
unit => "%",
|
||||
},
|
||||
VideoEnhance => {
|
||||
busy => $values[15] + 0.0,
|
||||
sema => $values[16] + 0.0,
|
||||
wait => $values[17] + 0.0,
|
||||
unit => "%",
|
||||
},
|
||||
},
|
||||
clients => {},
|
||||
};
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Intel GPU — long-running collector
|
||||
# ============================================================================
|
||||
|
||||
sub collector_for_intel_device {
|
||||
my ($device) = @_;
|
||||
$process_type = 'collector';
|
||||
$0 = "collector-gpu-intel-$device->{card}";
|
||||
|
||||
my $drm_dev = "drm:/dev/dri/$device->{card}";
|
||||
my $intel_gpu_top_pid = undef;
|
||||
my $device_state_file = "$pve_mod_working_dir/stats-$device->{card}.json";
|
||||
|
||||
debug(__LINE__, "Collector started for device: $drm_dev, writing to $device_state_file");
|
||||
|
||||
my $shutdown = 0;
|
||||
setup_collector_signals($device->{card}, \$shutdown, sub {
|
||||
kill 'TERM', $intel_gpu_top_pid
|
||||
if defined $intel_gpu_top_pid && $intel_gpu_top_pid > 0;
|
||||
});
|
||||
|
||||
my $node_name = "node0";
|
||||
|
||||
if ($config{debug}{intel_mode} && -f $config{debug}{intel_output_file}) {
|
||||
debug(__LINE__, "Debug mode: reading Intel GPU stats from $config{debug}{intel_output_file}");
|
||||
while (!$shutdown) {
|
||||
if (open my $fh, '<', $config{debug}{intel_output_file}) {
|
||||
while (my $line = <$fh>) {
|
||||
chomp $line;
|
||||
next if $line =~ /MHz|IRQ|RC6|Power|RCS|BCS|VCS|VECS|req\s+act|^\s*$/;
|
||||
|
||||
if ($line =~ /^\s*[\d\s\.]+$/) {
|
||||
my $stats = _parse_intel_gpu_line($line);
|
||||
|
||||
if ($stats) {
|
||||
my $device_data = {
|
||||
$node_name => {
|
||||
name => $device->{name},
|
||||
device_path => $device->{path},
|
||||
drm_path => $device->{drm_path},
|
||||
stats => $stats,
|
||||
}
|
||||
};
|
||||
|
||||
safe_write_json($device_state_file, $device_data);
|
||||
update_intel_gpu_rrd($device->{card}, $stats);
|
||||
}
|
||||
}
|
||||
}
|
||||
close $fh;
|
||||
} else {
|
||||
debug(__LINE__, "Failed to open debug file $config{debug}{intel_output_file}: $!");
|
||||
}
|
||||
sleep $config{intervals}{data_pull} unless $shutdown;
|
||||
}
|
||||
} else {
|
||||
debug(__LINE__, "About to open pipe to intel_gpu_top");
|
||||
my $intel_pull_interval = $config{intervals}{data_pull} * 1000; # milliseconds
|
||||
$intel_gpu_top_pid = open(my $fh, '-|',
|
||||
"intel_gpu_top -d $drm_dev -s $intel_pull_interval -l 2>&1");
|
||||
|
||||
unless (defined $intel_gpu_top_pid && $intel_gpu_top_pid > 0) {
|
||||
debug(__LINE__, "Failed to run intel_gpu_top for $drm_dev: $!");
|
||||
exit 1;
|
||||
}
|
||||
|
||||
debug(__LINE__, "Pipe opened successfully, PID=$intel_gpu_top_pid");
|
||||
|
||||
while (my $line = <$fh>) {
|
||||
last if $shutdown;
|
||||
chomp $line;
|
||||
|
||||
next if $line =~ /MHz|IRQ|RC6|Power|RCS|BCS|VCS|VECS|req\s+act|^\s*$/;
|
||||
|
||||
if ($line =~ /^\s*[\d\s\.]+$/) {
|
||||
my $stats = _parse_intel_gpu_line($line);
|
||||
|
||||
if ($stats) {
|
||||
my $device_data = {
|
||||
$node_name => {
|
||||
name => $device->{name},
|
||||
device_path => $device->{path},
|
||||
drm_path => $device->{drm_path},
|
||||
stats => $stats,
|
||||
}
|
||||
};
|
||||
|
||||
safe_write_json($device_state_file, $device_data);
|
||||
update_intel_gpu_rrd($device->{card}, $stats);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close $fh;
|
||||
}
|
||||
|
||||
debug(__LINE__, "Collector for $device->{card} shutting down");
|
||||
exit 0;
|
||||
}
|
||||
|
||||
1;
|
||||
Reference in new issue
Block a user