1 /* This file implements kernel debugging functionality that is not included
2 * in the standard kernel. Available functionality includes timing of lock
3 * functions and sanity checking of the scheduling queues.
6 #include "kernel/kernel.h"
8 #include <minix/callnr.h>
14 #define MAX_LOOP (NR_PROCS + NR_TASKS)
16 int runqueues_ok_cpu(unsigned cpu
)
19 register struct proc
*xp
;
20 struct proc
**rdy_head
, **rdy_tail
;
22 rdy_head
= get_cpu_var(cpu
, run_q_head
);
23 rdy_tail
= get_cpu_var(cpu
, run_q_tail
);
25 for (xp
= BEG_PROC_ADDR
; xp
< END_PROC_ADDR
; ++xp
) {
27 if (l
++ > MAX_LOOP
) panic("check error");
30 for (q
=l
=0; q
< NR_SCHED_QUEUES
; q
++) {
31 if (rdy_head
[q
] && !rdy_tail
[q
]) {
32 printf("head but no tail in %d\n", q
);
35 if (!rdy_head
[q
] && rdy_tail
[q
]) {
36 printf("tail but no head in %d\n", q
);
39 if (rdy_tail
[q
] && rdy_tail
[q
]->p_nextready
) {
40 printf("tail and tail->next not null in %d\n", q
);
43 for(xp
= rdy_head
[q
]; xp
; xp
= xp
->p_nextready
) {
44 const vir_bytes vxp
= (vir_bytes
) xp
;
46 if(vxp
< (vir_bytes
) BEG_PROC_ADDR
|| vxp
>= (vir_bytes
) END_PROC_ADDR
) {
47 printf("xp out of range\n");
50 dxp
= vxp
- (vir_bytes
) BEG_PROC_ADDR
;
51 if(dxp
% sizeof(struct proc
)) {
52 printf("xp not a real pointer");
55 if(!proc_ptr_ok(xp
)) {
56 printf("xp bogus pointer");
59 if (RTS_ISSET(xp
, RTS_SLOT_FREE
)) {
60 printf("scheduling error: dead proc q %d %d\n",
64 if (!proc_is_runnable(xp
)) {
65 printf("scheduling error: unready on runq %d proc %d\n",
69 if (xp
->p_priority
!= q
) {
70 printf("scheduling error: wrong priority q %d proc %d ep %d name %s\n",
71 q
, xp
->p_nr
, xp
->p_endpoint
, xp
->p_name
);
75 printf("scheduling error: double sched q %d proc %d\n",
80 if (!xp
->p_nextready
&& rdy_tail
[q
] != xp
) {
81 printf("sched err: last element not tail q %d proc %d\n",
86 printf("loop in schedule queue?");
92 for (xp
= BEG_PROC_ADDR
; xp
< END_PROC_ADDR
; ++xp
) {
93 if(!proc_ptr_ok(xp
)) {
94 printf("xp bogus pointer in proc table\n");
99 if(proc_is_runnable(xp
) && !xp
->p_found
) {
100 printf("sched error: ready proc %d not on queue\n", xp
->p_nr
);
110 static int runqueues_ok_all(void)
114 for (c
= 0 ; c
< ncpus
; c
++) {
115 if (!runqueues_ok_cpu(c
))
121 int runqueues_ok(void)
123 return runqueues_ok_all();
128 int runqueues_ok(void)
130 return runqueues_ok_cpu(0);
137 rtsflagstr(const u32_t flags
)
139 static char str
[100];
142 #define FLAG(n) if(flags & n) { strlcat(str, #n " ", sizeof(str)); }
149 FLAG(RTS_SIG_PENDING
);
152 FLAG(RTS_NO_ENDPOINT
);
156 FLAG(RTS_VMREQTARGET
);
158 FLAG(RTS_NO_QUANTUM
);
164 miscflagstr(const u32_t flags
)
166 static char str
[100];
171 FLAG(MF_KCALL_RESUME
);
177 schedulerstr(struct proc
*scheduler
)
179 if (scheduler
!= NULL
)
181 return scheduler
->p_name
;
188 print_proc_name(struct proc
*pp
)
190 char *name
= pp
->p_name
;
191 endpoint_t ep
= pp
->p_endpoint
;
194 printf("%s(%d)", name
, ep
);
202 print_endpoint(endpoint_t ep
)
205 struct proc
*pp
= NULL
;
218 if(!isokendpt(ep
, &proc_nr
)) {
219 printf("??? %d\n", ep
);
222 pp
= proc_addr(proc_nr
);
224 printf("??? empty slot %d\n", proc_nr
);
235 print_sigmgr(struct proc
*pp
)
237 endpoint_t sig_mgr
, bak_sig_mgr
;
238 sig_mgr
= priv(pp
) ? priv(pp
)->s_sig_mgr
: NONE
;
239 bak_sig_mgr
= priv(pp
) ? priv(pp
)->s_bak_sig_mgr
: NONE
;
240 if(sig_mgr
== NONE
) { printf("no sigmgr"); return; }
242 print_endpoint(sig_mgr
);
243 if(bak_sig_mgr
!= NONE
) {
245 print_endpoint(bak_sig_mgr
);
249 void print_proc(struct proc
*pp
)
253 printf("%d: %s %d prio %d time %d/%d cycles 0x%x%08x cpu %2d "
254 "pdbr 0x%lx rts %s misc %s sched %s ",
255 proc_nr(pp
), pp
->p_name
, pp
->p_endpoint
,
256 pp
->p_priority
, pp
->p_user_time
,
257 pp
->p_sys_time
, ex64hi(pp
->p_cycles
),
258 ex64lo(pp
->p_cycles
), pp
->p_cpu
,
259 #if defined(__i386__)
261 #elif defined(__arm__)
264 rtsflagstr(pp
->p_rts_flags
), miscflagstr(pp
->p_misc_flags
),
265 schedulerstr(pp
->p_scheduler
));
269 dep
= P_BLOCKEDON(pp
);
271 printf(" blocked on: ");
277 static void print_proc_depends(struct proc
*pp
, const int level
)
279 struct proc
*depproc
= NULL
;
281 #define COL { int i; for(i = 0; i < level; i++) printf("> "); }
283 if(level
>= NR_PROCS
) {
296 dep
= P_BLOCKEDON(pp
);
297 if(dep
!= NONE
&& dep
!= ANY
) {
299 if(isokendpt(dep
, &procno
)) {
300 depproc
= proc_addr(procno
);
301 if(isemptyp(depproc
))
305 print_proc_depends(depproc
, level
+1);
309 void print_proc_recursive(struct proc
*pp
)
311 print_proc_depends(pp
, 0);
314 #if DEBUG_DUMPIPC || DEBUG_DUMPIPCF
315 static const char *mtypename(int mtype
, int *possible_callname
)
317 char *callname
= NULL
, *errname
= NULL
;
318 /* use generated file to recognize message types
320 * we try to match both error numbers and call numbers, as the
321 * reader can probably decide from context what's going on.
323 * whenever it might be a call number we tell the caller so the
324 * call message fields can be decoded if known.
327 #define IDENT(x) case x: callname = #x; *possible_callname = 1; break;
328 #include "kernel/extracted-mtype.h"
332 #define IDENT(x) case x: errname = #x; break;
333 #include "kernel/extracted-errno.h"
338 if(!errname
&& !callname
)
342 if(errname
&& callname
) {
343 static char typename
[100];
344 strcpy(typename
, errname
);
345 strcat(typename
, " / ");
346 strcat(typename
, callname
);
350 if(errname
) return errname
;
356 static void printproc(struct proc
*rp
)
359 printf(" %s(%d)", rp
->p_name
, rp
- proc
);
364 static void printparam(const char *name
, const void *data
, size_t size
)
366 printf(" %s=", name
);
368 case sizeof(char): printf("%d", *(char *) data
); break;
369 case sizeof(short): printf("%d", *(short *) data
); break;
370 case sizeof(int): printf("%d", *(int *) data
); break;
371 default: printf("(%u bytes)", size
); break;
375 #ifdef DEBUG_DUMPIPC_NAMES
376 static int namematch(char **names
, int nnames
, char *name
)
379 for(i
= 0; i
< nnames
; i
++)
380 if(!strcmp(names
[i
], name
))
386 void printmsg(message
*msg
, struct proc
*src
, struct proc
*dst
,
387 char operation
, int printparams
)
390 int mtype
= msg
->m_type
, mightbecall
= 0;
392 #ifdef DEBUG_DUMPIPC_NAMES
394 char *names
[] = DEBUG_DUMPIPC_NAMES
;
395 int nnames
= sizeof(names
)/sizeof(names
[0]);
397 /* skip printing messages for messages neither to
398 * or from DEBUG_DUMPIPC_EP if it is defined; either
399 * can be NULL to indicate kernel
401 if(!(src
&& namematch(names
, nnames
, src
->p_name
)) &&
402 !(dst
&& namematch(names
, nnames
, dst
->p_name
))) {
408 /* source, destination and message type */
409 printf("%c", operation
);
412 name
= mtypename(mtype
, &mightbecall
);
414 printf(" %s(%d/0x%x)", name
, mtype
, mtype
);
416 printf(" %d/0x%x", mtype
, mtype
);
419 if (mightbecall
&& printparams
) {
420 #define IDENT(x, y) if (mtype == x) printparam(#y, &msg->y, sizeof(msg->y));
421 #include "kernel/extracted-mfield.h"
429 #define IPCPROCS (NR_PROCS+1) /* number of slots we need */
430 #define KERNELIPC NR_PROCS /* slot number to use for kernel calls */
431 static int messages
[IPCPROCS
][IPCPROCS
];
433 #define PRINTSLOTS 20
435 int src
, dst
, messages
;
436 } winners
[PRINTSLOTS
];
437 static int total
, goodslots
;
439 static void printstats(int ticks
)
442 for(i
= 0; i
< goodslots
; i
++) {
443 #define name(s) (s == KERNELIPC ? "kernel" : proc_addr(s)->p_name)
444 #define persec(n) (system_hz*(n)/ticks)
445 char *n1
= name(winners
[i
].src
),
446 *n2
= name(winners
[i
].dst
);
447 printf("%2d. %8s -> %8s %9d/s\n",
448 i
, n1
, n2
, persec(winners
[i
].messages
));
450 printf("total %d/s\n", persec(total
));
453 static void sortstats(void)
455 /* Print top message senders/receivers. */
456 int src_slot
, dst_slot
;
457 total
= goodslots
= 0;
458 for(src_slot
= 0; src_slot
< IPCPROCS
; src_slot
++) {
459 for(dst_slot
= 0; dst_slot
< IPCPROCS
; dst_slot
++) {
460 int w
= PRINTSLOTS
, rem
,
461 n
= messages
[src_slot
][dst_slot
];
463 while(w
> 0 && n
> winners
[w
-1].messages
)
465 if(w
>= PRINTSLOTS
) continue;
467 /* This combination has beaten the current winners
468 * and should be inserted at position 'w.'
470 rem
= PRINTSLOTS
-w
-1;
472 assert(rem
< PRINTSLOTS
);
474 assert(w
+1 <= PRINTSLOTS
-1);
476 memmove(&winners
[w
+1], &winners
[w
],
477 rem
*sizeof(winners
[0]));
479 winners
[w
].src
= src_slot
;
480 winners
[w
].dst
= dst_slot
;
481 winners
[w
].messages
= n
;
482 if(goodslots
< PRINTSLOTS
) goodslots
++;
487 #define proc2slot(p, s) { \
488 if(p) { s = p->p_nr; } \
489 else { s = KERNELIPC; } \
490 assert(s >= 0 && s < IPCPROCS); \
493 static void statmsg(message
*msg
, struct proc
*srcp
, struct proc
*dstp
)
495 int src
, dst
, now
, secs
, dt
;
496 static int lastprint
;
500 proc2slot(srcp
, src
);
501 proc2slot(dstp
, dst
);
502 messages
[src
][dst
]++;
504 /* Print something? */
505 now
= get_monotonic();
506 dt
= now
- lastprint
;
509 memset(winners
, 0, sizeof(winners
));
512 memset(messages
, 0, sizeof(messages
));
519 void hook_ipc_msgkcall(message
*msg
, struct proc
*proc
)
522 printmsg(msg
, proc
, NULL
, 'k', 1);
526 void hook_ipc_msgkresult(message
*msg
, struct proc
*proc
)
529 printmsg(msg
, NULL
, proc
, 'k', 0);
532 statmsg(msg
, proc
, NULL
);
536 void hook_ipc_msgrecv(message
*msg
, struct proc
*src
, struct proc
*dst
)
539 printmsg(msg
, src
, dst
, 'r', 0);
542 statmsg(msg
, src
, dst
);
546 void hook_ipc_msgsend(message
*msg
, struct proc
*src
, struct proc
*dst
)
549 printmsg(msg
, src
, dst
, 's', 1);
553 void hook_ipc_clear(struct proc
*p
)
559 for(i
= 0; i
< IPCPROCS
; i
++)
560 messages
[slot
][i
] = messages
[i
][slot
] = 0;