Uso de los threads de NFS
En un servidor NFS, mediante el fichero /proc/net/rpc/nfsd podemos hacernos una idea del estado del servicio. Hoy vamos a ver el significado de la linea th.
Un ejemplo del fichero sería:
$ cat /proc/net/rpc/nfsd rc 0 6671596 875517006 fh 351 0 0 0 0 io 738666746 3982364348 th 32 6006 36721.284 7532.056 2336.704 2441.997 1132.242 114.302 52.948 34.700 18.690 10.416 ra 64 46200169 49090 30766 16462 11972 10878 7780 7874 6044 5386 41789739 net 882193724 0 882189762 9448 rpc 882190850 0 0 0 0 proc2 18 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 proc3 22 3 347659355 691506 121853078 315329478 0 88134489 5082870 751855 43470 0 0 101862 0 28 3 80 1482946 1041 5 0 761589 proc4 2 0 0
En este caso la linea th (threads) es esta:
th 32 6006 36721.284 7532.056 2336.704 2441.997 1132.242 114.302 52.948 34.700 18.690 10.416
Los valores son:
- Total de threads definidos
- Veces que han estado todos los threads en uso
- 10 valores representando el tiempo en que cierto porcentaje de threads han estado en uso.
En el caso del ejemplo, podemos ver:
- Esta configurado para usar 32 threads
- En el tiempo que lleva levantado el servicio ha estado 6006 veces usando todos los threads
- El primer 10% de los threads estaban en uso 36721.284 segundos, el el segundo 10% (entre el 10 y el 20% de los threads) 7532.056 segundos… y así el resto.
Por lo tanto, mediante estas estadísticas podemos valorar si hace falta reducir o ampliar el número de threads (procesos) dedicados al NFS.
Si deseamos profundizar en como se calculan estos valores, podemos mirar el fichero fs/nfsd/stats.c la función static int nfsd_proc_show(struct seq_file *seq, void *v). En ella podemos encontrar el siguiente código:
/* thread usage: */
seq_printf(seq, "th %u %u", nfsdstats.th_cnt, nfsdstats.th_fullcnt);
for (i=0; i<10; i++) {
unsigned int jifs = nfsdstats.th_usage[i];
unsigned int sec = jifs / HZ, msec = (jifs % HZ)*1000/HZ;
seq_printf(seq, " %u.%03u", sec, msec);
}
Como vemos, se basa en nfsdstats.th_usage, el cual se actualiza en el loop principal de NFS (fs/nfsd/nfssvc.c):
for (;;) {
/*
* Find a socket with data available and call its
* recvfrom routine.
*/
while ((err = svc_recv(rqstp, 60*60*HZ)) == -EAGAIN)
;
if (err == -EINTR)
break;
else if (err < 0) {
if (err != preverr) {
printk(KERN_WARNING "%s: unexpected error "
"from svc_recv (%d)\n", __func__, -err);
preverr = err;
}
schedule_timeout_uninterruptible(HZ);
continue;
}
update_thread_usage(atomic_read(&nfsd_busy));
atomic_inc(&nfsd_busy);
/* Lock the export hash tables for reading. */
exp_readlock();
svc_process(rqstp);
/* Unlock export hash tables */
exp_readunlock();
update_thread_usage(atomic_read(&nfsd_busy));
atomic_dec(&nfsd_busy);
}
El código de la función es el siguiente:
static inline void
update_thread_usage(int busy_threads)
{
unsigned long prev_call;
unsigned long diff;
int decile;
spin_lock(&nfsd_call_lock);
prev_call = nfsd_last_call;
nfsd_last_call = jiffies;
decile = busy_threads*10/nfsdstats.th_cnt;
if (decile>0 && decile <= 10) {
diff = nfsd_last_call - prev_call;
if ( (nfsdstats.th_usage[decile-1] += diff) >= NFSD_USAGE_WRAP)
nfsdstats.th_usage[decile-1] -= NFSD_USAGE_WRAP;
if (decile == 10)
nfsdstats.th_fullcnt++;
}
spin_unlock(&nfsd_call_lock);
}
Como vemos siguiendo el código, se basa en un simple contador que según el porcentaje de threads en uso incrementa una o otra variable del array nfsdstats.th_usage.
Relacionados
Imprimir
Deja un comentario: