schedtool v0.99
Copyright (C) 2002/2003 Freek <freeky@_NOSPAM_uni.de>
Release under GPL, version 2 (see LICENSE)
Use at your own risk.
Inspired by setbatch (C) 2002 Ingo Molnar
Suggestions are welcome.

Content:
--------
-Descrition and usage of schedtool
-Appendix A: A course into Multi-Level-Feedback-Queue-scheduling


Info:
-----
Born in the need of querying and setting a process' scheduling-policies
under Linux.
Recently, querying and setting of CPU-affinity was added.
If you don't know about scheduling policies, you probably don't want to
use this program - or learn and read "man sched_setscheduler".
I WARNED YOU!
All output, even errors, go to STDOUT to ease piping.


Usage:
------
... is pretty straight forward:

Query process(es):
#> schedtool <LIST OF PIDs>

Query your $SHELL for its setting:
#> schedtool $$


Set process(es):
to (B)ATCH mode:
	#> schedtool -3 <LIST OF PIDs>	or
	#> schedtool -B <LIST OF PIDs>

to (N)ORMAL mode:
	#> schedtool -0 <LIST OF PIDs>
	#> schedtool -N <LIST OF PIDs>

Useful is to set the current shell to SCHED_BATCH and so all started processes
will be SCHED_BATCH ([1]):
#> schedtool -3 $$


