#! /usr/bin/python # -*- python -*- # -*- coding: utf-8 -*- # Copyright (C) 2008 Red Hat Inc. # # Arnaldo Carvalho de Melo # # This application is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; version 2. # # This application is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. from __future__ import print_function import os import schedutils import sys def usage(): print('''ptaskset (python-schedutils) usage: ptaskset [options] [mask | cpu-list] [pid | cmd [args...]] set or get the affinity of a process -p, --pid operate on existing given pid -c, --cpu-list display and specify cpus in list format -h, --help display this help''') return def hexbitmask(l): hexbitmask = [] bit = 0 mask = 0 nr_entries = 1 << max(l) for entry in range(nr_entries): if entry in l: mask |= (1 << bit) bit += 1 if bit == 32: bit = 0 hexbitmask.insert(0, mask) mask = 0 if bit < 32 and mask != 0: hexbitmask.insert(0, mask) return hexbitmask def find_last_bit(n, wordsize=32): bit = wordsize - 1 while bit != 0: if n & (1 << bit): return bit bit -= 1 return 0 def bitmasklist(line): fields = line.strip().split(",") bitmasklist = [] while int(fields[0], 16) == 0: fields.pop(0) if not fields: return [] nr_entries = (len(fields) - 1) * 32 + find_last_bit(int(fields[0], 16)) + 1 entry = 0 for i in range(len(fields) - 1, -1, -1): mask = int(fields[i], 16) while mask != 0: if mask & 1: bitmasklist.append(entry) mask >>= 1 entry += 1 if entry == nr_entries: break if entry == nr_entries: break return bitmasklist def cpustring_to_list(cpustr): """Convert a string of numbers to an integer list. Given a string of comma-separated numbers and number ranges, return a simple sorted list of the integers it represents. This function will throw exceptions for badly-formatted strings. Returns a list of integers.""" fields = cpustr.strip().split(",") cpu_list = [] for field in fields: ends = field.split("-") if len(ends) > 2: raise "Syntax error" if len(ends) == 2: cpu_list += list(range(int(ends[0]), int(ends[1]) + 1)) else: cpu_list += [int(ends[0])] return list(set(cpu_list)) def show_settings(pid, when, cpu_list_mode): affinity = schedutils.get_affinity(pid) if cpu_list_mode: mask = ",".join([str(a) for a in affinity]) else: mask = ",".join(["%x" % a for a in hexbitmask(affinity)]) print("pid %d's %s affinity mask: %s" % (pid, when, mask)) def change_settings(pid, affinity, cpu_list_mode): if cpu_list_mode: try: affinity = [int(a) for a in affinity.split(",")] except: affinity = cpustring_to_list(affinity) else: affinity = bitmasklist(affinity) try: schedutils.set_affinity(pid, affinity) except SystemError as err: print("sched_setaffinity: %s" % err[1]) print("failed to set pid %d's affinity" % pid) def main(): args = sys.argv[1:] if not args: usage() return cpu_list_mode = False while True: o = args.pop(0) if o in ("-h", "--help"): usage() return elif o in ("-c", "--cpu-list"): cpu_list_mode = True elif o in ("-p", "--pid"): if len(args) > 1: affinity = args.pop(0) pid = int(args.pop(0)) show_settings(pid, "current", cpu_list_mode) change_settings(pid, affinity, cpu_list_mode) show_settings(pid, "new", cpu_list_mode) else: pid = int(args.pop(0)) show_settings(pid, "current", cpu_list_mode) return else: break affinity = o change_settings(0, affinity, cpu_list_mode) os.execvp(args[0], args) if __name__ == '__main__': main()