En el artículo anterior vimos las nociones básicas para poder utilizar el debugger, ahora vamos a ver, de una forma práctica, cómo podemos sacar provecho a mdb, para ello vamos a realizar varios ejemplos, en los que podremos obtener información de los procesos, el uso de las CPUs, los ficheros abiertos, etc.
Ejemplo 1: Listado de los ficheros abiertos por un proceso
Todos los procesos disponen de una lista de ficheros abiertos, esta lista la podemos encontrar en el campo uf_info_t p_user.u_finfo, vamos a utilizar el comando ::ps para sacar el listado de todos los procesos que están corriendo y le pasamos la salida al comando grep del SO mediante la utilización del carácter ! a modo de tubería. Utilizamos la dirección de memoria donde se encuentran los datos de la estructura proc_t del proceso.
(root@huelva)# mdb -k
Loading modules: [ unix krtld genunix ip usba ipc random nfs ptm ]
>
> ::ps ! grep syslog
R 5021 1 5021 5021 0 0x00000008 00000301386a5508 syslogd
>
> 00000301386a5508::print -t proc_t p_user.u_finfo
{
kmutex_t p_user.u_finfo.fi_lock = {
void * [1] _opaque = [ 0 ]
}
kmutex_t p_user.u_finfo.fi_pad = {
void * [1] _opaque = [ 0 ]
}
int p_user.u_finfo.fi_nfiles = 0x1ff
volatile uf_entry_t *p_user.u_finfo.fi_list = 0x30382f6a000
uf_rlist_t *p_user.u_finfo.fi_rlist = 0
}
>
> ::sizeof uf_entry_t
sizeof (uf_entry_t) = 0x28
>
>
Hemos utilizado el parámetro -t en el comando ::print para que nos devuelva la estructura con todos los tipos de datos de los distintos miembros. De lo devuelto por ::print, nos interesan dos campos, fi_nfiles que contiene el número de elementos del array y fi_list es un puntero al array de elementos de tipo uf_entry_t. Con el comando ::sizeof tipo podemos obtener el tamaño de los elementos del array.
| Dir | Pos. Array |
| 0×30382f6a000 | 1 |
| 0×30382f6a028 | 2 |
| 0×30382f6a050 | 3 |
| 0×30382f6a078 | 4 |
| 0×30382f6a0a0 | 5 |
| … | 0×1ff |
> > 0x30382f6a000,0x1ff::print uf_entry_t uf_file |::print file_t f_vnode f_vnode = 0x3000039dd40 f_vnode = 0x3000039dd40 f_vnode = 0x3000039dd40 f_vnode = 0x3000373c7b8 f_vnode = 0x300035f3d08 f_vnode = 0x301557b9c88 f_vnode = 0x30012bf3848 f_vnode = 0x3019887d088 f_vnode = 0x3557b326928 f_vnode = 0x3000373d2a8 f_vnode = 0x3012b81c828 mdb: failed to read f_vnode pointer at 10: no mapping for address mdb: failed to read f_vnode pointer at 10: no mapping for address mdb: failed to read f_vnode pointer at 10: no mapping for address mdb: failed to read f_vnode pointer at 10: no mapping for address mdb: failed to read f_vnode pointer at 10: no mapping for address mdb: failed to read f_vnode pointer at 10: no mapping for address ...
Cada elemento de array es de tipo uf_entry_t esta estructura de datos tiene un miebro de tipo file_t, el cual a su vez tienen un miembro llamado f_vnode que es un puntero a un vnode, con la linea anterior hemos obtenido la lista del primer vnode de todos los ficheros abiertos por el proceso.
Podríamos utilizar el comando ::vnode2path el cual, como su propio nombre indica, devuelve el pathname de un vnode. Esta vez solo vamos a sacar los 11 primeros elementos del array.
> > 0x30382f6a000,0xb::print uf_entry_t uf_file |::print -t file_t f_vnode | ::vnode2path / / / /var/adm/messages /var/log/syslog >
Otra forma de conocer el nombre de los ficheros que tiene abierto un proceso es mediante el comando ::dnlc el cual devuelve la lista de todos los nombres de fichero que están registrados en el directory name lookup cache (DNLC), la primera columna de la salida del comando corresponde al vnode del fichero.
> ::dnlc VP DVP NAME 0000030155e040a0 00000300993b51d8 si 00000300994d40a0 00000300ba091c60 statusdock_button.png 0000030155fe00a0 0000030005697118 usba 00000300992a40a0 000003000368ba30 dfl3O9t0f0002778 00000300597900a0 00000300598d8af8 SchoolBoldItalicCE10.pcf.Z 00000300a36ee0a0 000003007d9ba4e8 runtime.html 00000300cf04c0a0 00000300cf064d20 show-path 00000300b9d380a0 00000300b9d38fe0 gmatch.3gen 000003578004a0a0 00000300b9748590 tool_16.gif ...
Ejemplo 2: Estado de las CPUs
Ver qué está ocurriendo con las CPUs de nuestro sistema es algo que puede ayudar a entender donde se puede estar produciendo un cuello de botella. Para chequear el estado de las CPUs de nuestro sistema podemos utilizar el comando ::cpuinfo [-v]. La salida del comando será parecida a la siguiente.
(root@huelva)# mdb -k Loading modules: [ unix krtld genunix ip usba ipc random nfs ptm ] > ::cpuinfo ID ADDR FLG NRUN BSPL PRI RNRN KRNRN SWITCH THREAD PROC 0 300019d2000 1b 0 0 59 no no t-0 3578db997a0 mdb 1 00001400000 1b 0 0 59 no no t-0 3578dbc6d60 sshd
Existe una línea por cada CPU del sistema, cada una de las cuales dipone de una serie de columnas, de las cuales nos vamos a centrar en:
-ADDR es la dirección de memoria de la estructura de tipo cpu_t que contiene la información con la que trabaja el Kernel.
-FLG son los flag de estado de la CPU.
| 0×01 | RUNNING |
| 0×02 | READY |
| 0×04 | QUIESCED |
| 0×08 | EXISTS |
| 0×10 | ENABLE |
| 0×20 | OFFLINE |
| 0×40 | POWEROFF |
> ::cpuinfo
ID ADDR FLG NRUN BSPL PRI RNRN KRNRN SWITCH THREAD PROC
0 300019d2000 1b 0 0 -1 no no t-0 2a100013d40 (idle)
1 00001400000 1b 0 0 59 no no t-0 3578db997a0 mdb
> 0x300019d2000::print cpu_t
{
cpu_id = 0
cpu_seqid = 0x1
cpu_flags = 0x1b
cpu_thread = 0x3578db997a0
cpu_idle_thread = 0x2a100013d40
...
cpu_runrun = ' 0'
cpu_kprunrun = ' 0'
cpu_chosen_level = 0xffff
cpu_dispthread = 0x3578db997a0
cpu_thread_lock = 0
cpu_dontsteal = 0
cpu_dispatch_pri = 0x3b
cpu_last_swtch = 0x35998b68
...
cpu_stat = {
__cpu_stat_lock = [ 0, 0 ]
cpu_sysinfo = {
cpu = [ 0x3490af0a, 0x2ea12b, 0xbfc33d, 0x1a756c ]
wait = [ 0x1a756c, 0, 0 ]
bread = 0xc47
bwrite = 0x88b1d7
lread = 0x3888759
lwrite = 0x200c105
phread = 0x502a
phwrite = 0x52
pswitch = 0x5c882f7b
trap = 0x3103dc24
intr = 0x826f42f
syscall = 0x7e9bea80
sysread = 0x65dad0e
syswrite = 0x12788cd
sysfork = 0x4bdac6
sysvfork = 0x239ef
sysexec = 0x656e0a
...
nthreads = 0x520ca9
cpumigrate = 0xa40d9eb
xcalls = 0x163f39ef
mutex_adenters = 0x34db367
rw_rdfails = 0xb55
rw_wrfails = 0x8e4
...
}
cpu_syswait = {
iowait = 0
swap = 0
physio = 0
}
cpu_vminfo = {
pgrec = 0x7182587
pgfrec = 0x7182587
pgin = 0x23965
pgpgin = 0x5a939
pgout = 0
pgpgout = 0
swapin = 0
pgswapin = 0
swapout = 0
pgswapout = 0
zfod = 0x5b2b425
dfree = 0
scan = 0x2fff
rev = 0
hat_fault = 0
as_fault = 0x2a7108c8
maj_fault = 0x1c360
cow_fault = 0x86e3a25
prot_fault = 0x7c9636b
softlock = 0x1f509
kernel_asflt = 0
pgrrun = 0x1
execpgin = 0x6550
execpgout = 0
execfree = 0
anonpgin = 0
anonpgout = 0
anonfree = 0
fspgin = 0x543e9
fspgout = 0
fsfree = 0
}
}
cpu_kstat = 0x30001cc8570
cpu_info_kstat = 0x30001cc8370
...
cpu_type_info = {
pi_state = 0x2
pi_processor_type = [ "sparcv9" ]
pi_fputypes = [ "sparcv9" ]
pi_clock = 0x538
}
...
}
>
De todos los datos de la estructura son especialmente interesantes cpu_sysinfo que es de tipo cpu_sysinfo_t y contiene
información como el número de llamadas al sistema (syscall), el número de threads creados (nthreads), el número de crosscalls, el número
de llamadas fork, etc. El miembro cpu_syswait que es de tipo cpu_syswait_t, almacena información sobre los estados de espera
del proceso que se está ejecutando. El miembro cpu_vminfo que es de tipo cpu_vminfo_t y presenta información del uso
de la memoria por parte del procesador, páginas de entrada, páginas de salida, número de páginas escaneadas, fallos de página, fallos
de copy-on-write. La definición de estos 3 tipos de datos la podemos encontrar en el fichero de cabecera /usr/include/sys/sysinfo.h.
Buceando en el Kernel con mdb (I) << | >> Buceando en el Kernel con mdb (III)
Technorati Tag(s) : Solaris OpenSolaris MDB
Algunos derechos reservados. Licencia Creative Commons
Comentarios Recientes
Sobre
Esta plantilla a sido creada con la validacion de CSS y XHTML, por N.Design Studio.Los iconos usados son de Web 2 Mini pack.