5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
22 class CoreHandler(object):
27 def hex_to_set(hexstr):
28 hexn = int(hexstr, 16)
31 for i in range(0, 64):
38 def set_to_hex(cpuset):
43 return '0x{:x}'.format(cpumask)
46 def string_to_set(cpustr):
47 if cpustr == '' or cpustr is None:
48 raise Exception("Empty string")
50 cpuset_reject_ids = set()
51 for rule in cpustr.split(','):
56 # Note the count limit in the .split() call
57 range_parts = rule.split('-', 1)
58 if len(range_parts) > 1:
59 # So, this was a range; start by converting the parts to ints
61 start, end = [int(p.strip()) for p in range_parts]
63 raise Exception("Invalid range expression {}".format(rule))
64 # Make sure it's a valid range
66 raise Exception("Invalid range expression (start > end): {}".format(rule))
67 # Add available CPU ids to set
68 cpuset_ids |= set(range(start, end + 1))
70 # Not a range, the rule is an exclusion rule; convert to int
72 cpuset_reject_ids.add(int(rule[1:].strip()))
74 raise Exception("Invalid exclusion expression {}".format(rule))
76 # OK, a single CPU to include; convert to int
78 cpuset_ids.add(int(rule))
80 raise Exception("Invalid inclusion expression {}".format(rule))
82 # Use sets to handle the exclusion rules for us
83 cpuset_ids -= cpuset_reject_ids
87 def set_to_string(cpuset):
90 for cpuindex in sorted(cpuset):
91 if previndex is None or previndex != (cpuindex - 1):
93 ranges[-1].append(cpuindex)
99 parts.append(str(entry[0]))
101 parts.append("{}-{}".format(entry[0], entry[len(entry) - 1]))
102 return ",".join(parts)
104 def hex_to_string(self, hexstr):
106 :param hexstr: CPU mask as hex string
107 :returns: a formatted CPU range string
109 cpuset = self.hex_to_set(hexstr)
110 return self.set_to_string(cpuset)
112 def string_to_hex(self, cpustr):
113 cpuset = self.string_to_set(cpustr)
114 return self.set_to_hex(cpuset)
117 class OvsVsctl(object):
118 def __init__(self, cores, pcore, tcore, sockets):
121 self.threads_per_core = tcore
122 self.sockets = sockets
124 def is_hyperthreading_enabled(self):
125 if int(self.threads_per_core) >= 2:
129 def is_single_socket(self):
130 if int(self.sockets) == 1:
135 def get_value(field):
136 """Get value for specified field in Open_vSwitch other_config.
138 Value without quotes or newlines
139 None if field is not set
142 current_value = subprocess.check_output(["ovs-vsctl", "get", "Open_vSwitch", ".", "other_config:{}".format(field)])
145 return current_value.lstrip('\"').strip('\n').rstrip('\"')
147 def set_pmd_cpu_mask(self, value):
148 """Set DPDK core mask."""
149 current_value = self.get_value('pmd-cpu-mask')
150 print "INFO: New core mask {}, current_value {}".format(value, current_value)
151 if current_value == value:
154 subprocess.check_output(["ovs-vsctl", "set", "Open_vSwitch", ".", "other_config:pmd-cpu-mask=\"{}\"".format(value)])
159 def set_lcore_mask(self):
160 """Set DPDK library mask."""
161 #if self.is_single_socket():
163 # TODO: measure if it would be beneficial to reserve more cores and from second socket
164 current_value = self.get_value('dpdk-lcore-mask')
165 print "INFO: Mask {}, current_value {}".format(mask, current_value)
167 if current_value == mask:
170 subprocess.check_output(["ovs-vsctl", "set", "Open_vSwitch", ".", "other_config:dpdk-lcore-mask=\"{}\"".format(mask)])
175 def set_socket_mem(self, value):
176 """Set DPDK memory."""
177 if self.is_single_socket():
178 mem = '{0},0'.format(value)
180 mem = '{0},{0}'.format(value)
181 current_value = self.get_value('dpdk-socket-mem')
182 print "INFO: New mem {}, current_value {}".format(mem, current_value)
184 if current_value == mem:
187 subprocess.check_output(["ovs-vsctl", "set", "Open_vSwitch", ".", "other_config:dpdk-socket-mem=\"{}\"".format(mem)])
192 def enable_dpdk(self):
194 current_value = self.get_value('dpdk-init')
195 print "INFO: Enable DPDK, current_value {}".format(current_value)
196 if current_value == 'true':
200 with open('/etc/performance-nodes/dpdk.enabled', 'a'):
209 parser = argparse.ArgumentParser()
210 parser.add_argument('--dpdkcores', dest='dpdkcores', help='DPDK cores', required=False, type=str)
211 parser.add_argument('--cores', dest='cores', help='Logical cores', required=False, type=str)
212 parser.add_argument('--pcore', dest='pcore', help='Cores per processor', required=False, type=str)
213 parser.add_argument('--tcore', dest='tcore', help='Threads per core', required=False, type=str)
214 parser.add_argument('--sockets', dest='sockets', help='Number of sockets', required=False, type=str)
215 parser.add_argument('--mem', dest='mem', help='Socket mem', required=False, type=str, default='4096')
216 args = parser.parse_args()
218 ovsvsctl = OvsVsctl(args.cores, args.pcore, args.tcore, args.sockets)
219 coreh = CoreHandler()
223 print "INFO: dpdk cores: {}, cpu count: {}".format(args.dpdkcores, args.cores)
225 dpdkcoreset = coreh.string_to_set(args.dpdkcores)
226 except Exception as exp:
227 print "ERROR: Calculating of cpu/core set failed: {}".format(exp)
230 if max(dpdkcoreset) > int(args.cores):
231 print "ERROR: invalid DPDK cores (too big)"
234 # Check if hyperthreading is off and we can calculate new core set so that
235 # DPDK has a chance to start.
236 if not ovsvsctl.is_hyperthreading_enabled() and max(dpdkcoreset) > int(args.cores):
237 print "INFO: Hyperthreading off, DPDK cores contain too big core"
238 dpdkcoreset = set([x for x in dpdkcoreset if x < int(args.cores)])
239 print "INFO: new dpdkcoreset {}".format(dpdkcoreset)
241 dpdkcoreset = dpdkcoreset
242 dpdkcoremask = coreh.set_to_hex(dpdkcoreset)
246 changed |= ovsvsctl.set_pmd_cpu_mask(dpdkcoremask)
247 #changed |= ovsvsctl.set_lcore_mask()
248 changed |= ovsvsctl.set_socket_mem(args.mem)
249 changed |= ovsvsctl.enable_dpdk()
255 if __name__ == "__main__":