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.
8 #include <minix/callnr.h>
9 #include <minix/sysutil.h>
10 #include <minix/u64.h>
15 #define MAX_LOOP (NR_PROCS + NR_TASKS)
17 int runqueues_ok_cpu(unsigned cpu
)
20 register struct proc
*xp
;
21 struct proc
**rdy_head
, **rdy_tail
;
23 rdy_head
= get_cpu_var(cpu
, run_q_head
);
24 rdy_tail
= get_cpu_var(cpu
, run_q_tail
);
26 for (xp
= BEG_PROC_ADDR
; xp
< END_PROC_ADDR
; ++xp
) {
28 if (l
++ > MAX_LOOP
) panic("check error");
31 for (q
=l
=0; q
< NR_SCHED_QUEUES
; q
++) {
32 if (rdy_head
[q
] && !rdy_tail
[q
]) {
33 printf("head but no tail in %d\n", q
);
36 if (!rdy_head
[q
] && rdy_tail
[q
]) {
37 printf("tail but no head in %d\n", q
);
40 if (rdy_tail
[q
] && rdy_tail
[q
]->p_nextready
) {
41 printf("tail and tail->next not null in %d\n", q
);
44 for(xp
= rdy_head
[q
]; xp
; xp
= xp
->p_nextready
) {
45 const vir_bytes vxp
= (vir_bytes
) xp
;
47 if(vxp
< (vir_bytes
) BEG_PROC_ADDR
|| vxp
>= (vir_bytes
) END_PROC_ADDR
) {
48 printf("xp out of range\n");
51 dxp
= vxp
- (vir_bytes
) BEG_PROC_ADDR
;
52 if(dxp
% sizeof(struct proc
)) {
53 printf("xp not a real pointer");
56 if(!proc_ptr_ok(xp
)) {
57 printf("xp bogus pointer");
60 if (RTS_ISSET(xp
, RTS_SLOT_FREE
)) {
61 printf("scheduling error: dead proc q %d %d\n",
65 if (!proc_is_runnable(xp
)) {
66 printf("scheduling error: unready on runq %d proc %d\n",
70 if (xp
->p_priority
!= q
) {
71 printf("scheduling error: wrong priority q %d proc %d ep %d name %s\n",
72 q
, xp
->p_nr
, xp
->p_endpoint
, xp
->p_name
);
76 printf("scheduling error: double sched q %d proc %d\n",
81 if (!xp
->p_nextready
&& rdy_tail
[q
] != xp
) {
82 printf("sched err: last element not tail q %d proc %d\n",
87 printf("loop in schedule queue?");
93 for (xp
= BEG_PROC_ADDR
; xp
< END_PROC_ADDR
; ++xp
) {
94 if(!proc_ptr_ok(xp
)) {
95 printf("xp bogus pointer in proc table\n");
100 if(proc_is_runnable(xp
) && !xp
->p_found
) {
101 printf("sched error: ready proc %d not on queue\n", xp
->p_nr
);
111 static int runqueues_ok_all(void)
115 for (c
= 0 ; c
< ncpus
; c
++) {
116 if (!runqueues_ok_cpu(c
))
122 int runqueues_ok(void)
124 return runqueues_ok_all();
129 int runqueues_ok(void)
131 return runqueues_ok_cpu(0);
138 rtsflagstr(const u32_t flags
)
140 static char str
[100];
143 #define FLAG(n) if(flags & n) { strlcat(str, #n " ", sizeof(str)); }
150 FLAG(RTS_SIG_PENDING
);
153 FLAG(RTS_NO_ENDPOINT
);
157 FLAG(RTS_VMREQTARGET
);
159 FLAG(RTS_NO_QUANTUM
);
165 miscflagstr(const u32_t flags
)
167 static char str
[100];
172 FLAG(MF_KCALL_RESUME
);
178 schedulerstr(struct proc
*scheduler
)
180 if (scheduler
!= NULL
)
182 return scheduler
->p_name
;
189 print_proc_name(struct proc
*pp
)
191 char *name
= pp
->p_name
;
192 endpoint_t ep
= pp
->p_endpoint
;
195 printf("%s(%d)", name
, ep
);
203 print_endpoint(endpoint_t ep
)
206 struct proc
*pp
= NULL
;
219 if(!isokendpt(ep
, &proc_nr
)) {
220 printf("??? %d\n", ep
);
223 pp
= proc_addr(proc_nr
);
225 printf("??? empty slot %d\n", proc_nr
);
236 print_sigmgr(struct proc
*pp
)
238 endpoint_t sig_mgr
, bak_sig_mgr
;
239 sig_mgr
= priv(pp
)->s_sig_mgr
;
240 bak_sig_mgr
= priv(pp
)->s_bak_sig_mgr
;
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 "cr3 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
,
260 rtsflagstr(pp
->p_rts_flags
), miscflagstr(pp
->p_misc_flags
),
261 schedulerstr(pp
->p_scheduler
));
265 dep
= P_BLOCKEDON(pp
);
267 printf(" blocked on: ");
273 static void print_proc_depends(struct proc
*pp
, const int level
)
275 struct proc
*depproc
= NULL
;
277 #define COL { int i; for(i = 0; i < level; i++) printf("> "); }
279 if(level
>= NR_PROCS
) {
292 dep
= P_BLOCKEDON(pp
);
293 if(dep
!= NONE
&& dep
!= ANY
) {
295 if(isokendpt(dep
, &procno
)) {
296 depproc
= proc_addr(procno
);
297 if(isemptyp(depproc
))
301 print_proc_depends(depproc
, level
+1);
305 void print_proc_recursive(struct proc
*pp
)
307 print_proc_depends(pp
, 0);
311 static const char *mtypename(int mtype
, int iscall
)
313 /* use generated file to recognize message types */
316 #define IDENT(x) case x: return #x;
317 #include "extracted-mtype.h"
322 #define IDENT(x) case x: return #x;
323 #include "extracted-errno.h"
332 static void printproc(struct proc
*rp
)
335 printf(" %s(%d)", rp
->p_name
, rp
- proc
);
340 static void printparam(const char *name
, const void *data
, size_t size
)
342 printf(" %s=", name
);
344 case sizeof(char): printf("%d", *(char *) data
); break;
345 case sizeof(short): printf("%d", *(short *) data
); break;
346 case sizeof(int): printf("%d", *(int *) data
); break;
347 default: printf("(%u bytes)", size
); break;
351 static void printmsg(message
*msg
, struct proc
*src
, struct proc
*dst
,
352 char operation
, int iscall
, int printparams
)
355 int mtype
= msg
->m_type
;
357 /* source, destination and message type */
358 printf("%c", operation
);
361 name
= mtypename(mtype
, iscall
);
363 printf(" %s(%d)", name
, mtype
);
365 printf(" %d", mtype
);
368 if (iscall
&& printparams
) {
369 #define IDENT(x, y) if (mtype == x) printparam(#y, &msg->y, sizeof(msg->y));
370 #include "extracted-mfield.h"
378 #define IPCPROCS (NR_PROCS+1) /* number of slots we need */
379 #define KERNELIPC NR_PROCS /* slot number to use for kernel calls */
380 static int messages
[IPCPROCS
][IPCPROCS
];
382 #define PRINTSLOTS 20
384 int src
, dst
, messages
;
385 } winners
[PRINTSLOTS
];
386 static int total
, goodslots
;
388 static void printstats(int ticks
)
391 for(i
= 0; i
< goodslots
; i
++) {
392 #define name(s) (s == KERNELIPC ? "kernel" : proc_addr(s)->p_name)
393 #define persec(n) (system_hz*(n)/ticks)
394 char *n1
= name(winners
[i
].src
),
395 *n2
= name(winners
[i
].dst
);
396 printf("%2d. %8s -> %8s %9d/s\n",
397 i
, n1
, n2
, persec(winners
[i
].messages
));
399 printf("total %d/s\n", persec(total
));
402 static void sortstats(void)
404 /* Print top message senders/receivers. */
405 int src_slot
, dst_slot
;
406 total
= goodslots
= 0;
407 for(src_slot
= 0; src_slot
< IPCPROCS
; src_slot
++) {
408 for(dst_slot
= 0; dst_slot
< IPCPROCS
; dst_slot
++) {
409 int w
= PRINTSLOTS
, rem
,
410 n
= messages
[src_slot
][dst_slot
];
412 while(w
> 0 && n
> winners
[w
-1].messages
)
414 if(w
>= PRINTSLOTS
) continue;
416 /* This combination has beaten the current winners
417 * and should be inserted at position 'w.'
419 rem
= PRINTSLOTS
-w
-1;
421 assert(rem
< PRINTSLOTS
);
423 assert(w
+1 <= PRINTSLOTS
-1);
425 memmove(&winners
[w
+1], &winners
[w
],
426 rem
*sizeof(winners
[0]));
428 winners
[w
].src
= src_slot
;
429 winners
[w
].dst
= dst_slot
;
430 winners
[w
].messages
= n
;
431 if(goodslots
< PRINTSLOTS
) goodslots
++;
436 #define proc2slot(p, s) { \
437 if(p) { s = p->p_nr; } \
438 else { s = KERNELIPC; } \
439 assert(s >= 0 && s < IPCPROCS); \
442 static void statmsg(message
*msg
, struct proc
*srcp
, struct proc
*dstp
)
444 int src
, dst
, now
, secs
, dt
;
445 static int lastprint
;
449 proc2slot(srcp
, src
);
450 proc2slot(dstp
, dst
);
451 messages
[src
][dst
]++;
453 /* Print something? */
455 dt
= now
- lastprint
;
458 memset(winners
, 0, sizeof(winners
));
461 memset(messages
, 0, sizeof(messages
));
468 void hook_ipc_msgkcall(message
*msg
, struct proc
*proc
)
471 printmsg(msg
, proc
, NULL
, 'k', 1, 1);
475 void hook_ipc_msgkresult(message
*msg
, struct proc
*proc
)
478 printmsg(msg
, NULL
, proc
, 'k', 0, 0);
481 statmsg(msg
, proc
, NULL
);
485 void hook_ipc_msgrecv(message
*msg
, struct proc
*src
, struct proc
*dst
)
488 printmsg(msg
, src
, dst
, 'r', src
->p_misc_flags
& MF_REPLY_PEND
, 0);
491 statmsg(msg
, src
, dst
);
495 void hook_ipc_msgsend(message
*msg
, struct proc
*src
, struct proc
*dst
)
498 printmsg(msg
, src
, dst
, 's', src
->p_misc_flags
& MF_REPLY_PEND
, 1);
502 void hook_ipc_clear(struct proc
*p
)
508 for(i
= 0; i
< IPCPROCS
; i
++)
509 messages
[slot
][i
] = messages
[i
][slot
] = 0;