lkml.org 
[lkml]   [2003]   [Feb]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[patch] Make diskstats per-cpu using kmalloc_percpu
    Hi Andrew,
    Sometime back you'd asked for this on irc. This version makes
    the disk stats on struct gendisk per-cpu. I am working on making the
    per partition stats per-cpu too (struct hd_struct), Meanwhile, I was
    wondering if this can get some testing on the -mm tree. Patch has been
    tested on a PIII 4way in smp and up configurations. Applies on 2.5.63.

    Thanks,
    Kiran


    drivers/block/genhd.c | 23 +++++++---
    drivers/block/ll_rw_blk.c | 29 +++++++------
    drivers/md/md.c | 4 +
    fs/partitions/check.c | 8 ---
    include/linux/genhd.h | 97 ++++++++++++++++++++++++++++++++++++++++++----
    5 files changed, 124 insertions(+), 37 deletions(-)

    diff -ruN -X dontdiff linux-2.5.62/drivers/block/genhd.c diskstat-2.5.62/drivers/block/genhd.c
    --- linux-2.5.62/drivers/block/genhd.c Tue Feb 18 04:26:14 2003
    +++ diskstat-2.5.62/drivers/block/genhd.c Wed Feb 19 15:44:47 2003
    @@ -328,14 +328,16 @@
    "%8u %8u %8llu %8u "
    "%8u %8u %8u"
    "\n",
    - disk->reads, disk->read_merges,
    - (unsigned long long)disk->read_sectors,
    - jiffies_to_msec(disk->read_ticks),
    - disk->writes, disk->write_merges,
    - (unsigned long long)disk->write_sectors,
    - jiffies_to_msec(disk->write_ticks),
    - disk->in_flight, jiffies_to_msec(disk->io_ticks),
    - jiffies_to_msec(disk->time_in_queue));
    + DISK_STAT_READ(disk, reads), DISK_STAT_READ(disk, read_merges),
    + (unsigned long long)DISK_STAT_READ(disk, read_sectors),
    + jiffies_to_msec(DISK_STAT_READ(disk, read_ticks)),
    + DISK_STAT_READ(disk, writes),
    + DISK_STAT_READ(disk, write_merges),
    + (unsigned long long)DISK_STAT_READ(disk, write_sectors),
    + jiffies_to_msec(DISK_STAT_READ(disk, write_ticks)),
    + DISK_STAT_READ(disk, in_flight),
    + jiffies_to_msec(DISK_STAT_READ(disk, io_ticks)),
    + jiffies_to_msec(DISK_STAT_READ(disk, time_in_queue)));
    }
    static struct disk_attribute disk_attr_dev = {
    .attr = {.name = "dev", .mode = S_IRUGO },
    @@ -367,6 +369,7 @@
    struct gendisk *disk = to_disk(kobj);
    kfree(disk->random);
    kfree(disk->part);
    + free_disk_stats(disk);
    kfree(disk);
    }

    @@ -386,6 +389,10 @@
    struct gendisk *disk = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
    if (disk) {
    memset(disk, 0, sizeof(struct gendisk));
    + if (!init_disk_stats(disk)) {
    + kfree(disk);
    + return NULL;
    + }
    if (minors > 1) {
    int size = (minors - 1) * sizeof(struct hd_struct);
    disk->part = kmalloc(size, GFP_KERNEL);
    diff -ruN -X dontdiff linux-2.5.62/drivers/block/ll_rw_blk.c diskstat-2.5.62/drivers/block/ll_rw_blk.c
    --- linux-2.5.62/drivers/block/ll_rw_blk.c Tue Feb 18 04:25:53 2003
    +++ diskstat-2.5.62/drivers/block/ll_rw_blk.c Thu Feb 20 12:07:18 2003
    @@ -1474,17 +1474,17 @@
    return;

    if (rw == READ) {
    - rq->rq_disk->read_sectors += nr_sectors;
    + DISK_STAT_ADD(rq->rq_disk, read_sectors, nr_sectors);
    if (!new_io)
    - rq->rq_disk->read_merges++;
    + DISK_STAT_INC(rq->rq_disk, read_merges);
    } else if (rw == WRITE) {
    - rq->rq_disk->write_sectors += nr_sectors;
    + DISK_STAT_ADD(rq->rq_disk, write_sectors, nr_sectors);
    if (!new_io)
    - rq->rq_disk->write_merges++;
    + DISK_STAT_INC(rq->rq_disk, write_merges);
    }
    if (new_io) {
    disk_round_stats(rq->rq_disk);
    - rq->rq_disk->in_flight++;
    + DISK_STAT_INC(rq->rq_disk, in_flight);
    }
    }

    @@ -1524,11 +1524,12 @@
    {
    unsigned long now = jiffies;

    - disk->time_in_queue += disk->in_flight * (now - disk->stamp);
    + DISK_STAT_ADD(disk, time_in_queue,
    + DISK_STAT_READ(disk, in_flight) * (now - disk->stamp));
    disk->stamp = now;

    - if (disk->in_flight)
    - disk->io_ticks += (now - disk->stamp_idle);
    + if (DISK_STAT_READ(disk, in_flight))
    + DISK_STAT_ADD(disk, io_ticks, (now - disk->stamp_idle));
    disk->stamp_idle = now;
    }

    @@ -1646,7 +1647,7 @@

    if (req->rq_disk) {
    disk_round_stats(req->rq_disk);
    - req->rq_disk->in_flight--;
    + DISK_STAT_DEC(req->rq_disk, in_flight);
    }

    __blk_put_request(q, next);
    @@ -2198,16 +2199,16 @@
    unsigned long duration = jiffies - req->start_time;
    switch (rq_data_dir(req)) {
    case WRITE:
    - disk->writes++;
    - disk->write_ticks += duration;
    + DISK_STAT_INC(disk, writes);
    + DISK_STAT_ADD(disk, write_ticks, duration);
    break;
    case READ:
    - disk->reads++;
    - disk->read_ticks += duration;
    + DISK_STAT_INC(disk, reads);
    + DISK_STAT_ADD(disk, read_ticks, duration);
    break;
    }
    disk_round_stats(disk);
    - disk->in_flight--;
    + DISK_STAT_DEC(disk, in_flight);
    }
    __blk_put_request(req->q, req);
    }
    diff -ruN -X dontdiff linux-2.5.62/drivers/md/md.c diskstat-2.5.62/drivers/md/md.c
    --- linux-2.5.62/drivers/md/md.c Tue Feb 18 04:26:10 2003
    +++ diskstat-2.5.62/drivers/md/md.c Wed Feb 19 15:56:38 2003
    @@ -2771,7 +2771,9 @@
    idle = 1;
    ITERATE_RDEV(mddev,rdev,tmp) {
    struct gendisk *disk = rdev->bdev->bd_contains->bd_disk;
    - curr_events = disk->read_sectors + disk->write_sectors - disk->sync_io;
    + curr_events = DISK_STAT_READ(disk, read_sectors) +
    + DISK_STAT_READ(disk, write_sectors) -
    + disk->sync_io;
    if ((curr_events - rdev->last_events) > 32) {
    rdev->last_events = curr_events;
    idle = 0;
    diff -ruN -X dontdiff linux-2.5.62/fs/partitions/check.c diskstat-2.5.62/fs/partitions/check.c
    --- linux-2.5.62/fs/partitions/check.c Tue Feb 18 04:26:56 2003
    +++ diskstat-2.5.62/fs/partitions/check.c Wed Feb 19 16:48:13 2003
    @@ -503,13 +503,7 @@
    disk->capacity = 0;
    disk->flags &= ~GENHD_FL_UP;
    unlink_gendisk(disk);
    - disk->reads = disk->writes = 0;
    - disk->read_sectors = disk->write_sectors = 0;
    - disk->read_merges = disk->write_merges = 0;
    - disk->read_ticks = disk->write_ticks = 0;
    - disk->in_flight = 0;
    - disk->io_ticks = 0;
    - disk->time_in_queue = 0;
    + disk_stat_set_all(disk, 0);
    disk->stamp = disk->stamp_idle = 0;
    devfs_remove_partitions(disk);
    if (disk->driverfs_dev) {
    diff -ruN -X dontdiff linux-2.5.62/include/linux/genhd.h diskstat-2.5.62/include/linux/genhd.h
    --- linux-2.5.62/include/linux/genhd.h Tue Feb 18 04:25:57 2003
    +++ diskstat-2.5.62/include/linux/genhd.h Thu Feb 20 12:05:14 2003
    @@ -73,6 +73,16 @@
    #define GENHD_FL_CD 8
    #define GENHD_FL_UP 16

    +struct disk_stats {
    + unsigned read_sectors, write_sectors;
    + unsigned reads, writes;
    + unsigned read_merges, write_merges;
    + unsigned read_ticks, write_ticks;
    + unsigned io_ticks;
    + int in_flight;
    + unsigned time_in_queue;
    +};
    +
    struct gendisk {
    int major; /* major number of driver */
    int first_minor;
    @@ -97,16 +107,89 @@
    int policy;

    unsigned sync_io; /* RAID */
    - unsigned read_sectors, write_sectors;
    - unsigned reads, writes;
    - unsigned read_merges, write_merges;
    - unsigned read_ticks, write_ticks;
    - unsigned io_ticks;
    - int in_flight;
    unsigned long stamp, stamp_idle;
    - unsigned time_in_queue;
    +#ifdef CONFIG_SMP
    + struct disk_stats *dkstats;
    +#else
    + struct disk_stats dkstats;
    +#endif
    };

    +/*
    + * Macros to operate on percpu disk statistics:
    + * Since writes to disk_stats are serialised through the queue_lock,
    + * smp_processor_id() should be enough to get to the per_cpu versions
    + * of statistics counters
    + */
    +#ifdef CONFIG_SMP
    +#define DISK_STAT_INC(gendiskp, field) \
    + (per_cpu_ptr(gendiskp->dkstats, smp_processor_id())->field++)
    +#define DISK_STAT_DEC(gendiskp, field) \
    + (per_cpu_ptr(gendiskp->dkstats, smp_processor_id())->field--)
    +#define DISK_STAT_ADD(gendiskp, field, addnd) \
    + (per_cpu_ptr(gendiskp->dkstats, smp_processor_id())->field += addnd)
    +#define DISK_STAT_SUB(gendiskp, field, subnd) \
    + (per_cpu_ptr(gendiskp->dkstats, smp_processor_id())->field -= subnd)
    +#define DISK_STAT_READ(gendiskp, field) \
    +({ \
    + typeof(gendiskp->dkstats->field) res = 0; \
    + int i; \
    + for (i=0; i < NR_CPUS; i++) { \
    + if (!cpu_possible(i)) \
    + continue; \
    + res += per_cpu_ptr(gendiskp->dkstats, i)->field; \
    + } \
    + res; \
    +})
    +
    +static inline void disk_stat_set_all(struct gendisk *gendiskp, int value) {
    + int i;
    + for (i=0; i < NR_CPUS; i++) {
    + if (cpu_possible(i)) {
    + memset(per_cpu_ptr(gendiskp->dkstats, i), value,
    + sizeof (struct disk_stats));
    + }
    + }
    +}
    +
    +#else
    +#define DISK_STAT_INC(gendiskp, field) (gendiskp->dkstats.field++)
    +#define DISK_STAT_DEC(gendiskp, field) (gendiskp->dkstats.field--)
    +#define DISK_STAT_ADD(gendiskp, field, addnd) (gendiskp->dkstats.field += addnd)
    +#define DISK_STAT_SUB(gendiskp, field, subnd) (gendiskp->dkstats.field -= subnd)
    +#define DISK_STAT_READ(gendiskp, field) (gendiskp->dkstats.field)
    +
    +static inline void disk_stat_set_all(struct gendisk *gendiskp, int value) {
    + memset(&gendiskp->dkstats, value, sizeof (struct disk_stats));
    +}
    +#endif
    +
    +/* Inlines to alloc and free disk stats in struct gendisk */
    +#ifdef CONFIG_SMP
    +static inline int init_disk_stats(struct gendisk *disk)
    +{
    + disk->dkstats = kmalloc_percpu(sizeof (struct disk_stats), GFP_KERNEL);
    + if (!disk->dkstats)
    + return 0;
    + disk_stat_set_all(disk, 0);
    + return 1;
    +}
    +
    +static inline void free_disk_stats(struct gendisk *disk)
    +{
    + kfree_percpu(disk->dkstats);
    +}
    +#else /* CONFIG_SMP */
    +static inline int init_disk_stats(struct gendisk *disk)
    +{
    + return 1;
    +}
    +
    +static inline void free_disk_stats(struct gendisk *disk)
    +{
    +}
    +#endif /* CONFIG_SMP */
    +
    /* drivers/block/ll_rw_blk.c */
    extern void disk_round_stats(struct gendisk *disk);

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/
    \
     
     \ /
      Last update: 2005-03-22 13:33    [W:0.036 / U:0.064 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site