From daaaec3869dd76122eb2ee2ca5ae19ab54a26336 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+kernattila@users.noreply.github.com> Date: Thu, 1 Jun 2023 17:05:16 +0200 Subject: [PATCH 01/78] fix: rssupdate error, need strings --- rqd/rqd/rqmachine.py | 1 + 1 file changed, 1 insertion(+) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 2fc5a32ce..4c0a4fdb6 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -274,6 +274,7 @@ def rssUpdate(self, frames): # - rss: inaccurate, similar to VmRss in /proc/[pid]/status child_statm_fields = self._getStatFields( rqd.rqconstants.PATH_PROC_PID_STATM.format(pid)) + child_statm_fields = map(child_statm_fields, str) pids[pid]['statm_size'] = \ int(re.search(r"\d+", child_statm_fields[0]).group()) \ if re.search(r"\d+", child_statm_fields[0]) else -1 From 4f0876f194c2d520f910a37483418422a4eec23a Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+kernattila@users.noreply.github.com> Date: Thu, 1 Jun 2023 17:10:04 +0200 Subject: [PATCH 02/78] fix: count procs per core, sort cores in order (not random anymore), reserve precisely according to request (P-cores first, E-cores last) --- rqd/rqd/rqmachine.py | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 4c0a4fdb6..35f10666f 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -825,7 +825,7 @@ def reserveHT(self, frameCores): # Prefer to assign cores from the same physical cpu. # Spread different frames around on different physical cpus. avail_cores = {} - avail_cores_count = 0 + avail_procs_count = 0 reserved_cores = self.__coreInfo.reserved_cores for physid, cores in self.__procs_by_physid_and_coreid.items(): @@ -834,14 +834,14 @@ def reserveHT(self, frameCores): int(coreid) in reserved_cores[int(physid)].coreid: continue avail_cores.setdefault(physid, set()).add(coreid) - avail_cores_count += 1 + avail_procs_count += len(cores[coreid]) - remaining_cores = frameCores / 100 + remaining_procs = frameCores / 100 - if avail_cores_count < remaining_cores: + if avail_procs_count < remaining_procs: err = ('Not launching, insufficient hyperthreading cores to reserve ' 'based on frameCores (%s < %s)') \ - % (avail_cores_count, remaining_cores) + % (avail_procs_count, remaining_procs) log.critical(err) raise rqd.rqexceptions.CoreReservationFailureException(err) @@ -853,18 +853,22 @@ def reserveHT(self, frameCores): # the most idle cores first. key=lambda tup: len(tup[1]), reverse=True): - - while remaining_cores > 0 and len(cores) > 0: - coreid = cores.pop() - # Give all the hyperthreads on this core. - # This counts as one core. + cores = sorted(list(cores), key=lambda _coreid: int(_coreid)) + while remaining_procs > 0 and len(cores) > 0: + # Reserve cores with max threads first + # Avoid booking too much threads + # ex: if remaining_procs==2, get the next core with 2 threads + # ex: if remaining_procs==1, get the next core with 1 thread or any other core + coreid = next(iter([cid for cid in cores + if len(self.__procs_by_physid_and_coreid[physid][cid]) <= remaining_procs]), + cores[0]) + cores.remove(coreid) + procids = self.__procs_by_physid_and_coreid[physid][coreid] reserved_cores[int(physid)].coreid.extend([int(coreid)]) - remaining_cores -= 1 - - for procid in self.__procs_by_physid_and_coreid[physid][coreid]: - tasksets.append(procid) + remaining_procs -= len(procids) + tasksets.extend(procids) - if remaining_cores == 0: + if remaining_procs == 0: break log.warning('Taskset: Reserving procs - %s', ','.join(tasksets)) From 57bb9466bd2e13541c6204c2397acf58f90087b6 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+kernattila@users.noreply.github.com> Date: Thu, 1 Jun 2023 18:02:56 +0200 Subject: [PATCH 03/78] fix: reverse map() arguments --- rqd/rqd/rqmachine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 35f10666f..0f3c07436 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -274,7 +274,7 @@ def rssUpdate(self, frames): # - rss: inaccurate, similar to VmRss in /proc/[pid]/status child_statm_fields = self._getStatFields( rqd.rqconstants.PATH_PROC_PID_STATM.format(pid)) - child_statm_fields = map(child_statm_fields, str) + child_statm_fields = list(map(str, child_statm_fields)) pids[pid]['statm_size'] = \ int(re.search(r"\d+", child_statm_fields[0]).group()) \ if re.search(r"\d+", child_statm_fields[0]) else -1 From f968ad3709295622fce35c2d6e229faaac239e6b Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+kernattila@users.noreply.github.com> Date: Thu, 1 Jun 2023 19:11:15 +0200 Subject: [PATCH 04/78] test!: update HT test --- rqd/tests/rqmachine_tests.py | 78 +++++++++++++++++------------------- 1 file changed, 37 insertions(+), 41 deletions(-) diff --git a/rqd/tests/rqmachine_tests.py b/rqd/tests/rqmachine_tests.py index 1b1bdaf4a..017a3f224 100644 --- a/rqd/tests/rqmachine_tests.py +++ b/rqd/tests/rqmachine_tests.py @@ -447,12 +447,13 @@ def test_getBootReport(self): def test_reserveHT(self): """ - Total 2 physical(ph) processors with 4 cores each with 2 threads each - step1 - taskset1: Reserve 3 cores (ph1) - step2 - taskset0: Reserve 4 cores (ph0) - step3 - Release cores on taskset0 - step4 - taskset3: Reserve 2 cores (ph0) - step5 - taskset4: 3 remaining, Reserve 3 cores (ph0+ph1) + Total 2 physical(ph) processors with 4 cores each with 2 threads each (total 16 threads) + note: reserving odd threads will result in even threads when there is no mono-thread cores + step1 - taskset0: Reserve 4 threads (2 cores) (ph0->0,1) + step2 - taskset1: Reserve 6 threads (3 cores) (ph1->0,1,2) + step3 - Release cores on taskset0 (ph0->0,1) + step4 - taskset3: Reserve 6 threads (3 cores) (ph0->0,1,2) + step5 - taskset4: 4 remaining, Reserve 4 threads (2 cores) (ph0->3 + ph1->3) step5 - taskset5: No more cores """ cpuInfo = os.path.join(os.path.dirname(__file__), 'cpuinfo', '_cpuinfo_shark_ht_8-4-2-2') @@ -462,21 +463,6 @@ def test_reserveHT(self): self.machine.setupTaskset() # ------------------------step1------------------------- - # phys_id 1 - # - core_id 0 - # - process_id 4 - # - process_id 12 - # - core_id 1 - # - process_id 5 - # - process_id 13 - # - core_id 3 - # - process_id 7 - # - process_id 15 - tasksets1 = self.machine.reserveHT(300) - # pylint: disable=no-member - self.assertItemsEqual(['4', '5', '7', '12', '13', '15'], sorted(tasksets1.split(','))) - - # ------------------------step2------------------------- # phys_id 0 # - core_id 0 # - process_id 0 @@ -484,20 +470,30 @@ def test_reserveHT(self): # - core_id 1 # - process_id 1 # - process_id 9 - # - core_id 2 - # - process_id 2 - # - process_id 10 - # - core_id 3 - # - process_id 3 - # - process_id 11 tasksets0 = self.machine.reserveHT(400) # pylint: disable=no-member - self.assertItemsEqual(['0', '1', '2', '3', '8', '9', '10', '11'], + self.assertCountEqual(['0', '8', '1', '9'], sorted(tasksets0.split(','))) + # ------------------------step2------------------------- + # phys_id 1 + # - core_id 0 + # - process_id 4 + # - process_id 12 + # - core_id 1 + # - process_id 5 + # - process_id 13 + # - core_id 2 + # - process_id 6 + # - process_id 14 + tasksets1 = self.machine.reserveHT(600) + # pylint: disable=no-member + self.assertCountEqual(['4', '12', '5', '13', '6', '14'], + sorted(tasksets1.split(','))) + # reserved cores got updated properly # pylint: disable=no-member - self.assertItemsEqual([0, 1, 2, 3], self.coreDetail.reserved_cores[0].coreid) + self.assertCountEqual([0, 1], self.coreDetail.reserved_cores[0].coreid) # Make sure tastsets don't overlap self.assertTrue(set(tasksets0.split(',')).isdisjoint(tasksets1.split(','))) @@ -508,7 +504,7 @@ def test_reserveHT(self): # pylint: disable=no-member self.assertTrue(1 in self.coreDetail.reserved_cores) # pylint: disable=no-member - self.assertItemsEqual([0, 1, 3], self.coreDetail.reserved_cores[1].coreid) + self.assertCountEqual([0, 1, 2], self.coreDetail.reserved_cores[1].coreid) # ------------------------step4------------------------- # phys_id 0 @@ -518,30 +514,30 @@ def test_reserveHT(self): # - core_id 1 # - process_id 1 # - process_id 9 - tasksets3 = self.machine.reserveHT(200) + # - core_id 2 + # - process_id 2 + # - process_id 10 + tasksets3 = self.machine.reserveHT(600) # pylint: disable=no-member - self.assertItemsEqual(['0', '1', '8', '9'], sorted(tasksets3.split(','))) + self.assertCountEqual(['0', '8', '1', '9', '2', '10'], sorted(tasksets3.split(','))) # ------------------------step5------------------------- # phys_id 0 - # - core_id 2 - # - process_id 2 - # - process_id 10 # - core_id 3 # - process_id 3 # - process_id 11 # phys_id 1 - # - core_id 2 - # - process_id 6 - # - process_id 14 - tasksets4 = self.machine.reserveHT(300) + # - core_id 3 + # - process_id 7 + # - process_id 15 + tasksets4 = self.machine.reserveHT(400) # pylint: disable=no-member - self.assertItemsEqual(['2', '10', '3', '11', '6', '14'], sorted(tasksets4.split(','))) + self.assertCountEqual(['3', '11', '7', '15'], sorted(tasksets4.split(','))) # ------------------------step6------------------------- # No cores available with self.assertRaises(rqd.rqexceptions.CoreReservationFailureException): - self.machine.reserveHT(300) + self.machine.reserveHT(200) def test_tags(self): From ce22de2bf05e398955ae71fa29fd8401c21b699f Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+kernattila@users.noreply.github.com> Date: Thu, 1 Jun 2023 19:15:04 +0200 Subject: [PATCH 05/78] test!: avoid rqd RQD_USE_PATH_ENV_VAR option --- rqd/tests/rqmachine_tests.py | 1 + 1 file changed, 1 insertion(+) diff --git a/rqd/tests/rqmachine_tests.py b/rqd/tests/rqmachine_tests.py index 017a3f224..c29b260b6 100644 --- a/rqd/tests/rqmachine_tests.py +++ b/rqd/tests/rqmachine_tests.py @@ -371,6 +371,7 @@ def test_multipleGpus(self): self.assertEqual(122701222, self.machine.getGpuMemoryFree()) def test_getPathEnv(self): + rqd.rqconstants.RQD_USE_PATH_ENV_VAR = False self.assertEqual( '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', self.machine.getPathEnv()) From 56ee4871af2165848274a4da165cf0572409666e Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+kernattila@users.noreply.github.com> Date: Thu, 1 Jun 2023 19:48:23 +0200 Subject: [PATCH 06/78] test: add i9-12900 proc for tests --- .../_cpuinfo_i9_12900_hybrid_ht_24-12-2-1 | 672 ++++++++++++++++++ 1 file changed, 672 insertions(+) create mode 100644 rqd/tests/cpuinfo/_cpuinfo_i9_12900_hybrid_ht_24-12-2-1 diff --git a/rqd/tests/cpuinfo/_cpuinfo_i9_12900_hybrid_ht_24-12-2-1 b/rqd/tests/cpuinfo/_cpuinfo_i9_12900_hybrid_ht_24-12-2-1 new file mode 100644 index 000000000..f5daa0edc --- /dev/null +++ b/rqd/tests/cpuinfo/_cpuinfo_i9_12900_hybrid_ht_24-12-2-1 @@ -0,0 +1,672 @@ + +processor : 0 +vendor_id : GenuineIntel +cpu family : 6 +model : 151 +model name : 12th Gen Intel(R) Core(TM) i9-12900 +stepping : 2 +microcode : 0x22 +cpu MHz : 1238.064 +cache size : 30720 KB +physical id : 0 +siblings : 24 +core id : 0 +cpu cores : 16 +apicid : 0 +initial apicid : 0 +fpu : yes +fpu_exception : yes +cpuid level : 32 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr flush_l1d arch_capabilities +vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause +bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb +bogomips : 4838.40 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: + +processor : 1 +vendor_id : GenuineIntel +cpu family : 6 +model : 151 +model name : 12th Gen Intel(R) Core(TM) i9-12900 +stepping : 2 +microcode : 0x22 +cpu MHz : 2400.000 +cache size : 30720 KB +physical id : 0 +siblings : 24 +core id : 0 +cpu cores : 16 +apicid : 1 +initial apicid : 1 +fpu : yes +fpu_exception : yes +cpuid level : 32 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr flush_l1d arch_capabilities +vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause +bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb +bogomips : 4838.40 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: + +processor : 2 +vendor_id : GenuineIntel +cpu family : 6 +model : 151 +model name : 12th Gen Intel(R) Core(TM) i9-12900 +stepping : 2 +microcode : 0x22 +cpu MHz : 2400.000 +cache size : 30720 KB +physical id : 0 +siblings : 24 +core id : 4 +cpu cores : 16 +apicid : 8 +initial apicid : 8 +fpu : yes +fpu_exception : yes +cpuid level : 32 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr flush_l1d arch_capabilities +vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause +bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb +bogomips : 4838.40 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: + +processor : 3 +vendor_id : GenuineIntel +cpu family : 6 +model : 151 +model name : 12th Gen Intel(R) Core(TM) i9-12900 +stepping : 2 +microcode : 0x22 +cpu MHz : 2400.000 +cache size : 30720 KB +physical id : 0 +siblings : 24 +core id : 4 +cpu cores : 16 +apicid : 9 +initial apicid : 9 +fpu : yes +fpu_exception : yes +cpuid level : 32 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr flush_l1d arch_capabilities +vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause +bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb +bogomips : 4838.40 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: + +processor : 4 +vendor_id : GenuineIntel +cpu family : 6 +model : 151 +model name : 12th Gen Intel(R) Core(TM) i9-12900 +stepping : 2 +microcode : 0x22 +cpu MHz : 2400.000 +cache size : 30720 KB +physical id : 0 +siblings : 24 +core id : 8 +cpu cores : 16 +apicid : 16 +initial apicid : 16 +fpu : yes +fpu_exception : yes +cpuid level : 32 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr flush_l1d arch_capabilities +vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause +bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb +bogomips : 4838.40 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: + +processor : 5 +vendor_id : GenuineIntel +cpu family : 6 +model : 151 +model name : 12th Gen Intel(R) Core(TM) i9-12900 +stepping : 2 +microcode : 0x22 +cpu MHz : 2400.000 +cache size : 30720 KB +physical id : 0 +siblings : 24 +core id : 8 +cpu cores : 16 +apicid : 17 +initial apicid : 17 +fpu : yes +fpu_exception : yes +cpuid level : 32 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr flush_l1d arch_capabilities +vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause +bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb +bogomips : 4838.40 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: + +processor : 6 +vendor_id : GenuineIntel +cpu family : 6 +model : 151 +model name : 12th Gen Intel(R) Core(TM) i9-12900 +stepping : 2 +microcode : 0x22 +cpu MHz : 2400.000 +cache size : 30720 KB +physical id : 0 +siblings : 24 +core id : 12 +cpu cores : 16 +apicid : 24 +initial apicid : 24 +fpu : yes +fpu_exception : yes +cpuid level : 32 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr flush_l1d arch_capabilities +vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause +bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb +bogomips : 4838.40 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: + +processor : 7 +vendor_id : GenuineIntel +cpu family : 6 +model : 151 +model name : 12th Gen Intel(R) Core(TM) i9-12900 +stepping : 2 +microcode : 0x22 +cpu MHz : 998.689 +cache size : 30720 KB +physical id : 0 +siblings : 24 +core id : 12 +cpu cores : 16 +apicid : 25 +initial apicid : 25 +fpu : yes +fpu_exception : yes +cpuid level : 32 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr flush_l1d arch_capabilities +vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause +bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb +bogomips : 4838.40 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: + +processor : 8 +vendor_id : GenuineIntel +cpu family : 6 +model : 151 +model name : 12th Gen Intel(R) Core(TM) i9-12900 +stepping : 2 +microcode : 0x22 +cpu MHz : 2400.000 +cache size : 30720 KB +physical id : 0 +siblings : 24 +core id : 16 +cpu cores : 16 +apicid : 32 +initial apicid : 32 +fpu : yes +fpu_exception : yes +cpuid level : 32 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr flush_l1d arch_capabilities +vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause +bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb +bogomips : 4838.40 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: + +processor : 9 +vendor_id : GenuineIntel +cpu family : 6 +model : 151 +model name : 12th Gen Intel(R) Core(TM) i9-12900 +stepping : 2 +microcode : 0x22 +cpu MHz : 2400.000 +cache size : 30720 KB +physical id : 0 +siblings : 24 +core id : 16 +cpu cores : 16 +apicid : 33 +initial apicid : 33 +fpu : yes +fpu_exception : yes +cpuid level : 32 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr flush_l1d arch_capabilities +vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause +bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb +bogomips : 4838.40 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: + +processor : 10 +vendor_id : GenuineIntel +cpu family : 6 +model : 151 +model name : 12th Gen Intel(R) Core(TM) i9-12900 +stepping : 2 +microcode : 0x22 +cpu MHz : 2400.000 +cache size : 30720 KB +physical id : 0 +siblings : 24 +core id : 20 +cpu cores : 16 +apicid : 40 +initial apicid : 40 +fpu : yes +fpu_exception : yes +cpuid level : 32 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr flush_l1d arch_capabilities +vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause +bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb +bogomips : 4838.40 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: + +processor : 11 +vendor_id : GenuineIntel +cpu family : 6 +model : 151 +model name : 12th Gen Intel(R) Core(TM) i9-12900 +stepping : 2 +microcode : 0x22 +cpu MHz : 2400.000 +cache size : 30720 KB +physical id : 0 +siblings : 24 +core id : 20 +cpu cores : 16 +apicid : 41 +initial apicid : 41 +fpu : yes +fpu_exception : yes +cpuid level : 32 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr flush_l1d arch_capabilities +vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause +bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb +bogomips : 4838.40 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: + +processor : 12 +vendor_id : GenuineIntel +cpu family : 6 +model : 151 +model name : 12th Gen Intel(R) Core(TM) i9-12900 +stepping : 2 +microcode : 0x22 +cpu MHz : 2391.143 +cache size : 30720 KB +physical id : 0 +siblings : 24 +core id : 24 +cpu cores : 16 +apicid : 48 +initial apicid : 48 +fpu : yes +fpu_exception : yes +cpuid level : 32 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr flush_l1d arch_capabilities +vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause +bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb +bogomips : 4838.40 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: + +processor : 13 +vendor_id : GenuineIntel +cpu family : 6 +model : 151 +model name : 12th Gen Intel(R) Core(TM) i9-12900 +stepping : 2 +microcode : 0x22 +cpu MHz : 2400.000 +cache size : 30720 KB +physical id : 0 +siblings : 24 +core id : 24 +cpu cores : 16 +apicid : 49 +initial apicid : 49 +fpu : yes +fpu_exception : yes +cpuid level : 32 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr flush_l1d arch_capabilities +vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause +bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb +bogomips : 4838.40 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: + +processor : 14 +vendor_id : GenuineIntel +cpu family : 6 +model : 151 +model name : 12th Gen Intel(R) Core(TM) i9-12900 +stepping : 2 +microcode : 0x22 +cpu MHz : 2244.091 +cache size : 30720 KB +physical id : 0 +siblings : 24 +core id : 28 +cpu cores : 16 +apicid : 56 +initial apicid : 56 +fpu : yes +fpu_exception : yes +cpuid level : 32 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr flush_l1d arch_capabilities +vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause +bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb +bogomips : 4838.40 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: + +processor : 15 +vendor_id : GenuineIntel +cpu family : 6 +model : 151 +model name : 12th Gen Intel(R) Core(TM) i9-12900 +stepping : 2 +microcode : 0x22 +cpu MHz : 2400.000 +cache size : 30720 KB +physical id : 0 +siblings : 24 +core id : 28 +cpu cores : 16 +apicid : 57 +initial apicid : 57 +fpu : yes +fpu_exception : yes +cpuid level : 32 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr flush_l1d arch_capabilities +vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause +bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb +bogomips : 4838.40 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: + +processor : 16 +vendor_id : GenuineIntel +cpu family : 6 +model : 151 +model name : 12th Gen Intel(R) Core(TM) i9-12900 +stepping : 2 +microcode : 0x22 +cpu MHz : 2400.000 +cache size : 30720 KB +physical id : 0 +siblings : 24 +core id : 32 +cpu cores : 16 +apicid : 64 +initial apicid : 64 +fpu : yes +fpu_exception : yes +cpuid level : 32 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr flush_l1d arch_capabilities +vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause +bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb +bogomips : 4838.40 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: + +processor : 17 +vendor_id : GenuineIntel +cpu family : 6 +model : 151 +model name : 12th Gen Intel(R) Core(TM) i9-12900 +stepping : 2 +microcode : 0x22 +cpu MHz : 2400.000 +cache size : 30720 KB +physical id : 0 +siblings : 24 +core id : 33 +cpu cores : 16 +apicid : 66 +initial apicid : 66 +fpu : yes +fpu_exception : yes +cpuid level : 32 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr flush_l1d arch_capabilities +vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause +bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb +bogomips : 4838.40 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: + +processor : 18 +vendor_id : GenuineIntel +cpu family : 6 +model : 151 +model name : 12th Gen Intel(R) Core(TM) i9-12900 +stepping : 2 +microcode : 0x22 +cpu MHz : 2400.000 +cache size : 30720 KB +physical id : 0 +siblings : 24 +core id : 34 +cpu cores : 16 +apicid : 68 +initial apicid : 68 +fpu : yes +fpu_exception : yes +cpuid level : 32 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr flush_l1d arch_capabilities +vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause +bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb +bogomips : 4838.40 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: + +processor : 19 +vendor_id : GenuineIntel +cpu family : 6 +model : 151 +model name : 12th Gen Intel(R) Core(TM) i9-12900 +stepping : 2 +microcode : 0x22 +cpu MHz : 2400.000 +cache size : 30720 KB +physical id : 0 +siblings : 24 +core id : 35 +cpu cores : 16 +apicid : 70 +initial apicid : 70 +fpu : yes +fpu_exception : yes +cpuid level : 32 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr flush_l1d arch_capabilities +vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause +bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb +bogomips : 4838.40 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: + +processor : 20 +vendor_id : GenuineIntel +cpu family : 6 +model : 151 +model name : 12th Gen Intel(R) Core(TM) i9-12900 +stepping : 2 +microcode : 0x22 +cpu MHz : 2400.000 +cache size : 30720 KB +physical id : 0 +siblings : 24 +core id : 36 +cpu cores : 16 +apicid : 72 +initial apicid : 72 +fpu : yes +fpu_exception : yes +cpuid level : 32 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr flush_l1d arch_capabilities +vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause +bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb +bogomips : 4838.40 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: + +processor : 21 +vendor_id : GenuineIntel +cpu family : 6 +model : 151 +model name : 12th Gen Intel(R) Core(TM) i9-12900 +stepping : 2 +microcode : 0x22 +cpu MHz : 2400.000 +cache size : 30720 KB +physical id : 0 +siblings : 24 +core id : 37 +cpu cores : 16 +apicid : 74 +initial apicid : 74 +fpu : yes +fpu_exception : yes +cpuid level : 32 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr flush_l1d arch_capabilities +vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause +bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb +bogomips : 4838.40 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: + +processor : 22 +vendor_id : GenuineIntel +cpu family : 6 +model : 151 +model name : 12th Gen Intel(R) Core(TM) i9-12900 +stepping : 2 +microcode : 0x22 +cpu MHz : 2400.000 +cache size : 30720 KB +physical id : 0 +siblings : 24 +core id : 38 +cpu cores : 16 +apicid : 76 +initial apicid : 76 +fpu : yes +fpu_exception : yes +cpuid level : 32 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr flush_l1d arch_capabilities +vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause +bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb +bogomips : 4838.40 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: + +processor : 23 +vendor_id : GenuineIntel +cpu family : 6 +model : 151 +model name : 12th Gen Intel(R) Core(TM) i9-12900 +stepping : 2 +microcode : 0x22 +cpu MHz : 2400.000 +cache size : 30720 KB +physical id : 0 +siblings : 24 +core id : 39 +cpu cores : 16 +apicid : 78 +initial apicid : 78 +fpu : yes +fpu_exception : yes +cpuid level : 32 +wp : yes +flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves split_lock_detect avx_vnni dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req hfi umip pku ospke waitpkg gfni vaes vpclmulqdq tme rdpid movdiri movdir64b fsrm md_clear serialize pconfig arch_lbr flush_l1d arch_capabilities +vmx flags : vnmi preemption_timer posted_intr invvpid ept_x_only ept_ad ept_1gb flexpriority apicv tsc_offset vtpr mtf vapic ept vpid unrestricted_guest vapic_reg vid ple shadow_vmcs ept_mode_based_exec tsc_scaling usr_wait_pause +bugs : spectre_v1 spectre_v2 spec_store_bypass swapgs eibrs_pbrsb +bogomips : 4838.40 +clflush size : 64 +cache_alignment : 64 +address sizes : 46 bits physical, 48 bits virtual +power management: From c084fa2275ebaeb19d5e7d9577930e30530c9242 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+kernattila@users.noreply.github.com> Date: Thu, 1 Jun 2023 19:50:39 +0200 Subject: [PATCH 07/78] test: add test_i9_12900() --- rqd/tests/rqmachine_tests.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rqd/tests/rqmachine_tests.py b/rqd/tests/rqmachine_tests.py index c29b260b6..b10f01ea2 100644 --- a/rqd/tests/rqmachine_tests.py +++ b/rqd/tests/rqmachine_tests.py @@ -585,6 +585,9 @@ def test_srdsvr05(self): def test_srdsvr09(self): self.__cpuinfoTestHelper('_cpuinfo_srdsvr09_48-12-4') + def test_i9_12900(self): + self.__cpuinfoTestHelper('_cpuinfo_i9_12900_hybrid_ht_24-12-2-1') + def __cpuinfoTestHelper(self, pathCpuInfo): # File format: _cpuinfo_dub_x-x-x where x-x-x is totalCores-coresPerProc-numProcs pathCpuInfo = os.path.join(os.path.dirname(__file__), 'cpuinfo', pathCpuInfo) From a21d62f8fa036e53f4d2e3a1f4a49711e1682eb9 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+kernattila@users.noreply.github.com> Date: Thu, 1 Jun 2023 22:43:07 +0200 Subject: [PATCH 08/78] fix: fixed and renamed cpu file --- ...ybrid_ht_24-12-2-1 => _cpuinfo_i9_12900_hybrid_ht_24-24-1-1} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename rqd/tests/cpuinfo/{_cpuinfo_i9_12900_hybrid_ht_24-12-2-1 => _cpuinfo_i9_12900_hybrid_ht_24-24-1-1} (100%) diff --git a/rqd/tests/cpuinfo/_cpuinfo_i9_12900_hybrid_ht_24-12-2-1 b/rqd/tests/cpuinfo/_cpuinfo_i9_12900_hybrid_ht_24-24-1-1 similarity index 100% rename from rqd/tests/cpuinfo/_cpuinfo_i9_12900_hybrid_ht_24-12-2-1 rename to rqd/tests/cpuinfo/_cpuinfo_i9_12900_hybrid_ht_24-24-1-1 index f5daa0edc..1862c4e90 100644 --- a/rqd/tests/cpuinfo/_cpuinfo_i9_12900_hybrid_ht_24-12-2-1 +++ b/rqd/tests/cpuinfo/_cpuinfo_i9_12900_hybrid_ht_24-24-1-1 @@ -1,4 +1,3 @@ - processor : 0 vendor_id : GenuineIntel cpu family : 6 @@ -670,3 +669,4 @@ clflush size : 64 cache_alignment : 64 address sizes : 46 bits physical, 48 bits virtual power management: + From 8add4c90575f6255d115fcb2487e31e456374870 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+kernattila@users.noreply.github.com> Date: Thu, 1 Jun 2023 22:45:02 +0200 Subject: [PATCH 09/78] test: added a test for hybrid cpus with 8 performance cores and 8 efficiency cores. --- rqd/tests/rqmachine_tests.py | 159 ++++++++++++++++++++++++++++++++++- 1 file changed, 158 insertions(+), 1 deletion(-) diff --git a/rqd/tests/rqmachine_tests.py b/rqd/tests/rqmachine_tests.py index b10f01ea2..816a4a7c6 100644 --- a/rqd/tests/rqmachine_tests.py +++ b/rqd/tests/rqmachine_tests.py @@ -540,6 +540,163 @@ def test_reserveHT(self): with self.assertRaises(rqd.rqexceptions.CoreReservationFailureException): self.machine.reserveHT(200) + def test_reserveHybridHT(self): + """ + Total 1 physical(ph) processors with 8 P-cores(2 threads) and 8 E-cores(1 thread), total 24 threads. + note: reserving odd threads will result in even threads when there is no mono-thread cores, + which is not the case here. it should reserve E-cores to match the odd request. + step1 - taskset0: Reserve 4 threads (2P), 4 threads occupied + step2 - taskset1: Reserve 5 threads (2P, 1E), 9 threads occupied + step3 - taskset2: Reserve 6 threads (3P), 15 threads occupied + step4 - Release taskset0, 3P and 7E remaining, 11 threads occupied + step5 - taskset3: Reserve 12 threads (3P, 6E), 23 threads occupied + step6 - taskset4: Reserve 1 thread (1E), 24 threads occupied + step7 - Reserve 1 thread (1E), no more free cores + """ + cpuInfo = os.path.join(os.path.dirname(__file__), 'cpuinfo', '_cpuinfo_i9_12900_hybrid_ht_24-24-1-1') + self.fs.add_real_file(cpuInfo) + self.machine.testInitMachineStats(cpuInfo) + + self.machine.setupTaskset() + + # ------------------------step1------------------------- + # phys_id 0 + # - P core_id 0 + # - process_id 0 + # - process_id 1 + # - P core_id 4 + # - process_id 2 + # - process_id 3 + # - P core_id 8 + # - process_id 4 + # - process_id 5 + # - P core_id 12 + # - process_id 6 + # - process_id 7 + # - P core_id 16 + # - process_id 8 + # - process_id 9 + # - P core_id 20 + # - process_id 10 + # - process_id 11 + # - P core_id 24 + # - process_id 12 + # - process_id 13 + # - P core_id 28 + # - process_id 14 + # - process_id 15 + + # - E core_id 32 + # - process_id 16 + # - E core_id 33 + # - process_id 17 + # - E core_id 34 + # - process_id 18 + # - E core_id 35 + # - process_id 19 + # - E core_id 36 + # - process_id 20 + # - E core_id 37 + # - process_id 21 + # - E core_id 38 + # - process_id 22 + # - E core_id 39 + # - process_id 23 + tasksets0 = self.machine.reserveHT(400) + + # should reserve 2P (0,1, 2,3) + # pylint: disable=no-member + self.assertCountEqual(['0', '1', '2', '3'], tasksets0.split(',')) + + # should have 2 cores occupied + # pylint: disable=no-member + self.assertCountEqual([0, 4], self.coreDetail.reserved_cores[0].coreid) + # should have 4 threads occupied + self.assertEqual(len(tasksets0.split(',')), 4) + + + # ------------------------step2------------------------- + tasksets1 = self.machine.reserveHT(500) + + # should reserve 2P + 1E (4,5, 6,7, 16) + # pylint: disable=no-member + self.assertCountEqual(['4', '5', '6', '7', '16'], tasksets1.split(',')) + + # should have 5 cores occupied + # pylint: disable=no-member + self.assertCountEqual([0, 4, 8, 12, 32], self.coreDetail.reserved_cores[0].coreid) + # should have 9 threads occupied + self.assertEqual(len(tasksets0.split(',')) + + len(tasksets1.split(',')), + 9) + + + # ------------------------step3------------------------- + tasksets2 = self.machine.reserveHT(600) + + # should reserve 3P (8,9, 10,11, 12,13) + # pylint: disable=no-member + self.assertCountEqual(['8', '9', '10', '11', '12', '13'], tasksets2.split(',')) + + # should have 8 cores occupied + # pylint: disable=no-member + self.assertCountEqual([0, 4, 8, 12, 16, 20, 24, 32], self.coreDetail.reserved_cores[0].coreid) + # should have 15 threads occupied + self.assertEqual(len(tasksets0.split(',')) + + len(tasksets1.split(',')) + + len(tasksets2.split(',')), + 15) + + + # ------------------------step4------------------------- + self.machine.releaseHT(tasksets0) + # should release 2P (0,1, 2,3) + # should have 6 cores occupied + # pylint: disable=no-member + self.assertCountEqual([8, 12, 16, 20, 24, 32], self.coreDetail.reserved_cores[0].coreid) + # should have 11 threads occupied + self.assertEqual(len(tasksets1.split(',')) + + len(tasksets2.split(',')), + 11) + + + # ------------------------step5------------------------- + tasksets3 = self.machine.reserveHT(1200) + + # should reserve 3P + 6E (0,1, 2,3, 14,15, 17, 18, 19, 20, 21, 22) + # pylint: disable=no-member + self.assertCountEqual(['0', '1', '2', '3', '14', '15', '17', '18', '19', '20', '21', '22'], tasksets3.split(',')) + + # should have 15 cores occupied, 1E free + # pylint: disable=no-member + self.assertCountEqual([0, 4, 8, 12, 16, 20, 24, 28, 32, 33, 34, 35, 36, 37, 38], + self.coreDetail.reserved_cores[0].coreid) + + # should have 23 threads occupied + self.assertEqual(len(tasksets1.split(',')) + + len(tasksets2.split(',')) + + len(tasksets3.split(',')), + 23) + + # ------------------------step6------------------------- + tasksets4 = self.machine.reserveHT(100) + + # should reserve 1E (23) + # pylint: disable=no-member + self.assertCountEqual(['23'], tasksets4.split(',')) + + # Make sure 24 threads are occupied + self.assertEqual(len(tasksets1.split(',')) + + len(tasksets2.split(',')) + + len(tasksets3.split(',')) + + len(tasksets4.split(',')), + 24) + + # ------------------------step7------------------------- + # No cores available + with self.assertRaises(rqd.rqexceptions.CoreReservationFailureException): + self.machine.reserveHT(100) + def test_tags(self): tags = ["test1", "test2", "test3"] @@ -586,7 +743,7 @@ def test_srdsvr09(self): self.__cpuinfoTestHelper('_cpuinfo_srdsvr09_48-12-4') def test_i9_12900(self): - self.__cpuinfoTestHelper('_cpuinfo_i9_12900_hybrid_ht_24-12-2-1') + self.__cpuinfoTestHelper('_cpuinfo_i9_12900_hybrid_ht_24-24-1-1') def __cpuinfoTestHelper(self, pathCpuInfo): # File format: _cpuinfo_dub_x-x-x where x-x-x is totalCores-coresPerProc-numProcs From f0558898abc0f91d4adad6e3a24b4ecb2ea42dbd Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+kernattila@users.noreply.github.com> Date: Thu, 1 Jun 2023 22:56:05 +0200 Subject: [PATCH 10/78] doc: fix typo --- rqd/tests/rqmachine_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rqd/tests/rqmachine_tests.py b/rqd/tests/rqmachine_tests.py index 816a4a7c6..237b9c688 100644 --- a/rqd/tests/rqmachine_tests.py +++ b/rqd/tests/rqmachine_tests.py @@ -455,7 +455,7 @@ def test_reserveHT(self): step3 - Release cores on taskset0 (ph0->0,1) step4 - taskset3: Reserve 6 threads (3 cores) (ph0->0,1,2) step5 - taskset4: 4 remaining, Reserve 4 threads (2 cores) (ph0->3 + ph1->3) - step5 - taskset5: No more cores + step6 - taskset5: No more cores """ cpuInfo = os.path.join(os.path.dirname(__file__), 'cpuinfo', '_cpuinfo_shark_ht_8-4-2-2') self.fs.add_real_file(cpuInfo) From caff254cd4861157b501c6c601c3f6fd599aadfa Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+kernattila@users.noreply.github.com> Date: Fri, 2 Jun 2023 02:34:24 +0200 Subject: [PATCH 11/78] fix: read proper statm columns (see issue #1188) --- rqd/rqd/rqmachine.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 0f3c07436..17cbc12ac 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -274,13 +274,12 @@ def rssUpdate(self, frames): # - rss: inaccurate, similar to VmRss in /proc/[pid]/status child_statm_fields = self._getStatFields( rqd.rqconstants.PATH_PROC_PID_STATM.format(pid)) - child_statm_fields = list(map(str, child_statm_fields)) pids[pid]['statm_size'] = \ - int(re.search(r"\d+", child_statm_fields[0]).group()) \ - if re.search(r"\d+", child_statm_fields[0]) else -1 + int(re.search(r"\d+", child_statm_fields[2]).group()) \ + if re.search(r"\d+", child_statm_fields[2]) else -1 pids[pid]['statm_rss'] = \ - int(re.search(r"\d+", child_statm_fields[1]).group()) \ - if re.search(r"\d+", child_statm_fields[1]) else -1 + int(re.search(r"\d+", child_statm_fields[3]).group()) \ + if re.search(r"\d+", child_statm_fields[3]) else -1 # pylint: disable=broad-except except (OSError, IOError): From a3596e192b4d636b49c8f10c0b14d42258555b4a Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Wed, 28 Aug 2024 13:21:18 +0200 Subject: [PATCH 12/78] doc: explain the logic for reserving cores/threads. --- rqd/rqd/rqmachine.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 947d08cb1..7d8532065 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -866,10 +866,12 @@ def reserveHT(self, frameCores): reverse=True): cores = sorted(list(cores), key=lambda _coreid: int(_coreid)) while remaining_procs > 0 and len(cores) > 0: - # Reserve cores with max threads first - # Avoid booking too much threads + # Reserve hyper-threaded cores first (2 threads(logical cores) for 1 physical core) + # Avoid booking a hyper-threaded core for an odd thread count remainder # ex: if remaining_procs==2, get the next core with 2 threads # ex: if remaining_procs==1, get the next core with 1 thread or any other core + # here we fall back on the first physical core (assuming "first in list" == "has more threads") + # if we didn't find a core with the right number of threads, and continue the loop. coreid = next(iter([cid for cid in cores if len(self.__procs_by_physid_and_coreid[physid][cid]) <= remaining_procs]), cores[0]) From caa534d1a17846e4d38b5c57c231badda77b91a1 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Sat, 21 Sep 2024 03:41:37 +0200 Subject: [PATCH 13/78] fix: lint and remove useless lambda, sorting does not need to cast str to int. --- rqd/rqd/rqmachine.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 64220c3ed..e60b8819f 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -887,17 +887,19 @@ def reserveHT(self, frameCores): # the most idle cores first. key=lambda tup: len(tup[1]), reverse=True): - cores = sorted(list(cores), key=lambda _coreid: int(_coreid)) + cores = sorted(list(cores)) while remaining_procs > 0 and len(cores) > 0: # Reserve hyper-threaded cores first (2 threads(logical cores) for 1 physical core) # Avoid booking a hyper-threaded core for an odd thread count remainder # ex: if remaining_procs==2, get the next core with 2 threads # ex: if remaining_procs==1, get the next core with 1 thread or any other core - # here we fall back on the first physical core (assuming "first in list" == "has more threads") + # here we fall back on the first physical core + # (assuming "first in list" == "has more threads") # if we didn't find a core with the right number of threads, and continue the loop. - coreid = next(iter([cid for cid in cores - if len(self.__procs_by_physid_and_coreid[physid][cid]) <= remaining_procs]), - cores[0]) + coreid = next(iter( + [cid for cid in cores + if len(self.__procs_by_physid_and_coreid[physid][cid]) <= remaining_procs]), + cores[0]) cores.remove(coreid) procids = self.__procs_by_physid_and_coreid[physid][coreid] reserved_cores[int(physid)].coreid.extend([int(coreid)]) From 320c670b41c1e2d6b3f10800fafd073bd7f6f0c9 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Sat, 21 Sep 2024 04:07:33 +0200 Subject: [PATCH 14/78] fix: lint lines too long --- rqd/tests/rqmachine_tests.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/rqd/tests/rqmachine_tests.py b/rqd/tests/rqmachine_tests.py index 237b9c688..6e401ad2d 100644 --- a/rqd/tests/rqmachine_tests.py +++ b/rqd/tests/rqmachine_tests.py @@ -542,7 +542,8 @@ def test_reserveHT(self): def test_reserveHybridHT(self): """ - Total 1 physical(ph) processors with 8 P-cores(2 threads) and 8 E-cores(1 thread), total 24 threads. + Total 1 physical(ph) processors with 8 P-cores(2 threads) and 8 E-cores(1 thread), + for a total of 24 threads. note: reserving odd threads will result in even threads when there is no mono-thread cores, which is not the case here. it should reserve E-cores to match the odd request. step1 - taskset0: Reserve 4 threads (2P), 4 threads occupied @@ -553,7 +554,9 @@ def test_reserveHybridHT(self): step6 - taskset4: Reserve 1 thread (1E), 24 threads occupied step7 - Reserve 1 thread (1E), no more free cores """ - cpuInfo = os.path.join(os.path.dirname(__file__), 'cpuinfo', '_cpuinfo_i9_12900_hybrid_ht_24-24-1-1') + cpuInfo = os.path.join(os.path.dirname(__file__), + 'cpuinfo', + '_cpuinfo_i9_12900_hybrid_ht_24-24-1-1') self.fs.add_real_file(cpuInfo) self.machine.testInitMachineStats(cpuInfo) @@ -640,7 +643,8 @@ def test_reserveHybridHT(self): # should have 8 cores occupied # pylint: disable=no-member - self.assertCountEqual([0, 4, 8, 12, 16, 20, 24, 32], self.coreDetail.reserved_cores[0].coreid) + self.assertCountEqual([0, 4, 8, 12, 16, 20, 24, 32], + self.coreDetail.reserved_cores[0].coreid) # should have 15 threads occupied self.assertEqual(len(tasksets0.split(',')) + len(tasksets1.split(',')) @@ -665,7 +669,8 @@ def test_reserveHybridHT(self): # should reserve 3P + 6E (0,1, 2,3, 14,15, 17, 18, 19, 20, 21, 22) # pylint: disable=no-member - self.assertCountEqual(['0', '1', '2', '3', '14', '15', '17', '18', '19', '20', '21', '22'], tasksets3.split(',')) + self.assertCountEqual(['0', '1', '2', '3', '14', '15', '17', '18', '19', '20', '21', '22'], + tasksets3.split(',')) # should have 15 cores occupied, 1E free # pylint: disable=no-member From adb179fb57979045c4dec022de9be79d264d059a Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Fri, 27 Sep 2024 11:05:19 +0200 Subject: [PATCH 15/78] fix: revert statm field indices, error was fixed by #1308 --- rqd/rqd/rqmachine.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 64220c3ed..d330d420f 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -279,11 +279,11 @@ def rssUpdate(self, frames): child_statm_fields = self._getStatFields( rqd.rqconstants.PATH_PROC_PID_STATM.format(pid)) pids[pid]['statm_size'] = \ - int(re.search(r"\d+", child_statm_fields[2]).group()) \ - if re.search(r"\d+", child_statm_fields[2]) else -1 + int(re.search(r"\d+", child_statm_fields[0]).group()) \ + if re.search(r"\d+", child_statm_fields[0]) else -1 pids[pid]['statm_rss'] = \ - int(re.search(r"\d+", child_statm_fields[3]).group()) \ - if re.search(r"\d+", child_statm_fields[3]) else -1 + int(re.search(r"\d+", child_statm_fields[1]).group()) \ + if re.search(r"\d+", child_statm_fields[1]) else -1 # pylint: disable=broad-except except (OSError, IOError): From 31ba6da3e3f796839e0f41c68389bdf0ff7014d7 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Wed, 16 Oct 2024 13:42:25 +0200 Subject: [PATCH 16/78] fix: force to list cores in ascending order --- rqd/rqd/rqmachine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index de1ea3f6b..8c0750e19 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -887,7 +887,7 @@ def reserveHT(self, frameCores): # the most idle cores first. key=lambda tup: len(tup[1]), reverse=True): - cores = sorted(list(cores)) + cores = sorted(list(cores), key=int) while remaining_procs > 0 and len(cores) > 0: # Reserve hyper-threaded cores first (2 threads(logical cores) for 1 physical core) # Avoid booking a hyper-threaded core for an odd thread count remainder From 8fc315c358388efe44c906ba8c9168cdbd7711a0 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Wed, 16 Oct 2024 13:43:06 +0200 Subject: [PATCH 17/78] fix: get out of the loop for edge cases (1 too many core booked) --- rqd/rqd/rqmachine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 8c0750e19..7146478e6 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -906,7 +906,7 @@ def reserveHT(self, frameCores): remaining_procs -= len(procids) tasksets.extend(procids) - if remaining_procs == 0: + if remaining_procs <= 0: break log.warning('Taskset: Reserving procs - %s', ','.join(tasksets)) From 989d85b028581b704aa7491bf3c834fea2d89a40 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Thu, 17 Apr 2025 07:00:29 +0200 Subject: [PATCH 18/78] refacto: deprecated reserveHT() and created a new reserveCores() methods that handles both logical (threads) and physical cores (that's what reserveHT was doing. --- rqd/rqd/rqmachine.py | 69 ++++++++++++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 19 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 0d01eb94d..ff7f99b42 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -42,6 +42,7 @@ import tempfile import time import traceback +import warnings # pylint: disable=import-error,wrong-import-position if platform.system() in ('Linux', 'Darwin'): @@ -841,20 +842,23 @@ def setupGpu(self): """ Setup rqd for Gpus """ self.__gpusets = set(range(self.getGpuCount())) - def reserveHT(self, frameCores): + def reserveCores(self, coresCount=0, logical=True): """ Reserve cores for use by taskset taskset -c 0,1,8,9 COMMAND Not thread save, use with locking. - @type frameCores: int - @param frameCores: The total physical cores reserved by the frame. + @type coresCount: int + @param coresCount: The total physical cores reserved by the frame. + @type logical: bool + @param logical: If True, reserve logical cores (aka threads), else physical cores. + note: logical cores is what you see in htop or task manager. @rtype: string @return: The cpu-list for taskset -c """ - if frameCores % 100: + if coresCount % 100: log.warning('Taskset: Can not reserveHT with fractional cores') return None - log.warning('Taskset: Requesting reserve of %d', (frameCores // 100)) + log.warning('Taskset: Requesting reserve of %d', (coresCount // 100)) # Look for the most idle physical cpu. # Prefer to assign cores from the same physical cpu. @@ -869,14 +873,19 @@ def reserveHT(self, frameCores): int(coreid) in reserved_cores[int(physid)].coreid: continue avail_cores.setdefault(physid, set()).add(coreid) - avail_procs_count += len(cores[coreid]) - - remaining_procs = frameCores / 100 - - if avail_procs_count < remaining_procs: - err = ('Not launching, insufficient hyperthreading cores to reserve ' - 'based on frameCores (%s < %s)') \ - % (avail_procs_count, remaining_procs) + if logical: + # Count all threads (logical cores) + avail_procs_count += len(cores[coreid]) + else: + # Count only physical cores + avail_procs_count += 1 + + query_procs = coresCount / 100 + + if avail_procs_count < query_procs: + err = ('Not launching, insufficient cores to reserve ' + 'based on coresCount (%s < %s)') \ + % (avail_procs_count, query_procs) log.critical(err) raise rqd.rqexceptions.CoreReservationFailureException(err) @@ -889,31 +898,53 @@ def reserveHT(self, frameCores): key=lambda tup: len(tup[1]), reverse=True): cores = sorted(list(cores), key=int) - while remaining_procs > 0 and len(cores) > 0: + while query_procs > 0 and len(cores) > 0: # Reserve hyper-threaded cores first (2 threads(logical cores) for 1 physical core) # Avoid booking a hyper-threaded core for an odd thread count remainder - # ex: if remaining_procs==2, get the next core with 2 threads - # ex: if remaining_procs==1, get the next core with 1 thread or any other core + # ex: if query_procs==2, get the next core with 2 threads + # ex: if query_procs==1, get the next core with 1 thread or any other core # here we fall back on the first physical core # (assuming "first in list" == "has more threads") # if we didn't find a core with the right number of threads, and continue the loop. coreid = next(iter( [cid for cid in cores - if len(self.__procs_by_physid_and_coreid[physid][cid]) <= remaining_procs]), + if len(self.__procs_by_physid_and_coreid[physid][cid]) <= query_procs]), cores[0]) cores.remove(coreid) procids = self.__procs_by_physid_and_coreid[physid][coreid] reserved_cores[int(physid)].coreid.extend([int(coreid)]) - remaining_procs -= len(procids) + if logical: + query_procs -= len(procids) + else: + query_procs -= 1 tasksets.extend(procids) - if remaining_procs <= 0: + if query_procs <= 0: + # Could be negative if we reserved a full core with more threads than needed break log.warning('Taskset: Reserving procs - %s', ','.join(tasksets)) return ','.join(tasksets) + + def reserveHT(self, frameCores): + """ Reserve cores for use by taskset + taskset -c 0,1,8,9 COMMAND + Not thread save, use with locking. + @type frameCores: int + @param frameCores: The total physical cores reserved by the frame. + @rtype: string + @return: The cpu-list for taskset -c + """ + warnings.warn( + "The `reserveHT` method is deprecated and will be removed in a future release. " + "Use `reserveCores(logical=False)` instead.", + DeprecationWarning, + stacklevel=2 + ) + return reserveCores(frameCores, logical=False) + # pylint: disable=inconsistent-return-statements def releaseHT(self, reservedHT): """ Release cores used by taskset From a120265fed940b2baac55d28232f5a1a2fe83e30 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Fri, 18 Apr 2025 15:17:07 +0200 Subject: [PATCH 19/78] refacto: use reserveCores() in place of the deprecated reserveHT(). Rename variable `reserveHT` -> `taskset` for clarity. --- rqd/rqd/rqcore.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rqd/rqd/rqcore.py b/rqd/rqd/rqcore.py index 5b85efe75..8163b8e02 100644 --- a/rqd/rqd/rqcore.py +++ b/rqd/rqd/rqcore.py @@ -843,9 +843,9 @@ def launchFrame(self, runFrame): # pylint: enable=no-member if runFrame.environment.get('CUE_THREADABLE') == '1': - reserveHT = self.machine.reserveHT(runFrame.num_cores) - if reserveHT: - runFrame.attributes['CPU_LIST'] = reserveHT + taskset = self.machine.reserveCores(runFrame.num_cores) + if taskset: + runFrame.attributes['CPU_LIST'] = taskset if runFrame.num_gpus: reserveGpus = self.machine.reserveGpus(runFrame.num_gpus) From ef232ae5580be22bec90c27fe4636681ae7c95a8 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Fri, 18 Apr 2025 16:29:04 +0200 Subject: [PATCH 20/78] feat: add fields for logical cores in: - CoreDetail: total_threads - RenderHost: threads_per_proc - RunningFrameInfo: use_threads --- proto/report.proto | 67 ++++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/proto/report.proto b/proto/report.proto index f9c56d5f4..0600129c0 100644 --- a/proto/report.proto +++ b/proto/report.proto @@ -32,12 +32,13 @@ message BootReport { } message CoreDetail { - int32 total_cores = 1; - int32 idle_cores = 2; - int32 locked_cores = 3; - int32 booked_cores = 4; + int32 total_cores = 1; // physical cores + int32 total_threads = 2; // logical cores + int32 idle_cores = 3; + int32 locked_cores = 4; + int32 booked_cores = 5; //map - map reserved_cores = 5; + map reserved_cores = 6; } message CoreId { @@ -65,21 +66,22 @@ message RenderHost { bool nimby_locked = 3; // if nimby has locked the host due to user activity string facility= 4; // The name of the facility that the host is in int32 num_procs = 5; // the number of physical procs on this machine - int32 cores_per_proc = 6; // the number of cores per proc - int64 total_swap = 7; // the total size of the swap in kB - int64 total_mem = 8; // the total size of the main memory pool in kB - int64 total_mcp = 9; // the total size of MCP in kB - int64 free_swap = 10; // the current amount of free swap in kB - int64 free_mem = 11; // the current amount of free memory in kB - int64 free_mcp = 12; // the current amount of free MCP in kB - int32 load = 13; // the current load on the proc - int32 boot_time = 14; // the time the proc was booted - repeated string tags = 15; // an array of default tags that are added to the host record - host.HardwareState state = 16; // hardware state for the host - map attributes = 17; // additional data can be provided about the host - int32 num_gpus = 18; // the number of physical GPU's - int64 free_gpu_mem = 19; // the current amount of free gpu memory in kB - int64 total_gpu_mem = 20; // the total size of gpu memory in kB + int32 cores_per_proc = 6; // the number of physical cores per proc + int32 threads_per_proc = 7; // the number of logical cores per proc + int64 total_swap = 8; // the total size of the swap in kB + int64 total_mem = 9; // the total size of the main memory pool in kB + int64 total_mcp = 10; // the total size of MCP in kB + int64 free_swap = 11; // the current amount of free swap in kB + int64 free_mem = 12; // the current amount of free memory in kB + int64 free_mcp = 13; // the current amount of free MCP in kB + int32 load = 14; // the current load on the proc + int32 boot_time = 15; // the time the proc was booted + repeated string tags = 16; // an array of default tags that are added to the host record + host.HardwareState state = 17; // hardware state for the host + map attributes = 18; // additional data can be provided about the host + int32 num_gpus = 19; // the number of physical GPU's + int64 free_gpu_mem = 20; // the current amount of free gpu memory in kB + int64 total_gpu_mem = 21; // the total size of gpu memory in kB }; message RunningFrameInfo { @@ -90,18 +92,19 @@ message RunningFrameInfo { string frame_name = 5; string layer_id = 6; int32 num_cores = 7; - int64 start_time = 8; - int64 max_rss = 9; // kB - int64 rss = 10; // kB - int64 max_vsize = 11; // kB - int64 vsize = 12; // kB - map attributes = 13; //additional data can be provided about the running frame - int64 llu_time = 14; - int32 num_gpus = 15; - int64 max_used_gpu_memory = 16; // kB - int64 used_gpu_memory = 17; // kB - ChildrenProcStats children = 18; //additional data about the running frame's child processes - int64 used_swap_memory = 19; // kB + bool use_threads = 8; // whether the frame is requesting logical or physical cores + int64 start_time = 9; + int64 max_rss = 10; // kB + int64 rss = 11; // kB + int64 max_vsize = 12; // kB + int64 vsize = 13; // kB + map attributes = 14; //additional data can be provided about the running frame + int64 llu_time = 15; + int32 num_gpus = 16; + int64 max_used_gpu_memory = 17; // kB + int64 used_gpu_memory = 18; // kB + ChildrenProcStats children = 19; //additional data about the running frame's child processes + int64 used_swap_memory = 20; // kB }; message ChildrenProcStats { From 04d89bf60cc0fcce1308b984f08ad12f09482ca4 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Fri, 18 Apr 2025 16:29:50 +0200 Subject: [PATCH 21/78] refacto: change variable name again taskset -> cpu_list --- rqd/rqd/rqcore.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rqd/rqd/rqcore.py b/rqd/rqd/rqcore.py index 8163b8e02..7e7b3f479 100644 --- a/rqd/rqd/rqcore.py +++ b/rqd/rqd/rqcore.py @@ -843,9 +843,9 @@ def launchFrame(self, runFrame): # pylint: enable=no-member if runFrame.environment.get('CUE_THREADABLE') == '1': - taskset = self.machine.reserveCores(runFrame.num_cores) - if taskset: - runFrame.attributes['CPU_LIST'] = taskset + cpu_list = self.machine.reserveCores(coresCount=runFrame.num_cores, logical=runFrame.use_threads) + if cpu_list: + runFrame.attributes['CPU_LIST'] = cpu_list if runFrame.num_gpus: reserveGpus = self.machine.reserveGpus(runFrame.num_gpus) From f8fed7a21e508aea89f7746c3ca5f144cb02a9b8 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Fri, 18 Apr 2025 16:30:15 +0200 Subject: [PATCH 22/78] doc: add docstring to releaseCores() --- rqd/rqd/rqcore.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rqd/rqd/rqcore.py b/rqd/rqd/rqcore.py index 7e7b3f479..5f690999d 100644 --- a/rqd/rqd/rqcore.py +++ b/rqd/rqd/rqcore.py @@ -735,7 +735,10 @@ def killAllFrame(self, reason): def releaseCores(self, reqRelease, releaseHT=None, releaseGpus=None): """The requested number of cores are released @type reqRelease: int - @param reqRelease: Number of cores to release, 100 = 1 physical core""" + @param reqRelease: Number of cores to release, 100 = 1 physical core + @type releaseHT: str + @param releaseHT: The hyper-threading cores to release + """ with self.__threadLock: # pylint: disable=no-member self.cores.booked_cores -= reqRelease From 65bc6f8ef51defe9c70b94e75318acc935b894da Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Fri, 18 Apr 2025 17:07:35 +0200 Subject: [PATCH 23/78] feat: add total_threads to rqcore --- rqd/rqd/rqcore.py | 1 + 1 file changed, 1 insertion(+) diff --git a/rqd/rqd/rqcore.py b/rqd/rqd/rqcore.py index 5f690999d..b7cd8aff5 100644 --- a/rqd/rqd/rqcore.py +++ b/rqd/rqd/rqcore.py @@ -553,6 +553,7 @@ def __init__(self, optNimbyoff=False): self.cores = rqd.compiled_proto.report_pb2.CoreDetail( total_cores=0, + total_threads=0, idle_cores=0, locked_cores=0, booked_cores=0, From a280edd9eea7bf4cdc5bf2bc719c26e1b30fdd2d Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Fri, 18 Apr 2025 17:08:15 +0200 Subject: [PATCH 24/78] feat: use total_threads instead of total_cores to test if we should unlock nimby. --- rqd/rqd/rqmachine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index ff7f99b42..80b62abb9 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -131,7 +131,7 @@ def isNimbySafeToUnlock(self): """Returns False if nimby should not unlock due to resource limits""" if not self.isNimbySafeToRunJobs(): return False - if self.getLoadAvg() / self.__coreInfo.total_cores > rqd.rqconstants.MAXIMUM_LOAD: + if self.getLoadAvg() / self.__coreInfo.total_threads > rqd.rqconstants.MAXIMUM_LOAD: return False return True From d57541de1e6829b4b70c279c4655fedea004a657 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Fri, 18 Apr 2025 17:29:42 +0200 Subject: [PATCH 25/78] test: use logical cores for hybrid CPU test --- rqd/tests/rqmachine_test.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/rqd/tests/rqmachine_test.py b/rqd/tests/rqmachine_test.py index 0cd670c27..7198d0501 100644 --- a/rqd/tests/rqmachine_test.py +++ b/rqd/tests/rqmachine_test.py @@ -645,7 +645,7 @@ def test_reserveHybridHT(self): # - process_id 22 # - E core_id 39 # - process_id 23 - tasksets0 = self.machine.reserveHT(400) + tasksets0 = self.machine.reserveCores(400, logical=True) # should reserve 2P (0,1, 2,3) # pylint: disable=no-member @@ -659,7 +659,7 @@ def test_reserveHybridHT(self): # ------------------------step2------------------------- - tasksets1 = self.machine.reserveHT(500) + tasksets1 = self.machine.reserveCores(500, logical=True) # should reserve 2P + 1E (4,5, 6,7, 16) # pylint: disable=no-member @@ -675,7 +675,7 @@ def test_reserveHybridHT(self): # ------------------------step3------------------------- - tasksets2 = self.machine.reserveHT(600) + tasksets2 = self.machine.reserveCores(600, logical=True) # should reserve 3P (8,9, 10,11, 12,13) # pylint: disable=no-member @@ -705,7 +705,7 @@ def test_reserveHybridHT(self): # ------------------------step5------------------------- - tasksets3 = self.machine.reserveHT(1200) + tasksets3 = self.machine.reserveCores(1200, logical=True) # should reserve 3P + 6E (0,1, 2,3, 14,15, 17, 18, 19, 20, 21, 22) # pylint: disable=no-member @@ -724,7 +724,7 @@ def test_reserveHybridHT(self): 23) # ------------------------step6------------------------- - tasksets4 = self.machine.reserveHT(100) + tasksets4 = self.machine.reserveCores(100, logical=True) # should reserve 1E (23) # pylint: disable=no-member @@ -740,7 +740,7 @@ def test_reserveHybridHT(self): # ------------------------step7------------------------- # No cores available with self.assertRaises(rqd.rqexceptions.CoreReservationFailureException): - self.machine.reserveHT(100) + self.machine.reserveCores(100, logical=True) def test_tags(self): tags = ["test1", "test2", "test3"] From f27aed767325050f75dd6febc7ad08b6fb1fcd87 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Fri, 18 Apr 2025 18:07:21 +0200 Subject: [PATCH 26/78] fix: removed ghost log --- rqd/rqd/rqmachine.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 24a6cdb44..dae1199fe 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -933,8 +933,7 @@ def reserveCores(self, coresCount=0, logical=True): if coresCount % 100: log.warning('Taskset: Can not reserveHT with fractional cores') return None - log.warning('Taskset: Requesting reserve of %d', (coresCount // 100)) - log.info('Taskset: Requesting reserve of %d', (frameCores // 100)) + log.info('Taskset: Requesting reserve of %d', (coresCount // 100)) # Look for the most idle physical cpu. # Prefer to assign cores from the same physical cpu. From 705ed07f831d2162f4c67243f3ca370c55257ffd Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Fri, 18 Apr 2025 18:23:34 +0200 Subject: [PATCH 27/78] fix: call forgot self when calling self.reserveCores() --- rqd/rqd/rqmachine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index dae1199fe..56c816a2e 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -1018,7 +1018,7 @@ def reserveHT(self, frameCores): DeprecationWarning, stacklevel=2 ) - return reserveCores(frameCores, logical=False) + return self.reserveCores(frameCores, logical=False) # pylint: disable=inconsistent-return-statements def releaseHT(self, reservedHT): From 0bd2f53924a2d3b3e81bb34c0471910cbcfdf59b Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Fri, 18 Apr 2025 23:42:49 +0200 Subject: [PATCH 28/78] chore: lint test fail, line too long. --- rqd/rqd/rqcore.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rqd/rqd/rqcore.py b/rqd/rqd/rqcore.py index e16c7dbd2..0886e3418 100644 --- a/rqd/rqd/rqcore.py +++ b/rqd/rqd/rqcore.py @@ -424,7 +424,9 @@ def launchFrame(self, runFrame): # pylint: enable=no-member if runFrame.environment.get('CUE_THREADABLE') == '1': - cpu_list = self.machine.reserveCores(coresCount=runFrame.num_cores, logical=runFrame.use_threads) + cpu_list = self.machine.reserveCores( + coresCount=runFrame.num_cores, + logical=runFrame.use_threads) if cpu_list: runFrame.attributes['CPU_LIST'] = cpu_list From 48cc64e85612b35d5ec4e245205b97370c1824c1 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Fri, 18 Apr 2025 23:54:15 +0200 Subject: [PATCH 29/78] feat: Added rqwinutils, specific calls to Windows dll in order to get the structure of the CPU(s) in the system. I dug into psutils and couldn't get the proper mapping for hybrid CPUs. It just gives you the number of logical and physical cores, but it doesn't tell you the real structure (how many logical core(s) each physical core has). This is also very fast compared to the current use of WMI. --- rqd/rqd/rqwinutils.py | 129 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 rqd/rqd/rqwinutils.py diff --git a/rqd/rqd/rqwinutils.py b/rqd/rqd/rqwinutils.py new file mode 100644 index 000000000..06aecf97c --- /dev/null +++ b/rqd/rqd/rqwinutils.py @@ -0,0 +1,129 @@ +""" +This module provides functionality to retrieve and display information about the logical processors in a Windows system. +It uses Windows API calls to gather details about processor groups, their affinities, and the number of logical cores. +Classes: + GROUP_AFFINITY (Structure): Represents the affinity of a group of processors. + PROCESSOR_RELATIONSHIP (Structure): Represents information about affinity within a processor group. + DUMMYUNIONNAME (Union): A union of possible information to get about a processor. + SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX (Structure): Contains information about the relationships of logical processors and related hardware. +Functions: + get_logical_processor_information_ex(): Retrieves information about all the logical processors in the system. + +Note: + This is tailored for the needs of OpenCue, especially for hybrid CPUs + TODO: Maybe we should contribute this back to psutils ? +""" +from ctypes import c_size_t, c_ulonglong, c_int, Structure, Union, WinDLL +from ctypes import POINTER, sizeof, WinError, byref, get_last_error +from ctypes import wintypes + +# pylint: disable=line-too-long + +class GROUP_AFFINITY(Structure): + """ A structure that represents the affinity of a group of processors. + Attributes: + Mask (c_ulonglong): A bitmask that specifies the affinity of processors in the group. + Group (wintypes.WORD): The processor group number. + Reference: + https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-group_affinity + """ + _fields_ = [("Mask", c_ulonglong), + ("Group", wintypes.WORD), + ("Reserved", wintypes.WORD * 3)] + + +class PROCESSOR_RELATIONSHIP(Structure): + """ Represents information about affinity within a processor group. + Attributes: + Flags (BYTE): Flags that provide additional information about the processor. + EfficiencyClass (BYTE): The efficiency class of the processor. + GroupCount (WORD): The number of processor groups. + GroupMask (GROUP_AFFINITY * 1): The affinity mask for the processor group. + Reference: + - https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-processor_relationship + """ + _fields_ = [("Flags", wintypes.BYTE), + ("EfficiencyClass", wintypes.BYTE), + ("Reserved", wintypes.BYTE * 20), + ("GroupCount", wintypes.WORD), + ("GroupMask", GROUP_AFFINITY * 1)] + + +class DUMMYUNIONNAME(Union): + """ A union of possible information to get about a processor. + Here we only get the processor relationship. + Attributes: + Processor (PROCESSOR_RELATIONSHIP): Represents the processor relationship. + Reference: + - https://learn.microsoft.com/fr-fr/windows/win32/api/winnt/ns-winnt-system_logical_processor_information_ex + """ + _fields_ = [("Processor", PROCESSOR_RELATIONSHIP)] + + +class SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX(Structure): + """ Contains information about the relationships of logical processors and related hardware. + Attributes: + Relationship: The type of relationship between the logical processors. + Size: The size of the structure. + DUMMYUNIONNAME: see the class doc. + Reference: + - https://learn.microsoft.com/fr-fr/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlogicalprocessorinformationex + """ + _fields_ = [("Relationship", wintypes.DWORD), + ("Size", wintypes.DWORD), + ("DUMMYUNIONNAME", DUMMYUNIONNAME)] + + +def get_logical_processor_information_ex(): + """ Retrieves information about all the logical processors in the system. + Usage: + Used in rqmachine.Machine.__initStatsWindows() + Returns: + List of tuples for each thread (logical core): + - group (int): Its processor group ID. (we can't detect different CPUS directly) + - core_id (int): Its physical core ID. + - thread_id (int): Its logical core ID. + Raises: + WinError: If there is an error in retrieving the processor information. + References: + https://learn.microsoft.com/fr-fr/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlogicalprocessorinformationex + """ + + kernel32 = WinDLL('kernel32', use_last_error=True) + GetLogicalProcessorInformationEx = kernel32.GetLogicalProcessorInformationEx + GetLogicalProcessorInformationEx.argtypes = [wintypes.DWORD, + POINTER(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX), + POINTER(wintypes.DWORD)] + GetLogicalProcessorInformationEx.restype = wintypes.BOOL + + RelationProcessorCore = 0 # RelationProcessorCore constant + ERROR_INSUFFICIENT_BUFFER = 122 + + # Get required buffer size by calling the function with a null buffer + buffer_size = wintypes.DWORD(0) + if not GetLogicalProcessorInformationEx(RelationProcessorCore, None, byref(buffer_size)): + if get_last_error() != ERROR_INSUFFICIENT_BUFFER: + raise WinError(get_last_error()) + + # Get information about all the logical processors + buffer = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX * ( + buffer_size.value // sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)))() + if not GetLogicalProcessorInformationEx(RelationProcessorCore, buffer, byref(buffer_size)): + raise WinError(get_last_error()) + + # Extract information + cores_info = [] + core_id = 0 + _thread_id_inc = 0 + for item in buffer: + if item.Relationship == RelationProcessorCore: + mask = item.DUMMYUNIONNAME.Processor.GroupMask[0].Mask + group = item.DUMMYUNIONNAME.Processor.GroupMask[0].Group + logical_cores = bin(mask).count('1') + thread_ids = [_thread_id_inc + i for i in range(logical_cores)] + for thread_id in thread_ids: + cores_info.append((group, core_id, thread_id)) + _thread_id_inc += logical_cores + core_id += 1 + + return cores_info From 9c3f9bb5d63d58507075014df47d9fcb848b5261 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Mon, 21 Apr 2025 05:25:39 +0200 Subject: [PATCH 30/78] refacto: renamed cpuInfo test file for hybrid i9-12900 relying on true values --- ...ybrid_ht_24-24-1-1 => _cpuinfo_i9_12900_hybrid_ht_24-16-1.5-1} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename rqd/tests/cpuinfo/{_cpuinfo_i9_12900_hybrid_ht_24-24-1-1 => _cpuinfo_i9_12900_hybrid_ht_24-16-1.5-1} (100%) diff --git a/rqd/tests/cpuinfo/_cpuinfo_i9_12900_hybrid_ht_24-24-1-1 b/rqd/tests/cpuinfo/_cpuinfo_i9_12900_hybrid_ht_24-16-1.5-1 similarity index 100% rename from rqd/tests/cpuinfo/_cpuinfo_i9_12900_hybrid_ht_24-24-1-1 rename to rqd/tests/cpuinfo/_cpuinfo_i9_12900_hybrid_ht_24-16-1.5-1 From 90c506e21518bb416348df53a8921d136480c5de Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Mon, 21 Apr 2025 05:31:04 +0200 Subject: [PATCH 31/78] fix: get boot time for all OS with psutil --- rqd/rqd/rqmachine.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 56c816a2e..aa1dfefd2 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -459,12 +459,7 @@ def getLoadAvg(self): @rqd.rqutil.Memoize def getBootTime(self): """Returns epoch when the system last booted""" - if platform.system() == "Linux": - with open(rqd.rqconstants.PATH_STAT, "r", encoding='utf-8') as statFile: - for line in statFile: - if line.startswith("btime"): - return int(line.split()[1]) - return 0 + return int(psutil.boot_time()) @rqd.rqutil.Memoize def getGpuCount(self): From cc4460818937d945c45f75aba58cf61de67eefe5 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Mon, 21 Apr 2025 05:34:10 +0200 Subject: [PATCH 32/78] refacto: renamed variable to be closer to what the code does. --- rqd/rqd/rqmachine.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index aa1dfefd2..e53e3cc1a 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -85,11 +85,11 @@ def __init__(self, rqCore, coreInfo): # A dictionary built from /proc/cpuinfo containing # { : { : set([, , ...]), ... }, ... } - self.__procs_by_physid_and_coreid = {} + self.__threadid_by_cpuid_and_coreid = {} # A reverse mapping of the above. # { : (, ), ... } - self.__physid_and_coreid_by_proc = {} + self.__cpuid_and_coreid_by_threadid = {} if platform.system() == 'Linux': self.__vmstat = rqd.rqswap.VmStat() @@ -937,7 +937,7 @@ def reserveCores(self, coresCount=0, logical=True): avail_procs_count = 0 reserved_cores = self.__coreInfo.reserved_cores - for physid, cores in self.__procs_by_physid_and_coreid.items(): + for physid, cores in self.__threadid_by_cpuid_and_coreid.items(): for coreid in cores.keys(): if int(physid) in reserved_cores and \ int(coreid) in reserved_cores[int(physid)].coreid: @@ -978,10 +978,10 @@ def reserveCores(self, coresCount=0, logical=True): # if we didn't find a core with the right number of threads, and continue the loop. coreid = next(iter( [cid for cid in cores - if len(self.__procs_by_physid_and_coreid[physid][cid]) <= query_procs]), + if len(self.__threadid_by_cpuid_and_coreid[physid][cid]) <= query_procs]), cores[0]) cores.remove(coreid) - procids = self.__procs_by_physid_and_coreid[physid][coreid] + procids = self.__threadid_by_cpuid_and_coreid[physid][coreid] reserved_cores[int(physid)].coreid.extend([int(coreid)]) if logical: query_procs -= len(procids) @@ -1031,7 +1031,7 @@ def releaseHT(self, reservedHT): # aren't valid core identities. reserved_cores = self.__coreInfo.reserved_cores for core in reservedHT.split(','): - physical_id_str, core_id_str = self.__physid_and_coreid_by_proc.get(core) + physical_id_str, core_id_str = self.__cpuid_and_coreid_by_threadid.get(core) physical_id = int(physical_id_str) core_id = int(core_id_str) From 635608b8456a7574999bc178da23bde0dfb8b755 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Mon, 21 Apr 2025 05:38:25 +0200 Subject: [PATCH 33/78] refacto: made ht multiplier a float for hybrid systems. --- rqd/rqd/rqmachine.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index e53e3cc1a..6143b157b 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -449,11 +449,16 @@ def getLoadAvg(self): if platform.system() == "Linux": with open(rqd.rqconstants.PATH_LOADAVG, "r", encoding='utf-8') as loadAvgFile: loadAvg = int(float(loadAvgFile.read().split()[0]) * 100) - if self.__enabledHT(): - loadAvg = loadAvg // self.getHyperthreadingMultiplier() + loadAvg = loadAvg // self.getHyperthreadingMultiplier() loadAvg = loadAvg + rqd.rqconstants.LOAD_MODIFIER loadAvg = max(loadAvg, 0) return loadAvg + elif platform.system() == "Windows": + # Use psutil to get the CPU utilization over 1 second + # This is not the same as load average, but it gives a + # similar idea of CPU load. + load_avg = psutil.cpu_percent(interval=1) + return int(load_avg * 100) return 0 @rqd.rqutil.Memoize @@ -899,10 +904,10 @@ def __enabledHT(self): def getHyperthreadingMultiplier(self): """ - Multiplied used to compute the number of threads that can be allocated simultaneously - on a core + Multiplier used to compute the number of threads that can be allocated simultaneously + on a core. This is a float as it can be fractional for hybrid cores. """ - return int(self.__renderHost.attributes['hyperthreadingMultiplier']) + return float(self.__renderHost.attributes['hyperthreadingMultiplier']) def setupTaskset(self): """ Setup rqd for hyper-threading """ From 62f4cc712a8a01d139c8e42cfa65cc7a9040ec79 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Mon, 21 Apr 2025 05:42:38 +0200 Subject: [PATCH 34/78] refacto: functions to gather machine information was split and extracted from their main methods. Replaced WMI usage by direct DLL access to get Windows CPU structure information. --- rqd/rqd/rqmachine.py | 266 +++++++++++++++---------------------------- 1 file changed, 91 insertions(+), 175 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 6143b157b..57117567f 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -608,192 +608,136 @@ def testInitMachineStats(self, pathCpuInfo): return self.__renderHost, self.__coreInfo def __initMachineStats(self, pathCpuInfo=None): - """Updates static machine information during initialization""" + """Updates static machine information during initialization + + @type pathCpuInfo: str + @param pathCpuInfo: Path to a specific cpuinfo file + """ self.__renderHost.name = self.getHostname() self.__renderHost.boot_time = self.getBootTime() self.__renderHost.facility = rqd.rqconstants.DEFAULT_FACILITY self.__renderHost.attributes['SP_OS'] = rqd.rqconstants.SP_OS + # Get the total memory and swap self.updateMachineStats() - __numProcs = __totalCores = 0 - if platform.system() == "Linux" or pathCpuInfo is not None: - # Reads static information for mcp - mcpStat = os.statvfs(self.getTempPath()) - self.__renderHost.total_mcp = mcpStat.f_blocks * mcpStat.f_frsize // KILOBYTE - - # Reset mappings - self.__procs_by_physid_and_coreid = {} - self.__physid_and_coreid_by_proc = {} - - # Reads static information from /proc/cpuinfo - with open(pathCpuInfo or rqd.rqconstants.PATH_CPUINFO, "r", - encoding='utf-8') as cpuinfoFile: - currCore = {} - procsFound = [] - for line in cpuinfoFile: - lineList = line.strip().replace("\t", "").split(": ") - # A normal entry added to the singleCore dictionary - if len(lineList) >= 2: - currCore[lineList[0]] = lineList[1] - # The end of a processor block - elif lineList == ['']: - # Check for hyper-threading - hyperthreadingMultiplier = (int(currCore.get('siblings', '1')) - // int(currCore.get('cpu cores', '1'))) - - __totalCores += rqd.rqconstants.CORE_VALUE - if "core id" in currCore \ - and "physical id" in currCore \ - and not currCore["physical id"] in procsFound: - procsFound.append(currCore["physical id"]) - __numProcs += 1 - elif "core id" not in currCore: - __numProcs += 1 - - if 'physical id' in currCore and 'core id' in currCore: - # Keep track of what processors are on which core on - # which physical socket. - procid, physid, coreid = ( - currCore['processor'], - currCore['physical id'], - currCore['core id']) - self.__procs_by_physid_and_coreid \ - .setdefault(physid, {}) \ - .setdefault(coreid, set()).add(procid) - self.__physid_and_coreid_by_proc[procid] = physid, coreid - currCore = {} - - # An entry without data - elif len(lineList) == 1: - currCore[lineList[0]] = "" - - # Reads information from /proc/meminfo - with codecs.open(rqd.rqconstants.PATH_MEMINFO, "r", encoding="utf-8") as fp: - for line in fp: - if line.startswith("MemTotal"): - self.__renderHost.total_mem = int(line.split()[1]) - elif line.startswith("SwapTotal"): - self.__renderHost.total_swap = int(line.split()[1]) - else: - hyperthreadingMultiplier = 1 + cpu_count = core_count = thread_count = 0 - if platform.system() == 'Windows': - logicalCoreCount, __numProcs, hyperthreadingMultiplier = self.__initStatsFromWindows() - __totalCores = logicalCoreCount * rqd.rqconstants.CORE_VALUE + if platform.system() == "Linux" or pathCpuInfo is not None: + cpu_count, core_count, thread_count = self.__initStatsLinux(pathCpuInfo) + elif platform.system() == 'Windows': + cpu_count, core_count, thread_count = self.__initStatsWindows() # All other systems will just have one proc/core - if not __numProcs or not __totalCores: - __numProcs = 1 - __totalCores = rqd.rqconstants.CORE_VALUE + if not cpu_count or not core_count: + cpu_count = 1 + thread_count = 1 + core_count = 1 + # Override values from rqd.conf if rqd.rqconstants.OVERRIDE_MEMORY is not None: log.warning("Manually overriding the total memory") self.__renderHost.total_mem = rqd.rqconstants.OVERRIDE_MEMORY if rqd.rqconstants.OVERRIDE_CORES is not None: log.warning("Manually overriding the number of reported cores") - __totalCores = rqd.rqconstants.OVERRIDE_CORES * rqd.rqconstants.CORE_VALUE + core_count = rqd.rqconstants.OVERRIDE_CORES * rqd.rqconstants.CORE_VALUE + if rqd.rqconstants.OVERRIDE_THREADS is None: + thread_count = core_count + if rqd.rqconstants.OVERRIDE_THREADS is not None: + log.warning("Manually overriding the number of reported threads") + thread_count = rqd.rqconstants.OVERRIDE_THREADS * rqd.rqconstants.CORE_VALUE if rqd.rqconstants.OVERRIDE_PROCS is not None: log.warning("Manually overriding the number of reported procs") - __numProcs = rqd.rqconstants.OVERRIDE_PROCS - - # Don't report/reserve cores added due to hyperthreading - __totalCores = __totalCores // hyperthreadingMultiplier + cpu_count = rqd.rqconstants.OVERRIDE_PROCS - self.__coreInfo.idle_cores = __totalCores - self.__coreInfo.total_cores = __totalCores - self.__renderHost.num_procs = __numProcs - self.__renderHost.cores_per_proc = __totalCores // __numProcs + self.__coreInfo.idle_cores = core_count * rqd.rqconstants.CORE_VALUE + self.__coreInfo.total_cores = core_count * rqd.rqconstants.CORE_VALUE + self.__coreInfo.total_threads = thread_count * rqd.rqconstants.CORE_VALUE + self.__renderHost.num_procs = cpu_count + self.__renderHost.cores_per_proc = core_count * rqd.rqconstants.CORE_VALUE // cpu_count + self.__renderHost.threads_per_proc = thread_count * rqd.rqconstants.CORE_VALUE // cpu_count + hyperthreadingMultiplier = thread_count / core_count if hyperthreadingMultiplier >= 1: self.__renderHost.attributes['hyperthreadingMultiplier'] = str(hyperthreadingMultiplier) - def __initStatsFromWindows(self): + def __initStatsWindows(self): """Init machine stats for Windows platforms. @rtype: tuple @return: A 3-items tuple containing: + - the number of physical CPU + - the number of physical cores - the number of logical cores - the number of physical processors - the hyper-threading multiplier """ - # Windows memory information - stat = self.getWindowsMemory() - TEMP_DEFAULT = 1048576 - self.__renderHost.total_mcp = TEMP_DEFAULT - self.__renderHost.total_mem = int(stat.ullTotalPhys / 1024) - self.__renderHost.total_swap = int(stat.ullTotalPageFile / 1024) + import rqd.rqwinutils # Windows-specific # Windows CPU information - self.__updateProcsMappingsFromWindows() + coreInfo = rqd.rqwinutils.get_logical_processor_information_ex() + self.__updateProcsMappings(coreInfo=coreInfo) + processorCount = len(self.__threadid_by_cpuid_and_coreid) + physicalCoreCount = psutil.cpu_count(logical=False) logicalCoreCount = psutil.cpu_count(logical=True) - actualCoreCount = psutil.cpu_count(logical=False) - hyperThreadingMultiplier = logicalCoreCount // actualCoreCount - physicalProcessorCount = len(self.__procs_by_physid_and_coreid) + return processorCount, physicalCoreCount, logicalCoreCount - return logicalCoreCount, physicalProcessorCount, hyperThreadingMultiplier + def updateWindowsMemory(self): + """Updates the internal store of memory available for Windows.""" + import rqd.rqwinutils # Windows-specific - def __updateProcsMappingsFromWindows(self): - """ - Update `__procs_by_physid_and_coreid` and `__physid_and_coreid_by_proc` mappings - for Windows platforms. - """ - # Windows-specific - import wmi # pylint:disable=import-outside-toplevel,import-error - - # Reset mappings - self.__procs_by_physid_and_coreid = {} - self.__physid_and_coreid_by_proc = {} - - # Connect to the Windows Management Instrumentation (WMI) interface - wmiInstance = wmi.WMI() - - # Retrieve CPU information using WMI - for physicalId, processor in enumerate(wmiInstance.Win32_Processor()): - - threadPerCore = processor.NumberOfLogicalProcessors // processor.NumberOfCores - procId = 0 - - for coreId in range(processor.NumberOfCores): - for _ in range(threadPerCore): - self.__procs_by_physid_and_coreid.setdefault( - str(physicalId), {} - ).setdefault(str(coreId), set()).add(str(procId)) - self.__physid_and_coreid_by_proc[str(procId)] = ( - str(physicalId), - str(coreId), - ) - procId += 1 - - def getWindowsMemory(self): - """Gets information on system memory, Windows compatible version.""" - # From - # http://stackoverflow.com/questions/2017545/get-memory-usage-of-computer-in-windows-with-python if not hasattr(self, '__windowsStat'): - class MEMORYSTATUSEX(ctypes.Structure): - """Represents Windows memory information.""" - _fields_ = [("dwLength", ctypes.c_uint), - ("dwMemoryLoad", ctypes.c_uint), - ("ullTotalPhys", ctypes.c_ulonglong), - ("ullAvailPhys", ctypes.c_ulonglong), - ("ullTotalPageFile", ctypes.c_ulonglong), - ("ullAvailPageFile", ctypes.c_ulonglong), - ("ullTotalVirtual", ctypes.c_ulonglong), - ("ullAvailVirtual", ctypes.c_ulonglong), - ("sullAvailExtendedVirtual", ctypes.c_ulonglong),] - - def __init__(self): - # have to initialize this to the size of MEMORYSTATUSEX - self.dwLength = 2*4 + 7*8 # size = 2 ints, 7 longs - super(MEMORYSTATUSEX, self).__init__() - - self.__windowsStat = MEMORYSTATUSEX() + self.__windowsStat = rqd.rqwinutils.MEMORYSTATUSEX() ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(self.__windowsStat)) - return self.__windowsStat + + stat = self.__windowsStat + temp_path = os.getenv('TEMP') # Windows temp directory + disk_usage = psutil.disk_usage(temp_path) + + self.__renderHost.total_mcp = disk_usage.total // 1024 + self.__renderHost.free_mcp = disk_usage.free // 1024 + + self.__renderHost.total_mem = int(stat.ullTotalPhys / 1024) + self.__renderHost.free_mem = int(stat.ullAvailPhys / 1024) + + self.__renderHost.total_swap = int(stat.ullTotalPageFile / 1024) + self.__renderHost.free_swap = int(stat.ullAvailPageFile / 1024) + + self.__renderHost.num_gpus = self.getGpuCount() + self.__renderHost.total_gpu_mem = self.getGpuMemoryTotal() + self.__renderHost.free_gpu_mem = self.getGpuMemoryFree() + + def updateLinuxMemory(self): + """Gets information on system memory for Linux.""" + # Reads dynamic information for mcp + mcpStat = os.statvfs(self.getTempPath()) + self.__renderHost.free_mcp = (mcpStat.f_bavail * mcpStat.f_bsize) // KILOBYTE + + # Reads dynamic information from /proc/meminfo + with open(rqd.rqconstants.PATH_MEMINFO, "r", encoding='utf-8') as fp: + for line in fp: + if line.startswith("MemFree"): + freeMem = int(line.split()[1]) + elif line.startswith("SwapFree"): + freeSwapMem = int(line.split()[1]) + elif line.startswith("SwapTotal"): + self.__renderHost.total_swap = int(line.split()[1]) + elif line.startswith("Cached"): + cachedMem = int(line.split()[1]) + elif line.startswith("MemTotal"): + self.__renderHost.total_mem = int(line.split()[1]) + + self.__renderHost.free_swap = freeSwapMem + self.__renderHost.free_mem = freeMem + cachedMem + self.__renderHost.num_gpus = self.getGpuCount() + self.__renderHost.total_gpu_mem = self.getGpuMemoryTotal() + self.__renderHost.free_gpu_mem = self.getGpuMemoryFree() + + self.__renderHost.attributes['swapout'] = self.__getSwapout() def updateMacMemory(self): """Updates the internal store of memory available, macOS compatible version.""" @@ -827,43 +771,15 @@ def updateMacMemory(self): def updateMachineStats(self): """Updates dynamic machine information during runtime""" + if platform.system() == "Linux": - # Reads dynamic information for mcp - mcpStat = os.statvfs(self.getTempPath()) - self.__renderHost.free_mcp = (mcpStat.f_bavail * mcpStat.f_bsize) // KILOBYTE - - # Reads dynamic information from /proc/meminfo - with open(rqd.rqconstants.PATH_MEMINFO, "r", encoding='utf-8') as fp: - for line in fp: - if line.startswith("MemFree"): - freeMem = int(line.split()[1]) - elif line.startswith("SwapFree"): - freeSwapMem = int(line.split()[1]) - elif line.startswith("Cached"): - cachedMem = int(line.split()[1]) - elif line.startswith("MemTotal"): - self.__renderHost.total_mem = int(line.split()[1]) - - self.__renderHost.free_swap = freeSwapMem - self.__renderHost.free_mem = freeMem + cachedMem - self.__renderHost.num_gpus = self.getGpuCount() - self.__renderHost.total_gpu_mem = self.getGpuMemoryTotal() - self.__renderHost.free_gpu_mem = self.getGpuMemoryFree() - - self.__renderHost.attributes['swapout'] = self.__getSwapout() + self.updateLinuxMemory() elif platform.system() == 'Darwin': self.updateMacMemory() elif platform.system() == 'Windows': - TEMP_DEFAULT = 1048576 - stats = self.getWindowsMemory() - self.__renderHost.free_mcp = TEMP_DEFAULT - self.__renderHost.free_swap = int(stats.ullAvailPageFile / 1024) - self.__renderHost.free_mem = int(stats.ullAvailPhys / 1024) - self.__renderHost.num_gpus = self.getGpuCount() - self.__renderHost.total_gpu_mem = self.getGpuMemoryTotal() - self.__renderHost.free_gpu_mem = self.getGpuMemoryFree() + self.updateWindowsMemory() # Updates dynamic information self.__renderHost.load = self.getLoadAvg() From 6ef848fa1460af484dad305df20d59ca73aa7960 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Mon, 21 Apr 2025 05:42:48 +0200 Subject: [PATCH 35/78] doc: update --- rqd/rqd/rqmachine.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 57117567f..2ad24ce0a 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -671,8 +671,6 @@ def __initStatsWindows(self): - the number of physical CPU - the number of physical cores - the number of logical cores - - the number of physical processors - - the hyper-threading multiplier """ import rqd.rqwinutils # Windows-specific From 380a82efc4e9a826c9ab3e189b1503df4593680b Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Mon, 21 Apr 2025 05:43:22 +0200 Subject: [PATCH 36/78] feat: added OVERRIDE_THREADS constant --- rqd/rqd/__main__.py | 1 + rqd/rqd/rqconstants.py | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/rqd/rqd/__main__.py b/rqd/rqd/__main__.py index e068a2284..80ad5df80 100755 --- a/rqd/rqd/__main__.py +++ b/rqd/rqd/__main__.py @@ -31,6 +31,7 @@ In /etc/opencue/rqd.conf (on Linux) or %LOCALAPPDATA%/OpenCue/rqd.conf (on Windows): [Override] OVERRIDE_CORES = 2 +OVERRIDE_THREADS = 4 OVERRIDE_PROCS = 3 OVERRIDE_MEMORY = 1000000 OVERRIDE_CUEBOT = cuebot1 cuebot2 cuebot3 diff --git a/rqd/rqd/rqconstants.py b/rqd/rqd/rqconstants.py index 1a90d8570..129c66b5c 100644 --- a/rqd/rqd/rqconstants.py +++ b/rqd/rqd/rqconstants.py @@ -150,6 +150,7 @@ CONFIG_FILE = sys.argv[sys.argv.index('-c') + 1] OVERRIDE_CORES = None # number of cores. ex: None or 8 +OVERRIDE_THREADS = None # number of threads. ex: None or 16 OVERRIDE_IS_DESKTOP = None # Force rqd to run in 'desktop' mode OVERRIDE_PROCS = None # number of physical cpus. ex: None or 2 OVERRIDE_MEMORY = None # in Kb @@ -157,7 +158,7 @@ USE_NIMBY_PYNPUT = True # True pynput, False select OVERRIDE_HOSTNAME = None # Force to use this hostname ALLOW_GPU = False -LOAD_MODIFIER = 0 # amount to add/subtract from load +LOAD_MODIFIER = 0 # amount to add/subtract from load, LOG_FORMAT = '%(levelname)-9s openrqd-%(module)-10s: %(message)s' CONSOLE_LOG_LEVEL = logging.WARNING @@ -204,6 +205,8 @@ CUEBOT_GRPC_PORT = config.getint(__override_section, "CUEBOT_GRPC_PORT") if config.has_option(__override_section, "OVERRIDE_CORES"): OVERRIDE_CORES = config.getint(__override_section, "OVERRIDE_CORES") + if config.has_option(__override_section, "OVERRIDE_THREADS"): + OVERRIDE_THREADS = config.getint(__override_section, "OVERRIDE_THREADS") if config.has_option(__override_section, "OVERRIDE_PROCS"): OVERRIDE_PROCS = config.getint(__override_section, "OVERRIDE_PROCS") if config.has_option(__override_section, "OVERRIDE_MEMORY"): @@ -231,7 +234,7 @@ RQD_USE_PATH_ENV_VAR = config.getboolean(__override_section, "RQD_USE_PATH_ENV_VAR") if config.has_option(__override_section, "RQD_USE_ALL_HOST_ENV_VARS"): RQD_USE_HOST_ENV_VARS = config.getboolean(__override_section, - "RQD_USE_ALL_HOST_ENV_VARS") + "RQD_USE_ALL_HOST_ENV_VARS") if config.has_option(__override_section, "RQD_BECOME_JOB_USER"): RQD_BECOME_JOB_USER = config.getboolean(__override_section, "RQD_BECOME_JOB_USER") if config.has_option(__override_section, "RQD_TAGS"): From 7f4a34c1ef9f21358003affc699ce64bd6ec91f2 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Mon, 21 Apr 2025 05:44:46 +0200 Subject: [PATCH 37/78] test: fixed test to use floats for ht multiplier. --- rqd/tests/rqmachine_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rqd/tests/rqmachine_test.py b/rqd/tests/rqmachine_test.py index 7198d0501..be0257005 100644 --- a/rqd/tests/rqmachine_test.py +++ b/rqd/tests/rqmachine_test.py @@ -813,7 +813,7 @@ def __cpuinfoTestHelper(self, pathCpuInfo): self.assertEqual(coreInfo.booked_cores, 0) if '_ht_' in pathCpuInfo: self.assertEqual( - renderHost.attributes['hyperthreadingMultiplier'], pathCpuInfo.split('-')[3]) + float(renderHost.attributes['hyperthreadingMultiplier']), float(pathCpuInfo.split('-'))[3]) if __name__ == '__main__': From 23b0ab78528e7a9a8e41572592431c6632cf6e90 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Mon, 21 Apr 2025 05:53:40 +0200 Subject: [PATCH 38/78] fix: revert code --- rqd/rqd/rqmachine.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 2ad24ce0a..13d465615 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -449,7 +449,8 @@ def getLoadAvg(self): if platform.system() == "Linux": with open(rqd.rqconstants.PATH_LOADAVG, "r", encoding='utf-8') as loadAvgFile: loadAvg = int(float(loadAvgFile.read().split()[0]) * 100) - loadAvg = loadAvg // self.getHyperthreadingMultiplier() + if self.__enabledHT(): + loadAvg = loadAvg // self.getHyperthreadingMultiplier() loadAvg = loadAvg + rqd.rqconstants.LOAD_MODIFIER loadAvg = max(loadAvg, 0) return loadAvg From 5afd53c39c16c42fdf083b00e1755a1b961399da Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Mon, 21 Apr 2025 06:41:29 +0200 Subject: [PATCH 39/78] fix: get batck __updateProcsMappings and __initStatsLinux --- rqd/rqd/rqmachine.py | 65 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 13d465615..8db561237 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -664,6 +664,39 @@ def __initMachineStats(self, pathCpuInfo=None): if hyperthreadingMultiplier >= 1: self.__renderHost.attributes['hyperthreadingMultiplier'] = str(hyperthreadingMultiplier) + def __initStatsLinux(self, pathCpuInfo=None): + """Init machine stats for Linux platforms. + + @type pathCpuInfo: str + @param pathCpuInfo: Path to a specific cpuinfo file + """ + coreInfo = [] + _count = {"cpus": set(), "cores": set(), "threads": set()} + # Reads static information from /proc/cpuinfo + with (open(pathCpuInfo or rqd.rqconstants.PATH_CPUINFO, "r", + encoding='utf-8') as cpuinfoFile): + infoBlock = {} + for line in cpuinfoFile: + lineList = line.strip().replace("\t", "").split(": ") + # A normal entry added to the singleCore dictionary + if len(lineList) >= 2: + infoBlock[lineList[0]] = lineList[1] + # An entry without data + elif len(lineList) == 1: + infoBlock[lineList[0]] = "" + # The end of a processor block + elif lineList == ['']: + cpu_id = infoBlock['physical id'] + physical_core_id = infoBlock['core id'] + logical_core_id = infoBlock['processor'] + _count["cpus"].add(cpu_id) + _count["cores"].add(physical_core_id) + _count["threads"].add(logical_core_id) + coreInfo.append((cpu_id, physical_core_id, logical_core_id)) + infoBlock.clear() + + self.__updateProcsMappings(coreInfo=coreInfo) + def __initStatsWindows(self): """Init machine stats for Windows platforms. @@ -685,6 +718,38 @@ def __initStatsWindows(self): return processorCount, physicalCoreCount, logicalCoreCount + def __updateProcsMappings(self, coreInfo): + """ + Update `__threadid_by_cpuid_and_coreid` and `__cpuid_and_coreid_by_threadid` mappings. + + @type coreInfo: list[tuple[str, str, str]] + @param coreInfo: A list of tuples containing CPU ID, Physical Core ID, and Logical Core ID. + + Implementation detail: + One CPU has one or more physical cores, + and each physical core has one or more logical cores. + Some CPUs have hyper-threading, which means that each logical core is treated as + a separate core by the operating system, while being on the same physical core. + Hybrid CPUs have performance cores that are hyper-threaded, + and efficient cores that are mono-threaded. + On Windows, we can't detect each physical CPU, + so instead we use CPU groups (64 cores per group). + """ + + # Reset mappings + self.__threadid_by_cpuid_and_coreid = {} + self.__cpuid_and_coreid_by_threadid = {} + + for (cpu_id, physical_core_id, logical_core_id) in coreInfo: + log.debug(f"CPU ID: {cpu_id}, " + f"Physical core ID: {physical_core_id}, " + f"Logical core ID: {logical_core_id}") + + self.__threadid_by_cpuid_and_coreid.setdefault( + str(cpu_id), {}).setdefault( + physical_core_id, set()).add(str(logical_core_id)) + self.__cpuid_and_coreid_by_threadid[logical_core_id] = (str(cpu_id), str(physical_core_id)) + def updateWindowsMemory(self): """Updates the internal store of memory available for Windows.""" import rqd.rqwinutils # Windows-specific From 29b12fb428c33700a3ea89f3592d61f67af8dfe6 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Mon, 21 Apr 2025 15:29:11 +0200 Subject: [PATCH 40/78] fix: return values in __initStatsLinux() --- rqd/rqd/rqmachine.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 8db561237..d0d4d2fe5 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -697,6 +697,8 @@ def __initStatsLinux(self, pathCpuInfo=None): self.__updateProcsMappings(coreInfo=coreInfo) + return len(_count["cpus"]), len(_count["cores"]), len(_count["threads"]) + def __initStatsWindows(self): """Init machine stats for Windows platforms. From dd9f8bc152dba5b5ca04c4e45cc1130e9256d649 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Mon, 21 Apr 2025 15:32:20 +0200 Subject: [PATCH 41/78] chore: py lint disable=line-too-long + removed unused imports. --- rqd/rqd/rqwinutils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rqd/rqd/rqwinutils.py b/rqd/rqd/rqwinutils.py index 06aecf97c..eb13f1e69 100644 --- a/rqd/rqd/rqwinutils.py +++ b/rqd/rqd/rqwinutils.py @@ -1,3 +1,4 @@ +# pylint: disable=line-too-long """ This module provides functionality to retrieve and display information about the logical processors in a Windows system. It uses Windows API calls to gather details about processor groups, their affinities, and the number of logical cores. @@ -13,11 +14,10 @@ This is tailored for the needs of OpenCue, especially for hybrid CPUs TODO: Maybe we should contribute this back to psutils ? """ -from ctypes import c_size_t, c_ulonglong, c_int, Structure, Union, WinDLL +from ctypes import c_ulonglong, Structure, Union, WinDLL from ctypes import POINTER, sizeof, WinError, byref, get_last_error from ctypes import wintypes -# pylint: disable=line-too-long class GROUP_AFFINITY(Structure): """ A structure that represents the affinity of a group of processors. From 2abbd0df6a422f6dd7a912b5b16f49e9936233ae Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Mon, 21 Apr 2025 16:35:41 +0200 Subject: [PATCH 42/78] fix: point to correct spuinfo file for i9 12900 --- rqd/tests/rqmachine_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rqd/tests/rqmachine_test.py b/rqd/tests/rqmachine_test.py index be0257005..956ce9a22 100644 --- a/rqd/tests/rqmachine_test.py +++ b/rqd/tests/rqmachine_test.py @@ -596,7 +596,7 @@ def test_reserveHybridHT(self): """ cpuInfo = os.path.join(os.path.dirname(__file__), 'cpuinfo', - '_cpuinfo_i9_12900_hybrid_ht_24-24-1-1') + '_cpuinfo_i9_12900_hybrid_ht_24-16-1.5-1') self.fs.add_real_file(cpuInfo) self.machine.testInitMachineStats(cpuInfo) @@ -795,7 +795,7 @@ def test_srdsvr09(self): self.__cpuinfoTestHelper('_cpuinfo_srdsvr09_48-12-4') def test_i9_12900(self): - self.__cpuinfoTestHelper('_cpuinfo_i9_12900_hybrid_ht_24-24-1-1') + self.__cpuinfoTestHelper('_cpuinfo_i9_12900_hybrid_ht_24-16-1.5-1') def __cpuinfoTestHelper(self, pathCpuInfo): # File format: _cpuinfo_dub_x-x-x where x-x-x is totalCores-coresPerProc-numProcs From 90a34745fb9de9fda2b58608d54a73a85510e8a4 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Mon, 21 Apr 2025 16:39:04 +0200 Subject: [PATCH 43/78] fix: getLoadAvg() returns an int --- rqd/rqd/rqmachine.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index d0d4d2fe5..37974e5bf 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -453,13 +453,13 @@ def getLoadAvg(self): loadAvg = loadAvg // self.getHyperthreadingMultiplier() loadAvg = loadAvg + rqd.rqconstants.LOAD_MODIFIER loadAvg = max(loadAvg, 0) - return loadAvg + return int(loadAvg) elif platform.system() == "Windows": # Use psutil to get the CPU utilization over 1 second # This is not the same as load average, but it gives a # similar idea of CPU load. - load_avg = psutil.cpu_percent(interval=1) - return int(load_avg * 100) + loadAvg = psutil.cpu_percent(interval=1) + return int(loadAvg * 100) return 0 @rqd.rqutil.Memoize From 0a12e9b35376dc6414a87d75bac08e471b950dc9 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Tue, 22 Apr 2025 04:18:20 +0200 Subject: [PATCH 44/78] fix: the first digit represents the total number of threads not cores. The cpuinfo numbers represent totalThreads-coresPerProc-numProcs + hyperThreadingMultiplier (optional) --- ...rid_ht_24-16-1.5-1 => _cpuinfo_i9_12900_hybrid_ht_24-16-1-1.5} | 0 .../{_cpuinfo_shark_ht_8-4-2-2 => _cpuinfo_shark_ht_16-4-2-2} | 0 ...cpuinfo_srdsvr05_ht_12-6-2-2 => _cpuinfo_srdsvr05_ht_24-6-2-2} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename rqd/tests/cpuinfo/{_cpuinfo_i9_12900_hybrid_ht_24-16-1.5-1 => _cpuinfo_i9_12900_hybrid_ht_24-16-1-1.5} (100%) rename rqd/tests/cpuinfo/{_cpuinfo_shark_ht_8-4-2-2 => _cpuinfo_shark_ht_16-4-2-2} (100%) rename rqd/tests/cpuinfo/{_cpuinfo_srdsvr05_ht_12-6-2-2 => _cpuinfo_srdsvr05_ht_24-6-2-2} (100%) diff --git a/rqd/tests/cpuinfo/_cpuinfo_i9_12900_hybrid_ht_24-16-1.5-1 b/rqd/tests/cpuinfo/_cpuinfo_i9_12900_hybrid_ht_24-16-1-1.5 similarity index 100% rename from rqd/tests/cpuinfo/_cpuinfo_i9_12900_hybrid_ht_24-16-1.5-1 rename to rqd/tests/cpuinfo/_cpuinfo_i9_12900_hybrid_ht_24-16-1-1.5 diff --git a/rqd/tests/cpuinfo/_cpuinfo_shark_ht_8-4-2-2 b/rqd/tests/cpuinfo/_cpuinfo_shark_ht_16-4-2-2 similarity index 100% rename from rqd/tests/cpuinfo/_cpuinfo_shark_ht_8-4-2-2 rename to rqd/tests/cpuinfo/_cpuinfo_shark_ht_16-4-2-2 diff --git a/rqd/tests/cpuinfo/_cpuinfo_srdsvr05_ht_12-6-2-2 b/rqd/tests/cpuinfo/_cpuinfo_srdsvr05_ht_24-6-2-2 similarity index 100% rename from rqd/tests/cpuinfo/_cpuinfo_srdsvr05_ht_12-6-2-2 rename to rqd/tests/cpuinfo/_cpuinfo_srdsvr05_ht_24-6-2-2 From 2c488f84b86a7f1fe21081d13ae83ad5b1dfef9f Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Tue, 22 Apr 2025 04:19:12 +0200 Subject: [PATCH 45/78] doc: explicit description for override constants. --- rqd/rqd/rqconstants.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rqd/rqd/rqconstants.py b/rqd/rqd/rqconstants.py index 129c66b5c..c50174c3e 100644 --- a/rqd/rqd/rqconstants.py +++ b/rqd/rqd/rqconstants.py @@ -149,10 +149,10 @@ if '-c' in sys.argv: CONFIG_FILE = sys.argv[sys.argv.index('-c') + 1] -OVERRIDE_CORES = None # number of cores. ex: None or 8 -OVERRIDE_THREADS = None # number of threads. ex: None or 16 -OVERRIDE_IS_DESKTOP = None # Force rqd to run in 'desktop' mode OVERRIDE_PROCS = None # number of physical cpus. ex: None or 2 +OVERRIDE_CORES = None # number of cores per cpu. ex: None or 8 +OVERRIDE_THREADS = None # number of threads per cpu. ex: None or 16 +OVERRIDE_IS_DESKTOP = None # Force rqd to run in 'desktop' mode OVERRIDE_MEMORY = None # in Kb OVERRIDE_NIMBY = None # True to turn on, False to turn off USE_NIMBY_PYNPUT = True # True pynput, False select From 0ab423158d4a7eb3182bee11daa86d5f7a52de6f Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Tue, 22 Apr 2025 04:20:34 +0200 Subject: [PATCH 46/78] feat: add function count_cores() to get all core units data. --- rqd/rqd/rqmachine.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 37974e5bf..611c926f9 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -664,6 +664,18 @@ def __initMachineStats(self, pathCpuInfo=None): if hyperthreadingMultiplier >= 1: self.__renderHost.attributes['hyperthreadingMultiplier'] = str(hyperthreadingMultiplier) + def count_cores(self): + """Counts the number of cores on the machine""" + cpu_count = len(self.__threadid_by_cpuid_and_coreid.keys()) + total_threads = len(self.__cpuid_and_coreid_by_threadid.keys()) + thread_per_proc = total_threads // cpu_count + total_cores = sum( + len(cores) for _, cores in self.__threadid_by_cpuid_and_coreid.items() + ) + core_per_proc = total_cores // cpu_count + + return cpu_count, total_cores, total_threads, core_per_proc, thread_per_proc + def __initStatsLinux(self, pathCpuInfo=None): """Init machine stats for Linux platforms. From bc6fccdf37913ec6155b905c04540ae72be2a345 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Tue, 22 Apr 2025 04:33:38 +0200 Subject: [PATCH 47/78] fix: hyperthreadingMultiplier can be a float for hybrid CPU --- rqd/rqd/rqmachine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 611c926f9..cf0227a64 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -901,7 +901,7 @@ def getHyperthreadingMultiplier(self): Multiplier used to compute the number of threads that can be allocated simultaneously on a core. This is a float as it can be fractional for hybrid cores. """ - return float(self.__renderHost.attributes['hyperthreadingMultiplier']) + return float(self.__renderHost.attributes.get('hyperthreadingMultiplier', 1.0)) def setupTaskset(self): """ Setup rqd for hyper-threading """ From 2d38bf6c4e3f7646707643d4cd262186473b4de0 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Tue, 22 Apr 2025 04:35:58 +0200 Subject: [PATCH 48/78] refacto: decompose cpu, core and thread counts to be more explicit and provide the correct values. --- rqd/rqd/rqmachine.py | 62 ++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index cf0227a64..2a813451d 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -622,45 +622,48 @@ def __initMachineStats(self, pathCpuInfo=None): # Get the total memory and swap self.updateMachineStats() - cpu_count = core_count = thread_count = 0 + # By default all systems will just have one proc/core + cpu_count = total_cores = total_threads = core_per_proc = thread_per_proc = 1 if platform.system() == "Linux" or pathCpuInfo is not None: - cpu_count, core_count, thread_count = self.__initStatsLinux(pathCpuInfo) + self.__initStatsLinux(pathCpuInfo) + cpu_count, total_cores, total_threads, core_per_proc, thread_per_proc = self.count_cores() elif platform.system() == 'Windows': - cpu_count, core_count, thread_count = self.__initStatsWindows() - - # All other systems will just have one proc/core - if not cpu_count or not core_count: - cpu_count = 1 - thread_count = 1 - core_count = 1 + self.__initStatsWindows() + cpu_count, total_cores, total_threads, core_per_proc, thread_per_proc = self.count_cores() # Override values from rqd.conf if rqd.rqconstants.OVERRIDE_MEMORY is not None: log.warning("Manually overriding the total memory") self.__renderHost.total_mem = rqd.rqconstants.OVERRIDE_MEMORY + if rqd.rqconstants.OVERRIDE_PROCS is not None: + log.warning("Manually overriding the number of reported procs") + cpu_count = rqd.rqconstants.OVERRIDE_PROCS + if rqd.rqconstants.OVERRIDE_CORES is not None: log.warning("Manually overriding the number of reported cores") - core_count = rqd.rqconstants.OVERRIDE_CORES * rqd.rqconstants.CORE_VALUE + core_per_proc = rqd.rqconstants.OVERRIDE_CORES + total_cores = core_per_proc * cpu_count if rqd.rqconstants.OVERRIDE_THREADS is None: - thread_count = core_count + thread_per_proc = core_count + total_threads = thread_per_proc * cpu_count if rqd.rqconstants.OVERRIDE_THREADS is not None: log.warning("Manually overriding the number of reported threads") - thread_count = rqd.rqconstants.OVERRIDE_THREADS * rqd.rqconstants.CORE_VALUE + thread_per_proc = rqd.rqconstants.OVERRIDE_THREADS + total_threads = thread_per_proc * cpu_count - if rqd.rqconstants.OVERRIDE_PROCS is not None: - log.warning("Manually overriding the number of reported procs") - cpu_count = rqd.rqconstants.OVERRIDE_PROCS + log.warning(f"{cpu_count=}, {total_cores=}, {total_threads=}, {core_per_proc=}, {thread_per_proc=}") - self.__coreInfo.idle_cores = core_count * rqd.rqconstants.CORE_VALUE - self.__coreInfo.total_cores = core_count * rqd.rqconstants.CORE_VALUE - self.__coreInfo.total_threads = thread_count * rqd.rqconstants.CORE_VALUE + self.__coreInfo.idle_cores = total_cores * rqd.rqconstants.CORE_VALUE + # TODO: add idle_threads ? anyway we need to address reserving threads instead of cores. + self.__coreInfo.total_cores = total_cores * rqd.rqconstants.CORE_VALUE + self.__coreInfo.total_threads = total_threads * rqd.rqconstants.CORE_VALUE self.__renderHost.num_procs = cpu_count - self.__renderHost.cores_per_proc = core_count * rqd.rqconstants.CORE_VALUE // cpu_count - self.__renderHost.threads_per_proc = thread_count * rqd.rqconstants.CORE_VALUE // cpu_count + self.__renderHost.cores_per_proc = core_per_proc * rqd.rqconstants.CORE_VALUE + self.__renderHost.threads_per_proc = thread_per_proc * rqd.rqconstants.CORE_VALUE - hyperthreadingMultiplier = thread_count / core_count + hyperthreadingMultiplier = thread_per_proc / core_per_proc if hyperthreadingMultiplier >= 1: self.__renderHost.attributes['hyperthreadingMultiplier'] = str(hyperthreadingMultiplier) @@ -683,7 +686,6 @@ def __initStatsLinux(self, pathCpuInfo=None): @param pathCpuInfo: Path to a specific cpuinfo file """ coreInfo = [] - _count = {"cpus": set(), "cores": set(), "threads": set()} # Reads static information from /proc/cpuinfo with (open(pathCpuInfo or rqd.rqconstants.PATH_CPUINFO, "r", encoding='utf-8') as cpuinfoFile): @@ -697,20 +699,16 @@ def __initStatsLinux(self, pathCpuInfo=None): elif len(lineList) == 1: infoBlock[lineList[0]] = "" # The end of a processor block - elif lineList == ['']: - cpu_id = infoBlock['physical id'] - physical_core_id = infoBlock['core id'] + if lineList == ['']: logical_core_id = infoBlock['processor'] - _count["cpus"].add(cpu_id) - _count["cores"].add(physical_core_id) - _count["threads"].add(logical_core_id) + cpu_id = infoBlock.get('physical id', infoBlock['processor']) + physical_core_id = infoBlock.get('core id', infoBlock['processor']) + coreInfo.append((cpu_id, physical_core_id, logical_core_id)) infoBlock.clear() self.__updateProcsMappings(coreInfo=coreInfo) - return len(_count["cpus"]), len(_count["cores"]), len(_count["threads"]) - def __initStatsWindows(self): """Init machine stats for Windows platforms. @@ -755,10 +753,6 @@ def __updateProcsMappings(self, coreInfo): self.__cpuid_and_coreid_by_threadid = {} for (cpu_id, physical_core_id, logical_core_id) in coreInfo: - log.debug(f"CPU ID: {cpu_id}, " - f"Physical core ID: {physical_core_id}, " - f"Logical core ID: {logical_core_id}") - self.__threadid_by_cpuid_and_coreid.setdefault( str(cpu_id), {}).setdefault( physical_core_id, set()).add(str(logical_core_id)) From c34d98497ec9b3cfc9c0c510444b8aea7628ce09 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Tue, 22 Apr 2025 04:37:03 +0200 Subject: [PATCH 49/78] refacto: changed cpuinfo files naming for hyperthreaded CPUs --- rqd/tests/rqmachine_test.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/rqd/tests/rqmachine_test.py b/rqd/tests/rqmachine_test.py index 956ce9a22..8c2fe5e43 100644 --- a/rqd/tests/rqmachine_test.py +++ b/rqd/tests/rqmachine_test.py @@ -497,7 +497,7 @@ def test_reserveCores(self): step5 - taskset4: 4 remaining, Reserve 4 threads (2 cores) (ph0->3 + ph1->3) step6 - taskset5: No more cores """ - cpuInfo = os.path.join(os.path.dirname(__file__), 'cpuinfo', '_cpuinfo_shark_ht_8-4-2-2') + cpuInfo = os.path.join(os.path.dirname(__file__), 'cpuinfo', '_cpuinfo_shark_ht_16-4-2-2') self.fs.add_real_file(cpuInfo) self.machine.testInitMachineStats(cpuInfo) @@ -596,7 +596,7 @@ def test_reserveHybridHT(self): """ cpuInfo = os.path.join(os.path.dirname(__file__), 'cpuinfo', - '_cpuinfo_i9_12900_hybrid_ht_24-16-1.5-1') + '_cpuinfo_i9_12900_hybrid_ht_24-16-1-1.5') self.fs.add_real_file(cpuInfo) self.machine.testInitMachineStats(cpuInfo) @@ -765,7 +765,7 @@ def setUp(self): self.rqd = rqd.rqcore.RqCore() def test_shark(self): - self.__cpuinfoTestHelper('_cpuinfo_shark_ht_8-4-2-2') + self.__cpuinfoTestHelper('_cpuinfo_shark_ht_16-4-2-2') def test_shark_ht(self): self.__cpuinfoTestHelper('_cpuinfo_shark_8-4-2') @@ -789,16 +789,16 @@ def test_8600(self): self.__cpuinfoTestHelper('_cpuinfo_hp8600_8-4-2') def test_srdsvr05(self): - self.__cpuinfoTestHelper('_cpuinfo_srdsvr05_ht_12-6-2-2') + self.__cpuinfoTestHelper('_cpuinfo_srdsvr05_ht_24-6-2-2') def test_srdsvr09(self): self.__cpuinfoTestHelper('_cpuinfo_srdsvr09_48-12-4') def test_i9_12900(self): - self.__cpuinfoTestHelper('_cpuinfo_i9_12900_hybrid_ht_24-16-1.5-1') + self.__cpuinfoTestHelper('_cpuinfo_i9_12900_hybrid_ht_24-16-1-1.5') def __cpuinfoTestHelper(self, pathCpuInfo): - # File format: _cpuinfo_dub_x-x-x where x-x-x is totalCores-coresPerProc-numProcs + # File format: _cpuinfo_dub_x-x-x where x-x-x is totalThreads-coresPerProc-numProcs pathCpuInfo = os.path.join(os.path.dirname(__file__), 'cpuinfo', pathCpuInfo) self.meminfo.set_contents(MEMINFO_MODERATE_USAGE) renderHost, coreInfo = self.rqd.machine.testInitMachineStats(pathCpuInfo) From 10d184754179eece046e9931b6d73fd1dea498a7 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Tue, 22 Apr 2025 04:37:53 +0200 Subject: [PATCH 50/78] fix: syntax error --- rqd/tests/rqmachine_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rqd/tests/rqmachine_test.py b/rqd/tests/rqmachine_test.py index 8c2fe5e43..cbcfa3712 100644 --- a/rqd/tests/rqmachine_test.py +++ b/rqd/tests/rqmachine_test.py @@ -813,7 +813,7 @@ def __cpuinfoTestHelper(self, pathCpuInfo): self.assertEqual(coreInfo.booked_cores, 0) if '_ht_' in pathCpuInfo: self.assertEqual( - float(renderHost.attributes['hyperthreadingMultiplier']), float(pathCpuInfo.split('-'))[3]) + float(renderHost.attributes['hyperthreadingMultiplier']), float(pathCpuInfo.split('-')[3])) if __name__ == '__main__': From efaff3e4a21caa02686f766a536fa8c02692c7ca Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Tue, 22 Apr 2025 04:44:08 +0200 Subject: [PATCH 51/78] test: add test for total_threads, threadsPerProc and hyperthreadingMultiplier --- rqd/tests/rqmachine_test.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/rqd/tests/rqmachine_test.py b/rqd/tests/rqmachine_test.py index cbcfa3712..60b276abe 100644 --- a/rqd/tests/rqmachine_test.py +++ b/rqd/tests/rqmachine_test.py @@ -802,13 +802,20 @@ def __cpuinfoTestHelper(self, pathCpuInfo): pathCpuInfo = os.path.join(os.path.dirname(__file__), 'cpuinfo', pathCpuInfo) self.meminfo.set_contents(MEMINFO_MODERATE_USAGE) renderHost, coreInfo = self.rqd.machine.testInitMachineStats(pathCpuInfo) - totalCores, coresPerProc, numProcs = pathCpuInfo.split('_')[-1].split('-')[:3] + totalThreads, coresPerProc, numProcs = map(int, pathCpuInfo.split('_')[-1].split('-')[:3]) + threadsPerProc = totalThreads // numProcs + ht_multiplier = float(pathCpuInfo.split('-')[3]) if '_ht_' in pathCpuInfo else 1.0 + totalCores = totalThreads // ht_multiplier + self.assertEqual(renderHost.attributes.get('hyperthreadingMultiplier', 1.0), ht_multiplier) + self.assertEqual(coresPerProc * numProcs, totalThreads // ht_multiplier) # pylint: disable=no-member - self.assertEqual(renderHost.num_procs, int(numProcs)) - self.assertEqual(renderHost.cores_per_proc, int(coresPerProc) * 100) - self.assertEqual(coreInfo.total_cores, int(totalCores) * 100) - self.assertEqual(coreInfo.idle_cores, int(totalCores) * 100) + self.assertEqual(renderHost.num_procs, numProcs) + self.assertEqual(coreInfo.total_cores, totalCores * 100) + self.assertEqual(coreInfo.total_threads, totalThreads * 100) + self.assertEqual(renderHost.cores_per_proc, coresPerProc * 100) + self.assertEqual(renderHost.threads_per_proc, threadsPerProc * 100) + self.assertEqual(coreInfo.idle_cores, totalCores * 100) self.assertEqual(coreInfo.locked_cores, 0) self.assertEqual(coreInfo.booked_cores, 0) if '_ht_' in pathCpuInfo: From daa6dab750f62c3e0a10b7359495a6dbd8526c41 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Tue, 22 Apr 2025 05:13:27 +0200 Subject: [PATCH 52/78] test: fix assert (cast str to float) --- rqd/tests/rqmachine_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rqd/tests/rqmachine_test.py b/rqd/tests/rqmachine_test.py index 60b276abe..b1d9e5abd 100644 --- a/rqd/tests/rqmachine_test.py +++ b/rqd/tests/rqmachine_test.py @@ -806,7 +806,7 @@ def __cpuinfoTestHelper(self, pathCpuInfo): threadsPerProc = totalThreads // numProcs ht_multiplier = float(pathCpuInfo.split('-')[3]) if '_ht_' in pathCpuInfo else 1.0 totalCores = totalThreads // ht_multiplier - self.assertEqual(renderHost.attributes.get('hyperthreadingMultiplier', 1.0), ht_multiplier) + self.assertEqual(float(renderHost.attributes.get('hyperthreadingMultiplier'), 1.0), ht_multiplier) self.assertEqual(coresPerProc * numProcs, totalThreads // ht_multiplier) # pylint: disable=no-member From 1a156575cfd4d29c8de5b00d34aea49eac51e50b Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Tue, 22 Apr 2025 05:20:58 +0200 Subject: [PATCH 53/78] doc: add some instruction comments --- rqd/rqd/rqmachine.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 2a813451d..24b5d9bdb 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -689,7 +689,7 @@ def __initStatsLinux(self, pathCpuInfo=None): # Reads static information from /proc/cpuinfo with (open(pathCpuInfo or rqd.rqconstants.PATH_CPUINFO, "r", encoding='utf-8') as cpuinfoFile): - infoBlock = {} + infoBlock = {} # Gets reset for each processor block for line in cpuinfoFile: lineList = line.strip().replace("\t", "").split(": ") # A normal entry added to the singleCore dictionary @@ -700,10 +700,11 @@ def __initStatsLinux(self, pathCpuInfo=None): infoBlock[lineList[0]] = "" # The end of a processor block if lineList == ['']: + # Get relevant information from the block logical_core_id = infoBlock['processor'] cpu_id = infoBlock.get('physical id', infoBlock['processor']) physical_core_id = infoBlock.get('core id', infoBlock['processor']) - + # Save that and iterate coreInfo.append((cpu_id, physical_core_id, logical_core_id)) infoBlock.clear() From 2b737e9e1fcfbe1960659e3b7f0b96bd3f2ee040 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Tue, 22 Apr 2025 05:21:53 +0200 Subject: [PATCH 54/78] refacto: simplify __initStatsWindows --- rqd/rqd/rqmachine.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 24b5d9bdb..424ce3259 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -712,25 +712,11 @@ def __initStatsLinux(self, pathCpuInfo=None): def __initStatsWindows(self): """Init machine stats for Windows platforms. - - @rtype: tuple - @return: A 3-items tuple containing: - - the number of physical CPU - - the number of physical cores - - the number of logical cores """ import rqd.rqwinutils # Windows-specific - - # Windows CPU information coreInfo = rqd.rqwinutils.get_logical_processor_information_ex() self.__updateProcsMappings(coreInfo=coreInfo) - processorCount = len(self.__threadid_by_cpuid_and_coreid) - physicalCoreCount = psutil.cpu_count(logical=False) - logicalCoreCount = psutil.cpu_count(logical=True) - - return processorCount, physicalCoreCount, logicalCoreCount - def __updateProcsMappings(self, coreInfo): """ Update `__threadid_by_cpuid_and_coreid` and `__cpuid_and_coreid_by_threadid` mappings. From 5ec2387524c594537d1d0417ef1a6f0da8e4d7cc Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Tue, 22 Apr 2025 05:36:38 +0200 Subject: [PATCH 55/78] test: fix syntax --- rqd/tests/rqmachine_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rqd/tests/rqmachine_test.py b/rqd/tests/rqmachine_test.py index b1d9e5abd..957a8a0d1 100644 --- a/rqd/tests/rqmachine_test.py +++ b/rqd/tests/rqmachine_test.py @@ -806,7 +806,7 @@ def __cpuinfoTestHelper(self, pathCpuInfo): threadsPerProc = totalThreads // numProcs ht_multiplier = float(pathCpuInfo.split('-')[3]) if '_ht_' in pathCpuInfo else 1.0 totalCores = totalThreads // ht_multiplier - self.assertEqual(float(renderHost.attributes.get('hyperthreadingMultiplier'), 1.0), ht_multiplier) + self.assertEqual(float(renderHost.attributes.get('hyperthreadingMultiplier', 1.0)), ht_multiplier) self.assertEqual(coresPerProc * numProcs, totalThreads // ht_multiplier) # pylint: disable=no-member From 0ef7ee3e51ad51d10a22f9bc25b197c4948f661d Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Tue, 22 Apr 2025 05:49:54 +0200 Subject: [PATCH 56/78] fix: copy correct cpuinfo file --- rqd/tests/rqmachine_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rqd/tests/rqmachine_test.py b/rqd/tests/rqmachine_test.py index 957a8a0d1..a1a80326f 100644 --- a/rqd/tests/rqmachine_test.py +++ b/rqd/tests/rqmachine_test.py @@ -419,7 +419,7 @@ def test_reserveHT(self): step5 - taskset4: 3 remaining, Reserve 3 cores (ph0+ph1) step5 - taskset5: No more cores """ - cpuInfo = os.path.join(os.path.dirname(__file__), 'cpuinfo', '_cpuinfo_shark_ht_8-4-2-2') + cpuInfo = os.path.join(os.path.dirname(__file__), 'cpuinfo', '_cpuinfo_shark_ht_16-4-2-2') self.fs.add_real_file(cpuInfo) self.machine.testInitMachineStats(cpuInfo) From 2a2074a7a9c14972a1630ccc11f6523efbe88e7f Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Tue, 22 Apr 2025 05:51:02 +0200 Subject: [PATCH 57/78] fix: revert getBootTime() and use the stat file only if it exists, else use psutil --- rqd/rqd/rqmachine.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 424ce3259..943f5395a 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -465,6 +465,11 @@ def getLoadAvg(self): @rqd.rqutil.Memoize def getBootTime(self): """Returns epoch when the system last booted""" + if os.path.isfile(rqd.rqconstants.PATH_STAT): + with open(rqd.rqconstants.PATH_STAT, "r", encoding='utf-8') as statFile: + for line in statFile: + if line.startswith("btime"): + return int(line.split()[1]) return int(psutil.boot_time()) @rqd.rqutil.Memoize From c7ae00abfc3feab1eaab50754d1c2c65f32c95a4 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Tue, 22 Apr 2025 06:08:27 +0200 Subject: [PATCH 58/78] fix: remove unused codecs import --- rqd/rqd/rqmachine.py | 1 - 1 file changed, 1 deletion(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 943f5395a..b4084defb 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -29,7 +29,6 @@ from builtins import range from builtins import object -import codecs import ctypes import errno import logging From a506b377d344b79e2ac5b277503927145faa4de2 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Tue, 22 Apr 2025 06:09:16 +0200 Subject: [PATCH 59/78] chore: import rqd.win_utils once --- rqd/rqd/rqmachine.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index b4084defb..3ee098763 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -53,6 +53,11 @@ winpsIsAvailable = True except ImportError: pass + + try: + import rqd.winutils + except ImportError: + pass # pylint: enable=import-error,wrong-import-position import psutil @@ -717,7 +722,6 @@ def __initStatsLinux(self, pathCpuInfo=None): def __initStatsWindows(self): """Init machine stats for Windows platforms. """ - import rqd.rqwinutils # Windows-specific coreInfo = rqd.rqwinutils.get_logical_processor_information_ex() self.__updateProcsMappings(coreInfo=coreInfo) @@ -751,8 +755,6 @@ def __updateProcsMappings(self, coreInfo): def updateWindowsMemory(self): """Updates the internal store of memory available for Windows.""" - import rqd.rqwinutils # Windows-specific - if not hasattr(self, '__windowsStat'): self.__windowsStat = rqd.rqwinutils.MEMORYSTATUSEX() ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(self.__windowsStat)) From 6344104b5adc4edfc207be6fbc30bc1d5ad3da6b Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Tue, 22 Apr 2025 06:09:56 +0200 Subject: [PATCH 60/78] fix: lint and override cores/threads operate both ways. --- rqd/rqd/rqmachine.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 3ee098763..cbf0a7760 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -636,10 +636,12 @@ def __initMachineStats(self, pathCpuInfo=None): if platform.system() == "Linux" or pathCpuInfo is not None: self.__initStatsLinux(pathCpuInfo) - cpu_count, total_cores, total_threads, core_per_proc, thread_per_proc = self.count_cores() + (cpu_count, total_cores, total_threads, + core_per_proc, thread_per_proc) = self.count_cores() elif platform.system() == 'Windows': self.__initStatsWindows() - cpu_count, total_cores, total_threads, core_per_proc, thread_per_proc = self.count_cores() + (cpu_count, total_cores, total_threads, + core_per_proc, thread_per_proc) = self.count_cores() # Override values from rqd.conf if rqd.rqconstants.OVERRIDE_MEMORY is not None: @@ -655,14 +657,16 @@ def __initMachineStats(self, pathCpuInfo=None): core_per_proc = rqd.rqconstants.OVERRIDE_CORES total_cores = core_per_proc * cpu_count if rqd.rqconstants.OVERRIDE_THREADS is None: - thread_per_proc = core_count - total_threads = thread_per_proc * cpu_count + thread_per_proc = core_per_proc + total_threads = total_cores + if rqd.rqconstants.OVERRIDE_THREADS is not None: log.warning("Manually overriding the number of reported threads") thread_per_proc = rqd.rqconstants.OVERRIDE_THREADS total_threads = thread_per_proc * cpu_count - - log.warning(f"{cpu_count=}, {total_cores=}, {total_threads=}, {core_per_proc=}, {thread_per_proc=}") + if rqd.rqconstants.OVERRIDE_CORES is None: + core_per_proc = thread_per_proc + total_cores = total_threads self.__coreInfo.idle_cores = total_cores * rqd.rqconstants.CORE_VALUE # TODO: add idle_threads ? anyway we need to address reserving threads instead of cores. @@ -672,9 +676,9 @@ def __initMachineStats(self, pathCpuInfo=None): self.__renderHost.cores_per_proc = core_per_proc * rqd.rqconstants.CORE_VALUE self.__renderHost.threads_per_proc = thread_per_proc * rqd.rqconstants.CORE_VALUE - hyperthreadingMultiplier = thread_per_proc / core_per_proc - if hyperthreadingMultiplier >= 1: - self.__renderHost.attributes['hyperthreadingMultiplier'] = str(hyperthreadingMultiplier) + ht_multiplier = thread_per_proc / core_per_proc + if ht_multiplier >= 1: + self.__renderHost.attributes['hyperthreadingMultiplier'] = str(ht_multiplier) def count_cores(self): """Counts the number of cores on the machine""" @@ -751,7 +755,8 @@ def __updateProcsMappings(self, coreInfo): self.__threadid_by_cpuid_and_coreid.setdefault( str(cpu_id), {}).setdefault( physical_core_id, set()).add(str(logical_core_id)) - self.__cpuid_and_coreid_by_threadid[logical_core_id] = (str(cpu_id), str(physical_core_id)) + self.__cpuid_and_coreid_by_threadid[logical_core_id] = (str(cpu_id), + str(physical_core_id)) def updateWindowsMemory(self): """Updates the internal store of memory available for Windows.""" From 246f7c5a6f307fb63fbcf43b8e4bcd612b44f94b Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Tue, 22 Apr 2025 07:00:11 +0200 Subject: [PATCH 61/78] lint: regroup rqd imports --- rqd/rqd/rqmachine.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index cbf0a7760..0ec9fc186 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -53,11 +53,6 @@ winpsIsAvailable = True except ImportError: pass - - try: - import rqd.winutils - except ImportError: - pass # pylint: enable=import-error,wrong-import-position import psutil @@ -68,6 +63,8 @@ import rqd.rqexceptions import rqd.rqswap import rqd.rqutil +if platform.system() == "Windows": + import rqd.winutils log = logging.getLogger(__name__) From 981365e1aba125265c3e91402e1626c7b880a3b7 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Tue, 22 Apr 2025 07:14:20 +0200 Subject: [PATCH 62/78] install: remove unused wmi import. --- rqd/setup.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rqd/setup.py b/rqd/setup.py index bf58e98fa..9afa557f9 100644 --- a/rqd/setup.py +++ b/rqd/setup.py @@ -59,8 +59,7 @@ 'grpcio', 'grpcio-tools', 'psutil', - 'pywin32==301; platform_system == "Windows"', - 'wmi==1.5.1; platform_system == "Windows"' + 'pywin32; platform_system == "Windows"' ] ) From e7080e8124b86ec684933bdb045a39e46f3847a0 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Tue, 22 Apr 2025 07:21:30 +0200 Subject: [PATCH 63/78] fix: use proper import --- rqd/rqd/rqmachine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 0ec9fc186..bfe7116a0 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -64,7 +64,7 @@ import rqd.rqswap import rqd.rqutil if platform.system() == "Windows": - import rqd.winutils + import rqd.rqwinutils log = logging.getLogger(__name__) From f23a83c0b2d3ed8216ca30e107a347156c6778ad Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Tue, 22 Apr 2025 07:21:48 +0200 Subject: [PATCH 64/78] chore: version bump --- VERSION.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION.in b/VERSION.in index 625934097..2e0e38c63 100644 --- a/VERSION.in +++ b/VERSION.in @@ -1 +1 @@ -1.8 +1.9 From 1518568013f71afca282522c5a211f14637d8843 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Tue, 22 Apr 2025 08:02:43 +0200 Subject: [PATCH 65/78] test: remove duplicate test + lint --- rqd/tests/rqmachine_test.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/rqd/tests/rqmachine_test.py b/rqd/tests/rqmachine_test.py index a1a80326f..7360b0075 100644 --- a/rqd/tests/rqmachine_test.py +++ b/rqd/tests/rqmachine_test.py @@ -806,8 +806,10 @@ def __cpuinfoTestHelper(self, pathCpuInfo): threadsPerProc = totalThreads // numProcs ht_multiplier = float(pathCpuInfo.split('-')[3]) if '_ht_' in pathCpuInfo else 1.0 totalCores = totalThreads // ht_multiplier - self.assertEqual(float(renderHost.attributes.get('hyperthreadingMultiplier', 1.0)), ht_multiplier) - self.assertEqual(coresPerProc * numProcs, totalThreads // ht_multiplier) + self.assertEqual(float(renderHost.attributes.get('hyperthreadingMultiplier', 1.0)), + ht_multiplier) + self.assertEqual(coresPerProc * numProcs, + totalThreads // ht_multiplier) # pylint: disable=no-member self.assertEqual(renderHost.num_procs, numProcs) @@ -818,9 +820,6 @@ def __cpuinfoTestHelper(self, pathCpuInfo): self.assertEqual(coreInfo.idle_cores, totalCores * 100) self.assertEqual(coreInfo.locked_cores, 0) self.assertEqual(coreInfo.booked_cores, 0) - if '_ht_' in pathCpuInfo: - self.assertEqual( - float(renderHost.attributes['hyperthreadingMultiplier']), float(pathCpuInfo.split('-')[3])) if __name__ == '__main__': From eb85324fd7ba1e17563841f58c0b3e98087bd357 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Wed, 2 Jul 2025 21:51:43 +0200 Subject: [PATCH 66/78] fix: revert field numbering and append new ones to fix backward compatibility. --- proto/report.proto | 66 +++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/proto/report.proto b/proto/report.proto index 7e94cb323..1c9a828e1 100644 --- a/proto/report.proto +++ b/proto/report.proto @@ -35,12 +35,12 @@ message BootReport { message CoreDetail { int32 total_cores = 1; // physical cores - int32 total_threads = 2; // logical cores - int32 idle_cores = 3; - int32 locked_cores = 4; - int32 booked_cores = 5; + int32 idle_cores = 2; + int32 locked_cores = 3; + int32 booked_cores = 4; //map - map reserved_cores = 6; + map reserved_cores = 5; + int32 total_threads = 6; // logical cores } message CoreId { @@ -69,21 +69,21 @@ message RenderHost { string facility= 4; // The name of the facility that the host is in int32 num_procs = 5; // the number of physical procs on this machine int32 cores_per_proc = 6; // the number of physical cores per proc - int32 threads_per_proc = 7; // the number of logical cores per proc - int64 total_swap = 8; // the total size of the swap in kB - int64 total_mem = 9; // the total size of the main memory pool in kB - int64 total_mcp = 10; // the total size of MCP in kB - int64 free_swap = 11; // the current amount of free swap in kB - int64 free_mem = 12; // the current amount of free memory in kB - int64 free_mcp = 13; // the current amount of free MCP in kB - int32 load = 14; // the current load on the proc - int32 boot_time = 15; // the time the proc was booted - repeated string tags = 16; // an array of default tags that are added to the host record - host.HardwareState state = 17; // hardware state for the host - map attributes = 18; // additional data can be provided about the host - int32 num_gpus = 19; // the number of physical GPU's - int64 free_gpu_mem = 20; // the current amount of free gpu memory in kB - int64 total_gpu_mem = 21; // the total size of gpu memory in kB + int64 total_swap = 7; // the total size of the swap in kB + int64 total_mem = 8; // the total size of the main memory pool in kB + int64 total_mcp = 9; // the total size of MCP in kB + int64 free_swap = 10; // the current amount of free swap in kB + int64 free_mem = 11; // the current amount of free memory in kB + int64 free_mcp = 12; // the current amount of free MCP in kB + int32 load = 13; // the current load on the proc + int32 boot_time = 14; // the time the proc was booted + repeated string tags = 15; // an array of default tags that are added to the host record + host.HardwareState state = 16; // hardware state for the host + map attributes = 17; // additional data can be provided about the host + int32 num_gpus = 18; // the number of physical GPU's + int64 free_gpu_mem = 19; // the current amount of free gpu memory in kB + int64 total_gpu_mem = 20; // the total size of gpu memory in kB + int32 threads_per_proc = 21; // the number of logical cores per proc }; message RunningFrameInfo { @@ -94,19 +94,19 @@ message RunningFrameInfo { string frame_name = 5; string layer_id = 6; int32 num_cores = 7; - bool use_threads = 8; // whether the frame is requesting logical or physical cores - int64 start_time = 9; - int64 max_rss = 10; // kB - int64 rss = 11; // kB - int64 max_vsize = 12; // kB - int64 vsize = 13; // kB - map attributes = 14; //additional data can be provided about the running frame - int64 llu_time = 15; - int32 num_gpus = 16; - int64 max_used_gpu_memory = 17; // kB - int64 used_gpu_memory = 18; // kB - ChildrenProcStats children = 19; //additional data about the running frame's child processes - int64 used_swap_memory = 20; // kB + int64 start_time = 8; + int64 max_rss = 9; // kB + int64 rss = 10; // kB + int64 max_vsize = 11; // kB + int64 vsize = 12; // kB + map attributes = 13; //additional data can be provided about the running frame + int64 llu_time = 14; + int32 num_gpus = 15; + int64 max_used_gpu_memory = 16; // kB + int64 used_gpu_memory = 17; // kB + ChildrenProcStats children = 18; //additional data about the running frame's child processes + int64 used_swap_memory = 19; // kB + bool use_threads = 20; // whether the frame is requesting logical or physical cores }; message ChildrenProcStats { From c308521ad9f4f116fdc6557765b9f54143cd1882 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Wed, 2 Jul 2025 21:58:46 +0200 Subject: [PATCH 67/78] doc: explicit instruction for LOAD_MODIFIER. Removed useless whitespace. --- rqd/rqd/rqconstants.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rqd/rqd/rqconstants.py b/rqd/rqd/rqconstants.py index c471b50e0..523276091 100644 --- a/rqd/rqd/rqconstants.py +++ b/rqd/rqd/rqconstants.py @@ -159,7 +159,7 @@ USE_NIMBY_PYNPUT = True # True pynput, False select OVERRIDE_HOSTNAME = None # Force to use this hostname ALLOW_GPU = False -LOAD_MODIFIER = 0 # amount to add/subtract from load, +LOAD_MODIFIER = 0 # amount to add/subtract from load, used to make the machine look busier than it really is to CueBot. LOG_FORMAT = '%(levelname)-9s openrqd-%(module)-10s: %(message)s' CONSOLE_LOG_LEVEL = logging.WARNING @@ -233,7 +233,7 @@ RQD_USE_PATH_ENV_VAR = config.getboolean(__override_section, "RQD_USE_PATH_ENV_VAR") if config.has_option(__override_section, "RQD_USE_ALL_HOST_ENV_VARS"): RQD_USE_HOST_ENV_VARS = config.getboolean(__override_section, - "RQD_USE_ALL_HOST_ENV_VARS") + "RQD_USE_ALL_HOST_ENV_VARS") if config.has_option(__override_section, "RQD_BECOME_JOB_USER"): RQD_BECOME_JOB_USER = config.getboolean(__override_section, "RQD_BECOME_JOB_USER") if config.has_option(__override_section, "RQD_TAGS"): From b6fa9b2d4e11d6f20c04dd44ec763c608b2df205 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Wed, 16 Jul 2025 22:12:27 +0200 Subject: [PATCH 68/78] lint: line too long --- rqd/rqd/rqconstants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rqd/rqd/rqconstants.py b/rqd/rqd/rqconstants.py index 45be54567..1454e1a85 100644 --- a/rqd/rqd/rqconstants.py +++ b/rqd/rqd/rqconstants.py @@ -155,7 +155,7 @@ USE_NIMBY_PYNPUT = True # True pynput, False select OVERRIDE_HOSTNAME = None # Force to use this hostname ALLOW_GPU = False -LOAD_MODIFIER = 0 # amount to add/subtract from load, used to make the machine look busier than it really is to CueBot. +LOAD_MODIFIER = 0 # amount to add/subtract from load, makes the machine look busier to CueBot. LOG_FORMAT = '%(levelname)-9s openrqd-%(module)-10s: %(message)s' CONSOLE_LOG_LEVEL = logging.WARNING From 29527d9f9578e281f2c75f345c2b8ef71291f18f Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Wed, 30 Jul 2025 22:19:19 +0200 Subject: [PATCH 69/78] fix: restore MEMORYSTATUSEX in rqwinutils.py (moved from rqmachine.py) --- rqd/rqd/rqwinutils.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/rqd/rqd/rqwinutils.py b/rqd/rqd/rqwinutils.py index eb13f1e69..6e843d96a 100644 --- a/rqd/rqd/rqwinutils.py +++ b/rqd/rqd/rqwinutils.py @@ -14,7 +14,7 @@ This is tailored for the needs of OpenCue, especially for hybrid CPUs TODO: Maybe we should contribute this back to psutils ? """ -from ctypes import c_ulonglong, Structure, Union, WinDLL +from ctypes import c_ulonglong, c_uint, Structure, Union, WinDLL from ctypes import POINTER, sizeof, WinError, byref, get_last_error from ctypes import wintypes @@ -74,6 +74,26 @@ class SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX(Structure): ("DUMMYUNIONNAME", DUMMYUNIONNAME)] +class MEMORYSTATUSEX(Structure): + """Represents Windows memory information.""" + # From + # http://stackoverflow.com/questions/2017545/get-memory-usage-of-computer-in-windows-with-python + _fields_ = [("dwLength", c_uint), + ("dwMemoryLoad", c_uint), + ("ullTotalPhys", c_ulonglong), + ("ullAvailPhys", c_ulonglong), + ("ullTotalPageFile", c_ulonglong), + ("ullAvailPageFile", c_ulonglong), + ("ullTotalVirtual", c_ulonglong), + ("ullAvailVirtual", c_ulonglong), + ("ullAvailExtendedVirtual", c_ulonglong), ] + + def __init__(self): + # have to initialize this to the size of MEMORYSTATUSEX + self.dwLength = 2 * 4 + 7 * 8 # size = 2 ints, 7 longs + super(MEMORYSTATUSEX, self).__init__() + + def get_logical_processor_information_ex(): """ Retrieves information about all the logical processors in the system. Usage: From 5a1a935531db00b77799f131eedb02fedd01f979 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Thu, 31 Jul 2025 17:31:23 +0200 Subject: [PATCH 70/78] feat: - Always add the LOAD_MODIFIER to the loadAvg, even on unchecked systems. - Get cpu load instead for Windows and MacOS. doc: - Explicit documentation to differentiate the value meaning on each system. --- rqd/rqd/rqmachine.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index a6b1e1ae2..34a721d45 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -458,22 +458,23 @@ def _getProcSwap(self, pid): def getLoadAvg(self): """Returns average number of processes waiting to be served - for the last 1 minute multiplied by 100.""" + for the last 1 minute across all cores, x100 for cuebot.""" + loadAvg = 0 if platform.system() == "Linux": + # On linux, the load is the average number of processes in queue + # It helps measures the CPU utilization as well as disk i/o. with open(rqd.rqconstants.PATH_LOADAVG, "r", encoding='utf-8') as loadAvgFile: - loadAvg = int(float(loadAvgFile.read().split()[0]) * 100) - if self.__enabledHT(): - loadAvg = loadAvg // self.getHyperthreadingMultiplier() - loadAvg = loadAvg + rqd.rqconstants.LOAD_MODIFIER - loadAvg = max(loadAvg, 0) - return int(loadAvg) - elif platform.system() == "Windows": - # Use psutil to get the CPU utilization over 1 second - # This is not the same as load average, but it gives a - # similar idea of CPU load. - loadAvg = psutil.cpu_percent(interval=1) - return int(loadAvg * 100) - return 0 + loadAvg = float(loadAvgFile.read().split()[0]) * 100 + elif platform.system() in ("Windows", "Darwin"): + # On Windows and MacOS, we can only get the CPU usage. + # Here we get the sum of the CPU usage across all cores. + # (note: CueGui divides this value by the number of physical cores) + loadAvg = sum(psutil.cpu_percent(interval=2, percpu=True)) + if self.__enabledHT(): + loadAvg = loadAvg // self.getHyperthreadingMultiplier() + loadAvg += rqd.rqconstants.LOAD_MODIFIER + loadAvg = max(loadAvg, 0) + return int(loadAvg) @rqd.rqutil.Memoize def getBootTime(self): From 1177d3802a23d9fbecc839133776fac3cf17d40e Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Thu, 31 Jul 2025 17:33:30 +0200 Subject: [PATCH 71/78] fix: use KILOBYTE constant instead of hard 1024 value. --- rqd/rqd/rqmachine.py | 48 ++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 34a721d45..40e3e68a2 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -227,7 +227,7 @@ def rssUpdateWindows(self, frames): self.__updateGpuAndLlu(frame) if frame.pid > 0 and frame.pid in stats: stat = stats[frame.pid] - frame.rss = stat["rss"] // 1024 + frame.rss = stat["rss"] // KILOBYTE frame.maxRss = max(frame.rss, frame.maxRss) frame.runFrame.attributes["pcpu"] = str( stat["pcpu"] * self.__coreInfo.total_cores @@ -379,33 +379,33 @@ def rssUpdate(self, frames): # If children was already accounted for, only keep the highest # recorded rss value if child_pid in frame.childrenProcs: - childRss = (int(data["rss"]) * resource.getpagesize()) // 1024 + childRss = (int(data["rss"]) * resource.getpagesize()) // KILOBYTE if childRss > frame.childrenProcs[child_pid]['rss']: frame.childrenProcs[child_pid]['rss_page'] = int(data["rss"]) frame.childrenProcs[child_pid]['rss'] = childRss frame.childrenProcs[child_pid]['vsize'] = \ - int(data["vsize"]) // 1024 - frame.childrenProcs[child_pid]['swap'] = swap // 1024 + int(data["vsize"]) // KILOBYTE + frame.childrenProcs[child_pid]['swap'] = swap // KILOBYTE frame.childrenProcs[child_pid]['statm_rss'] = \ (int(data["statm_rss"]) \ - * resource.getpagesize()) // 1024 + * resource.getpagesize()) // KILOBYTE frame.childrenProcs[child_pid]['statm_size'] = \ (int(data["statm_size"]) * \ - resource.getpagesize()) // 1024 + resource.getpagesize()) // KILOBYTE else: frame.childrenProcs[child_pid] = \ {'name': data['name'], 'rss_page': int(data["rss"]), - 'rss': (int(data["rss"]) * resource.getpagesize()) // 1024, - 'vsize': int(data["vsize"]) // 1024, - 'swap': swap // 1024, + 'rss': (int(data["rss"]) * resource.getpagesize()) // KILOBYTE, + 'vsize': int(data["vsize"]) // KILOBYTE, + 'swap': swap // KILOBYTE, 'state': data['state'], # statm reports in pages (~ 4kB) # same as VmRss in /proc/[pid]/status (in KB) 'statm_rss': (int(data["statm_rss"]) * \ - resource.getpagesize()) // 1024, + resource.getpagesize()) // KILOBYTE, 'statm_size': (int(data["statm_size"]) * \ - resource.getpagesize()) // 1024, + resource.getpagesize()) // KILOBYTE, 'cmd_line': data["cmd_line"], 'start_time': seconds} @@ -415,9 +415,9 @@ def rssUpdate(self, frames): 'Failure with pid rss update due to: %s at %s', e, traceback.extract_tb(sys.exc_info()[2])) # convert bytes to KB - rss = (rss * resource.getpagesize()) // 1024 - vsize = int(vsize/1024) - swap = swap // 1024 + rss = (rss * resource.getpagesize()) // KILOBYTE + vsize = int(vsize/KILOBYTE) + swap = swap // KILOBYTE frame.rss = rss frame.maxRss = max(rss, frame.maxRss) @@ -778,14 +778,14 @@ def updateWindowsMemory(self): temp_path = os.getenv('TEMP') # Windows temp directory disk_usage = psutil.disk_usage(temp_path) - self.__renderHost.total_mcp = disk_usage.total // 1024 - self.__renderHost.free_mcp = disk_usage.free // 1024 + self.__renderHost.total_mcp = disk_usage.total // KILOBYTE + self.__renderHost.free_mcp = disk_usage.free // KILOBYTE - self.__renderHost.total_mem = int(stat.ullTotalPhys / 1024) - self.__renderHost.free_mem = int(stat.ullAvailPhys / 1024) + self.__renderHost.total_mem = int(stat.ullTotalPhys / KILOBYTE) + self.__renderHost.free_mem = int(stat.ullAvailPhys / KILOBYTE) - self.__renderHost.total_swap = int(stat.ullTotalPageFile / 1024) - self.__renderHost.free_swap = int(stat.ullAvailPageFile / 1024) + self.__renderHost.total_swap = int(stat.ullTotalPageFile / KILOBYTE) + self.__renderHost.free_swap = int(stat.ullAvailPageFile / KILOBYTE) self.__renderHost.num_gpus = self.getGpuCount() self.__renderHost.total_gpu_mem = self.getGpuMemoryTotal() @@ -825,7 +825,7 @@ def updateMacMemory(self): memsizeRegex = re.compile(r'^hw.memsize: (?P[\d]+)$') memsizeMatch = memsizeRegex.match(memsizeOutput) if memsizeMatch: - self.__renderHost.total_mem = int(memsizeMatch.group('totalMemBytes')) // 1024 + self.__renderHost.total_mem = int(memsizeMatch.group('totalMemBytes')) // KILOBYTE else: self.__renderHost.total_mem = 0 @@ -837,15 +837,15 @@ def updateMacMemory(self): if match: vmStats[match.group('field')] = int(match.group('pages')) * 4096 - freeMemory = vmStats.get("Pages free", 0) // 1024 - inactiveMemory = vmStats.get("Pages inactive", 0) // 1024 + freeMemory = vmStats.get("Pages free", 0) // KILOBYTE + inactiveMemory = vmStats.get("Pages inactive", 0) // KILOBYTE self.__renderHost.free_mem = freeMemory + inactiveMemory swapStats = subprocess.getoutput('sysctl vm.swapusage').strip() swapRegex = re.compile(r'^.* free = (?P[\d]+)M .*$') swapMatch = swapRegex.match(swapStats) if swapMatch: - self.__renderHost.free_swap = int(float(swapMatch.group('freeMb')) * 1024) + self.__renderHost.free_swap = int(float(swapMatch.group('freeMb')) * KILOBYTE) else: self.__renderHost.free_swap = 0 From f5f4f0587a80b8521b0344606a403f786e2badd3 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Tue, 5 Aug 2025 07:24:19 +0200 Subject: [PATCH 72/78] fix: thinking about it, 1024 is explicit enough, and triggers a linting report on tests. --- rqd/rqd/rqmachine.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 40e3e68a2..7092b3668 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -227,7 +227,7 @@ def rssUpdateWindows(self, frames): self.__updateGpuAndLlu(frame) if frame.pid > 0 and frame.pid in stats: stat = stats[frame.pid] - frame.rss = stat["rss"] // KILOBYTE + frame.rss = stat["rss"] // 1024 frame.maxRss = max(frame.rss, frame.maxRss) frame.runFrame.attributes["pcpu"] = str( stat["pcpu"] * self.__coreInfo.total_cores @@ -379,33 +379,33 @@ def rssUpdate(self, frames): # If children was already accounted for, only keep the highest # recorded rss value if child_pid in frame.childrenProcs: - childRss = (int(data["rss"]) * resource.getpagesize()) // KILOBYTE + childRss = (int(data["rss"]) * resource.getpagesize()) // 1024 if childRss > frame.childrenProcs[child_pid]['rss']: frame.childrenProcs[child_pid]['rss_page'] = int(data["rss"]) frame.childrenProcs[child_pid]['rss'] = childRss frame.childrenProcs[child_pid]['vsize'] = \ - int(data["vsize"]) // KILOBYTE - frame.childrenProcs[child_pid]['swap'] = swap // KILOBYTE + int(data["vsize"]) // 1024 + frame.childrenProcs[child_pid]['swap'] = swap // 1024 frame.childrenProcs[child_pid]['statm_rss'] = \ (int(data["statm_rss"]) \ - * resource.getpagesize()) // KILOBYTE + * resource.getpagesize()) // 1024 frame.childrenProcs[child_pid]['statm_size'] = \ (int(data["statm_size"]) * \ - resource.getpagesize()) // KILOBYTE + resource.getpagesize()) // 1024 else: frame.childrenProcs[child_pid] = \ {'name': data['name'], 'rss_page': int(data["rss"]), - 'rss': (int(data["rss"]) * resource.getpagesize()) // KILOBYTE, - 'vsize': int(data["vsize"]) // KILOBYTE, - 'swap': swap // KILOBYTE, + 'rss': (int(data["rss"]) * resource.getpagesize()) // 1024, + 'vsize': int(data["vsize"]) // 1024, + 'swap': swap // 1024, 'state': data['state'], # statm reports in pages (~ 4kB) # same as VmRss in /proc/[pid]/status (in KB) 'statm_rss': (int(data["statm_rss"]) * \ - resource.getpagesize()) // KILOBYTE, + resource.getpagesize()) // 1024, 'statm_size': (int(data["statm_size"]) * \ - resource.getpagesize()) // KILOBYTE, + resource.getpagesize()) // 1024, 'cmd_line': data["cmd_line"], 'start_time': seconds} @@ -415,9 +415,9 @@ def rssUpdate(self, frames): 'Failure with pid rss update due to: %s at %s', e, traceback.extract_tb(sys.exc_info()[2])) # convert bytes to KB - rss = (rss * resource.getpagesize()) // KILOBYTE - vsize = int(vsize/KILOBYTE) - swap = swap // KILOBYTE + rss = (rss * resource.getpagesize()) // 1024 + vsize = int(vsize/1024) + swap = swap // 1024 frame.rss = rss frame.maxRss = max(rss, frame.maxRss) From 44a0a7a9b22c2ff988c751d9c28c7b5c53bf482c Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Wed, 6 Aug 2025 17:24:56 +0200 Subject: [PATCH 73/78] update: increment minor version --- VERSION.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION.in b/VERSION.in index c044b1a32..809bdcb85 100644 --- a/VERSION.in +++ b/VERSION.in @@ -1 +1 @@ -1.10 +1.12 From 5007a471dd82dd95b6b342b101c186dc75ef44e5 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Wed, 6 Aug 2025 17:34:24 +0200 Subject: [PATCH 74/78] fix: revert to 1024 instead of KILOBYTE --- rqd/rqd/rqmachine.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index 7092b3668..b0bb13aa4 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -778,14 +778,14 @@ def updateWindowsMemory(self): temp_path = os.getenv('TEMP') # Windows temp directory disk_usage = psutil.disk_usage(temp_path) - self.__renderHost.total_mcp = disk_usage.total // KILOBYTE - self.__renderHost.free_mcp = disk_usage.free // KILOBYTE + self.__renderHost.total_mcp = disk_usage.total // 1024 + self.__renderHost.free_mcp = disk_usage.free // 1024 - self.__renderHost.total_mem = int(stat.ullTotalPhys / KILOBYTE) - self.__renderHost.free_mem = int(stat.ullAvailPhys / KILOBYTE) + self.__renderHost.total_mem = int(stat.ullTotalPhys / 1024) + self.__renderHost.free_mem = int(stat.ullAvailPhys / 1024) - self.__renderHost.total_swap = int(stat.ullTotalPageFile / KILOBYTE) - self.__renderHost.free_swap = int(stat.ullAvailPageFile / KILOBYTE) + self.__renderHost.total_swap = int(stat.ullTotalPageFile / 1024) + self.__renderHost.free_swap = int(stat.ullAvailPageFile / 1024) self.__renderHost.num_gpus = self.getGpuCount() self.__renderHost.total_gpu_mem = self.getGpuMemoryTotal() @@ -795,7 +795,7 @@ def updateLinuxMemory(self): """Gets information on system memory for Linux.""" # Reads dynamic information for mcp mcpStat = os.statvfs(self.getTempPath()) - self.__renderHost.free_mcp = (mcpStat.f_bavail * mcpStat.f_bsize) // KILOBYTE + self.__renderHost.free_mcp = (mcpStat.f_bavail * mcpStat.f_bsize) // 1024 # Reads dynamic information from /proc/meminfo with open(rqd.rqconstants.PATH_MEMINFO, "r", encoding='utf-8') as fp: @@ -825,7 +825,7 @@ def updateMacMemory(self): memsizeRegex = re.compile(r'^hw.memsize: (?P[\d]+)$') memsizeMatch = memsizeRegex.match(memsizeOutput) if memsizeMatch: - self.__renderHost.total_mem = int(memsizeMatch.group('totalMemBytes')) // KILOBYTE + self.__renderHost.total_mem = int(memsizeMatch.group('totalMemBytes')) // 1024 else: self.__renderHost.total_mem = 0 @@ -837,15 +837,15 @@ def updateMacMemory(self): if match: vmStats[match.group('field')] = int(match.group('pages')) * 4096 - freeMemory = vmStats.get("Pages free", 0) // KILOBYTE - inactiveMemory = vmStats.get("Pages inactive", 0) // KILOBYTE + freeMemory = vmStats.get("Pages free", 0) // 1024 + inactiveMemory = vmStats.get("Pages inactive", 0) // 1024 self.__renderHost.free_mem = freeMemory + inactiveMemory swapStats = subprocess.getoutput('sysctl vm.swapusage').strip() swapRegex = re.compile(r'^.* free = (?P[\d]+)M .*$') swapMatch = swapRegex.match(swapStats) if swapMatch: - self.__renderHost.free_swap = int(float(swapMatch.group('freeMb')) * KILOBYTE) + self.__renderHost.free_swap = int(float(swapMatch.group('freeMb')) * 1024) else: self.__renderHost.free_swap = 0 From a35e16f885ad646682fd09f4d42e9aa4ac3d546d Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Wed, 6 Aug 2025 18:36:07 +0200 Subject: [PATCH 75/78] doc: updated docstring for reserveCores, being a bit more explicit on the new `logical` parameter. --- rqd/rqd/rqmachine.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index b0bb13aa4..ef6004866 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -920,8 +920,10 @@ def reserveCores(self, coresCount=0, logical=True): @type coresCount: int @param coresCount: The total physical cores reserved by the frame. @type logical: bool - @param logical: If True, reserve logical cores (aka threads), else physical cores. - note: logical cores is what you see in htop or task manager. + @param logical: If True, reserve logical cores (aka threads), + else reserve physical cores (legacy). + note: logical cores is what you see in htop or task manager. + For example, a 16 core CPU with hyper-threading will have 32 logical cores. @rtype: string @return: The cpu-list for taskset -c """ From 027d8114371812f4c121030e9b92a1a186906883 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Wed, 27 Aug 2025 15:35:12 +0200 Subject: [PATCH 76/78] chore: remove old setup.py --- rqd/setup.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 rqd/setup.py diff --git a/rqd/setup.py b/rqd/setup.py deleted file mode 100644 index e69de29bb..000000000 From b2b08e71c818f81318ea9b41c34d909b92d3bfd9 Mon Sep 17 00:00:00 2001 From: Jimmy Christensen Date: Tue, 23 Sep 2025 23:24:26 +0200 Subject: [PATCH 77/78] feat(rqd): Add threads_per_proc to host stats --- rust/crates/rqd/src/system/linux.rs | 6 ++++++ rust/crates/rqd/src/system/machine.rs | 1 + rust/crates/rqd/src/system/manager.rs | 2 ++ rust/crates/rqd/src/system/reservation.rs | 12 ++++++++++++ 4 files changed, 21 insertions(+) diff --git a/rust/crates/rqd/src/system/linux.rs b/rust/crates/rqd/src/system/linux.rs index 28cca98c5..5bbcea39a 100644 --- a/rust/crates/rqd/src/system/linux.rs +++ b/rust/crates/rqd/src/system/linux.rs @@ -63,6 +63,7 @@ pub struct ProcessorInfoData { hyperthreading_multiplier: u32, num_sockets: u32, cores_per_socket: u32, + threads_per_proc: u32, pub processor_structure: ProcessorStructure, } @@ -80,6 +81,7 @@ struct MachineStaticInfo { /// Number of sockets (also know as physical cores) pub num_sockets: u32, pub cores_per_socket: u32, + pub threads_per_proc: u32, // Unlike the python counterpart, the multiplier is not automatically applied to total_procs pub hyperthreading_multiplier: u32, pub boot_time_secs: u64, @@ -152,6 +154,7 @@ impl LinuxSystem { total_swap, num_sockets: cpu_initial_info.num_sockets, cores_per_socket: cpu_initial_info.cores_per_socket, + threads_per_proc: cpu_initial_info.threads_per_proc, hyperthreading_multiplier: cpu_initial_info.hyperthreading_multiplier, boot_time_secs: Self::read_boot_time(&config.proc_stat_path).unwrap_or(0), tags: Self::setup_tags(config), @@ -295,6 +298,7 @@ impl LinuxSystem { hyperthreading_multiplier: hyper_modifier, num_sockets, cores_per_socket: num_threads / num_sockets, + threads_per_proc: num_threads / num_sockets, processor_structure, }) } @@ -748,6 +752,7 @@ impl SystemManager for LinuxSystem { total_swap: self.static_info.total_swap, num_sockets: self.static_info.num_sockets, cores_per_socket: self.static_info.cores_per_socket, + threads_per_proc: self.static_info.threads_per_proc, boot_time: self.static_info.boot_time_secs as u32, tags: self.static_info.tags.clone(), available_memory: dinamic_stat.available_memory, @@ -1412,6 +1417,7 @@ mod tests { total_swap: 0, num_sockets: physical_cpus, cores_per_socket: cores_per_cpu, + threads_per_proc: threads_per_core, hyperthreading_multiplier: 1, boot_time_secs: 0, tags: vec![], diff --git a/rust/crates/rqd/src/system/machine.rs b/rust/crates/rqd/src/system/machine.rs index 8b646625f..c4aac4138 100644 --- a/rust/crates/rqd/src/system/machine.rs +++ b/rust/crates/rqd/src/system/machine.rs @@ -450,6 +450,7 @@ impl MachineMonitor { facility: config.facility.clone(), num_procs: stats.num_sockets as i32, cores_per_proc: (stats.cores_per_socket * config.core_multiplier) as i32, + threads_per_proc: stats.threads_per_proc as i32, total_swap: (stats.total_swap / KIB) as i64, total_mem: (stats.total_memory / KIB) as i64, total_mcp: (stats.total_temp_storage / KIB) as i64, diff --git a/rust/crates/rqd/src/system/manager.rs b/rust/crates/rqd/src/system/manager.rs index 23087dbc6..8e3cc75ac 100644 --- a/rust/crates/rqd/src/system/manager.rs +++ b/rust/crates/rqd/src/system/manager.rs @@ -74,6 +74,8 @@ pub struct MachineStat { pub num_sockets: u32, /// Number of cores per processor unit pub cores_per_socket: u32, + // Number of threads per processor unit + pub threads_per_proc: u32, /// Timestamp for when the machine was booted up pub boot_time: u32, /// List of tags associated with this machine diff --git a/rust/crates/rqd/src/system/reservation.rs b/rust/crates/rqd/src/system/reservation.rs index a5957ef08..649d5bb43 100644 --- a/rust/crates/rqd/src/system/reservation.rs +++ b/rust/crates/rqd/src/system/reservation.rs @@ -40,6 +40,10 @@ impl ProcessorStructure { pub fn num_cores(&self) -> u32 { self.threads_by_core_unique_id.len() as u32 } + + pub fn num_threads(&self) -> u32 { + self.thread_id_lookup_table.len() as u32 + } } #[derive(Debug, Clone)] @@ -353,6 +357,7 @@ impl CoreStateManager { pub fn get_core_info_report(&self, core_multiplier: u32) -> CoreDetail { let total_cores = self.processor_structure.num_cores() as i32; let locked_cores = self.locked_cores as i32; + let total_threads = self.processor_structure.num_threads() as i32; // Idle cores needs to take both cores that are booked and locked. // At the end, the number of idle cores is the min between non_booked and unlocked cores @@ -370,6 +375,7 @@ impl CoreStateManager { .sum::(); CoreDetail { + total_threads, total_cores: total_cores * core_multiplier as i32, idle_cores: idle_cores * core_multiplier as i32, locked_cores: locked_cores * core_multiplier as i32, @@ -450,6 +456,12 @@ mod tests { assert_eq!(processor_structure.num_cores(), 4); } + #[test] + fn test_processor_structure_num_threads() { + let processor_structure = create_test_processor_structure(); + assert_eq!(processor_structure.num_threads(), 8); + } + #[test] fn test_core_booking_new() { let booking = CoreBooking::new(); From 3d1fed1665920c54bfd16bff88d26c0ee57237b7 Mon Sep 17 00:00:00 2001 From: Kern Attila GERMAIN <5556461+KernAttila@users.noreply.github.com> Date: Wed, 8 Oct 2025 17:58:46 +0200 Subject: [PATCH 78/78] fix: use self.getTempPath() instead of env var. chore: merge/adapt changes to mac memory detection from PR #2023 --- rqd/rqd/rqmachine.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/rqd/rqd/rqmachine.py b/rqd/rqd/rqmachine.py index ef6004866..20cf21964 100644 --- a/rqd/rqd/rqmachine.py +++ b/rqd/rqd/rqmachine.py @@ -774,13 +774,13 @@ def updateWindowsMemory(self): self.__windowsStat = rqd.rqwinutils.MEMORYSTATUSEX() ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(self.__windowsStat)) - stat = self.__windowsStat - temp_path = os.getenv('TEMP') # Windows temp directory - disk_usage = psutil.disk_usage(temp_path) + disk_usage = psutil.disk_usage(self.getTempPath()) self.__renderHost.total_mcp = disk_usage.total // 1024 self.__renderHost.free_mcp = disk_usage.free // 1024 + stat = self.__windowsStat + self.__renderHost.total_mem = int(stat.ullTotalPhys / 1024) self.__renderHost.free_mem = int(stat.ullAvailPhys / 1024) @@ -795,6 +795,7 @@ def updateLinuxMemory(self): """Gets information on system memory for Linux.""" # Reads dynamic information for mcp mcpStat = os.statvfs(self.getTempPath()) + self.__renderHost.total_mcp = (mcpStat.f_blocks * mcpStat.f_frsize) // 1024 self.__renderHost.free_mcp = (mcpStat.f_bavail * mcpStat.f_bsize) // 1024 # Reads dynamic information from /proc/meminfo @@ -849,6 +850,11 @@ def updateMacMemory(self): else: self.__renderHost.free_swap = 0 + # Reads dynamic information for mcp + mcpStat = os.statvfs(self.getTempPath()) + self.__renderHost.total_mcp = (mcpStat.f_blocks * mcpStat.f_frsize) // KILOBYTE + self.__renderHost.free_mcp = (mcpStat.f_bavail * mcpStat.f_bsize) // KILOBYTE + def updateMachineStats(self): """Updates dynamic machine information during runtime"""