diff options
author | phk <phk@FreeBSD.org> | 2003-02-07 23:08:24 +0000 |
---|---|---|
committer | phk <phk@FreeBSD.org> | 2003-02-07 23:08:24 +0000 |
commit | e8f2dea5ddc06968c8deacd684154cd56b9664ff (patch) | |
tree | 926f1fc791d8d4e6893f5573cb0b3fed3a603f7c /sys/geom/geom_io.c | |
parent | 3c791c8729585027435477ccde6a53be4ba01225 (diff) | |
download | FreeBSD-src-e8f2dea5ddc06968c8deacd684154cd56b9664ff.zip FreeBSD-src-e8f2dea5ddc06968c8deacd684154cd56b9664ff.tar.gz |
Commit the correct copy of the g_stat structure.
Add debug.sizeof.g_stat sysctl.
Set the id field of the g_stat when we create consumers and providers.
Remove biocount from consumer, we will use the counters in the g_stat
structure instead. Replace one field which will need to be atomically
manipulated with two fields which will not (stat.nop and stat.nend).
Change add companion field to bio_children: bio_inbed for the exact
same reason.
Don't output the biocount in the confdot output.
Fix KASSERT in g_io_request().
Add sysctl kern.geom.collectstats defaulting to off.
Collect the following raw statistics conditioned on this sysctl:
for each consumer and provider {
total number of operations started.
total number of operations completed.
time last operation completed.
sum of idle-time.
for each of BIO_READ, BIO_WRITE and BIO_DELETE {
number of operations completed.
number of bytes completed.
number of ENOMEM errors.
number of other errors.
sum of transaction time.
}
}
API for getting hold of these statistics data not included yet.
Diffstat (limited to 'sys/geom/geom_io.c')
-rw-r--r-- | sys/geom/geom_io.c | 103 |
1 files changed, 80 insertions, 23 deletions
diff --git a/sys/geom/geom_io.c b/sys/geom/geom_io.c index 9a6d215..842595a 100644 --- a/sys/geom/geom_io.c +++ b/sys/geom/geom_io.c @@ -154,7 +154,7 @@ g_clone_bio(struct bio *bp) bp2->bio_offset = bp->bio_offset; bp2->bio_data = bp->bio_data; bp2->bio_attribute = bp->bio_attribute; - bp->bio_children++; /* XXX: atomic ? */ + bp->bio_children++; } /* g_trace(G_T_BIO, "g_clone_bio(%p) = %p", bp, bp2); */ return(bp2); @@ -261,24 +261,46 @@ g_io_check(struct bio *bp) void g_io_request(struct bio *bp, struct g_consumer *cp) { + struct g_provider *pp; + struct bintime bt; + pp = cp->provider; KASSERT(cp != NULL, ("NULL cp in g_io_request")); KASSERT(bp != NULL, ("NULL bp in g_io_request")); KASSERT(bp->bio_data != NULL, ("NULL bp->data in g_io_request")); - KASSERT(bp->bio_to == NULL, ("consumer not attached in g_io_request")); + KASSERT(pp != NULL, ("consumer not attached in g_io_request")); + bp->bio_from = cp; - bp->bio_to = cp->provider; + bp->bio_to = pp; bp->bio_error = 0; bp->bio_completed = 0; - /* begin_stats(&bp->stats); */ + if (g_collectstats) { + /* Collect statistics */ + binuptime(&bp->bio_t0); + if (cp->stat.nop == cp->stat.nend) { + /* Consumer is idle */ + bt = bp->bio_t0; + bintime_sub(&bt, &cp->stat.wentidle); + bintime_add(&cp->stat.it, &bt); + if (pp->stat.nop == pp->stat.nend) { + /* + * NB: Provider can only be idle if the + * consumer is but we cannot trust them + * to have gone idle at the same time. + */ + bt = bp->bio_t0; + bintime_sub(&bt, &pp->stat.wentidle); + bintime_add(&pp->stat.it, &bt); + } + } + } + cp->stat.nop++; + pp->stat.nop++; - atomic_add_int(&cp->biocount, 1); - /* Pass it on down. */ g_trace(G_T_BIO, "bio_request(%p) from %p(%s) to %p(%s) cmd %d", - bp, bp->bio_from, bp->bio_from->geom->name, - bp->bio_to, bp->bio_to->name, bp->bio_cmd); + bp, cp, cp->geom->name, pp, pp->name, bp->bio_cmd); g_bioq_enqueue_tail(bp, &g_bio_run_down); wakeup(&g_wait_down); } @@ -286,32 +308,69 @@ g_io_request(struct bio *bp, struct g_consumer *cp) void g_io_deliver(struct bio *bp, int error) { + struct g_consumer *cp; + struct g_provider *pp; + struct bintime t1; + int idx; + cp = bp->bio_from; + pp = bp->bio_to; KASSERT(bp != NULL, ("NULL bp in g_io_deliver")); - KASSERT(bp->bio_from != NULL, ("NULL bio_from in g_io_deliver")); - KASSERT(bp->bio_from->geom != NULL, - ("NULL bio_from->geom in g_io_deliver")); - KASSERT(bp->bio_to != NULL, ("NULL bio_to in g_io_deliver")); + KASSERT(cp != NULL, ("NULL bio_from in g_io_deliver")); + KASSERT(cp->geom != NULL, ("NULL bio_from->geom in g_io_deliver")); + KASSERT(pp != NULL, ("NULL bio_to in g_io_deliver")); g_trace(G_T_BIO, "g_io_deliver(%p) from %p(%s) to %p(%s) cmd %d error %d off %jd len %jd", - bp, bp->bio_from, bp->bio_from->geom->name, - bp->bio_to, bp->bio_to->name, bp->bio_cmd, error, + bp, cp, cp->geom->name, pp, pp->name, bp->bio_cmd, error, (intmax_t)bp->bio_offset, (intmax_t)bp->bio_length); - /* finish_stats(&bp->stats); */ + + switch (bp->bio_cmd) { + case BIO_READ: idx = G_STAT_IDX_READ; break; + case BIO_WRITE: idx = G_STAT_IDX_WRITE; break; + case BIO_DELETE: idx = G_STAT_IDX_DELETE; break; + case BIO_GETATTR: idx = -1; break; + case BIO_SETATTR: idx = -1; break; + default: + panic("unknown bio_cmd in g_io_deliver"); + break; + } + + /* Collect statistics */ + if (g_collectstats) { + binuptime(&t1); + pp->stat.wentidle = t1; + cp->stat.wentidle = t1; + + if (idx >= 0) { + bintime_sub(&t1, &bp->bio_t0); + bintime_add(&cp->stat.ops[idx].dt, &t1); + bintime_add(&pp->stat.ops[idx].dt, &t1); + pp->stat.ops[idx].nbyte += bp->bio_completed; + cp->stat.ops[idx].nbyte += bp->bio_completed; + pp->stat.ops[idx].nop++; + cp->stat.ops[idx].nop++; + if (error == ENOMEM) { + cp->stat.ops[idx].nmem++; + pp->stat.ops[idx].nmem++; + } else if (error != 0) { + cp->stat.ops[idx].nerr++; + pp->stat.ops[idx].nerr++; + } + } + } + + pp->stat.nend++; /* In reverse order of g_io_request() */ + cp->stat.nend++; if (error == ENOMEM) { - printf("ENOMEM %p on %p(%s)\n", - bp, bp->bio_to, bp->bio_to->name); - g_io_request(bp, bp->bio_from); + printf("ENOMEM %p on %p(%s)\n", bp, pp, pp->name); + g_io_request(bp, cp); pace++; return; } - bp->bio_error = error; - g_bioq_enqueue_tail(bp, &g_bio_run_up); - wakeup(&g_wait_up); } @@ -362,8 +421,6 @@ g_io_schedule_up(struct thread *tp __unused) break; cp = bp->bio_from; - - atomic_add_int(&cp->biocount, -1); biodone(bp); } } |