¿Quieres dar formación sobre rendimiento en Solaris/OpenSolaris a tus técnicos?

A raíz del interés mostrado en las últimas charlas he decidido ofrecer mis servicios para consultoría y formación a empresas.

Ponte en contacto conmigo para pedir información.

OpenSolaris: Scheduling Classes

Introducción

En los distintos unix cada proceso tiene definida una prioridad, en base a esta se decide cual de ellos se debe ejecutar primero y cual debe esperar a que una cpu se encuentre libre. Con los sistemas multithread cada uno de los hilos de un proceso puede tener una prioridad distinta, además esta es dinámica, es decir durante su vida puede variar en función de varios parámetros, como pueda ser la carga el sistema, como interactúe con otros hilos, ...

Las Scheduling Classes en Opensolaris

Cuando un threads es creado en Solaris se asigna a una scheduling class, para que nos entendemos esta define el rango de prioridades en el que fluctuará durante su vida. Existen 6 rangos distintos.

  • Timeshare (TS): Es la scheduling class por defecto, la prioridad del hilo aumenta a medida que va esperando un cpu libre, una vez consiga cpu se ejecutará hasta que se agote su quantum.
  • Interactive (IA): Parecida a la anterior, solo se usa en entornos de escritorio, los threads correspondientes a los procesos X window reciben un incremento de prioridad.
  • Fair Share (FSS): El tiempo de cpu se divide en unidades llamadas shares, cada thread puede consumir x shares dependiendo del número de threads que hay en esa scheduling class, de su consumo reciente y de su prioridad.
  • Fixed Priority (FX): El thread tiene las misma prioridad durante todo su ciclo de vida.
  • Real Time (RT): Es el rango de prioridades altas, garantiza el mínimo tiempo de lantencia entre que el thread pasa a estado running hasta que se le asigna CPU.
  • System (SYS): Es la clase usada para los threads del kernel, tiene prioridad superior a las demás excepto la Real Time.

Las estructuras para el uso de las distintas clases se cargan de forma dinámica cuando son requeridas. Con mdb podemos ver las que hay actualmente cargadas.

Mirando dentro del kernel

Podemos jugar un poco con kmbd para ver las distintas estructuras del kernel. Con el dcm ::class podemos ver actualmente las distintas prioridades que tenemos cargadas en el kernel

root@myhost:~# mdb -k
Loading modules: [ unix genunix specfs dtrace uppc pcplusmp scsi_vhci ufs ip hook neti sctp arp usba md lofs zfs random
nfs ipc ptm crypto logindmux sppp ]
> ::class
SLOT NAME       INIT FCN                 CLASS FCN
   0 SYS        sys_init                 sys_classfuncs
   1 TS         ts_init                  ts_classfuncs
   2 FX         fx_init                  fx_classfuncs
   3            0                        0
   4            0                        0
   5            0                        0
   6            0                        0
   7            0                        0
   8            0                        0
   9            0                        0

Ahora vamos a jugar un poco, el proceso 475 es la shell de mi consola, al ser un proceso de usuario no relacionado con las X su scheduling class es TS.

> ::ps
S    PID   PPID   PGID    SID    UID      FLAGS     ADDR NAME
R      0      0      0      0      0 0x00000001 fec205d0 sched
R      3      0      0      0      0 0x00020001 d5286308 fsflush
R      2      0      0      0      0 0x00020001 d5286b88 pageout
R      1      0      0      0      0 0x4a004000 d5287408 init
R   1559      1   1559   1559      0 0x42000000 d527e890 nscd
R    700      1    700    700      0 0x42000000 d94bd140 devfsadm
R    681      1    637    637      0 0x4a004000 d526a030 gksu
R    682    681    637    637      0 0x4a004000 d94c1038 gnome-terminal
R   1768    682   1768   1768      0 0x4a014000 d94bc040 bash
R   1784   1768   1784   1768      0 0x4a004000 d94ba348 more
R    745    682    745    745      0 0x4a014000 d94bc8c0 bash
R    686    682    686    686      0 0x4a014000 d94bd9c0 bash
R   1785    686   1785    686      0 0x4a004000 d94babc8 mdb
R    685    682    637    637      0 0x5a006000 d94bf340 gnome-pty-helper
R    671      1    567    567      0 0x4a004000 d94be240 mixer_applet2
R    670      1    567    567      0 0x4a004000 d94beac0 clock-applet
R    667      1    667    667      0 0x42000000 d94c0440 gnome-screensave
R    664      1    639    639      0 0x4a004000 d94bfbc0 mapping-daemon
R    659      1    567    567      0 0x4a004000 d94c3238 trashapplet

La columna ADDR indica la dirección de memoria de la estructura del proceso, usando un walker podemos ver los distintos threads de este, en nuestro caso solo tenemos 1.

> d94bc8c0 ::walk thread
d9a01c00

La dirección de memoria que nos devuelve correspone a la estructura del thread, podéis ver una descripción completa de dicha estructura en el fichero /usr/include/sys/thread.h, en este caso solo nos interesa el campo t_cldata, este es un puntero a la estructura de la scheduling class del thread.

>  d9a01c00 ::print kthread_t ! grep t_cldata
    t_cldata = 0xd95dea88

