diff options
Diffstat (limited to 'inxi')
| -rwxr-xr-x | inxi | 977 |
1 files changed, 686 insertions, 291 deletions
@@ -48,8 +48,8 @@ use POSIX qw(ceil uname strftime ttyname); ## INXI INFO ## my $self_name='inxi'; -my $self_version='3.3.21'; -my $self_date='2022-08-22'; +my $self_version='3.3.22'; +my $self_date='2022-10-08'; my $self_patch='00'; ## END INXI INFO ## @@ -1938,6 +1938,7 @@ sub display_data { ['weston','--version'], ['wlr-randr',''], ['xdpyinfo',''], + ['xdriinfo',''], ['Xorg','-version'], ['xprop','-root'], ['xrandr',''], @@ -2945,11 +2946,11 @@ sub check_items { } elsif ($type eq 'recommended display information programs'){ if ($bsd_type){ - @data = qw(glxinfo wmctrl xdpyinfo xprop xrandr); + @data = qw(glxinfo wmctrl xdpyinfo xprop xdriinfo xrandr); $info_os = 'info-bsd'; } else { - @data = qw(glxinfo wmctrl xdpyinfo xprop xrandr); + @data = qw(glxinfo wmctrl xdpyinfo xprop xdriinfo xrandr); } $b_program = 1; $item = 'Program'; @@ -3007,7 +3008,7 @@ sub check_items { } else { @data = qw(/dev /dev/disk/by-id /dev/disk/by-label /dev/disk/by-path - /dev/disk/by-uuid /sys/class/dmi/id); + /dev/disk/by-uuid /sys/class/dmi/id /sys/class/hwmon); } $b_dir = 1; $item = 'Directory'; @@ -3089,9 +3090,6 @@ sub item_data { my ($type) = @_; my $data = { # Directory Data - '/sys/class/dmi/id' => { - 'info' => '-M system, motherboard, bios', - }, '/dev' => { 'info' => '-l,-u,-o,-p,-P,-D disk partition data', }, @@ -3113,6 +3111,12 @@ sub item_data { '/sys' => { 'info' => '', }, + '/sys/class/dmi/id' => { + 'info' => '-M system, motherboard, bios', + }, + '/sys/class/hwmon' => { + 'info' => '-s sensor data (fallback if no lm-sensors)', + }, # File Data '/etc/lsb-release' => { 'info' => '-S distro version data (older version)', @@ -3377,7 +3381,7 @@ sub item_data { 'rpm' => 'systemd or sysvinit', }, 'sensors' => { - 'info' => '-s sensors output', + 'info' => '-s sensors output (optional, /sys supplies most)', 'info-bsd' => '', 'apt' => 'lm-sensors', 'pacman' => 'lm-sensors', @@ -3475,6 +3479,13 @@ sub item_data { 'pacman' => 'xorg-xdpyinfo', 'rpm' => 'xorg-x11-utils (SUSE/Fedora?: xdpyinfo)', }, + 'xdriinfo' => { + 'info' => '-G (X) DRI driver (if missing, fallback to Xorg log)', + 'info-bsd' => '-G (X) DRI driver (if missing, fallback to Xorg log', + 'apt' => 'X11-utils', + 'pacman' => 'xorg-xdriinfo', + 'rpm' => 'xorg-x11-utils (SUSE/Fedora?: xdriinfo)', + }, 'xprop' => { 'info' => '-S (X) desktop data', 'info-bsd' => '-S (X) desktop data', @@ -5194,7 +5205,7 @@ sub get { if ($arg){ my $wl = 'bluetooth|compiler|cpu|dboot|dmidecode|elbrus|ipmi|logical|lspci|'; $wl .= 'partitions|pciconf|pcictl|pcidump|raid-btrfs|raid-hw|raid-lvm|'; - $wl .= 'raid-md|raid-soft|raid-zfs|sensors|swaymsg|sysctl|'; + $wl .= 'raid-md|raid-soft|raid-zfs|sensors|sensors-sys|swaymsg|sysctl|'; $wl .= 'uptime|usbconfig|usbdevs|vmstat|wl-info|wlr-randr|xorg-log|xrandr'; for (split(',',$arg)){ if ($_ =~ /\b($wl)\b/){ @@ -5220,7 +5231,7 @@ sub get { my ($opt,$arg) = @_; if ($arg){ my $wl = 'colors|cpuinfo|display|dmidecode|hddtemp|lsusb|man|meminfo|'; - $wl .= 'no-dig|no-doas|no-html-wan|no-sudo|pkg|rpm||usb-sys|'; + $wl .= 'no-dig|no-doas|no-html-wan|no-sudo|pkg|rpm|sensors-sys|usb-sys|'; $wl .= 'vmstat|wayland|wmctrl'; for (split(',',$arg)){ if ($_ =~ /\b($wl)\b/){ @@ -5340,6 +5351,8 @@ sub get { else { main::error_handler('bad-arg',$opt,$arg); }}, + 'sensors-sys' => sub { + $force{'sensors-sys'} = 1;}, 'sensors-use:s' => sub { my ($opt,$arg) = @_; if ($arg){ @@ -5790,7 +5803,8 @@ sub show_options { LMP version."], ['2', '-G', '', "GPU arch (AMD/Intel/Nvidia only); Specific vendor/product information (if relevant); PCI/USB ID of device; Direct rendering status - (in X); Screen number GPU is running on (Nvidia only)."], + (in X); Screen number GPU is running on (Nvidia only); device temp (Linux, + if found)."], ['2', '-i', '', "For IPv6, show additional scope addresses: Global, Site, Temporary, Unknown. See --limit for large counts of IP addresses."], ['2', '-I', '', "Default system GCC. With -xx, also shows other installed @@ -5802,7 +5816,8 @@ sub show_options { ['2', '-L', '', "For VG > LV, and other Devices, dm:"], ['2', '-m,--memory-modules', '', "Max memory module size (if available)."], ['2', '-N', '', "Specific vendor/product information (if relevant); - PCI/USB ID of device; Version/port(s)/driver version (if available)."], + PCI/USB ID of device; Version/port(s)/driver version (if available); device + temperature (Linux, if found)."], ['2', '-o,-p,-P', '', "Add mapped: name if partition mapped."], ['2', '-r', '', "Packages, see -Ix."], ['2', '-R', '', "md-raid: second RAID Info line with extra data: @@ -5828,7 +5843,6 @@ sub show_options { ['2', '-A', '', "Chip vendor:product ID for each audio device; PCIe speed, lanes (if found)."], ['2', '-B', '', "Serial number."], - ['2', '-C', '', "Add microarchitecture level."], ['2', '-D', '', "Disk transfer speed; NVMe lanes; Disk serial number; LVM volume group free space (if available); disk duid (some BSDs)."], ['2', '-E', '', "Chip vendor:product ID, LMP subversion; PCIe speed, lanes @@ -5911,11 +5925,12 @@ sub show_options { also sets --extra=3:"], ['2', '-A', '', "If available: list of alternate kernel modules/drivers for device(s); PCIe lanes-max: gen, speed, lanes (if relevant)."], - ['2', '-C', '', "If available: CPU generation, process node, built years; CPU - socket type, base/boost speeds (dmidecode+root/sudo/doas required); Full - topology line, with cores, threads, threads per core, granular cache data, - smt status; CPU vulnerabilities (bugs); family, model-id, stepping - format: - hex (decimal) if greater than 9; microcode format: hex."], + ['2', '-C', '', "If available: microarchitecture level (64 bit AMD/Intel + only).CPU generation, process node, built years; CPU socket type, base/boost + speeds (dmidecode+root/sudo/doas required); Full topology line, with cores, + threads, threads per core, granular cache data, smt status; CPU + vulnerabilities (bugs); family, model-id, stepping - format: hex (decimal) + if greater than 9; microcode format: hex."], ['2', '-d,-D', '', "If available: logical and physical block sizes; drive family; maj:min, USB drive specifics; SMART report."], ['2', '-E', '', "If available: in Report:, adds Info: line: acl-mtu, @@ -6023,9 +6038,9 @@ sub show_options { ['1', '', '--sensors-default', "Removes configuration item SENSORS_USE and SENSORS_EXCLUDE. Same as default behavior."], ['1', '', '--sensors-exclude', "[sensor[s] name, comma separated] Exclude - supplied sensor array[s] for -s output (lm-sensors, Linux only)."], + supplied sensor array[s] for -s output (lm-sensors, /sys. Linux only)."], ['1', '', '--sensors-use', "[sensor[s] name, comma separated] Use only - supplied sensor array[s] for -s output (lm-sensors, Linux only)."], + supplied sensor array[s] for -s output (lm-sensors, /sys. Linux only)."], ['1', '', '--sleep', "[0-x.x] Change CPU sleep time, in seconds, for -C (default:^$cpu_sleep). Allows system to catch up and show a more accurate CPU use. Example:^$self_name^-Cxxx^--sleep^0.15"], @@ -6787,6 +6802,7 @@ sub message { 'monitor-wayland' => 'no compositor data', 'note-check' => 'check', 'note-est' => 'est.', + 'note-not-reliable' => 'not reliable', 'nv-current' => "current (as of $id)", 'nv-legacy-active' => "legacy-active (EOL~$id)", 'nv-legacy-eol' => 'legacy (EOL)', @@ -6818,11 +6834,15 @@ sub message { 'root-suggested' => 'try sudo/root',# gdm only 'screen-wayland' => 'no compositor data', 'screen-xvesa' => 'no Xvesa data', - 'sensors-data-bsd' => "$id sensor data found but not usable.", - 'sensors-data-bsd-ok' => 'No sensor data found. Are sensors present?', - 'sensors-data-ipmi' => 'No ipmi sensor data found.', - 'sensors-data-linux' => 'No sensor data found. Is lm-sensors configured?', - 'sensors-ipmi-root' => 'Unable to run ipmi sensors. Root privileges required.', + 'sensor-data-bsd' => "$id sensor data found but not usable.", + 'sensor-data-bsd-ok' => 'No sensor data found. Are data sources present?', + 'sensor-data-bsd-unsupported' => 'Sensor data not available. Unsupported BSD variant.', + 'sensor-data-ipmi' => 'No ipmi sensor data found.', + 'sensor-data-ipmi-root' => 'Unable to run ipmi sensors. Root privileges required.', + 'sensors-data-linux' => 'No sensor data found. Missing /sys/class/hwmon, lm-sensors.', + 'sensor-data-lm-sensors' => 'No sensor data found. Is lm-sensors configured?', + 'sensor-data-sys' => 'No sensor data found in /sys/class/hwmon.', + 'sensor-data-sys-lm' => 'No sensor data found using /sys/class/hwmon or lm-sensors.', 'smartctl-command' => 'A mandatory SMART command failed. Various possible causes.', 'smartctl-open' => 'Unable to open device. Wrong device ID given?', 'smartctl-udma-crc' => 'Bad cable/connection?', @@ -7575,21 +7595,21 @@ sub sound_server_output { my ($program); my ($j,$num) = (0,0); foreach my $server (@{sound_server_data()}){ - next if $extra < 1 && (!$server->[2] || $server->[2] ne 'yes'); + next if $extra < 1 && (!$server->[3] || $server->[3] ne 'yes'); $j = scalar @$rows; - $server->[1] ||= 'N/A'; $server->[2] ||= 'N/A'; + $server->[3] ||= 'N/A'; push(@$rows, { - main::key($num++,1,1,'Sound Server') => $server->[0], - main::key($num++,0,2,'v') => $server->[1], - main::key($num++,0,2,'running') => $server->[2], + main::key($num++,1,1,$server->[0]) => $server->[1], + main::key($num++,0,2,'v') => $server->[2], + main::key($num++,0,2,'running') => $server->[3], }); } eval $end if $b_log; } sub sound_server_data { eval $start if $b_log; - my ($program,$running,$server,$version); + my ($program,$running,$server,$type,$version); my $servers = []; if (my $file = $system_files{'asound-version'}){ # avoid possible second line if compiled by user @@ -7598,55 +7618,61 @@ sub sound_server_data { $version = (split(/\s+/, $content))[-1]; $version =~ s/\.$//; # trim off period $server = 'ALSA'; + $type = 'Sound API'; $running = 'yes'; # not needed I think, if asound is there, it's running, but if that's # not correct, can use one of the info/list/stat tests for aplay # if (main::check_program('aplay') && main::grabber('aplay -l 2>/dev/null')){ # $running = 'yes'; # } - push(@$servers, [$server,$version,$running]); - ($running,$server,$version) = ('','',''); + push(@$servers, [$type,$server,$version,$running]); + ($running,$version) = ('',''); } # sndstat file may be removed in linux oss if (-e '/dev/sndstat' || ($program = main::check_program('ossinfo'))){ $server = 'OSS'; + $type = 'Sound API'; #$version = main::program_version('oss','\S',2); $version = (grep {/^hw.snd.version:/} @{$sysctl{'audio'}})[0] if $sysctl{'audio'}; $version = (split(/:\s*/,$version),1)[1] if $version; $version =~ s|/.*$|| if $version; # not a great test, but ok for now $running = (-e '/dev/sndstat') ? 'yes' : 'no?'; - push(@$servers, [$server,$version,$running]); - ($running,$server,$version) = ('','',''); + push(@$servers, [$type,$server,$version,$running]); + ($running,$version) = ('',''); } if ($program = main::check_program('sndiod')){ $server = 'sndio'; + $type = 'Sound Interface'; #$version = main::program_version('sndio','\S',2); $running = (grep {/sndiod/} @ps_cmd) ? 'yes': 'no'; - push(@$servers, [$server,$version,$running]); - ($running,$server,$version) = ('','',''); + push(@$servers, [$type,$server,$version,$running]); + ($running,$version) = ('',''); } if ($program = main::check_program('jackd')){ $server = 'JACK'; + $type = 'Sound Server'; $version = main::program_version($program,'^jackd',3,'--version',1); $running = (grep {/jackd/} @ps_cmd) ? 'yes':'no' ; - push(@$servers, [$server,$version,$running]); - ($running,$server,$version) = ('','',''); + push(@$servers, [$type,$server,$version,$running]); + ($running,$version) = ('',''); } # note: pactl info/list/stat could be used if ($program = main::check_program('pactl')){ $server = 'PulseAudio'; + $type = 'Sound Server'; $version = main::program_version($program,'^pactl',2,'--version',1); $running = (grep {m|/pulseaudiod?\b|} @ps_cmd) ? 'yes':'no' ; - push(@$servers, [$server,$version,$running]); - ($running,$server,$version) = ('','',''); + push(@$servers, [$type,$server,$version,$running]); + ($running,$version) = ('',''); } if ($program = main::check_program('pipewire')){ $server = 'PipeWire'; + $type = 'Sound Server'; $version = main::program_version($program,'^Compiled with libpipe',4,'--version',1); $running = (grep {/pipewire/} @ps_cmd) ? 'yes':'no' ; - push(@$servers, [$server,$version,$running]); - ($running,$server,$version) = ('','',''); + push(@$servers, [$type,$server,$version,$running]); + ($running,$version) = ('',''); } main::log_data('dump','sound servers: @$servers',$servers) if $b_log; print Data::Dumper::Dumper $servers if $dbg[26]; @@ -8744,8 +8770,11 @@ sub full_output { if ($b_admin && $cpu->{'gen'}){ $rows->[$j]{main::key($num++,0,3,'gen')} = $cpu->{'gen'}; } - if ($extra > 1 && $properties->{'arch-level'}){ - $rows->[$j]{main::key($num++,0,2,'level')} = $properties->{'arch-level'}; + if ($b_admin && $properties->{'arch-level'}){ + $rows->[$j]{main::key($num++,1,2,'level')} = $properties->{'arch-level'}[0]; + if ($properties->{'arch-level'}[1]){ + $rows->[$j]{main::key($num++,0,3,'note')} = $properties->{'arch-level'}[1]; + } } if ($b_admin){ if ($cpu->{'year'}){ @@ -10291,7 +10320,7 @@ sub cpu_properties { $bits_sys = ($cpu->{'flags'} =~ /\blm\b/) ? 64 : 32; } # must run after to make sure we have cpu bits - if (!%risc && $bits_sys && $bits_sys == 64 && $cpu->{'flags'}){ + if ($b_admin && !%risc && $bits_sys && $bits_sys == 64 && $cpu->{'flags'}){ $arch_level = cp_cpu_level( $cpu->{'flags'} ); @@ -10999,7 +11028,7 @@ sub cp_cpu_arch { $process = 'GF 12nm'; $year = '2018-21';} # used this but it didn't age well: ^(2[0123456789ABCDEF]| - elsif ($model =~ /^(31|47|60|68|71|90)$/){ + elsif ($model =~ /^(31|47|60|68|71|90|98|A.)$/){ $arch = 'Zen 2'; $gen = '3'; $process = 'TSMC n7 (7nm)'; # some consumer maybe GF 14nm @@ -11020,19 +11049,19 @@ sub cp_cpu_arch { elsif ($family eq '19'){ # ext model 6,7, but no base models yet # 10 engineering sample - if ($model =~ /^(10|[67][0-9A-F])$/){ + if ($model =~ /^(1.|6.|7.|A.)$/){ $arch = 'Zen 4'; $gen = '5'; $process = 'TSMC n5 (5nm)'; $year = '2022';} # double check 40, 44 - elsif ($model =~ /^(40|44)$/){ + elsif ($model =~ /^(4.)$/){ $arch = 'Zen 3+'; $gen = '4'; $process = 'TSMC n6 (7nm)'; $year = '2022';} - # 21, 50: step 0; - elsif ($model =~ /^(0|1|8|21|50)$/){ + # 21, 50: step 0; known: 21, 3x, 50 + elsif ($model =~ /^(0|1|8|2.|3.|5.)$/){ $arch = 'Zen 3'; $gen = '4'; $process = 'TSMC n7 (7nm)'; @@ -11094,72 +11123,73 @@ sub cp_cpu_arch { } } # note, to test uncoment $cpu{'type'} = Elbrus in proc/cpuinfo logic + # ExpLicit Basic Resources Utilization Scheduling elsif ($type eq 'elbrus'){ # E8CB if ($family eq '4'){ if ($model eq '1'){ - $arch = 'Elbrus'; - $process = ''; - $year = '';} + $arch = 'Elbrus 2000 (gen-1)'; + $process = 'Mikron 130nm'; + $year = '2005';} elsif ($model eq '2'){ - $arch = 'Elbrus-S'; - $process = ''; - $year = '';} + $arch = 'Elbrus-S (gen-2)'; + $process = 'Mikron 90nm'; + $year = '2010';} elsif ($model eq '3'){ - $arch = 'Elbrus-4C'; - $process = '65nm'; - $year = '';} + $arch = 'Elbrus-4C (gen-3)'; + $process = 'TSMC 65nm'; + $year = '2014';} elsif ($model eq '4'){ - $arch = 'Elbrus-2C+'; - $process = '90nm'; - $year = '';} + $arch = 'Elbrus-2C+ (gen-2)'; + $process = 'Mikron 90nm'; + $year = '2011';} elsif ($model eq '6'){ - $arch = 'Elbrus-2CM'; - $process = '90nm'; - $year = '';} + $arch = 'Elbrus-2CM (gen-2)'; + $note = $check; + $process = 'Mikron 90nm'; + $year = '2011 (?)';} elsif ($model eq '7'){ if ($stepping >= 2){ - $arch = 'Elbrus-8C1'; - $process = '28nm'; - $year = '';} + $arch = 'Elbrus-8C1 (gen-4)'; + $process = 'TSMC 28nm'; + $year = '2016';} else { - $arch = 'Elbrus-8C'; - $process = '28nm'; - $year = '';} + $arch = 'Elbrus-8C (gen-4)'; + $process = 'TSMC 28nm'; + $year = '2016';} } # note: stepping > 1 may be 8C1 elsif ($model eq '8'){ - $arch = 'Elbrus-1C+'; + $arch = 'Elbrus-1C+ (gen-4)'; $process = 'TSMC 40nm'; - $year = '';} + $year = '2016';} # 8C2 morphed out of E8CV, but the two were the same die elsif ($model eq '9'){ - $arch = 'Elbrus-8CV/8C2'; + $arch = 'Elbrus-8CV/8C2 (gen-4/5)'; $process = 'TSMC 28nm'; $note = $check; - $year = '';} + $year = '2016/2020';} elsif ($model eq 'A'){ - $arch = 'Elbrus-12C'; - $process = 'TSMC 16nm'; # guess - $year = '';} + $arch = 'Elbrus-12C (gen-6)'; + $process = 'TSMC 16nm'; + $year = '2021+';} elsif ($model eq 'B'){ - $arch = 'Elbrus-16C'; + $arch = 'Elbrus-16C (gen-6)'; $process = 'TSMC 16nm'; - $year = '';} + $year = '2021+';} elsif ($model eq 'C'){ - $arch = 'Elbrus-2C3'; + $arch = 'Elbrus-2C3 (gen-6)'; $process = 'TSMC 16nm'; - $year = '';} + $year = '2021+';} else { $arch = 'Elbrus-??';; - $year = ''; $note = $check; $year = '';} } elsif ($family eq '5'){ if ($model eq '9'){ - $arch = 'Elbrus-8C2'; + $arch = 'Elbrus-8C2 (gen-4)'; $process = 'TSMC 28nm'; - $year = '';} + $year = '2020';} else { $arch = 'Elbrus-??'; $note = $check; @@ -11168,17 +11198,21 @@ sub cp_cpu_arch { } elsif ($family eq '6'){ if ($model eq 'A'){ - $arch = 'Elbrus-12C'; - $process = 'TSMC 16nm'; # guess - $year = '';} + $arch = 'Elbrus-12C (gen-6)'; + $process = 'TSMC 16nm'; + $year = '2021+';} elsif ($model eq 'B'){ - $arch = 'Elbrus-16C'; + $arch = 'Elbrus-16C (gen-6)'; $process = 'TSMC 16nm'; - $year = '';} + $year = '2021+';} elsif ($model eq 'C'){ - $arch = 'Elbrus-2C3'; + $arch = 'Elbrus-2C3 (gen-6)'; $process = 'TSMC 16nm'; - $year = '';} + $year = '2021+';} + # elsif ($model eq '??'){ + # $arch = 'Elbrus-32C (gen-7)'; + # $process = '?? 7nm'; + # $year = '2025';} else { $arch = 'Elbrus-??'; $note = $check; @@ -11302,10 +11336,6 @@ sub cp_cpu_arch { $arch = 'M Tolapai'; # pentium M system on chip $process = 'Intel 90nm'; $year = '2008';} - elsif ($model =~ /^(1D)$/){ - $arch = 'Penryn'; - $process = 'Intel 45nm'; - $year = '2007-08';} elsif ($model =~ /^(17)$/){ $arch = 'Penryn'; # 17:A:Core 2,Celeron-wolfdale,yorkfield $process = 'Intel 45nm'; @@ -11319,6 +11349,10 @@ sub cp_cpu_arch { $arch = 'Bonnell'; $process = 'Intel 45nm'; $year = '2008-13';} # atom Bonnell? 27? + elsif ($model =~ /^(1D)$/){ + $arch = 'Penryn'; + $process = 'Intel 45nm'; + $year = '2007-08';} # 25 may be nahelem in a stepping, check. Stepping 2 is westmere elsif ($model =~ /^(25|2C|2F)$/){ $arch = 'Westmere'; # die shrink of nehalem @@ -11363,7 +11397,7 @@ sub cp_cpu_arch { $process = 'Intel 14nm'; $year = '2019';} elsif ($stepping >= 8){ - $arch = 'Cooper Lake'; + $arch = 'Cooper Lake'; # 55:A:14nm $process = 'Intel 14nm'; $year = '2020';} else { @@ -11382,12 +11416,12 @@ sub cp_cpu_arch { $arch = 'Skylake-S'; $process = 'Intel 14nm'; $year = '2015';} - elsif ($model =~ /^(66)$/){ + elsif ($model =~ /^(66|67)$/){ $arch = 'Cannon Lake'; $process = 'Intel 10nm'; $year = '2018';} # 6 are servers, 7 not - elsif ($model =~ /^(6A|6C|7D|7E)$/){ + elsif ($model =~ /^(6A|6C|7D|7E|9F)$/){ $arch = 'Ice Lake'; $process = 'Intel 10nm'; $year = '2019-21';} @@ -11399,10 +11433,22 @@ sub cp_cpu_arch { $arch = 'Knights Mill'; $process = 'Intel 14nm'; $year = '2017-19';} - elsif ($model =~ /^(8A|96|9C)$/){ - $arch = 'Tremont'; + elsif ($model =~ /^(86)$/){ + $arch = 'Tremont Snow Ridge'; # embedded $process = 'Intel 10nm'; - $year = '2019';} + $year = '2020';} + elsif ($model =~ /^(87)$/){ + $arch = 'Tremont Parker Ridge'; # embedded + $process = 'Intel 10nm'; + $year = '2022';} + elsif ($model =~ /^(8A)$/){ + $arch = 'Tremont Lakefield'; + $process = 'Intel 10nm'; + $year = '2020';} # ? + elsif ($model =~ /^(96)$/){ + $arch = 'Tremont Elkhart Lake'; + $process = 'Intel 10nm'; + $year = '2020';} # ? elsif ($model =~ /^(8C|8D)$/){ $arch = 'Tiger Lake'; $process = 'Intel 10nm'; @@ -11444,27 +11490,21 @@ sub cp_cpu_arch { $arch = 'Sapphire Rapids'; $process = 'Intel 7 (10nm ESF)'; $year = '2021+';} # server - elsif ($model =~ /^(97|9A)$/){ + elsif ($model =~ /^(97|9A|BE)$/){ $arch = 'Alder Lake'; # socket LG 1700 $process = 'Intel 7 (10nm ESF)'; $year = '2021+';} - ## IDS UNKNOWN, release late 2022 - # elsif ($model =~ /^()$/){ - # $arch = 'Raptor Lake'; # 13 gen, socket LG 1700,1800 - # $process = 'Intel 7 (10nm)'; - # $year = '2022+';} - # elsif ($model =~ /^()$/){ - # $arch = 'Meteor Lake'; # 14 gen - # $process = 'Intel 4';} - # Granite Rapids: Intel 3 (7nm) - # Arrow Lake - 15 gen + elsif ($model =~ /^(9A|9C)$/){ + $arch = 'Tremont Jasper Lake'; + $process = 'Intel 10nm'; + $year = '2021+';} # ? elsif ($model =~ /^(9E)$/){ if ($stepping == 9){ $arch = 'Kaby Lake'; $process = 'Intel 14nm'; $year = '2018';} elsif ($stepping >= 10 && $stepping <= 13){ - $arch = 'Coffee Lake'; + $arch = 'Coffee Lake'; # 9E:A,B,C,D $process = 'Intel 14nm'; $year = '2018';} else { @@ -11473,16 +11513,36 @@ sub cp_cpu_arch { $process = 'Intel 14nm'; $year = '2018';} } - elsif ($model =~ /^(A5)$/){ + elsif ($model =~ /^(A5|A6)$/){ $arch = 'Comet Lake'; # stepping 0-5 $process = 'Intel 14nm'; $year = '2020';} - elsif ($model =~ /^(A7)$/){ + elsif ($model =~ /^(A7|A8)$/){ $arch = 'Rocket Lake'; # stepping 1 $process = 'Intel 14nm'; $year = '2021+';} # More info: comet: shares family/model, need to find stepping numbers - # Coming: meteor lake; granite rapids; diamond rapids + # Coming: meteor lake; granite rapids; emerald rapids, diamond rapids + ## IDS UNKNOWN, release late 2022 + elsif ($model =~ /^(AA|AB|AC|B5)$/){ + $arch = 'Meteor Lake'; # 14 gen + $process = 'Intel 4 (7nm)'; # confirm + $year = '2023+';} + elsif ($model =~ /^(AD|AE)$/){ + $arch = 'Granite Rapids'; # ? + $process = 'Intel 3 (7nm+)'; # confirm + $year = '2024+';} + elsif ($model =~ /^(B6)$/){ + $arch = 'Grand Ridge'; # 14 gen + $process = 'Intel 4 (7nm)'; # confirm + $year = '2023+';} + elsif ($model =~ /^(B7|BA)$/){ + $arch = 'Raptor Lake'; # 13 gen, socket LG 1700,1800 + $process = 'Intel 7 (10nm)'; + $year = '2022+';} + # Granite Rapids: Intel 3 (7nm+) + # Arrow Lake - 15 gen, 20A (2nm), 2025 + # Lunar Lake - 16 gn, 18A (1.8nm), 2025 } # itanium 1 family 7 all recalled elsif ($family eq 'B'){ @@ -11502,7 +11562,12 @@ sub cp_cpu_arch { $process = 'Intel 180nm'; $year = '2000-01';} elsif ($model =~ /^(2)$/){ - $arch = 'Netburst Northwood'; + if ($stepping <= 4 || $stepping > 6){ + $arch = 'Netburst Northwood';} + elsif ($stepping == 5){ + $arch = 'Netburst Gallatin';} + else { + $arch = 'Netburst';} $process = 'Intel 130nm'; $year = '2002-03';} elsif ($model =~ /^(3)$/){ @@ -11510,6 +11575,7 @@ sub cp_cpu_arch { $process = 'Intel 90nm'; $year = '2004-06';} # 6? Nocona elsif ($model =~ /^(4)$/){ + # these are vague, and same stepping can have > 1 core names if ($stepping < 10){ $arch = 'Netburst Prescott'; # 4:1,9:prescott $process = 'Intel 90nm'; @@ -11520,7 +11586,7 @@ sub cp_cpu_arch { $year = '2005-06';} # 6? Nocona } elsif ($model =~ /^(6)$/){ - $arch = 'Netburst Presler'; + $arch = 'Netburst Presler'; # 6:2,4,5:presler $process = 'Intel 65nm'; $year = '2006';} else { @@ -11559,23 +11625,34 @@ sub cp_cpu_arch { # Only AMD/Intel 64 bit cpus sub cp_cpu_level { eval $start if $b_log; - my ($flags) = @_; - my $level; - if ($flags =~ /AVX512/i){ - $level = 'v4'; - } - # ~2015: Haswell and Excavator - elsif ($flags =~ /\b(AVX2|BMI[12]|F16C|FMA|LZCNT|MOVBE|OSXSAVE)\b/i){ - $level = 'v3'; - } - # !2009: Nehalem and Jaguar - elsif ($flags =~ /\b(CMPXCHG16B|[LS]AHF|POPCNT|SSS?E3|SSE4_[12])\b/i){ - $level = 'v2'; - } - # baseline: all x86_64 cpus - elsif ($flags =~ /\b(CX8|FPU|FXSR|MMX|OSFXSR|SCE|SSE2?)\b/i){ + my %flags = map {$_ =>1} split(/\s+/,$_[0]); + my ($level,$note,@found); + # note, each later cpu level must contain all subsequent cpu flags + # baseline: all x86_64 cpus lm cmov cx8 fpu fxsr mmx syscall sse2 + my @l1 = qw(cmov cx8 fpu fxsr lm mmx syscall sse2); + my @l2 = qw(cx16 lahf_lm popcnt sse4_1 sse4_2 ssse3); + my @l3 = qw(abm avx avx2 bmi1 bmi2 f16c fma movbe xsave); + my @l4 = qw(avx512f avx512bw avx512cd avx512dq avx512vl); + if ((@found = grep {$flags{$_}} @l1) && scalar(@found) == scalar(@l1)){ $level = 'v1'; + # print 'v1: ', Data::Dumper::Dumper \@found; + if ((@found = grep {$flags{$_}} @l2) && scalar(@found) == scalar(@l2)){ + $level = 'v2'; + # print 'v2: ', Data::Dumper::Dumper \@found; + # It's not 100% certain that if flags exist v3/v4 supported. flags don't + # give full possible outcomes in these cases. See: docs/inxi-cpu.txt + if ((@found = grep {$flags{$_}} @l3) && scalar(@found) == scalar(@l3)){ + $level = 'v3'; + # print 'v3: ', Data::Dumper::Dumper \@found; + $note = main::message('note-check'); + if ((@found = grep {$flags{$_}} @l4) && scalar(@found) == scalar(@l4)){ + $level = 'v4'; + # print 'v4: ', Data::Dumper::Dumper \@found; + } + } + } } + $level = [$level,$note] if $level; eval $end if $b_log; return $level; } @@ -13305,7 +13382,7 @@ sub set_disk_vendors { # HM320II HM320II HM ['(SAMSUNG|^(AWMB|[BC]DS20|[BC]WB|BJ[NT]|[BC]GND|CJN|CUT|[DG]3 Station|DUO\b|DUT|CKT|[GS]2 Portable|GN|HD\d{3}[A-Z]{2}$|(HM|SP)\d{2}|HS\d|M[AB]G\d[FG]|MCC|MCBOE|MCG\d+GC|[CD]JN|MZ|^G[CD][1-9][QS]|P[BM]\d|(SSD\s?)?SM\s?841)|^SSD\s?[89]\d{2}\s(DCT|PRO|QVD|\d+[GT]B)|\bEVO\b|SV\d|[BE][A-Z][1-9]QT|YP\b|[CH]N-M|MMC[QR]E)','SAMSUNG','Samsung',''], # maybe ^SM, ^HM # Android UMS Composite?U1 - ['(SanDisk|0781|^(ABLCD|AFGCE|D[AB]4|DX[1-9]|Extreme|Firebird|S[CD]\d{2}G|SD(S[S]?[ADQ]|SL\d+G|SU\d)|SDW[1-9]|SEM[1-9]|\d[STU]|U(3\b|1\d0))|Clip Sport|Cruzer|iXpand|SSD (Plus|U1[01]0) [1-9]|ULTRA\s(FIT|trek|II)|X[1-6]\d{2})','(SanDisk|0781)','SanDisk',''], + ['(SanDisk|0781|^(A[BCD]LC[DE]|AFGCE|D[AB]4|DX[1-9]|Extreme|Firebird|S[CD]\d{2}G|SD(S[S]?[ADQ]|SL\d+G|SU\d)|SDW[1-9]|SE\d{2}|SEM[1-9]|\d[STU]|U(3\b|1\d0))|Clip Sport|Cruzer|iXpand|SSD (Plus|U1[01]0) [1-9]|ULTRA\s(FIT|trek|II)|X[1-6]\d{2})','(SanDisk|0781)','SanDisk',''], # these are HP/Sandisk cobranded. DX110064A5xnNMRI ids as HP and Sandisc ['(^DX[1-9])','^(HP\b|SANDDISK)','Sandisk/HP',''], # ssd drive, must come before seagate ST test # real, SSEAGATE Backup+; XP1600HE30002 | 024 HN (spinpoint) ; possible usb: 24AS @@ -13330,7 +13407,7 @@ sub set_disk_vendors { ['^(DKR|HGST|Touro|54[15]0|7250|HC[CT]\d)','^HGST','HGST (Hitachi)',''], # HGST HUA ['^((ATA\s)?Hitachi|HCS|HD[PST]|DK\d|IC|(HDD\s)?HT|HU|HMS|HDE|0G\d|IHAT)','Hitachi','Hitachi',''], # vb: VB0250EAVER but clashes with vbox; HP_SSD_S700_120G ;GB0500EAFYL GB starter too generic? - ['^(HP\b|[MV]B[0-6]|G[BJ]\d|DF\d|F[BK]|0-9]|MM\d{4}|PSS|XR\d{4}|c350|v\d{3}[bgorw]$|x\d{3}[w]$|VK0|HC[CPY]\d|EX9\d\d)','^HP','HP',''], + ['^(HP\b|[MV]B[0-6]|G[BJ]\d|DF\d|F[BK]|0-9]|MM\d{4}|PSS|XR\d{4}|c350|v\d{3}[bgorw]$|x\d{3}[w]$|VK0|HC[CPY]\d|EX9\d\d|VO0)','^HP','HP',''], ['^(Lexar|LSD|JumpDrive|JD\s?Firefly|LX\d|WorkFlow)','^Lexar','Lexar',''], # mmc-LEXAR_0xb016546c; JD Firefly; # these must come before maxtor because STM ['^STmagic','^STmagic','STmagic',''], @@ -13433,7 +13510,7 @@ sub set_disk_vendors { ['^Disain','^Disain','Disain',''], ['^(Disney|PIX[\s]?JR)','^Disney','Disney',''], ['^(Doggo|DQ-|Sendisk|Shenchu)','^(doggo|Sendisk(.?Shenchu)?|Shenchu(.?Sendisk)?)','Doggo (SENDISK/Shenchu)',''], - ['^(Dogfish|Shark)','^Dogfish(\s*Technology)?','Dogfish Technology',''], + ['^(Dogfish|M\.2 2242|Shark)','^Dogfish(\s*Technology)?','Dogfish Technology',''], ['^DragonDiamond','^DragonDiamond','DragonDiamond',''], ['^(DREVO\b|X1\s\d+[GT])','^DREVO','Drevo',''], ['^DSS','^DSS DAHUA','DSS DAHUA',''], @@ -13452,6 +13529,7 @@ sub set_disk_vendors { ['^Epson','^Epson','Epson',''], ['^(Etelcom|SSD051)','^Etelcom','Etelcom',''], ['^EURS','^EURS','EURS',''], + ['^eVAULT','^eVAULT','eVAULT',''], # NOTE: ESA3... may be IBM PCIe SAD card/drives ['^(EXCELSTOR|r technology)','^EXCELSTOR( TECHNO(LOGY)?)?','ExcelStor',''], ['^EYOTA','^EYOTA','EYOTA',''], @@ -13459,7 +13537,7 @@ sub set_disk_vendors { ['^EZLINK','^EZLINK','EZLINK',''], ['^Fantom','^Fantom( Drive[s]?)?','Fantom Drives',''], ['^Fanxiang','^Fanxiang','Fanxiang',''], - ['^Faspeed','^Faspeed','Faspeed',''], + ['^(Faspeed|K3[\s-])','^Faspeed','Faspeed',''], ['^FASTDISK','^FASTDISK','FASTDISK',''], ['^Festtive','^Festtive','Festtive',''], ['^FiiO','^FiiO','FiiO',''], @@ -13475,7 +13553,7 @@ sub set_disk_vendors { ['^(Garmin|Fenix|Nuvi|Zumo)','^Garmin','Garmin',''], ['^Geil','^Geil','Geil',''], ['^GelL','^GelL','GelL',''], # typo for Geil? GelL ZENITH R3 120GB - ['^(Generic|UY[67]|SLD)','^Generic','Generic',''], + ['^(Generic|G1J3|SCA128|SLD|UY[67])','^Generic','Generic',''], ['^(Genesis(\s?Logic)?|05e3)','(Genesis(\s?Logic)?|05e3)','Genesis Logic',''], ['^Geonix','^Geonix','Geonix',''], ['^Getrich','^Getrich','Getrich',''], @@ -13540,6 +13618,7 @@ sub set_disk_vendors { ['^Jingyi','^Jingyi','Jingyi',''], # NOTE: ITY2 120GB hard to find ['^JMicron','^JMicron(\s?Tech(nology)?)?','JMicron Tech',''], #JMicron H/W raid + ['^(Jual|RX7)','^Jual','Jual',''], ['^Kazuk','^Kazuk','Kazuk',''], ['(\bKDI\b|^OM3P)','\bKDI\b','KDI',''], ['^KLLISRE','^KLLISRE','KLLISRE',''], @@ -13579,7 +13658,7 @@ sub set_disk_vendors { ['^(LG\b|Xtick)','^LG','LG',''], ['(LITE[-\s]?ON[\s-]?IT)','LITE[-]?ON[\s-]?IT','LITE-ON IT',''], # LITEONIT_LSS-24L6G # PH6-CE240-L; CL1-3D256-Q11 NVMe LITEON 256GB - ['(LITE[-\s]?ON|^PH[1-9]|^DMT|^CV\d-|L(8[HT]|AT|C[HST]|JH|M[HST]|S[ST])-)','LITE[-]?ON','LITE-ON',''], + ['(LITE[-\s]?ON|^PH[1-9]|^DMT|^CV\d-|L(8[HT]|AT|C[HST]|JH|M[HST]|S[ST])-|^S900)','LITE[-]?ON','LITE-ON',''], ['^LONDISK','^LONDISK','LONDISK',''], ['^Longline','^Longline','Longline',''], ['^LuminouTek','^LuminouTek','LuminouTek',''], @@ -13627,7 +13706,7 @@ sub set_disk_vendors { ['^(MyDigitalSSD|BP[4X])','^MyDigitalSSD','MyDigitalSSD',''], # BP4 = BulletProof4 ['^(Myson)','^Myson([\s-]?Century)?([\s-]?Inc\.?)?','Myson Century',''], ['^(Neo\s*Forza|NFS\d)','^Neo\s*Forza','Neo Forza',''], - ['^(Netac|S535N)','^Netac','Netac',''], + ['^(Netac|OnlyDisk|S535N)','^Netac','Netac',''], ['^NFHK','^NFHK','NFHK',''], # NGFF is a type, like msata, sata ['^Nik','^Nikimi','Nikimi',''], @@ -13635,6 +13714,7 @@ sub set_disk_vendors { ['^ODYS','^ODYS','ODYS',''], ['^Olympus','^Olympus','Olympus',''], ['^Orico','^Orico','Orico',''], + ['^Ortial','^Ortial','Ortial',''], ['^OSC','^OSC\b','OSC',''], ['^oyunkey','^oyunkey','Oyunkey',''], ['^PALIT','PALIT','Palit',''], # ssd @@ -13673,6 +13753,7 @@ sub set_disk_vendors { ['^SAMSWEET','^SAMSWEET','Samsweet',''], ['^SandForce','^SandForce','SandForce',''], ['^Sannobel','^Sannobel','Sannobel',''], + ['^(Sansa|fuse\b)','^Sansa','Sansa',''], # SATADOM can be innodisk or supermirco: dom == disk on module # SATAFIRM is an ssd failure message ['^(Sea\s?Tech|Transformer)','^Sea\s?Tech','Sea Tech',''], @@ -13680,6 +13761,8 @@ sub set_disk_vendors { # DIAMOND_040_GB ['^(SILICON\s?MOTION|SM\d|090c)','^(SILICON\s?MOTION|090c)','Silicon Motion',''], ['(Silicon[\s-]?Power|^SP[CP]C|^Silicon|^Diamond|^HasTopSunlightpeed)','Silicon[\s-]?Power','Silicon Power',''], + # simple drive could also maybe be hgst + ['^(Simple\s?Tech|Simple[\s-]?Drive)','^Simple\s?Tech','SimpleTech',''], ['^SINTECHI?','^SINTECHI?','SinTech (adapter)',''], ['^SiS\b','^SiS','SiS',''], ['Smartbuy','\s?Smartbuy','Smartbuy',''], # SSD Smartbuy 60GB; mSata Smartbuy 3 @@ -14077,6 +14160,7 @@ sub device_output { return if !$devices{'graphics'}; my $rows = $_[0]; my ($j,$num) = (0,1); + my ($bus_id); set_monitors_sys() if !$monitor_ids && -e '/sys/class/drm'; foreach my $row (@{$devices{'graphics'}}){ $num = 1; @@ -14090,6 +14174,7 @@ sub device_output { # print "$row->[0] $row->[3]\n"; $j = scalar @$rows; my $device = main::trimmer($row->[4]); + ($bus_id) = (); $device = ($device) ? main::clean_pci($device,'output') : 'N/A'; # have seen absurdly verbose card descriptions, with non related data etc if (length($device) > 85 || $size{'max-cols'} < 110){ @@ -14153,7 +14238,7 @@ sub device_output { } } if ($extra > 0){ - my $bus_id = (!$row->[2] && !$row->[3]) ? 'N/A' : "$row->[2].$row->[3]"; + $bus_id = (!$row->[2] && !$row->[3]) ? 'N/A' : "$row->[2].$row->[3]"; if ($extra > 1 && $bus_id ne 'N/A'){ main::get_pcie_data($bus_id,$j,$rows,\$num,'gpu'); } @@ -14169,6 +14254,12 @@ sub device_output { if ($extra > 2 && $row->[1]){ $rows->[$j]{main::key($num++,0,2,'class-ID')} = $row->[1]; } + if (!$bsd_type && $extra > 0 && $bus_id ne 'N/A' && $bus_id =~ /\.0$/){ + my $temp = main::get_device_temp($bus_id); + if ($temp){ + $rows->[$j]{main::key($num++,0,2,'temp')} = $temp . ' C'; + } + } # print "$row->[0]\n"; } eval $end if $b_log; @@ -14383,18 +14474,23 @@ sub display_output(){ # The only wayland setups with x drivers have xorg, transitional that is. if (@$x_drivers){ $rows->[$j]{main::key($num++,1,3,'X')} = ''; - my $driver = ($x_drivers->[0]) ? $x_drivers->[0] : 'N/A'; + my $driver = ($x_drivers->[0]) ? join(',',@{$x_drivers->[0]}) : 'N/A'; $rows->[$j]{main::key($num++,1,4,'loaded')} = $driver; if ($x_drivers->[1]){ - $rows->[$j]{main::key($num++,0,4,'unloaded')} = $x_drivers->[1]; + $rows->[$j]{main::key($num++,0,4,'unloaded')} = join(',',@{$x_drivers->[1]}); } if ($x_drivers->[2]){ - $rows->[$j]{main::key($num++,0,4,'failed')} = $x_drivers->[2]; + $rows->[$j]{main::key($num++,0,4,'failed')} = join(',',@{$x_drivers->[2]}); } if ($extra > 1 && $x_drivers->[3]){ - $rows->[$j]{main::key($num++,0,4,'alternate')} = $x_drivers->[3]; + $rows->[$j]{main::key($num++,0,4,'alternate')} = join(',',@{$x_drivers->[3]}); } } + if ($graphics{'dri-drivers'}){ + # note: if want to exclude if matches gpu/x driver, loop through and test. + # Here using all dri drivers found. + $rows->[$j]{main::key($num++,1,3,'dri')} = join(',',@{$graphics{'dri-drivers'}}); + } my $drivers; if (@$gpu_drivers){ $drivers = join(',',@$gpu_drivers); @@ -15342,7 +15438,7 @@ sub get_model_serial { # DISPLAY DATA X.org ## sub display_data_x { eval $start if $b_log; - my ($prog_xdpyinfo,$prog_xrandr); + my ($prog_xdpyinfo,$prog_xdriinfo,$prog_xrandr); if ($prog_xdpyinfo = main::check_program('xdpyinfo')){ xdpyinfo_data($prog_xdpyinfo); } @@ -15350,6 +15446,10 @@ sub display_data_x { if ($prog_xrandr = main::check_program('xrandr')){ xrandr_data($prog_xrandr); } + # if tool not installed, falls back to testing Xorg log file + if ($prog_xdriinfo = main::check_program('xdriinfo')){ + xdriinfo_data($prog_xdriinfo); + } if (!$graphics{'screens'}){ $graphics{'tty'} = tty_data(); } @@ -15368,6 +15468,40 @@ sub display_data_x { main::log_data('dump','$graphics{screens}',$graphics{'screens'}) if $b_log; eval $end if $b_log; } +sub xdriinfo_data { + eval $start if $b_log; + my $program = $_[0]; + my (%dri_drivers,$screen,$xdriinfo); + if (!$fake{'xdriinfo'}){ + $xdriinfo = main::grabber("$program $display_opt 2>/dev/null",'','strip','ref'); + } + else { + # $xdriinfo = main::reader("$ENV{HOME}/bin/scripts/inxi/data/xrandr/xrandr-test-1.txt",'strip','ref'); + } + foreach $screen (@$xdriinfo){ + if ($screen =~ /^Screen (\d+):\s+(\S+)/){ + $dri_drivers{$1} = $2 if $2 !~ /^not\b/; + } + } + if ($graphics{'screens'}){ + # assign to the screen if it's found + foreach $screen (@{$graphics{'screens'}}){ + if (defined $dri_drivers{$screen->{'screen'}} ){ + $screen->{'dri-driver'} = $dri_drivers{$screen->{'screen'}}; + } + } + } + # now the display drivers + foreach $screen (sort keys %dri_drivers){ + if (!$graphics{'dri-drivers'} || + !(grep {$dri_drivers{$screen} eq $_} @{$graphics{'dri-drivers'}})){ + push (@{$graphics{'dri-drivers'}},$dri_drivers{$screen}); + } + } + print 'x dri driver: ', Data::Dumper::Dumper \%dri_drivers if $dbg[17]; + main::log_data('dump','%dri_drivers',\%dri_drivers) if $b_log; + eval $end if $b_log; +} sub xdpyinfo_data { eval $start if $b_log; my ($program) = @_; @@ -15471,8 +15605,9 @@ sub xrandr_data { $xrandr = main::grabber("$program $display_opt 2>/dev/null",'','strip','ref'); } else { + $xrandr = main::reader("$ENV{HOME}/bin/scripts/inxi/data/xrandr/xrandr-4-displays-1.txt",'strip','ref'); # $xrandr = main::reader("$ENV{HOME}/bin/scripts/inxi/data/xrandr/xrandr-test-1.txt",'strip','ref'); - $xrandr = main::reader("$ENV{HOME}/bin/scripts/inxi/data/xrandr/xrandr-test-2.txt",'strip','ref'); + # $xrandr = main::reader("$ENV{HOME}/bin/scripts/inxi/data/xrandr/xrandr-test-2.txt",'strip','ref'); } # $graphics{'dimensions'} = (\@dimensions); # we get a bit more info from xrandr than xdpyinfo, but xrandr fails to handle @@ -15755,9 +15890,7 @@ sub gpu_drivers_sys { } sub display_drivers_x { eval $start if $b_log; - my ($driver,%drivers); my $driver_data = []; - my ($alternate,$failed,$loaded,$sep,$unloaded) = ('','','','',''); if (my $log = $system_files{'xorg-log'}){ if ($fake{'xorg-log'}){ # $log = "$ENV{HOME}/bin/scripts/inxi/data/xorg-logs/Xorg.0-voyager-serena.log"; @@ -15778,21 +15911,30 @@ sub display_drivers_x { sunbw2 suncg14 suncg3 suncg6 sunffb sunleo suntcx tdfx tga trident tseng unichrome v4l vboxvideo vesa vga via vmware vmwgfx voodoo)); $list = qr/$list/; # i only added perl 5.14, don't use + my ($b_use_dri,$dri,$driver,%drivers); + my ($alternate,$failed,$loaded,$unloaded); + my $pattern = 'Failed|Unload|Loading'; + # preferred source xdriinfo because it's current and accurate, but fallback here + if (!$graphics{'dri-drivers'}){ + $b_use_dri = 1; + $pattern .= '|DRI driver:'; + } + $pattern = qr/$pattern/; # it's much cheaper to grab the simple pattern match then do the expensive one # in the main loop. # @xorg = grep {/Failed|Unload|Loading/} @xorg; - foreach (@$xorg){ - next if !/Failed|Unload|Loading/; + foreach my $line (@$xorg){ + next if $line !~ /$pattern/i; # print "$_\n"; # note that in file names, driver is always lower case - if (/\sLoading.*($list)_drv\.so$/i){ + if ($line =~ /\sLoading.*($list)_drv\.so$/i){ $driver=lc($1); # we get all the actually loaded drivers first, we will use this to compare the # failed/unloaded, which have not always actually been truly loaded $drivers{$driver}='loaded'; } # openbsd uses UnloadModule: - elsif (/(Unloading\s|UnloadModule).*\"?($list)(_drv\.so)?\"?$/i){ + elsif ($line =~ /(Unloading\s|UnloadModule).*\"?($list)(_drv\.so)?\"?$/i){ $driver=lc($2); # we get all the actually loaded drivers first, we will use this to compare the # failed/unloaded, which have not always actually been truly loaded @@ -15808,14 +15950,14 @@ sub display_drivers_x { # (II) Unloading nouveau # (II) Failed to load module "nouveau" (already loaded, 0) # (II) LoadModule: "modesetting" - elsif (/Failed.*($list)\"?.*$/i){ + elsif ($line =~ /Failed.*($list)\"?.*$/i){ # Set driver to lower case because sometimes it will show as # RADEON or NVIDIA in the actual x start $driver=lc($1); # we need to make sure that the driver has already been truly loaded, # not just discussed if (exists $drivers{$driver} && $drivers{$driver} ne 'alternate'){ - if ($_ !~ /\(already loaded/){ + if ($line !~ /\(already loaded/){ $drivers{$driver}='failed'; } # reset the previous line's 'unloaded' to 'loaded' as well @@ -15823,28 +15965,30 @@ sub display_drivers_x { $drivers{$driver}='loaded'; } } - elsif ($_ =~ /module does not exist/){ + elsif ($line =~ /module does not exist/){ $drivers{$driver}='alternate'; } } + elsif ($b_use_dri && $line =~ /DRI driver:\s*(\S+)/i){ + $dri = $1; + if (!$graphics{'dri-drivers'} || + !(grep {$dri eq $_} @{$graphics{'dri-drivers'}})){ + push(@{$graphics{'dri-drivers'}},$dri); + } + } } - my $sep = ''; foreach (sort keys %drivers){ if ($drivers{$_} eq 'loaded'){ - $sep = ($loaded) ? ',' : ''; - $loaded .= $sep . $_; + push(@$loaded,$_); } elsif ($drivers{$_} eq 'unloaded'){ - $sep = ($unloaded) ? ',' : ''; - $unloaded .= $sep . $_; + push(@$unloaded,$_); } elsif ($drivers{$_} eq 'failed'){ - $sep = ($failed) ? ',' : ''; - $failed .= $sep . $_; + push(@$failed,$_); } elsif ($drivers{$_} eq 'alternate'){ - $sep = ($alternate) ? ',' : ''; - $alternate .= $sep . $_; + push(@$alternate,$_); } } if ($loaded || $unloaded || $failed || $alternate){ @@ -16195,7 +16339,8 @@ sub set_intel_data { 'years' => '2020-21', }, {'arch' => 'Gen-12.2', - 'ids' => '4626|4628|4682|4688|4690|4692|4693|46a3|46a6|46a8|46aa|46b3|46c3', + 'ids' => '4626|4628|4682|4688|468a|468b|4690|4692|4693|46a3|46a6|46a8|46aa|' . + '46b3|46c3', 'code' => '', 'process' => 'Intel 10nm', 'years' => '2021-22+', @@ -16486,7 +16631,7 @@ sub set_nv_data { {'arch' => 'Hopper', 'ids' => '', 'code' => 'GH1xx', - 'pattern' => 'G?H[12]\d{2}', + 'pattern' => '\bG?H[12]\d{2}', 'process' => 'TSMC n4 (5nm)', 'series' => '515.xx+', 'status' => $status_current, @@ -16495,8 +16640,8 @@ sub set_nv_data { {'arch' => 'Lovelace', 'ids' => '', 'code' => 'AD1xx', - 'pattern' => 'G?L\d{1,4}|RTX 40\d{2}', - 'process' => 'TSMC n5 (5nm)', + 'pattern' => '\bG?L\d{1,4}|\bAD1\d{2}|RTX [6-8]0\d{2}', + 'process' => 'TSMC n4 (5nm)', 'series' => '515.xx+', 'status' => $status_current, 'years' => '2022-23+', @@ -16528,8 +16673,8 @@ sub get_gpu_data { eval $start if $b_log; my ($gpu,$p_id,$name) = @_; my ($info); - # Reverse, newer will be more common geneerally than older, so save some cpu! - # This means for amd/intel/nvidia current, the regex name search runs FIRST! + # Don't use reverse because if product ID is matched, we want that, not a looser + # regex match. Tried with reverse and led to false matches. foreach my $item (reverse @$gpu){ next if !$item->{'ids'} && (!$item->{'pattern'} || !$name); if (($item->{'ids'} && $p_id =~ /^($item->{'ids'})$/) || @@ -16718,8 +16863,9 @@ sub advanced_monitor_data { push(@vert,$monitors->{$key}{'pos-y'}); } } - @horiz = sort(@horiz); - @vert = sort(@vert); + # we need NUMERIC sort, because positions can be less than 1000! + @horiz = sort {$a <=> $b} @horiz; + @vert =sort {$a <=> $b} @vert; my ($h,$v) = (scalar(@horiz),scalar(@vert)); # print Data::Dumper::Dumper \@horiz; # print Data::Dumper::Dumper \@vert; @@ -18272,9 +18418,12 @@ sub device_output { my $bus_id = 'N/A'; # note: for arm/mips we want to see the single item bus id, why not? # note: we can have bus id: 0002 / 0 which is valid, but 0 / 0 is invalid - if (defined $row->[2] && $row->[2] ne '0' && defined $row->[3]){$bus_id = "$row->[2].$row->[3]"} - elsif (defined $row->[2] && $row->[2] ne '0'){$bus_id = $row->[2]} - elsif (defined $row->[3] && $row->[3] ne '0'){$bus_id = $row->[3]} + if (defined $row->[2] && $row->[2] ne '0' && defined $row->[3]){ + $bus_id = "$row->[2].$row->[3]"} + elsif (defined $row->[2] && $row->[2] ne '0'){ + $bus_id = $row->[2]} + elsif (defined $row->[3] && $row->[3] ne '0'){ + $bus_id = $row->[3]} if ($extra > 0){ if ($row->[9] && !$bsd_type){ my $version = main::get_module_version($row->[9]); @@ -18290,7 +18439,9 @@ sub device_output { main::get_pcie_data($bus_id,$j,$rows,\$num); } # as far as I know, wifi has no port, but in case it does in future, use it - $rows->[$j]{main::key($num++,0,2,'port')} = $row->[8] if (!$b_wifi || ($b_wifi && $row->[8] ne 'N/A')); + if (!$b_wifi || ($b_wifi && $row->[8] ne 'N/A')){ + $rows->[$j]{main::key($num++,0,2,'port')} = $row->[8]; + } $rows->[$j]{main::key($num++,0,2,'bus-ID')} = $bus_id; } if ($extra > 1){ @@ -18299,6 +18450,12 @@ sub device_output { if ($extra > 2 && $row->[1]){ $rows->[$j]{main::key($num++,0,2,'class-ID')} = $row->[1]; } + if (!$bsd_type && $extra > 0 && $bus_id ne 'N/A' && $bus_id =~ /\.0$/){ + my $temp = main::get_device_temp($bus_id); + if ($temp){ + $rows->[$j]{main::key($num++,0,2,'temp')} = $temp . ' C'; + } + } if ($show{'network-advanced'}){ my @data; if (!$bsd_type){ @@ -23022,10 +23179,12 @@ sub file_path { package SensorItem; my $gpu_data = []; my $sensors_raw = {}; +my $max_fan = 15000; sub get { eval $start if $b_log; - my ($b_data,$key1,$program,$val1,$sensors); - my ($num,$rows) = (0,[]); + my ($b_data,$b_ipmi,$b_no_lm,$b_no_sys); + my ($message_type,$program,$val1,$sensors); + my ($key1,$num,$rows) = ('Message',0,[]); my $source = 'sensors'; # will trip some type output if ipmi + another type # we're allowing 1 or 2 ipmi tools, first the gnu one, then the # almost certain to be present in BSDs @@ -23036,54 +23195,99 @@ sub get { $sensors = ipmi_data($program); $b_data = sensors_output($rows,'ipmi',$sensors); if (!$b_data){ - $key1 = 'Message'; - $val1 = main::message('sensors-data-ipmi'); - # $val1 = main::message('dev'); - push(@$rows,{main::key($num++,0,1,$key1) => $val1}); + $val1 = main::message('sensor-data-ipmi'); + push(@$rows,{ + main::key($num++,1,1,'Src') => 'ipmi', + main::key($num++,0,1,$key1) => $val1, + }); } - $source = 'lm-sensors'; # trips per sensor type output } else { $key1 = 'Permissions'; - $val1 = main::message('sensors-ipmi-root'); - push(@$rows,{main::key($num++,0,1,$key1) => $val1}); + $val1 = main::message('sensor-data-ipmi-root'); + push(@$rows,{ + main::key($num++,1,1,'Src') => 'ipmi', + main::key($num++,0,2,$key1) => $val1, + }); } + $b_ipmi = 1; } - if ($sysctl{'sensor'}){ - $sensors = sysctl_data(); - $b_data = sensors_output($rows,'sysctl-sensors',$sensors); - if (!$b_data){ - $key1 = 'Message'; - $val1 = main::message('sensors-data-bsd',$uname[0]); - push(@$rows,{main::key($num++,0,1,$key1) => $val1}); + $b_data = 0; + if ($bsd_type){ + if ($sysctl{'sensor'}){ + $sensors = sysctl_data(); + $source = 'sysctl' if $b_ipmi; + $b_data = sensors_output($rows,$source,$sensors); + if (!$b_data){ + $source = 'sysctl'; + $val1 = main::message('sensor-data-bsd',$uname[0]); + } + } + else { + if ($bsd_type =~ /^(free|open)bsd/){ + $source = 'sysctl'; + $val1 = main::message('sensor-data-bsd-ok'); + } + else { + $source = 'N/A'; + $val1 = main::message('sensor-data-bsd-unsupported'); + } } } else { - if (!$fake{'sensors'} && $alerts{'sensors'}->{'action'} ne 'use'){ + if (!$force{'sensors-sys'} && + ($fake{'sensors'} || $alerts{'sensors'}->{'action'} eq 'use')){ + load_lm_sensors(); + $sensors = linux_sensors_data(); + $source = 'lm-sensors' if $b_ipmi; # trips per sensor type output + $b_data = sensors_output($rows,$source,$sensors); # print "here 1\n"; - if ($bsd_type && $bsd_type =~ /^(free|open)bsd/){ - $key1 = 'Message'; - $val1 = main::message('sensors-data-bsd-ok'); + $b_no_lm = 1 if !$b_data; + } + # given recency of full /sys data, we want to prefer lm-sensors for a long time + # and use /sys as a fallback. This will handle servers, which often do not + # have lm-sensors installed, but do have /sys hwmon data. + if (!$b_data && -d '/sys/class/hwmon'){ + load_sys_data(); + $sensors = linux_sensors_data(); + $source = '/sys'; # trips per sensor type output + $b_data = sensors_output($rows,$source,$sensors); + # print "here 2\n"; + $b_no_sys = 1 if !$b_data; + } + if (!$b_data){ + if ($b_no_lm || $b_no_sys){ + if ($b_no_lm && $b_no_sys){ + $source = 'lm-sensors+/sys'; + $val1 = main::message('sensor-data-sys-lm'); + } + elsif ($b_no_lm){ + $source = 'lm-sensors'; + $val1 = main::message('sensor-data-lm-sensors'); + } + else { + $val1 = main::message('sensor-data-sys'); + } } - else { + elsif (!$fake{'sensors'} && $alerts{'sensors'}->{'action'} ne 'use'){ + # print "here 3\n"; + $source = 'lm-sensors'; $key1 = $alerts{'sensors'}->{'action'}; - $val1 = $alerts{'sensors'}->{'message'}; $key1 = ucfirst($key1); + $val1 = $alerts{'sensors'}->{'message'}; } - push(@$rows,{main::key($num++,0,1,$key1) => $val1,}); - } - else { - $sensors = lm_sensors_data(); - $b_data = sensors_output($rows,$source,$sensors); - # print "here 2\n"; - if (!$b_data){ - $key1 = 'Message'; + else { + $source = 'N/A'; $val1 = main::message('sensors-data-linux'); - push(@$rows,{main::key($num++,0,1,$key1) => $val1}); } - } } + if (!$b_data){ + push(@$rows,{ + main::key($num++,1,1,'Src') => $source, + main::key($num++,0,2,$key1) => $val1, + }); + } eval $end if $b_log; return $rows; } @@ -23095,129 +23299,128 @@ sub sensors_output { my $num = 0; my $j = scalar @$rows; if (!$loaded{'gpu-data'} && - ($source eq 'sensors' || $source eq 'lm-sensors')){ + ($source eq 'sensors' || $source eq 'lm-sensors' || $source eq '/sys')){ gpu_sensor_data(); } # gpu sensors data might be present even if standard sensors data wasn't return if !%$sensors && !@$gpu_data; - $b_result = 1; ## need t trip data found conditions + $b_result = 1; ## need to trip data found conditions my $temp_unit = (defined $sensors->{'temp-unit'}) ? " $sensors->{'temp-unit'}": ''; my $cpu_temp = (defined $sensors->{'cpu-temp'}) ? $sensors->{'cpu-temp'} . $temp_unit: 'N/A'; my $mobo_temp = (defined $sensors->{'mobo-temp'}) ? $sensors->{'mobo-temp'} . $temp_unit: 'N/A'; - my $cpu1_key = ($sensors->{'cpu2-temp'}) ? 'cpu-1': 'cpu' ; - my $data_source = ($source eq 'ipmi' || $source eq 'lm-sensors') ? $source : ''; - push(@$rows, { - main::key($num++,1,1,'System Temperatures') => $data_source, - main::key($num++,0,2,$cpu1_key) => $cpu_temp, - }); + my $cpu1_key = ($sensors->{'cpu2-temp'}) ? 'cpu-1': 'cpu'; + my ($l1,$l2,$l3) = (1,2,3); + if ($source ne 'sensors'){ + $rows->[$j]{main::key($num++,1,1,'Src')} = $source; + ($l1,$l2,$l3) = (2,3,4); + } + $rows->[$j]{main::key($num++,1,$l1,'System Temperatures')} = ''; + $rows->[$j]{main::key($num++,0,$l2,$cpu1_key)} = $cpu_temp; if ($sensors->{'cpu2-temp'}){ - $rows->[$j]{main::key($num++,0,2,'cpu-2')} = $sensors->{'cpu2-temp'} . $temp_unit; + $rows->[$j]{main::key($num++,0,$l2,'cpu-2')} = $sensors->{'cpu2-temp'} . $temp_unit; } if ($sensors->{'cpu3-temp'}){ - $rows->[$j]{main::key($num++,0,2,'cpu-3')} = $sensors->{'cpu3-temp'} . $temp_unit; + $rows->[$j]{main::key($num++,0,$l2,'cpu-3')} = $sensors->{'cpu3-temp'} . $temp_unit; } if ($sensors->{'cpu4-temp'}){ - $rows->[$j]{main::key($num++,0,2,'cpu-4')} = $sensors->{'cpu4-temp'} . $temp_unit; + $rows->[$j]{main::key($num++,0,$l2,'cpu-4')} = $sensors->{'cpu4-temp'} . $temp_unit; } if (defined $sensors->{'pch-temp'}){ my $pch_temp = $sensors->{'pch-temp'} . $temp_unit; - $rows->[$j]{main::key($num++,0,2,'pch')} = $pch_temp; + $rows->[$j]{main::key($num++,0,$l2,'pch')} = $pch_temp; } - $rows->[$j]{main::key($num++,0,2,'mobo')} = $mobo_temp; + $rows->[$j]{main::key($num++,0,$l2,'mobo')} = $mobo_temp; if (defined $sensors->{'sodimm-temp'}){ my $sodimm_temp = $sensors->{'sodimm-temp'} . $temp_unit; - $rows->[$j]{main::key($num++,0,2,'sodimm')} = $sodimm_temp; + $rows->[$j]{main::key($num++,0,$l2,'sodimm')} = $sodimm_temp; } if (defined $sensors->{'psu-temp'}){ my $psu_temp = $sensors->{'psu-temp'} . $temp_unit; - $rows->[$j]{main::key($num++,0,2,'psu')} = $psu_temp; + $rows->[$j]{main::key($num++,0,$l2,'psu')} = $psu_temp; } if (defined $sensors->{'ambient-temp'}){ my $ambient_temp = $sensors->{'ambient-temp'} . $temp_unit; - $rows->[$j]{main::key($num++,0,2,'ambient')} = $ambient_temp; + $rows->[$j]{main::key($num++,0,$l2,'ambient')} = $ambient_temp; } if (scalar @$gpu_data == 1 && defined $gpu_data->[0]{'temp'}){ my $gpu_temp = $gpu_data->[0]{'temp'}; my $gpu_type = $gpu_data->[0]{'type'}; my $gpu_unit = (defined $gpu_data->[0]{'temp-unit'} && $gpu_temp) ? " $gpu_data->[0]{'temp-unit'}" : ' C'; - $rows->[$j]{main::key($num++,1,2,'gpu')} = $gpu_type; - $rows->[$j]{main::key($num++,0,3,'temp')} = $gpu_temp . $gpu_unit; + $rows->[$j]{main::key($num++,1,$l2,'gpu')} = $gpu_type; + $rows->[$j]{main::key($num++,0,$l3,'temp')} = $gpu_temp . $gpu_unit; if ($extra > 1 && $gpu_data->[0]{'temp-mem'}){ - $rows->[$j]{main::key($num++,0,3,'mem')} = $gpu_data->[0]{'temp-mem'} . $gpu_unit; + $rows->[$j]{main::key($num++,0,$l3,'mem')} = $gpu_data->[0]{'temp-mem'} . $gpu_unit; } } $j = scalar @$rows; @fan_main = @{$sensors->{'fan-main'}} if $sensors->{'fan-main'}; @fan_default = @{$sensors->{'fan-default'}} if $sensors->{'fan-default'}; - my $fan_def = ($data_source) ? $data_source : ''; - if (!@fan_main && !@fan_default){ - $fan_def = ($fan_def) ? "$data_source N/A" : 'N/A'; - } - $rows->[$j]{main::key($num++,1,1,'Fan Speeds (RPM)')} = $fan_def; + my $fan_def = (!@fan_main && !@fan_default) ? 'N/A' : ''; + $rows->[$j]{main::key($num++,1,$l1,'Fan Speeds (RPM)')} = $fan_def; my $b_cpu = 0; for (my $i = 0; $i < scalar @fan_main; $i++){ next if $i == 0;# starts at 1, not 0 if (defined $fan_main[$i]){ if ($i == 1 || ($i == 2 && !$b_cpu)){ - $rows->[$j]{main::key($num++,0,2,'cpu')} = $fan_main[$i]; + $rows->[$j]{main::key($num++,0,$l2,'cpu')} = $fan_main[$i]; $b_cpu = 1; } elsif ($i == 2 && $b_cpu){ - $rows->[$j]{main::key($num++,0,2,'mobo')} = $fan_main[$i]; + $rows->[$j]{main::key($num++,0,$l2,'mobo')} = $fan_main[$i]; } elsif ($i == 3){ - $rows->[$j]{main::key($num++,0,2,'psu')} = $fan_main[$i]; + $rows->[$j]{main::key($num++,0,$l2,'psu')} = $fan_main[$i]; } elsif ($i == 4){ - $rows->[$j]{main::key($num++,0,2,'sodimm')} = $fan_main[$i]; + $rows->[$j]{main::key($num++,0,$l2,'sodimm')} = $fan_main[$i]; } elsif ($i > 4){ $fan_number = $i - 4; - $rows->[$j]{main::key($num++,0,2,"case-$fan_number")} = $fan_main[$i]; + $rows->[$j]{main::key($num++,0,$l2,"case-$fan_number")} = $fan_main[$i]; } } } for (my $i = 0; $i < scalar @fan_default; $i++){ next if $i == 0;# starts at 1, not 0 if (defined $fan_default[$i]){ - $rows->[$j]{main::key($num++,0,2,"fan-$i")} = $fan_default[$i]; + $rows->[$j]{main::key($num++,0,$l2,"fan-$i")} = $fan_default[$i]; } } - $rows->[$j]{main::key($num++,0,2,'psu')} = $sensors->{'fan-psu'} if defined $sensors->{'fan-psu'}; - $rows->[$j]{main::key($num++,0,2,'psu-1')} = $sensors->{'fan-psu1'} if defined $sensors->{'fan-psu1'}; - $rows->[$j]{main::key($num++,0,2,'psu-2')} = $sensors->{'fan-psu2'} if defined $sensors->{'fan-psu2'}; + $rows->[$j]{main::key($num++,0,$l2,'psu')} = $sensors->{'fan-psu'} if defined $sensors->{'fan-psu'}; + $rows->[$j]{main::key($num++,0,$l2,'psu-1')} = $sensors->{'fan-psu1'} if defined $sensors->{'fan-psu1'}; + $rows->[$j]{main::key($num++,0,$l2,'psu-2')} = $sensors->{'fan-psu2'} if defined $sensors->{'fan-psu2'}; # note: so far, only nvidia-settings returns speed, and that's in percent if (scalar @$gpu_data == 1 && defined $gpu_data->[0]{'fan-speed'}){ my $gpu_fan = $gpu_data->[0]{'fan-speed'} . $gpu_data->[0]{'speed-unit'}; my $gpu_type = $gpu_data->[0]{'type'}; - $rows->[$j]{main::key($num++,1,2,'gpu')} = $gpu_type; - $rows->[$j]{main::key($num++,0,3,'fan')} = $gpu_fan; + $rows->[$j]{main::key($num++,1,$l2,'gpu')} = $gpu_type; + $rows->[$j]{main::key($num++,0,$l3,'fan')} = $gpu_fan; } if (scalar @$gpu_data > 1){ $j = scalar @$rows; - $rows->[$j]{main::key($num++,1,1,'GPU')} = ''; + $rows->[$j]{main::key($num++,1,$l1,'GPU')} = ''; my $gpu_unit = (defined $gpu_data->[0]{'temp-unit'}) ? " $gpu_data->[0]{'temp-unit'}" : ' C'; foreach my $info (@$gpu_data){ # speed unit is either '' or % my $gpu_fan = (defined $info->{'fan-speed'}) ? $info->{'fan-speed'} . $info->{'speed-unit'}: undef; my $gpu_type = $info->{'type'}; my $gpu_temp = (defined $info->{'temp'}) ? $info->{'temp'} . $gpu_unit: 'N/A'; - $rows->[$j]{main::key($num++,1,2,'device')} = $gpu_type; + $rows->[$j]{main::key($num++,1,$l2,'device')} = $gpu_type; if (defined $info->{'screen'}){ - $rows->[$j]{main::key($num++,0,3,'screen')} = $info->{'screen'}; + $rows->[$j]{main::key($num++,0,$l3,'screen')} = $info->{'screen'}; } - $rows->[$j]{main::key($num++,0,3,'temp')} = $gpu_temp; + $rows->[$j]{main::key($num++,0,$l3,'temp')} = $gpu_temp; if ($extra > 1 && $info->{'temp-mem'}){ - $rows->[$j]{main::key($num++,0,3,'mem')} = $info->{'temp-mem'} . $gpu_unit; + $rows->[$j]{main::key($num++,0,$l3,'mem')} = $info->{'temp-mem'} . $gpu_unit; } if (defined $gpu_fan){ - $rows->[$j]{main::key($num++,0,3,'fan')} = $gpu_fan; + $rows->[$j]{main::key($num++,0,$l3,'fan')} = $gpu_fan; } if ($extra > 2 && $info->{'watts'}){ - $rows->[$j]{main::key($num++,0,3,'watts')} = $info->{'watts'}; + $rows->[$j]{main::key($num++,0,$l3,'watts')} = $info->{'watts'}; } - if ($extra > 2 && $info->{'mvolts'}){ - $rows->[$j]{main::key($num++,0,3,'mV')} = $info->{'mvolts'}; + if ($extra > 2 && $info->{'volts-gpu'}){ + $rows->[$j]{main::key($num++,0,$l3,$info->{'volts-gpu'}[1])} = $info->{'volts-gpu'}[0]; } } } @@ -23229,24 +23432,36 @@ sub sensors_output { $sensors->{'volts-5'} ||= 'N/A'; $sensors->{'volts-3.3'} ||= 'N/A'; $sensors->{'volts-vbat'} ||= 'N/A'; - $rows->[$j]{main::key($num++,1,1,'Power')} = $data_source; - $rows->[$j]{main::key($num++,0,2,'12v')} = $sensors->{'volts-12'}; - $rows->[$j]{main::key($num++,0,2,'5v')} = $sensors->{'volts-5'}; - $rows->[$j]{main::key($num++,0,2,'3.3v')} = $sensors->{'volts-3.3'}; - $rows->[$j]{main::key($num++,0,2,'vbat')} = $sensors->{'volts-vbat'}; + $rows->[$j]{main::key($num++,1,$l1,'Power')} = ''; + $rows->[$j]{main::key($num++,0,$l2,'12v')} = $sensors->{'volts-12'}; + $rows->[$j]{main::key($num++,0,$l2,'5v')} = $sensors->{'volts-5'}; + $rows->[$j]{main::key($num++,0,$l2,'3.3v')} = $sensors->{'volts-3.3'}; + $rows->[$j]{main::key($num++,0,$l2,'vbat')} = $sensors->{'volts-vbat'}; if ($extra > 1 && $source eq 'ipmi'){ $sensors->{'volts-dimm-p1'} ||= 'N/A'; $sensors->{'volts-dimm-p2'} ||= 'N/A'; - $rows->[$j]{main::key($num++,0,2,'dimm-p1')} = $sensors->{'volts-dimm-p1'} if $sensors->{'volts-dimm-p1'}; - $rows->[$j]{main::key($num++,0,2,'dimm-p2')} = $sensors->{'volts-dimm-p2'} if $sensors->{'volts-dimm-p2'}; - $rows->[$j]{main::key($num++,0,2,'soc-p1')} = $sensors->{'volts-soc-p1'} if $sensors->{'volts-soc-p1'}; - $rows->[$j]{main::key($num++,0,2,'soc-p2')} = $sensors->{'volts-soc-p2'} if $sensors->{'volts-soc-p2'}; + if ($sensors->{'volts-dimm-p1'}){ + $rows->[$j]{main::key($num++,0,$l2,'dimm-p1')} = $sensors->{'volts-dimm-p1'}; + } + if ($sensors->{'volts-dimm-p2'}){ + $rows->[$j]{main::key($num++,0,$l2,'dimm-p2')} = $sensors->{'volts-dimm-p2'}; + } + if ($sensors->{'volts-soc-p1'}){ + $rows->[$j]{main::key($num++,0,$l2,'soc-p1')} = $sensors->{'volts-soc-p1'}; + } + if ($sensors->{'volts-soc-p2'}){ + $rows->[$j]{main::key($num++,0,$l2,'soc-p2')} = $sensors->{'volts-soc-p2'}; + } } if (scalar @$gpu_data == 1 && $extra > 2 && - ($gpu_data->[0]{'watts'} || $gpu_data->[0]{'mvolts'})){ - $rows->[$j]{main::key($num++,1,2,'gpu')} = $gpu_data->[0]{'type'}; - $rows->[$j]{main::key($num++,0,3,'watts')} = $gpu_data->[0]{'watts'} if $gpu_data->[0]{'watts'}; - $rows->[$j]{main::key($num++,0,3,'mV')} = $gpu_data->[0]{'mvolts'} if $gpu_data->[0]{'mvolts'}; + ($gpu_data->[0]{'watts'} || $gpu_data->[0]{'volts-gpu'})){ + $rows->[$j]{main::key($num++,1,$l2,'gpu')} = $gpu_data->[0]{'type'}; + if ($gpu_data->[0]{'watts'}){ + $rows->[$j]{main::key($num++,0,$l3,'watts')} = $gpu_data->[0]{'watts'}; + } + if ($gpu_data->[0]{'volts-gpu'}){ + $rows->[$j]{main::key($num++,0,$l3,$gpu_data->[0]{'volts-gpu'}[1])} = $gpu_data->[0]{'volts-gpu'}[0]; + } } } eval $end if $b_log; @@ -23255,7 +23470,7 @@ sub sensors_output { sub ipmi_data { eval $start if $b_log; my ($program) = @_; - my ($b_cpu_0,$cmd,$file,@data,$fan_working,@row,$sys_fan_nu,$temp_working, + my ($b_cpu_0,$cmd,$file,@data,$fan_working,@row,$speed,$sys_fan_nu,$temp_working, $working_unit); my ($b_ipmitool,$i_key,$i_value,$i_unit); my $sensors = {}; @@ -23368,7 +23583,8 @@ sub ipmi_data { # note: can be cpu fan:, cpu fan speed:, etc. elsif ($row[$i_key] =~ /^(CPU|Processor)[\s_]Fan/i || $row[$i_key] =~ /^SYS\.[0-9][\s_]?\(CPU\s?0\)$/i){ - $sensors->{'fan-main'}->[1] = int($row[$i_value]); + $speed = int($row[$i_value]); + $sensors->{'fan-main'}->[1] = $speed if $speed < $max_fan; } # note that the counters are dynamically set for fan numbers here # otherwise you could overwrite eg aux fan2 with case fan2 in theory @@ -23378,6 +23594,7 @@ sub ipmi_data { elsif ($row[$i_key] =~ /^(SYS[\s_])?FAN[\s_]?([0-9A-F]+)/i){ $sys_fan_nu = hex($2); $fan_working = int($row[$i_value]); + next if $fan_working > $max_fan; $sensors->{'fan-default'} = () if !$sensors->{'fan-default'}; if ($sys_fan_nu =~ /^([0-9]+)$/){ # add to array if array index does not exist OR if number is > existing number @@ -23392,13 +23609,16 @@ sub ipmi_data { } } elsif ($row[$i_key] =~ /^(FAN PSU|PSU FAN)$/i){ - $sensors->{'fan-psu'} = int($row[$i_value]); + $speed = int($row[$i_value]); + $sensors->{'fan-psu'} = $speed if $speed < $max_fan; } elsif ($row[$i_key] =~ /^(FAN PSU1|PSU1 FAN)$/i){ - $sensors->{'fan-psu-1'} = int($row[$i_value]); + $speed = int($row[$i_value]); + $sensors->{'fan-psu-1'} = $speed if $speed < $max_fan; } elsif ($row[$i_key] =~ /^(FAN PSU2|PSU2 FAN)$/i){ - $sensors->{'fan-psu-2'} = int($row[$i_value]); + $speed = int($row[$i_value]); + $sensors->{'fan-psu-2'} = $speed if $speed < $max_fan; } if ($extra > 0){ if ($row[$i_key] =~ /^((.+\s|P[_]?)?\+?12V|PSU[12]_VOUT)$/i){ @@ -23435,12 +23655,11 @@ sub ipmi_data { print Data::Dumper::Dumper $sensors if $dbg[31]; return $sensors; } -sub lm_sensors_data { +sub linux_sensors_data { eval $start if $b_log; my $sensors = {}; my ($sys_fan_nu) = (0); my ($adapter,$fan_working,$temp_working,$working_unit) = ('','','','',''); - load_lm_sensors(); foreach $adapter (keys %{$sensors_raw->{'main'}}){ next if !$adapter || ref $sensors_raw->{'main'}{$adapter} ne 'ARRAY'; # not sure why hwmon is excluded, forgot to add info in comments @@ -23551,22 +23770,23 @@ sub lm_sensors_data { $sensors->{'temp-unit'} = set_temp_unit($sensors->{'temp-unit'},$working_unit) if $working_unit; } # note: can be cpu fan:, cpu fan speed:, etc. - elsif (!$sensors->{'fan-main'}->[1] && $_ =~ /^F?(CPU|Processor).*:([0-9]+)[\s]RPM/i){ - $sensors->{'fan-main'}->[1] = $2; + elsif (!defined $sensors->{'fan-main'}->[1] && $_ =~ /^F?(CPU|Processor).*:([0-9]+)[\s]RPM/i){ + $sensors->{'fan-main'}->[1] = $2 if $2 < $max_fan; } - elsif (!$sensors->{'fan-main'}->[2] && $_ =~ /^F?(M\/B|MB|SYS|Motherboard).*:([0-9]+)[\s]RPM/i){ - $sensors->{'fan-main'}->[2] = $2; + elsif (!defined $sensors->{'fan-main'}->[2] && $_ =~ /^F?(M\/B|MB|SYS|Motherboard).*:([0-9]+)[\s]RPM/i){ + $sensors->{'fan-main'}->[2] = $2 if $2 < $max_fan; } - elsif (!$sensors->{'fan-main'}->[3] && $_ =~ /F?(Power|P\/S|POWER).*:([0-9]+)[\s]RPM/i){ - $sensors->{'fan-main'}->[3] = $2; + elsif (!defined $sensors->{'fan-main'}->[3] && $_ =~ /F?(Power|P\/S|POWER).*:([0-9]+)[\s]RPM/i){ + $sensors->{'fan-main'}->[3] = $2 if $2 < $max_fan; } - elsif (!$sensors->{'fan-main'}->[4] && $_ =~ /F?(dimm|mem|sodimm).*:([0-9]+)[\s]RPM/i){ - $sensors->{'fan-main'}->[4] = $2; + elsif (!defined $sensors->{'fan-main'}->[4] && $_ =~ /F?(dimm|mem|sodimm).*:([0-9]+)[\s]RPM/i){ + $sensors->{'fan-main'}->[4] = $2 if $2 < $max_fan; } # note that the counters are dynamically set for fan numbers here # otherwise you could overwrite eg aux fan2 with case fan2 in theory # note: cpu/mobo/ps/sodimm are 1/2/3/4 elsif ($_ =~ /^F?(AUX|CASE|CHASSIS|FRONT|REAR).*:([0-9]+)[\s]RPM/i){ + next if $2 > $max_fan; $temp_working = $2; for (my $i = 5; $i < 30; $i++){ next if defined $sensors->{'fan-main'}->[$i]; @@ -23578,9 +23798,10 @@ sub lm_sensors_data { } # in rare cases syntax is like: fan1: xxx RPM elsif ($_ =~ /^FAN(1)?:([0-9]+)[\s]RPM/i){ - $sensors->{'fan-default'}->[1] = $2; + $sensors->{'fan-default'}->[1] = $2 if $2 < $max_fan; } elsif ($_ =~ /^FAN([2-9]|1[0-9]).*:([0-9]+)[\s]RPM/i){ + next if $2 > $max_fan; $fan_working = $2; $sys_fan_nu = $1; if ($sys_fan_nu =~ /^([0-9]+)$/){ @@ -23636,6 +23857,7 @@ sub lm_sensors_data { } } } + print Data::Dumper::Dumper $sensors if $dbg[31]; process_data($sensors) if %$sensors; main::log_data('dump','lm-sensors: %sensors',$sensors) if $b_log; @@ -23694,8 +23916,8 @@ sub load_lm_sensors { elsif ($adapter =~ /^(.*hwmon)-/){ $type = 'hwmon'; } - # ath/iwl: wifi; enp/eno/eth: lan nic - elsif ($adapter =~ /^(ath|iwl|en[op][0-9]|eth)[\S]+-/){ + # ath/iwl: wifi; enp/eno/eth/i350bb: lan nic + elsif ($adapter =~ /^(ath|i350bb|iwl|en[op][0-9]|eth)[\S]+-/){ $type = 'network'; } # put last just in case some other sensor type above had intel in name @@ -23703,7 +23925,7 @@ sub load_lm_sensors { $type = 'gpu'; } elsif ($adapter =~ /^(acpitz)-/ && $adapter !~ /^(acpitz-virtual)-/ ){ - $type = 'board'; + $type = 'acpitz'; } else { $type = 'main'; @@ -23726,6 +23948,159 @@ sub load_lm_sensors { main::log_data('dump','lm-sensors data: %$sensors_raw',$sensors_raw) if $b_log; eval $end if $b_log; } +sub load_sys_data { + eval $start if $b_log; + my ($device,$mon,$name,$label,$unit,$value,@values,%hwmons); + my ($j,$holder,$sensor,$type) = (0,'','',''); + my $glob = '/sys/class/hwmon/hwmon*/'; + $glob .= '{name,device,{curr,fan,in,power,temp}*_{input,label}}'; + my @hwmon = main::globber($glob); + # print Data::Dumper::Dumper \@sensors_data; + @hwmon = sort @hwmon; + push(@hwmon,'END'); + foreach my $item (@hwmon){ + next if ! -e $item; + $item =~ m|/sys/class/hwmon/(hwmon\d+)/|; + $mon = $1; + $mon =~ s/hwmon(\d)$/hwmon0$1/ if $mon =~ /hwmon\d$/; + # if it's a new hwmon, dump all previous data to avoid carry-over + if (!defined $hwmons{$mon}){ + $sensor = ''; + $holder = ''; + $j = 0; + } + if ($item =~ m/([^\/]+)_input$/){ + $sensor = $1; + $value = main::reader($item,'strip',0);; + } + # add the label to the just created _input item, if valid + elsif ($item =~ m/([^\/]+)_label$/){ + print "3: mon: $mon id: $sensor holder: $holder file: $item\n" if $dbg[51]; + # if this doesn't match, something unexpected happened, like no _input for + # _label item. Seen that, real. + next if !$holder || $1 ne $holder; + if (defined $hwmons{$mon}->{'sensors'}[$j]{'id'}){ + $sensor = $1; + $hwmons{$mon}->{'sensors'}[$j]{'label'} = main::reader($item,'strip',0); + } + } + if ($sensor && ($sensor ne $holder || $item eq 'END')){ + print "2: mon: $mon id: $sensor holder: $holder file: $item\n" if $dbg[51]; + # add the item, we'll add label after if it's located since it will be next + # in loop due to sort order. + if ($value){ + push(@{$hwmons{$mon}->{'sensors'}},{ + 'id' => $sensor, + 'value' => $value, + }); + $j = $#{$hwmons{$mon}->{'sensors'}}; + } + $holder = $sensor; + ($sensor,$value) = ('',undef,undef); + } + print "1: mon: $mon id: $sensor holder: $holder file: $item\n" if $dbg[51]; + # print "$item\n"; + if ($item =~ /name$/){ + $name = main::reader($item,'strip',0); + if ($name =~ /^(drive|nvme)/){ + $type = 'disk'; + } + elsif ($name =~ /^(BAT)/i){ + $type = 'bat'; + } + # intel on die io controller, like southbridge/northbridge used to be + elsif ($name =~ /^(pch)/){ + $type = 'pch'; + } + elsif ($name =~ /^(.*hwmon)/){ + $type = 'hwmon'; + } + # ath/iwl: wifi; enp/eno/eth/i350bb: lan nic + elsif ($name =~ /^(ath|i350|iwl|en[op][0-9]|eth)[\S]/){ + $type = 'network'; + } + # put last just in case some other sensor type above had intel in name + elsif ($name =~ /^(amdgpu|intel|nouveau|radeon)/){ + $type = 'gpu'; + } + # not confirmed in /sys that name will be acpitz-virtual, verify + elsif ($name =~ /^(acpitz)/ && $name !~ /^(acpitz-virtual)/ ){ + $type = 'acpitz'; + } + else { + $type = 'main'; + } + $hwmons{$mon}->{'name'} = $name; + $hwmons{$mon}->{'type'} = $type; + } + elsif ($item =~ /device$/){ + $device = readlink($item); + print "device: $device\n" if $dbg[51]; + $device =~ s|^.*/||; + $hwmons{$mon}->{'device'} = $device; + } + } + print '/sys/class/hwmon raw: ', Data::Dumper::Dumper \%hwmons if $dbg[18]; + main::log_data('dump','/sys data raw: %hwmons',\%hwmons) if $b_log; + # $sensors_raw->{$type}{$adapter} = [@values]; + foreach my $hwmon (sort keys %hwmons){ + my $adapter = $hwmons{$hwmon}->{'name'}; + $hwmons{$hwmon}->{'device'} =~ s/^0000://; + $adapter .= '-' . $hwmons{$hwmon}->{'device'}; + @values = (); + foreach my $item (@{$hwmons{$hwmon}->{'sensors'}}){ + my $name = ($item->{'label'}) ? $item->{'label'}: $item->{'id'}; + if ($item->{'id'} =~ /^temp/){ + $unit = 'C'; + $value = sprintf('%0.1f',$item->{'value'}/1000); + } + elsif ($item->{'id'} =~ /^fan/){ + $unit = 'RPM'; + $value = $item->{'value'}; + } + # note: many sensors require further math on value, so these will be wrong + # in many cases since this is not running the math on the results like + # lm-sensors will do if sensors are detected and loaded and configured. + elsif ($item->{'id'} =~ /^in\d/){ + if ($item->{'value'} >= 1000){ + $unit = 'V'; + $value = sprintf('%0.2f',$item->{'value'}/1000) + 0; + if ($hwmons{$hwmon}->{'type'} eq 'main' && $name =~ /^in\d/){ + if ($value >= 10 && $value <= 14){ + $name = '12V'; + } + elsif ($value >= 4 && $value <= 6){ + $name = '5V'; + } + # vbat can be 3, 3.3, but so can 3.3V board + } + } + else { + $unit = 'mV'; + $value = $item->{'value'}; + } + } + elsif ($item->{'id'} =~ /^power/){ + $unit = 'W'; + $value = sprintf('%0.1f',$item->{'value'}/1000); + } + my $string = $name . ':' . $value . " $unit"; + push(@values,$string); + } +# if ($hwmons{$hwmon}->{'type'} eq 'acpitz' && $hwmons{$hwmon}->{'device'}){ +# my $tz ='/sys/class/thermal/' . $hwmons{$hwmon}->{'device'} . '/type'; +# if (-e $tz){ +# my $tz_type = main::reader($tz,'strip',0),"\n"; +# } +# } + if (@values){ + $sensors_raw->{$hwmons{$hwmon}->{'type'}}{$adapter} = [@values]; + } + } + print '/sys/class/hwmon processed: ' , Data::Dumper::Dumper $sensors_raw if $dbg[18]; + main::log_data('dump','/sys data: %$sensors_raw',$sensors_raw) if $b_log; + eval $end if $b_log; +} # bsds sysctl may have hw.sensors data sub sysctl_data { @@ -23734,6 +24109,7 @@ sub sysctl_data { my $sensors = {}; # assume always starts at 0, can't do dynamic because freebsd shows tz1 first my $add = 1; + print Data::Dumper::Dumper $sysctl{'sensor'} if $dbg[18];; foreach (@{$sysctl{'sensor'}}){ my ($sensor,$type,$number,$value); if (/^hw\.sensors\.([a-z]+)([0-9]+)\.(cpu|temp|fan|volt)([0-9])/){ @@ -23776,7 +24152,7 @@ sub sysctl_data { $sensors->{'temp' . $number} = $value; } elsif ($type eq 'fan' && !defined $sensors->{'fan-main'}->[$number]){ - $sensors->{'fan-main'}->[$number] = $value; + $sensors->{'fan-main'}->[$number] = $value if $value < $max_fan; } elsif ($type eq 'volt'){ if ($working =~ /\+3\.3V/i){ @@ -24184,8 +24560,8 @@ sub gpu_sensor_data { elsif (/^[^:]+:([0-9\.]+)\s+W\s/i){ $gpu_data->[$j]{'watts'} = $1; } - elsif (/^[^:]+:([0-9\.]+)\s+mV\s/i){ - $gpu_data->[$j]{'mvolts'} = $1; + elsif (/^[^:]+:([0-9\.]+)\s+(m?V)\s/i){ + $gpu_data->[$j]{'volts-gpu'} = [$1,$2]; } } } @@ -26684,6 +27060,7 @@ sub set_xprop { } +## DeviceData # creates arrays: $devices{'audio'}; $devices{'graphics'}; $devices{'hwraid'}; # $devices{'network'}; $devices{'timer'} and local @devices for logging/debugging # 0 type @@ -27442,6 +27819,24 @@ sub pci_class { } } +# if > 1, returns first found, not going to be too granular with this yet. +sub get_device_temp { + eval $start if $b_log; + my $bus_id = $_[0]; + my $glob = "/sys/devices/pci*/*/*:$bus_id/hwmon/hwmon*/temp*_input"; + my @files = main::globber($glob); + my $temp; + foreach my $file (@files){ + $temp = main::reader($file,'strip',0); + if ($temp){ + $temp = sprintf('%0.1f',$temp/1000); + last; + } + } + eval $end if $b_log; + return $temp; +} + ## DiskDataBSD # handles disks and partition extra data for disks bsd, raid-zfs, # partitions, swap, unmounted |
