1#!/usr/bin/env python3

2"""

3 cpu_topology.py

4 Written by Jeffrey Lane <jeffrey.lane@canonical.com>

5"""

6 import sys

7 import os

8 import re

9

10

11 class proc_cpuinfo:

12 """

13 Class to get and handle information from /proc/cpuinfo

14 Creates a dictionary of data gleaned from that file.

15 """

16

17 def __init__(self):

18 self.cpuinfo = {}

19 cpu_fh = open("/proc/cpuinfo", "r")

20 try:

21 temp = cpu_fh.readlines()

22 finally:

23 cpu_fh.close()

24

25 r_s390 = re.compile(r"processor [0-9]")

26 r_x86 = re.compile(r"processor\s+:")

27 for i in temp:

28 # Handle s390 first

29 if r_s390.match(i):

30 cpu_num = i.split(":")[0].split()[1].strip()

31 key = "cpu" + cpu_num

32 self.cpuinfo[key] = {

33 "core_id": cpu_num,

34 "physical_package_id": cpu_num,

35 }

36 elif r_x86.match(i):

37 key = "cpu" + (i.split(":")[1].strip())

38 self.cpuinfo[key] = {"core_id": "", "physical_package_id": ""}

39 elif i.startswith("core id"):

40 self.cpuinfo[key].update({"core_id": i.split(":")[1].strip()})

41 elif i.startswith("physical id"):

42 self.cpuinfo[key].update(

43 {"physical_package_id": i.split(":")[1].strip()}

44 )

45 else:

46 continue

47

48

49 class sysfs_cpu:

50 """

51 Class to get and handle information from sysfs as relates to CPU topology

52 Creates an informational class to present information on various CPUs

53 """

54

55 def __init__(self, proc):

56 self.syscpu = {}

57 self.path = "/sys/devices/system/cpu/" + proc + "/topology"

58 items = ["core_id", "physical_package_id"]

59 for i in items:

60 try:

61 syscpu_fh = open(os.path.join(self.path, i), "r")

62 except OSError as e:

63 print("ERROR: %s" % e)

64 sys.exit(1)

65 else:

66 self.syscpu[i] = syscpu_fh.readline().strip()

67 syscpu_fh.close()

68

69

70 def compare(proc_cpu, sys_cpu):

71 cpu_map = {}

72 """

73 If there is only 1 CPU the test don't look for core_id

74 and physical_package_id because those information are absent in

75 /proc/cpuinfo on singlecore system

76 """

77 for key in proc_cpu.keys():

78 if "cpu1" not in proc_cpu:

79 cpu_map[key] = True

80 else:

81 for subkey in proc_cpu[key].keys():

82 if proc_cpu[key][subkey] == sys_cpu[key][subkey]:

83 cpu_map[key] = True

84 else:

85 cpu_map[key] = False

86 return cpu_map

87

88

89 def main():

90 cpuinfo = proc_cpuinfo()

91 sys_cpu = {}

92 keys = cpuinfo.cpuinfo.keys()

93 for k in keys:

94 sys_cpu[k] = sysfs_cpu(k).syscpu

95 cpu_map = compare(cpuinfo.cpuinfo, sys_cpu)

96 if False in cpu_map.values() or len(cpu_map) < 1:

97 print("FAIL: CPU Topology is incorrect", file=sys.stderr)

98 print("-" * 52, file=sys.stderr)

99 print(

100 "{0}{1}".format("/proc/cpuinfo".center(30), "sysfs".center(25)),

101 file=sys.stderr,

102 )

103 print(

104 "{0}{1}{2}{3}{1}{2}".format(

105 "CPU".center(6),

106 "Physical ID".center(13),

107 "Core ID".center(9),

108 "|".center(3),

109 ),

110 file=sys.stderr,

111 )

112 for key in sorted(sys_cpu.keys()):

113 print(

114 "{0}{1}{2}{3}{4}{5}".format(

115 key.center(6),

116 cpuinfo.cpuinfo[key]["physical_package_id"].center(13),

117 cpuinfo.cpuinfo[key]["core_id"].center(9),

118 "|".center(3),

119 sys_cpu[key]["physical_package_id"].center(13),

120 sys_cpu[key]["core_id"].center(9),

121 ),

122 file=sys.stderr,

123 )

124 return 1

125 else:

126 return 0

127

128

129 if __name__ == "__main__":

130 sys.exit(main())