2 ''' Reusable functions related to sched mc FVT are put together
10 __author__
= "Vaidyanathan Srinivasan <svaidy@linux.vnet.ibm.com>"
11 __author__
= "Poornima Nayak <mpnayak@linux.vnet.ibm.com>"
24 intr_stat_timer_0
= []
32 os
.system('dmesg -c >/dev/null')
34 print 'Clearing dmesg failed', e
38 ''' Returns number of cpu's in system
41 cpuinfo
= open('/proc/cpuinfo', 'r')
44 if line
.startswith('processor'):
48 print "Could not get cpu count", e
51 def count_num_sockets():
52 ''' Returns number of cpu's in system
57 for i
in range(0, cpu_count
):
58 phy_pkg_file
= '/sys/devices/system/cpu/cpu%s' % i
59 phy_pkg_file
+= '/topology/physical_package_id'
60 socket_id
= open(phy_pkg_file
).read().rstrip()
61 if socket_id
not in socket_list
:
62 socket_list
.append(socket_id
)
63 socket_count
= socket_count
+ 1
64 except Exception, details
:
65 print "INFO: Failed to get number of sockets in system", details
68 def is_multi_socket():
69 '''Return 1 if the system is multi socket else return 0
77 print "Failed to check if system is multi socket system"
80 def is_hyper_threaded():
81 '''Return 1 if the system is hyper threaded else return 0
84 file_cpuinfo
= open("/proc/cpuinfo", 'r')
85 for line
in file_cpuinfo
:
86 if line
.startswith('siblings'):
87 siblings
= line
.split(":")
88 if line
.startswith('cpu cores'):
89 cpu_cores
= line
.split(":")
91 if int( siblings
[1] ) / int( cpu_cores
[1] )> 1:
97 print "Failed to check if system is hyper-threaded"
101 ''' Return true if system has sockets has multiple cores
105 file_cpuinfo
= open("/proc/cpuinfo", 'r')
106 for line
in file_cpuinfo
:
107 if line
.startswith('siblings'):
108 siblings
= line
.split(":")
109 if line
.startswith('cpu cores'):
110 cpu_cores
= line
.split(":")
113 if int( siblings
[1] ) == int( cpu_cores
[1] ):
114 if int( cpu_cores
[1] ) > 1:
119 num_of_cpus
= int(siblings
[1]) / int(cpu_cores
[1])
127 print "Failed to check if system is multi core system"
130 def get_hyper_thread_count():
131 ''' Return number of threads in CPU. For eg for x3950 this function
132 would return 2. In future if 4 threads are supported in CPU, this
133 routine would return 4
136 file_cpuinfo
= open("/proc/cpuinfo", 'r')
137 for line
in file_cpuinfo
:
138 if line
.startswith('siblings'):
139 siblings
= line
.split(":")
140 if line
.startswith('cpu cores'):
141 cpu_cores
= line
.split(":")
143 return( int( siblings
[1] ) / int( cpu_cores
[1] ) )
145 print "Failed to check if system is hyper-threaded"
148 def map_cpuid_pkgid():
149 ''' Routine to map physical package id to cpu id
151 if is_hyper_threaded():
154 for i
in range(0, cpu_count
):
155 phy_pkg_file
= '/sys/devices/system/cpu/cpu%s' % i
156 phy_pkg_file
+= '/topology/physical_package_id'
157 core_file
= '/sys/devices/system/cpu/cpu%s' % i
158 core_file
+= '/topology/core_id'
159 core_id
= open(core_file
).read().rstrip()
160 cpu_phy_id
= open(phy_pkg_file
).read().rstrip()
161 if not cpu_phy_id
in cpu_map
.keys():
163 if not core_id
in core_info
.keys():
164 core_info
[core_id
] = [i
]
166 core_info
[core_id
].append(i
)
167 if not cpu_phy_id
in cpu_map
.keys():
168 cpu_map
[cpu_phy_id
]= core_info
169 except Exception, details
:
170 print "Package, core & cpu map table creation failed", e
173 for i
in range(0, cpu_count
):
175 phy_pkg_file
= '/sys/devices/system/cpu/cpu%s' %i
176 phy_pkg_file
+= '/topology/physical_package_id'
177 cpu_phy_id
= open(phy_pkg_file
).read().rstrip()
178 if not cpu_phy_id
in cpu_map
.keys():
179 cpu_map
[cpu_phy_id
] = [i
]
181 cpu_map
[cpu_phy_id
].append(i
)
183 print "Mapping of CPU to pkg id failed", e
187 def generate_sibling_list():
188 ''' Routine to generate siblings list
191 for i
in range(0, cpu_count
):
192 siblings_file
= '/sys/devices/system/cpu/cpu%s' % i
193 siblings_file
+= '/topology/thread_siblings_list'
194 threads_sibs
= open(siblings_file
).read().rstrip()
195 thread_ids
= threads_sibs
.split("-")
197 if not thread_ids
in siblings_list
:
198 siblings_list
.append(thread_ids
)
199 except Exception, details
:
200 print "Exception in generate_siblings_list", details
203 def get_siblings(cpu_id
):
204 ''' Return siblings of cpu_id
208 for i
in range(0, len(siblings_list
)):
209 for cpu
in siblings_list
[i
]:
211 for j
in siblings_list
[i
]:
212 # Exclude cpu_id in the list of siblings
217 except Exception, details
:
218 print "Exception in get_siblings", details
221 def get_proc_data(stats_list
):
222 ''' Read /proc/stat info and store in dictionary
225 file_procstat
= open("/proc/stat", 'r')
226 for line
in file_procstat
:
227 if line
.startswith('cpu'):
229 stats_list
[data
[0]] = data
230 file_procstat
.close()
232 print "Could not read statistics", e
235 def get_proc_loc_count(loc_stats
):
236 ''' Read /proc/interrupts info and store in list
239 file_procstat
= open("/proc/interrupts", 'r')
240 for line
in file_procstat
:
241 if line
.startswith(' LOC:') or line
.startswith('LOC:'):
243 for i
in range(0, cpu_count
):
245 loc_stats
.append(data
[i
+1])
246 file_procstat
.close()
248 except Exception, details
:
249 print "Could not read interrupt statistics", details
253 def set_sched_mc_power(sched_mc_level
):
254 ''' Routine to set sched_mc_power_savings to required level
257 os
.system('echo %s > \
258 /sys/devices/system/cpu/sched_mc_power_savings 2>/dev/null'
261 get_proc_data(stats_start
)
263 print "Could not set sched_mc_power_savings to", sched_mc_level
, e
266 def set_sched_smt_power(sched_smt_level
):
267 ''' Routine to set sched_smt_power_savings to required level
270 os
.system('echo %s > \
271 /sys/devices/system/cpu/sched_smt_power_savings 2>/dev/null'
274 get_proc_data(stats_start
)
276 print "Could not set sched_smt_power_savings to", sched_smt_level
, e
279 def set_timer_migration_interface(value
):
280 ''' Set value of timer migration interface to a value
284 os
.system('echo %s > \
285 /proc/sys/kernel/timer_migration 2>/dev/null' % value
)
287 print "Could not set timer_migration to ", value
, e
290 def get_job_count(stress
, workload
, sched_smt
):
291 ''' Returns number of jobs/threads to be triggered
295 if stress
== "thread":
296 threads
= get_hyper_thread_count()
297 if stress
== "partial":
298 threads
= cpu_count
/ socket_count
299 if is_hyper_threaded():
300 if workload
== "ebizzy" and int(sched_smt
) ==0:
301 threads
= threads
/ get_hyper_thread_count()
302 if workload
== "kernbench" and int(sched_smt
) < 2:
303 threads
= threads
/ get_hyper_thread_count()
306 if stress
== "single_job":
310 except Exception, details
:
311 print "get job count failed ", details
314 def trigger_ebizzy (sched_smt
, stress
, duration
, background
, pinned
):
315 ''' Triggers ebizzy workload for sched_mc=1
319 threads
= get_job_count(stress
, "ebizzy", sched_smt
)
321 path
= '%s/utils/benchmark' % os
.environ
['LTPROOT']
327 # Use the latest version of similar workload available
328 for file_name
in os
.listdir('.'):
329 if file_name
.find(workload
) != -1:
330 wklds_avlbl
.append(file_name
)
333 workload_dir
= wklds_avlbl
[len(wklds_avlbl
)-1]
334 if workload_dir
!= "":
335 new_path
= os
.path
.join(path
,"%s" % workload_dir
)
336 get_proc_data(stats_start
)
337 get_proc_loc_count(intr_start
)
340 if background
== "yes":
341 succ
= os
.system('./ebizzy -t%s -s4096 -S %s >/dev/null &'
342 % (threads
, duration
))
345 succ
= os
.system('taskset -c %s ./ebizzy -t%s -s4096 -S %s >/dev/null'
346 % (cpu_count
-1, threads
, duration
))
348 succ
= os
.system('./ebizzy -t%s -s4096 -S %s >/dev/null'
349 % (threads
, duration
))
352 print "INFO: ebizzy workload triggerd"
354 #Commented bcoz it doesnt make sense to capture it when workload triggered
356 #get_proc_loc_count(intr_stop)
357 #get_proc_data(stats_stop)
359 print "INFO: ebizzy workload triggerd failed"
362 except Exception, details
:
363 print "Ebizzy workload trigger failed ", details
365 except Exception, details
:
366 print "Ebizzy workload trigger failed ", details
369 def trigger_kernbench (sched_smt
, stress
, background
, pinned
, perf_test
):
370 ''' Trigger load on system like kernbench.
371 Copys existing copy of LTP into as LTP2 and then builds it
376 threads
= get_job_count(stress
, "kernbench", sched_smt
)
380 path
= '%s/utils/benchmark' % os
.environ
['LTPROOT']
383 for file_name
in os
.listdir('.'):
384 if file_name
.find("kernbench") != -1:
385 wklds_avlbl
.append(file_name
)
388 workload_dir
= wklds_avlbl
[len(wklds_avlbl
)-1]
389 if workload_dir
!= "":
390 benchmark_path
= os
.path
.join(path
,"%s" % workload_dir
)
392 print "INFO: kernbench benchmark not found"
398 for file_name
in os
.listdir('.'):
399 if file_name
.find("linux-2.6") != -1 and os
.path
.isdir(file_name
):
400 linux_source_dir
=file_name
402 if linux_source_dir
!= "":
403 os
.chdir(linux_source_dir
)
405 print "INFO: Linux kernel source not found in /root. Workload\
406 Kernbench cannot be executed"
409 get_proc_data(stats_start
)
410 get_proc_loc_count(intr_start
)
412 os
.system ( 'taskset -c %s %s/kernbench -o %s -M -H -n 1 \
413 >/dev/null 2>&1 &' % (cpu_count
-1, benchmark_path
, threads
))
415 # We have to delete import in future
418 stop_wkld("kernbench")
420 if background
== "yes":
421 os
.system ( '%s/kernbench -o %s -M -H -n 1 >/dev/null 2>&1 &' \
422 % (benchmark_path
, threads
))
424 if perf_test
== "yes":
425 os
.system ( '%s/kernbench -o %s -M -H -n 1 >/dev/null 2>&1' \
426 % (benchmark_path
, threads
))
428 os
.system ( '%s/kernbench -o %s -M -H -n 1 >/dev/null 2>&1 &' \
429 % (benchmark_path
, threads
))
430 # We have to delete import in future
433 stop_wkld("kernbench")
435 print "INFO: Workload kernbench triggerd"
437 except Exception, details
:
438 print "Workload kernbench trigger failed ", details
441 def trigger_workld(sched_smt
, workload
, stress
, duration
, background
, pinned
, perf_test
):
442 ''' Triggers workload passed as argument. Number of threads
443 triggered is based on stress value.
446 if workload
== "ebizzy":
447 trigger_ebizzy (sched_smt
, stress
, duration
, background
, pinned
)
448 if workload
== "kernbench":
449 trigger_kernbench (sched_smt
, stress
, background
, pinned
, perf_test
)
450 except Exception, details
:
451 print "INFO: Trigger workload failed", details
454 def generate_report():
455 ''' Generate report of CPU utilization
457 cpu_labels
= ('cpu', 'user', 'nice', 'system', 'idle', 'iowait', 'irq',
459 if (not os
.path
.exists('/procstat')):
460 os
.mkdir('/procstat')
462 get_proc_data(stats_stop
)
464 reportfile
= open('/procstat/cpu-utilisation', 'a')
465 debugfile
= open('/procstat/cpu-utilisation.debug', 'a')
469 for i
in range(1, len(stats_stop
[l
])):
470 stats_stop
[l
][i
] = int(stats_stop
[l
][i
]) - int(stats_start
[l
][i
])
471 total
+= stats_stop
[l
][i
]
472 percentage_list
.append(l
)
473 for i
in range(1, len(stats_stop
[l
])):
474 percentage_list
.append(float(stats_stop
[l
][i
])*100/total
)
476 stats_percentage
[l
] = percentage_list
478 for i
in range(0, len(cpu_labels
)):
479 print >> debugfile
, cpu_labels
[i
], '\t',
481 for l
in sorted(stats_stop
.keys()):
482 print >> debugfile
, l
, '\t',
483 for i
in range(1, len(stats_stop
[l
])):
484 print >> debugfile
, stats_stop
[l
][i
], '\t',
487 for i
in range(0, len(cpu_labels
)):
488 print >> reportfile
, cpu_labels
[i
], '\t',
490 for l
in sorted(stats_percentage
.keys()):
491 print >> reportfile
, l
, '\t',
492 for i
in range(1, len(stats_percentage
[l
])):
493 print >> reportfile
, " %3.4f" % stats_percentage
[l
][i
],
496 #Now get the package ID information
498 print >> debugfile
, "cpu_map: ", cpu_map
499 keyvalfile
= open('/procstat/keyval', 'a')
500 print >> keyvalfile
, "nr_packages=%d" % len(cpu_map
)
501 print >> keyvalfile
, "system-idle=%3.4f" % (stats_percentage
['cpu'][4])
502 for pkg
in sorted(cpu_map
.keys()):
503 if is_hyper_threaded():
504 for core
in sorted(cpu_map
[pkg
].keys()):
507 for cpu
in cpu_map
[pkg
][core
]:
508 total_idle
+= stats_stop
["cpu%d" % cpu
][4]
509 for i
in range(1, len(stats_stop
["cpu%d" % cpu
])):
510 total
+= stats_stop
["cpu%d" % cpu
][i
]
514 for cpu
in cpu_map
[pkg
]:
515 total_idle
+= stats_stop
["cpu%d" % cpu
][4]
516 for i
in range(1, len(stats_stop
["cpu%d" % cpu
])):
517 total
+= stats_stop
["cpu%d" % cpu
][i
]
518 print >> reportfile
, "Package: ", pkg
, "Idle %3.4f%%" \
519 % (float(total_idle
)*100/total
)
520 print >> keyvalfile
, "package-%s=%3.4f" % \
521 (pkg
, (float(total_idle
)*100/total
))
522 except Exception, details
:
523 print "Generating utilization report failed: ", details
526 #Add record delimiter '\n' before closing these files
534 def generate_loc_intr_report():
535 ''' Generate interrupt report of CPU's
538 if (not os
.path
.exists('/procstat')):
539 os
.mkdir('/procstat')
541 get_proc_loc_count(intr_stop
)
543 reportfile
= open('/procstat/cpu-loc_interrupts', 'a')
544 print >> reportfile
, "=============================================="
545 print >> reportfile
, " Local timer interrupt stats "
546 print >> reportfile
, "=============================================="
548 for i
in range(0, cpu_count
):
549 intr_stop
[i
] = int(intr_stop
[i
]) - int(intr_start
[i
])
550 print >> reportfile
, "CPU%s: %s" %(i
, intr_stop
[i
])
553 except Exception, details
:
554 print "Generating interrupt report failed: ", details
557 def record_loc_intr_count():
558 ''' Record Interrupt statistics when timer_migration
562 global intr_start
, intr_stop
563 for i
in range(0, cpu_count
):
564 intr_stat_timer_0
.append(intr_stop
[i
])
567 except Exception, details
:
568 print "INFO: Record interrupt statistics when timer_migration=0",details
570 def expand_range(range_val
):
572 Expand the range of value into actual numbers
576 sep_comma
= range_val
.split(",")
577 for i
in range(0, len(sep_comma
)):
578 hyphen_values
= sep_comma
[i
].split("-")
579 if len(hyphen_values
) == 1:
580 ids_list
.append(int(hyphen_values
[0]))
582 for j
in range(int(hyphen_values
[0]), int(hyphen_values
[1])+1):
585 except Exception, details
:
586 print "INFO: expand_pkg_grps failed ", details
590 Read /proc/cpuinfo and check if system is Quad core
593 cpuinfo
= open('/proc/cpuinfo', 'r')
595 if line
.startswith('cpu cores'):
596 cores
= line
.split("cpu cores")
597 num_cores
= cores
[1].split(":")
599 if int(num_cores
[1]) == 4:
604 print "Failed to get cpu core information", e
607 def validate_cpugrp_map(cpu_group
, sched_mc_level
, sched_smt_level
):
609 Verify if cpugrp belong to same package
611 modi_cpu_grp
= cpu_group
[:]
613 if is_hyper_threaded():
614 for pkg
in sorted(cpu_map
.keys()):
615 # if CPU utilized is across package this condition will be true
616 if len(modi_cpu_grp
) != len(cpu_group
):
618 for core
in sorted(cpu_map
[pkg
].keys()):
619 core_cpus
= cpu_map
[pkg
][core
]
620 if core_cpus
== modi_cpu_grp
:
623 #if CPUs used across the cores
624 for i
in range(0, len(core_cpus
)):
625 if core_cpus
[i
] in modi_cpu_grp
:
626 modi_cpu_grp
.remove(core_cpus
[i
])
627 if len(modi_cpu_grp
) == 0:
629 #This code has to be deleted
631 # If sched_smt == 0 then its oky if threads run
632 # in different cores of same package
633 #if sched_smt_level > 0 :
636 for pkg
in sorted(cpu_map
.keys()):
637 pkg_cpus
= cpu_map
[pkg
]
638 if len(cpu_group
) == len(pkg_cpus
):
639 if pkg_cpus
== cpu_group
:
642 if int(cpus_utilized
[0]) in cpu_map
[pkg
] or int(cpus_utilized
[1]) in cpu_map
[pkg
]:
647 except Exception, details
:
648 print "Exception in validate_cpugrp_map: ", details
652 def verify_sched_domain_dmesg(sched_mc_level
, sched_smt_level
):
654 Read sched domain information from dmesg.
658 dmesg_info
= os
.popen('dmesg').read()
660 lines
= dmesg_info
.split('\n')
661 for i
in range(0, len(lines
)):
662 if lines
[i
].endswith('CPU'):
663 groups
= lines
[i
+1].split("groups:")
664 group_info
= groups
[1]
665 if group_info
.find("(") != -1:
666 openindex
=group_info
.index("(")
667 closeindex
=group_info
.index(")")
668 group_info
=group_info
.replace\
669 (group_info
[openindex
:closeindex
+1],"")
671 subgroup
= group_info
.split()
672 for j
in range(0, len(subgroup
)):
673 cpu_group
= expand_range(subgroup
[j
])
674 status
= validate_cpugrp_map(cpu_group
, sched_mc_level
,\
677 if is_quad_core() == 1:
678 if int(sched_mc_level
) == 0:
687 except Exception, details
:
688 print "Reading dmesg failed", details
691 def get_cpu_utilization(cpu
):
692 ''' Return cpu utilization of cpu_id
695 for l
in sorted(stats_percentage
.keys()):
696 if cpu
== stats_percentage
[l
][0]:
697 return stats_percentage
[l
][1]
699 except Exception, details
:
700 print "Exception in get_cpu_utilization", details
703 def validate_cpu_consolidation(stress
, work_ld
, sched_mc_level
, sched_smt_level
):
704 ''' Verify if cpu's on which threads executed belong to same
707 cpus_utilized
= list()
708 threads
= get_job_count(stress
, work_ld
, sched_smt_level
)
710 for l
in sorted(stats_percentage
.keys()):
712 cpu_id
= stats_percentage
[l
][0].split("cpu")
715 if int(cpu_id
[1]) in cpus_utilized
:
717 if is_hyper_threaded():
718 if work_ld
== "kernbench" and sched_smt_level
< sched_mc_level
:
719 siblings
= get_siblings(cpu_id
[1])
721 sib_list
= siblings
.split()
722 utilization
= int(stats_percentage
[l
][1])
723 for i
in range(0, len(sib_list
)):
724 utilization
+= int(get_cpu_utilization("cpu%s" %sib
_list
[i
]))
726 utilization
= stats_percentage
[l
][1]
728 cpus_utilized
.append(int(cpu_id
[1]))
730 for i
in range(0, len(sib_list
)):
731 cpus_utilized
.append(int(sib_list
[i
]))
733 # This threshold wuld be modified based on results
734 if stats_percentage
[l
][1] > 40:
735 cpus_utilized
.append(int(cpu_id
[1]))
737 if work_ld
== "kernbench" :
738 if stats_percentage
[l
][1] > 50:
739 cpus_utilized
.append(int(cpu_id
[1]))
741 if stats_percentage
[l
][1] > 70:
742 cpus_utilized
.append(int(cpu_id
[1]))
744 print "INFO: CPU's utilized ", cpus_utilized
746 # If length of CPU's utilized is not = number of jobs exit with 1
747 if len(cpus_utilized
) < threads
:
750 status
= validate_cpugrp_map(cpus_utilized
, sched_mc_level
, \
753 print "INFO: CPUs utilized is not in same package or core"
756 except Exception, details
:
757 print "Exception in validate_cpu_consolidation: ", details
760 def get_cpuid_max_intr_count():
761 '''Return the cpu id's of two cpu's with highest number of intr'''
767 #Skipping CPU0 as it is generally high
768 for i
in range(1, cpu_count
):
769 if int(intr_stop
[i
]) > int(highest
):
771 second_highest
= highest
772 cpu2_max_intr
= cpu1_max_intr
773 highest
= int(intr_stop
[i
])
776 if int(intr_stop
[i
]) > int(second_highest
):
777 second_highest
= int(intr_stop
[i
])
779 cpus_utilized
.append(cpu1_max_intr
)
780 cpus_utilized
.append(cpu2_max_intr
)
782 for i
in range(1, cpu_count
):
783 if i
!= cpu1_max_intr
and i
!= cpu2_max_intr
:
784 diff
= second_highest
- intr_stop
[i
]
785 ''' Threshold of difference has to be manipulated '''
787 print "INFO: Diff in interrupt count is below threshold"
790 print "INFO: Interrupt count in other CPU's low as expected"
792 except Exception, details
:
793 print "Exception in get_cpuid_max_intr_count: ", details
796 def validate_ilb (sched_mc_level
, sched_smt_level
):
797 ''' Validate if ilb is running in same package where work load is running
800 cpus_utilized
= get_cpuid_max_intr_count()
801 if not cpus_utilized
:
804 status
= validate_cpugrp_map(cpus_utilized
, sched_mc_level
, sched_smt_level
)
806 except Exception, details
:
807 print "Exception in validate_ilb: ", details
811 ''' Routine to reset sched_mc_power_savings to Zero level
814 os
.system('echo 0 > \
815 /sys/devices/system/cpu/sched_mc_power_savings 2>/dev/null')
817 print "Could not set sched_mc_power_savings to 0", e
820 def reset_schedsmt():
821 ''' Routine to reset sched_smt_power_savings to Zero level
824 os
.system('echo 0 > \
825 /sys/devices/system/cpu/sched_smt_power_savings 2>/dev/null')
827 print "Could not set sched_smt_power_savings to 0", e
830 def stop_wkld(work_ld
):
831 ''' Kill workload triggered in background
834 os
.system('pkill %s 2>/dev/null' %work_ld
)
835 if work_ld
== "kernbench":
836 os
.system('pkill make 2>/dev/null')
838 print "Exception in stop_wkld", e