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 | */
|
---|
5 |
|
---|
6 | #include "kernel.h"
|
---|
7 | #include "proc.h"
|
---|
8 | #include "debug.h"
|
---|
9 | #include <limits.h>
|
---|
10 |
|
---|
11 | #if DEBUG_TIME_LOCKS /* only include code if enabled */
|
---|
12 |
|
---|
13 | /* Data structures to store lock() timing data. */
|
---|
14 | struct lock_timingdata timingdata[TIMING_CATEGORIES];
|
---|
15 | static unsigned long starttimes[TIMING_CATEGORIES][2];
|
---|
16 |
|
---|
17 | #define HIGHCOUNT 0
|
---|
18 | #define LOWCOUNT 1
|
---|
19 |
|
---|
20 | void timer_start(int cat, char *name)
|
---|
21 | {
|
---|
22 | static int init = 0;
|
---|
23 | unsigned long h, l;
|
---|
24 | int i;
|
---|
25 |
|
---|
26 | if (cat < 0 || cat >= TIMING_CATEGORIES) return;
|
---|
27 |
|
---|
28 | for(i = 0; i < sizeof(timingdata[0].names) && *name; i++)
|
---|
29 | timingdata[cat].names[i] = *name++;
|
---|
30 | timingdata[0].names[sizeof(timingdata[0].names)-1] = '\0';
|
---|
31 |
|
---|
32 | if (starttimes[cat][HIGHCOUNT]) { return; }
|
---|
33 |
|
---|
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;
|
---|
41 | }
|
---|
42 | }
|
---|
43 |
|
---|
44 | read_tsc(&starttimes[cat][HIGHCOUNT], &starttimes[cat][LOWCOUNT]);
|
---|
45 | }
|
---|
46 |
|
---|
47 | void timer_end(int cat)
|
---|
48 | {
|
---|
49 | unsigned long h, l, d = 0, binsize;
|
---|
50 | int bin;
|
---|
51 |
|
---|
52 | read_tsc(&h, &l);
|
---|
53 | if (cat < 0 || cat >= TIMING_CATEGORIES) return;
|
---|
54 | if (!starttimes[cat][HIGHCOUNT]) {
|
---|
55 | timingdata[cat].misses++;
|
---|
56 | return;
|
---|
57 | }
|
---|
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;
|
---|
66 | }
|
---|
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++;
|
---|
86 | }
|
---|
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++;
|
---|
98 | }
|
---|
99 |
|
---|
100 | return;
|
---|
101 | }
|
---|
102 |
|
---|
103 | #endif /* DEBUG_TIME_LOCKS */
|
---|
104 |
|
---|
105 | #if DEBUG_SCHED_CHECK /* only include code if enabled */
|
---|
106 |
|
---|
107 | #define PROCLIMIT 10000
|
---|
108 |
|
---|
109 | PUBLIC void
|
---|
110 | check_runqueues(char *when)
|
---|
111 | {
|
---|
112 | int q, l = 0;
|
---|
113 | register struct proc *xp;
|
---|
114 |
|
---|
115 | for (xp = BEG_PROC_ADDR; xp < END_PROC_ADDR; ++xp) {
|
---|
116 | xp->p_found = 0;
|
---|
117 | if (l++ > PROCLIMIT) { panic("check error", NO_NUM); }
|
---|
118 | }
|
---|
119 |
|
---|
120 | for (q=0; q < NR_SCHED_QUEUES; q++) {
|
---|
121 | if (rdy_head[q] && !rdy_tail[q]) {
|
---|
122 | kprintf("head but no tail: %s", when);
|
---|
123 | panic("scheduling error", NO_NUM);
|
---|
124 | }
|
---|
125 | if (!rdy_head[q] && rdy_tail[q]) {
|
---|
126 | kprintf("tail but no head: %s", when);
|
---|
127 | panic("scheduling error", NO_NUM);
|
---|
128 | }
|
---|
129 | if (rdy_tail[q] && rdy_tail[q]->p_nextready != NIL_PROC) {
|
---|
130 | kprintf("tail and tail->next not null; %s", when);
|
---|
131 | panic("scheduling error", NO_NUM);
|
---|
132 | }
|
---|
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: %s\n", when);
|
---|
136 |
|
---|
137 | panic("found unready process on run queue", NO_NUM);
|
---|
138 | }
|
---|
139 | if (xp->p_priority != q) {
|
---|
140 | kprintf("scheduling error: wrong priority: %s\n", when);
|
---|
141 |
|
---|
142 | panic("wrong priority", NO_NUM);
|
---|
143 | }
|
---|
144 | if (xp->p_found) {
|
---|
145 | kprintf("scheduling error: double scheduling: %s\n", when);
|
---|
146 | panic("proc more than once on scheduling queue", NO_NUM);
|
---|
147 | }
|
---|
148 | xp->p_found = 1;
|
---|
149 | if (xp->p_nextready == NIL_PROC && rdy_tail[q] != xp) {
|
---|
150 | kprintf("scheduling error: last element not tail: %s\n", when);
|
---|
151 | panic("scheduling error", NO_NUM);
|
---|
152 | }
|
---|
153 | if (l++ > PROCLIMIT) panic("loop in schedule queue?", NO_NUM);
|
---|
154 | }
|
---|
155 | }
|
---|
156 |
|
---|
157 | for (xp = BEG_PROC_ADDR; xp < END_PROC_ADDR; ++xp) {
|
---|
158 | if (! isemptyp(xp) && xp->p_ready && ! xp->p_found) {
|
---|
159 | kprintf("scheduling error: ready not on queue: %s\n", when);
|
---|
160 | panic("ready proc not on scheduling queue", NO_NUM);
|
---|
161 | if (l++ > PROCLIMIT) { panic("loop in proc.t?", NO_NUM); }
|
---|
162 | }
|
---|
163 | }
|
---|
164 | }
|
---|
165 |
|
---|
166 | #endif /* DEBUG_SCHED_CHECK */
|
---|