1079 lines
27 KiB
C
1079 lines
27 KiB
C
|
/**
|
||
|
*
|
||
|
* KAIR - Library for Kernel perspective AI based Resource Control
|
||
|
*
|
||
|
* COPYRIGHT(C) Samsung Electronics Co., Ltd. All Right Reserved.
|
||
|
*
|
||
|
* Implementation of ECAVE - Elastic Capacity Vessel - theory to abstract of
|
||
|
* arbitrary systems whose capacity is self regulated by purely observing the
|
||
|
* behavior of object coming from outside of the system.
|
||
|
*
|
||
|
**/
|
||
|
|
||
|
#include <linux/kernel.h>
|
||
|
#include <linux/string.h>
|
||
|
#include <linux/slab.h>
|
||
|
#include <linux/init.h>
|
||
|
#include <linux/kair.h>
|
||
|
|
||
|
#include "d2u_decl_cmtpdf.h"
|
||
|
|
||
|
#define __INFTY (0xEFEFEFEF)
|
||
|
|
||
|
#define POSITIVE_STRETCH (0x80000000)
|
||
|
#define NEGATIVE_STRETCH (0x40000000)
|
||
|
#define STRETCH_MASK (0xC0000000)
|
||
|
#define HARMONIC_MASK (0x3FFFFFFF)
|
||
|
#define ONE2TWO_RES (64)
|
||
|
|
||
|
#define LOG_UPSCALE (512)
|
||
|
#define LOG_UPSCALE_SHIFT (9)
|
||
|
|
||
|
#define ASYMMETRIC_INFERENCE
|
||
|
|
||
|
const unsigned int __lb2[ONE2TWO_RES] =
|
||
|
{ 11, 22, 33, 44, 54, 65, 75, 85, 95, 105, 115, 125, 134, 144,
|
||
|
153, 162, 171, 180, 189, 198, 206, 215, 223, 232, 240, 248, 256, 264,
|
||
|
272, 280, 288, 295, 303, 310, 318, 325, 332, 340, 347, 354, 361, 368,
|
||
|
375, 381, 388, 395, 401, 408, 414, 421, 427, 434, 440, 446, 452, 459,
|
||
|
465, 471, 477, 483, 488, 494, 500, 506};
|
||
|
|
||
|
typedef enum {
|
||
|
KLD_LPLANE,
|
||
|
KLD_RPLANE,
|
||
|
} kld_plane;
|
||
|
|
||
|
/*.............................................................................
|
||
|
*.............................................................................
|
||
|
*............. """ sysfs interfaces with an Kair instance """" ..............
|
||
|
*.............................................................................
|
||
|
*...........................................................................*/
|
||
|
|
||
|
/**
|
||
|
* HTML skeletons for building Kair PDF description template
|
||
|
**/
|
||
|
const char __hcmp_head[] = "<!DOCTYPE html><html><head><title>Kair TPDF description</title></head><body lang=\"en\"><table width=\"100\%\" cellpadding=\"4\" cellspacing=\"0\">";
|
||
|
const char __hcmp_entr[] = "<tr valign=i\"top\"><td><p>level ";
|
||
|
const char __hcmp_flr1[] = " TPDF shape</p><p><br></p><p>- randomness : ";
|
||
|
const char __hcmp_flr2[] = "</p><p>- observation interval : ";
|
||
|
const char __hcmp_flr3[] = "</p><p>- weight : ";
|
||
|
const char __hcmp_iter[] = "</p></td><td><p>";
|
||
|
const char __hcmp_clsr[] = "</p></td></tr>";
|
||
|
const char __hcmp_foot[] = "</table></body></html>\n";
|
||
|
|
||
|
/**
|
||
|
* @abst_kobj : /abstract entry direcly placed beneath /sys.
|
||
|
**/
|
||
|
struct kobject *abst_kobj;
|
||
|
|
||
|
/**
|
||
|
* KAIR instance can be dynamically created by anonymous clients.
|
||
|
* SYSFS interface to the particular instance will be handled through an
|
||
|
* exclusive form of kset in sysfs /sys/abst/kair, which means /kair is
|
||
|
* defined as a primitive abstraction node.
|
||
|
**/
|
||
|
static struct kset *krinst_set;
|
||
|
|
||
|
static unsigned int kair_cap_soft_bettor(struct kair_class *self,
|
||
|
struct rand_var *v,
|
||
|
unsigned int cap_legacy);
|
||
|
static unsigned int kair_cap_strict_bettor(struct kair_class *self,
|
||
|
struct rand_var *v,
|
||
|
unsigned int cap_legacy);
|
||
|
|
||
|
static ssize_t krinst_attr_show(struct kobject *kobj,
|
||
|
struct attribute *attr,
|
||
|
char *buf)
|
||
|
{
|
||
|
struct krinst_attribute *attribute = to_krinst_attr(attr);
|
||
|
struct krinst_obj *node = to_krinst_obj(kobj);
|
||
|
|
||
|
if (!attribute->show)
|
||
|
return -EIO;
|
||
|
|
||
|
return attribute->show(node, attribute, buf);
|
||
|
}
|
||
|
|
||
|
static ssize_t krinst_attr_store(struct kobject *kobj,
|
||
|
struct attribute *attr,
|
||
|
const char *buf, size_t len)
|
||
|
{
|
||
|
struct krinst_attribute *attribute = to_krinst_attr(attr);
|
||
|
struct krinst_obj *node = to_krinst_obj(kobj);
|
||
|
|
||
|
if (!attribute->store)
|
||
|
return -EIO;
|
||
|
|
||
|
return attribute->store(node, attribute, buf, len);
|
||
|
}
|
||
|
|
||
|
static const struct sysfs_ops krinst_sysfs_ops = {
|
||
|
.show = krinst_attr_show,
|
||
|
.store = krinst_attr_store,
|
||
|
};
|
||
|
|
||
|
static void krinst_release(struct kobject *kobj)
|
||
|
{
|
||
|
struct krinst_obj *node = to_krinst_obj(kobj);
|
||
|
|
||
|
kfree(node);
|
||
|
}
|
||
|
|
||
|
static ssize_t choke_cnt_show(struct krinst_obj *node,
|
||
|
struct krinst_attribute *attr,
|
||
|
char *buf)
|
||
|
{
|
||
|
if (node->inst)
|
||
|
return sprintf(buf, "%d\n", node->inst->stats.choke_cnt);
|
||
|
else
|
||
|
return sprintf(buf, "dangled reference\n");
|
||
|
}
|
||
|
KRINST_ATTR_RO(choke_cnt);
|
||
|
|
||
|
static ssize_t save_total_show(struct krinst_obj *node,
|
||
|
struct krinst_attribute *attr,
|
||
|
char *buf)
|
||
|
{
|
||
|
if (node->inst)
|
||
|
return sprintf(buf, "%lld\n", node->inst->stats.save_total);
|
||
|
else
|
||
|
return sprintf(buf, "dangled reference\n");
|
||
|
}
|
||
|
KRINST_ATTR_RO(save_total);
|
||
|
|
||
|
static ssize_t epsilon_show(struct krinst_obj *node,
|
||
|
struct krinst_attribute *attr,
|
||
|
char *buf)
|
||
|
{
|
||
|
if (node->inst)
|
||
|
return sprintf(buf, "%d\n", node->inst->epsilon);
|
||
|
else
|
||
|
return sprintf(buf, "dangled reference\n");
|
||
|
}
|
||
|
|
||
|
static ssize_t epsilon_store(struct krinst_obj *node,
|
||
|
struct krinst_attribute *attr,
|
||
|
const char *buf, size_t count)
|
||
|
{
|
||
|
int retval = 0;
|
||
|
|
||
|
if (node->inst) {
|
||
|
retval = kstrtouint(buf, 10, &node->inst->epsilon);
|
||
|
if (retval < 0)
|
||
|
return retval;
|
||
|
} else
|
||
|
return -EFAULT;
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
KRINST_ATTR_RW(epsilon);
|
||
|
|
||
|
static ssize_t resilience_show(struct krinst_obj *node,
|
||
|
struct krinst_attribute *attr,
|
||
|
char *buf)
|
||
|
{
|
||
|
if (node->inst)
|
||
|
return sprintf(buf, "%d\n", node->inst->resilience);
|
||
|
else
|
||
|
return sprintf(buf, "dangled reference\n");
|
||
|
}
|
||
|
KRINST_ATTR_RO(resilience);
|
||
|
|
||
|
static ssize_t rand_neutral_show(struct krinst_obj *node,
|
||
|
struct krinst_attribute *attr,
|
||
|
char *buf)
|
||
|
{
|
||
|
if (node->inst)
|
||
|
return sprintf(buf, "%d\n", node->inst->stats.rand_neutral);
|
||
|
else
|
||
|
return sprintf(buf, "dangled reference\n");
|
||
|
}
|
||
|
|
||
|
static ssize_t rand_neutral_store(struct krinst_obj *node,
|
||
|
struct krinst_attribute *attr,
|
||
|
const char *buf, size_t count)
|
||
|
{
|
||
|
int retval = 0;
|
||
|
|
||
|
if (node->inst) {
|
||
|
retval = kstrtouint(buf, 10, &node->inst->stats.rand_neutral);
|
||
|
if (retval < 0)
|
||
|
return retval;
|
||
|
} else
|
||
|
return -EFAULT;
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
KRINST_ATTR_RW(rand_neutral);
|
||
|
|
||
|
static ssize_t throttling_show(struct krinst_obj *node,
|
||
|
struct krinst_attribute *attr,
|
||
|
char *buf)
|
||
|
{
|
||
|
if (node->inst)
|
||
|
return sprintf(buf, "%d\n", node->inst->stats.throttling);
|
||
|
else
|
||
|
return sprintf(buf, "dangled reference\n");
|
||
|
}
|
||
|
KRINST_ATTR_RO(throttling);
|
||
|
|
||
|
static ssize_t bettor_select_show(struct krinst_obj *node,
|
||
|
struct krinst_attribute *attr,
|
||
|
char *buf)
|
||
|
{
|
||
|
if (node->inst) {
|
||
|
if (node->inst->cap_bettor == kair_cap_soft_bettor)
|
||
|
return sprintf(buf, "soft\n");
|
||
|
else
|
||
|
return sprintf(buf, "strict\n");
|
||
|
} else
|
||
|
return sprintf(buf, "dangled reference\n");
|
||
|
}
|
||
|
|
||
|
static ssize_t bettor_select_store(struct krinst_obj *node,
|
||
|
struct krinst_attribute *attr,
|
||
|
const char *buf, size_t count)
|
||
|
{
|
||
|
if (node->inst) {
|
||
|
if (!strncmp(buf, "soft", 4))
|
||
|
node->inst->cap_bettor = kair_cap_soft_bettor;
|
||
|
else if (!strncmp(buf, "strict", 6))
|
||
|
node->inst->cap_bettor = kair_cap_strict_bettor;
|
||
|
} else
|
||
|
return -EFAULT;
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
KRINST_ATTR_RW(bettor_select);
|
||
|
|
||
|
static ssize_t tpdf_cascade_show(struct krinst_obj *node,
|
||
|
struct krinst_attribute *attr,
|
||
|
char *buf)
|
||
|
{
|
||
|
char *btemp = NULL;
|
||
|
char *ptemp = NULL;
|
||
|
struct tpdf *level;
|
||
|
unsigned int inc, run;
|
||
|
struct list_head *head;
|
||
|
|
||
|
if (node->inst) {
|
||
|
/**
|
||
|
* Allocating memory for HTML template
|
||
|
**/
|
||
|
btemp = kzalloc(PAGE_SIZE, GFP_KERNEL);
|
||
|
if (!btemp)
|
||
|
return -1;
|
||
|
else
|
||
|
ptemp = btemp;
|
||
|
|
||
|
ptemp += sprintf(ptemp, "%s", __hcmp_head);
|
||
|
head = &node->inst->tpdf_cascade;
|
||
|
|
||
|
for (level = list_first_entry(head, struct tpdf, pos), inc = 1;
|
||
|
&level->pos != head;
|
||
|
level = list_next_entry(level, pos), inc++) {
|
||
|
ptemp += sprintf(ptemp, "%s", __hcmp_entr);
|
||
|
ptemp += sprintf(ptemp, "%d", inc);
|
||
|
ptemp += sprintf(ptemp, "%s", __hcmp_flr1);
|
||
|
ptemp += sprintf(ptemp, "%d", level->irand);
|
||
|
ptemp += sprintf(ptemp, "%s", __hcmp_flr2);
|
||
|
ptemp += sprintf(ptemp, "%lld", kair_window_size(level));
|
||
|
ptemp += sprintf(ptemp, "%s", __hcmp_flr3);
|
||
|
ptemp += sprintf(ptemp, "x%d", level->weight);
|
||
|
|
||
|
ptemp += sprintf(ptemp, "%s", __hcmp_iter);
|
||
|
for (run = 0; run < level->qlvl; run++) {
|
||
|
ptemp += sprintf(ptemp, "%d", level->qtbl[run]);
|
||
|
ptemp += sprintf(ptemp, "%s", __hcmp_iter);
|
||
|
}
|
||
|
ptemp += sprintf(ptemp, "%s", __hcmp_clsr);
|
||
|
}
|
||
|
|
||
|
ptemp += sprintf(ptemp, "%s", __hcmp_foot);
|
||
|
memcpy(buf, btemp, PAGE_SIZE);
|
||
|
kfree(btemp);
|
||
|
}
|
||
|
|
||
|
return (ssize_t)(ptemp - btemp);
|
||
|
}
|
||
|
KRINST_ATTR_RO(tpdf_cascade);
|
||
|
|
||
|
static struct attribute *krinst_default_attrs[] = {
|
||
|
&choke_cnt_attr.attr,
|
||
|
&save_total_attr.attr,
|
||
|
&epsilon_attr.attr,
|
||
|
&resilience_attr.attr,
|
||
|
&rand_neutral_attr.attr,
|
||
|
&throttling_attr.attr,
|
||
|
&bettor_select_attr.attr,
|
||
|
&tpdf_cascade_attr.attr,
|
||
|
NULL,
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* KAIR exclusive ktype for our kobjects
|
||
|
**/
|
||
|
static struct kobj_type krinst_ktype = {
|
||
|
.sysfs_ops = &krinst_sysfs_ops,
|
||
|
.release = krinst_release,
|
||
|
.default_attrs = krinst_default_attrs,
|
||
|
};
|
||
|
|
||
|
static struct krinst_obj *create_krinst_obj(struct kair_class *src)
|
||
|
{
|
||
|
struct krinst_obj *node;
|
||
|
int retval;
|
||
|
|
||
|
node = kzalloc(sizeof(*node), GFP_KERNEL);
|
||
|
if (!node)
|
||
|
return NULL;
|
||
|
|
||
|
/* Linking @ parent kset /sys/kair */
|
||
|
node->obj.kset = krinst_set;
|
||
|
node->inst = src;
|
||
|
|
||
|
retval = kobject_init_and_add(&node->obj, &krinst_ktype,
|
||
|
&krinst_set->kobj, "%s",
|
||
|
(const char *)src->alias);
|
||
|
if (retval) {
|
||
|
kobject_put(&node->obj);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/* Sending the uevent that the kobject was added to the system */
|
||
|
kobject_uevent(&node->obj, KOBJ_ADD);
|
||
|
|
||
|
return node;
|
||
|
}
|
||
|
|
||
|
static void destroy_krinst_obj(struct krinst_obj *node)
|
||
|
{
|
||
|
node->inst = NULL;
|
||
|
|
||
|
kobject_del(&node->obj);
|
||
|
kobject_put(&node->obj);
|
||
|
}
|
||
|
|
||
|
static int __init kair_prepare(void)
|
||
|
{
|
||
|
abst_kobj = kobject_create_and_add("abst", NULL);
|
||
|
if (!abst_kobj)
|
||
|
goto s1_error;
|
||
|
|
||
|
krinst_set = kset_create_and_add("kair", NULL, abst_kobj);
|
||
|
if (!krinst_set)
|
||
|
goto s2_error;
|
||
|
|
||
|
return 0;
|
||
|
s2_error:
|
||
|
kobject_put(abst_kobj);
|
||
|
s1_error:
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
postcore_initcall(kair_prepare);
|
||
|
|
||
|
static void __exit kair_clean(void)
|
||
|
{
|
||
|
kset_unregister(krinst_set);
|
||
|
|
||
|
kobject_put(abst_kobj);
|
||
|
}
|
||
|
__exitcall(kair_clean);
|
||
|
|
||
|
/*.............................................................................
|
||
|
*.............................................................................
|
||
|
*... """ KAIR-wise Temporal Probability Density Function Manipulators """ ....
|
||
|
*.............................................................................
|
||
|
*...........................................................................*/
|
||
|
|
||
|
/**
|
||
|
* """ KAIR TPDF cascading method """
|
||
|
**/
|
||
|
void kair_tpdf_cascading(struct kair_class *vessel, struct tpdf *element)
|
||
|
{
|
||
|
list_add(&element->pos, &vessel->tpdf_cascade);
|
||
|
}
|
||
|
EXPORT_SYMBOL(kair_tpdf_cascading);
|
||
|
|
||
|
/**
|
||
|
* """ KAIR TPDF cleaning method """
|
||
|
**/
|
||
|
void kair_tpdf_cleaning(struct kair_class *vessel)
|
||
|
{
|
||
|
struct tpdf *cur, *tmp;
|
||
|
|
||
|
if (!list_empty(&vessel->tpdf_cascade)) {
|
||
|
list_for_each_entry_safe(cur, tmp, &vessel->tpdf_cascade, pos) {
|
||
|
list_del(&cur->pos);
|
||
|
|
||
|
cur->untabling(cur);
|
||
|
cur->rv_unregister(cur);
|
||
|
|
||
|
kfree(cur);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
EXPORT_SYMBOL(kair_tpdf_cleaning);
|
||
|
|
||
|
/**
|
||
|
* """ KAIR default API to build 3-level TPDF cascading """
|
||
|
**/
|
||
|
int kair_build_tpdf_cascade(struct kair_class *vessel)
|
||
|
{
|
||
|
unsigned int weight_sum;
|
||
|
|
||
|
#if KAIR_TPDF_CASCADE_LEVEL > 1
|
||
|
struct tpdf *tpdf_inf, *tpdf_fin, *tpdf_ins;
|
||
|
|
||
|
tpdf_inf = kmalloc(sizeof(struct tpdf), GFP_KERNEL);
|
||
|
if (!tpdf_inf)
|
||
|
goto l3_nomem;
|
||
|
|
||
|
tpdf_fin = kmalloc(sizeof(struct tpdf), GFP_KERNEL);
|
||
|
if (!tpdf_fin)
|
||
|
goto l2_nomem;
|
||
|
|
||
|
tpdf_ins = kmalloc(sizeof(struct tpdf), GFP_KERNEL);
|
||
|
if (!tpdf_ins)
|
||
|
goto l1_nomem;
|
||
|
|
||
|
kair_l3_pdf_init(tpdf_inf);
|
||
|
kair_l2_pdf_init(tpdf_fin);
|
||
|
kair_l1_pdf_init(tpdf_ins);
|
||
|
|
||
|
kair_tpdf_cascading(vessel, tpdf_inf);
|
||
|
kair_tpdf_cascading(vessel, tpdf_fin);
|
||
|
kair_tpdf_cascading(vessel, tpdf_ins);
|
||
|
|
||
|
weight_sum = tpdf_inf->weight + tpdf_fin->weight + tpdf_ins->weight;
|
||
|
goto exit;
|
||
|
|
||
|
l1_nomem:
|
||
|
kfree(tpdf_fin);
|
||
|
l2_nomem:
|
||
|
kfree(tpdf_inf);
|
||
|
l3_nomem:
|
||
|
return -ENOMEM;
|
||
|
|
||
|
exit:
|
||
|
#else
|
||
|
struct tpdf *tpdf_ins;
|
||
|
|
||
|
tpdf_ins = kmalloc(sizeof(struct tpdf), GFP_KERNEL);
|
||
|
if (!tpdf_ins)
|
||
|
return -ENOMEM;
|
||
|
|
||
|
kair_l1_pdf_init(tpdf_ins);
|
||
|
kair_tpdf_cascading(vessel, tpdf_ins);
|
||
|
weight_sum = tpdf_ins->weight;
|
||
|
#endif
|
||
|
|
||
|
vessel->capa_denom = ilog2(weight_sum + 1);
|
||
|
return 0;
|
||
|
}
|
||
|
EXPORT_SYMBOL(kair_build_tpdf_cascade);
|
||
|
|
||
|
/**
|
||
|
* """ KAIR TPDF availability checker """
|
||
|
**/
|
||
|
static inline bool is_tpdf_prepared(struct tpdf *self)
|
||
|
{
|
||
|
bool ret;
|
||
|
|
||
|
if (is_kair_window_infty(self))
|
||
|
ret = (kair_windowing_cnt(self) >= KAIR_TPDF_CUMSUM)
|
||
|
? true : false;
|
||
|
else
|
||
|
ret = (kair_windowing_cnt(self) >= kair_window_size(self))
|
||
|
? true : false;
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* """ KAIR default TPDF total equilibrator """
|
||
|
**/
|
||
|
void kair_tpdf_equilibrator(struct tpdf *self)
|
||
|
{
|
||
|
unsigned int cursor;
|
||
|
|
||
|
self->pc_cnt++;
|
||
|
|
||
|
if (self->pc_cnt == KAIR_TPDF_CUMSUM) {
|
||
|
for (cursor = 0; cursor < self->qlvl; cursor++)
|
||
|
self->qtbl[cursor] >>= 1;
|
||
|
self->pc_cnt = 0;
|
||
|
}
|
||
|
}
|
||
|
EXPORT_SYMBOL(kair_tpdf_equilibrator);
|
||
|
|
||
|
/**
|
||
|
* """ KAIR default TPDF rescaler """
|
||
|
* The rescaling ratio is calculated 'kair_TPDF_CUMSUM / kair_window_size()'
|
||
|
**/
|
||
|
void kair_tpdf_rescaler(struct tpdf *self)
|
||
|
{
|
||
|
unsigned int cursor;
|
||
|
unsigned int denom = (unsigned int)kair_window_size(self);
|
||
|
|
||
|
if (kair_window_need_rescale(self)) {
|
||
|
for (cursor = 0; cursor < self->qlvl; cursor++)
|
||
|
self->qtbl[cursor] = mult_frac(self->qtbl[cursor],
|
||
|
KAIR_TPDF_CUMSUM, denom);
|
||
|
kair_window_rescale_done(self);
|
||
|
}
|
||
|
}
|
||
|
EXPORT_SYMBOL(kair_tpdf_rescaler);
|
||
|
|
||
|
/**
|
||
|
* """ KAIR default TPDF tabling procedure """
|
||
|
* Which is mainly composed of;
|
||
|
* - memory allocation
|
||
|
* - copying the existing TPDF image from storage to runtime memory
|
||
|
* - address mapping to self
|
||
|
**/
|
||
|
int kair_tpdf_tabling(struct tpdf *self)
|
||
|
{
|
||
|
self->qtbl = kzalloc(sizeof(int) * self->qlvl, GFP_KERNEL);
|
||
|
if (!self->qtbl)
|
||
|
return -ENOMEM;
|
||
|
|
||
|
if (!is_kair_window_infty(self)) {
|
||
|
if (tfifo_alloc(&self->cache, kair_window_size(self)) == false)
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
EXPORT_SYMBOL(kair_tpdf_tabling);
|
||
|
|
||
|
/**
|
||
|
* """ KAIR default TPDF untabling procedure """
|
||
|
* Which is mainly composed of;
|
||
|
* - memory free
|
||
|
* - store the built TPDF image to storage
|
||
|
* - address unmapping
|
||
|
**/
|
||
|
void kair_tpdf_untabling(struct tpdf *self)
|
||
|
{
|
||
|
kfree(self->qtbl);
|
||
|
|
||
|
tfifo_free(&self->cache);
|
||
|
}
|
||
|
EXPORT_SYMBOL(kair_tpdf_untabling);
|
||
|
|
||
|
void kair_tpdf_rv_register(struct tpdf *self, struct rand_var *rv)
|
||
|
{
|
||
|
self->rv = rv;
|
||
|
}
|
||
|
EXPORT_SYMBOL(kair_tpdf_rv_register);
|
||
|
|
||
|
void kair_tpdf_rv_unregister(struct tpdf *self)
|
||
|
{
|
||
|
self->rv = NULL;
|
||
|
}
|
||
|
EXPORT_SYMBOL(kair_tpdf_rv_unregister);
|
||
|
|
||
|
/*.............................................................................
|
||
|
*.............................................................................
|
||
|
*.................. """ Generic Mathematical Functions """ ...................
|
||
|
*.............................................................................
|
||
|
*...........................................................................*/
|
||
|
|
||
|
/**
|
||
|
* """ Caculating Kullback-Liebler diversity """
|
||
|
* Evaluating how much two random variables are similar. this is actually done
|
||
|
* by taking full integral on the relative entropy.
|
||
|
* @comparer : TPDF structure quantized by its own qlvl.
|
||
|
* @comparee : comparee's raw integer TPDF table quantized by comparer's qlvl.
|
||
|
**/
|
||
|
int kl_diversity(struct tpdf *comparer, unsigned int *comparee)
|
||
|
{
|
||
|
int kl_div = 0;
|
||
|
unsigned int idx;
|
||
|
unsigned int p, q, pbase, qbase, entp, entq;
|
||
|
int log2p, log2q;
|
||
|
|
||
|
for (idx = 0; idx < comparer->qlvl; idx++) {
|
||
|
p = comparer->qtbl[idx];
|
||
|
q = comparee[idx];
|
||
|
|
||
|
/* Q(i)=0 implies P(i)=0 */
|
||
|
if (p == 0 || q == 0)
|
||
|
continue;
|
||
|
|
||
|
log2p = ilog2(p);
|
||
|
log2q = ilog2(q);
|
||
|
pbase = 1 << log2p;
|
||
|
qbase = 1 << log2q;
|
||
|
entp = (p == pbase) ? (p * log2p) :
|
||
|
((p * log2p) +
|
||
|
((p * __lb2[mult_frac(p - pbase, ONE2TWO_RES, pbase)])
|
||
|
>> LOG_UPSCALE_SHIFT));
|
||
|
entq = (q == qbase) ? (p * log2q) :
|
||
|
((p * log2q) +
|
||
|
((p * __lb2[mult_frac(q - qbase, ONE2TWO_RES, qbase)])
|
||
|
>> LOG_UPSCALE_SHIFT));
|
||
|
|
||
|
/**
|
||
|
* If the probability of comparer random variable at a scope is
|
||
|
* bigger than the one's of comparee, KL diversity will be increased
|
||
|
* as far as the relative entropy caculated differs, otherwise,
|
||
|
* KL diversity will be fairly decreased.
|
||
|
**/
|
||
|
kl_div += (entp - entq);
|
||
|
}
|
||
|
|
||
|
return kl_div;
|
||
|
}
|
||
|
EXPORT_SYMBOL(kl_diversity);
|
||
|
|
||
|
/**
|
||
|
* """ Caculating Asymmetric Kullback-Liebler diversity """
|
||
|
* Evaluating how much two random variables are similar. this is actually done
|
||
|
* by taking full integral on the relative entropy.
|
||
|
* @comparer : TPDF structure quantized by its own qlvl.
|
||
|
* @comparee : comparee's raw integer TPDF table quantized by comparer's qlvl.
|
||
|
**/
|
||
|
int kl_asymm_diversity(struct tpdf *comparer, unsigned int *comparee, kld_plane side)
|
||
|
{
|
||
|
int kl_div = 0;
|
||
|
unsigned int idx;
|
||
|
unsigned int mean = comparer->qlvl >> 1;
|
||
|
unsigned int head = (side == KLD_LPLANE) ? 0 : mean;
|
||
|
unsigned int foot = (side == KLD_LPLANE) ? mean : comparer->qlvl - 1;
|
||
|
unsigned int p, q, pbase, qbase, entp, entq;
|
||
|
int log2p, log2q;
|
||
|
|
||
|
for (idx = head; idx <= foot; idx++) {
|
||
|
p = comparer->qtbl[idx];
|
||
|
q = comparee[idx];
|
||
|
|
||
|
/* Q(i)=0 implies P(i)=0 */
|
||
|
if (p == 0 || q == 0)
|
||
|
continue;
|
||
|
|
||
|
log2p = ilog2(p);
|
||
|
log2q = ilog2(q);
|
||
|
pbase = 1 << log2p;
|
||
|
qbase = 1 << log2q;
|
||
|
entp = (p == pbase) ? (p * log2p) :
|
||
|
((p * log2p) +
|
||
|
((p * __lb2[mult_frac(p - pbase, ONE2TWO_RES, pbase)])
|
||
|
>> LOG_UPSCALE_SHIFT));
|
||
|
entq = (q == qbase) ? (p * log2q) :
|
||
|
((p * log2q) +
|
||
|
((p * __lb2[mult_frac(q - qbase, ONE2TWO_RES, qbase)])
|
||
|
>> LOG_UPSCALE_SHIFT));
|
||
|
|
||
|
/**
|
||
|
* If the probability of comparer random variable at a scope is
|
||
|
* bigger than the one's of comparee, KL diversity will be increased
|
||
|
* as far as the relative entropy caculated differs, otherwise,
|
||
|
* KL diversity will be fairly decreased.
|
||
|
**/
|
||
|
kl_div += (entp - entq);
|
||
|
}
|
||
|
|
||
|
return kl_div;
|
||
|
}
|
||
|
EXPORT_SYMBOL(kl_asymm_diversity);
|
||
|
|
||
|
/**
|
||
|
* """ Default linear interpolator """
|
||
|
* Returning interpolated value;
|
||
|
* @self : temporal probability density function
|
||
|
* @top_pos : top position
|
||
|
* @raw_pos : raw position
|
||
|
**/
|
||
|
unsigned int linear_interpolator(struct tpdf *self, unsigned int top_pos,
|
||
|
unsigned int raw_pos)
|
||
|
{
|
||
|
unsigned int psec = top_pos >> ilog2(self->qlvl);
|
||
|
unsigned int lpos = raw_pos >> psec;
|
||
|
unsigned int lval = self->qtbl[lpos];
|
||
|
unsigned int rval = self->qtbl[lpos + 1];
|
||
|
unsigned int delta = raw_pos - (lpos << psec);
|
||
|
|
||
|
return (delta * lval + (top_pos - delta) * rval) >> psec;
|
||
|
}
|
||
|
EXPORT_SYMBOL(linear_interpolator);
|
||
|
|
||
|
/*.............................................................................
|
||
|
*.............................................................................
|
||
|
*................... """ KAIR capsulated functions """ ......................
|
||
|
*.............................................................................
|
||
|
*...........................................................................*/
|
||
|
|
||
|
/**
|
||
|
* Under assuming the function kl-diversity to given TPDF-TPDF comparison is
|
||
|
* quite noisy-convex, an alternative greedy gradient decsending algorithm
|
||
|
* is exhibited here.
|
||
|
* @targ :
|
||
|
* @mold :
|
||
|
**/
|
||
|
static inline randomness __gs_on_kld(struct tpdf *targ,
|
||
|
unsigned int **mold,
|
||
|
unsigned int max_var)
|
||
|
{
|
||
|
int cur;
|
||
|
int min_idx = 0;
|
||
|
int min_kld = __INFTY;
|
||
|
|
||
|
int lmost = 0;
|
||
|
int rmost = (int)max_var - 1;
|
||
|
|
||
|
int width = (int)max_var;
|
||
|
int hop_total = ilog2((unsigned int)width);
|
||
|
int hop_width = (1 << hop_total) / hop_total;
|
||
|
int kld_ref[16];
|
||
|
|
||
|
memset(kld_ref, 0xEF, sizeof(kld_ref));
|
||
|
|
||
|
/**
|
||
|
* Complexity : O(N x log N * log(log N) x ...)
|
||
|
**/
|
||
|
do {
|
||
|
for (cur = lmost; cur <= (rmost + 1); cur += hop_width) {
|
||
|
cur = cur > rmost ? rmost : cur;
|
||
|
|
||
|
#ifndef ASYMMETRIC_INFERENCE
|
||
|
if (kld_ref[cur] == __INFTY)
|
||
|
kld_ref[cur] = kl_diversity(targ,
|
||
|
(unsigned int *)mold + cur * KAIR_QUANT_STEP);
|
||
|
|
||
|
if (abs(kld_ref[cur]) < abs(min_kld)) {
|
||
|
min_kld = kld_ref[cur];
|
||
|
min_idx = cur;
|
||
|
}
|
||
|
#else
|
||
|
if (kld_ref[cur] == __INFTY) {
|
||
|
kld_ref[cur] = kl_asymm_diversity(targ,
|
||
|
(unsigned int *)mold + cur * KAIR_QUANT_STEP, KLD_RPLANE);
|
||
|
}
|
||
|
|
||
|
if (abs(kld_ref[cur]) < abs(min_kld)) {
|
||
|
min_kld = kld_ref[cur];
|
||
|
min_idx = cur;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
lmost = max(min_idx - hop_width + 1, lmost);
|
||
|
rmost = min(min_idx + hop_width - 1, rmost);
|
||
|
|
||
|
width = rmost - lmost + 1;
|
||
|
hop_total = ilog2((unsigned int)width);
|
||
|
hop_width = (1 << hop_total) / hop_total;
|
||
|
} while (rmost - lmost > 2);
|
||
|
|
||
|
return (randomness)min_idx;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* """ KAIR default searcher of the template TPDF """
|
||
|
* Nearest resembling to given
|
||
|
**/
|
||
|
static int kair_search_nearest_job_tpdf(struct kair_class *self)
|
||
|
{
|
||
|
struct tpdf *level;
|
||
|
|
||
|
if (list_empty(&self->tpdf_cascade))
|
||
|
return KAIR_DIVERGING;
|
||
|
|
||
|
list_for_each_entry(level, &self->tpdf_cascade, pos) {
|
||
|
if (!is_tpdf_prepared(level))
|
||
|
continue;
|
||
|
|
||
|
if (level->pc_cnt)
|
||
|
continue;
|
||
|
|
||
|
level->irand = __gs_on_kld(level,
|
||
|
(unsigned int **)d2u_decl_cmtpdf,
|
||
|
self->resilience);
|
||
|
}
|
||
|
|
||
|
level = list_first_entry(&self->tpdf_cascade, struct tpdf, pos);
|
||
|
return level->irand;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
**/
|
||
|
static inline void kair_tpdf_carving_out(struct tpdf *self)
|
||
|
{
|
||
|
unsigned int scope;
|
||
|
unsigned int mult = kair_window_size(self) / KAIR_TPDF_CUMSUM;
|
||
|
|
||
|
self->rescaler(self);
|
||
|
|
||
|
self->pc_cnt++;
|
||
|
|
||
|
scope = tfifo_out(&self->cache);
|
||
|
self->qtbl[scope] = self->qtbl[scope] ? self->qtbl[scope] - 1 : 0;
|
||
|
|
||
|
if (self->pc_cnt == kair_window_size(self) / mult)
|
||
|
self->pc_cnt = 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* """ KAIR job probability collapse operator """
|
||
|
* Which takes place of generative learning what temporal probability density
|
||
|
* function of given job intensity looks like.
|
||
|
**/
|
||
|
static void kair_job_probability_collapse(struct kair_class *self,
|
||
|
struct rand_var *v)
|
||
|
{
|
||
|
struct tpdf *level;
|
||
|
unsigned int scope;
|
||
|
bool in_choke = (v->nval == v->ubound);
|
||
|
|
||
|
if (list_empty(&self->tpdf_cascade))
|
||
|
return;
|
||
|
|
||
|
if (in_choke) {
|
||
|
self->stats.choke_cnt++;
|
||
|
} else {
|
||
|
list_for_each_entry(level, &self->tpdf_cascade, pos) {
|
||
|
scope = (unsigned int)RV_TAILORED(level, v);
|
||
|
|
||
|
level->qtbl[scope]++;
|
||
|
|
||
|
if (is_kair_window_infty(level)) {
|
||
|
if (kair_windowing_cnt(level) >= KAIR_TPDF_CUMSUM)
|
||
|
level->equilibrator(level);
|
||
|
else
|
||
|
level->win_size++;
|
||
|
} else {
|
||
|
tfifo_in(&level->cache, scope);
|
||
|
|
||
|
if (kair_windowing_cnt(level) >= kair_window_size(level))
|
||
|
kair_tpdf_carving_out(level);
|
||
|
else
|
||
|
level->win_size++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* taking integral on Sunchul PDF from given i to maximum
|
||
|
**/
|
||
|
static inline unsigned int __integral_schi2m(randomness r, unsigned int i)
|
||
|
{
|
||
|
unsigned int total = 0;
|
||
|
unsigned int x;
|
||
|
|
||
|
for (x = i; x < KAIR_QUANT_STEP; x++)
|
||
|
total += d2u_decl_cmtpdf[(unsigned int)r][x];
|
||
|
|
||
|
return total;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* """ KAIR default desirable capacity bettor """
|
||
|
* Betting reasonable kair capacity per job intensity induced outside by
|
||
|
* stochastic processing of job intensity's centered-mean TPDF.
|
||
|
* @self
|
||
|
* @v
|
||
|
* @cap_legacy :
|
||
|
**/
|
||
|
static unsigned int kair_cap_soft_bettor(struct kair_class *self,
|
||
|
struct rand_var *v,
|
||
|
unsigned int cap_legacy)
|
||
|
{
|
||
|
struct tpdf *level;
|
||
|
unsigned int min_cap = mult_frac(cap_legacy,
|
||
|
self->kairistic.theta_numer,
|
||
|
self->kairistic.theta_denom);
|
||
|
unsigned int max_cap = mult_frac(cap_legacy,
|
||
|
self->kairistic.gamma_numer,
|
||
|
self->kairistic.gamma_denom);
|
||
|
unsigned int new_cap = 0;
|
||
|
|
||
|
if (list_empty(&self->tpdf_cascade))
|
||
|
return cap_legacy;
|
||
|
|
||
|
if (cap_legacy == 0)
|
||
|
return 0;
|
||
|
|
||
|
list_for_each_entry(level, &self->tpdf_cascade, pos) {
|
||
|
if (level->irand == KAIR_DIVERGING) {
|
||
|
new_cap = cap_legacy;
|
||
|
} else {
|
||
|
new_cap += level->weight *
|
||
|
((level->irand > self->stats.rand_neutral) ?
|
||
|
max_cap >> self->capa_denom : min_cap >> self->capa_denom);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
self->stats.save_total += ((long long)cap_legacy - (long long)new_cap) / 10;
|
||
|
|
||
|
return new_cap;
|
||
|
}
|
||
|
|
||
|
static unsigned int kair_cap_strict_bettor(struct kair_class *self,
|
||
|
struct rand_var *v,
|
||
|
unsigned int cap_legacy)
|
||
|
{
|
||
|
struct tpdf *level;
|
||
|
unsigned int new_cap = mult_frac(cap_legacy,
|
||
|
self->kairistic.theta_numer,
|
||
|
self->kairistic.theta_denom);
|
||
|
unsigned int max_cap = mult_frac(cap_legacy,
|
||
|
self->kairistic.gamma_numer,
|
||
|
self->kairistic.gamma_denom);
|
||
|
unsigned int skew;
|
||
|
unsigned int run_hmny;
|
||
|
unsigned int cap_unit = (max_cap - new_cap) >> self->capa_denom;
|
||
|
|
||
|
s32 cap_delta = 0;
|
||
|
|
||
|
if (list_empty(&self->tpdf_cascade))
|
||
|
return cap_legacy;
|
||
|
|
||
|
if (cap_legacy == 0)
|
||
|
return 0;
|
||
|
|
||
|
list_for_each_entry(level, &self->tpdf_cascade, pos) {
|
||
|
unsigned int scope = RV_TAILORED(level, v);
|
||
|
unsigned int min_hmny = __INFTY;
|
||
|
unsigned int opt_skew = __INFTY;
|
||
|
|
||
|
if (level->irand == KAIR_DIVERGING)
|
||
|
continue;
|
||
|
|
||
|
for (skew = 0; skew < self->resilience; skew++) {
|
||
|
unsigned int __cap = cap_legacy + cap_unit * (level->irand - skew);
|
||
|
|
||
|
run_hmny = self->epsilon * __integral_schi2m(skew, scope) + __cap;
|
||
|
|
||
|
if (min_hmny > run_hmny) {
|
||
|
min_hmny = run_hmny;
|
||
|
opt_skew = skew;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cap_delta = cap_unit * (level->irand - opt_skew);
|
||
|
new_cap += cap_delta * level->weight;
|
||
|
}
|
||
|
|
||
|
self->stats.save_total += ((long long)cap_legacy - (long long)new_cap) / 10;
|
||
|
|
||
|
return new_cap;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* """ KAIR default instance initializer """
|
||
|
* Making stuffs inside of kair instance ready. for now, preparing
|
||
|
* the multi-leveled TPDF cascade.
|
||
|
* @self : instance itself
|
||
|
**/
|
||
|
static int kair_initializer(struct kair_class *self)
|
||
|
{
|
||
|
int retval = 0;
|
||
|
|
||
|
retval = kair_build_tpdf_cascade(self);
|
||
|
if (retval < 0)
|
||
|
return retval;
|
||
|
|
||
|
self->extif = create_krinst_obj(self);
|
||
|
if (!self->extif)
|
||
|
return -ENOMEM;
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* """ KAIR default instance stopper """
|
||
|
* A part of suspend sequence. Reset TPDF as well.
|
||
|
* @self : instance itself
|
||
|
**/
|
||
|
static void kair_stopper(struct kair_class *self)
|
||
|
{
|
||
|
struct tpdf *cur;
|
||
|
|
||
|
if (!list_empty(&self->tpdf_cascade)) {
|
||
|
list_for_each_entry(cur, &self->tpdf_cascade, pos) {
|
||
|
if (!is_kair_window_infty(cur)) {
|
||
|
memset(cur->qtbl, 0, sizeof(int) * cur->qlvl);
|
||
|
|
||
|
tfifo_free(&cur->cache);
|
||
|
tfifo_alloc(&cur->cache, kair_window_size(cur));
|
||
|
|
||
|
cur->pc_cnt = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* """ KAIR default instance finalizer """
|
||
|
* Making the kair instance ready for the removal. for now, releasing resources
|
||
|
* occupied by the multi-leveled TPDF cascade structure.
|
||
|
**/
|
||
|
static void kair_finalizer(struct kair_class *self)
|
||
|
{
|
||
|
if (self->extif)
|
||
|
destroy_krinst_obj(self->extif);
|
||
|
|
||
|
kair_tpdf_cleaning(self);
|
||
|
}
|
||
|
|
||
|
/*.............................................................................
|
||
|
*.............................................................................
|
||
|
*................ """ KAIR Major External interfaces """ .....................
|
||
|
*.............................................................................
|
||
|
*...........................................................................*/
|
||
|
|
||
|
/**
|
||
|
* """ kair_obj_creator() """
|
||
|
* Creates an kair_class instance and returns the address.
|
||
|
**/
|
||
|
struct kair_class *kair_obj_creator(const char *alias,
|
||
|
unsigned int resilience,
|
||
|
unsigned int max_capa,
|
||
|
unsigned int min_capa,
|
||
|
struct kairistics *kairistic)
|
||
|
{
|
||
|
struct kair_class *vessel = kzalloc(sizeof(struct kair_class), GFP_ATOMIC);
|
||
|
|
||
|
if (!vessel)
|
||
|
return 0;
|
||
|
|
||
|
*vessel = (struct kair_class) {
|
||
|
.df_velocity = KAIR_UNDETERMINED,
|
||
|
.resilience = resilience,
|
||
|
.ep_ratio = KAIR_BALANCED_EP_RATIO,
|
||
|
.max_capa = max_capa,
|
||
|
.max_capa = min_capa,
|
||
|
.epsilon = 43000,
|
||
|
.kairistic = *kairistic,
|
||
|
|
||
|
.tpdf_cascade = LIST_HEAD_INIT(vessel->tpdf_cascade),
|
||
|
.capa_denom = 0,
|
||
|
.stats = {0, 0L, KAIR_DEF_RAND_NEUTRAL, 0},
|
||
|
|
||
|
.initializer = kair_initializer,
|
||
|
.stopper = kair_stopper,
|
||
|
.finalizer = kair_finalizer,
|
||
|
.job_learner = kair_job_probability_collapse,
|
||
|
.job_inferer = kair_search_nearest_job_tpdf,
|
||
|
.cap_bettor = kair_cap_soft_bettor
|
||
|
};
|
||
|
|
||
|
memcpy(&vessel->alias, alias, KAIR_ALIAS_LEN);
|
||
|
|
||
|
return vessel;
|
||
|
}
|
||
|
EXPORT_SYMBOL(kair_obj_creator);
|
||
|
|
||
|
/**
|
||
|
* """ kair_obj_destructor() """
|
||
|
* Releases the system resources occupied by the instance itself.
|
||
|
* @self : the target kair_class instance
|
||
|
**/
|
||
|
void kair_obj_destructor(struct kair_class *self)
|
||
|
{
|
||
|
kfree(self);
|
||
|
}
|
||
|
EXPORT_SYMBOL(kair_obj_destructor);
|