Use schedtool to execute process with altered parameters (the new process will
overwrite schedtool's process image)
(NOTE: No more quotation marks, just like with nice!)
#> schedtool [SCHED_PARAMETERS] -e command -arg1 -arg2 stuff


FIFO and RR are also supported; they need an additional param (static 
priority).

to (F)IFO:
	#> schedtool -1 -p STATIC_PRIO <LIST OF PIDs>	or
	#> schedtool -F -p STATIC_PRIO <LIST OF PIDs>

to (R)R (Round-Robin)
	#> schedtool -2 -p STATIC_PRIO <LIST OF PIDs>	or
	#> schedtool -R -p STATIC_PRIO <LIST OF PIDs>

where STATIC_PRIO is a number from 1-99; higher values mean higher priority in
that scheduling class (relative to other processes in the same class).


To give a PID a certain CPU-affinity, use the -a switch.
The value is used as a simple bitmask, the bit set to 1 denoting the 
PID may run on that CPU, the bit unset (0) denoting it must not.

The following picture uses only 16 bits for example purpose.
The resulting value is the bitwise OR of the single values for each CPU.
CPU0 (the first CPU in your system) is denoted by the least significant bit
(here, the one on the right side).

  CPU 0-----------,
 CPU 1-----------,|
  ...            ||
mask             VV		means				value  == dec
--------------------------------------------------------------------------
0000 0000 0000 0001	->	run only on CPU0	->	0x1    ==  1
0000 0000 0000 1001	->	run on CPU0 AND CPU3	->	0x9    ==  9
0000 0000 0000 1111	->	run on CPU0-CPU4	->	0xF    == 15
1111 1111 1111 1111	->	run on CPU0-CPU15	->	0xFFFF ==2^16-1

To set back to the default (PID may run on all CPUs), use the mask
0xFFFFFFFF (the kernel will automatically reduce it to the max # of cpus)


Complex example:
#> schedtool -R -p 50 -a 0x2 -e mplayer file.avi
Execute mplayer file.avi with SCHED_RR, static priority 50, affinity 0x2 
(only on CPU1).


About static priority:
----------------------
Static priority is something completely different than the nice-level; the
nice-level is added to the dynamic priority, and the higher it gets, the more 
the process is "punished"([2]), whereas the static priority is used to find 
the next process to run in the current scheduling class and the higher it is 
the more preferred >in general< the process is over others, e.g. when
it's becomming ready after a blocking action.

STATIC_PRIO can't be assigned to SCHED_NORMAL or SCHED_BATCH. The
code won't prevent this (a warning is printed - think UNIX), you maybe get an 
error later at the setting-call.


Policy overview + where to use:
-------------------------------
SCHED_NORMAL
is the standard scheduling policy and good for the average
job with reasonable interaction.


SCHED_BATCH
is encuraged for long-running and non-interactive
processes; the timeslice is considerably longer (1.5s I think) -
these processes, though, are interrupted almost anytime by
SCHED_NORMAL/OTHER ones to guarantee interactivenes.
Maybe you want to renice(8) daemons like ypbind and others which wakeup
regulary to do non-time-critical stuff to nice-level 18 or so.

Users are encuraged to set their computing jobs to SCHED_BATCH. Or, as
admin of a compute-server, you could set their shells to SCHED_BATCH
via the login-script.
The best way is to have a short talk and give some explanation about
the benefits.


SCHED_FF and SCHED_RR
are for real-time constraints.
Don't use them for normal stuff, because they've got extremely short
time-slices increasing the context-switching overhead and they won't
let other processes run until they get blocked by a system-call like
read() or actively free themselves from the CPU via the system-call 
sched_yield(2).


SCHED_ISO
is a new mode, currently only in Con's patches, to mimick the 
real-time class for non-root users. To quote Con:
"Any task trying to start as real time that doesn't have authority to do so 
will be set to SCHED_ISO. This is a non-expiring scheduler policy designed to 
guarantee a timeslice within a reasonable latency while preventing starvation.
Good for gaming, video at the limits of hardware, video capture etc.
It is best set using the schedtool by a normal user trying to start something
as SCHED_RR." [http://kerneltrap.org/node/view/2159]


As a start you can read the new file sched-design.txt as a good overview, but 
be warned, that *some* things may be outdated by the new O(1)-patches.
Then proceed to sched_setscheduler(2) - it gives a very good overview
and is strongly recommended.


Some Numbers et al:
-------------------
Running SamReport, a license reporting tool from www.globetrotter.com
written in JAVA, on an else quite idle P3-600/2.4.18 in SCHED_BATH resulted
in a 1-2 min shorter runtime with ~41 min being the total time.

Ingo did, however, post some very impressive numbers, showing up to
300% (iirc) improvements for network-server loads (irc-server?).


Final words:
------------
If you feel you are able to make this software better or you can report
some numbers with the different scheduling policies, please contact me.
Feedback is appreciated.
It's Freek <freeky@_NOSPAM_uni.de>


- -- -
[1]:
I noticed when using samreport, a license reporting tool written
in java, that the initially started threads are SCHED_BATCH, but newly
created threads are SCHED_NORMAL again - ??.

[2]:
A bit simplyfied - it's not all that easy :-) Go on to Appendix A for
an example on how scheduling is performed in Solaris.

[3]: (see also [4])
Nice level and dynamic priority are somewhat "strange": sometimes, higher
values mean higher priority (to be put on CPU when process ready); sometimes,
lower values mean higher priority.
At the moment, I confirm my system being the following:
- The nice-level ist SUBSTRACTED from the dynamic priority, thus giving a
Process nice -10 means INCREASING it's priority (valuewise) by 10 points.
- Higher values mean higher priority.
Use "ps -eO pri,nice" and look for yourself.



APPENDIX A:
-----------
This appendix uses information originating from the "System
Programming I"-course at my university; the examples are using Solaris
2.X, but I think, Linux is doing it in a >similar< (albeit not that 
overcomplicated) way.

Solaris has 60 wait queues for the class TS (TimeSharing); there are
other classes as system and RealTime as well.
A TS-queue looks like this (which is basically a set of rules):

Level    ts_quantum    ts_tqexp     ts_maxwait    ts_lwait   ts_slpret
0        200           0            0             50         50
.        .             .            .             .          .
.        .             .            .             .          .
.        .             .            .             .          .
44       40            34           0             55         55
45       40            35           0             56         56
.        .             .            .             .          .
.        .             .            .             .          .
.        .             .            .             .          .
59       20            49           32000         59         59


You can display all these numbers on a Solaris-box using
# dispadmin -c TS -g

Level:
	just an queue-ID.

ts_quantum:
	the maximum timeslice - the maximum time, the process
	is allowed to run continuesly until it's interrupted and another
	process is physically put on the CPU.

ts_tqexp: 
	if the process uses it's timeslice entirely, it's put into that
	queue [cf. Level].

ts_maxwait:
	maximum time to wait for the process in that queue without being
	run, in seconds.

ts_lwait:
	if one process stays too long in the current queue, it's put
	into that queue.
ts_slpret:
	queue to put the process in after it was blocked, e.g. in a
	syscall.


Let's start an imaginary process and look what's happening:
Start ->
-> queue 59, ts_quantum  20ms -> queue 49, ts_quantum  40ms
-> queue 39, ts_quantum  80ms -> queue 29, ts_quantum 120ms
-> queue 19, ts_quantum 160ms -> queue  9, ts_quantum 200ms

You see how this only number-crunching process is put into queues that
allow him to use the CPU for more and more time.


Now let's do the process a blocking action:

queue  0, ts_quantum 200ms, after e.g. 100ms blocking call! --> 
queue 50, ts_quantum  40ms, after e.g.  20ms blocking call! -->
queue 58, ts_quantum  40ms

Now you see how this process is "punished", or from another point of
view, the scheduler thinks, this is an interactive process computing a
bit and then outputting data, so it's put into a queue that has
averagely the same computing time until a this output occurs.
So the schedulers knows pretty much about the current state of the
machine and can plan accordingly.

The dynamic priority is something like an age - the higher[4] it is the more 
likely you get a seat :) (the CPU).
There are 4 rules:
-if a process is not run, it ages - the dynamic priority rises.
-if a process is running, the dynamic priority is lowered.
-the process with the (at the moment) highest priority is put onto the CPU.
-processes with lower priority are/can be interrupted by processes with
higher priority.

This garantees that no process is running for too long and others are
waiting for too long.

Phew.
	-End Of Documentation

- -- -

[4]:
higher (priority) in means of more important to run in the near future;
higher does not automatically mean a higher value in it's PCB[5]

[5]:
Process Controll Block, some structure where imporatant accounting and
else useful information is stored, usually only used by the kernel.
