diff -Naur linux-2.6.11-rc3-mm2/drivers/block/Kconfig.iosched linux-2.6.11-rc3-mm2-gs/drivers/block/Kconfig.iosched --- linux-2.6.11-rc3-mm2/drivers/block/Kconfig.iosched 2004-12-24 13:33:51.000000000 -0800 +++ linux-2.6.11-rc3-mm2-gs/drivers/block/Kconfig.iosched 2005-02-15 14:53:00.682898592 -0800 @@ -38,4 +38,12 @@ among all processes in the system. It should provide a fair working environment, suitable for desktop systems. +config GENETIC_IOSCHED_AS + bool "Genetic Anticipatory I/O scheduler (EXPERIMENTAL)" + depends on IOSCHED_AS && GENETIC_LIB && EXPERIMENTAL + default n + ---help--- + This will use a genetic algorithm to tweak the tunables of the + anticipatory scheduler autonomically and will adapt tunables + depending on the present workload. endmenu diff -Naur linux-2.6.11-rc3-mm2/drivers/block/as-iosched.c linux-2.6.11-rc3-mm2-gs/drivers/block/as-iosched.c --- linux-2.6.11-rc3-mm2/drivers/block/as-iosched.c 2005-02-14 17:29:20.210956240 -0800 +++ linux-2.6.11-rc3-mm2-gs/drivers/block/as-iosched.c 2005-02-15 15:24:11.244530000 -0800 @@ -20,6 +20,8 @@ #include #include #include +#include +#include #define REQ_SYNC 1 #define REQ_ASYNC 0 @@ -67,6 +69,8 @@ */ #define MAX_THINKTIME (HZ/50UL) +unsigned long max_thinktime = MAX_THINKTIME; + /* Bits in as_io_context.state */ enum as_io_states { AS_TASK_RUNNING=0, /* Process has not exitted */ @@ -83,6 +87,47 @@ * or timed out */ }; +#ifdef CONFIG_GENETIC_IOSCHED_AS + +static void as_create_child(genetic_child_t * child); +static void as_set_child_genes(void * in_genes); +static void as_calc_fitness(genetic_child_t * child); + +struct genetic_ops as_genetic_ops = { + .create_child = as_create_child, + .set_child_genes = as_set_child_genes, + .calc_fitness = as_calc_fitness, + .combine_genes = genetic_generic_combine_genes, + .mutate_child = genetic_generic_mutate_child, +}; + +#define AS_NUM_GENES 6 +#define AS_NUM_CHILDREN 8 + +struct as_genes { + unsigned long read_expire; + unsigned long write_expire; + unsigned long read_batch_expire; + unsigned long write_batch_expire; + unsigned long antic_expire; + unsigned long max_thinktime; +}; + +gene_param_t as_gene_param[AS_NUM_GENES] = { + { HZ/16, 3*HZ/16, default_read_expire, 0}, /* read_expire */ + { HZ/8, 3*HZ/8, default_write_expire, 0}, /* write_expire */ + { HZ/16, 3*HZ/16, default_write_batch_expire, 0},/* write_batch_expire */ + { HZ/4, 3*HZ/4, default_read_batch_expire, 0}, /* read_batch_expire */ + { HZ/300, HZ/100, default_antic_expire, 0}, /* default_antic_expire */ + { HZ/100, 3*HZ/100, MAX_THINKTIME, 0} +}; + +extern void disk_stats_snapshot(void); +extern unsigned long disk_calc_fitness(void); + +LIST_HEAD(as_data_list); +#endif + struct as_data { /* * run time data @@ -132,6 +177,9 @@ unsigned long fifo_expire[2]; unsigned long batch_expire[2]; unsigned long antic_expire; +#ifdef CONFIG_GENETIC_IOSCHED_AS + struct list_head data_list; +#endif }; #define list_entry_fifo(ptr) list_entry((ptr), struct as_rq, fifo) @@ -869,7 +917,7 @@ if (test_bit(AS_TASK_IORUNNING, &aic->state) && in_flight == 0) { thinktime = jiffies - aic->last_end_request; - thinktime = min(thinktime, MAX_THINKTIME-1); + thinktime = min(thinktime, max_thinktime-1); } else thinktime = 0; as_update_thinktime(ad, aic, thinktime); @@ -1854,6 +1902,11 @@ mempool_destroy(ad->arq_pool); put_io_context(ad->io_context); + +#ifdef CONFIG_GENETIC_IOSCHED_AS + list_del(&ad->data_list); +#endif + kfree(ad->hash); kfree(ad); } @@ -1916,6 +1969,10 @@ if (ad->write_batch_count < 2) ad->write_batch_count = 2; +#ifdef CONFIG_GENETIC_IOSCHED_AS + list_add_tail(&ad->data_list, &as_data_list); +#endif + return 0; } @@ -2098,13 +2155,18 @@ static int __init as_init(void) { + int rc; int ret; arq_pool = kmem_cache_create("as_arq", sizeof(struct as_rq), 0, 0, NULL, NULL); if (!arq_pool) return -ENOMEM; - + #ifdef CONFIG_GENETIC_IOSCHED_AS + rc = genetic_init(0, &as_genetic_ops, AS_NUM_CHILDREN, 2 * HZ, "as-ioscheduler"); + if (rc) + panic("as: failed to init genetic lib"); + #endif ret = elv_register(&iosched_as); if (!ret) { /* @@ -2120,6 +2182,73 @@ return ret; } +#ifdef CONFIG_GENETIC_IOSCHED_AS + +/* need to create the genes for the child */ +static void as_create_child(genetic_child_t * child) +{ + int i; + static int child_num = 0; + unsigned long range; + int range_incr; + unsigned long * genes; + + BUG_ON(!child); + + child->genes = (void *)kmalloc(sizeof(struct as_genes), GFP_KERNEL); + if (!child->genes) + panic("as_create_child: error mallocing space"); + + child->gene_param = as_gene_param; + + genes = (unsigned long *)child->genes; + + for (i = 0; i < AS_NUM_GENES; i++) { + range = child->gene_param[i].max - child->gene_param[i].min + 1; + range_incr = range / AS_NUM_CHILDREN; + if (range_incr) + genes[i] = child->gene_param[i].min + + (range_incr * child_num); + else + genes[i] = child->gene_param[i].min + + (child_num / (AS_NUM_CHILDREN / range)); + } + + child->num_genes = AS_NUM_GENES; + + child_num++; +} + +static void as_set_child_genes(void * in_genes) +{ + struct as_genes * genes = (struct as_genes *)in_genes; + struct list_head * d; + struct as_data * ad; + + list_for_each(d, &as_data_list) { + ad = list_entry(d, struct as_data, data_list); + ad->fifo_expire[REQ_SYNC] = genes->read_expire; + ad->fifo_expire[REQ_ASYNC] = genes->write_expire; + ad->antic_expire = genes->antic_expire; + ad->batch_expire[REQ_SYNC] = genes->read_batch_expire; + ad->batch_expire[REQ_ASYNC] = genes->write_batch_expire; + } + max_thinktime = genes->max_thinktime; + + /* Set a mark for the start of this child to help calculate + fitness */ + disk_stats_snapshot(); +} + +static void as_calc_fitness(genetic_child_t * child) +{ + child->fitness = disk_calc_fitness(); +} + +#endif + + + static void __exit as_exit(void) { kmem_cache_destroy(arq_pool); diff -Naur linux-2.6.11-rc3-mm2/drivers/block/genhd.c linux-2.6.11-rc3-mm2-gs/drivers/block/genhd.c --- linux-2.6.11-rc3-mm2/drivers/block/genhd.c 2005-02-14 17:28:33.502057072 -0800 +++ linux-2.6.11-rc3-mm2-gs/drivers/block/genhd.c 2005-02-15 14:37:35.783504672 -0800 @@ -31,6 +31,8 @@ char name[16]; } *major_names[MAX_PROBE_HASH]; +LIST_HEAD(gendisks); + /* index in the above - for now: assume no multimajor ranges */ static inline int major_to_index(int major) { @@ -589,6 +591,7 @@ kobj_set_kset_s(disk,block_subsys); kobject_init(&disk->kobj); rand_initialize_disk(disk); + list_add_tail(&disk->gendisks, &gendisks); } return disk; } diff -Naur linux-2.6.11-rc3-mm2/drivers/block/ll_rw_blk.c linux-2.6.11-rc3-mm2-gs/drivers/block/ll_rw_blk.c --- linux-2.6.11-rc3-mm2/drivers/block/ll_rw_blk.c 2005-02-14 17:29:20.465917480 -0800 +++ linux-2.6.11-rc3-mm2-gs/drivers/block/ll_rw_blk.c 2005-02-15 14:37:35.823498592 -0800 @@ -28,6 +28,7 @@ #include #include #include +#include /* * for max sense size @@ -2329,6 +2330,81 @@ __elv_add_request(q, req, ELEVATOR_INSERT_SORT, 0); } +#ifdef CONFIG_GENETIC_IOSCHED_AS +extern struct list_head gendisks; + +void disk_stats_snapshot(void) +{ + struct list_head * d; + struct gendisk *disk; + + list_for_each(d, &gendisks) { + disk = list_entry(d, struct gendisk, gendisks); + + disk_round_stats(disk); + + disk->reads_snap = disk_stat_read(disk, reads); + disk->writes_snap = disk_stat_read(disk, writes); + disk->read_sectors_snap = disk_stat_read(disk, read_sectors); + disk->write_sectors_snap = disk_stat_read(disk, write_sectors); + disk->time_in_queue_snap = disk_stat_read(disk, time_in_queue); + } +} + +/* XXX is this the best method to calc fitness */ +unsigned long disk_calc_fitness(void) +{ + struct list_head * d; + struct gendisk *disk; + unsigned long reads, writes, time_in_queue; + unsigned long read_sectors, write_sectors; + unsigned long disk_fitness; + unsigned long total_fitness = 0; + + list_for_each(d, &gendisks) { + disk = list_entry(d, struct gendisk, gendisks); + + disk_round_stats(disk); + + reads = disk_stat_read(disk, reads) - disk->reads_snap; + writes = disk_stat_read(disk, writes) - disk->writes_snap; + + read_sectors = disk_stat_read(disk, read_sectors) - disk->read_sectors_snap; + write_sectors = disk_stat_read(disk, write_sectors) - disk->write_sectors_snap; + + time_in_queue = disk_stat_read(disk, time_in_queue) - disk->time_in_queue_snap; + + /* Various attempts at collecting good fitness */ +#if 0 + if (time_in_queue) + disk_fitness = ((reads + writes) 2 * HZ) / time_in_queue; + else + disk_fitness = 0; + +#endif + +#if 1 + if (time_in_queue) + disk_fitness = ((read_sectors + write_sectors) * 2 * HZ) / time_in_queue; + else + disk_fitness = 0; +#endif + +#if 0 + disk_fitness = reads + writes; +#endif + +#if 0 + disk_fitness = read_sectors + write_sectors; +#endif + + total_fitness += disk_fitness; + } + + return total_fitness; +} +#endif + /* * disk_round_stats() - Round off the performance stats on a struct * disk_stats. @@ -2351,7 +2427,6 @@ __disk_stat_add(disk, time_in_queue, disk->in_flight * (now - disk->stamp)); disk->stamp = now; - if (disk->in_flight) __disk_stat_add(disk, io_ticks, (now - disk->stamp_idle)); disk->stamp_idle = now; diff -Naur linux-2.6.11-rc3-mm2/fs/proc/proc_misc.c linux-2.6.11-rc3-mm2-gs/fs/proc/proc_misc.c --- linux-2.6.11-rc3-mm2/fs/proc/proc_misc.c 2005-02-14 17:29:30.810344888 -0800 +++ linux-2.6.11-rc3-mm2-gs/fs/proc/proc_misc.c 2005-02-15 15:06:32.596468968 -0800 @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -201,6 +202,35 @@ #undef K } +#ifdef CONFIG_GENETIC_LIB +extern struct proc_dir_entry * genetic_root_dir; + +int genetic_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int i; + int n = 0; + genetic_t * genetic = (genetic_t *)data; + + n = sprintf(page, "generation_number:\t%ld\n", genetic->generation_number); + n += sprintf(page+n, "num_children:\t\t%ld\n", genetic->num_children); + n += sprintf(page+n, "child_number:\t\t%ld\n", genetic->child_number); + n += sprintf(page+n, "num_mutations:\t\t%ld\n", genetic->num_mutations); + n += sprintf(page+n, "avg_fitness:\t\t%ld\n", genetic->avg_fitness); + n += sprintf(page+n, "last_gen_avg_fitness:\t%ld\n", genetic->last_gen_avg_fitness); + + n += sprintf(page+n, "\nFitness history\n"); + + for (i = genetic->generation_number > GENETIC_HISTORY_SIZE ? GENETIC_HISTORY_SIZE + : genetic->generation_number-1; i > 0; i--) + n += sprintf(page+n, "generation(%ld):\t%ld\n", + genetic->generation_number - i, + genetic->fitness_history[(genetic->fitness_history_index - i) & GENETIC_HISTORY_MASK]); + + return proc_calc_metrics(page, start, off, count, eof, n); +} +#endif + extern struct seq_operations fragmentation_op; static int fragmentation_open(struct inode *inode, struct file *file) { diff -Naur linux-2.6.11-rc3-mm2/include/linux/genetic.h linux-2.6.11-rc3-mm2-gs/include/linux/genetic.h --- linux-2.6.11-rc3-mm2/include/linux/genetic.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.11-rc3-mm2-gs/include/linux/genetic.h 2005-02-15 14:37:22.981450880 -0800 @@ -0,0 +1,103 @@ +#ifndef __LINUX_GENETIC_H +#define __LINUX_GENETIC_H +/* + * include/linux/genetic.h + * + * Jake Moilanen + * Copyright (C) 2004 IBM + * + * Genetic algorithm library + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include + +#define GENETIC_DEFAULT_NUM_MUTATIONS 8 +#define GENETIC_HISTORY_SIZE 0x10 +#define GENETIC_HISTORY_MASK (GENETIC_HISTORY_SIZE - 1) + +#define GENETIC_DEBUG 0 + +#define gen_dbg(format, arg...) do { if (GENETIC_DEBUG) printk(KERN_EMERG __FILE__ ": " format "\n" , ## arg); } while (0) +#define gen_trc(format, arg...) do { if (GENETIC_DEBUG) printk(KERN_EMERG __FILE__ ":%s:%d\n" , __FUNCTION__, __LINE__); } while (0) + +struct gene_param_s; + +struct genetic_child_s { + struct list_head child; + long fitness; + unsigned long num_genes; + void *genes; + struct gene_param_s *gene_param; + void *stats_snapshot; +}; + +typedef struct genetic_child_s genetic_child_t; + +/* Here's a generic idea of what it the genes could look like */ +struct gene_param_s { + unsigned long min; + unsigned long max; + unsigned long initial; + void (*mutate_gene)(genetic_child_t *, unsigned long); +}; + +typedef struct gene_param_s gene_param_t; + +struct genetic_s { + struct list_head children_queue[2]; + struct list_head *run_queue; + struct list_head *finished_queue; + unsigned long child_life_time; + unsigned long num_children; /* Must be power of 2 */ + unsigned long natural_selection_cutoff; /* How many children + * will survive + */ + unsigned long num_mutations; + + void (*natural_selection)(struct genetic_s *); + + char *name; + struct timer_list timer; + struct genetic_ops *ops; + + genetic_child_t **child_ranking; + + /* performance metrics */ + long avg_fitness; + long last_gen_avg_fitness; + + unsigned long generation_number; + unsigned long child_number; + + unsigned long fitness_history_index; + long fitness_history[GENETIC_HISTORY_SIZE]; + +}; + +typedef struct genetic_s genetic_t; + +struct genetic_ops { + void (*create_child)(genetic_child_t *); + void (*set_child_genes)(void *); + void (*calc_fitness)(genetic_child_t *); + void (*combine_genes)(genetic_child_t *, genetic_child_t *, + genetic_child_t *, genetic_child_t *); + void (*mutate_child)(genetic_child_t *); +}; + +extern int __init genetic_init(genetic_t * genetic, struct genetic_ops * ops, unsigned long num_children, unsigned long child_life_time, char * name); +extern void genetic_generic_mutate_child(genetic_child_t * child); +extern void genetic_generic_combine_genes(genetic_child_t * parent_a, + genetic_child_t * parent_b, + genetic_child_t * child_a, + genetic_child_t * child_b); + + +#endif diff -Naur linux-2.6.11-rc3-mm2/include/linux/genhd.h linux-2.6.11-rc3-mm2-gs/include/linux/genhd.h --- linux-2.6.11-rc3-mm2/include/linux/genhd.h 2005-02-14 17:28:56.161612296 -0800 +++ linux-2.6.11-rc3-mm2-gs/include/linux/genhd.h 2005-02-15 14:37:35.851494336 -0800 @@ -121,11 +121,20 @@ atomic_t sync_io; /* RAID */ unsigned long stamp, stamp_idle; int in_flight; + struct list_head gendisks; #ifdef CONFIG_SMP struct disk_stats *dkstats; #else struct disk_stats dkstats; #endif +#ifdef CONFIG_GENETIC_LIB + unsigned reads_snap; + unsigned writes_snap; + unsigned read_sectors_snap; + unsigned write_sectors_snap; + unsigned time_in_queue_snap; +#endif + }; /* Structure for sysfs attributes on block devices */ diff -Naur linux-2.6.11-rc3-mm2/lib/Kconfig linux-2.6.11-rc3-mm2-gs/lib/Kconfig --- linux-2.6.11-rc3-mm2/lib/Kconfig 2004-12-24 13:34:58.000000000 -0800 +++ linux-2.6.11-rc3-mm2-gs/lib/Kconfig 2005-02-15 14:37:23.040441912 -0800 @@ -30,6 +30,12 @@ require M here. See Castagnoli93. Module will be libcrc32c. +config GENETIC_LIB + bool "Genetic Library" + help + This option will build in a genetic library that will tweak + kernel parameters autonomically to improve performance. + # # compression support is select'ed if needed # diff -Naur linux-2.6.11-rc3-mm2/lib/Makefile linux-2.6.11-rc3-mm2-gs/lib/Makefile --- linux-2.6.11-rc3-mm2/lib/Makefile 2005-02-14 17:29:35.793587320 -0800 +++ linux-2.6.11-rc3-mm2-gs/lib/Makefile 2005-02-15 14:37:23.041441760 -0800 @@ -25,6 +25,7 @@ obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o obj-$(CONFIG_CRC32) += crc32.o obj-$(CONFIG_LIBCRC32C) += libcrc32c.o +obj-$(CONFIG_GENETIC_LIB) += genetic.o obj-$(CONFIG_GENERIC_IOMAP) += iomap.o obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate/ diff -Naur linux-2.6.11-rc3-mm2/lib/genetic.c linux-2.6.11-rc3-mm2-gs/lib/genetic.c --- linux-2.6.11-rc3-mm2/lib/genetic.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.11-rc3-mm2-gs/lib/genetic.c 2005-02-15 14:37:23.043441456 -0800 @@ -0,0 +1,429 @@ +/* + * Genetic Algorithm Library + * + * Jake Moilanen + * Copyright (C) 2004 IBM + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +/* + * Life cycle + * + * 1.) Create random children + * 2.) Run tests + * 3.) Calculate fitness + * 4.) Take top preformers + * 5.) Make children + * 6.) Mutate + * 7.) Goto step 2 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static void genetic_ns_top_parents(genetic_t * genetic); +static void genetic_ns_award_top_parents(genetic_t * genetic); +static void genetic_create_children(genetic_t * genetic); +static void genetic_split_performers(genetic_t * genetic); +static void genetic_mutate(genetic_t * genetic); +static void genetic_run_child(genetic_t * genetic); +static void genetic_new_generation(genetic_t * genetic); + +void genetic_switch_child(unsigned long data); +struct proc_dir_entry * genetic_root_dir = 0; +extern int genetic_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data); + +int __init genetic_init(genetic_t * genetic, struct genetic_ops * ops, + unsigned long num_children, unsigned long child_life_time, + char * name) +{ + struct proc_dir_entry *entry; + + genetic = (genetic_t *)kmalloc(sizeof(genetic_t), GFP_KERNEL); + if (!genetic) { + printk(KERN_ERR "genetic_init: not enough memory\n"); + return -ENOMEM; + } + + genetic->name = (char *)kmalloc(strlen(name), GFP_KERNEL); + if (!genetic->name) { + kfree(genetic); + return -ENOMEM; + } + + genetic->child_ranking = (genetic_child_t **)kmalloc(num_children * sizeof(genetic_child_t *), GFP_KERNEL); + if (!genetic->child_ranking) { + kfree(genetic->name); + kfree(genetic); + return -ENOMEM; + } + + /* Init some of our values */ + strcpy(genetic->name, name); + + INIT_LIST_HEAD(&genetic->children_queue[0]); + INIT_LIST_HEAD(&genetic->children_queue[1]); + + genetic->run_queue = &genetic->children_queue[0]; + genetic->finished_queue = &genetic->children_queue[1]; + + genetic->ops = ops; + genetic->num_children = num_children; + genetic->child_life_time = child_life_time; + + genetic->generation_number = 1; + genetic->child_number = 0; + genetic->num_mutations = GENETIC_DEFAULT_NUM_MUTATIONS; + genetic->natural_selection = genetic_ns_top_parents; + genetic->natural_selection_cutoff = num_children / 2; + genetic->avg_fitness = 0; + genetic->last_gen_avg_fitness = 0; + + /* Create some children */ + genetic_create_children(genetic); + + /* Setup how long each child has to live */ + init_timer(&genetic->timer); + genetic->timer.function = genetic_switch_child; + genetic->timer.data = (unsigned long)genetic; + +#ifdef CONFIG_PROC_FS + + /* Setup proc structure to monitor */ + if (!genetic_root_dir) + genetic_root_dir = proc_mkdir("genetic", 0); + + entry = create_proc_entry(name, 0644, genetic_root_dir); + + if (entry) { + entry->nlink = 1; + entry->data = genetic; + entry->read_proc = genetic_read_proc; + } +#endif + + genetic_run_child(genetic); + + printk(KERN_INFO "%ld children started in %s genetic library\n", num_children, name); + + return 0; +} + +/* create some children, it is up to the lib user to come up w/ a good + distro of genes for it's children */ +static void genetic_create_children(genetic_t * genetic) +{ + unsigned long i; + genetic_child_t * child; + + for (i = 0; i < genetic->num_children; i++) { + genetic->child_ranking[i] = (genetic_child_t *)kmalloc(sizeof(genetic_child_t), GFP_KERNEL); + child = genetic->child_ranking[i]; + + genetic->ops->create_child(child); + + list_add_tail(&child->child, genetic->run_queue->next); + } +} + +/* See how well child did and run the next one */ +void genetic_switch_child(unsigned long data) +{ + genetic_t * genetic = (genetic_t *)data; + genetic_child_t * child; + + child = list_entry(genetic->run_queue->next, genetic_child_t, child); + + list_del(&child->child); + + list_add_tail(&child->child, genetic->finished_queue->next); + + genetic->ops->calc_fitness(child); + + genetic->child_ranking[genetic->child_number++] = child; + + /* See if need more children */ + if (list_empty(genetic->run_queue->next)) + genetic_new_generation(genetic); + + genetic_run_child(genetic); +} + +/* Set the childs genes for run */ +void genetic_run_child(genetic_t * genetic) +{ + genetic_child_t * child = list_entry(genetic->run_queue->next, genetic_child_t, child); + void * genes = child->genes; + + BUG_ON(!genes); + + genetic->ops->set_child_genes(genes); + + /* set a timer interrupt */ + genetic->timer.expires = jiffies + genetic->child_life_time; + add_timer(&genetic->timer); + +} + +/* This natural selection routine will take the top + * natural_select_cutoff and use them to make children for the next + * generation and keep the top half perfomers + * + * This assumes natural_select_cutoff is exactly half of num_children + * and num_children is a multable of 4. + */ +static void genetic_ns_top_parents(genetic_t * genetic) +{ + unsigned long i,j,k = 0; + unsigned long num_children = genetic->num_children; + unsigned long cutoff = num_children - genetic->natural_selection_cutoff; + + for (i = cutoff, j = num_children - 1; i < j; i++, j--, k += 2) { + genetic->ops->combine_genes(genetic->child_ranking[i], + genetic->child_ranking[j], + genetic->child_ranking[k], + genetic->child_ranking[k+1]); + } +} + +static void genetic_ns_clone_top_parents(genetic_t * genetic) +{ + unsigned long i,j,k = 0; + unsigned long num_children = genetic->num_children; + unsigned long cutoff = num_children - genetic->natural_selection_cutoff; + + for (i = cutoff, j = num_children - 1; i < j; i++, j--, k += 2) { + genetic->ops->combine_genes(genetic->child_ranking[i], + genetic->child_ranking[j], + genetic->child_ranking[k], + genetic->child_ranking[k+1]); + } +} + +/* This natural selection routine just has top parents populating + bottom performers. */ +static void genetic_ns_award_top_parents(genetic_t * genetic) +{ + unsigned long i; + unsigned long num_children = genetic->num_children; + unsigned long cutoff = num_children - genetic->natural_selection_cutoff; + + for (i = 0; i < cutoff; i += 2) { + genetic->ops->combine_genes(genetic->child_ranking[num_children - 1], + genetic->child_ranking[num_children - 2], + genetic->child_ranking[i], + genetic->child_ranking[i+1]); + } +} + + +static inline void genetic_swap(genetic_child_t ** a, genetic_child_t ** b) +{ + genetic_child_t * tmp = *a; + + *a = *b; + *b = tmp; +} + +/* bubble sort */ +/* XXX change this to quick sort */ +static void genetic_split_performers(genetic_t * genetic) +{ + int i, j; + + for (i = genetic->num_children; i > 1; i--) + for (j = 0; j < i - 1; j++) + if (genetic->child_ranking[j]->fitness > genetic->child_ranking[j+1]->fitness) + genetic_swap(&genetic->child_ranking[j], &genetic->child_ranking[j+1]); +} + +static void genetic_mutate(genetic_t * genetic) +{ + long child_entry = -1; + int i; + + for (i = 0; i < genetic->num_mutations; i++) { + get_random_bytes(&child_entry, sizeof(child_entry)); + child_entry = child_entry % genetic->num_children; + + genetic->ops->mutate_child(genetic->child_ranking[child_entry]); + } +} + +static void genetic_calc_stats(genetic_t * genetic) +{ + long total_fitness = 0; + int i; + + /* calculate the avg fitness for this generation and avg fitness + * so far */ + for (i = 0; i < genetic->num_children; i++) + total_fitness += genetic->child_ranking[i]->fitness; + + genetic->last_gen_avg_fitness = total_fitness / (long)genetic->num_children; + + genetic->avg_fitness = ((genetic->avg_fitness * (long)(genetic->generation_number - 1)) + + genetic->last_gen_avg_fitness) / (long)genetic->generation_number; + + genetic->fitness_history[genetic->fitness_history_index++ & GENETIC_HISTORY_MASK] = + genetic->last_gen_avg_fitness; + +} + +void dump_children(genetic_t * genetic) +{ + int i, j; + long * genes; + for (i = 0; i < genetic->num_children; i++) { + printk(KERN_EMERG "%d: %-8ld:\t", i, genetic->child_ranking[i]->fitness); + + for (j = 0; j < genetic->child_ranking[i]->num_genes; j++) { + genes = (long *)genetic->child_ranking[i]->genes; + printk("%ld\t", genes[j]); + } + printk("\n"); + } + + printk("\n"); +} + +void genetic_new_generation(genetic_t * genetic) +{ + struct list_head * tmp; + +#if GENETIC_DEBUG + printk(KERN_EMERG "-------------------------\n"); + printk(KERN_EMERG "new generation performers: \n"); + dump_children(genetic); +#endif + + /* figure out top performers */ + genetic_split_performers(genetic); + +#if GENETIC_DEBUG + printk(KERN_EMERG "split performers: \n"); + dump_children(genetic); +#endif + + /* calc stats */ + genetic_calc_stats(genetic); + + /* make some new children */ + genetic->natural_selection(genetic); + +#if GENETIC_DEBUG + printk(KERN_EMERG "selected: \n"); + dump_children(genetic); +#endif + + /* mutate a couple of the next generation */ + genetic_mutate(genetic); + +#if GENETIC_DEBUG + printk(KERN_EMERG "mutated: \n"); + dump_children(genetic); +#endif + + /* Move the new children still sitting in the finished queue to + the run queue */ + tmp = genetic->run_queue; + genetic->run_queue = genetic->finished_queue; + genetic->finished_queue = tmp; + + genetic->child_number = 0; + genetic->generation_number++; + +} + +void genetic_generic_mutate_gene(genetic_child_t * child, long gene_num) +{ + unsigned long *genes = (unsigned long *)child->genes; + unsigned long min = child->gene_param[gene_num].min; + unsigned long max = child->gene_param[gene_num].max; + unsigned long gene_value; + unsigned long range = max - min + 1; + + /* create a mutation value */ + get_random_bytes(&gene_value, sizeof(gene_value)); + +#if 0 + /* XXX we shouldn't need this now that it's unsigned */ + if (gene_value < 0) + gene_value = -gene_value; +#endif + + gene_value = gene_value % range; + + genes[gene_num] = min + gene_value; +} + +/* This assumes that all genes are a unsigned long array of size + num_genes */ +void genetic_generic_mutate_child(genetic_child_t * child) +{ + long gene_num = -1; + + /* pick a random gene */ + get_random_bytes(&gene_num, sizeof(gene_num)); + + if (gene_num < 0) + gene_num = -gene_num; + + gene_num = gene_num % child->num_genes; + + if (child->gene_param[gene_num].mutate_gene) + child->gene_param[gene_num].mutate_gene(child, gene_num); + else + genetic_generic_mutate_gene(child, gene_num); +} + + +/* combine the genes by randomly take a portion of A's and B's to make + * C. Then flip that portion of B and A to make D */ +void genetic_generic_combine_genes(genetic_child_t * parent_a, + genetic_child_t * parent_b, + genetic_child_t * child_a, + genetic_child_t * child_b) +{ + unsigned long * genes_a = (unsigned long *)parent_a->genes; + unsigned long * genes_b = (unsigned long *)parent_b->genes; + unsigned long * genes_c = (unsigned long *)child_a->genes; + unsigned long * genes_d = (unsigned long *)child_b->genes; + /* Assume parent_a and parent_b have same num_genes */ + unsigned long num_genes = parent_a->num_genes; + int combine_point; + int i; + + get_random_bytes(&combine_point, sizeof(combine_point)); + + if (combine_point < 0) + combine_point = -combine_point; + + combine_point = combine_point % num_genes; + + for (i = combine_point; i < num_genes; i++) + genes_c[i] = genes_a[i]; + + for (i = 0; i < combine_point; i++) + genes_c[i] = genes_b[i]; + + for (i = combine_point; i < num_genes; i++) + genes_d[i] = genes_b[i]; + + for (i = 0; i < combine_point; i++) + genes_d[i] = genes_a[i]; +}