[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This chapter describes functions for examining how much of various kinds of resources (CPU time, memory, etc.) a process has used and getting and setting limits on future usage.
22.1 Resource Usage | Measuring various resources used. | |
22.2 Limiting Resource Usage | Specifying limits on resource usage. | |
22.3 Process CPU Priority And Scheduling | Reading or setting process run priority. | |
22.4 Querying memory available resources | ||
22.5 Learn about the processors available |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The function getrusage
and the data type struct rusage
are used to examine the resource usage of a process. They are declared
in ‘sys/resource.h’.
This function reports resource usage totals for processes specified by
processes, storing the information in *rusage
.
In most systems, processes has only two valid values:
RUSAGE_SELF
Just the current process.
RUSAGE_CHILDREN
All child processes (direct and indirect) that have already terminated.
In the GNU system, you can also inquire about a particular child process by specifying its process ID.
The return value of getrusage
is zero for success, and -1
for failure.
EINVAL
The argument processes is not valid.
One way of getting resource usage for a particular child process is with
the function wait4
, which returns totals for a child when it
terminates. See section BSD Process Wait Functions.
This data type stores various resource usage statistics. It has the following members, and possibly others:
struct timeval ru_utime
Time spent executing user instructions.
struct timeval ru_stime
Time spent in operating system code on behalf of processes.
long int ru_maxrss
The maximum resident set size used, in kilobytes. That is, the maximum number of kilobytes of physical memory that processes used simultaneously.
long int ru_ixrss
An integral value expressed in kilobytes times ticks of execution, which indicates the amount of memory used by text that was shared with other processes.
long int ru_idrss
An integral value expressed the same way, which is the amount of unshared memory used for data.
long int ru_isrss
An integral value expressed the same way, which is the amount of unshared memory used for stack space.
long int ru_minflt
The number of page faults which were serviced without requiring any I/O.
long int ru_majflt
The number of page faults which were serviced by doing I/O.
long int ru_nswap
The number of times processes was swapped entirely out of main memory.
long int ru_inblock
The number of times the file system had to read from the disk on behalf of processes.
long int ru_oublock
The number of times the file system had to write to the disk on behalf of processes.
long int ru_msgsnd
Number of IPC messages sent.
long int ru_msgrcv
Number of IPC messages received.
long int ru_nsignals
Number of signals received.
long int ru_nvcsw
The number of times processes voluntarily invoked a context switch (usually to wait for some service).
long int ru_nivcsw
The number of times an involuntary context switch took place (because a time slice expired, or another process of higher priority was scheduled).
vtimes
is a historical function that does some of what
getrusage
does. getrusage
is a better choice.
vtimes
and its vtimes
data structure are declared in
‘sys/vtimes.h’.
vtimes
reports resource usage totals for a process.
If current is non-null, vtimes
stores resource usage totals for
the invoking process alone in the structure to which it points. If
child is non-null, vtimes
stores resource usage totals for all
past children (which have terminated) of the invoking process in the structure
to which it points.
This data type contains information about the resource usage of a process.
Each member corresponds to a member of the struct rusage
data type
described above.
vm_utime
User CPU time. Analogous to ru_utime
in struct rusage
vm_stime
System CPU time. Analogous to ru_stime
in struct rusage
vm_idsrss
Data and stack memory. The sum of the values that would be reported as
ru_idrss
and ru_isrss
in struct rusage
vm_ixrss
Shared memory. Analogous to ru_ixrss
in struct rusage
vm_maxrss
Maximent resident set size. Analogous to ru_maxrss
in
struct rusage
vm_majflt
Major page faults. Analogous to ru_majflt
in struct rusage
vm_minflt
Minor page faults. Analogous to ru_minflt
in struct rusage
vm_nswap
Swap count. Analogous to ru_nswap
in struct rusage
vm_inblk
Disk reads. Analogous to ru_inblk
in struct rusage
vm_oublk
Disk writes. Analogous to ru_oublk
in struct rusage
The return value is zero if the function succeeds; -1
otherwise.
An additional historical function for examining resource usage,
vtimes
, is supported but not documented here. It is declared in
‘sys/vtimes.h’.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
You can specify limits for the resource usage of a process. When the process tries to exceed a limit, it may get a signal, or the system call by which it tried to do so may fail, depending on the resource. Each process initially inherits its limit values from its parent, but it can subsequently change them.
There are two per-process limits associated with a resource:
The current limit is the value the system will not allow usage to exceed. It is also called the “soft limit” because the process being limited can generally raise the current limit at will.
The maximum limit is the maximum value to which a process is allowed to set its current limit. It is also called the “hard limit” because there is no way for a process to get around it. A process may lower its own maximum limit, but only the superuser may increase a maximum limit.
The symbols for use with getrlimit
, setrlimit
,
getrlimit64
, and setrlimit64
are defined in
‘sys/resource.h’.
Read the current and maximum limits for the resource resource
and store them in *rlp
.
The return value is 0
on success and -1
on failure. The
only possible errno
error condition is EFAULT
.
When the sources are compiled with _FILE_OFFSET_BITS == 64
on a
32-bit system this function is in fact getrlimit64
. Thus, the
LFS interface transparently replaces the old interface.
This function is similar to getrlimit
but its second parameter is
a pointer to a variable of type struct rlimit64
, which allows it
to read values which wouldn't fit in the member of a struct
rlimit
.
If the sources are compiled with _FILE_OFFSET_BITS == 64
on a
32-bit machine, this function is available under the name
getrlimit
and so transparently replaces the old interface.
Store the current and maximum limits for the resource resource
in *rlp
.
The return value is 0
on success and -1
on failure. The
following errno
error condition is possible:
EPERM
When the sources are compiled with _FILE_OFFSET_BITS == 64
on a
32-bit system this function is in fact setrlimit64
. Thus, the
LFS interface transparently replaces the old interface.
This function is similar to setrlimit
but its second parameter is
a pointer to a variable of type struct rlimit64
which allows it
to set values which wouldn't fit in the member of a struct
rlimit
.
If the sources are compiled with _FILE_OFFSET_BITS == 64
on a
32-bit machine this function is available under the name
setrlimit
and so transparently replaces the old interface.
This structure is used with getrlimit
to receive limit values,
and with setrlimit
to specify limit values for a particular process
and resource. It has two fields:
rlim_t rlim_cur
The current limit
rlim_t rlim_max
The maximum limit.
For getrlimit
, the structure is an output; it receives the current
values. For setrlimit
, it specifies the new values.
For the LFS functions a similar type is defined in ‘sys/resource.h’.
This structure is analogous to the rlimit
structure above, but
its components have wider ranges. It has two fields:
rlim64_t rlim_cur
This is analogous to rlimit.rlim_cur
, but with a different type.
rlim64_t rlim_max
This is analogous to rlimit.rlim_max
, but with a different type.
Here is a list of resources for which you can specify a limit. Memory and file sizes are measured in bytes.
RLIMIT_CPU
The maximum amount of CPU time the process can use. If it runs for
longer than this, it gets a signal: SIGXCPU
. The value is
measured in seconds. See section Operation Error Signals.
RLIMIT_FSIZE
The maximum size of file the process can create. Trying to write a
larger file causes a signal: SIGXFSZ
. See section Operation Error Signals.
RLIMIT_DATA
The maximum size of data memory for the process. If the process tries to allocate data memory beyond this amount, the allocation function fails.
RLIMIT_STACK
The maximum stack size for the process. If the process tries to extend
its stack past this size, it gets a SIGSEGV
signal.
See section Program Error Signals.
RLIMIT_CORE
The maximum size core file that this process can create. If the process terminates and would dump a core file larger than this, then no core file is created. So setting this limit to zero prevents core files from ever being created.
RLIMIT_RSS
The maximum amount of physical memory that this process should get. This parameter is a guide for the system's scheduler and memory allocator; the system may give the process more memory when there is a surplus.
RLIMIT_MEMLOCK
The maximum amount of memory that can be locked into physical memory (so it will never be paged out).
RLIMIT_NPROC
The maximum number of processes that can be created with the same user ID.
If you have reached the limit for your user ID, fork
will fail
with EAGAIN
. See section Creating a Process.
RLIMIT_NOFILE
RLIMIT_OFILE
The maximum number of files that the process can open. If it tries to
open more files than this, its open attempt fails with errno
EMFILE
. See section Error Codes. Not all systems support this limit;
GNU does, and 4.4 BSD does.
RLIMIT_AS
The maximum size of total memory that this process should get. If the
process tries to allocate more memory beyond this amount with, for
example, brk
, malloc
, mmap
or sbrk
, the
allocation function fails.
RLIM_NLIMITS
The number of different resource limits. Any valid resource
operand must be less than RLIM_NLIMITS
.
This constant stands for a value of “infinity” when supplied as
the limit value in setrlimit
.
The following are historical functions to do some of what the functions above do. The functions above are better choices.
ulimit
and the command symbols are declared in ‘ulimit.h’.
ulimit
gets the current limit or sets the current and maximum
limit for a particular resource for the calling process according to the
command cmd.a
If you are getting a limit, the command argument is the only argument.
If you are setting a limit, there is a second argument:
long int
limit which is the value to which you are setting
the limit.
The cmd values and the operations they specify are:
GETFSIZE
Get the current limit on the size of a file, in units of 512 bytes.
SETFSIZE
Set the current and maximum limit on the size of a file to limit * 512 bytes.
There are also some other cmd values that may do things on some systems, but they are not supported.
Only the superuser may increase a maximum limit.
When you successfully get a limit, the return value of ulimit
is
that limit, which is never negative. When you successfully set a limit,
the return value is zero. When the function fails, the return value is
-1
and errno
is set according to the reason:
EPERM
A process tried to increase a maximum limit, but is not superuser.
vlimit
and its resource symbols are declared in ‘sys/vlimit.h’.
vlimit
sets the current limit for a resource for a process.
resource identifies the resource:
LIM_CPU
Maximum CPU time. Same as RLIMIT_CPU
for setrlimit
.
LIM_FSIZE
Maximum file size. Same as RLIMIT_FSIZE
for setrlimit
.
LIM_DATA
Maximum data memory. Same as RLIMIT_DATA
for setrlimit
.
LIM_STACK
Maximum stack size. Same as RLIMIT_STACK
for setrlimit
.
LIM_CORE
Maximum core file size. Same as RLIMIT_COR
for setrlimit
.
LIM_MAXRSS
Maximum physical memory. Same as RLIMIT_RSS
for setrlimit
.
The return value is zero for success, and -1
with errno
set
accordingly for failure:
EPERM
The process tried to set its current limit beyond its maximum limit.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When multiple processes simultaneously require CPU time, the system's scheduling policy and process CPU priorities determine which processes get it. This section describes how that determination is made and GNU C library functions to control it.
It is common to refer to CPU scheduling simply as scheduling and a process' CPU priority simply as the process' priority, with the CPU resource being implied. Bear in mind, though, that CPU time is not the only resource a process uses or that processes contend for. In some cases, it is not even particularly important. Giving a process a high “priority” may have very little effect on how fast a process runs with respect to other processes. The priorities discussed in this section apply only to CPU time.
CPU scheduling is a complex issue and different systems do it in wildly different ways. New ideas continually develop and find their way into the intricacies of the various systems' scheduling algorithms. This section discusses the general concepts, some specifics of systems that commonly use the GNU C library, and some standards.
For simplicity, we talk about CPU contention as if there is only one CPU in the system. But all the same principles apply when a processor has multiple CPUs, and knowing that the number of processes that can run at any one time is equal to the number of CPUs, you can easily extrapolate the information.
The functions described in this section are all defined by the POSIX.1
and POSIX.1b standards (the sched…
functions are POSIX.1b).
However, POSIX does not define any semantics for the values that these
functions get and set. In this chapter, the semantics are based on the
Linux kernel's implementation of the POSIX standard. As you will see,
the Linux implementation is quite the inverse of what the authors of the
POSIX syntax had in mind.
22.3.1 Absolute Priority | The first tier of priority. Posix | |
22.3.2 Realtime Scheduling | Scheduling among the process nobility | |
22.3.3 Basic Scheduling Functions | Get/set scheduling policy, priority | |
22.3.4 Traditional Scheduling | Scheduling among the vulgar masses | |
22.3.5 Limiting execution to certain CPUs |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Every process has an absolute priority, and it is represented by a number. The higher the number, the higher the absolute priority.
On systems of the past, and most systems today, all processes have absolute priority 0 and this section is irrelevant. In that case, See section Traditional Scheduling. Absolute priorities were invented to accommodate realtime systems, in which it is vital that certain processes be able to respond to external events happening in real time, which means they cannot wait around while some other process that wants to, but doesn't need to run occupies the CPU.
When two processes are in contention to use the CPU at any instant, the one with the higher absolute priority always gets it. This is true even if the process with the lower priority is already using the CPU (i.e., the scheduling is preemptive). Of course, we're only talking about processes that are running or “ready to run,” which means they are ready to execute instructions right now. When a process blocks to wait for something like I/O, its absolute priority is irrelevant.
Note: The term “runnable” is a synonym for “ready to run.”
When two processes are running or ready to run and both have the same absolute priority, it's more interesting. In that case, who gets the CPU is determined by the scheduling policy. If the processes have absolute priority 0, the traditional scheduling policy described in Traditional Scheduling applies. Otherwise, the policies described in Realtime Scheduling apply.
You normally give an absolute priority above 0 only to a process that can be trusted not to hog the CPU. Such processes are designed to block (or terminate) after relatively short CPU runs.
A process begins life with the same absolute priority as its parent process. Functions described in Basic Scheduling Functions can change it.
Only a privileged process can change a process' absolute priority to
something other than 0
. Only a privileged process or the
target process' owner can change its absolute priority at all.
POSIX requires absolute priority values used with the realtime
scheduling policies to be consecutive with a range of at least 32. On
Linux, they are 1 through 99. The functions
sched_get_priority_max
and sched_set_priority_min
portably
tell you what the range is on a particular system.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
One thing you must keep in mind when designing real time applications is that having higher absolute priority than any other process doesn't guarantee the process can run continuously. Two things that can wreck a good CPU run are interrupts and page faults.
Interrupt handlers live in that limbo between processes. The CPU is executing instructions, but they aren't part of any process. An interrupt will stop even the highest priority process. So you must allow for slight delays and make sure that no device in the system has an interrupt handler that could cause too long a delay between instructions for your process.
Similarly, a page fault causes what looks like a straightforward
sequence of instructions to take a long time. The fact that other
processes get to run while the page faults in is of no consequence,
because as soon as the I/O is complete, the high priority process will
kick them out and run again, but the wait for the I/O itself could be a
problem. To neutralize this threat, use mlock
or
mlockall
.
There are a few ramifications of the absoluteness of this priority on a single-CPU system that you need to keep in mind when you choose to set a priority and also when you're working on a program that runs with high absolute priority. Consider a process that has higher absolute priority than any other process in the system and due to a bug in its program, it gets into an infinite loop. It will never cede the CPU. You can't run a command to kill it because your command would need to get the CPU in order to run. The errant program is in complete control. It controls the vertical, it controls the horizontal.
There are two ways to avoid this: 1) keep a shell running somewhere with a higher absolute priority. 2) keep a controlling terminal attached to the high priority process group. All the priority in the world won't stop an interrupt handler from running and delivering a signal to the process if you hit Control-C.
Some systems use absolute priority as a means of allocating a fixed percentage of CPU time to a process. To do this, a super high priority privileged process constantly monitors the process' CPU usage and raises its absolute priority when the process isn't getting its entitled share and lowers it when the process is exceeding it.
Note: The absolute priority is sometimes called the “static priority.” We don't use that term in this manual because it misses the most important feature of the absolute priority: its absoluteness.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Whenever two processes with the same absolute priority are ready to run, the kernel has a decision to make, because only one can run at a time. If the processes have absolute priority 0, the kernel makes this decision as described in Traditional Scheduling. Otherwise, the decision is as described in this section.
If two processes are ready to run but have different absolute priorities, the decision is much simpler, and is described in Absolute Priority.
Each process has a scheduling policy. For processes with absolute priority other than zero, there are two available:
The most sensible case is where all the processes with a certain absolute priority have the same scheduling policy. We'll discuss that first.
In Round Robin, processes share the CPU, each one running for a small quantum of time (“time slice”) and then yielding to another in a circular fashion. Of course, only processes that are ready to run and have the same absolute priority are in this circle.
In First Come First Served, the process that has been waiting the longest to run gets the CPU, and it keeps it until it voluntarily relinquishes the CPU, runs out of things to do (blocks), or gets preempted by a higher priority process.
First Come First Served, along with maximal absolute priority and careful control of interrupts and page faults, is the one to use when a process absolutely, positively has to run at full CPU speed or not at all.
Judicious use of sched_yield
function invocations by processes
with First Come First Served scheduling policy forms a good compromise
between Round Robin and First Come First Served.
To understand how scheduling works when processes of different scheduling policies occupy the same absolute priority, you have to know the nitty gritty details of how processes enter and exit the ready to run list:
In both cases, the ready to run list is organized as a true queue, where a process gets pushed onto the tail when it becomes ready to run and is popped off the head when the scheduler decides to run it. Note that ready to run and running are two mutually exclusive states. When the scheduler runs a process, that process is no longer ready to run and no longer in the ready to run list. When the process stops running, it may go back to being ready to run again.
The only difference between a process that is assigned the Round Robin scheduling policy and a process that is assigned First Come First Serve is that in the former case, the process is automatically booted off the CPU after a certain amount of time. When that happens, the process goes back to being ready to run, which means it enters the queue at the tail. The time quantum we're talking about is small. Really small. This is not your father's timesharing. For example, with the Linux kernel, the round robin time slice is a thousand times shorter than its typical time slice for traditional scheduling.
A process begins life with the same scheduling policy as its parent process. Functions described in Basic Scheduling Functions can change it.
Only a privileged process can set the scheduling policy of a process that has absolute priority higher than 0.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This section describes functions in the GNU C library for setting the absolute priority and scheduling policy of a process.
Portability Note: On systems that have the functions in this section, the macro _POSIX_PRIORITY_SCHEDULING is defined in ‘<unistd.h>’.
For the case that the scheduling policy is traditional scheduling, more functions to fine tune the scheduling are in Traditional Scheduling.
Don't try to make too much out of the naming and structure of these functions. They don't match the concepts described in this manual because the functions are as defined by POSIX.1b, but the implementation on systems that use the GNU C library is the inverse of what the POSIX structure contemplates. The POSIX scheme assumes that the primary scheduling parameter is the scheduling policy and that the priority value, if any, is a parameter of the scheduling policy. In the implementation, though, the priority value is king and the scheduling policy, if anything, only fine tunes the effect of that priority.
The symbols in this section are declared by including file ‘sched.h’.
This structure describes an absolute priority.
int sched_priority
absolute priority value
This function sets both the absolute priority and the scheduling policy for a process.
It assigns the absolute priority value given by param and the
scheduling policy policy to the process with Process ID pid,
or the calling process if pid is zero. If policy is
negative, sched_setscheduler
keeps the existing scheduling policy.
The following macros represent the valid values for policy:
SCHED_OTHER
Traditional Scheduling
SCHED_FIFO
First In First Out
SCHED_RR
Round Robin
On success, the return value is 0
. Otherwise, it is -1
and ERRNO
is set accordingly. The errno
values specific
to this function are:
EPERM
CAP_SYS_NICE
permission and
policy is not SCHED_OTHER
(or it's negative and the
existing policy is not SCHED_OTHER
.
CAP_SYS_NICE
permission and its
owner is not the target process' owner. I.e., the effective uid of the
calling process is neither the effective nor the real uid of process
pid.
ESRCH
There is no process with pid pid and pid is not zero.
EINVAL
sched_get_priority_max
and sched_get_priority_min
tell you what the valid range is.
This function returns the scheduling policy assigned to the process with Process ID (pid) pid, or the calling process if pid is zero.
The return value is the scheduling policy. See
sched_setscheduler
for the possible values.
If the function fails, the return value is instead -1
and
errno
is set accordingly.
The errno
values specific to this function are:
ESRCH
There is no process with pid pid and it is not zero.
EINVAL
pid is negative.
Note that this function is not an exact mate to sched_setscheduler
because while that function sets the scheduling policy and the absolute
priority, this function gets only the scheduling policy. To get the
absolute priority, use sched_getparam
.
This function sets a process' absolute priority.
It is functionally identical to sched_setscheduler
with
policy = -1
.
This function returns a process' absolute priority.
pid is the Process ID (pid) of the process whose absolute priority you want to know.
param is a pointer to a structure in which the function stores the absolute priority of the process.
On success, the return value is 0
. Otherwise, it is -1
and ERRNO
is set accordingly. The errno
values specific
to this function are:
ESRCH
There is no process with pid pid and it is not zero.
EINVAL
pid is negative.
This function returns the lowest absolute priority value that is allowable for a process with scheduling policy policy.
On Linux, it is 0 for SCHED_OTHER and 1 for everything else.
On success, the return value is 0
. Otherwise, it is -1
and ERRNO
is set accordingly. The errno
values specific
to this function are:
EINVAL
policy does not identify an existing scheduling policy.
This function returns the highest absolute priority value that is allowable for a process that with scheduling policy policy.
On Linux, it is 0 for SCHED_OTHER and 99 for everything else.
On success, the return value is 0
. Otherwise, it is -1
and ERRNO
is set accordingly. The errno
values specific
to this function are:
EINVAL
policy does not identify an existing scheduling policy.
This function returns the length of the quantum (time slice) used with the Round Robin scheduling policy, if it is used, for the process with Process ID pid.
It returns the length of time as interval.
With a Linux kernel, the round robin time slice is always 150 microseconds, and pid need not even be a real pid.
The return value is 0
on success and in the pathological case
that it fails, the return value is -1
and errno
is set
accordingly. There is nothing specific that can go wrong with this
function, so there are no specific errno
values.
This function voluntarily gives up the process' claim on the CPU.
Technically, sched_yield
causes the calling process to be made
immediately ready to run (as opposed to running, which is what it was
before). This means that if it has absolute priority higher than 0, it
gets pushed onto the tail of the queue of processes that share its
absolute priority and are ready to run, and it will run again when its
turn next arrives. If its absolute priority is 0, it is more
complicated, but still has the effect of yielding the CPU to other
processes.
If there are no other processes that share the calling process' absolute priority, this function doesn't have any effect.
To the extent that the containing program is oblivious to what other processes in the system are doing and how fast it executes, this function appears as a no-op.
The return value is 0
on success and in the pathological case
that it fails, the return value is -1
and errno
is set
accordingly. There is nothing specific that can go wrong with this
function, so there are no specific errno
values.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This section is about the scheduling among processes whose absolute priority is 0. When the system hands out the scraps of CPU time that are left over after the processes with higher absolute priority have taken all they want, the scheduling described herein determines who among the great unwashed processes gets them.
22.3.4.1 Introduction To Traditional Scheduling | ||
22.3.4.2 Functions For Traditional Scheduling |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Long before there was absolute priority (See Absolute Priority), Unix systems were scheduling the CPU using this system. When Posix came in like the Romans and imposed absolute priorities to accommodate the needs of realtime processing, it left the indigenous Absolute Priority Zero processes to govern themselves by their own familiar scheduling policy.
Indeed, absolute priorities higher than zero are not available on many systems today and are not typically used when they are, being intended mainly for computers that do realtime processing. So this section describes the only scheduling many programmers need to be concerned about.
But just to be clear about the scope of this scheduling: Any time a process with a absolute priority of 0 and a process with an absolute priority higher than 0 are ready to run at the same time, the one with absolute priority 0 does not run. If it's already running when the higher priority ready-to-run process comes into existence, it stops immediately.
In addition to its absolute priority of zero, every process has another priority, which we will refer to as "dynamic priority" because it changes over time. The dynamic priority is meaningless for processes with an absolute priority higher than zero.
The dynamic priority sometimes determines who gets the next turn on the CPU. Sometimes it determines how long turns last. Sometimes it determines whether a process can kick another off the CPU.
In Linux, the value is a combination of these things, but mostly it is just determines the length of the time slice. The higher a process' dynamic priority, the longer a shot it gets on the CPU when it gets one. If it doesn't use up its time slice before giving up the CPU to do something like wait for I/O, it is favored for getting the CPU back when it's ready for it, to finish out its time slice. Other than that, selection of processes for new time slices is basically round robin. But the scheduler does throw a bone to the low priority processes: A process' dynamic priority rises every time it is snubbed in the scheduling process. In Linux, even the fat kid gets to play.
The fluctuation of a process' dynamic priority is regulated by another value: The “nice” value. The nice value is an integer, usually in the range -20 to 20, and represents an upper limit on a process' dynamic priority. The higher the nice number, the lower that limit.
On a typical Linux system, for example, a process with a nice value of 20 can get only 10 milliseconds on the CPU at a time, whereas a process with a nice value of -20 can achieve a high enough priority to get 400 milliseconds.
The idea of the nice value is deferential courtesy. In the beginning, in the Unix garden of Eden, all processes shared equally in the bounty of the computer system. But not all processes really need the same share of CPU time, so the nice value gave a courteous process the ability to refuse its equal share of CPU time that others might prosper. Hence, the higher a process' nice value, the nicer the process is. (Then a snake came along and offered some process a negative nice value and the system became the crass resource allocation system we know today).
Dynamic priorities tend upward and downward with an objective of smoothing out allocation of CPU time and giving quick response time to infrequent requests. But they never exceed their nice limits, so on a heavily loaded CPU, the nice value effectively determines how fast a process runs.
In keeping with the socialistic heritage of Unix process priority, a process begins life with the same nice value as its parent process and can raise it at will. A process can also raise the nice value of any other process owned by the same user (or effective user). But only a privileged process can lower its nice value. A privileged process can also raise or lower another process' nice value.
GNU C Library functions for getting and setting nice values are described in See section Functions For Traditional Scheduling.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This section describes how you can read and set the nice value of a process. All these symbols are declared in ‘sys/resource.h’.
The function and macro names are defined by POSIX, and refer to "priority," but the functions actually have to do with nice values, as the terms are used both in the manual and POSIX.
The range of valid nice values depends on the kernel, but typically it
runs from -20
to 20
. A lower nice value corresponds to
higher priority for the process. These constants describe the range of
priority values:
PRIO_MIN
The lowest valid nice value.
PRIO_MAX
The highest valid nice value.
Return the nice value of a set of processes; class and id specify which ones (see below). If the processes specified do not all have the same nice value, this returns the lowest value that any of them has.
On success, the return value is 0
. Otherwise, it is -1
and ERRNO
is set accordingly. The errno
values specific
to this function are:
ESRCH
The combination of class and id does not match any existing process.
EINVAL
The value of class is not valid.
If the return value is -1
, it could indicate failure, or it could
be the nice value. The only way to make certain is to set errno =
0
before calling getpriority
, then use errno != 0
afterward as the criterion for failure.
Set the nice value of a set of processes to niceval; class and id specify which ones (see below).
The return value is 0
on success, and -1
on
failure. The following errno
error condition are possible for
this function:
ESRCH
The combination of class and id does not match any existing process.
EINVAL
The value of class is not valid.
EPERM
The call would set the nice value of a process which is owned by a different
user than the calling process (i.e., the target process' real or effective
uid does not match the calling process' effective uid) and the calling
process does not have CAP_SYS_NICE
permission.
EACCES
The call would lower the process' nice value and the process does not have
CAP_SYS_NICE
permission.
The arguments class and id together specify a set of processes in which you are interested. These are the possible values of class:
PRIO_PROCESS
One particular process. The argument id is a process ID (pid).
PRIO_PGRP
All the processes in a particular process group. The argument id is a process group ID (pgid).
PRIO_USER
All the processes owned by a particular user (i.e., whose real uid indicates the user). The argument id is a user ID (uid).
If the argument id is 0, it stands for the calling process, its process group, or its owner (real uid), according to class.
Increment the nice value of the calling process by increment.
The return value is the new nice value on success, and -1
on
failure. In the case of failure, errno
will be set to the
same values as for setpriority
.
Here is an equivalent definition of nice
:
int nice (int increment) { int result, old = getpriority (PRIO_PROCESS, 0); result = setpriority (PRIO_PROCESS, 0, old + increment); if (result != -1) return old + increment; else return -1; } |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
On a multi-processor system the operating system usually distributes the different processes which are runnable on all available CPUs in a way which allows the system to work most efficiently. Which processes and threads run can be to some extend be control with the scheduling functionality described in the last sections. But which CPU finally executes which process or thread is not covered.
There are a number of reasons why a program might want to have control over this aspect of the system as well:
The POSIX standard up to this date is of not much help to solve this problem. The Linux kernel provides a set of interfaces to allow specifying affinity sets for a process. The scheduler will schedule the thread or process on on CPUs specified by the affinity masks. The interfaces which the GNU C library define follow to some extend the Linux kernel interface.
This data set is a bitset where each bit represents a CPU. How the system's CPUs are mapped to bits in the bitset is system dependent. The data type has a fixed size; in the unlikely case that the number of bits are not sufficient to describe the CPUs of the system a different interface has to be used.
This type is a GNU extension and is defined in ‘sched.h’.
To manipulate the bitset, to set and reset bits, a number of macros is
defined. Some of the macros take a CPU number as a parameter. Here
it is important to never exceed the size of the bitset. The following
macro specifies the number of bits in the cpu_set_t
bitset.
The value of this macro is the maximum number of CPUs which can be
handled with a cpu_set_t
object.
The type cpu_set_t
should be considered opaque; all
manipulation should happen via the next four macros.
This macro initializes the CPU set set to be the empty set.
This macro is a GNU extension and is defined in ‘sched.h’.
This macro adds cpu to the CPU set set.
The cpu parameter must not have side effects since it is evaluated more than once.
This macro is a GNU extension and is defined in ‘sched.h’.
This macro removes cpu from the CPU set set.
The cpu parameter must not have side effects since it is evaluated more than once.
This macro is a GNU extension and is defined in ‘sched.h’.
This macro returns a nonzero value (true) if cpu is a member of the CPU set set, and zero (false) otherwise.
The cpu parameter must not have side effects since it is evaluated more than once.
This macro is a GNU extension and is defined in ‘sched.h’.
CPU bitsets can be constructed from scratch or the currently installed affinity mask can be retrieved from the system.
This functions stores the CPU affinity mask for the process or thread
with the ID pid in the cpusetsize bytes long bitmap
pointed to by cpuset. If successful, the function always
initializes all bits in the cpu_set_t
object and returns zero.
If pid does not correspond to a process or thread on the system
the or the function fails for some other reason, it returns -1
and errno
is set to represent the error condition.
ESRCH
No process or thread with the given ID found.
EFAULT
The pointer cpuset is does not point to a valid object.
This function is a GNU extension and is declared in ‘sched.h’.
Note that it is not portably possible to use this information to retrieve the information for different POSIX threads. A separate interface must be provided for that.
This function installs the cpusetsize bytes long affinity mask pointed to by cpuset for the process or thread with the ID pid. If successful the function returns zero and the scheduler will in future take the affinity information into account.
If the function fails it will return -1
and errno
is set
to the error code:
ESRCH
No process or thread with the given ID found.
EFAULT
The pointer cpuset is does not point to a valid object.
EINVAL
The bitset is not valid. This might mean that the affinity set might not leave a processor for the process or thread to run on.
This function is a GNU extension and is declared in ‘sched.h’.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The amount of memory available in the system and the way it is organized
determines oftentimes the way programs can and have to work. For
functions like mmap
it is necessary to know about the size of
individual memory pages and knowing how much memory is available enables
a program to select appropriate sizes for, say, caches. Before we get
into these details a few words about memory subsystems in traditional
Unix systems will be given.
22.4.1 Overview about traditional Unix memory handling | ||
22.4.2 How to get information about the memory subsystem? |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Unix systems normally provide processes virtual address spaces. This means that the addresses of the memory regions do not have to correspond directly to the addresses of the actual physical memory which stores the data. An extra level of indirection is introduced which translates virtual addresses into physical addresses. This is normally done by the hardware of the processor.
Using a virtual address space has several advantage. The most important is process isolation. The different processes running on the system cannot interfere directly with each other. No process can write into the address space of another process (except when shared memory is used but then it is wanted and controlled).
Another advantage of virtual memory is that the address space the processes see can actually be larger than the physical memory available. The physical memory can be extended by storage on an external media where the content of currently unused memory regions is stored. The address translation can then intercept accesses to these memory regions and make memory content available again by loading the data back into memory. This concept makes it necessary that programs which have to use lots of memory know the difference between available virtual address space and available physical memory. If the working set of virtual memory of all the processes is larger than the available physical memory the system will slow down dramatically due to constant swapping of memory content from the memory to the storage media and back. This is called “thrashing”.
A final aspect of virtual memory which is important and follows from what is said in the last paragraph is the granularity of the virtual address space handling. When we said that the virtual address handling stores memory content externally it cannot do this on a byte-by-byte basis. The administrative overhead does not allow this (leaving alone the processor hardware). Instead several thousand bytes are handled together and form a page. The size of each page is always a power of two byte. The smallest page size in use today is 4096, with 8192, 16384, and 65536 being other popular sizes.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The page size of the virtual memory the process sees is essential to
know in several situations. Some programming interface (e.g.,
mmap
, see section Memory-mapped I/O) require the user to provide
information adjusted to the page size. In the case of mmap
is it
necessary to provide a length argument which is a multiple of the page
size. Another place where the knowledge about the page size is useful
is in memory allocation. If one allocates pieces of memory in larger
chunks which are then subdivided by the application code it is useful to
adjust the size of the larger blocks to the page size. If the total
memory requirement for the block is close (but not larger) to a multiple
of the page size the kernel's memory handling can work more effectively
since it only has to allocate memory pages which are fully used. (To do
this optimization it is necessary to know a bit about the memory
allocator which will require a bit of memory itself for each block and
this overhead must not push the total size over the page size multiple.
The page size traditionally was a compile time constant. But recent development of processors changed this. Processors now support different page sizes and they can possibly even vary among different processes on the same system. Therefore the system should be queried at runtime about the current page size and no assumptions (except about it being a power of two) should be made.
The correct interface to query about the page size is sysconf
(see section Definition of sysconf
) with the parameter _SC_PAGESIZE
.
There is a much older interface available, too.
The getpagesize
function returns the page size of the process.
This value is fixed for the runtime of the process but can vary in
different runs of the application.
The function is declared in ‘unistd.h’.
Widely available on System V derived systems is a method to get information about the physical memory the system has. The call
sysconf (_SC_PHYS_PAGES) |
returns the total number of pages of physical the system has. This does not mean all this memory is available. This information can be found using
sysconf (_SC_AVPHYS_PAGES) |
These two values help to optimize applications. The value returned for
_SC_AVPHYS_PAGES
is the amount of memory the application can use
without hindering any other process (given that no other process
increases its memory usage). The value returned for
_SC_PHYS_PAGES
is more or less a hard limit for the working set.
If all applications together constantly use more than that amount of
memory the system is in trouble.
The GNU C library provides in addition to these already described way to
get this information two functions. They are declared in the file
‘sys/sysinfo.h’. Programmers should prefer to use the
sysconf
method described above.
The get_phys_pages
function returns the total number of pages of
physical the system has. To get the amount of memory this number has to
be multiplied by the page size.
This function is a GNU extension.
The get_phys_pages
function returns the number of available pages of
physical the system has. To get the amount of memory this number has to
be multiplied by the page size.
This function is a GNU extension.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The use of threads or processes with shared memory allows an application to take advantage of all the processing power a system can provide. If the task can be parallelized the optimal way to write an application is to have at any time as many processes running as there are processors. To determine the number of processors available to the system one can run
sysconf (_SC_NPROCESSORS_CONF) |
which returns the number of processors the operating system configured. But it might be possible for the operating system to disable individual processors and so the call
sysconf (_SC_NPROCESSORS_ONLN) |
returns the number of processors which are currently inline (i.e., available).
For these two pieces of information the GNU C library also provides functions to get the information directly. The functions are declared in ‘sys/sysinfo.h’.
The get_nprocs_conf
function returns the number of processors the
operating system configured.
This function is a GNU extension.
The get_nprocs
function returns the number of available processors.
This function is a GNU extension.
Before starting more threads it should be checked whether the processors are not already overused. Unix systems calculate something called the load average. This is a number indicating how many processes were running. This number is average over different periods of times (normally 1, 5, and 15 minutes).
This function gets the 1, 5 and 15 minute load averages of the
system. The values are placed in loadavg. getloadavg
will
place at most nelem elements into the array but never more than
three elements. The return value is the number of elements written to
loadavg, or -1 on error.
This function is declared in ‘stdlib.h’.
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated by root on January, 9 2009 using texi2html 1.78.