Con la dirección de memoria obtenida podemos hacer un volcado de la estructura de la clase TS.

> 0xd95dea88 ::print tsproc_t
{
    ts_timeleft = 0xb
    ts_dispwait = 0x8b
    ts_cpupri = 0x3b
    ts_uprilim = 0
    ts_upri = 0
    ts_umdpri = 0x3b
    ts_scpri = 0x6c17
    ts_nice = '\024'
    ts_boost = '\0'
    ts_flags = 0x2
    ts_tp = 0xd9a01c00
    ts_next = 0xd531df38
    ts_prev = ts_plisthead+0x268
    ts_caps = {
        csc_cputime = 0
    }
}

De los distintos campos podemos destacar:

  • ts_timeleft: tiempo que queda antes de agotar el quantum asignado
  • ts_cpupri: es la parte de la prioridad del thread establecida por el sistema
  • ts_upri: es la parte de la prioridad del thread establecida por el usuario

Aquí hay que aclarar que el usuario solo puede modificar uno de los valores de la formula que establece la prioridad final del thread, los demás son controlados por el kernel.

Con el comando priocntl vamos a cambiar la scheduling class de nuestro proceso a Real Time:

 #priocntl -s -c RT -i pid 745

Volvemos a repetir la operación anterior, ahora el campo t_cldata apunta a la estructura de la clase Real Time.

>  d9a01c00 ::print kthread_t ! grep t_cldata
    t_cldata = 0xd8f9f8c0
> 0xd8f9f8c0 ::print rtproc_t
{
    rt_pquantum = 0x64
    rt_timeleft = 0x63
    rt_pri = 0
    rt_flags = 0
    rt_tqsignal = 0
    rt_tp = 0xd9a01c00
    rt_next = 0xd516dcc0
    rt_prev = rt_plisthead
}

La linea de comandos

Por suerte no hace falta bucear por el kernel para ver los distintos valores mas significativos asignados a las scheduling classes, aunque como ejercicio didáctico es divertido :)

Con el comando dispadmin los podemos ver y modificar, aunque no es aconsejable hacer cambios salvo que sepamos muy bien lo que estamos haciendo



root@myhost:~#  dispadmin -l
CONFIGURED CLASSES
==================

SYS     (System Class)
TS      (Time Sharing)
FX      (Fixed Priority)
RT      (Real Time)
root@myhost:~#  dispadmin -c TS -g
# Time Sharing Dispatcher Configuration
RES=1000

# ts_quantum  ts_tqexp  ts_slpret  ts_maxwait ts_lwait  PRIORITY LEVEL
       200         0        50           0        50        #     0
       200         0        50           0        50        #     1
       200         0        50           0        50        #     2
       200         0        50           0        50        #     3
       200         0        50           0        50        #     4
       200         0        50           0        50        #     5
       200         0        50           0        50        #     6
       200         0        50           0        50        #     7
       200         0        50           0        50        #     8
       200         0        50           0        50        #     9
       160         0        51           0        51        #    10
       160         1        51           0        51        #    11
       160         2        51           0        51        #    12
       160         3        51           0        51        #    13
       160         4        51           0        51        #    14
       160         5        51           0        51        #    15
       160         6        51           0        51        #    16
       160         7        51           0        51        #    17
       160         8        51           0        51        #    18
       160         9        51           0        51        #    19
       120        10        52           0        52        #    20
       120        11        52           0        52        #    21
       120        12        52           0        52        #    22
       120        13        52           0        52        #    23
       120        14        52           0        52        #    24
       120        15        52           0        52        #    25
       120        16        52           0        52        #    26
       120        17        52           0        52        #    27
       120        18        52           0        52        #    28
       120        19        52           0        52        #    29
        80        20        53           0        53        #    30
        80        21        53           0        53        #    31
        80        22        53           0        53        #    32
        80        23        53           0        53        #    33
        80        24        53           0        53        #    34
        80        25        54           0        54        #    35
        80        26        54           0        54        #    36
        80        27        54           0        54        #    37
        80        28        54           0        54        #    38
        80        29        54           0        54        #    39
        40        30        55           0        55        #    40
        40        31        55           0        55        #    41
        40        32        55           0        55        #    42
        40        33        55           0        55        #    43
        40        34        55           0        55        #    44
        40        35        56           0        56        #    45
        40        36        57           0        57        #    46
        40        37        58           0        58        #    47
        40        38        58           0        58        #    48
        40        39        58           0        59        #    49
        40        40        58           0        59        #    50
        40        41        58           0        59        #    51
        40        42        58           0        59        #    52
        40        43        58           0        59        #    53
        40        44        58           0        59        #    54
        40        45        58           0        59        #    55
        40        46        58           0        59        #    56
        40        47        58           0        59        #    57
        40        48        58           0        59        #    58
        20        49        59       32000        59        #    59

Finalmente, como ya hemos visto, con el comando priocntl podemos asignar un proceso a una Scheduling class determinada.

root@myhost:~# priocntl -s -c RT -i pid 745
root@myhost:~# priocntl -d -i pid 745
REAL TIME PROCESSES:
    PID   RTPRI       TQNTM    TQSIG
    745       0        1000        0
Creative Commons License
Esta obra está bajo una licencia de Creative Commons.