genetic-lib: Genetic Library for Runtime Kernel Tuning The primary goal of the genetic library is to provide a framework for tuning various constants in the Kernel by evaluating the current workload and performance of the system. More information about the performance improvements and implementation of the library can be found in the 2005/2006 OLS papers: http://www.linuxsymposium.org/2005/linuxsymposium_procv1.pdf pg 335 http://www.linuxsymposium.org/2006/linuxsymposium_procv2.pdf pg 173 Signed-off-by: Jake Moilanen Signed-off-by: Brandon Philips --- include/linux/fingerprinting.h | 125 ++++ include/linux/genetic.h | 343 +++++++++++ lib/Kconfig | 7 lib/Makefile | 1 lib/fingerprinting.c | 276 +++++++++ lib/genetic.c | 1183 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 1935 insertions(+) Index: linux-rc/lib/Kconfig =================================================================== --- linux-rc.orig/lib/Kconfig +++ linux-rc/lib/Kconfig @@ -38,6 +38,13 @@ config LIBCRC32C require M here. See Castagnoli93. Module will be libcrc32c. +config GENETIC_LIB + bool "Genetic Library" + default y + 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 # Index: linux-rc/lib/Makefile =================================================================== --- linux-rc.orig/lib/Makefile +++ linux-rc/lib/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o obj-$(CONFIG_CRC16) += crc16.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_GENERIC_ALLOCATOR) += genalloc.o Index: linux-rc/lib/genetic.c =================================================================== --- /dev/null +++ linux-rc/lib/genetic.c @@ -0,0 +1,1183 @@ +/* + * Genetic Algorithm Library + * + * Jake Moilanen + * Brandon Philips + * Copyright (C) 2004-2006 IBM + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as published + * by the Free Software Foundation. + */ + +/* + * 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 + */ + +/* + * TODO: + * + * - Check to make sure DEF_DESKTOP_TIMESLICE is operating correctly + * - fix fixup_timeslice + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_FINGERPRINTING +#include +#include "fingerprinting.c" +#endif + +#define GENETIC_DEBUG_VERBOSE 1 + +char genetic_lib_version[] = "0.3.1"; + +int mutation_rate_change = GENETIC_DEFAULT_MUTATION_RATE_CHANGE; +int genetic_lib_enabled = 1; + +decl_subsys(genetic, NULL, NULL); + +void dump_children(phenotype_t * pt); +static void genetic_ns_top_parents(phenotype_t *); +static void genetic_ns_award_top_parents(phenotype_t *); +static int genetic_create_children(phenotype_t *); +static void genetic_split_performers(phenotype_t *); +static void genetic_mutate(phenotype_t *); +static void genetic_run_child(genetic_t * genetic); +static void genetic_new_generation(genetic_t * genetic); + +void genetic_switch_child(unsigned long data); + + +#define GENETIC_ATTR(_name, _mode, _show, _store) \ +struct genetic_attribute genetic_attr_##_name = { \ + .attr = {.name = __stringify(_name) , .mode = _mode }, \ + .show = _show, \ + .store = _store, \ +}; + +#define GENETIC_SHOW(_name, format_string) \ +static ssize_t g_show_##_name(struct genetic_s *g, char *buf) \ +{ \ + return sprintf(buf, format_string, g->_name); \ +} + +GENETIC_SHOW(child_number, "%lu\n"); +GENETIC_ATTR(child_number, S_IRUGO, g_show_child_number, NULL); + +GENETIC_SHOW(child_life_time, "%lu\n"); +GENETIC_ATTR(child_life_time, S_IRUGO, g_show_child_life_time, NULL); + +GENETIC_SHOW(num_children, "%lu\n"); +GENETIC_ATTR(num_children, S_IRUGO, g_show_num_children, NULL); + +GENETIC_SHOW(generation_number, "%lu\n"); +GENETIC_ATTR(generation_number, S_IRUGO, g_show_generation_number, NULL); + +GENETIC_SHOW(enabled, "%i\n"); +static ssize_t g_store_enabled (struct genetic_s *g, const char *buf, + size_t count) +{ + ssize_t consumed = -EINVAL; + + if ((count > 0) && (*buf == '0' || *buf == '1')) { + g->enabled = *buf == '1' ? 1 : 0; + consumed = count; + } + return consumed; +} +GENETIC_ATTR(enabled, 0644, g_show_enabled, g_store_enabled); + + +#ifdef CONFIG_FINGERPRINTING +static int show_fingerprinting(struct genetic_s *g, char *buf) +{ + return sprintf(buf, "%d\n", g->fingerprinting); +} + +GENETIC_ATTR(fingerprinting, S_IRUGO, show_fingerprinting, NULL); +#endif + +static struct attribute * genetic_attrs[] = { + &genetic_attr_child_number.attr, + &genetic_attr_child_life_time.attr, + &genetic_attr_num_children.attr, + &genetic_attr_generation_number.attr, + &genetic_attr_enabled.attr, +#ifdef CONFIG_FINGERPRINTING + &genetic_attr_fingerprinting.attr, +#endif + NULL +}; + +static ssize_t +genetic_attr_store(struct kobject * kobj, struct attribute * attr, + const char * buf, size_t count) +{ + struct genetic_attribute * g_attr = to_genetic_attr(attr); + struct genetic_s * g = to_genetic(kobj); + ssize_t ret = -EIO; + + if (g_attr->store) + ret = g_attr->store(g, buf, count); + return ret; +} + +static ssize_t genetic_attr_show(struct kobject *kobj, + struct attribute *attr, char *page) +{ + struct genetic_s *g = (struct genetic_s *)to_genetic(kobj); + struct genetic_attribute *g_attr = to_genetic_attr(attr); + ssize_t ret = -EIO; + + if (g_attr->show) { + ret = g_attr->show(g, page); + } + + return ret; +} + +static struct sysfs_ops genetic_sysfs_ops = { + .show = &genetic_attr_show, + .store = &genetic_attr_store, +}; + +/* TODO: free all phenotypes, etc */ +static void genetic_release(struct kobject *kobj) +{ + struct genetic_s *g = to_genetic(kobj); + kfree(g); +} + +static struct kobj_type genetic_ktype = { + .release = &genetic_release, + .sysfs_ops = &genetic_sysfs_ops, + .default_attrs = genetic_attrs, +}; + +static ssize_t +pt_attr_store(struct kobject *, struct attribute *, const char *, size_t); +static ssize_t pt_attr_show(struct kobject *, struct attribute *, char *); + +static ssize_t +pt_attr_store(struct kobject * kobj, struct attribute * attr, + const char * buf, size_t count) +{ + struct phenotype_s *p = (struct phenotype_s *)to_phenotype(kobj); + struct phenotype_attribute *p_attr = to_phenotype_attr(attr); + ssize_t ret = -EIO; + + if (p_attr->store) + ret = p_attr->store(p, buf, count); + return ret; +} + +static ssize_t pt_attr_show(struct kobject *kobj, + struct attribute *attr, char *page) +{ + struct phenotype_s *p = (struct phenotype_s *)to_phenotype(kobj); + struct phenotype_attribute *p_attr = to_phenotype_attr(attr); + ssize_t ret = -EIO; + + if (p_attr->show) { + ret = p_attr->show(p, page); + } + + return ret; +} + +static struct sysfs_ops phenotype_sysfs_ops = { + .show = &pt_attr_show, + .store = &pt_attr_store, +}; + +/* TODO: free all phenotypes, etc */ +static void phenotype_release(struct kobject *kobj) +{ + struct genetic_s *g = to_genetic(kobj); + kfree(g); +} + +#define PHENOTYPE_ATTR(_name, _mode, _show, _store) \ +struct phenotype_attribute pt_attr_##_name = { \ + .attr = {.name = __stringify(_name) , .mode = _mode }, \ + .show = _show, \ + .store = _store, \ +}; + +#define PHENOTYPE_SHOW(_name, format_string) \ +static ssize_t p_show_##_name(struct phenotype_s *p, char *buf) \ +{\ + return sprintf(buf, format_string, p->_name);\ +} + +PHENOTYPE_SHOW(child_number, "%lu\n"); +PHENOTYPE_ATTR(child_number, S_IRUGO, p_show_child_number, NULL); + +PHENOTYPE_SHOW(num_children, "%lu\n"); +PHENOTYPE_ATTR(num_children, S_IRUGO, p_show_num_children, NULL); + +PHENOTYPE_SHOW(natural_selection_cutoff, "%lu\n"); +PHENOTYPE_ATTR(natural_selection_cutoff, S_IRUGO, + p_show_natural_selection_cutoff, NULL); + +PHENOTYPE_SHOW(num_mutations, "%lu\n"); +PHENOTYPE_ATTR(num_mutations, S_IRUGO, p_show_num_mutations, NULL); + +PHENOTYPE_SHOW(num_genes, "%lu\n"); +PHENOTYPE_ATTR(num_genes, S_IRUGO, p_show_num_genes, NULL); + +PHENOTYPE_SHOW(uid, "%lu\n"); +PHENOTYPE_ATTR(uid, S_IRUGO, p_show_uid, NULL); + +PHENOTYPE_SHOW(avg_fitness, "%lli\n"); +PHENOTYPE_ATTR(avg_fitness, S_IRUGO, p_show_avg_fitness, NULL); + +PHENOTYPE_SHOW(last_gen_avg_fitness, "%lli\n"); +PHENOTYPE_ATTR(last_gen_avg_fitness, S_IRUGO, p_show_last_gen_avg_fitness, NULL); + +PHENOTYPE_SHOW(from_top, "%lli\n"); +PHENOTYPE_ATTR(from_top, S_IRUGO, p_show_from_top, NULL); + +static struct attribute * phenotype_attrs[] = { + &pt_attr_child_number.attr, + &pt_attr_num_children.attr, + &pt_attr_natural_selection_cutoff.attr, + &pt_attr_num_mutations.attr, + &pt_attr_num_genes.attr, + &pt_attr_uid.attr, + &pt_attr_avg_fitness.attr, + &pt_attr_last_gen_avg_fitness.attr, + &pt_attr_from_top.attr, + NULL, +}; + +static struct kobj_type phenotype_ktype = { + .release = &phenotype_release, + .sysfs_ops = &phenotype_sysfs_ops, + .default_attrs = phenotype_attrs, +}; + +int genetic_init(genetic_t ** in_genetic, unsigned long num_children, + unsigned long child_life_time, int fingerprinting, + char * name) +{ + genetic_t * genetic; + + if (!genetic_lib_enabled) + return 0; + + printk(KERN_INFO "Initializing Genetic Library - version %s\n", + genetic_lib_version); + + genetic = (genetic_t *)kzalloc(sizeof(genetic_t), GFP_KERNEL); + if (!genetic) { + printk(KERN_ERR "genetic_init: not enough memory\n"); + return -ENOMEM; + } + + genetic->kobj.kset = &genetic_subsys.kset; + genetic->kobj.ktype = &genetic_ktype; + kobject_set_name(&genetic->kobj, name); + + kobject_register(&genetic->kobj); + if (!(kobject_get(&genetic->kobj))) + return -ENOENT; + + kobject_set_name(&genetic->phenotypes.kobj, "phenotypes"); + genetic->phenotypes.ktype = &phenotype_ktype; + genetic->phenotypes.kobj.parent = &genetic->kobj; + kset_register(&genetic->phenotypes); + + genetic->num_children = num_children; + genetic->child_life_time = child_life_time; + + genetic->generation_number = 1; + genetic->child_number = 0; + genetic->enabled = 1; +#ifdef CONFIG_FINGERPRINTING + genetic->fingerprinting = fingerprinting; +#endif + + /* Setup how long each child has to live */ + init_timer(&genetic->timer); + genetic->timer.function = genetic_switch_child; + genetic->timer.data = (unsigned long)genetic; + + *in_genetic = genetic; + + return 0; +} + +struct phenotype_s * genetic_register_phenotype(genetic_t * genetic, + struct genetic_ops * ops, unsigned long num_children, + char * name, unsigned long num_genes, unsigned long uid) +{ + phenotype_t * pt; + int rc; + + if (!genetic_lib_enabled) + return 0; + + printk(KERN_INFO "Initializing %s's phenotype %s\n", genetic->kobj.name, + name); + + pt = (phenotype_t *)kzalloc(sizeof(phenotype_t), GFP_KERNEL); + if (!genetic) { + printk(KERN_ERR "genetic_register_phenotype: not enough\ + memory\n"); + return NULL; + } + + pt->child_ranking = (genetic_child_t **)kmalloc(num_children * sizeof(genetic_child_t *), GFP_KERNEL); + if (!pt->child_ranking) { + printk(KERN_ERR "genetic_register_phenotype: not enough\ + memory\n"); + kfree(pt); + return NULL; + } + + pt->kobj.kset = kset_get(&genetic->phenotypes); + kobject_set_name(&pt->kobj, name); + kobject_register(&pt->kobj); + + kobject_set_name(&pt->genes.kobj, "genes"); + pt->genes.ktype = &gene_param_ktype; + pt->genes.kobj.parent = &pt->kobj; + kset_register(&pt->genes); + + if (!(kobject_get(&pt->kobj))) + return NULL; + + INIT_LIST_HEAD(&pt->children_queue[0]); + INIT_LIST_HEAD(&pt->children_queue[1]); + + pt->run_queue = &pt->children_queue[0]; + pt->finished_queue = &pt->children_queue[1]; + + pt->ops = ops; + pt->num_children = num_children; + + pt->mutation_rate = GENETIC_DEFAULT_MUTATION_RATE; + pt->natural_selection = genetic_ns_top_parents; + pt->natural_selection_cutoff = num_children / 2; + pt->avg_fitness = 0; + pt->last_gen_avg_fitness = 0; + pt->child_number = 0; + + pt->uid = uid; + pt->num_genes = num_genes; + + pt->top_fitness = 0; + +#ifdef CONFIG_FINGERPRINTING + if (genetic->fingerprinting) { + if ((rc = genetic_init_fingerprinting(pt)) < 0) + return NULL; + } +#endif + + /* Create some children */ + rc = genetic_create_children(pt); + if (rc < 0) + return NULL; + + return pt; +} + +#define GENE_PARAM_SHOW(_name, format_string) \ +static ssize_t gp_show_##_name(struct gene_obj *g, char *buf) \ +{\ + return sprintf(buf, format_string, g->gene_param->_name);\ +} + +GENE_PARAM_SHOW(min, "%lu\n"); +GENE_PARAM_ATTR(min, S_IRUGO, gp_show_min, NULL); + +GENE_PARAM_SHOW(max, "%lu\n"); +GENE_PARAM_ATTR(max, S_IRUGO, gp_show_max, NULL); + +GENE_PARAM_SHOW(initial, "%lu\n"); +GENE_PARAM_ATTR(initial, S_IRUGO, gp_show_initial, NULL); + +static struct attribute * gene_param_attrs[] = { + &gene_param_attr_min.attr, + &gene_param_attr_max.attr, + &gene_param_attr_initial.attr, + NULL +}; + +ssize_t gene_obj_attr_store(struct kobject * kobj, struct attribute * attr, + const char * buf, size_t count) +{ + struct gene_obj_attribute * g_attr = to_gene_param_attr(attr); + struct gene_obj * g = to_gene_obj(kobj); + ssize_t ret = -EIO; + + if (g_attr->store) + ret = g_attr->store(g, buf, count); + + return ret; +} + +ssize_t gene_obj_attr_show(struct kobject *kobj, + struct attribute *attr, char *page) +{ + struct gene_obj_attribute * g_attr = to_gene_param_attr(attr); + struct gene_obj * g = to_gene_obj(kobj); + ssize_t ret = -EIO; + + if (g_attr->show) + ret = g_attr->show(g, page); + + return ret; +} + +struct sysfs_ops gene_param_sysfs_ops = { + .show = &gene_obj_attr_show, + .store = &gene_obj_attr_store, +}; + +/* TODO: free all phenotypes, etc */ +void gene_param_release(struct kobject *kobj) +{ + struct genetic_s *g = to_genetic(kobj); + kfree(g); +} + +struct kobj_type gene_param_ktype = { + .release = &gene_param_release, + .sysfs_ops = &genetic_sysfs_ops, + .default_attrs = gene_param_attrs, +}; + +int genetic_gene_obj_create(struct gene_param_s * gp, genetic_t * g, + struct kset * kset) +{ + struct gene_obj * go = kzalloc(sizeof(struct gene_obj), GFP_KERNEL); + + go->gene_param = gp; + go->genetic = g; + go->kobj.kset = kset_get(kset); + kobject_set_name(&go->kobj, gp->name); + return kobject_register(&go->kobj); + + +} + +void genetic_start(genetic_t * genetic) +{ + if (!genetic_lib_enabled) + return; + + genetic_run_child(genetic); + printk(KERN_INFO "%ld children started in %s genetic library\n", + genetic->num_children, genetic->kobj.name); +} + +/* create some children, it is up to the lib user to come up w/ a good + distro of genes for it's children */ +static int genetic_create_children(phenotype_t * pt) +{ + unsigned long i; + genetic_child_t * child; + + for (i = 0; i < pt->num_children; i++) { + pt->child_ranking[i] = (genetic_child_t *)kmalloc( + sizeof(genetic_child_t), GFP_KERNEL); + + if (!pt->child_ranking[i]) { + printk(KERN_ERR "genetic_create_child: not enough\ + memory\n"); + + for (i = i - 1; i >= 0; i--) + kfree(pt->child_ranking[i]); + + return -ENOMEM; + } + + child = pt->child_ranking[i]; + + child->id = i; + + pt->ops->create_child(child); + + list_add_tail(&child->list, pt->run_queue); + } + + return 0; +} + +/* 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; + + struct list_head * p; + phenotype_t * pt; + + int new_generation = 0; + + list_for_each(p, &genetic->phenotypes.list) { + pt = to_phenotype(to_kobj(p)); + + child = list_entry(pt->run_queue->next, genetic_child_t, list); + + list_del(&child->list); + + list_add_tail(&child->list, pt->finished_queue); + + if (pt->ops->calc_fitness) + pt->ops->calc_fitness(child); + + pt->child_ranking[pt->child_number++] = child; + + /* See if need more children */ + if (list_empty(pt->run_queue)) + new_generation = 1; + + } + + genetic->child_number++; + + if (new_generation) + genetic_new_generation(genetic); + + genetic_run_child(genetic); + +} + +/* Set the childs genes for run */ +void genetic_run_child(genetic_t * genetic) +{ + struct list_head * p; + phenotype_t * pt; + + genetic_child_t * child; + void * genes; + + list_for_each(p, &genetic->phenotypes.list) { + pt = to_phenotype(to_kobj(p)); + + child = list_entry(pt->run_queue->next, genetic_child_t, list); + + genes = child->genes; + + /* not enabled every child goes to defaults */ + if (!genetic->enabled) + genetic_create_child_defaults(child); + + /* set the child genes if we are enabled */ + if (pt->ops->set_child_genes) + pt->ops->set_child_genes(genes); + + if (pt->ops->take_snapshot) + pt->ops->take_snapshot(pt); + + } + + /* 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(phenotype_t * pt) +{ + unsigned long i,j,k = 0; + unsigned long num_children = pt->num_children; + unsigned long cutoff = num_children - pt->natural_selection_cutoff; + + for (i = cutoff, j = num_children - 1; i < j; i++, j--, k += 2) { + /* create child A */ + pt->ops->combine_genes(pt->child_ranking[i], + pt->child_ranking[j], + pt->child_ranking[k]); + + /* create child B */ + pt->ops->combine_genes(pt->child_ranking[i], + pt->child_ranking[j], + pt->child_ranking[k+1]); + } +} + + +/* This natural selection routine just has top parents populating + bottom performers. */ +static void genetic_ns_award_top_parents(phenotype_t * pt) +{ + unsigned long i; + unsigned long num_children = pt->num_children; + unsigned long cutoff = num_children - pt->natural_selection_cutoff; + + for (i = 0; i < cutoff; i += 2) { + pt->ops->combine_genes(pt->child_ranking[num_children - 1], + pt->child_ranking[num_children - 2], + pt->child_ranking[i]); + + pt->ops->combine_genes(pt->child_ranking[num_children - 1], + pt->child_ranking[num_children - 2], + pt->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(phenotype_t * pt) +{ + int i, j; + + for (i = pt->num_children; i > 1; i--) + for (j = 0; j < i - 1; j++) + if (pt->child_ranking[j]->fitness > pt->child_ranking[j+1]->fitness) + genetic_swap(&pt->child_ranking[j], &pt->child_ranking[j+1]); +} + +static void genetic_mutate(phenotype_t * pt) +{ + long child_entry = -1; + int i; + + if (!pt->num_genes) + return; + + for (i = 0; i < pt->num_mutations; i++) { + get_random_bytes(&child_entry, sizeof(child_entry)); + child_entry = child_entry % pt->num_children; + + pt->ops->mutate_child(pt->child_ranking[child_entry]); + } +} + +/* XXX This will either aid in handling new workloads, or send us on a + downward spiral */ +static void genetic_shift_mutation_rate(phenotype_t * pt, long long prev_gen_avg_fitness, long long avg_fitness) +{ + + long long low_bound; + long long high_bound; + long dummy; + struct genetic_s *g; + + g = to_genetic(pt->kobj.parent); + + if (mutation_rate_change && g->generation_number > 1) { + + if (pt->ops->shift_mutation_rate) { + pt->ops->shift_mutation_rate(pt); + } else { + + low_bound = avg_fitness * 90; + divll(&low_bound, 100, &dummy); + + high_bound = avg_fitness * 110; + divll(&high_bound, 100, &dummy); + + if (high_bound > prev_gen_avg_fitness) + pt->mutation_rate -= mutation_rate_change; + else if (low_bound < prev_gen_avg_fitness) + pt->mutation_rate += mutation_rate_change; + + if (pt->mutation_rate > GENETIC_MAX_MUTATION_RATE) + pt->mutation_rate = GENETIC_MAX_MUTATION_RATE; + else if (pt->mutation_rate < GENETIC_MIN_MUTATION_RATE) + pt->mutation_rate = GENETIC_MIN_MUTATION_RATE; + } + } +} + +void genetic_general_shift_mutation_rate(phenotype_t * in_pt) +{ + struct list_head * p; + phenotype_t * pt; + int count = 0; + long rate = 0; + struct kobject * k = &in_pt->kobj; + + list_for_each(p, &k->kset->list) { + pt = to_phenotype(to_kobj(p)); + + if (in_pt->uid & pt->uid && in_pt->uid != pt->uid) { + rate += pt->mutation_rate; + count++; + } + } + + /* If we are a general phenotype that is made up of other + phenotypes then we take the average */ + if (count) + in_pt->mutation_rate = (rate / count); + else + in_pt->mutation_rate = mutation_rate_change; +} + + +static long long genetic_calc_stats_parent(phenotype_t * in_pt) +{ + struct list_head * p; + struct kobject * k = &in_pt->kobj; + phenotype_t * pt; + int i = 0; + long long total_fitness = 0; + long dummy; +#ifdef CONFIG_FINGERPRINTING + int fp = to_phenotype_genetic(in_pt)->fingerprinting; + int numerical_fp; +#endif + +#ifdef CONFIG_FINGERPRINTING + if (fp) + numerical_fp = create_fingerprint(in_pt->fp); + + /* do we want this???? */ + if ((fp && (in_pt->last_fingerprint == numerical_fp)) || !fp) { +#else + if (1) { +#endif + list_for_each(p, &k->kset->list) { + pt = to_phenotype(to_kobj(p)); + + /* for each child */ + if (in_pt->uid & pt->uid && in_pt->uid != pt->uid) { + if (pt->avg_fitness) { + /* measure how far percentage-wise that we are from the top */ + pt->from_top = (pt->last_gen_avg_fitness - pt->avg_fitness) * 100; + divll(&pt->from_top, (pt->avg_fitness > 0) ? pt->avg_fitness : -pt->avg_fitness, &dummy); + + total_fitness += pt->from_top; + } + } + + i++; + + } + + } else { + /* XXX horrible horrible hack...but + * testing viability */ + total_fitness = 0; + i = 1; + } + + BUG_ON(!i); + + in_pt->last_gen_avg_fitness = total_fitness; + divll(&in_pt->last_gen_avg_fitness, i, &dummy); + + return total_fitness; +} + + +static void genetic_calc_stats(phenotype_t * pt) +{ + struct genetic_s * g; + long long total_fitness = 0; + long long prev_gen_avg_fitness = pt->last_gen_avg_fitness; + long long tmp_fitness; + long dummy; + int i = 0; + + /* On a general phenotype, need to look at other metrics since + * the fitness is normalized. It always average the same. It + * assumes that this phenotype is registered last. + */ + if (pt->ops->calc_post_fitness) { + total_fitness = genetic_calc_stats_parent(pt); + } else { + /* calculate the avg fitness for this generation and avg fitness + * so far */ + for (i = 0; i < pt->num_children; i++) + total_fitness += pt->child_ranking[i]->fitness; + + tmp_fitness = total_fitness >> long_log2(pt->num_children); + pt->last_gen_avg_fitness = tmp_fitness; + } + + /* Mutation rate calibration */ + genetic_shift_mutation_rate(pt, prev_gen_avg_fitness, + pt->last_gen_avg_fitness); + + pt->num_mutations = ((pt->num_children * pt->num_genes) * pt->mutation_rate) / 100; + + /* calc new avg fitness */ + tmp_fitness = pt->last_gen_avg_fitness - pt->avg_fitness; + g = to_phenotype_genetic(pt); + divll(&tmp_fitness, g->generation_number, &dummy); + pt->avg_fitness += tmp_fitness; + + pt->fitness_history[pt->fitness_history_index++ & GENETIC_HISTORY_MASK] + = pt->last_gen_avg_fitness; +} + + + + +void genetic_new_generation(genetic_t * genetic) +{ + struct list_head * tmp; + + struct list_head * p; + phenotype_t * pt; + + list_for_each(p, &genetic->phenotypes.list) { + pt = to_phenotype(to_kobj(p)); + + /* Check to see if need to recalibrate fitness to take + other phenotypes' rankings into account. This + should be ran after all phenotypes that have input + have been ran. */ + if (pt->ops->calc_post_fitness) + pt->ops->calc_post_fitness(pt); + + dump_children(pt); + + /* figure out top performers */ + genetic_split_performers(pt); + + /* calc stats */ + genetic_calc_stats(pt); + + dump_children(pt); + + /* make some new children */ + if (pt->num_genes) + pt->natural_selection(pt); + + dump_children(pt); + +#ifdef CONFIG_FINGERPRINTING + if (pt->ops->get_fingerprint) { + + pt->ops->get_fingerprint(pt); + reset_fp_snapshot(pt->fp_ss); + + /* See if this generation was a top performer + * for the current workload. + * Do this after natural selection to get rid + * of the bad apples + */ + update_top_performers(pt); + + /* We know the workload, lets put some known + good genes back in */ + reintroduce_genes(pt); + + pt->last_fingerprint = create_fingerprint(pt->fp); + } + + dump_children(pt); +#endif + + /* mutate a couple of the next generation */ + genetic_mutate(pt); + + dump_children(pt); + + /* Move the new children still sitting in the finished queue to + the run queue */ + tmp = pt->run_queue; + pt->run_queue = pt->finished_queue; + pt->finished_queue = tmp; + + pt->child_number = 0; +#if GENETIC_DEBUG + pt->debug_index = 0; +#endif + + } + + genetic->child_number = 0; + genetic->generation_number++; +} + +/** + * genetic_generic_random_mutate_gene - mutate child's gene to value in range + * @child: child whose gene we are mutating + * @gene_num: gene index from gene_param to mutate; gene must be unsigned long + * + * Mutate a gene picking a random value within the gene range that was + * specified in @child->gene_param. + */ +void genetic_generic_random_mutate_gene(genetic_child_t * child, + unsigned 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)); + + gene_value = gene_value % range; + + genes[gene_num] = min + gene_value; +} + +/** + * genetic_generic_iterative_mutate_gene + * @child: child whose gene we are mutating + * @gene_num: gene index from gene_param to mutate; gene must be unsigned long + */ +void genetic_generic_iterative_mutate_gene(genetic_child_t * child, + unsigned 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; + long change; + unsigned long old_value = genes[gene_num]; + unsigned long new_value; + unsigned long range = max - min + 1; + + /* If under 5, random might work better */ + if (range < 5) + return genetic_generic_random_mutate_gene(child, gene_num); + + /* get the % of change */ + get_random_bytes(&change, sizeof(change)); + + change = change % GENETIC_ITERATIVE_MUTATION_RANGE; + + new_value = ((long)(change * range) / (long)100) + old_value; + + if (new_value > max) + new_value = max; + else if (new_value < min) + new_value = min; + + genes[gene_num] = new_value; +} + +/** + * genetic_generic_mutate_child - mutate random gene in child + * @child: child whose gene we are mutating. + * + * Select a random gene and mutate it either using either the mutate_gene + * callback specified in '&struct gene_param' OR if that is NULL then use + * 'genetic_generic_random_mutate_gene()' + */ +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_random_mutate_gene(child, gene_num); +} + +/** + * genetic_generic_mutate_child - set all genes to their initial value + */ +void genetic_create_child_defaults(genetic_child_t * child) +{ + int i; + unsigned long * genes = child->genes; + + for (i = 0; i < child->num_genes; i++) { + genes[i] = child->gene_param[i].initial; + } +} + +void genetic_create_child_spread(genetic_child_t * child, + unsigned long num_children) +{ + int i; + unsigned long range; + int range_incr; + int child_num = child->id; + long num_genes = child->num_genes; + unsigned long * genes = child->genes; + + for (i = 0; i < num_genes; i++) { + range = child->gene_param[i].max - child->gene_param[i].min + 1; + range_incr = range / 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 / (num_children / range)); + } + +} + +#if 0 +/* Randomly pick which parent to use for each gene to create a child */ +void genetic_generic_combine_genes(genetic_child_t * parent_a, + genetic_child_t * parent_b, + genetic_child_t * child) +{ + unsigned long * genes_a = (unsigned long *)parent_a->genes; + unsigned long * genes_b = (unsigned long *)parent_b->genes; + unsigned long * child_genes = (unsigned long *)child->genes; + + /* Assume parent_a and parent_b have same num_genes */ + unsigned long num_genes = parent_a->num_genes; + int parent_selector; + int i; + + get_random_bytes(&parent_selector, sizeof(parent_selector)); + + if ((sizeof(parent_selector) * 8) < num_genes) + BUG(); + + for (i = 0; i < num_genes; i++) { + /* Look at each bit to determine which parent to use */ + if (parent_selector & 1) { + child_genes[i] = genes_a[i]; + } else { + child_genes[i] = genes_b[i]; + } + parent_selector >>= 1; + } +} +#else + +/** + * genetic_generic_combine_genes - create child using comb. of parent's genes + * @parent_a: gene doner + * @parent_b: gene doner + * @child: genes will be modified using a combination of a and b + */ +void genetic_generic_combine_genes(genetic_child_t * parent_a, + genetic_child_t * parent_b, + genetic_child_t * child) +{ + unsigned long * genes_a = (unsigned long *)parent_a->genes; + unsigned long * genes_b = (unsigned long *)parent_b->genes; + unsigned long * child_genes = (unsigned long *)child->genes; + + /* Assume parent_a and parent_b have same num_genes */ + unsigned long num_genes = parent_a->num_genes; + int percentage; + int i; + + for (i = 0; i < num_genes; i++) { + get_random_bytes(&percentage, sizeof(percentage)); + + /* Get percentage */ + percentage = percentage % 100; + + if (percentage < 0) + percentage = -percentage; + + /* Give child x% of parent A's genes value, plus + 100-x% of parent B's genes value */ + child_genes[i] = (((genes_a[i]+1) * percentage) + + (genes_b[i] * (100 - percentage))) / 100; + } +} +#endif + +#if GENETIC_DEBUG +/* Stores attributes into an array in the following format + * child_num fitness gene[0] gene[1] .... gene[num_genes-1] + * Add +1 to GENETIC_NUM_DEBUG_POINTS if add another dump_children + * call + */ +void dump_children(phenotype_t * pt) +{ + int i, j; + long * genes; + unsigned long debug_size = pt->debug_size; + + for (i = 0; i < pt->num_children; i++) { + pt->debug_history[pt->debug_index++ % debug_size] = pt->child_ranking[i]->id; + pt->debug_history[pt->debug_index++ % debug_size] = pt->child_ranking[i]->fitness; + + genes = (long *)pt->child_ranking[i]->genes; + + for (j = 0; j < pt->child_ranking[i]->num_genes; j++) { + pt->debug_history[pt->debug_index++ % debug_size] = genes[j]; + } + } +} +#else +void dump_children(phenotype_t * pt) {} +#endif /* GENETIC_DEBUG */ + +static int __init genetic_lib_init(void) +{ + int retval; + + kset_set_kset_s(&genetic_subsys, kernel_subsys); + + retval = subsystem_register(&genetic_subsys); + + return retval; +} +core_initcall(genetic_lib_init); + +static int __init genetic_boot_setup(char *str) +{ + if (strcmp(str, "on") == 0) + genetic_lib_enabled = 1; + else if (strcmp(str, "off") == 0) + genetic_lib_enabled = 0; + + return 1; +} + + +static int __init genetic_mutation_rate_change_setup(char *str) +{ + int i; + + if (get_option(&str,&i)) { + + if (i > GENETIC_MAX_MUTATION_RATE) + i = GENETIC_MAX_MUTATION_RATE; + else if (i < 0) + i = 0; + + mutation_rate_change = i; + } + + return 1; + +} +__setup("genetic=", genetic_boot_setup); +__setup("genetic_mutate_rate=", genetic_mutation_rate_change_setup); Index: linux-rc/lib/fingerprinting.c =================================================================== --- /dev/null +++ linux-rc/lib/fingerprinting.c @@ -0,0 +1,276 @@ +static int create_fingerprint(struct fingerprint * fp) +{ + int numerical_fp = 0; + + numerical_fp |= fp->type; + numerical_fp <<= 1; + + numerical_fp |= fp->pattern; + numerical_fp <<= 1; + + numerical_fp |= fp->size; + + return numerical_fp; +} + +static long long get_top_fitness(phenotype_t * pt, struct fingerprint * fp) +{ + return pt->top_fitness[fp->type][fp->pattern][fp->size]; +} + + +static int top_fitness_open(struct inode *inode, struct file *file) +{ + phenotype_t * pt = (phenotype_t *)inode->u.generic_ip; + + return single_open(file, pt->ops->top_fitness_show, inode->u.generic_ip); +} + +static struct file_operations top_fitness_ops = { + .open = top_fitness_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int snapshot_open(struct inode *inode, struct file *file) +{ + phenotype_t * pt = (phenotype_t *)inode->u.generic_ip; + + return single_open(file, pt->ops->snapshot_show, inode->u.generic_ip); +} + +static struct file_operations snapshot_ops = { + .open = snapshot_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int state_open(struct inode *inode, struct file *file) +{ + phenotype_t * pt = (phenotype_t *)inode->u.generic_ip; + + return single_open(file, pt->ops->state_show, inode->u.generic_ip); +} + +static struct file_operations state_ops = { + .open = state_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + + +int genetic_init_fingerprinting(phenotype_t * pt) +{ + int i, j, k; + struct genetic_ops * ops = pt->ops; + int num_genes = pt->num_genes; + + if (num_genes) { + + pt->fp = (struct fingerprint *)kmalloc( + sizeof(struct fingerprint), GFP_KERNEL); + + if (!pt->fp) { + printk(KERN_ERR "genetic_register_phenotype: not enough" + "memory\n"); + return -ENOMEM; + } + + reset_fp(pt->fp); + + pt->fp_ss = (struct fp_snapshot *)kmalloc( + sizeof(struct fp_snapshot), GFP_KERNEL); + + if (!pt->fp_ss) { + printk(KERN_ERR "genetic_register_phenotype: not enough" + "memory\n"); + return -ENOMEM; + } + + reset_fp_snapshot(pt->fp_ss); + + pt->top_child = (unsigned long ***)kmalloc( + sizeof(unsigned long ***) * 2, GFP_KERNEL); + + if (!pt->top_child) { + printk(KERN_ERR "genetic_register_phenotype: not enough" + "memory\n"); + return -ENOMEM; + } + + for (i = 0; i < 2; i++) { + pt->top_child[i] = (unsigned long **)kmalloc( + sizeof(unsigned long **) * 2, + GFP_KERNEL); + + if (!pt->top_child[i]) { + printk(KERN_ERR "genetic_register_phenotype:\ + not enough memory\n"); + return -ENOMEM; + } + + for (j = 0; j < 2; j++) { + pt->top_child[i][j] = (unsigned long *)kmalloc( + sizeof(unsigned long *) * 2, + GFP_KERNEL); + + if (!pt->top_child[i][j]) { + printk(KERN_ERR "genetic_register_phenotype: not enough memory\n"); + return -ENOMEM; + } + + for (k = 0; k < 2; k++) { + pt->top_child[i][j][k] = (unsigned long)ops->create_top_genes(pt); + if (!pt->top_child[i][j][k]) + return -ENOMEM; + } + } + } + } /* if (num_genes) */ + + pt->top_fitness = (long long ***)kmalloc(sizeof(long long ***) * 2, GFP_KERNEL); + if (!pt->top_fitness) { + printk(KERN_ERR "genetic_register_phenotype: not enough" + "memory\n"); + return -ENOMEM; + } + + for (i = 0; i < 2; i++) { + pt->top_fitness[i] = (long long **)kmalloc(sizeof(long long **) * 2, GFP_KERNEL); + if (!pt->top_fitness[i]) { + printk(KERN_ERR "genetic_register_phenotype: not" + "enough memory\n"); + return -ENOMEM; + } + + for (j = 0; j < 2; j++) { + pt->top_fitness[i][j] = (long long *)kmalloc( + sizeof(long long *) * 2, + GFP_KERNEL); + + if (!pt->top_fitness[i][j]) { + printk(KERN_ERR "genetic_register_phenotype: " + "not enough memory\n"); + return -ENOMEM; + } + + for (k = 0; k < 2; k++) { + pt->top_fitness[i][j][k] = 0; + } + } + } + + pt->last_fingerprint = 0; + + return 0; +} + +static void decay_fitness(phenotype_t * pt, struct fingerprint * fp) +{ + long long fitness; + long dummy; + + fitness = get_top_fitness(pt, fp); + + /* reduce the fitness to eventually get new genes in */ + fitness *= FP_DECAY; + divll(&fitness, 100, &dummy); + + pt->top_fitness[fp->type][fp->pattern][fp->size] = fitness; +} + +static void update_phenotype_top_performer(phenotype_t * pt, struct fingerprint * fp) +{ + long long top_fitness; + unsigned long * genes; + long long * avg_genes; + long dummy; + int i, j; + + + /* Decay the top fitness so not to have a fluke and have a + * high set which are less than optimal. So decay the top + * fitness so eventually these genes are phased out. + */ + decay_fitness(pt, fp); + + top_fitness = get_top_fitness(pt, fp); + + if (pt->last_gen_avg_fitness >= top_fitness) { + + pt->top_fitness[fp->type][fp->pattern][fp->size] = pt->last_gen_avg_fitness; + + /* We don't need to track this if there's no genes! */ + if (!pt->num_genes) + return; + + avg_genes = (long long *)kmalloc(sizeof(long long) * pt->num_genes, GFP_KERNEL); + if (!avg_genes) { + printk(KERN_ERR "update_top_performers: unable to alloc space\n"); + return; + } + + memset(avg_genes, 0, sizeof(long long) * pt->num_genes); + + for (i = 0; i < pt->num_genes; i++) { + for (j = 0; j < pt->num_children; j++) { + genes = pt->child_ranking[j]->genes; + avg_genes[i] += genes[i]; + } + } + + for (j = 0; j < pt->num_genes; j++) + divll(&avg_genes[j], pt->num_children, &dummy); + + genes = (unsigned long *)pt->top_child[fp->type][fp->pattern][fp->size]; + for (j = 0; j < pt->num_genes; j++) + genes[j] = avg_genes[j]; + + kfree(avg_genes); + } +} + +static void update_top_performers(phenotype_t * master) +{ + phenotype_t * pt; + struct list_head * entry; + struct kobject * k = &master->kobj; + + list_for_each(entry, &k->kset->list) { + pt = to_phenotype(to_kobj(entry)); + + if (master->uid & pt->uid && master->uid != pt->uid) { + update_phenotype_top_performer(pt, master->fp); + } + } + update_phenotype_top_performer(master, master->fp); +} + +static void reintroduce_genes(phenotype_t * master) +{ + struct fingerprint * fp = master->fp; + phenotype_t * pt; + unsigned long * top_genes; + unsigned long * genes; + struct list_head * entry; + int i; + struct kobject * k = &master->kobj; + + list_for_each(entry, &k->kset->list) { + pt = to_phenotype(to_kobj(entry)); + + if (pt->num_genes) { + + /* Do this more intelligently, so can have n-points on + the fingerprint */ + /* just take the first one */ + top_genes = (unsigned long *)pt->top_child[fp->type][fp->pattern][fp->size]; + genes = pt->child_ranking[0]->genes; + for (i = 0; i < pt->num_children; i++) + genes[i] = top_genes[i]; + } + } +} Index: linux-rc/include/linux/fingerprinting.h =================================================================== --- /dev/null +++ linux-rc/include/linux/fingerprinting.h @@ -0,0 +1,125 @@ +#ifndef __LINUX_FINGERPRINTING_H +#define __LINUX_FINGERPRINTING_H + +/* + * include/linux/fingerprinting.h + * + * Jake Moilanen + * Copyright (C) 2006 IBM + * + * I/O Workload Fingerprinting + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as published + * by the Free Software Foundation. +*/ + +#include +#include + +#define FP_TYPE_READ 0 +#define FP_TYPE_WRITE 1 +#define FP_PATTERN_SEQ 0 +#define FP_PATTERN_RAND 1 +#define FP_SIZE_SMALL 0 +#define FP_SIZE_LARGE 1 +#define FP_NUM_POINTS (2 * 2 * 2) + +struct fingerprint { + __u8 type; + __u8 pattern; + __u8 size; +}; + +struct fp_snapshot { + /* type */ + unsigned long reads; + unsigned long writes; + /* pattern */ + unsigned long head_pos; + unsigned long avg_dist; + /* size */ + unsigned long avg_size; +}; + +/* Number of reads/writes before classified as read */ +#define FP_CLASS_READ_WRITE_RATIO 2 + +/* Number of sectors before pattern is random */ +#define FP_CLASS_PATTERN_RAND 25 + +/* Number of sectors before size is large */ +#define FP_CLASS_SIZE_LARGE 8 + +extern void update_fp_snapshot(struct bio * bio); +extern void calc_fp(struct fingerprint * fp, struct fp_snapshot * fp_ss); +extern void reset_fp_snapshot(struct fp_snapshot * ss); +extern void reset_fp(struct fingerprint * fp); +extern void consolidate_fp_snapshot(struct fp_snapshot * master, struct fp_snapshot * instance); +extern int fingerprint_state_show(struct seq_file *s, void *unused); +extern int fingerprint_snapshot_show(struct seq_file *s, void *unused); +extern int fingerprint_top_fitness_show(struct seq_file *s, void *unused); + +/* XXX do this more intelligently */ +#ifndef DIVLL_OP +#define DIVLL_OP +#if BITS_PER_LONG >= 64 + +static inline void divll(long long *n, long div, long *rem) +{ + *rem = *n % div; + *n /= div; +} + +#else + +static inline void divl(int32_t high, int32_t low, + int32_t div, + int32_t *q, int32_t *r) +{ + int64_t n = (u_int64_t)high << 32 | low; + int64_t d = (u_int64_t)div << 31; + int32_t q1 = 0; + int c = 32; + while (n > 0xffffffff) { + q1 <<= 1; + if (n >= d) { + n -= d; + q1 |= 1; + } + d >>= 1; + c--; + } + q1 <<= c; + if (n) { + low = n; + *q = q1 | (low / div); + *r = low % div; + } else { + *r = 0; + *q = q1; + } + return; +} + +static inline void divll(long long *n, long div, long *rem) +{ + int32_t low, high; + low = *n & 0xffffffff; + high = *n >> 32; + if (high) { + int32_t high1 = high % div; + int32_t low1 = low; + high /= div; + divl(high1, low1, div, &low, (int32_t *)rem); + *n = (int64_t)high << 32 | low; + } else { + *n = low / div; + *rem = low % div; + } +} +#endif + +#endif /* #ifndef divll */ + +#endif /* __LINUX_FINGERPRINTINT_H */ Index: linux-rc/include/linux/genetic.h =================================================================== --- /dev/null +++ linux-rc/include/linux/genetic.h @@ -0,0 +1,343 @@ +#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 version 2 of the GNU General Public License as published + * by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#define GENETIC_HISTORY_SIZE 0x8 +#define GENETIC_HISTORY_MASK (GENETIC_HISTORY_SIZE - 1) + +/* percentage of total number genes to mutate */ +#define GENETIC_DEFAULT_MUTATION_RATE 15 + +/* XXX TODO Make this an adjustable runtime variable */ +/* Percentage that an iteration can jump within the range */ +#define GENETIC_ITERATIVE_MUTATION_RANGE 20 + +/* the rate that GENETIC_DEFAULT_MUTATION_RATE itself can change */ +#define GENETIC_DEFAULT_MUTATION_RATE_CHANGE 4 +#define GENETIC_MAX_MUTATION_RATE 45 +#define GENETIC_MIN_MUTATION_RATE 10 + +#define GENETIC_DEBUG 0 + +#ifdef CONFIG_FINGERPRINTING +#define FP_DECAY 90 +#define GENETIC_NUM_DEBUG_POINTS 5 +#else +#define GENETIC_NUM_DEBUG_POINTS 4 +#endif + +#define GENETIC_PRINT_DEBUG 0 +#define gen_dbg(format, arg...) do { if (GENETIC_PRINT_DEBUG) printk(KERN_EMERG __FILE__ ": " format "\n" , ## arg); } while (0) +#define gen_trc(format, arg...) do { if (GENETIC_PRINT_DEBUG) printk(KERN_EMERG __FILE__ ":%s:%d\n" , __FUNCTION__, __LINE__); } while (0) + +#define to_kobj(_entry) (struct kobject *)container_of(_entry, struct kobject, entry) + +struct gene_param_s; +struct genetic_s; +struct phenotype_s; + +struct genetic_child_s { + struct list_head list; + long long fitness; + unsigned long num_genes; + void *genes; + struct gene_param_s *gene_param; + void *stats_snapshot; + int id; +}; + +typedef struct genetic_child_s genetic_child_t; + +#define to_gene_obj(obj) container_of(obj, struct gene_obj, kobj) +#define to_gene_param_attr(_attr) container_of(_attr, struct gene_obj_attribute, attr) + +struct gene_obj { + struct kobject kobj; + struct genetic_s *genetic; + struct gene_param_s *gene_param; +}; + + +struct gene_obj_attribute { + struct attribute attr; + ssize_t (*show)(struct gene_obj *, char *); + ssize_t (*store)(struct gene_obj *, const char *, size_t); +}; + +/* Here's a generic idea of what it the genes could look like */ +struct gene_param_s { + char * name; + 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; + +#define GENE_PARAM_ATTR(_name, _mode, _show, _store) \ +struct gene_obj_attribute gene_param_attr_##_name = { \ + .attr = {.name = __stringify(_name) , .mode = _mode }, \ + .show = _show, \ + .store = _store, \ +}; + +extern struct kobj_type gene_param_ktype; + +#define to_phenotype_genetic(pt) (to_genetic(to_kset(pt->kobj.parent)->kobj.parent)) +#define to_phenotype(obj) container_of(obj, struct phenotype_s, kobj) +#define to_phenotype_attr(_attr) container_of(_attr, struct phenotype_attribute, attr) + +struct phenotype_attribute { + struct attribute attr; + ssize_t (*show)(struct phenotype_s *, char *); + ssize_t (*store)(struct phenotype_s *, const char *, size_t); +}; + +struct phenotype_s { + struct kobject kobj; + + struct list_head children_queue[2]; + struct list_head *run_queue; + struct list_head *finished_queue; + + struct genetic_ops *ops; + + unsigned long num_children; /* Must be power of 2 */ + unsigned long natural_selection_cutoff; /* How many children + * will survive + */ + void *stats_snapshot; + unsigned long child_number; + + struct kset genes; + + /* percentage of total number of genes to mutate */ + long mutation_rate; + unsigned long num_mutations; + unsigned long num_genes; + + genetic_child_t **child_ranking; + + void (*natural_selection)(struct phenotype_s *); + + /* This UID is bitmap comprised of other phenotypes that contribute + to the genes */ + unsigned long uid; + + /* performance metrics */ + long long avg_fitness; + long long last_gen_avg_fitness; + + unsigned long fitness_history_index; + long long fitness_history[GENETIC_HISTORY_SIZE]; + +#if GENETIC_DEBUG + unsigned long debug_size; /* number of longs in + debug history */ + unsigned long debug_index; + long long *debug_history; +#endif +#ifdef CONFIG_FINGERPRINTING + struct dentry *fp_dir; + struct fingerprint *fp; + struct fp_snapshot *fp_ss; + unsigned long ***top_child; + long long ***top_fitness; + int last_fingerprint; +#else + long long top_fitness; +#endif + + long long from_top; + +}; + +typedef struct phenotype_s phenotype_t; + +/** + * struct genetic_s - contains all data structures for a genetic plugin + * @name: string that will identify this genetic alg. in debugfs and printk + * @phenotype: list of all registered phenotypes + * @child_number: the running child index (< @num_children) + * @child_life_time: time in ms each child is ran before being swapped + * @num_children: number of children in each generation (must be a power of 2) + * @generation_number: increased once every child in a generation is ran + * @defaults: when 1 the genetic library will hold all genes at defaults + * @fingerprinting: when 1 the genetic library wil use gene fingerprinting if CONFIG_FINGERPRINTING + */ +struct genetic_s { + struct kobject kobj; + + struct kset phenotypes; + + struct timer_list timer; + + unsigned long child_number; + unsigned long child_life_time; + unsigned long num_children; + + unsigned long generation_number; + int enabled; + + /* private */ +#ifdef CONFIG_FINGERPRINTING + int fingerprinting; +#endif +}; + +struct genetic_attribute { + struct attribute attr; + ssize_t (*show)(struct genetic_s *, char *); + ssize_t (*store)(struct genetic_s *, const char *, size_t); +}; + +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 *); + void (*mutate_child)(genetic_child_t *); + void (*calc_post_fitness)(phenotype_t *); /* Fitness routine used when + * need to take into account + * other phenotype fitness + * results after they ran + */ + void (*take_snapshot)(phenotype_t *); + void (*shift_mutation_rate)(phenotype_t *); + int (*gene_show)(struct seq_file *, void *); +#ifdef CONFIG_FINGERPRINTING + void (*get_fingerprint)(phenotype_t *); + void (*update_fingerprint)(phenotype_t *); + void * (*create_top_genes)(phenotype_t *); + int (*top_fitness_show)(struct seq_file *, void *); + int (*snapshot_show)(struct seq_file *, void *); + int (*state_show)(struct seq_file *, void *); +#endif +}; + +int genetic_gene_obj_create(struct gene_param_s *, genetic_t *, struct kset *); + +#define to_genetic(obj) container_of(obj, struct genetic_s, kobj) +#define to_genetic_attr(_attr) container_of(_attr, struct genetic_attribute, attr) + +#define GENETIC_TUNABLE(_var, _name) \ +static int g_show_##_name(struct gene_obj *g, char *buf) \ +{ \ + return sprintf(buf, "%lu\n", _var); \ +} \ +static int g_store_##_name(struct gene_obj *g, const char *buf, size_t size) \ +{ \ + char *p = (char *)buf; \ + unsigned long temp; \ + temp = simple_strtoul(p, &p, 10); \ + g->genetic->enabled = 0; \ + if (temp < g->gene_param->max && temp > g->gene_param->min) \ + g->gene_param->initial = temp; \ + return size; \ +} + +/* Setup routines */ +int genetic_init(genetic_t ** in_genetic, unsigned long num_children, + unsigned long child_life_time, int fingerprinting, + char * name); +phenotype_t * genetic_register_phenotype(genetic_t * genetic, struct genetic_ops * ops, + unsigned long num_children, char * name, + unsigned long num_genes, unsigned long uid); +void genetic_start(genetic_t * genetic); + +/* Generic helper functions */ +void genetic_generic_mutate_child(genetic_child_t * child); +void genetic_generic_iterative_mutate_gene(genetic_child_t * child, unsigned long gene_num); +void genetic_generic_combine_genes(genetic_child_t * parent_a, + genetic_child_t * parent_b, + genetic_child_t * child); +void genetic_create_child_spread(genetic_child_t * child, unsigned long num_children); +void genetic_create_child_defaults(genetic_child_t * child); +void genetic_general_shift_mutation_rate(phenotype_t * in_pt); +int genetic_generic_gene_show(struct seq_file *s, void *unused); + +/* XXX do this more intelligently */ +#ifndef DIVLL_OP +#define DIVLL_OP +#if BITS_PER_LONG >= 64 + +static inline void divll(long long *n, long div, long *rem) +{ + *rem = *n % div; + *n /= div; +} + +#else + +static inline void divl(int32_t high, int32_t low, + int32_t div, + int32_t *q, int32_t *r) +{ + int64_t n = (u_int64_t)high << 32 | low; + int64_t d = (u_int64_t)div << 31; + int32_t q1 = 0; + int c = 32; + while (n > 0xffffffff) { + q1 <<= 1; + if (n >= d) { + n -= d; + q1 |= 1; + } + d >>= 1; + c--; + } + q1 <<= c; + if (n) { + low = n; + *q = q1 | (low / div); + *r = low % div; + } else { + *r = 0; + *q = q1; + } + return; +} + +static inline void divll(long long *n, long div, long *rem) +{ + int32_t low, high; + low = *n & 0xffffffff; + high = *n >> 32; + if (high) { + int32_t high1 = high % div; + int32_t low1 = low; + high /= div; + divl(high1, low1, div, &low, (int32_t *)rem); + *n = (int64_t)high << 32 | low; + } else { + *n = low / div; + *rem = low % div; + } +} +#endif + +#endif /* #ifndef divll */ + +#endif