@@ -79,6 +79,49 @@ def parse_mdata(raw_input: IO[bytes]) -> Tuple[Dict[str, str], Dict[int, ProcSta
7979 return mdata , procs
8080
8181
82+ def extract_kernel_version (system_info : str ) -> tuple [int , int , int ] | None :
83+ """
84+ Extract kernel version from system info string.
85+
86+ Args:
87+ system_info: String like "Linux apollo 6.12.31 #1-NixOS SMP..."
88+
89+ Returns:
90+ Tuple of (major, minor, patch) version numbers, or None if parsing fails
91+ """
92+ # Match kernel version pattern: major.minor.patch
93+ # Example: "Linux apollo 6.12.31 #1-NixOS SMP Thu May 29 09:03:27 UTC 2025 aarch64 GNU/Linux"
94+ match = re .search (r"Linux\s+\S+\s+(\d+)\.(\d+)\.(\d+)" , system_info )
95+ if match :
96+ return (int (match .group (1 )), int (match .group (2 )), int (match .group (3 )))
97+ return None
98+
99+
100+ def is_eevdf_scheduler (mdata : Dict [str , str ]) -> bool :
101+ """
102+ Determine if the system uses EEVDF scheduler based on kernel version.
103+
104+ EEVDF became the default scheduler in Linux 6.6+.
105+
106+ Args:
107+ mdata: Metadata dictionary containing system info
108+
109+ Returns:
110+ True if EEVDF scheduler is likely in use, False otherwise
111+ """
112+ system_info = mdata .get ("system" , "" )
113+ if not system_info :
114+ return False
115+
116+ version_tuple = extract_kernel_version (system_info )
117+ if not version_tuple :
118+ return False
119+
120+ major , minor , _ = version_tuple
121+ # EEVDF became default in 6.6
122+ return major > 6 or (major == 6 and minor >= 6 )
123+
124+
82125#
83126# Tests
84127#
@@ -125,58 +168,91 @@ def test_parse_mdata(self) -> None:
125168 "perf-sched-cmd" : "perf sched record --mmap-pages 8M sleep 10 --aio" ,
126169 "perf-script-cmd" : "perf script --show-task-events --fields pid,tid,cpu,time,event,trace --ns" ,
127170 }
128- # fmt: off
129- expected_procs = {
130- 1 : ProcStat (
131- 1 , "init" , "S" , 0 , 1 , 1 , 34816 , 1 , 4202752 , 2750 , 3190270 ,
132- 1 , 559 , 2 , 14 , 7921 , 2767 , 20 , 0 , 1 , 0 , 22698 , 28897280 ,
133- 480 , 18446744073709551615 , 94075734745088 , 94075735046540 ,
134- 140731912490512 , 140731912489592 , 140174869709891 , 0 , 0 ,
135- 4096 , 536962595 , 18446744071765192153 , 0 , 0 , 17 , 3 , 0 , 0 ,
136- 0 , 0 , 0 , 94075737145592 , 94075737155264 , 94075757477888 ,
137- 140731912494870 , 140731912494881 , 140731912494881 ,
138- 140731912495085 , 0
171+ import io
172+
173+ mdata , procs = parse_mdata (io .BytesIO (raw_input ))
174+ self .assertEqual (mdata , expected_mdata )
175+ self .assertEqual (len (procs ), 4 )
176+
177+ def test_extract_kernel_version (self ) -> None :
178+ # Test various kernel version formats
179+ test_cases = [
180+ (
181+ "Linux apollo 6.12.31 #1-NixOS SMP Thu May 29 09:03:27 UTC 2025 aarch64 GNU/Linux" ,
182+ (6 , 12 , 31 ),
139183 ),
140- 10236 : ProcStat (
141- 10236 , "wanphy_proc" , "S" , 3901 , 10236 , 3806 , 0 , - 1 ,
142- 4202752 , 5174 , 1808 , 0 , 0 , 38 , 7 , 0 , 0 , 20 , 0 , 6 ,
143- 0 , 34222 , 8171171840 , 4333 , 18446744073709551615 ,
144- 93970763452416 , 93970763463572 , 140723891487136 ,
145- 140723891485840 , 140083330865987 , 0 , 0 , 0 , 17582 ,
146- 18446744073709551615 , 0 , 0 , 17 , 2 , 0 , 0 , 0 , 0 , 0 ,
147- 93970765561856 , 93970765563680 , 93970770280448 ,
148- 140723891489507 , 140723891489519 , 140723891489519 ,
149- 140723891490787 , 0
184+ (
185+ "Linux xr-vm_node0_RSP0_CPU0 3.14.23-WR7.0.0.2_standard #1 SMP Wed Feb 19 08:56:10 PST 2020 x86_64 x86_64 x86_64 GNU/Linux" ,
186+ (3 , 14 , 23 ),
150187 ),
151- 10237 : ProcStat (
152- 10237 , "ssh_server" , "S" , 3901 , 10237 , 3806 , 0 , - 1 ,
153- 4202752 , 7386 , 10556 , 0 , 1 , 67 , 14 , 65 , 15 , 20 , 0 ,
154- 12 , 0 , 34223 , 8826036224 , 6216 , 18446744073709551615 ,
155- 94165094514688 , 94165094747684 , 140724922712336 ,
156- 140724922710704 , 140635724155715 , 0 , 88583 , 0 , 17582 ,
157- 18446744073709551615 , 0 , 0 , 17 , 0 , 0 , 0 , 0 , 0 , 0 ,
158- 94165096844840 , 94165096873280 , 94165117935616 ,
159- 140724922718949 , 140724922718960 , 140724922718960 ,
160- 140724922720228 , 0
188+ (
189+ "Linux hostname 5.4.0-74-generic #83-Ubuntu SMP Mon May 17 02:39:06 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux" ,
190+ (5 , 4 , 0 ),
161191 ),
162- 10238 : ProcStat (
163- 10238 , "ssh_backup_serv" , "S" , 3901 , 10238 , 3806 , 0 ,
164- - 1 , 4202752 , 6298 , 1810 , 0 , 0 , 59 , 9 , 0 , 0 , 20 , 0 ,
165- 9 , 0 , 34223 , 8595910656 , 5380 , 18446744073709551615 ,
166- 94686349664256 , 94686349760644 , 140721224446864 ,
167- 140721224445456 , 140667692329795 , 0 , 88583 , 0 , 17582 ,
168- 18446744073709551615 , 0 , 0 , 17 , 1 , 0 , 0 , 0 , 0 , 0 ,
169- 94686351857800 , 94686351875360 , 94686377046016 ,
170- 140721224452823 , 140721224452841 , 140721224452841 ,
171- 140721224454109 , 0
192+ (
193+ "Linux test 6.6.0 #1 SMP PREEMPT_DYNAMIC Mon Oct 2 14:58:11 UTC 2023 x86_64 GNU/Linux" ,
194+ (6 , 6 , 0 ),
172195 ),
173- }
174- # fmt: on
175- import io
196+ ( "Invalid format" , None ),
197+ ( "" , None ),
198+ ]
176199
177- mdata , procs = parse_mdata (io .BytesIO (raw_input ))
178- self .assertEqual (mdata , expected_mdata )
179- self .assertEqual (procs , expected_procs )
200+ for system_info , expected in test_cases :
201+ with self .subTest (system_info = system_info ):
202+ result = extract_kernel_version (system_info )
203+ self .assertEqual (result , expected )
204+
205+ def test_is_eevdf_scheduler (self ) -> None :
206+ # Test EEVDF detection based on kernel version
207+ test_cases = [
208+ # EEVDF cases (6.6+)
209+ (
210+ {
211+ "system" : "Linux apollo 6.12.31 #1-NixOS SMP Thu May 29 09:03:27 UTC 2025 aarch64 GNU/Linux"
212+ },
213+ True ,
214+ ),
215+ (
216+ {
217+ "system" : "Linux test 6.6.0 #1 SMP PREEMPT_DYNAMIC Mon Oct 2 14:58:11 UTC 2023 x86_64 GNU/Linux"
218+ },
219+ True ,
220+ ),
221+ (
222+ {
223+ "system" : "Linux host 7.0.1 #1 SMP Mon Jan 1 00:00:00 UTC 2024 x86_64 GNU/Linux"
224+ },
225+ True ,
226+ ),
227+ # CFS cases (< 6.6)
228+ (
229+ {
230+ "system" : "Linux xr-vm_node0_RSP0_CPU0 3.14.23-WR7.0.0.2_standard #1 SMP Wed Feb 19 08:56:10 PST 2020 x86_64 x86_64 x86_64 GNU/Linux"
231+ },
232+ False ,
233+ ),
234+ (
235+ {
236+ "system" : "Linux hostname 5.4.0-74-generic #83-Ubuntu SMP Mon May 17 02:39:06 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux"
237+ },
238+ False ,
239+ ),
240+ (
241+ {
242+ "system" : "Linux test 6.5.9 #1 SMP Mon Oct 2 14:58:11 UTC 2023 x86_64 GNU/Linux"
243+ },
244+ False ,
245+ ),
246+ # Edge cases
247+ ({"system" : "Invalid format" }, False ),
248+ ({"system" : "" }, False ),
249+ ({}, False ),
250+ ]
251+
252+ for mdata , expected in test_cases :
253+ with self .subTest (mdata = mdata ):
254+ result = is_eevdf_scheduler (mdata )
255+ self .assertEqual (result , expected )
180256
181257
182258if __name__ == "__main__" :
0 commit comments