[9] | 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 */
|
---|