block: General purpose routines to fingerprint disk IO Signed-off-by: Jake Moilanen --- block/genhd.c | 22 ++++++- block/ll_rw_blk.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/blkdev.h | 13 ++++ include/linux/genhd.h | 1 4 files changed, 166 insertions(+), 6 deletions(-) Index: linux-rc/block/genhd.c =================================================================== --- linux-rc.orig/block/genhd.c +++ linux-rc/block/genhd.c @@ -29,6 +29,8 @@ static struct blk_major_name { char name[16]; } *major_names[BLKDEV_MAJOR_HASH_SIZE]; +LIST_HEAD(gendisks); + /* index in the above - for now: assume no multimajor ranges */ static inline int major_to_index(int major) { @@ -387,19 +389,22 @@ static ssize_t disk_stats_read(struct ge jiffies_to_msecs(disk_stat_read(disk, io_ticks)), jiffies_to_msecs(disk_stat_read(disk, time_in_queue))); } + +#ifdef CONFIG_FINGERPRINTING static ssize_t disk_fp_read(struct gendisk * disk, char *page) { - return sprintf(page, "reads: %llx\n" - "writes: %llx\n" - "head_pos: %llx\n" - "avg_dist: %llx\n" - "avg_size: %llx\n", + return sprintf(page, "reads: %lld\n" + "writes: %lld\n" + "head_pos: %lld\n" + "avg_dist: %lld\n" + "avg_size: %lld\n", (unsigned long long)disk->fp_ss->reads, (unsigned long long)disk->fp_ss->writes, (unsigned long long)disk->fp_ss->head_pos, (unsigned long long)disk->fp_ss->avg_dist, (unsigned long long)disk->fp_ss->avg_size); } +#endif static struct disk_attribute disk_attr_uevent = { .attr = {.name = "uevent", .mode = S_IWUSR }, @@ -425,10 +430,13 @@ static struct disk_attribute disk_attr_s .attr = {.name = "stat", .mode = S_IRUGO }, .show = disk_stats_read }; + +#ifdef CONFIG_FINGERPRINTING static struct disk_attribute disk_attr_fp = { .attr = {.name = "fp", .mode = S_IRUGO }, .show = disk_fp_read }; +#endif static struct attribute * default_attrs[] = { &disk_attr_uevent.attr, @@ -437,7 +445,9 @@ static struct attribute * default_attrs[ &disk_attr_removable.attr, &disk_attr_size.attr, &disk_attr_stat.attr, +#ifdef CONFIG_FINGERPRINTING &disk_attr_fp.attr, +#endif NULL, }; @@ -446,6 +456,7 @@ static void disk_release(struct kobject struct gendisk *disk = to_disk(kobj); kfree(disk->random); kfree(disk->part); + list_del(&disk->gendisks); free_disk_stats(disk); kfree(disk); } @@ -646,6 +657,7 @@ struct gendisk *alloc_disk_node(int mino kobj_set_kset_s(disk,block_subsys); kobject_init(&disk->kobj); rand_initialize_disk(disk); + list_add_tail(&disk->gendisks, &gendisks); } disk->fp_ss = kmalloc(sizeof(struct fp_snapshot), GFP_KERNEL); Index: linux-rc/block/ll_rw_blk.c =================================================================== --- linux-rc.orig/block/ll_rw_blk.c +++ linux-rc/block/ll_rw_blk.c @@ -21,6 +21,7 @@ #include #include #include /* for max_pfn/max_low_pfn */ +#include #include #include #include @@ -2608,6 +2609,141 @@ static inline void add_request(request_q __elv_add_request(q, req, ELEVATOR_INSERT_SORT, 0); } +#ifdef CONFIG_GENETIC_IOSCHED_AS +extern struct list_head gendisks; + +void disk_stats_snapshot(phenotype_t * pt) +{ + struct list_head * d; + struct gendisk *disk; + struct disk_stats_snapshot * ss = (struct disk_stats_snapshot *)pt->child_ranking[0]->stats_snapshot; + + memset(ss, 0, sizeof(struct disk_stats_snapshot)); + + list_for_each(d, &gendisks) { + disk = list_entry(d, struct gendisk, gendisks); + + disk_round_stats(disk); + + ss->reads += disk_stat_read(disk, ios[READ]); + ss->writes += disk_stat_read(disk, ios[WRITE]); + ss->read_sectors += disk_stat_read(disk, sectors[READ]); + ss->write_sectors += disk_stat_read(disk, sectors[WRITE]); + ss->time_in_queue += disk_stat_read(disk, time_in_queue); + } +} + +long long disk_num_ops_calc_fitness(genetic_child_t * child) +{ + struct list_head * d; + struct gendisk *disk; + struct disk_stats_snapshot * ss = (struct disk_stats_snapshot *)child->stats_snapshot; + long long reads = 0; + long long writes = 0; + + list_for_each(d, &gendisks) { + disk = list_entry(d, struct gendisk, gendisks); + + disk_round_stats(disk); + + reads += disk_stat_read(disk, ios[READ]); + writes += disk_stat_read(disk, ios[WRITE]); + } + + reads -= ss->reads; + writes -= ss->writes; + + return reads + writes; +} + +long long disk_throughput_calc_fitness(genetic_child_t * child) +{ + struct list_head * d; + struct gendisk *disk; + struct disk_stats_snapshot * ss = (struct disk_stats_snapshot *)child->stats_snapshot; + long long read_sectors = 0; + long long write_sectors = 0; + + list_for_each(d, &gendisks) { + disk = list_entry(d, struct gendisk, gendisks); + + disk_round_stats(disk); + + read_sectors += disk_stat_read(disk, sectors[READ]); + write_sectors += disk_stat_read(disk, sectors[WRITE]); + } + + read_sectors -= ss->read_sectors; + write_sectors -= ss->write_sectors; + + return read_sectors + write_sectors; +} + +long long disk_latency_calc_fitness(genetic_child_t * child) +{ + struct list_head * d; + struct gendisk *disk; + struct disk_stats_snapshot * ss = (struct disk_stats_snapshot *)child->stats_snapshot; + long long time_in_queue = 0; + + list_for_each(d, &gendisks) { + disk = list_entry(d, struct gendisk, gendisks); + + disk_round_stats(disk); + + time_in_queue += disk_stat_read(disk, time_in_queue); + } + + time_in_queue = -(time_in_queue - ss->time_in_queue); + + return time_in_queue; +} + +#ifdef CONFIG_FINGERPRINTING + +void disk_update_fingerprint(phenotype_t * pt) +{ + struct list_head * d; + struct gendisk *disk; + + BUG_ON(!pt->fp_ss); + + /* tally up all the other disk snapshots */ + list_for_each(d, &gendisks) { + disk = list_entry(d, struct gendisk, gendisks); + + consolidate_fp_snapshot(pt->fp_ss, disk->fp_ss); + + /* reset it for the next generation */ + reset_fp_snapshot(disk->fp_ss); + } + +} + +void disk_get_fingerprint(phenotype_t * pt) +{ + struct list_head * d; + struct gendisk *disk; + + BUG_ON(!pt->fp_ss); + + /* tally up all the other disk snapshots */ + list_for_each(d, &gendisks) { + disk = list_entry(d, struct gendisk, gendisks); + + consolidate_fp_snapshot(pt->fp_ss, disk->fp_ss); + + /* reset it for the next generation */ + reset_fp_snapshot(disk->fp_ss); + } + + calc_fp(pt->fp, pt->fp_ss); +} + +#endif /* CONFIG_FINGERPRINTING */ + +#endif /* GENETIC_IOSCHED_AS */ + /* * disk_round_stats() - Round off the performance stats on a struct * disk_stats. Index: linux-rc/include/linux/genhd.h =================================================================== --- linux-rc.orig/include/linux/genhd.h +++ linux-rc/include/linux/genhd.h @@ -124,6 +124,7 @@ struct gendisk { atomic_t sync_io; /* RAID */ unsigned long stamp; int in_flight; + struct list_head gendisks; #ifdef CONFIG_SMP struct disk_stats *dkstats; #else Index: linux-rc/include/linux/blkdev.h =================================================================== --- linux-rc.orig/include/linux/blkdev.h +++ linux-rc/include/linux/blkdev.h @@ -833,12 +833,23 @@ void kblockd_flush(void); _res; \ } \ ) -#endif +#endif #define MODULE_ALIAS_BLOCKDEV(major,minor) \ MODULE_ALIAS("block-major-" __stringify(major) "-" __stringify(minor)) #define MODULE_ALIAS_BLOCKDEV_MAJOR(major) \ MODULE_ALIAS("block-major-" __stringify(major) "-*") +#ifdef CONFIG_GENETIC_IOSCHED_AS + +struct disk_stats_snapshot +{ + unsigned long reads; + unsigned long writes; + unsigned long read_sectors; + unsigned long write_sectors; + unsigned long time_in_queue; +}; +#endif /* CONFIG_GENETIC_IOSCHED_AS */ #endif