2012-02-11 19:08:41 +00:00
|
|
|
// (c) 2010 Thomas Schoebel-Theuer / 1&1 Internet AG
|
|
|
|
// (c) 2012 Thomas Schoebel-Theuer
|
|
|
|
|
|
|
|
#ifndef LIB_RANK_H
|
|
|
|
#define LIB_RANK_H
|
|
|
|
|
|
|
|
/* Generic round-robin scheduler based on ranking information.
|
|
|
|
*/
|
|
|
|
|
2012-10-15 14:35:36 +00:00
|
|
|
#define RKI_DUMMY INT_MIN
|
|
|
|
|
2012-02-11 19:08:41 +00:00
|
|
|
struct rank_info {
|
|
|
|
int rki_x;
|
|
|
|
int rki_y;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct rank_data {
|
|
|
|
// public readonly
|
|
|
|
int rkd_current_points;
|
|
|
|
// private
|
|
|
|
int rkd_tmp;
|
|
|
|
int rkd_got;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Ranking phase.
|
|
|
|
*
|
|
|
|
* Calls should follow the following usage pattern:
|
|
|
|
*
|
|
|
|
* ranking_start(...);
|
|
|
|
* for (...) {
|
|
|
|
* ranking_compute(&rkd[this_time], ...);
|
|
|
|
* // usually you need at least 1 call for each rkd[] element,
|
|
|
|
* // but you can call more often to include ranking information
|
|
|
|
* // from many different sources.
|
|
|
|
* // Note: instead / additionally, you may also use
|
|
|
|
* // ranking_add() or ranking_override().
|
|
|
|
* }
|
|
|
|
* ranking_stop(...);
|
|
|
|
*
|
|
|
|
* => now the new ranking values are computed and already active
|
|
|
|
* for the round-robin ranking_select() mechanism described below.
|
|
|
|
*
|
|
|
|
* Important: the rki[] array describes a ranking function at some
|
|
|
|
* example points (x_i,y_i) which must be ordered according to x_i
|
|
|
|
* in ascending order. And, of course, you need to supply at least
|
2012-10-15 14:35:36 +00:00
|
|
|
* two sample points (otherwise a linear function cannot
|
2012-02-11 19:08:41 +00:00
|
|
|
* be described).
|
2012-10-15 14:35:36 +00:00
|
|
|
* The array _must_ always end with a dummy record where the x_i has the
|
|
|
|
* value RKI_DUMMY.
|
2012-02-11 19:08:41 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
extern inline
|
|
|
|
void ranking_start(struct rank_data rkd[], int rkd_count)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < rkd_count; i++) {
|
|
|
|
rkd[i].rkd_tmp = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-15 14:35:36 +00:00
|
|
|
extern void ranking_compute(struct rank_data *rkd, const struct rank_info rki[], int x);
|
2012-02-11 19:08:41 +00:00
|
|
|
|
|
|
|
/* This may be used to (exceptionally) add some extra salt...
|
|
|
|
*/
|
|
|
|
extern inline
|
|
|
|
void ranking_add(struct rank_data *rkd, int y)
|
|
|
|
{
|
|
|
|
rkd->rkd_tmp += y;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This may be used to (exceptionally) override certain ranking values.
|
|
|
|
*/
|
|
|
|
extern inline
|
|
|
|
void ranking_override(struct rank_data *rkd, int y)
|
|
|
|
{
|
|
|
|
rkd->rkd_tmp = y;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern inline
|
|
|
|
void ranking_stop(struct rank_data rkd[], int rkd_count)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < rkd_count; i++) {
|
|
|
|
rkd[i].rkd_current_points = rkd[i].rkd_tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* This is a round-robin scheduler taking her weights
|
|
|
|
* from the previous ranking phase (the more ranking points,
|
|
|
|
* the more frequently a candidate will be selected).
|
|
|
|
*
|
|
|
|
* Typical usage pattern (independent from the above ranking phase
|
|
|
|
* usage pattern):
|
|
|
|
*
|
|
|
|
* while (__there_is_work_to_be_done(...)) {
|
|
|
|
* int winner = ranking_select(...);
|
|
|
|
* if (winner >= 0) {
|
|
|
|
* __do_something(winner);
|
|
|
|
* ranking_select_done(..., winner, 1); // or higher, winpoints >= 1 must hold
|
|
|
|
* }
|
|
|
|
* ...
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
extern int ranking_select(struct rank_data rkd[], int rkd_count);
|
|
|
|
|
|
|
|
extern inline
|
|
|
|
void ranking_select_done(struct rank_data rkd[], int winner, int win_points)
|
|
|
|
{
|
2012-10-15 14:35:36 +00:00
|
|
|
if (winner >= 0) {
|
|
|
|
if (win_points < 1)
|
|
|
|
win_points = 1;
|
|
|
|
rkd[winner].rkd_got += win_points;
|
|
|
|
}
|
2012-02-11 19:08:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|