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.
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'.
*rusage
.
In most systems, processes has only two valid values:
RUSAGE_SELF
RUSAGE_CHILDREN
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
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.
struct timeval ru_utime
struct timeval ru_stime
long int ru_maxrss
long int ru_ixrss
long int ru_idrss
long int ru_isrss
long int ru_minflt
long int ru_majflt
long int ru_nswap
long int ru_inblock
long int ru_oublock
long int ru_msgsnd
long int ru_msgrcv
long int ru_nsignals
long int ru_nvcsw
long int ru_nivcsw
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.
struct rusage
data type
described above.
vm_utime
ru_utime
in struct rusage
vm_stime
ru_stime
in struct rusage
vm_idsrss
ru_idrss
and ru_isrss
in struct rusage
vm_ixrss
ru_ixrss
in struct rusage
vm_maxrss
ru_maxrss
in
struct rusage
vm_majflt
ru_majflt
in struct rusage
vm_minflt
ru_minflt
in struct rusage
vm_nswap
ru_nswap
in struct rusage
vm_inblk
ru_inblk
in struct rusage
vm_oublk
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'.
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 symbols for use with getrlimit
, setrlimit
,
getrlimit64
, and seterlimit64
are defined in
`sys/resource.h'.
*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.
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.
*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.
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.
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
rlim_t rlim_max
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'.
rlimit
structure above, but
its components have wider ranges. It has two fields:
rlim64_t rlim_cur
rlimit.rlim_cur
, but with a different type.
rlim64_t rlim_max
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
SIGXCPU
. The value is
measured in seconds. See section Operation Error Signals.
RLIMIT_FSIZE
SIGXFSZ
. See section Operation Error Signals.
RLIMIT_DATA
RLIMIT_STACK
SIGSEGV
signal.
See section Program Error Signals.
RLIMIT_CORE
RLIMIT_RSS
RLIMIT_MEMLOCK
RLIMIT_NPROC
fork
will fail
with EAGAIN
. See section Creating a Process.
RLIMIT_NOFILE
RLIMIT_OFILE
errno
EMFILE
. See section Error Codes. Not all systems support this limit;
GNU does, and 4.4 BSD does.
RLIMIT_AS
brk
, malloc
, mmap
or sbrk
, the
allocation function fails.
RLIM_NLIMITS
RLIM_NLIMITS
.
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
SETFSIZE
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
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
RLIMIT_CPU
for setrlimit
.
LIM_FSIZE
RLIMIT_FSIZE
for setrlimit
.
LIM_DATA
RLIMIT_DATA
for setrlimit
.
LIM_STACK
RLIMIT_STACK
for setrlimit
.
LIM_CORE
RLIMIT_COR
for setrlimit
.
LIM_MAXRSS
RLIMIT_RSS
for setrlimit
.
The return value is zero for success, and -1
with errno
set
accordingly for failure:
EPERM
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.
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 accomodate 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 processeses have absolute priority 0, the traditional scheduling policy described in section Traditional Scheduling applies. Otherwise, the policies described in section 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 section 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.
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 per centage 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.
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 section 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 section 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 section 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.
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 section 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'.
int sched_priority
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_setschedule
keeps the existing scheduling policy.
The following macros represent the valid values for policy:
SCHED_OTHER
SCHED_FIFO
SCHED_RR
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
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
EINVAL
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
EINVAL
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
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
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.
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 absolulte priority have taken all they want, the scheduling described herein determines who among the great unwashed processes gets them.
Long before there was absolute priority (See section Absolute Priority), Unix systems were scheduling the CPU using this system. When Posix came in like the Romans and imposed absolute priorities to accomodate 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.
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
PRIO_MAX
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
EINVAL
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.
The return value is the nice value on success, and -1
on
failure. The following errno
error condition are possible for
this function:
ESRCH
EINVAL
EPERM
CAP_SYS_NICE
permission.
EACCES
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
PRIO_PGRP
PRIO_USER
If the argument id is 0, it stands for the calling process, its process group, or its owner (real uid), according to class.
setpriority
.
Here is an equivalent definition of nice
:
int nice (int increment) { int old = getpriority (PRIO_PROCESS, 0); return setpriority (PRIO_PROCESS, 0, old + increment); }
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.
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.
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.
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.
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.
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.
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'.
get_nprocs_conf
function returns the number of processors the
operating system configured.
This function is a GNU extension.
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).
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'.
Go to the first, previous, next, last section, table of contents.