a script to decode stack traces.
[minix3.git] / kernel / debug.c
blobeeb3b775e07578fdfb66ea1948280dd71c4bef82
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.
4 */
6 #include "kernel.h"
7 #include "proc.h"
8 #include "debug.h"
9 #include <limits.h>
11 #if DEBUG_TIME_LOCKS /* only include code if enabled */
13 /* Data structures to store lock() timing data. */
14 struct lock_timingdata timingdata[TIMING_CATEGORIES];
15 static unsigned long starttimes[TIMING_CATEGORIES][2];
17 #define HIGHCOUNT 0
18 #define LOWCOUNT 1
20 void timer_start(int cat, char *name)
22 static int init = 0;
23 unsigned long h, l;
24 int i;
26 if (cat < 0 || cat >= TIMING_CATEGORIES) return;
28 for(i = 0; i < sizeof(timingdata[0].names) && *name; i++)
29 timingdata[cat].names[i] = *name++;
30 timingdata[cat].names[sizeof(timingdata[0].names)-1] = '\0';
32 if (starttimes[cat][HIGHCOUNT]) { return; }
34 if (!init) {
35 int t, f;
36 init = 1;
37 for(t = 0; t < TIMING_CATEGORIES; t++) {
38 timingdata[t].lock_timings_range[0] = 0;
39 timingdata[t].resets = timingdata[t].misses =
40 timingdata[t].measurements = 0;
44 read_tsc(&starttimes[cat][HIGHCOUNT], &starttimes[cat][LOWCOUNT]);
47 void timer_end(int cat)
49 unsigned long h, l, d = 0, binsize;
50 int bin;
52 read_tsc(&h, &l);
53 if (cat < 0 || cat >= TIMING_CATEGORIES) return;
54 if (!starttimes[cat][HIGHCOUNT]) {
55 timingdata[cat].misses++;
56 return;
58 if (starttimes[cat][HIGHCOUNT] == h) {
59 d = (l - starttimes[cat][1]);
60 } else if (starttimes[cat][HIGHCOUNT] == h-1 &&
61 starttimes[cat][LOWCOUNT] > l) {
62 d = ((ULONG_MAX - starttimes[cat][LOWCOUNT]) + l);
63 } else {
64 timingdata[cat].misses++;
65 return;
67 starttimes[cat][HIGHCOUNT] = 0;
68 if (!timingdata[cat].lock_timings_range[0] ||
69 d < timingdata[cat].lock_timings_range[0] ||
70 d > timingdata[cat].lock_timings_range[1]) {
71 int t;
72 if (!timingdata[cat].lock_timings_range[0] ||
73 d < timingdata[cat].lock_timings_range[0])
74 timingdata[cat].lock_timings_range[0] = d;
75 if (!timingdata[cat].lock_timings_range[1] ||
76 d > timingdata[cat].lock_timings_range[1])
77 timingdata[cat].lock_timings_range[1] = d;
78 for(t = 0; t < TIMING_POINTS; t++)
79 timingdata[cat].lock_timings[t] = 0;
80 timingdata[cat].binsize =
81 (timingdata[cat].lock_timings_range[1] -
82 timingdata[cat].lock_timings_range[0])/(TIMING_POINTS+1);
83 if (timingdata[cat].binsize < 1)
84 timingdata[cat].binsize = 1;
85 timingdata[cat].resets++;
87 bin = (d-timingdata[cat].lock_timings_range[0]) /
88 timingdata[cat].binsize;
89 if (bin < 0 || bin >= TIMING_POINTS) {
90 int t;
91 /* this indicates a bug, but isn't really serious */
92 for(t = 0; t < TIMING_POINTS; t++)
93 timingdata[cat].lock_timings[t] = 0;
94 timingdata[cat].misses++;
95 } else {
96 timingdata[cat].lock_timings[bin]++;
97 timingdata[cat].measurements++;
100 return;
103 #endif /* DEBUG_TIME_LOCKS */
105 #if DEBUG_SCHED_CHECK /* only include code if enabled */
107 #define MAX_LOOP (NR_PROCS + NR_TASKS)
109 PUBLIC void
110 check_runqueues(char *when)
112 int q, l = 0;
113 register struct proc *xp;
115 for (xp = BEG_PROC_ADDR; xp < END_PROC_ADDR; ++xp) {
116 xp->p_found = 0;
117 if (l++ > MAX_LOOP) { panic("check error", NO_NUM); }
120 for (q=l=0; q < NR_SCHED_QUEUES; q++) {
121 if (rdy_head[q] && !rdy_tail[q]) {
122 kprintf("head but no tail in %d: %s", q, when);
123 panic("scheduling error", NO_NUM);
125 if (!rdy_head[q] && rdy_tail[q]) {
126 kprintf("tail but no head in %d: %s", q, when);
127 panic("scheduling error", NO_NUM);
129 if (rdy_tail[q] && rdy_tail[q]->p_nextready != NIL_PROC) {
130 kprintf("tail and tail->next not null in %d: %s", q, when);
131 panic("scheduling error", NO_NUM);
133 for(xp = rdy_head[q]; xp != NIL_PROC; xp = xp->p_nextready) {
134 if (!xp->p_ready) {
135 kprintf("scheduling error: unready on runq %d proc %d: %s\n",
136 q, xp->p_nr, when);
137 panic("found unready process on run queue", NO_NUM);
139 if (xp->p_priority != q) {
140 kprintf("scheduling error: wrong priority q %d proc %d: %s\n",
141 q, xp->p_nr, when);
142 panic("wrong priority", NO_NUM);
144 if (xp->p_found) {
145 kprintf("scheduling error: double sched q %d proc %d: %s\n",
146 q, xp->p_nr, when);
147 panic("proc more than once on scheduling queue", NO_NUM);
149 xp->p_found = 1;
150 if (xp->p_nextready == NIL_PROC && rdy_tail[q] != xp) {
151 kprintf("sched err: last element not tail q %d proc %d: %s\n",
152 q, xp->p_nr, when);
153 panic("scheduling error", NO_NUM);
155 if (l++ > MAX_LOOP) panic("loop in schedule queue?", NO_NUM);
159 l = 0;
160 for (xp = BEG_PROC_ADDR; xp < END_PROC_ADDR; ++xp) {
161 if (! isemptyp(xp) && xp->p_ready && ! xp->p_found) {
162 kprintf("sched error: ready proc %d not on queue: %s\n",
163 xp->p_nr, when);
164 panic("ready proc not on scheduling queue", NO_NUM);
165 if (l++ > MAX_LOOP) { panic("loop in proc.t?", NO_NUM); }
170 #endif /* DEBUG_SCHED_CHECK */