1 # This program is free software; you can redistribute it and/or modify
2 # it under the terms of the GNU General Public License as published by
3 # the Free Software Foundation; either version 2 of the License, or
4 # (at your option) any later version.
6 # This program is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # GNU Library General Public License for more details.
11 # You should have received a copy of the GNU General Public License
12 # along with this program; if not, write to the Free Software
13 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
15 # See the COPYING file for license information.
17 # Copyright (c) 2007 Guillaume Chazarain <guichaz@gmail.com>
24 # From https://git.kernel.org/pub/scm/utils/util-linux/util-linux.git/tree/configure.ac#n2289
25 # i386 bit userspace under an x86_64 kernel will have its uname() appear as
26 # 'x86_64' but it will use the i386 syscall number, that's why we consider both
27 # the architecture name and the word size.
28 IOPRIO_GET_ARCH_SYSCALL
= [
33 ('mips*', '32bit', 4315),
34 ('mips*', '64bit', 5274),
35 ('parisc*', '*', 268),
36 ('powerpc*', '*', 274),
40 ('x86_64*', '32bit', 290),
41 ('x86_64*', '64bit', 252),
44 IOPRIO_SET_ARCH_SYSCALL
= [
49 ('mips*', '32bit', 4314),
50 ('mips*', '64bit', 5273),
51 ('parisc*', '*', 267),
52 ('powerpc*', '*', 273),
56 ('x86_64*', '32bit', 289),
57 ('x86_64*', '64bit', 251),
61 def find_ioprio_syscall_number(syscall_list
):
63 bits
= platform
.architecture()[0]
65 for candidate_arch
, candidate_bits
, syscall_nr
in syscall_list
:
66 if fnmatch
.fnmatch(arch
, candidate_arch
) and \
67 fnmatch
.fnmatch(bits
, candidate_bits
):
71 class IoprioSetError(Exception):
72 def __init__(self
, err
):
74 self
.err
= os
.strerror(err
)
79 from iotop
import _ioprio
80 __NR_ioprio_get
= _ioprio
.SYS_ioprio_get
81 __NR_ioprio_set
= _ioprio
.SYS_ioprio_set
82 except (ImportError, AttributeError):
83 __NR_ioprio_get
= find_ioprio_syscall_number(IOPRIO_GET_ARCH_SYSCALL
)
84 __NR_ioprio_set
= find_ioprio_syscall_number(IOPRIO_SET_ARCH_SYSCALL
)
87 ctypes_handle
= ctypes
.CDLL(None, use_errno
=True)
89 ctypes_handle
= ctypes
.CDLL(None)
91 syscall
= ctypes_handle
.syscall
93 PRIORITY_CLASSES
= [None, 'rt', 'be', 'idle']
95 IOPRIO_WHO_PROCESS
= 1
96 IOPRIO_CLASS_SHIFT
= 13
97 IOPRIO_PRIO_MASK
= (1 << IOPRIO_CLASS_SHIFT
) - 1
100 def ioprio_value(ioprio_class
, ioprio_data
):
102 ioprio_class
= PRIORITY_CLASSES
.index(ioprio_class
)
104 ioprio_class
= PRIORITY_CLASSES
.index(None)
105 return (ioprio_class
<< IOPRIO_CLASS_SHIFT
) | ioprio_data
108 def ioprio_class(ioprio
):
109 return PRIORITY_CLASSES
[ioprio
>> IOPRIO_CLASS_SHIFT
]
112 def ioprio_data(ioprio
):
113 return ioprio
& IOPRIO_PRIO_MASK
115 sched_getscheduler
= ctypes_handle
.sched_getscheduler
116 SCHED_OTHER
, SCHED_FIFO
, SCHED_RR
, SCHED_BATCH
, SCHED_ISO
, SCHED_IDLE
= \
119 getpriority
= ctypes_handle
.getpriority
123 def get_ioprio_from_sched(pid
):
124 scheduler
= sched_getscheduler(pid
)
125 nice
= getpriority(PRIO_PROCESS
, pid
)
126 ioprio_nice
= (nice
+ 20) / 5
128 if scheduler
in (SCHED_FIFO
, SCHED_RR
):
129 return 'rt/%d' % ioprio_nice
130 elif scheduler
== SCHED_IDLE
:
133 return 'be/%d' % ioprio_nice
137 if __NR_ioprio_get
is None:
140 ioprio
= syscall(__NR_ioprio_get
, IOPRIO_WHO_PROCESS
, pid
)
144 prio_class
= ioprio_class(ioprio
)
146 return get_ioprio_from_sched(pid
)
147 if prio_class
== 'idle':
149 return '%s/%d' % (prio_class
, ioprio_data(ioprio
))
152 def set_ioprio(which
, who
, ioprio_class
, ioprio_data
):
153 if __NR_ioprio_set
is None:
154 raise IoprioSetError('No ioprio_set syscall found')
156 ioprio_val
= ioprio_value(ioprio_class
, ioprio_data
)
157 ret
= syscall(__NR_ioprio_set
, which
, who
, ioprio_val
, use_errno
=True)
160 err
= ctypes
.get_errno()
161 except AttributeError:
163 'Unknown error (errno support not available before Python2.6)'
164 raise IoprioSetError(err
)
172 if key
.startswith('rt/'):
174 elif key
.startswith('be/'):
176 prio
= int(key
.split('/')[1])
181 return (1 << (shift
* IOPRIO_CLASS_SHIFT
)) + prio
184 def to_class_and_data(ioprio_str
):
185 if '/' in ioprio_str
:
186 split
= ioprio_str
.split('/')
187 return (split
[0], int(split
[1]))
188 elif ioprio_str
== 'idle':
192 if __name__
== '__main__':
194 if len(sys
.argv
) == 2:
195 pid
= int(sys
.argv
[1])
199 print('ioprio:', get(pid
))