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 <linux/hash.h>
 #include <linux/rbtree.h>
 #include <linux/interrupt.h>
+#include <linux/genetic.h>
+#include <linux/random.h>
 
 #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 <linux/slab.h>
 #include <linux/swap.h>
 #include <linux/writeback.h>
+#include <linux/genetic.h>
 
 /*
  * 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 <linux/jiffies.h>
 #include <linux/sysrq.h>
 #include <linux/vmalloc.h>
+#include <linux/genetic.h>
 #include <linux/crash_dump.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -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 <moilanen@austin.ibm.com>
+ * 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 <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+
+#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 <moilanen@austin.ibm.com>
+ * 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 <linux/genetic.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/random.h>
+
+#include <asm/uaccess.h>
+#include <asm/string.h>
+#include <asm/bug.h>
+
+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];
+}
