#define FREQSCALE 1000 int already_exists_in_q(struct proc *p) { struct buf *bp; sched_foreach(bp) if (bproc(bp) == p && (bp->b_flags & B_READ)) return 1; return 0; } quad_t tmp_a_thinktime; void seek_collect_stats(struct buf *new) { quad_t thinktime; int lastpos; quad_t distance; int direction; int i, nsamples, n, gotmedn = 0, gotmost = 0; /* struct buf *bp; */ assert(new); assert(bproc(new)); assert(pinfo(bproc(new))); thinktime = NOW - bpinfo(new).prev_finish_time; if (bpid(new) == 'a') tmp_a_thinktime = thinktime; #if 0 sched_foreach(bp) { if (new->b_flags & B_READ) { if (bproc(bp) == bproc(new) && (bp->b_flags & B_READ)) { thinktime = 1; break; } } else { if (bproc(bp) == bproc(new)) { return; /* xxx just ignore delayed writes */ } } } #else if (!(new->b_flags & B_READ)) return; if (already_exists_in_q(bproc(new))) thinktime = 1; #endif /* for density plot: */ /* printf("[%d] arrive %lld\n", bproc(new)->p_pid, thinktime); */ if (thinktime >= MAXTIME) thinktime = MAXTIME-1; nsamples = 0; for (i = 0; i < MAXTIME; i+=TIMEGRAIN) { bpinfo(new).bucket[i/TIMEGRAIN] *= BUCKETDECAY; bpinfo(new).bucket[i/TIMEGRAIN] /= 100; nsamples += bpinfo(new).bucket[i/TIMEGRAIN]; } bpinfo(new).bucket[thinktime/TIMEGRAIN] += FREQSCALE; nsamples += FREQSCALE; n = 0; for (i = 0; i < MAXTIME; i+=TIMEGRAIN) { if (gotmedn == 0 && n*2 > nsamples) bpinfo(new).expected_thinktime = i, gotmedn = 1; if (gotmost == 0 && n*100 > nsamples * 90 /* percentile */) bpinfo(new).expected_most_thinktime = i, gotmost = 1; n += bpinfo(new).bucket[i/TIMEGRAIN]; } if (!gotmedn) bpinfo(new).expected_thinktime = i; if (!gotmost) bpinfo(new).expected_most_thinktime = i; lastpos = bpinfo(new).prev_location; bpinfo(new).prev_location = pos(new) + (size(new)+511) / 512; distance = pos(new) - lastpos; if (distance < 0) distance = -distance, direction = 0; else direction = 1; bpinfo(new).expected_seek_distance = (bpinfo(new).expected_seek_distance * DECAY + distance * (100-DECAY)) / 100; bpinfo(new).expected_seek_direction = (bpinfo(new).expected_seek_direction * DECAY + (direction * 100) * (100-DECAY)) / 100; bpinfo(new).expected_positioning_time = postime(bpinfo(new).expected_seek_distance); } int seek_evaluate(volatile struct buf *last, volatile struct buf *next) { quad_t next_seek_distance; int next_seek_direction; quad_t next_positioning_time; #if NWCS quad_t elapsed, last_thinktime_left, last_expected_time; #endif assert(next); if (!last) return -1; next_seek_distance = pos(next) - (pos(last) + (size(last)+511) / 512); if (next_seek_distance < 0) { next_seek_distance = -next_seek_distance; next_seek_direction = 0; } else next_seek_direction = 1; next_positioning_time = postime(next_seek_distance); #define L bpinfo(last) #if NWCS elapsed = NOW - L.prev_finish_time; if (elapsed > L.expected_most_thinktime) { p("NOwait %lld > %c.%lld, elapsed too long", elapsed, bpid(last), L.expected_most_thinktime); return 0; } #ifdef CLOOK if (next_seek_direction == 1 && L.expected_seek_direction < 30) { p("%c.ahead, %c.behind: %d", bpid(next), bpid(last), L.expected_seek_direction); return 0; } if (next_seek_direction == 0 && L.expected_seek_direction > 70) { p("%c.behind, %c.ahead: %d", bpid(next), bpid(last), L.expected_seek_direction); if (noNWCS) return 0; /* solely to measure NWCS overhead */ return L.expected_most_thinktime - elapsed; } #endif /* CLOOK */ last_thinktime_left = L.expected_thinktime - elapsed; if (last_thinktime_left < 0) last_thinktime_left = 0; last_expected_time = L.expected_positioning_time + last_thinktime_left; if (next_positioning_time < last_expected_time) { p("nowait %c.%lld < (%c.%lld = %lld<%lld> + %lld)", bpid(next), next_positioning_time, bpid(last), last_expected_time, L.expected_positioning_time, L.expected_seek_distance, last_thinktime_left); return 0; } else { p(" wait %c.%lld > (%c.%lld = %lld<%lld> + %lld) -> *%lld*", bpid(next), next_positioning_time, bpid(last), last_expected_time, L.expected_positioning_time, L.expected_seek_distance, last_thinktime_left, L.expected_most_thinktime - elapsed); if (noNWCS) return 0; /* solely to measure NWCS overhead */ return L.expected_most_thinktime - elapsed; } #endif tprintf("notacceptable %lld us\n", L.expected_most_thinktime); if (noNWCS) return 0; return L.expected_most_thinktime; }