From b35054355994cae0ce0561b80df38217b65397d5 Mon Sep 17 00:00:00 2001 From: Unit 193 Date: Sat, 7 Sep 2024 17:59:41 -0400 Subject: New upstream version 3.3.36-1. --- inxi | 2582 ++++++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 1420 insertions(+), 1162 deletions(-) (limited to 'inxi') diff --git a/inxi b/inxi index bd3e545..b400b92 100755 --- a/inxi +++ b/inxi @@ -49,8 +49,8 @@ use POSIX qw(ceil uname strftime ttyname); ## INXI INFO ## my $self_name='inxi'; -my $self_version='3.3.35'; -my $self_date='2024-06-18'; +my $self_version='3.3.36'; +my $self_date='2024-09-04'; my $self_patch='00'; ## END INXI INFO ## @@ -208,7 +208,7 @@ sub initialize { set_display_size(); } -## CheckTools +## CheckTools ## { package CheckTools; my (%commands); @@ -901,7 +901,7 @@ sub set_colors { eval $end if $b_log; } -## SelectColors +## SelectColors ## { package SelectColors; my (@data,%configs,%status); @@ -1546,7 +1546,7 @@ sub set_debugger { } } -## SystemDebugger +## SystemDebugger ## { package SystemDebugger; my $option = 'main'; @@ -2018,6 +2018,7 @@ sub display_data { ['swaymsg','-t get_tree'], ['swaymsg','-t get_workspaces -p'], ['swaymsg','-t get_workspaces -r'], + ['switcherooctl','list'], ['twin','--version'], # TDE ['vainfo',''], ['vdpauinfo',''], @@ -2975,6 +2976,8 @@ sub error_handler { $errno=60; "Downloader program $two could not be located on your system." } elsif ($err eq 'missing-perl-downloader'){ $errno=61; $b_recommends=1; "Perl downloader missing required module." } + elsif ($err eq 'no-downloader'){ + $errno=62; $b_recommends=1; "No downloader program located on your system." } ## FTP elsif ($err eq 'ftp-bad-path'){ $errno=70; "Unable to locate for FTP upload file:\n$one" } @@ -3018,7 +3021,7 @@ sub error_defaults { #### RECOMMENDS #### ------------------------------------------------------------------- -## CheckRecommends +## CheckRecommends ## { package CheckRecommends; my ($item_data,@modules,@pms); @@ -3108,15 +3111,15 @@ sub check_items { elsif ($type eq 'recommended system programs'){ if ($bsd_type){ @data = qw(camcontrol dig disklabel dmidecode doas fdisk file glabel gpart - ifconfig ipmi-sensors ipmitool pciconfig pcidump pcictl smartctl sudo + ifconfig ipmi-sensors ipmitool pciconfig pcidump pcictl ps smartctl sudo sysctl tree upower uptime usbconfig usbdevs); $info_os = 'info-bsd'; } else { @data = qw(blockdev bt-adapter btmgmt dig dmidecode doas fdisk file fruid_print hciconfig hddtemp ifconfig ip ipmitool ipmi-sensors lsblk - lsusb lvs mdadm modinfo runlevel sensors smartctl strings sudo tree - udevadm upower uptime); + lspci lsusb lvs mdadm modinfo ps runlevel sensors smartctl strings sudo + tree udevadm upower uptime); } $b_program = 1; $item = 'Program'; @@ -3480,7 +3483,7 @@ sub set_item_data { 'rpm' => 'hddtemp', }, 'ifconfig' => { - 'info' => '-i ip LAN (deprecated)', + 'info' => '-i ip LAN (deprecated, ip preferred)', 'info-bsd' => '-i ip LAN', 'apt' => 'net-tools', 'pacman' => 'net-tools', @@ -3519,22 +3522,30 @@ sub set_item_data { 'pkgtool' => 'util-linux', 'rpm' => 'util-linux-ng', }, - 'lvs' => { - 'info' => '-L LVM data', + 'lspci' => { + 'info' => '-A,-E,-G,-N,-R PCI Device data (/sys supplies much)', 'info-bsd' => '', - 'apt' => 'lvm2', - 'pacman' => 'lvm2', - 'pkgtool' => 'lvm2', - 'rpm' => 'lvm2', + 'apt' => 'pciutils', + 'pacman' => 'pciutils', + 'pkgtool' => 'pciutils', + 'rpm' => 'pciutils', }, 'lsusb' => { - 'info' => '-A usb audio; -J (optional); -N usb networking', + 'info' => '-A,-E,-G,-J,-N USB Device data (/sys supplies much)', 'info-bsd' => '', 'apt' => 'usbutils', 'pacman' => 'usbutils', 'pkgtool' => 'usbutils', 'rpm' => 'usbutils', }, + 'lvs' => { + 'info' => '-L LVM data', + 'info-bsd' => '', + 'apt' => 'lvm2', + 'pacman' => 'lvm2', + 'pkgtool' => 'lvm2', + 'rpm' => 'lvm2', + }, 'mdadm' => { 'info' => '-Ra advanced mdraid data', 'info-bsd' => '', @@ -3563,6 +3574,14 @@ sub set_item_data { 'info' => '', 'info-bsd' => '-A,-E,-G,-N pci devices (OpenBSD+derived, doas/su)', }, + 'ps' => { + 'info' => '-G,-I,-n,-S,-t process/programs', + 'info-bsd' => '-G,-I,-n,-S,-t process/programs', + 'apt' => 'procps', + 'pacman' => 'procps', + 'pkgtool' => 'procps', + 'rpm' => 'procps', + }, 'runlevel' => { 'info' => '-I fallback to Perl', 'info-bsd' => '', @@ -4201,6 +4220,10 @@ sub update_me { error_handler('not-writable', "$self_name", ''); } $output .= "Starting $self_name self updater.\n"; + if (!$dl{'dl'}){ + print $output; + main::error_handler('no-downloader'); + } $output .= "Using $dl{'dl'} as downloader.\n"; $output .= "Currently running $self_name version number: $self_version\n"; $output .= "Current version patch number: $self_patch\n"; @@ -4370,7 +4393,7 @@ sub set_version_data { #### OPTIONS HANDLER / VERSION ######################################################################## -## OptionsHandler +## OptionsHandler ## { package OptionsHandler; # Note: used %trigger here, but perl 5.008 had issues, so mmoved to global. @@ -5756,9 +5779,9 @@ sub show_options { found); list of installed tools for servers."], ['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) + speeds (dmidecode+root/sudo/doas required); Full topology line, with dies, + clusters, 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 mode (if found); USB drive specifics; SMART report."], @@ -5837,7 +5860,7 @@ sub show_options { ['2', '44', '', "Bypass Curl, Fetch, and Wget as downloader options. Forces Perl if HTTP::Tiny present."], ['1', '', '--bt-tool', "[bt-adapter btmgmt hciconfig rfkill] Force use of - given tool forbluetooth report. Or use --force [tool]."], + given tool for bluetooth report. Or use --force [tool]."], ['1', '', '--dig', "Overrides configuration item NO_DIG (resets to default)."], ['1', '', '--display', "[:[0-9]] Try to get display data out of X (default: display 0)."], @@ -5999,7 +6022,7 @@ sub show_version { #### STARTUP DATA ######################################################################## -## StartClient +## StartClient ## { package StartClient; # use warnings; @@ -6179,7 +6202,7 @@ sub get_client_version { # show no tty are actually IRC. tmux is not a vt, but runs inside one if (!$client{'name-print'}){ my $wl_terms = 'alacritty|altyo|\bate\b|black-screen|conhost|doas|evilvte|'; - $wl_terms .= 'foot|germinal|guake|havoc|hyper|kate|kitty|kmscon|konsole|'; + $wl_terms .= 'foot|germinal|guake|havoc|hyper|kate|kgx|kitty|kmscon|konsole|'; $wl_terms .= 'login|macwise|minicom|putty|rxvt|sakura|securecrt|'; $wl_terms .= 'shellinabox|^st$|sudo|term|tilda|tilix|tmux|tym|wayst|xiki|'; $wl_terms .= 'yaft|yakuake|\bzoc\b'; @@ -6485,25 +6508,23 @@ sub filter { } # Note, let the print logic handle N/A cases +# args: 0: type; 1: string, by reference; 2: test value for system sub filter_partition { - my ($source,$string,$type) = @_; - return $string if !$string || $string eq 'N/A'; - if ($source eq 'system'){ - my $test = ($type eq 'label') ? '=LABEL=': '=UUID='; - $string =~ s/$test[^\s]+/$test$filter_string/g; + return if !$_[1] || !${$_[1]} || ${$_[1]} eq 'N/A'; + if ($_[0]eq 'system'){ + ${$_[1]} =~ s/${_[2]}[^\s]+/${_[2]}$filter_string/g; } else { - $string = $filter_string; + ${$_[1]} = $filter_string; } - return $string; } +# note these are tested before being sent so no need to test for null +# args: 0: string to filter. by reference sub filter_pci_long { - my ($string) = @_; - if ($string =~ /\[AMD(\/ATI)?\]/){ - $string =~ s/Advanced\sMicro\sDevices\s\[AMD(\/ATI)?\]/AMD/; + if ($_[0] =~ /\[AMD(\/ATI)?\]/){ + ${$_[0]} =~ s/Advanced\sMicro\sDevices\s\[AMD(\/ATI)?\]/AMD/; } - return $string; } # args: 0: list of values. Return the first one that is defined. @@ -7327,7 +7348,7 @@ sub print_line { #### ITEM GENERATORS #### ------------------------------------------------------------------- -## AudioItem +## AudioItem ## { package AudioItem; @@ -7377,7 +7398,7 @@ sub device_output { $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){ - $device = main::filter_pci_long($device); + main::filter_pci_long(\$device); } push(@$rows, { main::key($num++,1,1,'Device') => $device, @@ -7906,7 +7927,7 @@ sub sound_tools { } } -## BatteryItem +## BatteryItem ## { package BatteryItem; my (@upower_items,$b_upower,$upower); @@ -8453,7 +8474,7 @@ sub upower_data { } } -## BluetoothItem +## BluetoothItem ## { package BluetoothItem; my ($b_bluetooth,$b_hci_error,$b_hci,$b_rfk,$b_service); @@ -8509,7 +8530,7 @@ sub device_output { $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){ - $device = main::filter_pci_long($device); + main::filter_pci_long(\$device); } push(@$rows, { main::key($num++,1,1,'Device') => $device, @@ -9022,7 +9043,7 @@ sub bluetooth_version { } } -## CpuItem +## CpuItem ## { package CpuItem; my (%fake_data,$type); @@ -9062,9 +9083,9 @@ sub full_output { my ($key1,$val1) = ('',''); if ($alerts{'sysctl'}){ if ($alerts{'sysctl'}->{'action'} eq 'use'){ -# $key1 = 'Status'; -# $val1 = main::message('dev'); - $cpu = sysctl_data(); + # $key1 = 'Status'; + # $val1 = main::message('dev'); + $cpu = cpu_sysctl_data(); } else { $key1 = ucfirst($alerts{'sysctl'}->{'action'}); @@ -9088,7 +9109,7 @@ sub full_output { my $counter = (%system_cpus && scalar keys %system_cpus > 1) ? '-' : ''; foreach my $key (keys %system_cpus){ $counter = '-' . $i++ if $counter; - $rows->[$j]{main::key($num++,0,2,'variant'.$counter)} = $key; + $rows->[$j]{main::key($num++,0,2,'variant' . $counter)} = $key; } } if ($b_admin && $properties->{'socket'}){ @@ -9175,7 +9196,16 @@ sub full_output { } my $x = ($size{'max-cols'} == 1 || $output_type ne 'screen') ? '' : 'x'; $rows->[$j]{main::key($num++,0,$id,'cpus')} = $topo->{'cpus'} . $x; + if ($topo->{'dies-count'}){ + $rows->[$j]{main::key($num++,0,$id+1,'dies')} = $topo->{'dies-count'}; + } + if ($topo->{'clusters'}){ + $rows->[$j]{main::key($num++,0,$id+1,'clusters')} = $topo->{'clusters'}; + } $rows->[$j]{main::key($num++,1,$id+1,'cores')} = $topo->{'cores'}; + if ($topo->{'threads'}){ + $rows->[$j]{main::key($num++,0,$id+1,'threads')} = $topo->{'threads'}; + } if ($topo->{'cores-mt'} && $topo->{'cores-st'}){ $rows->[$j]{main::key($num++,1,$id+2,'mt')} = $topo->{'cores-mt'}; $rows->[$j]{main::key($num++,0,$id+3,'tpc')} = $topo->{'tpc'}; @@ -9200,12 +9230,7 @@ sub full_output { } $rows->[$j]{main::key($num++,0,$id+1,$key)} = $freq; } - if ($topo->{'threads'}){ - $rows->[$j]{main::key($num++,0,$id+1,'threads')} = $topo->{'threads'}; - } - if ($topo->{'dies'}){ - $rows->[$j]{main::key($num++,0,$id+1,'dies')} = $topo->{'dies'}; - } + } $cpu->{'smt'} ||= 'N/A'; $rows->[$j]{main::key($num++,0,2,'smt')} = $cpu->{'smt'}; @@ -9426,9 +9451,9 @@ sub short_data { my ($key1,$val1) = ('',''); if ($alerts{'sysctl'}){ if ($alerts{'sysctl'}->{'action'} eq 'use'){ -# $key1 = 'Status'; -# $val1 = main::message('dev'); - $cpu = sysctl_data($type); + # $key1 = 'Status'; + # $val1 = main::message('dev'); + $cpu = cpu_sysctl_data($type); } else { $key1 = ucfirst($alerts{'sysctl'}->{'action'}); @@ -9472,15 +9497,155 @@ sub prep_short_data { return $result; } -## PRIMARY DATA GENERATORS ## +## CPUINFO/SYS DATA GENERATORS ## + +## DEBUGGER DATA +# Set in one place to make sure we get them all consistent +sub set_fake_cpu_data { + $loaded{'cpu-fake-data'} = 1; + my ($ci,$sys); + ## CPUINFO DATA FILES ## + ## ARM/MIPS + # $ci = "$fake_data_dir/cpu/arm/arm-4-core-pinebook-1.txt"; + # $ci = "$fake_data_dir/cpu/arm/armv6-single-core-1.txt"; + # $ci = "$fake_data_dir/cpu/arm/armv7-dual-core-1.txt"; + # $ci = "$fake_data_dir/cpu/arm/armv7-new-format-model-name-single-core.txt"; + # $ci = "$fake_data_dir/cpu/arm/arm-2-die-96-core-rk01.txt"; + # $ci = "$fake_data_dir/cpu/arm/arm-shevaplug-1.2ghz.txt"; + # $ci = "$fake_data_dir/cpu/mips/mips-mainusg-cpuinfo.txt"; + # $ci = "$fake_data_dir/cpu/ppc/ppc-debian-ppc64-cpuinfo.txt"; + ## x86 + # $ci = "$fake_data_dir/cpu/amd/16-core-32-mt-ryzen.txt"; + # $ci = "$fake_data_dir/cpu/amd/2-16-core-epyc-abucodonosor.txt"; + # $ci = "$fake_data_dir/cpu/amd/2-core-probook-antix.txt"; + # $ci = "$fake_data_dir/cpu/amd/4-core-jean-antix.txt"; + # $ci = "$fake_data_dir/cpu/amd/4-core-althlon-mjro.txt"; + # $ci = "$fake_data_dir/cpu/amd/4-core-apu-vc-box.txt"; + # $ci = "$fake_data_dir/cpu/amd/4-core-a10-5800k-1.txt"; + # $ci = "$fake_data_dir/cpu/intel/1-core-486-fourtysixandtwo.txt"; + # $ci = "$fake_data_dir/cpu/intel/2-core-ht-atom-bruh.txt"; + # $ci = "$fake_data_dir/cpu/intel/core-2-i3.txt"; + # $ci = "$fake_data_dir/cpu/intel/8-core-i7-damentz64.txt"; + # $ci = "$fake_data_dir/cpu/intel/2-10-core-xeon-ht.txt"; + # $ci = "$fake_data_dir/cpu/intel/4-core-xeon-fake-dual-die-zyanya.txt"; + # $ci = "$fake_data_dir/cpu/intel/2-core-i5-fake-dual-die-hek.txt"; + # $ci = "$fake_data_dir/cpu/intel/2-1-core-xeon-vm-vs2017.txt"; + # $ci = "$fake_data_dir/cpu/intel/4-1-core-xeon-vps-frodo1.txt"; + # $ci = "$fake_data_dir/cpu/intel/4-6-core-xeon-no-mt-lathander.txt"; + ## Elbrus + # $cpu_type = 'elbrus'; # uncomment to test elbrus + # $ci = "$fake_data_dir/cpu/elbrus/elbrus-2c3/cpuinfo.txt"; + # $ci = "$fake_data_dir/cpu/elbrus/1xE1C-8.txt"; + # $ci = "$fake_data_dir/cpu/elbrus/1xE2CDSP-4.txt"; + # $ci = "$fake_data_dir/cpu/elbrus/1xE2S4-3-monocub.txt"; + # $ci = "$fake_data_dir/cpu/elbrus/1xMBE8C-7.txt"; + # $ci = "$fake_data_dir/cpu/elbrus/4xEL2S4-3.txt"; + # $ci = "$fake_data_dir/cpu/elbrus/4xE8C-7.txt"; + # $ci = "$fake_data_dir/cpu/elbrus/4xE2CDSP-4.txt"; + # $ci = "$fake_data_dir/cpu/elbrus/cpuinfo.e8c2.txt"; + ## Loongson + # $cpu_type = 'elbrus'; # uncomment to test loongson + # $ci = "$fake_data_dir/cpu/loongson/3A5000M-4-core-4.19.0.txt"; + + ## CPU CPUINFO/SYS PAIRS DATA FILES ## + # $ci = "$fake_data_dir/cpu/sys-ci-pairs/android-pocom3-fake-cpuinfo.txt"; + # $sys = "$fake_data_dir/cpu/sys-ci-pairs/android-pocom3-fake-sys.txt"; + # $ci = "$fake_data_dir/cpu/sys-ci-pairs/arm-pine64-cpuinfo-1.txt"; + # $sys = "$fake_data_dir/cpu/sys-ci-pairs/arm-pine64-sys-1.txt"; + # $ci = "$fake_data_dir/cpu/sys-ci-pairs/arm-riscyslack2-cpuinfo-1.txt"; + # $sys = "$fake_data_dir/cpu/sys-ci-pairs/arm-riscyslack2-sys-1.txt"; + # $ci = "$fake_data_dir/cpu/sys-ci-pairs/ppc-stuntkidz~cpuinfo.txt"; + # $sys = "$fake_data_dir/cpu/sys-ci-pairs/ppc-stuntkidz~sys.txt"; + # $ci = "$fake_data_dir/cpu/sys-ci-pairs/riscv-unmatched-2021~cpuinfo-1.txt"; + # $sys = "$fake_data_dir/cpu/sys-ci-pairs/riscv-unmatched-2021~sys-1.txt"; + # $ci = "$fake_data_dir/cpu/sys-ci-pairs/x86-brickwizard-atom-n270~cpuinfo-1.txt"; + # $sys = "$fake_data_dir/cpu/sys-ci-pairs/x86-brickwizard-atom-n270~sys-1.txt"; + # $ci = "$fake_data_dir/cpu/sys-ci-pairs/x86-amd-phenom-chrisretusn-cpuinfo-1.txt"; + # $sys = "$fake_data_dir/cpu/sys-ci-pairs/x86-amd-phenom-chrisretusn-sys-1.txt"; + # $ci = "$fake_data_dir/cpu/sys-ci-pairs/x86-drgibbon-intel-i7-cpuinfo.txt"; + # $sys = "$fake_data_dir/cpu/sys-ci-pairs/x86-drgibbon-intel-i7-sys.txt"; + # $ci = "$fake_data_dir/cpu/sys-ci-pairs/ryzen-threadripper-1x64-3950x-cpuinfo.txt"; + # $sys = "$fake_data_dir/cpu/sys-ci-pairs/ryzen-threadripper-1x64-3950x-sys.txt"; + # $ci = "$fake_data_dir/cpu/sys-ci-pairs/amd-threadripper-1x12-5945wx-cpuinfo-1.txt"; + # $sys = "$fake_data_dir/cpu/sys-ci-pairs/amd-threadripper-1x12-5945wx-sys-1.txt"; + # $ci = "$fake_data_dir/cpu/sys-ci-pairs/intel-i7-1165G7-4-core-no-smt-cpuinfo.txt"; + # $sys = "$fake_data_dir/cpu/sys-ci-pairs/intel-i7-1165G7-4-core-no-smt-sys.txt"; + # $ci = "$fake_data_dir/cpu/sys-ci-pairs/elbrus-e16c-1-cpuinfo.txt"; + # $sys = "$fake_data_dir/cpu/sys-ci-pairs/elbrus-e16c-1-sys.txt"; + # $ci = "$fake_data_dir/cpu/sys-ci-pairs/intel-raptor-lake-10-core-cpuinfo-1.txt"; + # $sys = "$fake_data_dir/cpu/sys-ci-pairs/intel-raptor-lake-10-core-sys-1.txt"; + # $ci = "$fake_data_dir/cpu/sys-ci-pairs/risc-v-spacemit-8-core-cpuinfo.txt"; + # $sys = "$fake_data_dir/cpu/sys-ci-pairs/risc-v-spacemit-8-core-sys.txt"; + # $ci = "$fake_data_dir/cpu/sys-ci-pairs/intel-xeon-2x12-core-mt-cpuinfo-1.txt"; + # $sys = "$fake_data_dir/cpu/sys-ci-pairs/intel-xeon-2x12-core-mt-sys-1.txt"; + $ci = "$fake_data_dir/cpu/sys-ci-pairs/amd-epyc-2x-16-core-4-die-cpuinfo-1.txt"; + $sys = "$fake_data_dir/cpu/sys-ci-pairs/amd-epyc-2x-16-core-4-die-sys-1.txt"; + $fake_data{'cpuinfo'} = $ci; + $fake_data{'sys'} = $sys; +} + +## CPUINFO DATA +sub cpuinfo_data_grabber { + eval $start if $b_log; + my ($file,$cpu_type) = @_; # type by ref + $loaded{'cpuinfo'} = 1; + # use --arm flag when testing arm cpus, and --fake-cpu to trigger fake data + $file = $fake_data{'cpuinfo'} if $fake{'cpu'}; + my $raw = main::reader($file,'','ref'); + @$raw = map {$_ =~ s/^\s*$/~~~/;$_;} @$raw; + push(@$raw,'~~~') if @$raw; + my ($b_processor,$key,$value); + my ($i) = (0); + my @key_tests = ('firmware','hardware','mmu','model','motherboard', + 'platform','system type','timebase'); + foreach my $row (@$raw){ + ($key,$value) = split(/\s*:\s*/,$row,2); + next if !defined $key; + # ARM: 'Hardware' can appear in processor block; system type (mips) + # ARM: CPU revision; machine: Revision/PPC: revision (CPU implied) + # orangepi3 has Hardware/Processor embedded in processor block + if (%risc && ((grep {lc($key) eq $_} @key_tests) || + (!$risc{'ppc'} && lc($key) eq 'revision'))){ + $b_processor = 0; + } + else { + $b_processor = 1; + } + if ($b_processor){ + if ($key eq '~~~'){ + $i++; + next; + } + # A small handful of ARM devices use Processor instead of 'model name' + # Processor : AArch64 Processor rev 4 (aarch64) + # Processor : Feroceon 88FR131 rev 1 (v5l) + $key = ($key eq 'Processor') ? 'model name' : lc($key); + $cpuinfo[$i]->{$key} = $value; + } + else { + next if $cpuinfo_machine{lc($key)}; + $cpuinfo_machine{lc($key)} = $value; + } + } + if ($b_log){ + main::log_data('dump','@cpuinfo',\@cpuinfo); + main::log_data('dump','%cpuinfo_machine',\%cpuinfo_machine); + } + if ($dbg[41]){ + print Data::Dumper::Dumper \@cpuinfo; + print Data::Dumper::Dumper \%cpuinfo_machine; + } + eval $end if $b_log; +} + sub cpuinfo_data { eval $start if $b_log; my ($file)= @_; my ($cpu,$arch,$note,$temp); # has to be set above fake cpu section set_cpu_data(\$cpu); - set_fake_data() if $fake{'cpu'} && !$loaded{'cpu-fake-data'}; - # sleep is also set in front of sysctl_data for BSDs, same idea + set_fake_cpu_data() if $fake{'cpu'} && !$loaded{'cpu-fake-data'}; + # sleep is also set in front of cpu_sysctl_data for BSDs, same idea my $sleep = $cpu_sleep * 1000000; if ($b_hires){ eval 'Time::HiRes::usleep($sleep)'; @@ -9772,236 +9937,11 @@ sub cpuinfo_speed_sys { eval $end if $b_log; } -sub cpuinfo_data_grabber { - eval $start if $b_log; - my ($file,$cpu_type) = @_; # type by ref - $loaded{'cpuinfo'} = 1; - # use --arm flag when testing arm cpus, and --fake-cpu to trigger fake data - $file = $fake_data{'cpuinfo'} if $fake{'cpu'}; - my $raw = main::reader($file,'','ref'); - @$raw = map {$_ =~ s/^\s*$/~~~/;$_;} @$raw; - push(@$raw,'~~~') if @$raw; - my ($b_processor,$key,$value); - my ($i) = (0); - my @key_tests = ('firmware','hardware','mmu','model','motherboard', - 'platform','system type','timebase'); - foreach my $row (@$raw){ - ($key,$value) = split(/\s*:\s*/,$row,2); - next if !defined $key; - # ARM: 'Hardware' can appear in processor block; system type (mips) - # ARM: CPU revision; machine: Revision/PPC: revision (CPU implied) - # orangepi3 has Hardware/Processor embedded in processor block - if (%risc && ((grep {lc($key) eq $_} @key_tests) || - (!$risc{'ppc'} && lc($key) eq 'revision'))){ - $b_processor = 0; - } - else { - $b_processor = 1; - } - if ($b_processor){ - if ($key eq '~~~'){ - $i++; - next; - } - # A small handful of ARM devices use Processor instead of 'model name' - # Processor : AArch64 Processor rev 4 (aarch64) - # Processor : Feroceon 88FR131 rev 1 (v5l) - $key = ($key eq 'Processor') ? 'model name' : lc($key); - $cpuinfo[$i]->{$key} = $value; - } - else { - next if $cpuinfo_machine{lc($key)}; - $cpuinfo_machine{lc($key)} = $value; - } - } - if ($b_log){ - main::log_data('dump','@cpuinfo',\@cpuinfo); - main::log_data('dump','%cpuinfo_machine',\%cpuinfo_machine); - } - if ($dbg[41]){ - print Data::Dumper::Dumper \@cpuinfo; - print Data::Dumper::Dumper \%cpuinfo_machine; - } - eval $end if $b_log; -} - -sub cpu_sys_data { - eval $start if $b_log; - my $sys_freq = $_[0]; - my $cpu_sys = {}; - my $working = sys_data_grabber(); - return $cpu_sys if !%$working; - $cpu_sys->{'data'} = $working->{'data'} if $working->{'data'}; - my ($core_id,$fake_core_id,$phys_id,) = (0,0,-1); - my (%cache_ids,@ci_freq_max,@ci_freq_min,@sc_freq_max,@sc_freq_min); - foreach my $key (sort keys %{$working->{'cpus'}}){ - ($core_id,$phys_id) = (0,0); - my $cpu_id = $key + 0; - my $speed; - my $cpu = $working->{'cpus'}{$key}; - if (defined $cpu->{'topology'}{'physical_package_id'}){ - $phys_id = sprintf("%04d",$cpu->{'topology'}{'physical_package_id'}); - } - if (defined $cpu->{'topology'}{'core_id'}){ - # id is not consistent, seen 5 digit id - $core_id = sprintf("%08d",$cpu->{'topology'}{'core_id'}); - if ($fake{'cpu'}){ - if (defined $cpu->{'cpufreq'}{'scaling_cur_freq'} && - $cpu->{'cpufreq'}{'affected_cpus'} && - $cpu->{'cpufreq'}{'affected_cpus'} ne 'UNDEFINED' && - # manually generated cpu debuggers will show '', not UNDEFINED - $cpu->{'cpufreq'}{'affected_cpus'} ne ''){ - $speed = clean_speed($cpu->{'cpufreq'}{'scaling_cur_freq'},'khz'); - } - } - elsif (defined $sys_freq && defined $sys_freq->{$key}){ - $speed = $sys_freq->{$key}; - } - if (defined $speed){ - push(@{$cpu_sys->{'cpus'}{$phys_id}{'cores'}{$core_id}},$speed); - push(@{$cpu_sys->{'data'}{'speeds'}{'all'}},$speed); - } - else { - push(@{$cpu_sys->{'data'}{'speeds'}{'all'}},0); - # seen cases, riscv, where core id, phys id, are all -1 - my $id = ($core_id != -1) ? $core_id: $fake_core_id++; - push(@{$cpu_sys->{'cpus'}{$phys_id}{'cores'}{$id}},0); - } - # Only use if topology core-id exists, some virtualized cpus can list - # frequency data for the non available cores, but those do not show - # topology data. - # For max / min, we want to prep for the day 1 pys cpu has > 1 min/max freq - if (defined $cpu->{'cpufreq'}{'cpuinfo_max_freq'}){ - $cpu->{'cpufreq'}{'cpuinfo_max_freq'} = clean_speed($cpu->{'cpufreq'}{'cpuinfo_max_freq'},'khz'); - if (!grep {$_ eq $cpu->{'cpufreq'}{'cpuinfo_max_freq'}} @ci_freq_max){ - push(@ci_freq_max,$cpu->{'cpufreq'}{'cpuinfo_max_freq'}); - } - if (!grep {$_ eq $cpu->{'cpufreq'}{'cpuinfo_max_freq'}} @{$cpu_sys->{'cpus'}{$phys_id}{'max-freq'}}){ - push(@{$cpu_sys->{'cpus'}{$phys_id}{'max-freq'}},$cpu->{'cpufreq'}{'cpuinfo_max_freq'}); - } - } - if (defined $cpu->{'cpufreq'}{'cpuinfo_min_freq'}){ - $cpu->{'cpufreq'}{'cpuinfo_min_freq'} = clean_speed($cpu->{'cpufreq'}{'cpuinfo_min_freq'},'khz'); - if (!grep {$_ eq $cpu->{'cpufreq'}{'cpuinfo_min_freq'}} @ci_freq_min){ - push(@ci_freq_min,$cpu->{'cpufreq'}{'cpuinfo_min_freq'}); - } - if (!grep {$_ eq $cpu->{'cpufreq'}{'cpuinfo_min_freq'}} @{$cpu_sys->{'cpus'}{$phys_id}{'min-freq'}}){ - push(@{$cpu_sys->{'cpus'}{$phys_id}{'min-freq'}},$cpu->{'cpufreq'}{'cpuinfo_min_freq'}); - } - } - if (defined $cpu->{'cpufreq'}{'scaling_max_freq'}){ - $cpu->{'cpufreq'}{'scaling_max_freq'} = clean_speed($cpu->{'cpufreq'}{'scaling_max_freq'},'khz'); - if (!grep {$_ eq $cpu->{'cpufreq'}{'scaling_max_freq'}} @sc_freq_max){ - push(@sc_freq_max,$cpu->{'cpufreq'}{'scaling_max_freq'}); - } - if (!grep {$_ eq $cpu->{'cpufreq'}{'scaling_max_freq'}} @{$cpu_sys->{'cpus'}{$phys_id}{'max-freq'}}){ - push(@{$cpu_sys->{'cpus'}{$phys_id}{'max-freq'}},$cpu->{'cpufreq'}{'scaling_max_freq'}); - } - } - if (defined $cpu->{'cpufreq'}{'scaling_min_freq'}){ - $cpu->{'cpufreq'}{'scaling_min_freq'} = clean_speed($cpu->{'cpufreq'}{'scaling_min_freq'},'khz'); - if (!grep {$_ eq $cpu->{'cpufreq'}{'scaling_min_freq'}} @sc_freq_min){ - push(@sc_freq_min,$cpu->{'cpufreq'}{'scaling_min_freq'}); - } - if (!grep {$_ eq $cpu->{'cpufreq'}{'scaling_min_freq'}} @{$cpu_sys->{'cpus'}{$phys_id}{'min-freq'}}){ - push(@{$cpu_sys->{'cpus'}{$phys_id}{'min-freq'}},$cpu->{'cpufreq'}{'scaling_min_freq'}); - } - } - if (defined $cpu->{'cpufreq'}{'scaling_governor'}){ - if (!grep {$_ eq $cpu->{'cpufreq'}{'scaling_governor'}} @{$cpu_sys->{'cpus'}{$phys_id}{'governor'}}){ - push(@{$cpu_sys->{'cpus'}{$phys_id}{'governor'}},$cpu->{'cpufreq'}{'scaling_governor'}); - } - } - if (defined $cpu->{'cpufreq'}{'scaling_driver'}){ - $cpu_sys->{'cpus'}{$phys_id}{'scaling-driver'} = $cpu->{'cpufreq'}{'scaling_driver'}; - } - } - if (!defined $cpu_sys->{'data'}{'cpufreq-boost'} && defined $cpu->{'cpufreq'}{'cpb'}){ - $cpu_sys->{'data'}{'cpufreq-boost'} = $cpu->{'cpufreq'}{'cpb'}; - } - if (defined $cpu->{'topology'}{'core_cpus_list'}){ - $cpu->{'topology'}{'thread_siblings_list'} = $cpu->{'topology'}{'core_cpus_list'}; - } - if (defined $cpu->{'cache'} && keys %{$cpu->{'cache'}} > 0){ - foreach my $key2 (sort keys %{$cpu->{'cache'}}){ - my $cache = $cpu->{'cache'}{$key2}; - my $type = ($cache->{'type'} =~ /^([DI])/i) ? lc($1): ''; - my $level = 'l' . $cache->{'level'} . $type; - # Very old systems, 2.6.xx do not have shared_cpu_list - if (!defined $cache->{'shared_cpu_list'} && defined $cache->{'shared_cpu_map'}){ - $cache->{'shared_cpu_list'} = $cache->{'shared_cpu_map'}; - } - # print Data::Dumper::Dumper $cache; - if (defined $cache->{'shared_cpu_list'}){ - # not needed, the cpu is always in the range - # my $range = main::regex_range($cache->{'shared_cpu_list'}); - my $size = main::translate_size($cache->{'size'}); - # print "cpuid: $cpu_id phys-core: $phys_id-$core_id level: $level range: $range shared: $cache->{'shared_cpu_list'}\n"; - if (!(grep {$_ eq $cache->{'shared_cpu_list'}} @{$cache_ids{$phys_id}->{$level}})){ - push(@{$cache_ids{$phys_id}->{$level}},$cache->{'shared_cpu_list'}); - push(@{$cpu_sys->{'cpus'}{$phys_id}{'caches'}{$level}},$size); - } - } - } - } - # die_id is relatively new, core_siblings_list has been around longer - if (defined $cpu->{'topology'}{'die_id'} || - defined $cpu->{'topology'}{'core_siblings_list'}){ - my $die = $cpu->{'topology'}{'die_id'}; - $die = $cpu->{'topology'}{'core_siblings_list'} if !defined $die; - if (!grep {$_ eq $die} @{$cpu_sys->{'cpus'}{$phys_id}{'dies'}}){ - push(@{$cpu_sys->{'cpus'}{$phys_id}{'dies'}},$die); - } - } - } - if (defined $cpu_sys->{'data'}{'cpufreq-boost'} && - $cpu_sys->{'data'}{'cpufreq-boost'} =~ /^[01]$/){ - if ($cpu_sys->{'data'}{'cpufreq-boost'}){ - $cpu_sys->{'data'}{'cpufreq-boost'} = 'enabled'; - } - else { - $cpu_sys->{'data'}{'cpufreq-boost'} = 'disabled'; - } - } - # cpuinfo_max_freq:["2000000"] cpuinfo_max_freq:["1500000"] - # cpuinfo_min_freq:["200000"] - if (@ci_freq_max){ - $cpu_sys->{'data'}{'speeds'}{'max-freq'} = join(':',@ci_freq_max); - } - if (@ci_freq_min){ - $cpu_sys->{'data'}{'speeds'}{'min-freq'} = join(':',@ci_freq_min); - } - # also handle off chance that cpuinfo_min/max not set, but scaling_min/max there - if (@sc_freq_max){ - $cpu_sys->{'data'}{'speeds'}{'scaling-max-freq'} = join(':',@sc_freq_max); - if (!$cpu_sys->{'data'}{'speeds'}{'max-freq'}){ - $cpu_sys->{'data'}{'speeds'}{'max-freq'} = $cpu_sys->{'data'}{'speeds'}{'scaling-max-freq'}; - } - } - if (@sc_freq_min){ - $cpu_sys->{'data'}{'speeds'}{'scaling-min-freq'} = join(':',@sc_freq_min); - if (!$cpu_sys->{'data'}{'speeds'}{'min-freq'}){ - $cpu_sys->{'data'}{'speeds'}{'min-freq'} = $cpu_sys->{'data'}{'speeds'}{'scaling-min-freq'}; - } - } - # this corrects a bug we see sometimes in min/max frequencies - if ((scalar @ci_freq_max < 2 && scalar @ci_freq_min < 2) && - (defined $cpu_sys->{'data'}{'speeds'}{'min-freq'} && - defined $cpu_sys->{'data'}{'speeds'}{'max-freq'}) && - ($cpu_sys->{'data'}{'speeds'}{'min-freq'} > $cpu_sys->{'data'}{'speeds'}{'max-freq'} || - $cpu_sys->{'data'}{'speeds'}{'min-freq'} == $cpu_sys->{'data'}{'speeds'}{'max-freq'})){ - $cpu_sys->{'data'}{'speeds'}{'min-freq'} = 0; - } - main::log_data('dump','%$cpu_sys',$cpu_sys) if $b_log; - print 'cpu-sys: ', Data::Dumper::Dumper $cpu_sys if $dbg[8]; - eval $end if $b_log; - return $cpu_sys; -} - -sub sys_data_grabber { +## SYS DATA +sub cpu_sys_data_grabber { eval $start if $b_log; my (@files); - set_fake_data() if $fake{'cpu'} && !$loaded{'cpu-fake-data'}; + set_fake_cpu_data() if $fake{'cpu'} && !$loaded{'cpu-fake-data'}; # this data has to match the data in cpuinfo grabber fake cpu, and remember # to use --arm flag if arm tests if ($fake{'cpu'}){ @@ -10017,12 +9957,15 @@ sub sys_data_grabber { $glob .= 'cpufreq,cpu*/topology,cpu*/cpufreq,cpu*/cache/index*,smt,vulnerabilities}/*'; } else { - $glob .= 'cpu*/topology/{core_cpus_list,core_id,core_siblings_list,die_id,'; - $glob .= 'physical_package_id,thread_siblings_list}'; + $glob .= 'cpu*/topology/'; + $glob .= '{{cluster_cpus,core_cpus,core_siblings,thread_siblings}_list,'; + $glob .= '{core,die,cluster,node,physical_package,socket}_id}'; $glob .= ',cpufreq/{boost,ondemand}'; - $glob .= ',cpu*/cpufreq/{cpb,cpuinfo_max_freq,cpuinfo_min_freq,'; - $glob .= 'scaling_max_freq,scaling_min_freq'; - $glob .= ',scaling_driver,scaling_governor' if $type eq 'full' && $b_admin; + $glob .= ',cpu*/cpufreq/'; + $glob .= '{cpb,{cpuinfo_max,cpuinfo_min,scaling_max,scaling_min}_freq'; + if ($type eq 'full' && $b_admin){ + $glob .= ',scaling_driver,scaling_governor'; + } $glob .= '}'; if ($type eq 'full'){ $glob .= ',cpu*/cache/index*/{level,shared_cpu_list,shared_cpu_map,size,type}'; @@ -10140,83 +10083,409 @@ sub sys_data_grabber { return $working; } -# Set in one place to make sure we get them all consistent -sub set_fake_data { - $loaded{'cpu-fake-data'} = 1; - my ($ci,$sys); - ## CPUINFO DATA FILES ## - ## ARM/MIPS - # $ci = "$fake_data_dir/cpu/arm/arm-4-core-pinebook-1.txt"; - # $ci = "$fake_data_dir/cpu/arm/armv6-single-core-1.txt"; - # $ci = "$fake_data_dir/cpu/arm/armv7-dual-core-1.txt"; - # $ci = "$fake_data_dir/cpu/arm/armv7-new-format-model-name-single-core.txt"; - # $ci = "$fake_data_dir/cpu/arm/arm-2-die-96-core-rk01.txt"; - # $ci = "$fake_data_dir/cpu/arm/arm-shevaplug-1.2ghz.txt"; - # $ci = "$fake_data_dir/cpu/mips/mips-mainusg-cpuinfo.txt"; - # $ci = "$fake_data_dir/cpu/ppc/ppc-debian-ppc64-cpuinfo.txt"; - ## x86 - # $ci = "$fake_data_dir/cpu/amd/16-core-32-mt-ryzen.txt"; - # $ci = "$fake_data_dir/cpu/amd/2-16-core-epyc-abucodonosor.txt"; - # $ci = "$fake_data_dir/cpu/amd/2-core-probook-antix.txt"; - # $ci = "$fake_data_dir/cpu/amd/4-core-jean-antix.txt"; - # $ci = "$fake_data_dir/cpu/amd/4-core-althlon-mjro.txt"; - # $ci = "$fake_data_dir/cpu/amd/4-core-apu-vc-box.txt"; - # $ci = "$fake_data_dir/cpu/amd/4-core-a10-5800k-1.txt"; - # $ci = "$fake_data_dir/cpu/intel/1-core-486-fourtysixandtwo.txt"; - # $ci = "$fake_data_dir/cpu/intel/2-core-ht-atom-bruh.txt"; - # $ci = "$fake_data_dir/cpu/intel/core-2-i3.txt"; - # $ci = "$fake_data_dir/cpu/intel/8-core-i7-damentz64.txt"; - # $ci = "$fake_data_dir/cpu/intel/2-10-core-xeon-ht.txt"; - # $ci = "$fake_data_dir/cpu/intel/4-core-xeon-fake-dual-die-zyanya.txt"; - # $ci = "$fake_data_dir/cpu/intel/2-core-i5-fake-dual-die-hek.txt"; - # $ci = "$fake_data_dir/cpu/intel/2-1-core-xeon-vm-vs2017.txt"; - # $ci = "$fake_data_dir/cpu/intel/4-1-core-xeon-vps-frodo1.txt"; - # $ci = "$fake_data_dir/cpu/intel/4-6-core-xeon-no-mt-lathander.txt"; - ## Elbrus - # $cpu_type = 'elbrus'; # uncomment to test elbrus - # $ci = "$fake_data_dir/cpu/elbrus/elbrus-2c3/cpuinfo.txt"; - # $ci = "$fake_data_dir/cpu/elbrus/1xE1C-8.txt"; - # $ci = "$fake_data_dir/cpu/elbrus/1xE2CDSP-4.txt"; - # $ci = "$fake_data_dir/cpu/elbrus/1xE2S4-3-monocub.txt"; - # $ci = "$fake_data_dir/cpu/elbrus/1xMBE8C-7.txt"; - # $ci = "$fake_data_dir/cpu/elbrus/4xEL2S4-3.txt"; - # $ci = "$fake_data_dir/cpu/elbrus/4xE8C-7.txt"; - # $ci = "$fake_data_dir/cpu/elbrus/4xE2CDSP-4.txt"; - # $ci = "$fake_data_dir/cpu/elbrus/cpuinfo.e8c2.txt"; - ## Loongson - # $cpu_type = 'elbrus'; # uncomment to test loongson - $ci = "$fake_data_dir/cpu/loongson/3A5000M-4-core-4.19.0.txt"; - - ## CPU CPUINFO/SYS PAIRS DATA FILES ## - # $ci = "$fake_data_dir/cpu/sys-ci-pairs/android-pocom3-fake-cpuinfo.txt"; - # $sys = "$fake_data_dir/cpu/sys-ci-pairs/android-pocom3-fake-sys.txt"; - # $ci = "$fake_data_dir/cpu/sys-ci-pairs/arm-pine64-cpuinfo-1.txt";v - # $sys = "$fake_data_dir/cpu/sys-ci-pairs/arm-pine64-sys-1.txt"; - # $ci = "$fake_data_dir/cpu/sys-ci-pairs/arm-riscyslack2-cpuinfo-1.txt"; - # $sys = "$fake_data_dir/cpu/sys-ci-pairs/arm-riscyslack2-sys-1.txt"; - # $ci = "$fake_data_dir/cpu/sys-ci-pairs/ppc-stuntkidz~cpuinfo.txt"; - # $sys = "$fake_data_dir/cpu/sys-ci-pairs/ppc-stuntkidz~sys.txt"; - # $ci = "$fake_data_dir/cpu/sys-ci-pairs/riscv-unmatched-2021~cpuinfo-1.txt"; - # $sys = "$fake_data_dir/cpu/sys-ci-pairs/riscv-unmatched-2021~sys-1.txt"; - # $ci = "$fake_data_dir/cpu/sys-ci-pairs/x86-brickwizard-atom-n270~cpuinfo-1.txt"; - # $sys = "$fake_data_dir/cpu/sys-ci-pairs/x86-brickwizard-atom-n270~sys-1.txt"; - # $ci = "$fake_data_dir/cpu/sys-ci-pairs/x86-amd-phenom-chrisretusn-cpuinfo-1.txt"; - # $sys = "$fake_data_dir/cpu/sys-ci-pairs/x86-amd-phenom-chrisretusn-sys-1.txt"; - # $ci = "$fake_data_dir/cpu/sys-ci-pairs/x86-drgibbon-intel-i7-cpuinfo.txt"; - # $sys = "$fake_data_dir/cpu/sys-ci-pairs/x86-drgibbon-intel-i7-sys.txt"; - # $ci = "$fake_data_dir/cpu/sys-ci-pairs/ryzen-threadripper-1x64-3950x-cpuinfo.txt"; - # $sys = "$fake_data_dir/cpu/sys-ci-pairs/ryzen-threadripper-1x64-3950x-sys.txt"; - # $ci = "$fake_data_dir/cpu/sys-ci-pairs/amd-threadripper-1x12-5945wx-cpuinfo-1.txt"; - # $sys = "$fake_data_dir/cpu/sys-ci-pairs/amd-threadripper-1x12-5945wx-sys-1.txt"; - # $ci = "$fake_data_dir/cpu/sys-ci-pairs/intel-i7-1165G7-4-core-no-smt-cpuinfo.txt"; - # $sys = "$fake_data_dir/cpu/sys-ci-pairs/intel-i7-1165G7-4-core-no-smt-sys.txt"; - # $ci = "$fake_data_dir/cpu/sys-ci-pairs/elbrus-e16c-1-cpuinfo.txt"; - # $sys = "$fake_data_dir/cpu/sys-ci-pairs/elbrus-e16c-1-sys.txt"; - $fake_data{'cpuinfo'} = $ci; - $fake_data{'sys'} = $sys; +sub cpu_sys_data { + eval $start if $b_log; + my $sys_freq = $_[0]; + my $cpu_sys = {}; + my $working = cpu_sys_data_grabber(); + return $cpu_sys if !%$working; + $cpu_sys->{'data'} = $working->{'data'} if $working->{'data'}; + my ($core_id,$fake_core_id,$die_id,$phys_id) = (0,0,0,-1); + my (%cache_ids,@ci_freq_max,@ci_freq_min,@sc_freq_max,@sc_freq_min); + foreach my $id (sort keys %{$working->{'cpus'}}){ + ($core_id,$phys_id) = (0,0); + my $cpu_id = $id + 0; + my ($cluster_id,$speed); + my $phys_cpu = $working->{'cpus'}{$id}; + if (defined $phys_cpu->{'topology'}{'physical_package_id'}){ + $phys_id = sprintf("%04d",$phys_cpu->{'topology'}{'physical_package_id'}); + } + if (defined $phys_cpu->{'topology'}{'die_id'}){ + $cpu_sys->{'data'}{'die-file'} = 'die_id'; + $die_id = sprintf("%08d",$phys_cpu->{'topology'}{$cpu_sys->{'data'}{'die-file'}}); + } + else { + $die_id = 'ID-UNSET'; + } + # RISCV seen with no die_id but cluster_id with core_ids per cluster + # node_id, socket_id not seen but possibles but don't use until real case + # also alder lake haw one die but > 1 clusters + if (defined $phys_cpu->{'topology'}{'cluster_id'}){ + $cpu_sys->{'data'}{'cluster-file'} = 'cluster_id'; + $cluster_id = sprintf("%08d",$phys_cpu->{'topology'}{$cpu_sys->{'data'}{'cluster-file'}}); + } + if (defined $phys_cpu->{'topology'}{'core_id'}){ + # id is not consistent, seen 5 digit id + $core_id = sprintf("%08d",$phys_cpu->{'topology'}{'core_id'}); + if ($fake{'cpu'}){ + if (defined $phys_cpu->{'cpufreq'}{'scaling_cur_freq'} && + $phys_cpu->{'cpufreq'}{'affected_cpus'} && + $phys_cpu->{'cpufreq'}{'affected_cpus'} ne 'UNDEFINED' && + # manually generated cpu debuggers will show '', not UNDEFINED + $phys_cpu->{'cpufreq'}{'affected_cpus'} ne ''){ + $speed = clean_speed($phys_cpu->{'cpufreq'}{'scaling_cur_freq'},'khz'); + } + } + elsif (defined $sys_freq && defined $sys_freq->{$phys_id}){ + $speed = $sys_freq->{$phys_id}; + } + # ($cluster_id,$die_id) = (); + if (defined $speed){ + if ($cpu_sys->{'data'}{'die-file'} || !$cluster_id){ + push(@{$cpu_sys->{'cpus'}{$phys_id}{'dies'}{$die_id}{'cores'}{$core_id}},$speed); + } + if ($cluster_id){ + push(@{$cpu_sys->{'cpus'}{$phys_id}{'dies'}{$die_id}{'clusters'}{$cluster_id}{'cores'}{$core_id}},$speed); + } + push(@{$cpu_sys->{'data'}{'speeds'}{'all'}},$speed); + } + else { + push(@{$cpu_sys->{'data'}{'speeds'}{'all'}},0); + # seen cases, riscv, where core id, phys id, are all -1 + my $id = ($core_id != -1) ? $core_id: $fake_core_id++; + if ($cpu_sys->{'data'}{'die-file'} || !$cluster_id){ + push(@{$cpu_sys->{'cpus'}{$phys_id}{'dies'}{$die_id}{'cores'}{$id}},0); + } + if ($cluster_id){ + push(@{$cpu_sys->{'cpus'}{$phys_id}{'dies'}{$die_id}{'clusters'}{$cluster_id}{'cores'}{$id}},0); + } + } + # Only use if topology core-id exists, some virtualized cpus can list + # frequency data for the non available cores, but those do not show + # topology data. + # For max / min, we want to prep for the day 1 pys cpu has > 1 min/max freq + if (defined $phys_cpu->{'cpufreq'}{'cpuinfo_max_freq'}){ + $phys_cpu->{'cpufreq'}{'cpuinfo_max_freq'} = clean_speed($phys_cpu->{'cpufreq'}{'cpuinfo_max_freq'},'khz'); + if (!grep {$_ eq $phys_cpu->{'cpufreq'}{'cpuinfo_max_freq'}} @ci_freq_max){ + push(@ci_freq_max,$phys_cpu->{'cpufreq'}{'cpuinfo_max_freq'}); + } + if (!grep {$_ eq $phys_cpu->{'cpufreq'}{'cpuinfo_max_freq'}} @{$cpu_sys->{'cpus'}{$phys_id}{'max-freq'}}){ + push(@{$cpu_sys->{'cpus'}{$phys_id}{'max-freq'}},$phys_cpu->{'cpufreq'}{'cpuinfo_max_freq'}); + } + } + if (defined $phys_cpu->{'cpufreq'}{'cpuinfo_min_freq'}){ + $phys_cpu->{'cpufreq'}{'cpuinfo_min_freq'} = clean_speed($phys_cpu->{'cpufreq'}{'cpuinfo_min_freq'},'khz'); + if (!grep {$_ eq $phys_cpu->{'cpufreq'}{'cpuinfo_min_freq'}} @ci_freq_min){ + push(@ci_freq_min,$phys_cpu->{'cpufreq'}{'cpuinfo_min_freq'}); + } + if (!grep {$_ eq $phys_cpu->{'cpufreq'}{'cpuinfo_min_freq'}} @{$cpu_sys->{'cpus'}{$phys_id}{'min-freq'}}){ + push(@{$cpu_sys->{'cpus'}{$phys_id}{'min-freq'}},$phys_cpu->{'cpufreq'}{'cpuinfo_min_freq'}); + } + } + if (defined $phys_cpu->{'cpufreq'}{'scaling_max_freq'}){ + $phys_cpu->{'cpufreq'}{'scaling_max_freq'} = clean_speed($phys_cpu->{'cpufreq'}{'scaling_max_freq'},'khz'); + if (!grep {$_ eq $phys_cpu->{'cpufreq'}{'scaling_max_freq'}} @sc_freq_max){ + push(@sc_freq_max,$phys_cpu->{'cpufreq'}{'scaling_max_freq'}); + } + if (!grep {$_ eq $phys_cpu->{'cpufreq'}{'scaling_max_freq'}} @{$cpu_sys->{'cpus'}{$phys_id}{'max-freq'}}){ + push(@{$cpu_sys->{'cpus'}{$phys_id}{'max-freq'}},$phys_cpu->{'cpufreq'}{'scaling_max_freq'}); + } + } + if (defined $phys_cpu->{'cpufreq'}{'scaling_min_freq'}){ + $phys_cpu->{'cpufreq'}{'scaling_min_freq'} = clean_speed($phys_cpu->{'cpufreq'}{'scaling_min_freq'},'khz'); + if (!grep {$_ eq $phys_cpu->{'cpufreq'}{'scaling_min_freq'}} @sc_freq_min){ + push(@sc_freq_min,$phys_cpu->{'cpufreq'}{'scaling_min_freq'}); + } + if (!grep {$_ eq $phys_cpu->{'cpufreq'}{'scaling_min_freq'}} @{$cpu_sys->{'cpus'}{$phys_id}{'min-freq'}}){ + push(@{$cpu_sys->{'cpus'}{$phys_id}{'min-freq'}},$phys_cpu->{'cpufreq'}{'scaling_min_freq'}); + } + } + if (defined $phys_cpu->{'cpufreq'}{'scaling_governor'}){ + if (!grep {$_ eq $phys_cpu->{'cpufreq'}{'scaling_governor'}} @{$cpu_sys->{'cpus'}{$phys_id}{'governor'}}){ + push(@{$cpu_sys->{'cpus'}{$phys_id}{'governor'}},$phys_cpu->{'cpufreq'}{'scaling_governor'}); + } + } + if (defined $phys_cpu->{'cpufreq'}{'scaling_driver'}){ + $cpu_sys->{'cpus'}{$phys_id}{'scaling-driver'} = $phys_cpu->{'cpufreq'}{'scaling_driver'}; + } + } + if (!defined $cpu_sys->{'data'}{'cpufreq-boost'} && defined $phys_cpu->{'cpufreq'}{'cpb'}){ + $cpu_sys->{'data'}{'cpufreq-boost'} = $phys_cpu->{'cpufreq'}{'cpb'}; + } + if (defined $phys_cpu->{'topology'}{'core_cpus_list'}){ + $phys_cpu->{'topology'}{'thread_siblings_list'} = $phys_cpu->{'topology'}{'core_cpus_list'}; + } + if (defined $phys_cpu->{'cache'} && keys %{$phys_cpu->{'cache'}} > 0){ + foreach my $key2 (sort keys %{$phys_cpu->{'cache'}}){ + my $cache = $phys_cpu->{'cache'}{$key2}; + my $type = ($cache->{'type'} =~ /^([DI])/i) ? lc($1): ''; + my $level = 'l' . $cache->{'level'} . $type; + # Very old systems, 2.6.xx do not have shared_cpu_list + if (!defined $cache->{'shared_cpu_list'} && defined $cache->{'shared_cpu_map'}){ + $cache->{'shared_cpu_list'} = $cache->{'shared_cpu_map'}; + } + # print Data::Dumper::Dumper $cache; + if (defined $cache->{'shared_cpu_list'}){ + # not needed, the cpu is always in the range + # my $range = main::regex_range($cache->{'shared_cpu_list'}); + my $size = main::translate_size($cache->{'size'}); + # print "cpuid: $cpu_id phys-core: $phys_id-$core_id level: $level range: $range shared: $cache->{'shared_cpu_list'}\n"; + if (!(grep {$_ eq $cache->{'shared_cpu_list'}} @{$cache_ids{$phys_id}->{$level}})){ + push(@{$cache_ids{$phys_id}->{$level}},$cache->{'shared_cpu_list'}); + push(@{$cpu_sys->{'cpus'}{$phys_id}{'caches'}{$level}},$size); + } + } + } + } + } + if (defined $cpu_sys->{'data'}{'cpufreq-boost'} && + $cpu_sys->{'data'}{'cpufreq-boost'} =~ /^[01]$/){ + if ($cpu_sys->{'data'}{'cpufreq-boost'}){ + $cpu_sys->{'data'}{'cpufreq-boost'} = 'enabled'; + } + else { + $cpu_sys->{'data'}{'cpufreq-boost'} = 'disabled'; + } + } + # cpuinfo_max_freq:["2000000"] cpuinfo_max_freq:["1500000"] + # cpuinfo_min_freq:["200000"] + if (@ci_freq_max){ + $cpu_sys->{'data'}{'speeds'}{'max-freq'} = join(':',@ci_freq_max); + } + if (@ci_freq_min){ + $cpu_sys->{'data'}{'speeds'}{'min-freq'} = join(':',@ci_freq_min); + } + # also handle off chance that cpuinfo_min/max not set, but scaling_min/max there + if (@sc_freq_max){ + $cpu_sys->{'data'}{'speeds'}{'scaling-max-freq'} = join(':',@sc_freq_max); + if (!$cpu_sys->{'data'}{'speeds'}{'max-freq'}){ + $cpu_sys->{'data'}{'speeds'}{'max-freq'} = $cpu_sys->{'data'}{'speeds'}{'scaling-max-freq'}; + } + } + if (@sc_freq_min){ + $cpu_sys->{'data'}{'speeds'}{'scaling-min-freq'} = join(':',@sc_freq_min); + if (!$cpu_sys->{'data'}{'speeds'}{'min-freq'}){ + $cpu_sys->{'data'}{'speeds'}{'min-freq'} = $cpu_sys->{'data'}{'speeds'}{'scaling-min-freq'}; + } + } + # this corrects a bug we see sometimes in min/max frequencies + if ((scalar @ci_freq_max < 2 && scalar @ci_freq_min < 2) && + (defined $cpu_sys->{'data'}{'speeds'}{'min-freq'} && + defined $cpu_sys->{'data'}{'speeds'}{'max-freq'}) && + ($cpu_sys->{'data'}{'speeds'}{'min-freq'} > $cpu_sys->{'data'}{'speeds'}{'max-freq'} || + $cpu_sys->{'data'}{'speeds'}{'min-freq'} == $cpu_sys->{'data'}{'speeds'}{'max-freq'})){ + $cpu_sys->{'data'}{'speeds'}{'min-freq'} = 0; + } + main::log_data('dump','%$cpu_sys',$cpu_sys) if $b_log; + print 'cpu_sys_data: %$cpu-sys: ', Data::Dumper::Dumper $cpu_sys if $dbg[8]; + eval $end if $b_log; + return $cpu_sys; } -sub sysctl_data { +# all values passed by reference so no need for returns +sub cp_data_sys { + eval $start if $b_log; + my ($cpu,$cpu_sys,$caches,$counts) = @_; + my @phys_keys = sort keys %{$cpu_sys->{'cpus'}}; + return if ! @phys_keys; + $counts->{'physical'} = scalar @phys_keys; + if ($type eq 'full' && $cpu_sys->{'cpus'}{$phys_keys[0]}{'caches'}){ + cp_sys_caches($cpu_sys->{'cpus'}{$phys_keys[0]}{'caches'},$caches,'l1','l1d'); + cp_sys_caches($cpu_sys->{'cpus'}{$phys_keys[0]}{'caches'},$caches,'l1','l1i'); + cp_sys_caches($cpu_sys->{'cpus'}{$phys_keys[0]}{'caches'},$caches,'l2',''); + cp_sys_caches($cpu_sys->{'cpus'}{$phys_keys[0]}{'caches'},$caches,'l3',''); + } + if ($cpu_sys->{'data'}{'speeds'}{'all'}){ + $counts->{'processors'} = scalar @{$cpu_sys->{'data'}{'speeds'}{'all'}}; + } + if (defined $cpu_sys->{'data'}{'smt-active'}){ + if ($cpu_sys->{'data'}{'smt-active'}){ + $cpu->{'smt'} = 'enabled'; + } + # values: on/off/notsupported/notimplemented + elsif (defined $cpu_sys->{'data'}{'smt-control'} && + $cpu_sys->{'data'}{'smt-control'} =~ /^not/){ + $cpu->{'smt'} = main::message('unsupported'); + } + else { + $cpu->{'smt'} = 'disabled'; + } + } + my $i = 0; + my ($b_skip,@governor,@max,@min,@phys_cores); + foreach my $phys_id (@phys_keys){ + cp_dies_clusters( + $cpu, + $counts, + $cpu_sys->{'cpus'}{$phys_id}, + $cpu_sys->{'data'}, + $i, + $b_skip); + $b_skip = 1; # skips count->{cpu-cores} after first phys iteration + foreach my $die_id (sort keys %{$cpu_sys->{'cpus'}{$phys_id}{'dies'}}){ + # If we ever get > 1 min/max speed per phy cpu, we'll need to fix the [0] + if ($cpu_sys->{'cpus'}{$phys_id}{'max-freq'}[0]){ + if (!grep {$cpu_sys->{'cpus'}{$phys_id}{'max-freq'}[0] eq $_} @max){ + push(@max,$cpu_sys->{'cpus'}{$phys_id}{'max-freq'}[0]); + } + $counts->{'cpu-topo'}[$i]{'max'} = $cpu_sys->{'cpus'}{$phys_id}{'max-freq'}[0]; + } + if ($cpu_sys->{'cpus'}{$phys_id}{'min-freq'}[0]){ + if (!grep {$cpu_sys->{'cpus'}{$phys_id}{'min-freq'}[0] eq $_} @min){ + push(@min,$cpu_sys->{'cpus'}{$phys_id}{'min-freq'}[0]); + } + $counts->{'cpu-topo'}[$i]{'min'} = $cpu_sys->{'cpus'}{$phys_id}{'min-freq'}[0]; + } + # cheating, this is not a count, but we need the data for topology, must + # sort since governors can be in different order if > 1 + if ($cpu_sys->{'cpus'}{$phys_id}{'governor'}){ + foreach my $gov (@{$cpu_sys->{'cpus'}{$phys_id}{'governor'}}){ + push(@governor,$gov) if !grep {$_ eq $gov} @governor; + } + $cpu->{'governor'} = join(',',@governor); + } + if ($cpu_sys->{'cpus'}{$phys_id}{'scaling-driver'}){ + $cpu->{'scaling-driver'} = $cpu_sys->{'cpus'}{$phys_id}{'scaling-driver'}; + } + if ($cpu_sys->{'cpus'}{$phys_id}{'scaling-driver'}){ + $cpu->{'scaling-driver'} = $cpu_sys->{'cpus'}{$phys_id}{'scaling-driver'}; + } + if ($cpu_sys->{'cpus'}{$phys_id}{'scaling-max-freq'}){ + $cpu->{'scaling-max-freq'} = $cpu_sys->{'cpus'}{$phys_id}{'scaling-max-freq'}; + } + if ($cpu_sys->{'cpus'}{$phys_id}{'scaling-min-freq'}){ + $cpu->{'scaling-min-freq'} = $cpu_sys->{'cpus'}{$phys_id}{'scaling-min-freq'}; + } + if (!grep {$counts->{'cpu-cores'} eq $_} @phys_cores){ + push(@phys_cores,$counts->{'cpu-cores'}); + } + } + if ($counts->{'processors'} && $counts->{'processors'} > $counts->{'cpu-cores'}){ + foreach my $die_id (sort keys %{$cpu_sys->{'cpus'}{$phys_id}{'dies'}}){ + if (!$cpu_sys->{'cpus'}{$phys_id}{'dies'}{$die_id}{'clusters'}){ + if ($cpu_sys->{'cpus'}{$phys_id}{'dies'}{$die_id}{'cores'}){ + cp_set_threads( + $cpu_sys->{'cpus'}{$phys_id}{'dies'}{$die_id}{'cores'}, + $counts, + $i); + } + } + else { + foreach my $cluster_id (sort keys %{$cpu_sys->{'cpus'}{$phys_id}{'dies'}{$die_id}{'clusters'}}){ + if ($cpu_sys->{'cpus'}{$phys_id}{'dies'}{$die_id}{'clusters'}{$cluster_id}{'cores'}){ + cp_set_threads( + $cpu_sys->{'cpus'}{$phys_id}{'dies'}{$die_id}{'clusters'}{$cluster_id}{'cores'}, + $counts, + $i); + } + } + } + + } + } + $i++; + } + $counts->{'struct-max'} = 1 if scalar @max > 1; + $counts->{'struct-min'} = 1 if scalar @min > 1; + $counts->{'struct-cores'} = 1 if scalar @phys_cores > 1; + if ($b_log){ + main::log_data('dump','%$caches',$caches); + main::log_data('dump','%$counts',$counts); + } + if ($dbg[68]){ + print '%$cpu: ', Data::Dumper::Dumper $cpu; + print 'cpu %$caches: ', Data::Dumper::Dumper $caches; + print 'cpu %$counts: ', Data::Dumper::Dumper $counts; + } + eval $end if $b_log; +} + +# args: 0: $cpu by ref; 1: $counts by ref; 2: $phy_cpu by ref; 3: $i +sub cp_dies_clusters { + eval $start if $b_log; + my ($cpu,$counts,$phys_cpu,$data,$i,$b_skip) = @_; + # we don't want the placeholder die ID counted as an actual die! + if ($phys_cpu->{'dies'} && $data->{'die-file'}){ + $counts->{'cpu-topo'}[$i]{'dies'} = scalar keys %{$phys_cpu->{'dies'}}; + $cpu->{'dies-count'} = $counts->{'cpu-topo'}[$i]{'dies'}; + } + foreach my $id (sort keys %{$phys_cpu->{'dies'}}){ + if ($phys_cpu->{'dies'}{$id}{'clusters'}){ + # this will show dies x clusters in output, since no way to know if cluster + # ids are per phys cpu or per die. + $cpu->{'clusters-count'} = scalar keys %{$phys_cpu->{'dies'}{$id}{'clusters'}}; + $counts->{'cpu-topo'}[$i]{'clusters'} = $cpu->{'clusters-count'}; + foreach my $cluster_id (sort keys %{$phys_cpu->{'dies'}{$id}{'clusters'}}){ + if ($phys_cpu->{'dies'}{$id}{'clusters'}{$cluster_id}{'cores'}){ + cp_core_counter( + $cpu, + $phys_cpu->{'dies'}{$id}{'clusters'}{$cluster_id}{'cores'}, + $counts, + $i, + $b_skip); + } + } + } + else { + if ($phys_cpu->{'dies'}{$id}{'cores'}){ + cp_core_counter( + $cpu, + $phys_cpu->{'dies'}{$id}{'cores'}, + $counts, + $i, + $b_skip); + } + } + } + eval $end if $b_log; +} + +# args: 0: $cpu by ref; 1: $cores; 2: $counts (by ref); 3: $i; +# 4: $b_dies: 0 for first iteration +sub cp_core_counter { + eval $start if $b_log; + my ($cpu,$item,$counts,$i,$b_skip) = @_; + my $cores = 0; + $cores = scalar keys %{$item}; + $counts->{'cpu-topo'}[$i]{'cores'} += $cores; + $cpu->{'cores'} = $cores; + $counts->{'cpu-cores'} += $cores if !$b_skip; + eval $end if $b_log; +} + +# args: 0: cores hash; 1: $counts, by ref; 2: $i +sub cp_set_threads { + eval $start if $b_log; + my ($cores,$counts,$i) = @_; + foreach my $core_key (sort keys %{$cores}){ + if ((my $threads = scalar @{$cores->{$core_key}}) > 1){ + $counts->{'cpu-topo'}[$i]{'cores-mt'}++; + $counts->{'cpu-topo'}[$i]{'threads'} += $threads; + # note: for mt+st type cpus, we need to handle tpc on output per type + $counts->{'cpu-topo'}[$i]{'tpc'} = $threads; + $counts->{'struct-mt'} = 1; + } + else { + $counts->{'cpu-topo'}[$i]{'cores-st'}++; + $counts->{'cpu-topo'}[$i]{'threads'}++; + $counts->{'struct-st'} = 1; + } + } + eval $end if $b_log; +} + +sub cp_sys_caches { + eval $start if $b_log; + my ($sys_caches,$caches,$id,$id_di) = @_; + my $cache_id = ($id_di) ? $id_di: $id; + my %cache_desc; + if ($sys_caches->{$cache_id}){ + # print Data::Dumper::Dumper $cpu_sys->{'cpus'}; + foreach (@{$sys_caches->{$cache_id}}){ + # android seen to have cache data without size item + next if !defined $_; + $caches->{$cache_id} += $_; + $cache_desc{$_}++ if $b_admin; + } + $caches->{$id} += $caches->{$id_di} if $id_di; + $caches->{$cache_id . '-desc'} = cp_cache_desc(\%cache_desc) if $b_admin; + } + eval $end if $b_log; +} +## END SYS DATA ## + +## BSD DATA +sub cpu_sysctl_data { eval $start if $b_log; my ($cpu,@line,%speeds,@working); my ($sep) = (''); @@ -10366,7 +10635,7 @@ sub sysctl_data { } } if (!$cpu->{'flags'} || !$cpu->{'family'}){ - my $dmesg_boot = dboot_data(); + my $dmesg_boot = cp_dboot_data(); # this core count may fix failed MT detection. $cpu->{'cores'} = $dmesg_boot->{'cores'} if $dmesg_boot->{'cores'}; $cpu->{'flags'} = $dmesg_boot->{'flags'} if !$cpu->{'flags'}; @@ -10385,13 +10654,12 @@ sub sysctl_data { $cpu->{'type'} = $dmesg_boot->{'type'} if !$cpu->{'type'}; } main::log_data('dump','%$cpu',$cpu) if $b_log; - print Data::Dumper::Dumper $cpu if $dbg[8]; + print 'sysctl $cpu: ', Data::Dumper::Dumper $cpu if $dbg[8]; eval $end if $b_log; return $cpu; } -## DATA GENERATOR DATA SOURCES ## -sub dboot_data { +sub cp_dboot_data { eval $start if $b_log; my ($max_freq,$min_freq,@scalings); my ($family,$flags,$microcode,$model,$sep,$stepping,$type) = ('','','','','','',''); @@ -10505,12 +10773,14 @@ sub dboot_data { 'stepping' => $stepping, 'type' => $type, }; - print Data::Dumper::Dumper $values if $dbg[27]; + print 'dboot $values: ', Data::Dumper::Dumper $values if $dbg[27]; eval $end if $b_log; return $values; } +## END BSD DATA ## -sub dmidecode_data { +## DMIDECODE DATA ## +sub cpu_dmidecode_data { eval $start if $b_log; my $dmi_data = {'L1' => 0, 'L2' => 0,'L3' => 0, 'phys-cnt' => 0, 'ext-clock' => undef, 'socket' => undef, 'speed' => undef, @@ -10608,12 +10878,61 @@ sub dmidecode_data { $dmi_data->{'upgrade'} = $upgrade; } main::log_data('dump','%$dmi_data',$dmi_data) if $b_log; - print Data::Dumper::Dumper $dmi_data if $dbg[27]; + print 'dmidecode $dmi_data: ', Data::Dumper::Dumper $dmi_data if $dbg[27]; eval $end if $b_log; return $dmi_data; } -## CPU PROPERTIES MAIN ## +# everything is passed by reference so no need to return anything +sub cp_data_dmi { + eval $start if $b_log; + my ($cpu,$dmi_data,$caches,$counts,$cache_check) = @_; + my $cpu_dmi = cpu_dmidecode_data(); + # fix for bsds that do not show physical cpus, like openbsd + if ($cpu_dmi->{'phys-cnt'} && $counts->{'physical'} == 1 && + $cpu_dmi->{'phys-cnt'} > 1){ + $counts->{'physical'} = $cpu_dmi->{'phys-cnt'}; + } + # We have to undef all the sys stuff to get back to the true dmidecode results + # Too many variants to treat one by one, just clear it out if forced. + undef $caches if $force{'dmidecode'}; + # We don't want to use dmi L1/L2/L3 at all for non BSD systems unless forced + # because have seen totally gibberish dmidecode data for caches. /sys cache + # data preferred, more granular and basically consistently right. + # Only run for linux if no cache data found, but BSD use to fill in missing + # (we don't care about legacy errors for BSD since the data isn't adequate). + # legacy dmidecode cache data used the per cache value, NOT the per CPU total + # value like it does today. Which makes it impossible to know for sure if the + # given value is right (new, or if cache matched cpu total) or inadequate. + if ((!$bsd_type && !$caches->{'l1'} && !$caches->{'l2'} && !$caches->{'l3'}) || + ($bsd_type && (!$caches->{'l1'} || !$caches->{'l2'} || !$caches->{'l3'}))){ + # Newer dmi: cache type total per phys cpu; Legacy: raw cache size only + if ($cpu_dmi->{'l1'} && !$caches->{'l1'}){ + $caches->{'l1'} = $cpu_dmi->{'l1'}; + $$cache_check = main::message('note-check'); + } + # note: bsds often won't have L2 catch data found yet, but bsd sysctl can + # have these values so let's check just in case. OpenBSD does have it often. + if ($cpu_dmi->{'l2'} && !$caches->{'l2'}){ + $caches->{'l2'} = $cpu_dmi->{'l2'}; + $$cache_check = main::message('note-check'); + } + if ($cpu_dmi->{'l3'} && !$caches->{'l3'}){ + $caches->{'l3'} = $cpu_dmi->{'l3'}; + $$cache_check = main::message('note-check'); + } + } + $dmi_data->{'max-speed'} = $cpu_dmi->{'max-speed'}; + $dmi_data->{'socket'} = $cpu_dmi->{'socket'} if $cpu_dmi->{'socket'}; + $dmi_data->{'upgrade'} = $cpu_dmi->{'upgrade'} if $cpu_dmi->{'upgrade'}; + $dmi_data->{'speed'} = $cpu_dmi->{'speed'} if $cpu_dmi->{'speed'}; + $dmi_data->{'ext-clock'} = $cpu_dmi->{'ext-clock'} if $cpu_dmi->{'ext-clock'}; + $dmi_data->{'volts'} = $cpu_dmi->{'volts'} if $cpu_dmi->{'volts'}; + eval $end if $b_log; +} +## END DMIDECODE DATA ## + +## CPU PROPERTIES ## sub cpu_properties { my ($cpu) = @_; my ($cpu_sys,$arch_level); @@ -10664,7 +10983,7 @@ sub cpu_properties { if (%risc && $counts->{'dies'} > 1 && $counts->{'cpu-cores'} == $counts->{'dies'}){ $counts->{'dies'} = 1; - $cpu->{'dies'} = 1; + $cpu->{'dies-count'} = 1; } if ($type eq 'full' && ($extra > 1 || ($bsd_type && !$cpu->{'l2-cache'}))){ cp_data_dmi( @@ -10720,7 +11039,7 @@ sub cpu_properties { $tests ); my $topology = {}; - cp_cpu_topology($counts,$topology); + cp_topology($counts,$topology); # print "$cpu->{'type'}\n"; # print Data::Dumper::Dumper $cpu; my $arch = cp_cpu_arch( @@ -10805,350 +11124,7 @@ sub cpu_properties { return $cpu_properties; } -## CPU DATA ENGINES ## -# everything is passed by reference so no need to return anything -sub cp_data_dmi { - eval $start if $b_log; - my ($cpu,$dmi_data,$caches,$counts,$cache_check) = @_; - my $cpu_dmi = dmidecode_data(); - # fix for bsds that do not show physical cpus, like openbsd - if ($cpu_dmi->{'phys-cnt'} && $counts->{'physical'} == 1 && - $cpu_dmi->{'phys-cnt'} > 1){ - $counts->{'physical'} = $cpu_dmi->{'phys-cnt'}; - } - # We have to undef all the sys stuff to get back to the true dmidecode results - # Too many variants to treat one by one, just clear it out if forced. - undef $caches if $force{'dmidecode'}; - # We don't want to use dmi L1/L2/L3 at all for non BSD systems unless forced - # because have seen totally gibberish dmidecode data for caches. /sys cache - # data preferred, more granular and basically consistently right. - # Only run for linux if no cache data found, but BSD use to fill in missing - # (we don't care about legacy errors for BSD since the data isn't adequate). - # legacy dmidecode cache data used the per cache value, NOT the per CPU total - # value like it does today. Which makes it impossible to know for sure if the - # given value is right (new, or if cache matched cpu total) or inadequate. - if ((!$bsd_type && !$caches->{'l1'} && !$caches->{'l2'} && !$caches->{'l3'}) || - ($bsd_type && (!$caches->{'l1'} || !$caches->{'l2'} || !$caches->{'l3'}))){ - # Newer dmi: cache type total per phys cpu; Legacy: raw cache size only - if ($cpu_dmi->{'l1'} && !$caches->{'l1'}){ - $caches->{'l1'} = $cpu_dmi->{'l1'}; - $$cache_check = main::message('note-check'); - } - # note: bsds often won't have L2 catch data found yet, but bsd sysctl can - # have these values so let's check just in case. OpenBSD does have it often. - if ($cpu_dmi->{'l2'} && !$caches->{'l2'}){ - $caches->{'l2'} = $cpu_dmi->{'l2'}; - $$cache_check = main::message('note-check'); - } - if ($cpu_dmi->{'l3'} && !$caches->{'l3'}){ - $caches->{'l3'} = $cpu_dmi->{'l3'}; - $$cache_check = main::message('note-check'); - } - } - $dmi_data->{'max-speed'} = $cpu_dmi->{'max-speed'}; - $dmi_data->{'socket'} = $cpu_dmi->{'socket'} if $cpu_dmi->{'socket'}; - $dmi_data->{'upgrade'} = $cpu_dmi->{'upgrade'} if $cpu_dmi->{'upgrade'}; - $dmi_data->{'speed'} = $cpu_dmi->{'speed'} if $cpu_dmi->{'speed'}; - $dmi_data->{'ext-clock'} = $cpu_dmi->{'ext-clock'} if $cpu_dmi->{'ext-clock'}; - $dmi_data->{'volts'} = $cpu_dmi->{'volts'} if $cpu_dmi->{'volts'}; - eval $end if $b_log; -} - -sub cp_data_fallback { - eval $start if $b_log; - my ($cpu,$caches,$cache_check,$counts,$tests) = @_; - if (!$counts->{'physical'}){ - # handle case where cpu reports say, phys id 0, 2, 4, 6 - foreach (@{$cpu->{'ids'}}){ - $counts->{'physical'}++ if $_; - } - } - # count unique processors ## - # note, this fails for intel cpus at times - # print ref $cpu->{'processors'}, "\n"; - if (!$counts->{'processors'}){ - $counts->{'processors'} = scalar @{$cpu->{'processors'}}; - } - # print "p count:$counts->{'processors'}\n"; - # print Data::Dumper::Dumper $cpu->{'processors'}; - # $counts->{'cpu-cores'} is per physical cpu - # note: elbrus supports turning off cores, so we need to add one for cases - # where rounds to 0 or 1 less - # print "$cpu{'type'},$cpu{'family'},$cpu{'model-id'},$cpu{'arch'}\n"; - if ($tests->{'elbrus'} && $counts->{'processors'}){ - my $elbrus = cp_elbrus_data($cpu->{'family'},$cpu->{'model-id'}, - $counts->{'processors'},$cpu->{'arch'}); - $counts->{'cpu-cores'} = $elbrus->[0]; - $counts->{'physical'} = $elbrus->[1]; - $cpu->{'arch'} = $elbrus->[2]; - # print 'model id: ' . $cpu->{'model-id'} . ' arch: ' . $cpu->{'arch'} . " cpc: $counts->{'cpu-cores'} phyc: $counts->{'physical'} proc: $counts->{'processors'} \n"; - } - $counts->{'physical'} ||= 1; # assume 1 if no id found, as with ARM - foreach my $die_ref (@{$cpu->{'ids'}}){ - next if ref $die_ref ne 'ARRAY'; - $counts->{'cores'} = 0; - $counts->{'dies'} = scalar @$die_ref; - #$cpu->{'dies'} = $counts->{'dies'}; - foreach my $core_ref (@$die_ref){ - next if ref $core_ref ne 'ARRAY'; - $counts->{'cores'} = 0;# reset for each die!! - # NOTE: the counters can be undefined because the index comes from - # core id: which can be 0 skip 1 then 2, which leaves index 1 undefined - # risc cpus do not actually show core id so ignore that counter - foreach my $id (@$core_ref){ - $counts->{'cores'}++ if defined $id && !%risc; - } - # print 'cores: ' . $counts->{'cores'}, "\n"; - } - } - # this covers potentially cases where ARM cpus have > 1 die - # maybe applies to all risc, not sure, but dies is broken anyway for cpuinfo - if (!$cpu->{'dies'}){ - if ($risc{'arm'} && $counts->{'dies'} <= 1 && $cpu->{'dies'} > 1){ - $counts->{'dies'} = $cpu->{'dies'}; - } - else { - $cpu->{'dies'} = $counts->{'dies'}; - } - } - # this is an attempt to fix the amd family 15 bug with reported cores vs actual cores - # NOTE: amd A6-4400M APU 2 core reports: cores: 1 siblings: 2 - # NOTE: AMD A10-5800K APU 4 core reports: cores: 2 siblings: 4 - if (!$counts->{'cpu-cores'}){ - if ($cpu->{'cores'} && !$counts->{'cores'} || - $cpu->{'cores'} >= $counts->{'cores'}){ - $counts->{'cpu-cores'} = $cpu->{'cores'}; - } - elsif ($counts->{'cores'} > $cpu->{'cores'}){ - $counts->{'cpu-cores'} = $counts->{'cores'}; - } - } - # print "cpu-c:$counts->{'cpu-cores'}\n"; - # $counts->{'cpu-cores'} = $cpu->{'cores'}; - # like, intel core duo - # NOTE: sadly, not all core intel are HT/MT, oh well... - # xeon may show wrong core / physical id count, if it does, fix it. A xeon - # may show a repeated core id : 0 which gives a fake num_of_cores=1 - if ($tests->{'intel'}){ - if ($cpu->{'siblings'} && $cpu->{'siblings'} > 1 && - $cpu->{'cores'} && $cpu->{'cores'} > 1){ - if ($cpu->{'siblings'}/$cpu->{'cores'} == 1){ - $tests->{'intel'} = 0; - $tests->{'ht'} = 0; - } - else { - $counts->{'cpu-cores'} = ($cpu->{'siblings'}/2); - $tests->{'ht'} = 1; - } - } - } - # ryzen is made out of blocks of 2, 4, or 8 core dies... - if ($tests->{'ryzen'}){ - $counts->{'cpu-cores'} = $cpu->{'cores'}; - # note: posix ceil isn't present in Perl for some reason, deprecated? - my $working = $counts->{'cpu-cores'} / 8; - my @temp = split('\.', $working); - $cpu->{'dies'} = ($temp[1] && $temp[1] > 0) ? $temp[0]++ : $temp[0]; - $counts->{'dies'} = $cpu->{'dies'}; - } - # these always have 4 dies - elsif ($tests->{'epyc'}){ - $counts->{'cpu-cores'} = $cpu->{'cores'}; - $counts->{'dies'} = $cpu->{'dies'} = 4; - } - # final check, override the num of cores value if it clearly is wrong - # and use the raw core count and synthesize the total instead of real count - if ($counts->{'cpu-cores'} == 0 && - $cpu->{'cores'} * $counts->{'physical'} > 1){ - $counts->{'cpu-cores'} = ($cpu->{'cores'} * $counts->{'physical'}); - } - # last check, seeing some intel cpus and vms with intel cpus that do not show any - # core id data at all, or siblings. - if ($counts->{'cpu-cores'} == 0 && $counts->{'processors'} > 0){ - $counts->{'cpu-cores'} = $counts->{'processors'}; - } - # this happens with BSDs which have very little cpu data available - if ($counts->{'processors'} == 0 && $counts->{'cpu-cores'} > 0){ - $counts->{'processors'} = $counts->{'cpu-cores'}; - if ($bsd_type && ($tests->{'ht'} || $tests->{'amd-zen'}) && - $counts->{'cpu-cores'} > 2){ - $counts->{'cpu-cores'} = $counts->{'cpu-cores'}/2;; - } - my $count = $counts->{'processors'}; - $count-- if $count > 0; - $cpu->{'processors'}[$count] = 0; - # no way to get per processor speeds yet, so assign 0 to each - # must be a numeric value. Could use raw speed from core 0, but - # that would just be a hack. - foreach (0 .. $count){ - $cpu->{'processors'}[$_] = 0; - } - } - # so far only OpenBSD has a way to detect MT cpus, but Openbsd has disabled MT - if ($bsd_type){ - if ($cpu->{'siblings'} && - $counts->{'cpu-cores'} && $counts->{'cpu-cores'} > 1){ - $counts->{'cores-multiplier'} = $counts->{'cpu-cores'}; - } - # if no siblings we couldn't get MT status of cpu so can't trust cache - else { - $$cache_check = main::message('note-check'); - } - } - # only elbrus shows L1 / L3 cache data in cpuinfo, cpu_sys data should show - # for newer full linux. - elsif ($counts->{'cpu-cores'} && - ($tests->{'elbrus'} || $counts->{'cpu-cores'} > 1)) { - $counts->{'cores-multiplier'} = $counts->{'cpu-cores'}; - } - # last test to catch some corner cases - # seen a case where a xeon vm in a dual xeon system actually had 2 cores, no MT - # so it reported 4 siblings, 2 cores, but actually only had 1 core per virtual cpu - # print "prc: $counts->{'processors'} phc: $counts->{'physical'} coc: $counts->{'cores'} cpc: $counts->{'cpu-cores'}\n"; - # this test was for arm but I think it applies to all risc, but risc will be sys - if (!%risc && - $counts->{'processors'} == $counts->{'physical'} * $counts->{'cores'} && - $counts->{'cpu-cores'} > $counts->{'cores'}){ - $tests->{'ht'} = 0; - # $tests->{'xeon'} = 0; - $tests->{'intel'} = 0; - $counts->{'cpu-cores'} = 1; - $counts->{'cores'} = 1; - $cpu->{'siblings'} = 1; - } - eval $end if $b_log; -} - -# all values passed by reference so no need for returns -sub cp_data_sys { - eval $start if $b_log; - my ($cpu,$cpu_sys,$caches,$counts) = @_; - my (@keys) = (sort keys %{$cpu_sys->{'cpus'}}); - return if !@keys; - $counts->{'physical'} = scalar @keys; - if ($type eq 'full' && $cpu_sys->{'cpus'}{$keys[0]}{'caches'}){ - cp_sys_caches($cpu_sys->{'cpus'}{$keys[0]}{'caches'},$caches,'l1','l1d'); - cp_sys_caches($cpu_sys->{'cpus'}{$keys[0]}{'caches'},$caches,'l1','l1i'); - cp_sys_caches($cpu_sys->{'cpus'}{$keys[0]}{'caches'},$caches,'l2',''); - cp_sys_caches($cpu_sys->{'cpus'}{$keys[0]}{'caches'},$caches,'l3',''); - } - if ($cpu_sys->{'data'}{'speeds'}{'all'}){ - $counts->{'processors'} = scalar @{$cpu_sys->{'data'}{'speeds'}{'all'}}; - } - if (defined $cpu_sys->{'data'}{'smt-active'}){ - if ($cpu_sys->{'data'}{'smt-active'}){ - $cpu->{'smt'} = 'enabled'; - } - # values: on/off/notsupported/notimplemented - elsif (defined $cpu_sys->{'data'}{'smt-control'} && - $cpu_sys->{'data'}{'smt-control'} =~ /^not/){ - $cpu->{'smt'} = main::message('unsupported'); - } - else { - $cpu->{'smt'} = 'disabled'; - } - } - my $i = 0; - my (@governor,@max,@min,@phys_cores); - foreach my $phys_id (@keys){ - if ($cpu_sys->{'cpus'}{$phys_id}{'cores'}){ - my ($mt,$st) = (0,0); - my (@core_keys) = keys %{$cpu_sys->{'cpus'}{$phys_id}{'cores'}}; - $cpu->{'cores'} = $counts->{'cpu-cores'} = scalar @core_keys; - $counts->{'cpu-topo'}[$i]{'cores'} = $cpu->{'cores'}; - if ($cpu_sys->{'cpus'}{$phys_id}{'dies'}){ - $counts->{'cpu-topo'}[$i]{'dies'} = scalar @{$cpu_sys->{'cpus'}{$phys_id}{'dies'}}; - $cpu->{'dies'} = $counts->{'cpu-topo'}[$i]{'dies'}; - } - # If we ever get > 1 min/max speed per phy cpu, we'll need to fix the [0] - if ($cpu_sys->{'cpus'}{$phys_id}{'max-freq'}[0]){ - if (!grep {$cpu_sys->{'cpus'}{$phys_id}{'max-freq'}[0] eq $_} @max){ - push(@max,$cpu_sys->{'cpus'}{$phys_id}{'max-freq'}[0]); - } - $counts->{'cpu-topo'}[$i]{'max'} = $cpu_sys->{'cpus'}{$phys_id}{'max-freq'}[0]; - } - if ($cpu_sys->{'cpus'}{$phys_id}{'min-freq'}[0]){ - if (!grep {$cpu_sys->{'cpus'}{$phys_id}{'min-freq'}[0] eq $_} @min){ - push(@min,$cpu_sys->{'cpus'}{$phys_id}{'min-freq'}[0]); - } - $counts->{'cpu-topo'}[$i]{'min'} = $cpu_sys->{'cpus'}{$phys_id}{'min-freq'}[0]; - } - # cheating, this is not a count, but we need the data for topology, must - # sort since governors can be in different order if > 1 - if ($cpu_sys->{'cpus'}{$phys_id}{'governor'}){ - foreach my $gov (@{$cpu_sys->{'cpus'}{$phys_id}{'governor'}}){ - push(@governor,$gov) if !grep {$_ eq $gov} @governor; - } - $cpu->{'governor'} = join(',',@governor); - } - if ($cpu_sys->{'cpus'}{$phys_id}{'scaling-driver'}){ - $cpu->{'scaling-driver'} = $cpu_sys->{'cpus'}{$phys_id}{'scaling-driver'}; - } - if ($cpu_sys->{'cpus'}{$phys_id}{'scaling-driver'}){ - $cpu->{'scaling-driver'} = $cpu_sys->{'cpus'}{$phys_id}{'scaling-driver'}; - } - if ($cpu_sys->{'cpus'}{$phys_id}{'scaling-max-freq'}){ - $cpu->{'scaling-max-freq'} = $cpu_sys->{'cpus'}{$phys_id}{'scaling-max-freq'}; - } - if ($cpu_sys->{'cpus'}{$phys_id}{'scaling-min-freq'}){ - $cpu->{'scaling-min-freq'} = $cpu_sys->{'cpus'}{$phys_id}{'scaling-min-freq'}; - } - if (!grep {$counts->{'cpu-cores'} eq $_} @phys_cores){ - push(@phys_cores,$counts->{'cpu-cores'}); - } - if ($counts->{'processors'}){ - if ($counts->{'processors'} > $counts->{'cpu-cores'}){ - for my $key (@core_keys){ - if ((my $threads = scalar @{$cpu_sys->{'cpus'}{$phys_id}{'cores'}{$key}}) > 1){ - $counts->{'cpu-topo'}[$i]{'cores-mt'}++; - $counts->{'cpu-topo'}[$i]{'threads'} += $threads; - # note: for mt+st type cpus, we need to handle tpc on output per type - $counts->{'cpu-topo'}[$i]{'tpc'} = $threads; - $counts->{'struct-mt'} = 1; - } - else { - $counts->{'cpu-topo'}[$i]{'cores-st'}++; - $counts->{'cpu-topo'}[$i]{'threads'}++; - $counts->{'struct-st'} = 1; - } - } - } - } - $i++; - } - } - $counts->{'struct-max'} = 1 if scalar @max > 1; - $counts->{'struct-min'} = 1 if scalar @min > 1; - $counts->{'struct-cores'} = 1 if scalar @phys_cores > 1; - if ($b_log){ - main::log_data('dump','%cpu_properties',$caches); - main::log_data('dump','%cpu_properties',$counts); - } - # print Data::Dumper::Dumper $caches; - # print Data::Dumper::Dumper $counts; - eval $end if $b_log; -} - -sub cp_sys_caches { - eval $start if $b_log; - my ($sys_caches,$caches,$id,$id_di) = @_; - my $cache_id = ($id_di) ? $id_di: $id; - my %cache_desc; - if ($sys_caches->{$cache_id}){ - # print Data::Dumper::Dumper $cpu_sys->{'cpus'}; - foreach (@{$sys_caches->{$cache_id}}){ - # android seen to have cache data without size item - next if !defined $_; - $caches->{$cache_id} += $_; - $cache_desc{$_}++ if $b_admin; - } - $caches->{$id} += $caches->{$id_di} if $id_di; - $caches->{$cache_id . '-desc'} = cp_cache_desc(\%cache_desc) if $b_admin; - } - eval $end if $b_log; -} - -## CPU PROPERTIES TOOLS ## +## CP TOOLS sub cp_cache_desc { my ($cache_desc) = @_; my ($desc,$sep) = ('',''); @@ -11232,6 +11208,358 @@ sub cp_caches_fallback { eval $end if $b_log; } +sub cp_cores_alpha { + my $cores = $_[0]; + my $string = ''; + if ($cores > 4){ + $string = $cores . '-core'; + } + elsif ($cores == 0){ + $string = main::message('unknown-cpu-topology'); + } + else { + my @alpha = qw(single dual triple quad); + $string = $alpha[$cores-1] . ' core'; + } + return $string; +} + +# Only AMD/Intel 64 bit cpus +sub cp_cpu_level { + eval $start if $b_log; + 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; +} + +# Logic: +# if > 1 processor && processor id (physical id) == core id then Multi threaded (MT) +# if siblings > 1 && siblings == 2 * num_of_cores ($cpu->{'cores'}) then Multi threaded (MT) +# if > 1 processor && processor id (physical id) != core id then Multi-Core Processors (MCP) +# if > 1 processor && processor ids (physical id) > 1 then Symmetric Multi Processing (SMP) +# if = 1 processor then single core/processor Uni-Processor (UP) +sub cp_cpu_type { + eval $start if $b_log; + my ($counts,$cpu,$tests) = @_; + my $cpu_type = ''; + if ($counts->{'processors'} > 1 || + (defined $tests->{'intel'} && $tests->{'intel'} && $cpu->{'siblings'} > 0)){ + # cpu_sys detected MT + if ($counts->{'struct-mt'}){ + if ($counts->{'struct-mt'} && $counts->{'struct-st'}){ + $cpu_type .= 'MST'; + } + else { + $cpu_type .= 'MT'; + } + } + # handle case of OpenBSD that has hw.smt but no other meaningful topology + elsif ($cpu->{'smt'}){ + $cpu_type .= 'MT' if $cpu->{'smt'} eq 'enabled'; + } + # non-multicore MT, with 2 or more threads per core + elsif ($counts->{'processors'} && $counts->{'physical'} && + $counts->{'cpu-cores'} && + $counts->{'processors'}/($counts->{'physical'} * $counts->{'cpu-cores'}) >= 2){ + # print "mt:1\n"; + $cpu_type .= 'MT'; + } + # 2 or more siblings per cpu real core + elsif ($cpu->{'siblings'} > 1 && $cpu->{'siblings'}/$counts->{'cpu-cores'} >= 2){ + # print "mt:3\n"; + $cpu_type .= 'MT'; + } + # non-MT multi-core or MT multi-core + if ($counts->{'cpu-cores'} > 1){ + if ($counts->{'struct-mt'} && $counts->{'struct-st'}){ + $cpu_type .= ' AMCP'; + } + else { + $cpu_type .= ' MCP'; + } + } + # only solidly known > 1 die cpus will use this + if (defined $cpu->{'dies'} && $cpu->{'dies'} > 1){ + $cpu_type .= ' MCM'; + } + # >1 cpu sockets active: Symetric Multi Processing + if ($counts->{'physical'} > 1){ + if ($counts->{'struct-cores'} || $counts->{'struct-max'} || + $counts->{'struct-min'}){ + $cpu_type .= ' AMP'; + } + else { + $cpu_type .= ' SMP'; + } + } + $cpu_type =~ s/^\s+//; + } + else { + $cpu_type = 'UP'; + } + eval $end if $b_log; + return $cpu_type; +} + +sub cp_speed_data { + eval $start if $b_log; + my ($cpu,$cpu_sys) = @_; + my $info = {}; + if (defined $cpu_sys->{'data'}){ + if (defined $cpu_sys->{'data'}{'speeds'}{'min-freq'}){ + $cpu->{'min-freq'} = $cpu_sys->{'data'}{'speeds'}{'min-freq'}; + } + if (defined $cpu_sys->{'data'}{'speeds'}{'max-freq'}){ + $cpu->{'max-freq'} = $cpu_sys->{'data'}{'speeds'}{'max-freq'}; + } + if (defined $cpu_sys->{'data'}{'speeds'}{'scaling-min-freq'}){ + $cpu->{'scaling-min-freq'} = $cpu_sys->{'data'}{'speeds'}{'scaling-min-freq'}; + } + if (defined $cpu_sys->{'data'}{'speeds'}{'scaling-max-freq'}){ + $cpu->{'scaling-max-freq'} = $cpu_sys->{'data'}{'speeds'}{'scaling-max-freq'}; + } + # we don't need to see these if they are the same + if ($cpu->{'min-freq'} && $cpu->{'max-freq'} && + $cpu->{'scaling-min-freq'} && $cpu->{'scaling-max-freq'} && + $cpu->{'min-freq'} eq $cpu->{'scaling-min-freq'} && + $cpu->{'max-freq'} eq $cpu->{'scaling-max-freq'}){ + undef $cpu->{'scaling-min-freq'}; + undef $cpu->{'scaling-max-freq'}; + } + if (defined $cpu_sys->{'data'}{'speeds'}{'all'}){ + # only replace if we got actual speed values from cpufreq, or if no legacy + # sourced processors data. Handles fake syz core speeds for counts. + if ((grep {$_} @{$cpu_sys->{'data'}{'speeds'}{'all'}}) || + !@{$cpu->{'processors'}}){ + $cpu->{'processors'} = $cpu_sys->{'data'}{'speeds'}{'all'}; + } + } + if (defined $cpu_sys->{'data'}{'cpufreq-boost'}){ + $cpu->{'boost'} = $cpu_sys->{'data'}{'cpufreq-boost'}; + } + } + if (defined $cpu->{'processors'}){ + if (scalar @{$cpu->{'processors'}} > 1){ + my ($agg,$high) = (0,0); + for (@{$cpu->{'processors'}}){ + next if !$_; # bsds might have 0 or undef value, that's junk + $agg += $_; + $high = $_ if $_ > $high; + } + if ($agg){ + $cpu->{'avg-freq'} = int($agg/scalar @{$cpu->{'processors'}}); + $cpu->{'cur-freq'} = $high; + $info->{'avg-speed-key'} = 'avg'; + $info->{'speed'} = $cpu->{'avg-freq'}; + if ($high > $cpu->{'avg-freq'}){ + $cpu->{'high-freq'} = $high; + $info->{'high-speed-key'} = 'high'; + } + } + } + elsif ($cpu->{'processors'}[0]) { + $cpu->{'cur-freq'} = $cpu->{'processors'}[0]; + $info->{'speed'} = $cpu->{'cur-freq'}; + } + } + # BSDs generally will have processors count, but not per core speeds + if ($cpu->{'cur-freq'} && !$info->{'speed'}){ + $info->{'speed'} = $cpu->{'cur-freq'}; + } + if ($cpu->{'min-freq'} || $cpu->{'max-freq'}){ + ($info->{'min-max'},$info->{'min-max-key'}) = cp_speed_min_max( + $cpu->{'min-freq'}, + $cpu->{'max-freq'}); + } + if ($cpu->{'scaling-min-freq'} || $cpu->{'scaling-max-freq'}){ + ($info->{'scaling-min-max'},$info->{'scaling-min-max-key'}) = cp_speed_min_max( + $cpu->{'scaling-min-freq'}, + $cpu->{'scaling-max-freq'}, + 'sc'); + } + if ($cpu->{'cur-freq'}){ + if ($show{'short'}){ + $info->{'speed-key'} = 'speed'; + } + elsif ($show{'cpu-basic'}){ + $info->{'speed-key'} = 'speed (MHz)'; + } + else { + $info->{'speed-key'} = 'Speed (MHz)'; + } + } + eval $end if $b_log; + return $info; +} + +sub cp_speed_min_max { + my ($min,$max,$type) = @_; + my ($min_max,$key); + if ($min && $max){ + $min_max = "$min/$max"; + $key = "min/max"; + } + elsif ($max){ + $min_max = $max; + $key = "max"; + } + elsif ($min){ + $min_max = $min; + $key = "min"; + } + $key = $type . '-' . $key if $type && $key; + return ($min_max,$key); +} + +# args: 0: cpu, by ref; 1: update $tests by reference +sub cp_test_types { + my ($cpu,$tests) = @_; + if ($cpu->{'type'} eq 'intel'){ + $$tests{'intel'} = 1; + $$tests{'xeon'} = 1 if $cpu->{'model_name'} =~ /Xeon/i; + } + elsif ($cpu->{'type'} eq 'amd'){ + if ($cpu->{'family'} && $cpu->{'family'} eq '17'){ + $$tests{'amd-zen'} = 1; + if ($cpu->{'model_name'}){ + if ($cpu->{'model_name'} =~ /Ryzen/i){ + $$tests{'ryzen'} = 1; + } + elsif ($cpu->{'model_name'} =~ /EPYC/i){ + $$tests{'epyc'} = 1; + } + } + } + } + elsif ($cpu->{'type'} eq 'elbrus'){ + $$tests{'elbrus'} = 1; + } +} + +sub cp_topology { + my ($counts,$topology) = @_; + my @alpha = qw(Single Dual Triple Quad); + my ($sep) = (''); + my (%keys,%done); + my @tests = ('x'); # prefill [0] because iterator runs before 'next' test. + if ($counts->{'cpu-topo'}){ + # first we want to find out how many of each physical variant there are + foreach my $topo (@{$counts->{'cpu-topo'}}){ + # turn sorted hash into string + my $test = join('::', map{$_ . ':' . $topo->{$_}} sort keys %$topo); + if ($keys{$test}){ + $keys{$test}++; + } + else { + $keys{$test} = 1; + } + push(@tests,$test); + } + my ($i,$j) = (0,0); + # then we build up the topology data per variant + foreach my $topo (@{$counts->{'cpu-topo'}}){ + my $key = ''; + $i++; + next if $done{$tests[$i]}; + $done{$tests[$i]} = 1; + if ($b_admin && $type eq 'full'){ + $topology->{'full'}[$j]{'cpus'} = $keys{$tests[$i]}; + $topology->{'full'}[$j]{'cores'} = $topo->{'cores'}; + if ($topo->{'threads'} && $topo->{'cores'} != $topo->{'threads'}){ + $topology->{'full'}[$j]{'threads'} = $topo->{'threads'}; + } + if ($topo->{'dies'}){ + $topology->{'full'}[$j]{'dies-count'} = $topo->{'dies'}; + } + if ($topo->{'clusters'}){ + # clusters _should_ be per die, but it's not a guarantee + if ($topo->{'dies'} && $topo->{'dies'} > 1){ + $topo->{'clusters'} = $topo->{'dies'} . 'x' . $topo->{'clusters'}; + } + $topology->{'full'}[$j]{'clusters'} = $topo->{'clusters'}; + } + if ($counts->{'struct-mt'}){ + $topology->{'full'}[$j]{'cores-mt'} = $topo->{'cores-mt'}; + } + if ($counts->{'struct-st'}){ + $topology->{'full'}[$j]{'cores-st'} = $topo->{'cores-st'}; + } + if ($counts->{'struct-max'} || $counts->{'struct-min'}){ + $topology->{'full'}[$j]{'max'} = $topo->{'max'}; + $topology->{'full'}[$j]{'min'} = $topo->{'min'}; + } + if ($topo->{'smt'}){ + $topology->{'full'}[$j]{'smt'} = $topo->{'smt'}; + } + if ($topo->{'tpc'}){ + $topology->{'full'}[$j]{'tpc'} = $topo->{'tpc'}; + } + $j++; + } + else { + # start building string + $topology->{'string'} .= $sep; + $sep = ','; + if ($counts->{'physical'} > 1) { + my $phys = ($topology->{'struct-cores'}) ? $keys{$tests[$i]} : $counts->{'physical'}; + $topology->{'string'} .= $phys . 'x '; + $topology->{'string'} .= $topo->{'cores'} . '-core'; + } + else { + $topology->{'string'} .= cp_cores_alpha($topo->{'cores'}); + } + # alder lake type cpu + if ($topo->{'cores-st'} && $topo->{'cores-mt'}){ + $topology->{'string'} .= ' (' . $topo->{'cores-mt'} . '-mt/'; + $topology->{'string'} .= $topo->{'cores-st'} . '-st)'; + } + # we only want to show > 1 phys short form basic if cpus have different + # core counts, not different min/max frequencies + last if !$topology->{'struct-cores'}; + } + } + } + else { + if ($counts->{'physical'} > 1) { + $topology->{'string'} = $counts->{'physical'} . 'x '; + $topology->{'string'} .= $counts->{'cpu-cores'} . '-core'; + } + else { + $topology->{'string'} = cp_cores_alpha($counts->{'cpu-cores'}); + } + } + $topology->{'string'} ||= ''; +} +## END CP TOOLS +## END CPU PROPERTIES ## + ## START CPU ARCH ## sub cp_cpu_arch { eval $start if $b_log; @@ -11464,13 +11792,13 @@ sub cp_cpu_arch { # shares model 8 with zen, stepping unknown elsif ($model =~ /^(8)$/){ $arch = 'Zen+'; - $gen = '2'; + $gen = '1+'; $process = 'GF 12nm'; $year = '2018-21';} # used this but it didn't age well: ^(2[0123456789ABCDEF]| elsif ($model =~ /^(3.|4.|5.|6.|7.|8.|9.|A.)$/){ $arch = 'Zen 2'; - $gen = '3'; + $gen = '2'; $process = 'TSMC n7 (7nm)'; # some consumer maybe GF 14nm $year = '2020-22';} else { @@ -11492,26 +11820,26 @@ sub cp_cpu_arch { # zen4c is for cloud hyperscale if ($model =~ /^(78)$/){ $arch = 'Zen 4c'; - $gen = '5'; - $process = 'TSMC n4 (4nm)'; + $gen = '4'; + $process = 'TSMC n5 (5nm)'; # roadmapped to n4 originally $year = '2023+';} # ext model 6,7, base models trickling in # 10 engineering sample elsif ($model =~ /^(1.|6.|7.|A.)$/){ $arch = 'Zen 4'; - $gen = '5'; + $gen = '4'; $process = 'TSMC n5 (5nm)'; $year = '2022+';} # double check 40, 44; 21 confirmed elsif ($model =~ /^(21|4.)$/){ $arch = 'Zen 3+'; - $gen = '4'; + $gen = '3'; $process = 'TSMC n6 (7nm)'; $year = '2022';} # 21, 50: step 0; known: 21, 3x, 50 elsif ($model =~ /^(0|1|8|2.|3.|5.)$/){ $arch = 'Zen 3'; - $gen = '4'; + $gen = '3'; $process = 'TSMC n7 (7nm)'; $year = '2021-22';} else { @@ -11525,13 +11853,18 @@ sub cp_cpu_arch { if ($model =~ /^(0)$/){ $arch = 'Zen 5'; $gen = '5'; - $process = 'TSMC n3 (3nm)'; # turin could be 4nm, need more data + $process = 'TSMC n4 (4nm)'; # turin could be 4nm, need more data $year = '2023+';} + elsif ($model =~ /^(1.)$/){ + $arch = 'Zen 5c'; + $gen = '5'; + $process = 'TSMC n3 (3nm)'; # turin could be 4nm, need more data + $year = '2024+';} # Strix Point; Granite Ridge; Krackan Point; Strix Halo - elsif ($model =~ /^(10|20|40|60|70)$/){ + elsif ($model =~ /^(2.|4.|6.|7.)$/){ $arch = 'Zen 5'; $gen = '5'; - $process = 'TSMC n3 (3nm)'; # desktop, granite ridge, confirm 2024 + $process = 'TSMC n4 (4nm)'; # desktop, granite ridge, confirm 2024 $year = '2024+';} else { $arch = 'Zen 5'; @@ -12013,7 +12346,11 @@ sub cp_cpu_arch { $year = '2023+';} elsif ($model =~ /^(AD|AE)$/){ $arch = 'Granite Rapids'; # ? - $process = 'Intel 3 (7nm+)'; # confirm + $process = 'Intel 3 (7nm+)'; # listed with intel 3 and 7 + $year = '2024+';} + elsif ($model =~ /^(AF)$/){ + $arch = 'Sierra Forest'; # ? + $process = 'Intel 3 (5nm)'; $year = '2024+';} elsif ($model =~ /^(B6)$/){ $arch = 'Grand Ridge'; # 14 gen @@ -12025,10 +12362,10 @@ sub cp_cpu_arch { $year = '2022+';} elsif ($model =~ /^(BC|BD)$/){ $arch = 'Lunar Lake'; # 15 gn - $process = 'Intel 18a (1.8nm)'; + $process = 'TSMC n3b (3nm)'; # n6 controller tile. Announced w/intel 18a $year = '2024+';} # seen APU IDs, so out there # Meteor Lake-S maybe cancelled, replaced by arrow - elsif ($model =~ /^(C5|C6)$/){ + elsif ($model =~ /^(C5|C6|CA)$/){ $arch = 'Arrow Lake'; # 15 gen; igpu battleimage 3/4nm # gfx tile is TSMC 3nm $process = 'Intel 20a (2nm)';# TSMC 3nm (corei3-5)/Intel 20A 2nm (core i5-9) @@ -12041,6 +12378,10 @@ sub cp_cpu_arch { $arch = 'Emerald Rapids'; # 5th gen xeon $process = 'Intel 7 (10nm)'; $year = '2023+';} + elsif ($model =~ /^(DD)$/){ + $arch = 'Clearwater Forest'; + $process = 'Intel 18a (1.8nm)'; + $year = '2025+';} ## roadmaps: check and update, since Intel misses their targets often # Sapphire Rapids: 13 gen (?), Intel 7 (10nm), 2023 # Emerald Rapids: Intel 7 (10nm), 2023 @@ -12195,212 +12536,170 @@ sub cp_cpu_arch { } ## END CPU ARCH ## -# Only AMD/Intel 64 bit cpus -sub cp_cpu_level { +## LEGACY CPU DATA ENGINE ## +sub cp_data_fallback { eval $start if $b_log; - 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; - } - } + my ($cpu,$caches,$cache_check,$counts,$tests) = @_; + if (!$counts->{'physical'}){ + # handle case where cpu reports say, phys id 0, 2, 4, 6 + foreach (@{$cpu->{'ids'}}){ + $counts->{'physical'}++ if $_; } } - $level = [$level,$note] if $level; - eval $end if $b_log; - return $level; -} - -sub cp_cpu_topology { - my ($counts,$topology) = @_; - my @alpha = qw(Single Dual Triple Quad); - my ($sep) = (''); - my (%keys,%done); - my @tests = ('x'); # prefill [0] because iterator runs before 'next' test. - if ($counts->{'cpu-topo'}){ - # first we want to find out how many of each physical variant there are - foreach my $topo (@{$counts->{'cpu-topo'}}){ - # turn sorted hash into string - my $test = join('::', map{$_ . ':' . $topo->{$_}} sort keys %$topo); - if ($keys{$test}){ - $keys{$test}++; - } - else { - $keys{$test} = 1; - } - push(@tests,$test); - } - my ($i,$j) = (0,0); - # then we build up the topology data per variant - foreach my $topo (@{$counts->{'cpu-topo'}}){ - my $key = ''; - $i++; - next if $done{$tests[$i]}; - $done{$tests[$i]} = 1; - if ($b_admin && $type eq 'full'){ - $topology->{'full'}[$j]{'cpus'} = $keys{$tests[$i]}; - $topology->{'full'}[$j]{'cores'} = $topo->{'cores'}; - if ($topo->{'threads'} && $topo->{'cores'} != $topo->{'threads'}){ - $topology->{'full'}[$j]{'threads'} = $topo->{'threads'}; - } - if ($topo->{'dies'} && $topo->{'dies'} > 1){ - $topology->{'full'}[$j]{'dies'} = $topo->{'dies'}; - } - if ($counts->{'struct-mt'}){ - $topology->{'full'}[$j]{'cores-mt'} = $topo->{'cores-mt'}; - } - if ($counts->{'struct-st'}){ - $topology->{'full'}[$j]{'cores-st'} = $topo->{'cores-st'}; - } - if ($counts->{'struct-max'} || $counts->{'struct-min'}){ - $topology->{'full'}[$j]{'max'} = $topo->{'max'}; - $topology->{'full'}[$j]{'min'} = $topo->{'min'}; - } - if ($topo->{'smt'}){ - $topology->{'full'}[$j]{'smt'} = $topo->{'smt'}; - } - if ($topo->{'tpc'}){ - $topology->{'full'}[$j]{'tpc'} = $topo->{'tpc'}; - } - $j++; - } - else { - # start building string - $topology->{'string'} .= $sep; - $sep = ','; - if ($counts->{'physical'} > 1) { - my $phys = ($topology->{'struct-cores'}) ? $keys{$tests[$i]} : $counts->{'physical'}; - $topology->{'string'} .= $phys . 'x '; - $topology->{'string'} .= $topo->{'cores'} . '-core'; - } - else { - $topology->{'string'} .= cp_cpu_alpha($topo->{'cores'}); - } - # alder lake type cpu - if ($topo->{'cores-st'} && $topo->{'cores-mt'}){ - $topology->{'string'} .= ' (' . $topo->{'cores-mt'} . '-mt/'; - $topology->{'string'} .= $topo->{'cores-st'} . '-st)'; - } - # we only want to show > 1 phys short form basic if cpus have different - # core counts, not different min/max frequencies - last if !$topology->{'struct-cores'}; + # count unique processors ## + # note, this fails for intel cpus at times + # print ref $cpu->{'processors'}, "\n"; + if (!$counts->{'processors'}){ + $counts->{'processors'} = scalar @{$cpu->{'processors'}}; + } + # print "p count:$counts->{'processors'}\n"; + # print Data::Dumper::Dumper $cpu->{'processors'}; + # $counts->{'cpu-cores'} is per physical cpu + # note: elbrus supports turning off cores, so we need to add one for cases + # where rounds to 0 or 1 less + # print "$cpu{'type'},$cpu{'family'},$cpu{'model-id'},$cpu{'arch'}\n"; + if ($tests->{'elbrus'} && $counts->{'processors'}){ + my $elbrus = cp_elbrus_data($cpu->{'family'},$cpu->{'model-id'}, + $counts->{'processors'},$cpu->{'arch'}); + $counts->{'cpu-cores'} = $elbrus->[0]; + $counts->{'physical'} = $elbrus->[1]; + $cpu->{'arch'} = $elbrus->[2]; + # print 'model id: ' . $cpu->{'model-id'} . ' arch: ' . $cpu->{'arch'} . " cpc: $counts->{'cpu-cores'} phyc: $counts->{'physical'} proc: $counts->{'processors'} \n"; + } + $counts->{'physical'} ||= 1; # assume 1 if no id found, as with ARM + foreach my $die_ref (@{$cpu->{'ids'}}){ + next if ref $die_ref ne 'ARRAY'; + $counts->{'cores'} = 0; + $counts->{'dies'} = scalar @$die_ref; + #$cpu->{'dies-count'} = $counts->{'dies'}; + foreach my $core_ref (@$die_ref){ + next if ref $core_ref ne 'ARRAY'; + $counts->{'cores'} = 0;# reset for each die!! + # NOTE: the counters can be undefined because the index comes from + # core id: which can be 0 skip 1 then 2, which leaves index 1 undefined + # risc cpus do not actually show core id so ignore that counter + foreach my $id (@$core_ref){ + $counts->{'cores'}++ if defined $id && !%risc; } + # print 'cores: ' . $counts->{'cores'}, "\n"; } } - else { - if ($counts->{'physical'} > 1) { - $topology->{'string'} = $counts->{'physical'} . 'x '; - $topology->{'string'} .= $counts->{'cpu-cores'} . '-core'; + # this covers potentially cases where ARM cpus have > 1 die + # maybe applies to all risc, not sure, but dies is broken anyway for cpuinfo + if (!$cpu->{'dies-count'}){ + if ($risc{'arm'} && $counts->{'dies'} <= 1 && $cpu->{'dies-count'} > 1){ + $counts->{'dies'} = $cpu->{'dies-count'}; } else { - $topology->{'string'} = cp_cpu_alpha($counts->{'cpu-cores'}); + $cpu->{'dies-count'} = $counts->{'dies'}; } } - $topology->{'string'} ||= ''; -} - -sub cp_cpu_alpha { - my $cores = $_[0]; - my $string = ''; - if ($cores > 4){ - $string = $cores . '-core'; - } - elsif ($cores == 0){ - $string = main::message('unknown-cpu-topology'); - } - else { - my @alpha = qw(single dual triple quad); - $string = $alpha[$cores-1] . ' core'; + # this is an attempt to fix the amd family 15 bug with reported cores vs actual cores + # NOTE: amd A6-4400M APU 2 core reports: cores: 1 siblings: 2 + # NOTE: AMD A10-5800K APU 4 core reports: cores: 2 siblings: 4 + if (!$counts->{'cpu-cores'}){ + if ($cpu->{'cores'} && !$counts->{'cores'} || + $cpu->{'cores'} >= $counts->{'cores'}){ + $counts->{'cpu-cores'} = $cpu->{'cores'}; + } + elsif ($counts->{'cores'} > $cpu->{'cores'}){ + $counts->{'cpu-cores'} = $counts->{'cores'}; + } } - return $string; -} - -# Logic: -# if > 1 processor && processor id (physical id) == core id then Multi threaded (MT) -# if siblings > 1 && siblings == 2 * num_of_cores ($cpu->{'cores'}) then Multi threaded (MT) -# if > 1 processor && processor id (physical id) != core id then Multi-Core Processors (MCP) -# if > 1 processor && processor ids (physical id) > 1 then Symmetric Multi Processing (SMP) -# if = 1 processor then single core/processor Uni-Processor (UP) -sub cp_cpu_type { - eval $start if $b_log; - my ($counts,$cpu,$tests) = @_; - my $cpu_type = ''; - if ($counts->{'processors'} > 1 || - (defined $tests->{'intel'} && $tests->{'intel'} && $cpu->{'siblings'} > 0)){ - # cpu_sys detected MT - if ($counts->{'struct-mt'}){ - if ($counts->{'struct-mt'} && $counts->{'struct-st'}){ - $cpu_type .= 'MST'; + # print "cpu-c:$counts->{'cpu-cores'}\n"; + # $counts->{'cpu-cores'} = $cpu->{'cores'}; + # like, intel core duo + # NOTE: sadly, not all core intel are HT/MT, oh well... + # xeon may show wrong core / physical id count, if it does, fix it. A xeon + # may show a repeated core id : 0 which gives a fake num_of_cores=1 + if ($tests->{'intel'}){ + if ($cpu->{'siblings'} && $cpu->{'siblings'} > 1 && + $cpu->{'cores'} && $cpu->{'cores'} > 1){ + if ($cpu->{'siblings'}/$cpu->{'cores'} == 1){ + $tests->{'intel'} = 0; + $tests->{'ht'} = 0; } else { - $cpu_type .= 'MT'; + $counts->{'cpu-cores'} = ($cpu->{'siblings'}/2); + $tests->{'ht'} = 1; } } - # handle case of OpenBSD that has hw.smt but no other meaningful topology - elsif ($cpu->{'smt'}){ - $cpu_type .= 'MT' if $cpu->{'smt'} eq 'enabled'; - } - # non-multicore MT, with 2 or more threads per core - elsif ($counts->{'processors'} && $counts->{'physical'} && - $counts->{'cpu-cores'} && - $counts->{'processors'}/($counts->{'physical'} * $counts->{'cpu-cores'}) >= 2){ - # print "mt:1\n"; - $cpu_type .= 'MT'; - } - # 2 or more siblings per cpu real core - elsif ($cpu->{'siblings'} > 1 && $cpu->{'siblings'}/$counts->{'cpu-cores'} >= 2){ - # print "mt:3\n"; - $cpu_type .= 'MT'; + } + # ryzen is made out of blocks of 2, 4, or 8 core dies... + if ($tests->{'ryzen'}){ + $counts->{'cpu-cores'} = $cpu->{'cores'}; + # note: posix ceil isn't present in Perl for some reason, deprecated? + my $working = $counts->{'cpu-cores'} / 8; + my @temp = split('\.', $working); + $cpu->{'dies-count'} = ($temp[1] && $temp[1] > 0) ? $temp[0]++ : $temp[0]; + $counts->{'dies'} = $cpu->{'dies-count'}; + } + # these always have 4 dies + elsif ($tests->{'epyc'}){ + $counts->{'cpu-cores'} = $cpu->{'cores'}; + $counts->{'dies'} = $cpu->{'dies-count'} = 4; + } + # final check, override the num of cores value if it clearly is wrong + # and use the raw core count and synthesize the total instead of real count + if ($counts->{'cpu-cores'} == 0 && + $cpu->{'cores'} * $counts->{'physical'} > 1){ + $counts->{'cpu-cores'} = ($cpu->{'cores'} * $counts->{'physical'}); + } + # last check, seeing some intel cpus and vms with intel cpus that do not show any + # core id data at all, or siblings. + if ($counts->{'cpu-cores'} == 0 && $counts->{'processors'} > 0){ + $counts->{'cpu-cores'} = $counts->{'processors'}; + } + # this happens with BSDs which have very little cpu data available + if ($counts->{'processors'} == 0 && $counts->{'cpu-cores'} > 0){ + $counts->{'processors'} = $counts->{'cpu-cores'}; + if ($bsd_type && ($tests->{'ht'} || $tests->{'amd-zen'}) && + $counts->{'cpu-cores'} > 2){ + $counts->{'cpu-cores'} = $counts->{'cpu-cores'}/2;; } - # non-MT multi-core or MT multi-core - if ($counts->{'cpu-cores'} > 1){ - if ($counts->{'struct-mt'} && $counts->{'struct-st'}){ - $cpu_type .= ' AMCP'; - } - else { - $cpu_type .= ' MCP'; - } + my $count = $counts->{'processors'}; + $count-- if $count > 0; + $cpu->{'processors'}[$count] = 0; + # no way to get per processor speeds yet, so assign 0 to each + # must be a numeric value. Could use raw speed from core 0, but + # that would just be a hack. + foreach (0 .. $count){ + $cpu->{'processors'}[$_] = 0; } - # only solidly known > 1 die cpus will use this - if ($cpu->{'dies'} > 1){ - $cpu_type .= ' MCM'; + } + # so far only OpenBSD has a way to detect MT cpus, but Openbsd has disabled MT + if ($bsd_type){ + if ($cpu->{'siblings'} && + $counts->{'cpu-cores'} && $counts->{'cpu-cores'} > 1){ + $counts->{'cores-multiplier'} = $counts->{'cpu-cores'}; } - # >1 cpu sockets active: Symetric Multi Processing - if ($counts->{'physical'} > 1){ - if ($counts->{'struct-cores'} || $counts->{'struct-max'} || - $counts->{'struct-min'}){ - $cpu_type .= ' AMP'; - } - else { - $cpu_type .= ' SMP'; - } + # if no siblings we couldn't get MT status of cpu so can't trust cache + else { + $$cache_check = main::message('note-check'); } - $cpu_type =~ s/^\s+//; } - else { - $cpu_type = 'UP'; + # only elbrus shows L1 / L3 cache data in cpuinfo, cpu_sys data should show + # for newer full linux. + elsif ($counts->{'cpu-cores'} && + ($tests->{'elbrus'} || $counts->{'cpu-cores'} > 1)) { + $counts->{'cores-multiplier'} = $counts->{'cpu-cores'}; + } + # last test to catch some corner cases + # seen a case where a xeon vm in a dual xeon system actually had 2 cores, no MT + # so it reported 4 siblings, 2 cores, but actually only had 1 core per virtual cpu + # print "prc: $counts->{'processors'} phc: $counts->{'physical'} coc: $counts->{'cores'} cpc: $counts->{'cpu-cores'}\n"; + # this test was for arm but I think it applies to all risc, but risc will be sys + if (!%risc && + $counts->{'processors'} == $counts->{'physical'} * $counts->{'cores'} && + $counts->{'cpu-cores'} > $counts->{'cores'}){ + $tests->{'ht'} = 0; + # $tests->{'xeon'} = 0; + $tests->{'intel'} = 0; + $counts->{'cpu-cores'} = 1; + $counts->{'cores'} = 1; + $cpu->{'siblings'} = 1; } eval $end if $b_log; - return $cpu_type; } # Legacy: this data should be comfing from the /sys tool now. @@ -12436,143 +12735,9 @@ sub cp_elbrus_data { eval $end if $b_log; return $return; } +## END LEGACY CPU DATA ENGINE ## -sub cp_speed_data { - eval $start if $b_log; - my ($cpu,$cpu_sys) = @_; - my $info = {}; - if (defined $cpu_sys->{'data'}){ - if (defined $cpu_sys->{'data'}{'speeds'}{'min-freq'}){ - $cpu->{'min-freq'} = $cpu_sys->{'data'}{'speeds'}{'min-freq'}; - } - if (defined $cpu_sys->{'data'}{'speeds'}{'max-freq'}){ - $cpu->{'max-freq'} = $cpu_sys->{'data'}{'speeds'}{'max-freq'}; - } - if (defined $cpu_sys->{'data'}{'speeds'}{'scaling-min-freq'}){ - $cpu->{'scaling-min-freq'} = $cpu_sys->{'data'}{'speeds'}{'scaling-min-freq'}; - } - if (defined $cpu_sys->{'data'}{'speeds'}{'scaling-max-freq'}){ - $cpu->{'scaling-max-freq'} = $cpu_sys->{'data'}{'speeds'}{'scaling-max-freq'}; - } - # we don't need to see these if they are the same - if ($cpu->{'min-freq'} && $cpu->{'max-freq'} && - $cpu->{'scaling-min-freq'} && $cpu->{'scaling-max-freq'} && - $cpu->{'min-freq'} eq $cpu->{'scaling-min-freq'} && - $cpu->{'max-freq'} eq $cpu->{'scaling-max-freq'}){ - undef $cpu->{'scaling-min-freq'}; - undef $cpu->{'scaling-max-freq'}; - } - if (defined $cpu_sys->{'data'}{'speeds'}{'all'}){ - # only replace if we got actual speed values from cpufreq, or if no legacy - # sourced processors data. Handles fake syz core speeds for counts. - if ((grep {$_} @{$cpu_sys->{'data'}{'speeds'}{'all'}}) || - !@{$cpu->{'processors'}}){ - $cpu->{'processors'} = $cpu_sys->{'data'}{'speeds'}{'all'}; - } - } - if (defined $cpu_sys->{'data'}{'cpufreq-boost'}){ - $cpu->{'boost'} = $cpu_sys->{'data'}{'cpufreq-boost'}; - } - } - if (defined $cpu->{'processors'}){ - if (scalar @{$cpu->{'processors'}} > 1){ - my ($agg,$high) = (0,0); - for (@{$cpu->{'processors'}}){ - next if !$_; # bsds might have 0 or undef value, that's junk - $agg += $_; - $high = $_ if $_ > $high; - } - if ($agg){ - $cpu->{'avg-freq'} = int($agg/scalar @{$cpu->{'processors'}}); - $cpu->{'cur-freq'} = $high; - $info->{'avg-speed-key'} = 'avg'; - $info->{'speed'} = $cpu->{'avg-freq'}; - if ($high > $cpu->{'avg-freq'}){ - $cpu->{'high-freq'} = $high; - $info->{'high-speed-key'} = 'high'; - } - } - } - elsif ($cpu->{'processors'}[0]) { - $cpu->{'cur-freq'} = $cpu->{'processors'}[0]; - $info->{'speed'} = $cpu->{'cur-freq'}; - } - } - # BSDs generally will have processors count, but not per core speeds - if ($cpu->{'cur-freq'} && !$info->{'speed'}){ - $info->{'speed'} = $cpu->{'cur-freq'}; - } - if ($cpu->{'min-freq'} || $cpu->{'max-freq'}){ - ($info->{'min-max'},$info->{'min-max-key'}) = cp_speed_min_max( - $cpu->{'min-freq'}, - $cpu->{'max-freq'}); - } - if ($cpu->{'scaling-min-freq'} || $cpu->{'scaling-max-freq'}){ - ($info->{'scaling-min-max'},$info->{'scaling-min-max-key'}) = cp_speed_min_max( - $cpu->{'scaling-min-freq'}, - $cpu->{'scaling-max-freq'}, - 'sc'); - } - if ($cpu->{'cur-freq'}){ - if ($show{'short'}){ - $info->{'speed-key'} = 'speed'; - } - elsif ($show{'cpu-basic'}){ - $info->{'speed-key'} = 'speed (MHz)'; - } - else { - $info->{'speed-key'} = 'Speed (MHz)'; - } - } - eval $end if $b_log; - return $info; -} - -sub cp_speed_min_max { - my ($min,$max,$type) = @_; - my ($min_max,$key); - if ($min && $max){ - $min_max = "$min/$max"; - $key = "min/max"; - } - elsif ($max){ - $min_max = $max; - $key = "max"; - } - elsif ($min){ - $min_max = $min; - $key = "min"; - } - $key = $type . '-' . $key if $type && $key; - return ($min_max,$key); -} - -# args: 0: cpu, by ref; 1: update $tests by reference -sub cp_test_types { - my ($cpu,$tests) = @_; - if ($cpu->{'type'} eq 'intel'){ - $$tests{'intel'} = 1; - $$tests{'xeon'} = 1 if $cpu->{'model_name'} =~ /Xeon/i; - } - elsif ($cpu->{'type'} eq 'amd'){ - if ($cpu->{'family'} && $cpu->{'family'} eq '17'){ - $$tests{'amd-zen'} = 1; - if ($cpu->{'model_name'}){ - if ($cpu->{'model_name'} =~ /Ryzen/i){ - $$tests{'ryzen'} = 1; - } - elsif ($cpu->{'model_name'} =~ /EPYC/i){ - $$tests{'epyc'} = 1; - } - } - } - } - elsif ($cpu->{'type'} eq 'elbrus'){ - $$tests{'elbrus'} = 1; - } -} - -## CPU UTILITIES ## +## CPU SHARED UTILITIES ## # args: 0: vendor_id,like GenuineIntel, AuthenticAMD sub cpu_vendor { eval $start if $b_log; @@ -12604,7 +12769,6 @@ sub set_cpu_data { 'bogomips' => 0, 'cores' => 0, 'cur-freq' => 0, # MHz - 'dies' => 0, 'family' => '', 'flags' => '', 'ids' => [], @@ -12650,6 +12814,7 @@ sub system_cpu_name { eval $end if $b_log; return $cpus; } +## END CPU SHARED UTILITIES ## ## CLEANERS/OUTPUT HANDLERS ## # MHZ - cell cpus @@ -12690,9 +12855,11 @@ sub hex_and_decimal { } return $data; } +## END CLEANERS/OUTPUT HANDLERS } +## END CpuItem ## -## DriveItem +## DriveItem ## { package DriveItem; my ($b_hddtemp,$b_nvme,$smartctl_missing,$vendors); @@ -13996,14 +14163,14 @@ sub set_disk_vendors { ['(\bINTEL\b|^(SSD(PAM|SA2)|HBR|(MEM|SSD)PEB?K|SSD(MCE|S[AC])))','\bINTEL\b','Intel',''], ['^(Intel[\s_-]?)?SRCSAS?','^Intel','Intel RAID',''], # note: S[AV][1-9]\d can trigger false positives - ['(K(ING)?STON|^(OM8P|RBU|S[AV][1234]00|S[HMN]S|SK[CY]|SQ5|SS200|SVP|SS0|SUV|SNV|T52|T[AB]29|Ultimate CF)|V100|DataTraveler|DT\s?(DUO|Microduo|101)|HyperX|13fe\b)','(KINGSTON|13fe)','Kingston',''], # maybe SHS: SHSS37A SKC SUV + ['(K(ING)?STON|^(A400|ASTC|OM8P|RBU|S100\d\d|S[AV][1234]00|S[HMN]S|SK[CY]|SQ5|SS200|SVP|SS0|SUV|SNV|T52|T[ABY]29|Y29\d|Ultimate CF)|V100|DataTraveler|DT\s?(DUO|Microduo|101)|HyperX|13fe\b)','(KINGSTON|13fe)','Kingston',''], # maybe SHS: SHSS37A SKC SUV # must come before samsung MU. NOTE: toshiba can have: TOSHIBA_MK6475GSX: mush: MKNSSDCR120GB_ ['(^MKN|Mushkin)','Mushkin','Mushkin',''], # MKNS # MU = Multiple_Flash_Reader too risky: |M[UZ][^L] HD103SI HD start risky # HM320II HM320II HM - ['(SAMSUNG|^(AWMB|[BC]DS20|[BC]WB|BJ[NT]|[BC]GND|CJ[NT]|CKT|CUT|[DG]3 Station|DUO\b|DUT|EB\dMW|E[CS]\d[A-Z]\d|FD\d[A-Z]\dGE4S5|[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 + ['(SAMSUNG|^(AGN[BD]|AWMB|[BC]DS20|[BCD]WB|BJ[NT]|[BC]GND|CJ[NT]|CKT|CUT|[DG]3 Station|DUO\b|DUT|EB\dMW|E[CS]\d[A-Z]\d|ED2|EE4|FD\d[A-Z]\d|[GS]2 Portable|GE4|GN|HD\d{3}[A-Z]{2}$|(HM|SP)\d{2}|HS\d|KLUD|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|^(A[BCD]LC[DE]|AFGCE|D[AB]4|DX[1-9]|Extreme|Firebird|S[CD]\d{2}G|SC\d{3,4}|SD(CF|S[S]?[ADQ]|SL\d+G|SU\d|U\d|\sUltra)|SDW[1-9]|SE\d{2}|SEM\d{2}|\d[STU]|U(3\b|1\d0))|Clip Sport|Cruzer|iXpand|SN(\d+G|128|256)|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|EZSD|Firebird|S[CD]\d{2}G|SB\d+G|SC\d{3,4}|SD(CF|S[S]?[ADQ]|SL\d+G|SU\d|U\d|\sUltra)|SDW[1-9]|SE\d{2}|SEM\d{2}|\d[STU]|U(3\b|1\d0))|Clip Sport|Cruzer|iXpand|SN(\d+G|128|256)|SSD (Plus|U1[01]0) [1-9]|SU(02|04|08|16|32|64)G|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 @@ -14032,7 +14199,7 @@ sub set_disk_vendors { ['^((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|c350|DF\d|EG0\d{3}|EX9\d\d|G[BJ]\d|F[BK]|0-9]|HC[CPY]\d|MM\d{4}|[MV]B[0-6]|PSS|VO0|VK0|v\d{3}[bgorw]$|x\d{3}[w]$|XR\d{4})','^HP','HP',''], - ['^(Lexar|LSD|JumpDrive|JD\s?Firefly|LX\d|WorkFlow)','^Lexar','Lexar',''], # mmc-LEXAR_0xb016546c; JD Firefly; + ['^(Lexar|LSD|JumpDrive|JD\s?Firefly|LX\d|NCard|ND\d+GB|WorkFlow)','^Lexar','Lexar',''], # mmc-LEXAR_0xb016546c; JD Firefly; # these must come before maxtor because STM ['^STmagic','^STmagic','STmagic',''], ['^(STMicro|SMI|CBA)','^(STMicroelectronics|SMI)','SMI (STMicroelectronics)',''], @@ -14054,6 +14221,7 @@ sub set_disk_vendors { ['^2[\s-]?Power','^2[\s-]?Power','2-Power',''], ['^(3ware|9650SE)','^3ware','3ware (controller)',''], ['^5ACE','^5ACE','5ACE',''], # could be seagate: ST316021 5ACE + ['^51RISC','^51RISC','51risc',''], ['^(Aar(vex)?|AX\d{2})','^AARVEX','AARVEX',''], ['^(AbonMax|ASU\d)','^AbonMax','AbonMax',''], ['^Acasis','^Acasis','Acasis (hub)',''], @@ -14071,6 +14239,7 @@ sub set_disk_vendors { ['^Aigo','^Aigo','Aigo',''], ['^AirDisk','^AirDisk','AirDisk',''], ['^Aireye','^Aireye','Aireye',''], + ['^AiteFeir','^AiteFeir','AiteFeir',''], ['^Alcatel','^Alcatel','Alcatel',''], ['^(Alcor(\s?Micro)?|058F)','^(Alcor(\s?Micro)?|058F)','Alcor Micro',''], ['^Alfawise','^Alfawise','Alfawise',''], @@ -14080,6 +14249,8 @@ sub set_disk_vendors { ['^ANK','^Anker','Anker',''], ['^Ant[\s_-]?Esports','^Ant[\s_-]?Esports','Ant Esports',''], ['^Anucell','^Anucell','Anucell',''], + ['^Aoluska','^Aoluska','Aoluska',''], + ['^(Aotec|AOK)','^Aotec','Aotec',''], ['^Apotop','^Apotop','Apotop',''], # must come before AP|Apacer ['^(APPLE|iPod|SSD\sSM\d+[CEGT])','^APPLE','Apple',''], @@ -14087,6 +14258,7 @@ sub set_disk_vendors { ['^(Apricom|SATAWire)','^Apricom','Apricom',''], ['^(A-?RAM|ARSSD)','^A-?RAM','A-RAM',''], ['^Arch','^Arch(\s*Memory)?','Arch Memory',''], + ['(Ardor|\bAlly\b|\bAL\d\d)','Ardor(\sGaming)?','Ardor Gaming',''], ['^(Asenno|AS[1-9])','^Asenno','Asenno',''], ['^Asgard','^Asgard','Asgard',''], ['^ASint','^ASint','ASint',''], @@ -14108,6 +14280,8 @@ sub set_disk_vendors { ['^BIWIN','^BIWIN','BIWIN',''], ['^Blackpcs','^Blackpcs','Blackpcs',''], ['^(BlitzWolf|BW-?PSSD)','^BlitzWolf','BlitzWolf',''], + ['^(BlueCase|BS2N\d)','^BlueCase[\s-]?(Horizon)?','BlueCase Horizon',''], + ['^(Blue[\s-]?Feather|BF\d)','^Blue[\s-]?Feather','Blue Feather',''], ['^(BlueRay|SDM\d)','^BlueRay','BlueRay',''], ['^Bory','^Bory','Bory',''], ['^Braveeagle','^Braveeagle','BraveEagle',''], @@ -14122,7 +14296,9 @@ sub set_disk_vendors { ['^CHIPAL','^CHIPAL','CHIPAL',''], ['^(Chipsbank|CHIPSBNK)','^Chipsbank','Chipsbank',''], ['^(Chipfancie)','^Chipfancier','Chipfancier',''], + ['\bCKS','\bCKS','CKS',''], ['^Clover','^Clover','Clover',''], + ['^Codeo','^Codeo','Codeo',''], ['^CODi','^CODi','CODi',''], ['^Colorful\b','^Colorful','Colorful',''], ['^CONSISTENT','^CONSISTENT','Consistent',''], @@ -14148,8 +14324,9 @@ sub set_disk_vendors { ['^DGM','^DGM\b','DGM',''], ['^(DICOM|MAESTRO)','^DICOM','DICOM',''], ['^Digifast','^Digifast','Digifast',''], + ['^(DIGIRICH|DGSSD)','^DIGIRICH','DIGIRICH',''], ['^DIGITAL\s?FILM','DIGITAL\s?FILM','Digital Film',''], - ['^(Digma|Run(\sY2)?\b)','^Digma','Digma',''], + ['(Digma|\bRun\s)','\bDigma','Digma',''], ['^Dikom','^Dikom','Dikom',''], ['^DINGGE','^DINGGE','DINGGE',''], ['^Disain','^Disain','Disain',''], @@ -14160,12 +14337,13 @@ sub set_disk_vendors { ['^(Dogfish|M\.2 2242|Shark)','^Dogfish(\s*Technology)?','Dogfish Technology',''], ['^DragonDiamond','^DragonDiamond','DragonDiamond',''], ['^(DREVO\b|X1\s\d+[GT])','^DREVO','Drevo',''], + ['^Drobo','^Drobo','Drobo',''], ['^DSS','^DSS DAHUA','DSS DAHUA',''], ['^(Duex|DX\b)','^Duex','Duex',''], # DX\d may be starter for sandisk string ['^(Dynabook|AE[1-3]00)','^Dynabook','Dynabook',''], # DX1100 is probably sandisk, but could be HP, or it could be hp branded sandisk ['^(Eaget|V8$)','^Eaget','Eaget',''], - ['^(Easy[\s-]?Memory)','^Easy[\s-]?Memory','Easy Memory',''], + ['^(Easy[\s-]?Memory|EYM\d)','^Easy[\s-]?Memory','Easy Memory',''], ['^EDGE','^EDGE','EDGE Tech',''], ['^(EDILOCA|ES\d+\b)','^EDILOCA','Ediloca',''], ['^Elecom','^Elecom','Elecom',''], @@ -14180,8 +14358,10 @@ sub set_disk_vendors { ['^(Shenzhen\s)?Etopso(\sTechnology)?','^(Shenzhen\s)?Etopso(\sTechnology)?','Etopso',''], ['^EURS','^EURS','EURS',''], ['^eVAULT','^eVAULT','eVAULT',''], - ['^EVM','^EVM','EVM',''], + ['\bEVM','\bEVM','EVM',''], ['^eVtran','^eVtran','eVtran',''], + ['\bExbom','^\bExbom','Exbom',''], + ['^(ExeGate|EX\d\d)','^ExeGate','ExeGate',''], # NOTE: ESA3... may be IBM PCIe SAD card/drives ['^(EXCELSTOR|r technology)','^EXCELSTOR( TECHNO(LOGY)?)?','ExcelStor',''], ['^EXRAM','^EXRAM','EXRAM',''], @@ -14196,15 +14376,18 @@ sub set_disk_vendors { ['^FiiO','^FiiO','FiiO',''], ['^FixMeStick','^FixMeStick','FixMeStick',''], ['^(FIKWOT|FS\d{3})','^FIKWOT','Kikwot',''], + ['^FNK[\s-]?TECH','^FNK[\s-]?TECH','FNK Tech',''], ['^Fordisk','^Fordisk','Fordisk',''], # FK0032CAAZP/FB160C4081 FK or FV can be HP but can be other things ['^(FORESEE|B[123]0)|P900F|S900M','^FORESEE','Foresee',''], ['^Founder','^Founder','Founder',''], + ['^(FOXIN|FX\d\d)','^FOXIN','FOXIN',''], ['^(FOXLINE|FLD)','^FOXLINE','Foxline',''], # russian vendor? ['^(Gateway|W800S)','^Gateway','Gateway',''], ['^Freecom','^Freecom(\sFreecom)?','Freecom',''], ['^(FronTech)','^FronTech','Frontech',''], ['^(Fuhler|FL-D\d{3})','^Fuhler','Fuhler',''], + ['^(FuturePath|FPT)','^FuturePath([\s-]?Technologies)?','FuturePath',''], ['^Gaiver','^Gaiver','Gaiver',''], ['^(GALAX\b|Gamer\s?L|TA\dD|Gamer[\s-]?V)','^GALAX','GALAX',''], ['^Galaxy\b','^Galaxy','Galaxy',''], @@ -14212,14 +14395,17 @@ sub set_disk_vendors { ['^(Garmin|Fenix|Nuvi|Zumo)','^Garmin','Garmin',''], ['^Geil','^Geil','Geil',''], ['^GelL','^GelL','GelL',''], # typo for Geil? GelL ZENITH R3 120GB - ['^(Generic|A3A|G1J3|M0S00|SCA\d{2}|SCY|SLD|S0J\d|UY[567])','^Generic','Generic',''], + ['^(GemiBook|G52)','^GemiBook','GemiBook',''], + ['^(Generic|58A4|58K7|A3A|G1J3|M0S00|SCA\d{2}|SCY|SLD|S0J\d|UY[567])','^Generic','Generic',''], ['^(Genesis(\s?Logic)?|05e3)','(Genesis(\s?Logic)?|05e3)','Genesis Logic',''], ['^Geonix','^Geonix','Geonix',''], + ['^(Gerffins)','^Gerffins','Gerffins',''], ['^Getrich','^Getrich','Getrich',''], ['^(Gigabyte|GP-G)','^Gigabyte','Gigabyte',''], # SSD ['^Gigastone','^Gigastone','Gigastone',''], ['^Gigaware','^Gigaware','Gigaware',''], ['^GJN','^GJN\b','GJN',''], + ['^(Global[\s-]?Memory)','Global[\s-]?Memory','Global Memory',''], ['^(Gloway|FER\d)','^Gloway','Gloway',''], ['^GLOWY','^GLOWY','Glowy',''], ['^Goldendisk','^Goldendisk','Goldendisk',''], @@ -14230,13 +14416,15 @@ sub set_disk_vendors { ['^(Goline)','^Goline','Goline',''], # Wilk Elektronik SA, poland ['^((Wilk|WE)\s*)?(GOODRAM|GOODDRIVE|IR[\s-]?SSD|IRP|SSDPR|Iridium)','^GOODRAM','GOODRAM',''], + ['^(Gost)','^Gost','Gost',''], ['^(GreatWall|GW\d{3})','^GreatWall','GreatWall',''], ['^(GreenHouse|GH\b)','^GreenHouse','GreenHouse',''], ['^Gritronix','^Gritronixx?','Gritronix',''], # supertalent also has FM: |FM ['^(G[\.]?SKILL)','^G[\.]?SKILL','G.SKILL',''], ['^G[\s-]*Tech','^G[\s-]*Tech(nology)?','G-Technology',''], - ['^(Gudga|GIM\d+|G[NV](R\d|\d{2,4}\b))','^Gudga','Gudga',''], + ['\b(GTL|XEON)','\bGTL\b','GTL',''], + ['^(Gudga|GIM\d+|G[NV](R\d|\d{2,4}\b)|GS-?\d\d)','^Gudga','Gudga',''], ['^(Hajaan|HS[1-9])','^Haajan','Haajan',''], ['^Haizhide','^Haizhide','Haizhide',''], ['^(Hama|FlashPen\s?Fancy)','^Hama','Hama',''], @@ -14245,20 +14433,24 @@ sub set_disk_vendors { ['^Hectron','^Hectron','Hectron',''], ['^HEMA','^HEMA','HEMA',''], ['(HEORIADY|^HX-0)','^HEORIADY','HEORIADY',''], + ['^(Heovose)','^Heovose','Heovose',''], ['^(Hikvision|HKVSN|HS-SSD)','^Hikvision','Hikvision',''], ['^Hi[\s-]?Level ','^Hi[\s-]?Level ','Hi-Level',''], # ^HI\b with no Level? ['^(Hisense|H8G)','^Hisense','Hisense',''], + ['^(HJDK|MHD)','^HJDK','HJDK',''], + ['^(HMZM)','^HMZM','HMZM',''], ['^Hoodisk','^Hoodisk','Hoodisk',''], + ['^(HRUIYL)','^HRUIYL','HRUIYL',''], ['^(HUAWEI|HWE)','^HUAWEI','Huawei',''], ['^Hypertec','^Hypertec','Hypertec',''], ['^HyperX','^HyperX','HyperX',''], ['^(HYSSD|HY-)','^HYSSD','HYSSD',''], ['^(Hyundai|C2S\d|Sapphire)','^Hyundai','Hyundai',''], ['^iMRAM','^iMRAM','iMRA',''], - ['^(IBM|DT|ESA[1-9]|ServeRaid)','^IBM','IBM',''], # M5110 too common + ['^(IBM|DT|ESA[1-9]|GBR|ServeRaid)','^IBM','IBM',''], # M5110 too common ['^IEI Tech','^IEI Tech(\.|nology)?( Corp(\.|oration)?)?','IEI Technology',''], ['^(IGEL|UD Pocket)','^IGEL','IGEL',''], - ['^(Imation|Nano\s?Pro|HQT)','^Imation(\sImation)?','Imation',''], # Imation_ImationFlashDrive; TF20 is imation/tdk + ['^(Imation|Nano\s?Pro|HQT|Ridge)','^Imation(\sImation)?','Imation',''], # Imation_ImationFlashDrive; TF20 is imation/tdk ['^(IMC|Kanguru)','^IMC\b','IMC',''], ['^(Inateck|FE20)','^Inateck','Inateck',''], ['^(Inca\b|Npenterprise)','^Inca','Inca',''], @@ -14280,6 +14472,7 @@ sub set_disk_vendors { ['^(INO-|i\.?norys)','^i\.?norys','i.norys',''], ['^(Integrated[\s-]?Technology|IT\d+)','^Integrated[\s-]?Technology','Integrated Technology',''], ['^(Iomega|ZIP\b|Clik!)','^Iomega','Iomega',''], + ['^(IPASON|PD\d\d)','^IPASON','IPASON',''], ['^(i[\s_-]?portable\b|ATCS)','^i[\s_-]?portable','i-Portable',''], ['^ISOCOM','^ISOCOM','ISOCOM (Shenzhen Longsys Electronics)',''], ['^iTE[\s-]*Tech','^iTE[\s-]*Tech(nology)?','iTE Tech',''], @@ -14289,9 +14482,13 @@ sub set_disk_vendors { ['^Jingyi','^Jingyi','Jingyi',''], # NOTE: ITY2 120GB hard to find ['^JMicron','^JMicron(\s?Tech(nology)?)?','JMicron Tech',''], #JMicron H/W raid + ['^Joint','^Joint','Joint',''], ['^JSYERA','^JSYERA','Jsyera',''], ['^(Jual|RX7)','^Jual','Jual',''], ['^(J\.?ZAO|JZ)','^J\.?ZAO','J.ZAO',''], + ['^(KAPBOM|KA-)','KAPBOM','KAPBOM',''], + ['^(KaBuM!?|KBM)','KaBuM!?','KaBuM!',''], + ['(Kaizen|KZ\d\d)','Kaizen','Kaizen',''], ['^Kazuk','^Kazuk','Kazuk',''], ['(\bKDI\b|^OM3P)','\bKDI\b','KDI',''], ['^KEEPDATA','^KEEPDATA','KeepData',''], @@ -14303,19 +14500,21 @@ sub set_disk_vendors { ['^Kingchux[\s-]?ing','^Kingchux[\s-]?ing','Kingchuxing',''], ['^(KINGCOMP|KCSSD)','^KINGCOMP','KingComp',''], ['(KingDian|^NGF|S(280|400))','KingDian','KingDian',''], - ['^(Kingfast|TYFS)','^Kingfast','Kingfast',''], + ['^(Kingfast|TYFS|2710)','^Kingfast','Kingfast',''], ['^KingMAX','^KingMAX','KingMAX',''], ['^Kingrich','^Kingrich','Kingrich',''], ['^Kingsand','^Kingsand','Kingsand',''], ['KING\s?SHA\s?RE','KING\s?SHA\s?RE','KingShare',''], - ['^(KingSpec|ACSC|C3000|KS[DQ]|MSH|N[ET]-\d|NX-\d{2,4}|P3$|P4\b|PA[_-]?(18|25)|Q-180|SPK|T-(3260|64|128)|Z(\d\s|F\d))','^KingSpec','KingSpec',''], + ['^(KingSpec|ACSC|C3000|CHA|KS[DQ]|MSH|N[ET]-\d|NX-\d{2,4}|P3$|P4\b|PA[_-]?(18|25)|Q-180|SPK|T-(3260|64|128)|Z(\d\s|F\d))','^KingSpec','KingSpec',''], ['^KingSSD','^KingSSD','KingSSD',''], # kingwin docking, not actual drive ['^(EZD|EZ-Dock)','','Kingwin Docking Station',''], ['^Kingwin','^Kingwin','Kingwin',''], ['^KLLISRE','^KLLISRE','KLLISRE',''], - ['(KIOXIA|^K[BX]G\d)','KIOXIA','KIOXIA',''], # company name comes after product ID + # company name comes after product ID + ['(KIOXIA|\bCL\d-|^K[BX]G\d|SSSTC|Solid\s?State\s?Storage\s?Tech)','KIOXIA','KIOXIA',''], ['^(KLEVV|NEO\sN|CRAS)','^KLEVV','KLEVV',''], + ['^(KNUP|KP\b)','^KNUP','KNUP',''], ['^(Kodak|Memory\s?Saver)','^Kodak','Kodak',''], ['^(KOOTION)','^KOOTION','KOOTION',''], ['^(KUAIKAI|MSAM)','^KUAIKAI','KuaKai',''], @@ -14329,6 +14528,7 @@ sub set_disk_vendors { ['^Lapcare','^Lapcare','Lapcare',''], ['^(Lazos|L-?ISS)','^Lazos','Lazos',''], ['^LDLC','^LDLC','LDLC',''], + ['^(Leica|MSD\d\d)','^Leica','Leica',''], # LENSE30512GMSP34MEAT3TA / UMIS RPITJ256PED2MWX ['^(LEN|UMIS|Think)','^Lenovo','Lenovo',''], ['^RPFT','','Lenovo O.E.M.',''], @@ -14349,6 +14549,8 @@ sub set_disk_vendors { ['^(Mach\s*Xtreme|MXSSD|MXU|MX[\s-])','^Mach\s*Xtreme','Mach Xtreme',''], ['^(MacroVIP|MV(\d|GLD))','^MacroVIP','MacroVIP',''], # maybe MV alone ['^Mainic','^Mainic','Mainic',''], + ['^(Mancer|MCR)','^ Mancer[\s-]?Reaper','Mancer Reaper',''], + ['^MARKVISION','^MARKVISION','MarkVision',''], ['^(MARSHAL\b|MAL\d)','^MARSHAL','Marshal',''], ['^Maxell','^Maxell','Maxell',''], ['^Maximus','^Maximus','Maximus',''], @@ -14357,19 +14559,23 @@ sub set_disk_vendors { ['^Maxone','^Maxone','Maxone',''], ['^MARVELL','^MARVELL','Marvell',''], ['^Maxsun','^Maxsun','Maxsun',''], + ['^(McQuest)','^McQuest([\s-]?Digital)?','McQuest Digital',''], ['^MDT\b','^MDT','MDT (rebuilt WD/Seagate)',''], # mdt rebuilds wd/seagate hdd # MD1TBLSSHD, careful with this MD starter!! ['^MD[1-9]','^Max\s*Digital','MaxDigital',''], + ['^(Media[\s-]?Dice|MD[\s-])','^Media[\s-]?Dice','MediaDice',''], ['^Medion','^Medion','Medion',''], ['^(MEDIAMAX|WL\d{2})','^MEDIAMAX','MediaMax',''], ['^(Memorex|TravelDrive|TD\s?Classic)','^Memorex','Memorex',''], ['^Mengmi','^Mengmi','Mengmi',''], - ['^MicroFrom','^MicroFrom','MicroFrom',''], ['^MGTEC','^MGTEC','MGTEC',''], + ['^MicroFrom','^MicroFrom','MicroFrom',''], + ['^(MILLENNIUM[\s-]?TECHNOLOGY|MIL\d\d)','^MILLENNIUM[\s-]?TECHNOLOGY','Millenium Technology',''], # must come before micron ['^(Mtron|MSP)','^Mtron','Mtron',''], # note: C300/400 can be either micron or crucial, but C400 is M4 from crucial - ['(^(Micron|2200[SV]|MT|M5|(\d+|[CM]\d+)\sMTF)|00-MT)','^Micron','Micron',''],# C400-MTFDDAK128MAM + # micron can be in middle of model name + ['(\bMicron|^(2200[SV]|MT|M5|(\d+|[CM]\d+)\sMTF)|00-MT)','\bMicron','Micron',''],# C400-MTFDDAK128MAM ['^(Microsoft|S31)','^Microsoft','Microsoft',''], ['^MidasForce','^MidasForce','MidasForce',''], ['^Milan','^Milan','Milan',''], @@ -14396,7 +14602,7 @@ sub set_disk_vendors { ['^(Myson)','^Myson([\s-]?Century)?([\s-]?Inc\.?)?','Myson Century',''], ['^(Natusun|i-flashdisk)','^Natusun','Natusun',''], ['^(Neo\s*Forza|NFS\d)','^Neo\s*Forza','Neo Forza',''], - ['^(Netac|NS\d{3}|OnlyDisk|S535N)','^Netac','Netac',''], + ['^(Netac|NS\d{3}|OnlyDisk|S535N|SMTC)','^Netac','Netac',''], ['^Newsmy','^Newsmy','Newsmy',''], ['^NFHK','^NFHK','NFHK',''], # NGFF is a type, like msata, sata @@ -14407,6 +14613,7 @@ sub set_disk_vendors { ['^ODYS','^ODYS','ODYS',''], ['^Olympus','^Olympus','Olympus',''], ['^Orico','^Orico','Orico',''], + ['(Origin|Inception|^TLC\d)','^Origin','Origin',''], ['^Ortial','^Ortial','Ortial',''], ['^OSC','^OSC\b','OSC',''], ['^(Ovation)','^Ovation','Ovation',''], @@ -14416,8 +14623,9 @@ sub set_disk_vendors { ['^(Parker|TP00)','^Parker','Parker',''], ['^(Pasoul|OASD)','^Pasoul','Pasoul',''], ['^(Patriot|PS[8F]|P2\d{2}|PBT|VPN|Viper|Burst|Blast|Blaze|Pyro|Ignite)','^Patriot([-\s]?Memory)?','Patriot',''],#Viper M.2 VPN100 - ['^PERC\b','','Dell PowerEdge RAID Card',''], # ssd - ['(PHISON[\s-]?|ESR\d|PSE)','PHISON[\s-]?','Phison',''],# E12-256G-PHISON-SSD-B3-BB1 + ['^PERC\b','','Dell PowerEdge RAID Card',''], # ssd + ['(\bPhilips)','\bPhilips','Philips',''], + ['(PHISON[\s-]?|ESR\d|PS[5E]|311CD|\bSSG\d\d)','PHISON[\s-]?','Phison',''],# E12-256G-PHISON-SSD-B3-BB1 ['^(Pichau[\s-]?Gaming|PG\d{2})','^Pichau[\s-]?Gaming','Pichau Gaming',''], ['^Pioneer','Pioneer','Pioneer',''], ['^Platinet','Platinet','Platinet',''], @@ -14430,7 +14638,9 @@ sub set_disk_vendors { # PS3109S9 is the result of an error condition with ssd controller: Phison PS3109 ['^PUSKILL','^PUSKILL','Puskill',''], ['QEMU','^\d*QEMU( QEMU)?','QEMU',''], # 0QUEMU QEMU HARDDISK + ['^QNIX','^QNIX','QNIX',''], ['(^Quantum|Fireball)','^Quantum','Quantum',''], + ['(^Quanxing)','^Quanxing','Quanxing',''], ['(^QOOTEC|QMT)','^QOOTEC','QOOTEC',''], ['^(QUMO|Q\dDT)','^QUMO','Qumo',''], ['^QOPP','^QOPP','Qopp',''], @@ -14442,6 +14652,7 @@ sub set_disk_vendors { ['^(Ramsta|R[1-9])','^Ramsta','Ramsta',''], ['^RCESSD','^RCESSD','RCESSD',''], ['^(Realtek|RTL)','^Realtek','Realtek',''], + ['^(Redragon|\bHaste)','^Redragon','Redragon',''], ['^(Reletech)','^Reletech','Reletech',''], # id: P400 but that's too short ['^RENICE','^RENICE','Renice',''], ['^RevuAhn','^RevuAhn','RevuAhn',''], @@ -14451,6 +14662,7 @@ sub set_disk_vendors { #RTDMA008RAV2BWL comes with lenovo but don't know brand ['^Runcore','^Runcore','Runcore',''], ['^Rundisk','^Rundisk','RunDisk',''], + ['^(RUNENG)','^RUNENG','RUNENG',''], ['^RZX','^RZX\b','RZX',''], ['^(S3Plus|S3\s?SSD)','^S3Plus','S3Plus',''], ['^(Sabrent|Rocket)','^Sabrent','Sabrent',''], @@ -14463,6 +14675,8 @@ sub set_disk_vendors { # SATAFIRM is an ssd failure message ['^SCUDA','^SCUDA','SCUDA',''], ['^(Sea\s?Tech|Transformer)','^Sea\s?Tech','Sea Tech',''], + ['^(SEIWHALE)','^SEIWHALE','SEIWHALE',''], + ['^(SIEMENS)','^SIEMENS','Siemens',''], ['^SigmaTel','^SigmaTel','SigmaTel',''], # DIAMOND_040_GB ['^(SILICON\s?MOTION|SM\d|090c)','^(SILICON\s?MOTION|090c)','Silicon Motion',''], @@ -14483,6 +14697,7 @@ sub set_disk_vendors { ['^Solidata','^Solidata','Solidata',''], ['^(SOLIDIGM|SSDPFK)','^SOLIDIGM\b','solidgm',''], ['^(Sony|IM9|Microvalut|S[FR]-)','^Sony','Sony',''], + # Note: SSC can be prefix for several companies ['^SSK\b','^SSK','SSK',''], ['^(SSSTC|CL1-)','^SSSTC','SSSTC',''], ['^(SST|SG[AN])','^SST\b','SST',''], @@ -14491,6 +14706,7 @@ sub set_disk_vendors { ['\dSUN\d','^SUN(\sMicrosystems)?','Sun Microsystems',''], ['^Sundisk','^Sundisk','Sundisk',''], ['^SUNEAST','^SUNEAST','SunEast',''], + ['^Suntrsi','^Suntrsi','Suntrsi',''], ['^SuperMicro','^SuperMicro','SuperMicro',''], ['^Supersonic','^Supersonic','Supersonic',''], ['^SuperSSpeed','^SuperSSpeed','SuperSSpeed',''], @@ -14506,7 +14722,7 @@ sub set_disk_vendors { ['^TANDBERG','^TANDBERG','Tanberg',''], ['^(TC[\s-]*SUNBOW|X3\s\d+[GT])','^TC[\s-]*SUNBOW','TCSunBow',''], ['^(TDK|TF[1-9]\d|LoR)','^TDK','TDK',''], - ['^TEAC','^TEAC','TEAC',''], + ['(^TEAC|\bUF00)','^TEAC','TEAC',''], ['^(TEAM|T[\s-]?Create|CX[12]\b|L\d\s?Lite|T\d{3,}[A-Z]|TM\d|(Dark\s?)?L3\b|T[\s-]?Force)','^TEAM(\s*Group)?','TeamGroup',''], ['^(Teclast|CoolFlash)','^Teclast','Teclast',''], ['^(tecmiyo)','^tecmiyo','TECMIYO',''], @@ -14537,6 +14753,7 @@ sub set_disk_vendors { ['^USBTech','^USBTech','USBTech',''], ['^(UNIC2)','^UNIC2','UNIC2',''], ['^(UG|Unigen)','^Unigen','Unigen',''], + ['^UnionSine','UnionSine','UnionSine',''], ['^(UNIREX)','^UNIREX','UNIREX',''], ['^(UNITEK)','^UNITEK','UNITEK',''], ['^(USBest|UT16)','^USBest','USBest',''], @@ -14545,6 +14762,7 @@ sub set_disk_vendors { ['^(Value\s?Tech|VTP\d)','^Value\s?Tech','ValueTech',''], ['^VBOX','','VirtualBox',''], ['^(Veno|Scorp)','^Veno','Veno',''], + ['^(VenomRX|VRX)','^VenomRX','VenomRX',''], ['^(Verbatim|STORE\s?\'?N\'?\s?(FLIP|GO)|Vi[1-9]|OTG\s?Tiny)','^Verbatim','Verbatim',''], ['^V-?GEN','^V-?GEN','V-Gen',''], ['^VICK','VICK','VICK',''], @@ -14559,10 +14777,12 @@ sub set_disk_vendors { ['^Walram','^Walram','WALRAM',''], ['^Walton','^Walton','Walton',''], ['^(Wearable|Air-?Stash)','^Wearable','Wearable',''], + ['\b(WiebeTech|eRazer)','WiebeTech','WiebeTech',''], ['^Wellcomm','^Wellcomm','Wellcomm',''], + ['^(WHALEKOM|WK)','^WHALEKOM','Whalekom',''], ['^(wicgtyp|[MN][V]?900)','^wicgtyp','wicgtyp',''], ['^Wilk','^Wilk','Wilk',''], - ['^(WinMemory|SWG\d)','^WinMemory','WinMemory',''], + ['^(WinMemory|SW[GR]\d)','^WinMemory','WinMemory',''], ['^(Winton|WT\d{2})','^Winton','Winton',''], ['^(WISE)','^WISE','WISE',''], ['^WPC','^WPC','WPC',''], # WPC-240GB @@ -14578,6 +14798,7 @@ sub set_disk_vendors { ['^XUNZHE','^XUNZHE','XUNZHE',''], ['^(Yangtze|ZhiTai|PC00[5-9]|SC00[1-9])','^Yangtze(\s*Memory)?','Yangtze Memory',''], ['^(Yeyian|valk)','^Yeyian','Yeyian',''], + ['^(YHJC|YHS)','^YHJC','YHJC',''], ['^(YingChu|YGC)','^YingChu','YingChu',''], ['^YongzhenWeiye','^YongzhenWeiye','YongzhenWeiye',''], ['^(YUCUN|R880)','^YUCUN','YUCUN',''], @@ -14593,6 +14814,7 @@ sub set_disk_vendors { ['^(Zotac|ZTSSD)','^Zotac','Zotac',''], ['^ZOZT','^ZOZT','ZOZT',''], ['^ZSPEED','^ZSPEED','ZSpeed',''], + ['^Zsuit','^Zsuit','Zsuit',''], ['^ZTC','^ZTC','ZTC',''], ['^ZTE','^ZTE','ZTE',''], ['^(ZY|ZhanYao)','^ZhanYao([\s-]?data)','ZhanYao',''], @@ -14844,7 +15066,7 @@ sub drive_speed { } } -## GraphicItem +## GraphicItem ## { package GraphicItem; my ($b_primary,$b_wayland_data,%graphics,%mesa_drivers, @@ -14915,7 +15137,7 @@ sub device_output { $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){ - $device = main::filter_pci_long($device); + main::filter_pci_long(\$device); } push(@$rows, { main::key($num++,1,1,'Device') => $device, @@ -18068,7 +18290,7 @@ sub set_intel_data { }, {'arch' => 'Gen-4', 'ids' => '2982|2983|2992|2993|29a2|29a3|29b2|29b3|29c2|29c3|29d2|29d3|2a02|' . - '2a03|2a12|2a13', + '2a03|2a12|2a13|2a42|2e02|2e12|2e22|2e32|2e42|2e92|a001|a011', 'code' => '', 'process' => 'Intel 65n', 'years' => '2006-07', @@ -18162,17 +18384,18 @@ sub set_intel_data { 'process' => 'Intel 10nm', 'years' => '2019-21', }, - {'arch' => 'Gen-12.1', - 'ids' => '4905|4907|4908|4909|4c8a|4c8b|4c90|4c9a|9a40|9a49|9a59|9a60|9a68|' . - '9a70|9a78|9ac0|9ac9|9ad9|9af8', + {'arch' => 'Gen-12.1', + 'ids' => '4626|4628|462a|4636|4638|463a|4680|4682|4688|468a|468b|4690|4692|' . + '4693|46a1|46a2|46a3|46b2|46b3|46c2|46c3|46d0|46d1|46d2|4905|4907|4908|4909|' . + '4c8a|4c8b|4c90|4c9a|9a40|9a49|9a59|9a60|9a68|9a70|9a78|9ac0|9ac9|9ad9|9af8|' . + 'a719|a720|a721|a780|a781|a782|a783|a788|a789|a78a|a78b|a7a8|a7a9', 'code' => '', 'process' => 'Intel 10nm', 'years' => '2020-21', }, {'arch' => 'Gen-12.2', - 'ids' => '4626|4628|462a|4636|4638|463a|4680|4682|4688|468a|468b|4690|4692|' . - '4693|46a0|46a1|46a2|46a3|46a6|46a8|46aa|46b0|46b1|46b2|46b3|46b6|46b8|46ba|' . - '46c0|46c1|46c2|46c3|46d0|46d1|46d2|46d3|46d4', + 'ids' => '4626|46a0|46a1|46a6|46a8|46aa|46b0|46b1|46b6|46b8|46ba|46c0|46c1|' . + '46d3|46d4', 'code' => '', 'process' => 'Intel 10nm', 'years' => '2021-22+', @@ -18205,9 +18428,15 @@ sub set_intel_data { 'years' => '2023+', }, {'arch' => 'Gen-14', + 'ids' => 'e202|e20b|e20c|e20d|e212', + 'code' => '', + 'process' => 'TSMC n4 (4nm)', + 'years' => '2024+', + }, + {'arch' => 'Gen-14', 'ids' => '6420|64a0|64b0', 'code' => '', - 'process' => 'TSMC 3nm', + 'process' => 'TSMC n3 (3nm)', 'years' => '2024+', }, {'arch' => 'Gen-15', @@ -18402,8 +18631,8 @@ sub set_nv_data { 'years' => '2010-2016', }, ## Legacy 470.xx - {'arch' => 'Fermi 2', - 'ids' => '0fec|1281|1289|128b|1295|1298', + {'arch' => 'Fermi-2', + 'ids' => '0fec|1281|1289|128b|1295', 'code' => 'GF119/GK208', 'kernel' => '', 'legacy' => 1, @@ -18416,7 +18645,7 @@ sub set_nv_data { }, # GT 720M and 805A/810A are the same cpu id. # years: 2012-2018 Kepler 2013-2015 Kepler 2.0 - {'arch' => 'Kepler', + {'arch' => 'Kepler-2', 'ids' => '0fc6|0fc8|0fc9|0fcd|0fce|0fd1|0fd2|0fd3|0fd4|0fd5|0fd8|0fd9|0fdf|' . '0fe0|0fe1|0fe2|0fe3|0fe4|0fe9|0fea|0fed|0fee|0ff6|0ff8|0ff9|0ffa|0ffb|0ffc|' . '0ffd|0ffe|0fff|1001|1004|1005|1007|1008|100a|100c|1021|1022|1023|1024|1026|' . @@ -18424,7 +18653,7 @@ sub set_nv_data { '118e|118f|1193|1194|1195|1198|1199|119a|119d|119e|119f|11a0|11a1|11a2|11a3|' . '11a7|11b4|11b6|11b7|11b8|11ba|11bc|11bd|11be|11c0|11c2|11c3|11c4|11c5|11c6|' . '11c8|11cb|11e0|11e1|11e2|11e3|11fa|11fc|1280|1282|1284|1286|1287|1288|1290|' . - '1291|1292|1293|1295|1296|1299|129a|12b9|12ba', + '1291|1292|1293|1295|1296|1298|1299|129a|12b9|12ba', 'code' => 'GKxxx', 'kernel' => '', 'legacy' => 1, @@ -18448,7 +18677,7 @@ sub set_nv_data { 'legacy' => 0, 'process' => 'TSMC 28nm', 'release' => '', - 'series' => '545.xx+', + 'series' => '550.xx+', 'status' => main::message('nv-current-eol',$date,'2026-12-xx'), 'xorg' => '', 'years' => '2014-2019', @@ -18465,7 +18694,7 @@ sub set_nv_data { 'legacy' => 0, 'process' => 'TSMC 16nm', 'release' => '', - 'series' => '545.xx+', + 'series' => '550.xx+', 'status' => main::message('nv-current-eol',$date,'2026-12-xx'), 'xorg' => '', 'years' => '2016-2021', @@ -18477,7 +18706,7 @@ sub set_nv_data { 'legacy' => 0, 'process' => 'TSMC 12nm', 'release' => '', - 'series' => '545.xx+', + 'series' => '550.xx+', 'status' => main::message('nv-current-eol',$date,'2026-12-xx'), 'xorg' => '', 'years' => '2017-2020', @@ -18507,7 +18736,7 @@ sub set_nv_data { '24b1|24b6|24b7|24b8|24b9|24ba|24bb|24c7|24c9|24dc|24dd|24e0|24fa|2503|2504|' . '2507|2508|2520|2521|2523|2531|2544|2560|2563|2571|2582|2584|25a0|25a2|25a5|' . '25ab|25ac|25b0|25b2|25b6|25b8|25b9|25ba|25bb|25bc|25bd|25e0|25e2|25e5|25ec|' . - '25f9|25fa|25fb|2838', + '25f9|25fa|25fb|2822|2838', 'code' => 'GAxxx', 'kernel' => '', 'legacy' => 0, @@ -18519,13 +18748,13 @@ sub set_nv_data { 'years' => '2020-2023', }, {'arch' => 'Hopper', - 'ids' => '2321|2322|2324|2329|2330|2331|2339|233a|2342', + 'ids' => '2321|2322|2324|2329|2330|2331|2335|2339|233a|2342', 'code' => 'GH1xx', 'kernel' => '', 'legacy' => 0, 'process' => 'TSMC n4 (5nm)', 'release' => '', - 'series' => '545.xx+', + 'series' => '550.xx+', 'status' => $status_current, 'xorg' => '', 'years' => '2022+', @@ -19095,7 +19324,7 @@ sub tty_data { } } -## LogicalItem +## LogicalItem ## { package LogicalItem; @@ -19460,7 +19689,7 @@ sub component_recursive_data { } } -## MachineItem +## MachineItem ## # public methods: get(), is_vm() { my $b_vm; @@ -20377,7 +20606,7 @@ sub check_vm { } } -## NetworkItem +## NetworkItem ## { package NetworkItem; my ($b_ip_run,@ifs_found); @@ -20925,6 +21154,7 @@ sub wan_ip { my @urls = (!$wan_url) ? qw(http://whatismyip.akamai.com/ http://icanhazip.com/ https://smxi.org/opt/ip.php) : ($wan_url); foreach (@urls){ + last if !$dl{'dl'}; $ua = 'ip' if $_ =~ /smxi/; $ip = main::download_file('stdout',$_,'',$ua); if ($ip){ @@ -20981,7 +21211,7 @@ sub check_wifi { } } -## OpticalItem +## OpticalItem ## { package OpticalItem; @@ -21305,7 +21535,7 @@ sub drive_data_linux { } } -## PartitionItem +## PartitionItem ## { # these will be globally accessible via PartitionItem::filters() my ($fs_exclude,$fs_skip,$part_filter); @@ -21406,14 +21636,14 @@ sub create_output { $fs !~ /^$fs_skip$/){ if ($show{'label'}){ if ($use{'filter-label'}){ - $row->{'label'} = main::filter_partition('part', $row->{'label'}, ''); + main::filter_partition('part', \$row->{'label'}, ''); } $row->{'label'} ||= 'N/A'; $rows->[$j]{main::key($num++,0,2,'label')} = $row->{'label'}; } if ($show{'uuid'}){ if ($use{'filter-uuid'}){ - $row->{'uuid'} = main::filter_partition('part', $row->{'uuid'}, ''); + main::filter_partition('part', \$row->{'uuid'}, ''); } $row->{'uuid'} ||= 'N/A'; $rows->[$j]{main::key($num++,0,2,'uuid')} = $row->{'uuid'}; @@ -22221,7 +22451,7 @@ sub get_uuid { } } -## ProcessItem +## ProcessItem ## { package ProcessItem; # header: @@ -22398,7 +22628,7 @@ sub throttled { } } -## RaidItem +## RaidItem ## { package RaidItem; @@ -23663,7 +23893,7 @@ sub check_zfs_status { } } -## RamItem +## RamItem ## { package RamItem; my ($speed_maps,$vendors,$vendor_ids); @@ -25209,7 +25439,7 @@ sub ram_vendor { } } -## RepoItem +## RepoItem ## { package RepoItem; # easier to keep these package global, but undef after done @@ -26294,7 +26524,7 @@ sub file_path { } } -## SensorItem +## SensorItem ## { package SensorItem; my $gpu_data = []; @@ -27702,7 +27932,7 @@ sub gpu_sensor_data { } } -## SlotItem +## SlotItem ## { package SlotItem; my ($sys_slots); @@ -28012,7 +28242,7 @@ sub slot_children_recursive { } } -## SwapItem +## SwapItem ## { package SwapItem; @@ -28119,14 +28349,14 @@ sub create_output { } if ($show{'label'} && ($row->{'label'} || $row->{'swap-type'} eq 'partition')){ if ($use{'filter-label'}){ - $row->{'label'} = main::filter_partition('part', $row->{'label'}, ''); + main::filter_partition('part', \$row->{'label'}, ''); } $row->{'label'} ||= 'N/A'; $rows->[$j]{main::key($num++,0,2,'label')} = $row->{'label'}; } if ($show{'uuid'} && ($row->{'uuid'} || $row->{'swap-type'} eq 'partition')){ if ($use{'filter-uuid'}){ - $row->{'uuid'} = main::filter_partition('part', $row->{'uuid'}, ''); + main::filter_partition('part', \$row->{'uuid'}, ''); } $row->{'uuid'} ||= 'N/A'; $rows->[$j]{main::key($num++,0,2,'uuid')} = $row->{'uuid'}; @@ -28136,7 +28366,7 @@ sub create_output { } } -## UnmountedItem +## UnmountedItem ## { package UnmountedItem; @@ -28234,14 +28464,14 @@ sub create_output { if (($show{'label'} || $show{'uuid'}) && $fs !~ /^$fs_skip$/){ if ($show{'label'}){ if ($use{'filter-label'}){ - $row->{'label'} = main::filter_partition('part', $row->{'label'}, ''); + main::filter_partition('part', \$row->{'label'}, ''); } $row->{'label'} ||= 'N/A'; $rows->[$j]{main::key($num++,0,2,'label')} = $row->{'label'}; } if ($show{'uuid'}){ if ($use{'filter-uuid'}){ - $row->{'uuid'} = main::filter_partition('part', $row->{'uuid'}, ''); + main::filter_partition('part', \$row->{'uuid'}, ''); } $row->{'uuid'} ||= 'N/A'; $rows->[$j]{main::key($num++,0,2,'uuid')} = $row->{'uuid'}; @@ -28442,7 +28672,7 @@ sub unmounted_filesystem { } } -## UsbItem +## UsbItem ## { package UsbItem; @@ -28588,7 +28818,7 @@ sub usb_output { } } -## WeatherItem +## WeatherItem ## # add metric / imperial (us) switch { package WeatherItem; @@ -29278,6 +29508,7 @@ sub get_location { $loc_arg = $loc{'zip'}; } $country = ($loc{'country3'}) ? $loc{'country3'} : $loc{'country'}; + $country ||= 'Country N/A'; $city = ($loc{'city'}) ? $loc{'city'} : 'City N/A'; $state = ($loc{'region-id'}) ? $loc{'region-id'} : 'Region N/A'; $loc_string = main::filter("$city, $state, $country"); @@ -29566,7 +29797,7 @@ sub set_dboot_data { eval $end if $b_log; } -## DesktopData +## DesktopData ## # returns array: # 0: desktop name # 1: version @@ -29958,6 +30189,7 @@ sub de_env_data { my @desktops =( [1,'unity','unity','',''], [0,'budgie','budgie-desktop','','gtk'], + [1,'cosmic','cosmic-session','','iced'], # debian package: lxde-core. # NOTE: some distros fail to set XDG data for root, ps may get it [1,'lxde','lxpanel','','gtk-na',',^lxsession$'], # no gtk v data, not same as system @@ -30096,7 +30328,7 @@ sub tk_gtk_data { eval $end if $b_log; } -# This handles stray tooltips that won't get versions, yet anyway. +# This handles stray toolkits that won't get versions, yet anyway. sub tk_misc_data { eval $start if $b_log; if ($tk_test eq 'gtk-na'){ @@ -30426,7 +30658,7 @@ sub set_xprop { } } -## DeviceData +## DeviceData ## # creates arrays: $devices{'audio'}; $devices{'graphics'}; $devices{'hwraid'}; # $devices{'network'}; $devices{'timer'} and local @devices for logging/debugging # 0: type @@ -31218,7 +31450,7 @@ sub get_device_temp { return $temp; } -## DiskDataBSD +## DiskDataBSD ## # handles disks and partition extra data for disks bsd, raid-zfs, # partitions, swap, unmounted # glabel: partID, logical/physical-block-size, uuid, label, size @@ -31533,7 +31765,7 @@ sub set_gpart_data { } } -## DmData +## DmData ## # Public method: get() # returns hash ref of array of arrays for dm/lm # hash: dm, lm @@ -31598,7 +31830,8 @@ sub get_dm_lm { lightdm loginx lxdm ly mdm mlogind nodm pcdm qingy sddm slim slimski tdm udm wdm x3dm xdm xdmctl xenodm); } - # greetd frontends: agreety dlm gtkgreet qtgreet tuigreet wlgreet + # greetd frontends: agreety cosmic-greeter dlm gtkgreet qtgreet tuigreet + # wlgreet # slick, elephant greeters for lightdm so aren't really lm else { @dms = qw(elogind greetd qtgreet seatd tbsm); @@ -31655,7 +31888,7 @@ sub test_ps_dm { } } -## DistroData +## DistroData ## { package DistroData; my ($id_src,@osr,@working); @@ -32640,7 +32873,7 @@ sub dbg_distro_files { } } -## DmidecodeData +## DmidecodeData ## { package DmidecodeData; @@ -32749,7 +32982,8 @@ sub get_driver_modules { return $modules; } -## GlabelData: public methods: get() +## GlabelData ## +# public methods: get() # Used to partitions, swap, RAID ZFS gptid path standard name, like ada0p1 { package GlabelData; @@ -32813,7 +33047,7 @@ sub get_hostname { return $hostname; } -## InitData +## InitData ## { package InitData; my ($init,$init_version,$program) = ('','',''); @@ -33024,7 +33258,7 @@ sub get_runlevel_default { } } -## IpData +## IpData ## { package IpData; @@ -33042,7 +33276,8 @@ sub set { sub set_ip_addr { eval $start if $b_log; - my @data = main::grabber($alerts{'ip'}->{'path'} . " addr 2>/dev/null",'\n','strip'); + my ($b_skip,$broadcast,$if,$if_id,$ip,$scope,$type); + my (@data,@ips,@temp); if ($fake{'ip-if'}){ # my $file = "$fake_data_dir/if/scope-ipaddr-1.txt"; # my $file = "$fake_data_dir/network/ip-addr-blue-advance.txt"; @@ -33051,7 +33286,9 @@ sub set_ip_addr { # my $file = "$fake_data_dir/network/ppoe/ppoe-ip-addr-3.txt"; # @data = main::reader($file,'strip') or die $!; } - my ($b_skip,$broadcast,$if,$if_id,$ip,@ips,$scope,$type,@temp,@temp2); + else { + @data = main::grabber($alerts{'ip'}->{'path'} . " addr 2>/dev/null",'\n','strip'); + } foreach (@data){ if (/^[0-9]/){ # print "$_\n"; @@ -33096,15 +33333,17 @@ sub set_ip_addr { sub set_ifconfig { eval $start if $b_log; + my ($b_skip,$broadcast,$duplex,$if,$if_id,$ip,$mac,$scope,$speed,$state,$type); + my (@data,@ips,@ips_bsd,@temp); # whitespace matters!! Don't use strip - my @data = main::grabber($alerts{'ifconfig'}->{'path'} . " 2>/dev/null",'\n',''); if ($fake{'ip-if'}){ # my $file = "$fake_data_dir/network/ppoe/ppoe-ifconfig-all-1.txt"; # my $file = "$fake_data_dir/network/vps-ifconfig-1.txt"; # @data = main::reader($file) or die $!; } - my ($b_skip,$broadcast,$if,@ips_bsd,$ip,@ips,$scope,$if_id,$type,@temp,@temp2); - my ($state,$speed,$duplex,$mac); + else { + @data = main::grabber($alerts{'ifconfig'}->{'path'} . " 2>/dev/null",'\n',''); + } foreach (@data){ if (/^[\S]/i){ # print "$_\n"; @@ -33239,7 +33478,7 @@ sub get_kernel_clocksource { eval $end if $b_log; } -## KernelCompiler +## KernelCompiler ## { package KernelCompiler; @@ -33352,7 +33591,7 @@ sub get_kernel_data { return $kernel; } -## KernelParameters +## KernelParameters ## { package KernelParameters; @@ -33387,7 +33626,8 @@ sub parameters_bsd { } } -## LsblkData: public methods: set(), get() +## LsblkData ## +# public methods: set(), get() { package LsblkData; @@ -33479,7 +33719,7 @@ sub set_mapper { eval $end if $b_log; } -## MemoryData +## MemoryData ## { package MemoryData; @@ -34127,7 +34367,7 @@ sub get_module_version { return $version; } -## PackageData +## PackageData ## # Note: this outputs the key/value pairs ready to go and is # called from either -r or -Ix, -r precedes. { @@ -34421,7 +34661,7 @@ sub count_libs { } } -## ParseEDID +## ParseEDID ## { package ParseEDID; # CVT_ratios: @@ -35129,7 +35369,8 @@ sub _round { } } -## PartitionData: public methods: set(), get() +## PartitionData ## +# public methods: set(), get() # for /proc/partitions only, see DiskDataBSD for BSD partition data. { package PartitionData; @@ -35276,7 +35517,8 @@ sub get_pcie_data { eval $end if $b_log; } -## PowerData: public method: get() +## PowerData ## +# public method: get() # No BSD support currently. Test by !$bsd_type. Should any BSD data source # appear, make bsd_data() and add $bsd_type switch here, remove from caller. { @@ -35341,7 +35583,7 @@ sub sys_data { } } -# ProgramData +# ProgramData ## # public methods: # full(): returns (print name, version nu, [full version data output]). # values(): returns program values array @@ -35442,7 +35684,8 @@ sub set_values { 'comfc' => ['^comfc',0,'0','comfc',0,1,0,'',''], # unverified 'compiz' => ['^compiz',2,'--version','Compiz',0,1,0,'',''], 'compton' => ['^\d',1,'--version','Compton',0,1,0,'',''], - 'cosmic-comp' => ['^cosmic-comp',0,'0','cosmic-comp',0,1,0,'',''], # unverified + 'cosmic-comp' => ['^cosmic-comp',0,'0','cosmic-comp',0,1,0,'',''], # cosmic alpha, no versions + 'cosmic-session' => ['^cosmic-session',0,'0','Cosmic',0,1,0,'',''], # cosmic alpha, no versions 'ctwm' => ['^\S',1,'-version','ctwm',0,1,0,'',''], 'cwm' => ['^cwm',0,'0','CWM',0,1,0,'',''], # no version 'dawn' => ['^dawn',1,'-v','dawn',0,1,1,'^dawn-',''], # to stderr, not verified @@ -35680,6 +35923,7 @@ sub set_values { 'cdm' => ['^cdm',0,'0','CDM',0,1,0,'',''], # might be xlogin, unknown output for -V 'clogin' => ['^clogin',0,'-V','clogin',0,1,0,'',''], # unverified, cysco router + 'cosmic-greeter' => ['^cosmic-greeter',0,'0','cosmic-greeter',0,1,0,'',''], # no version, uses greetd 'elephant-greeter' => ['^elephant',0,'0','elephant-greeter',0,1,0,'',''], # unverified, lightdm greeter 'elogind' => ['^elogind',0,'0','elogind',0,1,0,'',''], # no version 'emptty' => ['^emptty',0,'0','EMPTTY',0,1,0,'',''], # unverified @@ -35938,7 +36182,7 @@ sub version_pkg { } } -## PsData +## PsData ## # public methods: # set(): sets @ps_aux, @ps_cmd # set_dm(): sets $ps_data{'dm-active'} @@ -35950,14 +36194,21 @@ package PsData; sub set { eval $start if $b_log; - my ($b_busybox,$header,$ps,@temp); + my ($b_busybox,$header,$link,$path,$ps,@temp); $loaded{'ps-data'} = 1; my $args = 'wwaux'; - my $path = main::check_program('ps'); - my $link = readlink($path); - if ($link && $link =~ /busybox/i){ - $b_busybox = 1; - $args = ''; + # it's possible ps isn't even installed + if ($path = main::check_program('ps')){ + $link = readlink($path); + if ($link && $link =~ /busybox/i){ + $b_busybox = 1; + $args = ''; + } + } + else { + main::log_data('data','No ps installed.') if $b_log; + eval $end if $b_log; + return; } # note: some ps cut output based on terminal width, ww sets width unlimited # old busybox returns error with args, new busybox ignores auxww @@ -35969,6 +36220,8 @@ sub set { @temp = split(/\s+/, $header); } else { + main::log_data('data','@$ps is empty.') if $b_log; + eval $end if $b_log; return; } $ps_data{'header'}->[0] = $#temp; # the indexes, not the scalar count @@ -36033,7 +36286,7 @@ sub set_de_wm { if ($show{'system'}){ # some desktops detect via ps as fallback process_items(\@{$ps_data{'de-ps-detect'}},join('|', qw( - razor-desktop razor-session lxsession lxqt-session nscde + cosmic-session razor-desktop razor-session lxsession lxqt-session nscde tdelauncher tdeinit_phase1))); # order matters! process_items(\@{$ps_data{'wm-parent'}},join('|', qw(xfdesktop icewm fluxbox @@ -36061,14 +36314,16 @@ sub set_de_wm { if ($show{'graphic'}){ $b_de_wm_comp = 1; $b_wm_comp = 1; - process_items(\@{$ps_data{'compositors-pure'}},join('|',qw(cairo compton dcompmgr - mcompositor picom steamcompmgr surfaceflinger xcompmgr unagi))); + process_items(\@{$ps_data{'compositors-pure'}},join('|',qw(cairo compton + cosmic-comp dcompmgr mcompositor picom steamcompmgr surfaceflinger + xcompmgr unagi))); } if ($b_de_wm_comp){ process_items(\@{$ps_data{'de-wm-compositors'}},join('|',qw(budgie-wm compiz - deepin-kwin_wayland deepin-kwin_x11 deepin-wm enlightenment gala gnome-shell - twin kwin_wayland kwin_x11 kwinft kwin marco deepin-metacity metacity - metisse mir moksha muffin deepin-mutter mutter ukwm xfwm[345]?))); + deepin-kwin_wayland deepin-kwin_x11 deepin-wm enlightenment + gala gnome-shell twin kwin_wayland kwin_x11 kwinft kwin marco + deepin-metacity metacity metisse mir moksha muffin deepin-mutter mutter + ukwm xfwm[345]?))); } if ($b_wm_comp){ # x11: 3dwm, qtile [originally], rest wayland @@ -36145,7 +36400,8 @@ sub set_power { process_items(\@{$ps_data{'power-services'}},join('|', qw(apmd csd-power gnome-power-manager gsd-power kpowersave org\.dracolinux\.power org_kde_powerdevil mate-power-manager power-profiles-daemon powersaved - tdepowersave thermald tlp upowerd ukui-power-manager xfce4-power-manager))); + system76-power tdepowersave thermald tlp upowerd ukui-power-manager + xfce4-power-manager))); print '$ps_data{power-daemons}: ', Data::Dumper::Dumper $ps_data{'power-services'} if $dbg[5]; main::log_data('dump','$ps_data{power-daemons}',$ps_data{'power-services'}) if $b_log; eval $end if $b_log; @@ -36175,7 +36431,7 @@ sub get_self_version { return $self_version . $patch; } -## ServiceData +## ServiceData ## { package ServiceData; my ($key,$service,$type); @@ -36381,7 +36637,7 @@ sub set { } # $dbg[29] = 1; set_path(); print ServiceData::get('status','bluetooth'),"\n"; -## ShellData +## ShellData ## { package ShellData; my $b_debug = 0; # disable all debugger output in case forget to comment out! @@ -36859,7 +37115,7 @@ sub get_uptime { return $uptime; } -## UsbData +## UsbData ## # %usb array indexes # 0: bus id / sort id # 1: device id @@ -38009,7 +38265,7 @@ sub process_power { #### GENERATE OUTPUT ######################################################################## -## OutputGenerator +## OutputGenerator ## # Also creates Short, Info, and System items { package OutputGenerator; @@ -38460,10 +38716,12 @@ sub system_item { if ($b_admin && (my $params = KernelParameters::get())){ # print "$params\n"; if ($use{'filter-label'}){ - $params = main::filter_partition('system', $params, 'label'); + main::filter_partition('system', \$params, '=LABEL='); } if ($use{'filter-uuid'}){ - $params = main::filter_partition('system', $params, 'uuid'); + main::filter_partition('system', \$params, '=UUID='); + main::filter_partition('system', \$params, 'systemd.machine_id='); + } $data->{$data_name}[$index]{main::key($num++,0,2,'parameters')} = $params; -- cgit v1.2.3