Nir Soffer has posted comments on this change. Change subject: lib: daemon: autodetect online cpus for affinity ......................................................................
Patch Set 8: Code-Review-1 (21 comments) https://gerrit.ovirt.org/#/c/49402/8/lib/vdsm/config.py.in File lib/vdsm/config.py.in: Line 206: ('connection_stats_timeout', '3600', Line 207: 'Time in seconds defining how frequently we log transport stats'), Line 208: Line 209: ('cpu_affinity', 'auto', Line 210: 'Comma separated whitelist of CPU cores, expressed as integers ' Describe the comma separated list format after auto, since auto is preferred. Line 211: 'starting from zero, or the special string value "auto".' Line 212: 'This options selects the CPU cores on which VDSM is allowed ' Line 213: 'to run. Use the empty value to disable the affinity, allowing ' Line 214: 'Vdsm to run on all the online cores. ' Line 209: ('cpu_affinity', 'auto', Line 210: 'Comma separated whitelist of CPU cores, expressed as integers ' Line 211: 'starting from zero, or the special string value "auto".' Line 212: 'This options selects the CPU cores on which VDSM is allowed ' Line 213: 'to run. Use the empty value to disable the affinity, allowing ' Describe the empty value last, as this is the worst option for users. Line 214: 'Vdsm to run on all the online cores. ' Line 215: 'The default is "auto", meaning Vdsm will pick the first online ' Line 216: 'core, starting with the second one. If only the first core is ' Line 217: 'online, it will pin on the first core.' Line 213: 'to run. Use the empty value to disable the affinity, allowing ' Line 214: 'Vdsm to run on all the online cores. ' Line 215: 'The default is "auto", meaning Vdsm will pick the first online ' Line 216: 'core, starting with the second one. If only the first core is ' Line 217: 'online, it will pin on the first core.' Describe the default first, as this is the option that most people will use. Line 218: 'Valid examples: "1", "0,1", "0,2,3", "auto"'), Line 219: Line 220: ('ssl_implementation', '@SSL_IMPLEMENTATION@', Line 221: 'Specifies which ssl implementation should be used. ' Line 214: 'Vdsm to run on all the online cores. ' Line 215: 'The default is "auto", meaning Vdsm will pick the first online ' Line 216: 'core, starting with the second one. If only the first core is ' Line 217: 'online, it will pin on the first core.' Line 218: 'Valid examples: "1", "0,1", "0,2,3", "auto"'), Show valid examples in order of preferences: "auto", "1", "1,2", "" Don't show 0,1 or 0,2,3, these are bad settings. Line 219: Line 220: ('ssl_implementation', '@SSL_IMPLEMENTATION@', Line 221: 'Specifies which ssl implementation should be used. ' Line 222: 'There are 2 options: ' https://gerrit.ovirt.org/#/c/49402/8/lib/vdsm/taskset.py File lib/vdsm/taskset.py: Line 24: from . import constants Line 25: from . import utils Line 26: Line 27: Line 28: AUTOMATIC = "auto" AUTO? make it look like the value. Line 29: Line 30: Line 31: _SYS_ONLINE_CPUS = "/sys/devices/system/cpu/online" Line 32: Line 26: Line 27: Line 28: AUTOMATIC = "auto" Line 29: Line 30: Les keep one or zero empty line between these constants. Line 31: _SYS_ONLINE_CPUS = "/sys/devices/system/cpu/online" Line 32: Line 33: Line 34: def get(pid): Line 81: """ Line 82: Return a frozenset which contains identifiers of online CPUs, Line 83: as non-negative integers. Line 84: """ Line 85: return _expand_range(_read_contents(_SYS_ONLINE_CPUS)) _read_contents does not add any value, why not inline it here? Line 86: Line 87: Line 88: def pick_cpu(cpu_set): Line 89: """ Line 84: """ Line 85: return _expand_range(_read_contents(_SYS_ONLINE_CPUS)) Line 86: Line 87: Line 88: def pick_cpu(cpu_set): Why pick a cpu from the given set, instead of reading the online cpus and returning the best cpu? Line 89: """ Line 90: Autoselect the best CPU VDSM should pin to. Line 91: `cpu_set' is any iterable which produces the sequence of all Line 92: available CPUs, among which VDSM should pick the best one. Line 86: Line 87: Line 88: def pick_cpu(cpu_set): Line 89: """ Line 90: Autoselect the best CPU VDSM should pin to. Autoselect -> Select Line 91: `cpu_set' is any iterable which produces the sequence of all Line 92: available CPUs, among which VDSM should pick the best one. Line 93: """ Line 94: cpu_list = sorted(cpu_set) Line 102: # Let's play nice, and try to find a quieter spot. Line 103: return cpu_list[1] Line 104: Line 105: # no special care, just pick the first one Line 106: return cpu_list[0] Do we really want to return the first online cpu? I think we can simplify, returning the second online cpu, or the single online cpu if only one cpu is online: return cpu_list[:2][-1] >>> [0,1,2][:2][-1] 1 >>> [1,2,3][:2][-1] 2 >>> [0][:2][-1] 0 Line 107: Line 108: Line 109: def _cpu_set_from_output(line): Line 110: """ Line 116: mask = int(hexmask, 16) Line 117: return frozenset(i for i in range(mask.bit_length()) if mask & (1 << i)) Line 118: Line 119: Line 120: def _expand_range(cpu_range): Lets name it after the kernel function doing the same thing, cpulist_parse(). See https://www.kernel.org/doc/Documentation/cputopology.txt Line 121: """ Line 122: Expand the range syntax (e.g. 0-2,5) into a plain Line 123: frozenset of integers (e.g. frozenset([0,1,2,5])) Line 124: The input format is like the content of the special file Line 131: begin, end = item.split('-', 1) Line 132: cpus.extend(range(int(begin), int(end)+1)) Line 133: else: Line 134: cpus.append(int(item)) Line 135: return frozenset(cpus) This is very nice and clear, but maybe we can make a little bit nicer like this: def parse(item): if '-' in item: begin, end = items.split(',', 1) return range(int(begin), int(end) + 1) else: return int(item) return frozenset(parse(item) for item in data.split(',')) Line 136: Line 137: Line 138: def _read_contents(path): Line 139: with open(path, 'rt') as src: Line 135: return frozenset(cpus) Line 136: Line 137: Line 138: def _read_contents(path): Line 139: with open(path, 'rt') as src: Why t? Line 136: Line 137: Line 138: def _read_contents(path): Line 139: with open(path, 'rt') as src: Line 140: return src.read() Should be readline() https://gerrit.ovirt.org/#/c/49402/8/tests/tasksetTests.py File tests/tasksetTests.py: Line 105: Line 106: @expandPermutations Line 107: class OnlineCpusFunctionsTests(VdsmTestCase): Line 108: Line 109: @permutations([ Permutations are more clear when we add a comment like this: # raw_value, cpu_set Line 110: ['0', set((0,))], Line 111: ['0,1,2,3', set(range(4))], Line 112: ['0-3', set(range(4))], Line 113: ['0-1,3', set((0, 1, 3))], Line 117: Line 118: def _fake_sys(unused): Line 119: return raw_value Line 120: Line 121: with MonkeyPatchScope([(taskset, "_read_contents", _fake_sys)]): Lets monkeypatch the path (/sys/devices...), so online cpu will read from our temporary file instead. This way we check also the code reading from the file, and we don't need to add unneeded function line _read_contents. Line 122: self.assertEqual(taskset.online_cpus(), cpu_set) Line 123: Line 124: def test_online_cpus_sparse_ppc64(self): Line 125: # as seen on ppc64 20151130 Line 120: Line 121: with MonkeyPatchScope([(taskset, "_read_contents", _fake_sys)]): Line 122: self.assertEqual(taskset.online_cpus(), cpu_set) Line 123: Line 124: def test_online_cpus_sparse_ppc64(self): Why do we need separate test? this can be just another permutation. Line 125: # as seen on ppc64 20151130 Line 126: cpus = set( Line 127: (8, 16, 24, 32, 40, 48, 56, 64, 72, 80, Line 128: 88, 96, 104, 112, 120, 128, 136, 144, 152) Line 137: @permutations([ Line 138: [frozenset((0,)), 0], Line 139: [frozenset((1,)), 1], Line 140: [frozenset(range(4)), 1], Line 141: [frozenset(range(1, 4)), 1], We should pick 4, 1 is probably more busy Line 142: [frozenset(range(3, 9)), 3], Line 143: ]) Line 144: def test_pick_cpu(self, cpu_set, expected): Line 145: self.assertEqual(taskset.pick_cpu(cpu_set), expected) Line 138: [frozenset((0,)), 0], Line 139: [frozenset((1,)), 1], Line 140: [frozenset(range(4)), 1], Line 141: [frozenset(range(1, 4)), 1], Line 142: [frozenset(range(3, 9)), 3], Same Line 143: ]) Line 144: def test_pick_cpu(self, cpu_set, expected): Line 145: self.assertEqual(taskset.pick_cpu(cpu_set), expected) Line 146: https://gerrit.ovirt.org/#/c/49402/8/vdsm/vdsm File vdsm/vdsm: Line 215 Line 216 Line 217 Line 218 Line 219 Lets also fix this condition to early return style in another patch: if cpu_affinity == "": return Line 216: Line 217: def __set_cpu_affinity(): Line 218: cpu_affinity = config.get('vars', 'cpu_affinity') Line 219: if cpu_affinity != "": Line 220: online_cpus = taskset.online_cpus() Lets bail out here (with debug log) - if we have one cpu, user setting does not matter. if len(oneline_cpus) == 1: log.debug... return Line 221: Line 222: if cpu_affinity.lower() == taskset.AUTOMATIC: Line 223: cpu_set = frozenset((taskset.pick_cpu(online_cpus),)) Line 224: else: -- To view, visit https://gerrit.ovirt.org/49402 To unsubscribe, visit https://gerrit.ovirt.org/settings Gerrit-MessageType: comment Gerrit-Change-Id: Iba834f67a43ce766308036cbd079107340ed69d8 Gerrit-PatchSet: 8 Gerrit-Project: vdsm Gerrit-Branch: master Gerrit-Owner: Francesco Romani <from...@redhat.com> Gerrit-Reviewer: Dan Kenigsberg <dan...@redhat.com> Gerrit-Reviewer: Francesco Romani <from...@redhat.com> Gerrit-Reviewer: Jenkins CI Gerrit-Reviewer: Martin Polednik <mpoled...@redhat.com> Gerrit-Reviewer: Michal Skrivanek <mskri...@redhat.com> Gerrit-Reviewer: Milan Zamazal <mzama...@redhat.com> Gerrit-Reviewer: Nir Soffer <nsof...@redhat.com> Gerrit-Reviewer: Piotr Kliczewski <piotr.kliczew...@gmail.com> Gerrit-Reviewer: Vinzenz Feenstra <vfeen...@redhat.com> Gerrit-Reviewer: Yaniv Bronhaim <ybron...@redhat.com> Gerrit-Reviewer: gerrit-hooks <automat...@ovirt.org> Gerrit-HasComments: Yes _______________________________________________ vdsm-patches mailing list vdsm-patches@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/vdsm-patches