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
) ? priv(pp
)->s_sig_mgr
: NONE
;
240 bak_sig_mgr
= priv(pp
) ? priv(pp
)->s_bak_sig_mgr
: NONE
;
241 if(sig_mgr
== NONE
) { printf("no sigmgr"); return; }
243 print_endpoint(sig_mgr
);
244 if(bak_sig_mgr
!= NONE
) {
246 print_endpoint(bak_sig_mgr
);
250 void print_proc(struct proc
*pp
)
254 printf("%d: %s %d prio %d time %d/%d cycles 0x%x%08x cpu %2d "
255 "pdbr 0x%lx rts %s misc %s sched %s ",
256 proc_nr(pp
), pp
->p_name
, pp
->p_endpoint
,
257 pp
->p_priority
, pp
->p_user_time
,
258 pp
->p_sys_time
, ex64hi(pp
->p_cycles
),
259 ex64lo(pp
->p_cycles
), pp
->p_cpu
,
260 #if defined(__i386__)
262 #elif defined(__arm__)
265 rtsflagstr(pp
->p_rts_flags
), miscflagstr(pp
->p_misc_flags
),
266 schedulerstr(pp
->p_scheduler
));
270 dep
= P_BLOCKEDON(pp
);
272 printf(" blocked on: ");
278 static void print_proc_depends(struct proc
*pp
, const int level
)
280 struct proc
*depproc
= NULL
;
282 #define COL { int i; for(i = 0; i < level; i++) printf("> "); }
284 if(level
>= NR_PROCS
) {
297 dep
= P_BLOCKEDON(pp
);
298 if(dep
!= NONE
&& dep
!= ANY
) {
300 if(isokendpt(dep
, &procno
)) {
301 depproc
= proc_addr(procno
);
302 if(isemptyp(depproc
))
306 print_proc_depends(depproc
, level
+1);
310 void print_proc_recursive(struct proc
*pp
)
312 print_proc_depends(pp
, 0);
316 static const char *mtypename(int mtype
, int iscall
)
318 /* use generated file to recognize message types */
321 #define IDENT(x) case x: return #x;
322 #include "extracted-mtype.h"
327 #define IDENT(x) case x: return #x;
328 #include "extracted-errno.h"
337 static void printproc(struct proc
*rp
)
340 printf(" %s(%d)", rp
->p_name
, rp
- proc
);
345 static void printparam(const char *name
, const void *data
, size_t size
)
347 printf(" %s=", name
);
349 case sizeof(char): printf("%d", *(char *) data
); break;
350 case sizeof(short): printf("%d", *(short *) data
); break;
351 case sizeof(int): printf("%d", *(int *) data
); break;
352 default: printf("(%u bytes)", size
); break;
356 static void printmsg(message
*msg
, struct proc
*src
, struct proc
*dst
,
357 char operation
, int iscall
, int printparams
)
360 int mtype
= msg
->m_type
;
362 /* source, destination and message type */
363 printf("%c", operation
);
366 name
= mtypename(mtype
, iscall
);
368 printf(" %s(%d)", name
, mtype
);
370 printf(" %d", mtype
);
373 if (iscall
&& printparams
) {
374 #define IDENT(x, y) if (mtype == x) printparam(#y, &msg->y, sizeof(msg->y));
375 #include "extracted-mfield.h"
383 #define IPCPROCS (NR_PROCS+1) /* number of slots we need */
384 #define KERNELIPC NR_PROCS /* slot number to use for kernel calls */
385 static int messages
[IPCPROCS
][IPCPROCS
];
387 #define PRINTSLOTS 20
389 int src
, dst
, messages
;
390 } winners
[PRINTSLOTS
];
391 static int total
, goodslots
;
393 static void printstats(int ticks
)
396 for(i
= 0; i
< goodslots
; i
++) {
397 #define name(s) (s == KERNELIPC ? "kernel" : proc_addr(s)->p_name)
398 #define persec(n) (system_hz*(n)/ticks)
399 char *n1
= name(winners
[i
].src
),
400 *n2
= name(winners
[i
].dst
);
401 printf("%2d. %8s -> %8s %9d/s\n",
402 i
, n1
, n2
, persec(winners
[i
].messages
));
404 printf("total %d/s\n", persec(total
));
407 static void sortstats(void)
409 /* Print top message senders/receivers. */
410 int src_slot
, dst_slot
;
411 total
= goodslots
= 0;
412 for(src_slot
= 0; src_slot
< IPCPROCS
; src_slot
++) {
413 for(dst_slot
= 0; dst_slot
< IPCPROCS
; dst_slot
++) {
414 int w
= PRINTSLOTS
, rem
,
415 n
= messages
[src_slot
][dst_slot
];
417 while(w
> 0 && n
> winners
[w
-1].messages
)
419 if(w
>= PRINTSLOTS
) continue;
421 /* This combination has beaten the current winners
422 * and should be inserted at position 'w.'
424 rem
= PRINTSLOTS
-w
-1;
426 assert(rem
< PRINTSLOTS
);
428 assert(w
+1 <= PRINTSLOTS
-1);
430 memmove(&winners
[w
+1], &winners
[w
],
431 rem
*sizeof(winners
[0]));
433 winners
[w
].src
= src_slot
;
434 winners
[w
].dst
= dst_slot
;
435 winners
[w
].messages
= n
;
436 if(goodslots
< PRINTSLOTS
) goodslots
++;
441 #define proc2slot(p, s) { \
442 if(p) { s = p->p_nr; } \
443 else { s = KERNELIPC; } \
444 assert(s >= 0 && s < IPCPROCS); \
447 static void statmsg(message
*msg
, struct proc
*srcp
, struct proc
*dstp
)
449 int src
, dst
, now
, secs
, dt
;
450 static int lastprint
;
454 proc2slot(srcp
, src
);
455 proc2slot(dstp
, dst
);
456 messages
[src
][dst
]++;
458 /* Print something? */
460 dt
= now
- lastprint
;
463 memset(winners
, 0, sizeof(winners
));
466 memset(messages
, 0, sizeof(messages
));
473 void hook_ipc_msgkcall(message
*msg
, struct proc
*proc
)
476 printmsg(msg
, proc
, NULL
, 'k', 1, 1);
480 void hook_ipc_msgkresult(message
*msg
, struct proc
*proc
)
483 printmsg(msg
, NULL
, proc
, 'k', 0, 0);
486 statmsg(msg
, proc
, NULL
);
490 void hook_ipc_msgrecv(message
*msg
, struct proc
*src
, struct proc
*dst
)
493 printmsg(msg
, src
, dst
, 'r', src
->p_misc_flags
& MF_REPLY_PEND
, 0);
496 statmsg(msg
, src
, dst
);
500 void hook_ipc_msgsend(message
*msg
, struct proc
*src
, struct proc
*dst
)
503 printmsg(msg
, src
, dst
, 's', src
->p_misc_flags
& MF_REPLY_PEND
, 1);
507 void hook_ipc_clear(struct proc
*p
)
513 for(i
= 0; i
< IPCPROCS
; i
++)
514 messages
[slot
][i
] = messages
[i
][slot
] = 0;