static void print_proc_depends(struct proc *pp, const int level) { struct proc *depproc = NULL; endpoint_t dep; #define COL { int i; for(i = 0; i < level; i++) printf("> "); } if(level >= NR_PROCS) { printf("loop??\n"); return; } COL print_proc(pp); COL proc_stacktrace(pp); dep = P_BLOCKEDON(pp); if(dep != NONE && dep != ANY) { int procno; if(isokendpt(dep, &procno)) { depproc = proc_addr(procno); if(isemptyp(depproc)) depproc = NULL; } if (depproc) print_proc_depends(depproc, level+1); } }
void print_proc(struct proc *pp) { endpoint_t dep; printf("%d: %s %d prio %d time %d/%d cycles 0x%x%08x cpu %2d " "pdbr 0x%lx rts %s misc %s sched %s ", proc_nr(pp), pp->p_name, pp->p_endpoint, pp->p_priority, pp->p_user_time, pp->p_sys_time, ex64hi(pp->p_cycles), ex64lo(pp->p_cycles), pp->p_cpu, #if defined(__i386__) pp->p_seg.p_cr3, #elif defined(__arm__) pp->p_seg.p_ttbr, #endif rtsflagstr(pp->p_rts_flags), miscflagstr(pp->p_misc_flags), schedulerstr(pp->p_scheduler)); print_sigmgr(pp); dep = P_BLOCKEDON(pp); if(dep != NONE) { printf(" blocked on: "); print_endpoint(dep); } printf("\n"); }
PUBLIC void print_proc(struct proc *pp) { struct proc *depproc = NULL; endpoint_t dep; printf("%d: %s %d prio %d time %d/%d cycles 0x%x%08x cpu %2d " "cr3 0x%lx rts %s misc %s sched %s ", proc_nr(pp), pp->p_name, pp->p_endpoint, pp->p_priority, pp->p_user_time, pp->p_sys_time, ex64hi(pp->p_cycles), ex64lo(pp->p_cycles), pp->p_cpu, pp->p_seg.p_cr3, rtsflagstr(pp->p_rts_flags), miscflagstr(pp->p_misc_flags), schedulerstr(pp->p_scheduler)); print_sigmgr(pp); dep = P_BLOCKEDON(pp); if(dep != NONE) { printf(" blocked on: "); print_endpoint(dep); } printf("\n"); }
void print_procs(int maxlines, struct proc *proc1, struct proc *proc2, struct mproc *mproc) { int p, nprocs, tot=0; u64_t idleticks = cvu64(0); u64_t kernelticks = cvu64(0); u64_t systemticks = cvu64(0); u64_t userticks = cvu64(0); u64_t total_ticks = cvu64(0); unsigned long tcyc; unsigned long tmp; int blockedseen = 0; struct tp tick_procs[PROCS]; for(p = nprocs = 0; p < PROCS; p++) { if(isemptyp(&proc2[p])) continue; tick_procs[nprocs].p = proc2 + p; if(proc1[p].p_endpoint == proc2[p].p_endpoint) { tick_procs[nprocs].ticks = sub64(proc2[p].p_cycles, proc1[p].p_cycles); } else { tick_procs[nprocs].ticks = proc2[p].p_cycles; } total_ticks = add64(total_ticks, tick_procs[nprocs].ticks); if(p-NR_TASKS == IDLE) { idleticks = tick_procs[nprocs].ticks; continue; } if(p-NR_TASKS == KERNEL) { kernelticks = tick_procs[nprocs].ticks; continue; } if(mproc[proc2[p].p_nr].mp_procgrp == 0) systemticks = add64(systemticks, tick_procs[nprocs].ticks); else if (p > NR_TASKS) userticks = add64(userticks, tick_procs[nprocs].ticks); nprocs++; } if (!cmp64u(total_ticks, 0)) return; qsort(tick_procs, nprocs, sizeof(tick_procs[0]), cmp_ticks); tcyc = div64u(total_ticks, SCALE); tmp = div64u(userticks, SCALE); printf("CPU states: %6.2f%% user, ", 100.0*(tmp)/tcyc); tmp = div64u(systemticks, SCALE); printf("%6.2f%% system, ", 100.0*tmp/tcyc); tmp = div64u(kernelticks, SCALE); printf("%6.2f%% kernel, ", 100.0*tmp/tcyc); tmp = div64u(idleticks, SCALE); printf("%6.2f%% idle", 100.0*tmp/tcyc); #define NEWLINE do { printf("\n"); if(--maxlines <= 0) { return; } } while(0) NEWLINE; NEWLINE; printf(" PID USERNAME PRI NICE SIZE STATE TIME CPU COMMAND"); NEWLINE; for(p = 0; p < nprocs; p++) { struct proc *pr; int pnr; int level = 0; pnr = tick_procs[p].p->p_nr; if(pnr < 0) { /* skip old kernel tasks as they don't run anymore */ continue; } pr = tick_procs[p].p; /* If we're in blocked verbose mode, indicate start of * blocked processes. */ if(blockedverbose && pr->p_rts_flags && !blockedseen) { NEWLINE; printf("Blocked processes:"); NEWLINE; blockedseen = 1; } print_proc(&tick_procs[p], &mproc[pnr], tcyc); NEWLINE; if(!blockedverbose) continue; /* Traverse dependency chain if blocked. */ while(pr->p_rts_flags) { endpoint_t dep = NONE; struct tp *tpdep; level += 5; if((dep = P_BLOCKEDON(pr)) == NONE) { printf("not blocked on a process"); NEWLINE; break; } if(dep == ANY) break; tpdep = lookup(dep, tick_procs, nprocs); pr = tpdep->p; printf("%*s> ", level, ""); print_proc(tpdep, &mproc[pr->p_nr], tcyc); NEWLINE; } } }
/* * Return the LWP status of a process, along with additional information in * case the process is sleeping (LSSLEEP): a wchan value and text to indicate * what the process is sleeping on, and possibly a flag field modification to * indicate that the sleep is interruptible. */ static int get_lwp_stat(int mslot, uint64_t * wcptr, char * wmptr, size_t wmsz, int32_t * flag) { struct mproc *mp; struct fproc_light *fp; struct proc *kp; const char *wmesg; uint64_t wchan; endpoint_t endpt; mp = &mproc_tab[mslot]; fp = &fproc_tab[mslot]; kp = &proc_tab[NR_TASKS + mslot]; /* * First cover all the cases that the process is not sleeping. In * those cases, we need not return additional sleep information either. */ if (mp->mp_flags & (TRACE_ZOMBIE | ZOMBIE)) return LSZOMB; if (mp->mp_flags & EXITING) return LSDEAD; if ((mp->mp_flags & TRACE_STOPPED) || RTS_ISSET(kp, RTS_P_STOP)) return LSSTOP; if (proc_is_runnable(kp)) return LSRUN; /* * The process is sleeping. In that case, we must also figure out why, * and return an appropriate wchan value and human-readable wmesg text. * * The process can be blocked on either a known sleep state in PM or * VFS, or otherwise on IPC communication with another process, or * otherwise on a kernel RTS flag. In each case, decide what to use as * wchan value and wmesg text, and whether the sleep is interruptible. * * The wchan value should be unique for the sleep reason. We use its * lower eight bits to indicate a class: * 0x00 = kernel task * 0x01 = kerel RTS block * 0x02 = PM call * 0x03 = VFS call * 0x04 = MIB call * 0xff = blocked on process * The upper bits are used for class-specific information. The actual * value does not really matter, as long as it is nonzero and there is * no overlap between the different values. */ wchan = 0; wmesg = NULL; /* * First see if the process is marked as blocked in the tables of PM or * VFS. Such a block reason is always an interruptible sleep. Note * that we do not use the kernel table at all in this case: each of the * three tables is consistent within itself, but not necessarily * consistent with any of the other tables, so we avoid internal * mismatches if we can. */ if (mp->mp_flags & WAITING) { wchan = 0x102; wmesg = "wait"; } else if (mp->mp_flags & SIGSUSPENDED) { wchan = 0x202; wmesg = "pause"; } else if (fp->fpl_blocked_on != FP_BLOCKED_ON_NONE) { wchan = (fp->fpl_blocked_on << 8) | 0x03; switch (fp->fpl_blocked_on) { case FP_BLOCKED_ON_PIPE: wmesg = "pipe"; break; case FP_BLOCKED_ON_FLOCK: wmesg = "flock"; break; case FP_BLOCKED_ON_POPEN: wmesg = "popen"; break; case FP_BLOCKED_ON_SELECT: wmesg = "select"; break; case FP_BLOCKED_ON_CDEV: case FP_BLOCKED_ON_SDEV: /* * Add the task (= character or socket driver) endpoint * to the wchan value, and use the driver's process * name, without parentheses, as wmesg text. */ wchan |= (uint64_t)fp->fpl_task << 16; fill_wmesg(wmptr, wmsz, fp->fpl_task, FALSE /*ipc*/); break; default: /* A newly added flag we don't yet know about? */ wmesg = "???"; break; } } if (wchan != 0) { *wcptr = wchan; if (wmesg != NULL) /* NULL means "already set" here */ strlcpy(wmptr, wmesg, wmsz); *flag |= L_SINTR; } /* * See if the process is blocked on sending or receiving. If not, then * use one of the kernel RTS flags as reason. */ endpt = P_BLOCKEDON(kp); switch (endpt) { case MIB_PROC_NR: /* This is really just aesthetics. */ wchan = 0x04; wmesg = "sysctl"; break; case NONE: /* * The process is not running, but also not blocked on IPC with * another process. This means it must be stopped on a kernel * RTS flag. */ wchan = ((uint64_t)kp->p_rts_flags << 8) | 0x01; if (RTS_ISSET(kp, RTS_PROC_STOP)) wmesg = "kstop"; else if (RTS_ISSET(kp, RTS_SIGNALED) || RTS_ISSET(kp, RTS_SIGNALED)) wmesg = "ksignal"; else if (RTS_ISSET(kp, RTS_NO_PRIV)) wmesg = "knopriv"; else if (RTS_ISSET(kp, RTS_PAGEFAULT) || RTS_ISSET(kp, RTS_VMREQTARGET)) wmesg = "fault"; else if (RTS_ISSET(kp, RTS_NO_QUANTUM)) wmesg = "sched"; else wmesg = "kflag"; break; case ANY: /* * If the process is blocked receiving from ANY, mark it as * being in an interruptible sleep. This looks nicer, even * though "interruptible" is not applicable to services at all. */ *flag |= L_SINTR; break; } /* * If at this point wchan is still zero, the process is blocked sending * or receiving. Use a wchan value based on the target endpoint, and * use "(procname)" as wmesg text. */ if (wchan == 0) { *wcptr = ((uint64_t)endpt << 8) | 0xff; fill_wmesg(wmptr, wmsz, endpt, TRUE /*ipc*/); } else { *wcptr = wchan; if (wmesg != NULL) /* NULL means "already set" here */ strlcpy(wmptr, wmesg, wmsz); } return LSSLEEP; }