#ifndef UCS_FRAG_LIST_H
#define UCS_FRAG_LIST_H
#include <ucs/debug/log.h>
#include <ucs/datastruct/queue.h>
#include <ucs/sys/math.h>
#include <ucs/stats/stats.h>
typedef enum {
UCS_FRAG_LIST_INSERT_FAST,
UCS_FRAG_LIST_INSERT_FIRST,
UCS_FRAG_LIST_INSERT_SLOW,
UCS_FRAG_LIST_INSERT_DUP,
UCS_FRAG_LIST_INSERT_READY,
UCS_FRAG_LIST_INSERT_FAIL
} ucs_frag_list_ooo_type_t;
typedef uint16_t ucs_frag_list_sn_t;
#define UCS_FRAG_LIST_SN_CMP UCS_CIRCULAR_COMPARE16
#define UCS_FRAG_LIST_NEXT_SN(sn) ((ucs_frag_list_sn_t)((sn)+1))
typedef struct ucs_frag_list_head {
ucs_queue_head_t list;
ucs_frag_list_sn_t first_sn;
ucs_frag_list_sn_t last_sn;
} ucs_frag_list_head_t;
typedef struct ucs_frag_list_elem_t {
ucs_queue_elem_t list;
ucs_frag_list_head_t head;
} ucs_frag_list_elem_t;
typedef struct ucs_frag_list {
ucs_queue_head_t list;
ucs_queue_head_t ready_list;
ucs_frag_list_sn_t head_sn;
unsigned elem_count;
unsigned list_count;
int max_holes;
UCS_STATS_NODE_DECLARE(stats)
#ifdef ENABLE_STATS
ucs_frag_list_sn_t prev_sn;
#endif
} ucs_frag_list_t;
enum {
UCS_FRAG_LIST_STAT_GAPS,
UCS_FRAG_LIST_STAT_GAP_LEN,
UCS_FRAG_LIST_STAT_GAP_OUT,
UCS_FRAG_LIST_STAT_BURSTS,
UCS_FRAG_LIST_STAT_BURST_LEN,
UCS_FRAG_LIST_STAT_LAST
};
ucs_status_t ucs_frag_list_init(ucs_frag_list_sn_t initial_sn, ucs_frag_list_t *frag_list,
int max_holes
UCS_STATS_ARG(ucs_stats_node_t *stats_parent));
void ucs_frag_list_cleanup(ucs_frag_list_t *head);
ucs_frag_list_ooo_type_t ucs_frag_list_insert_slow(ucs_frag_list_t *head,
ucs_frag_list_elem_t *elem,
ucs_frag_list_sn_t sn);
ucs_frag_list_elem_t *ucs_frag_list_pull_slow(ucs_frag_list_t *head);
void ucs_frag_list_dump(ucs_frag_list_t *head, int how);
static inline ucs_frag_list_sn_t ucs_frag_list_sn(ucs_frag_list_t *head)
{
return head->head_sn;
}
static inline void ucs_frag_list_sn_inc(ucs_frag_list_t *head)
{
head->head_sn++;
}
static inline unsigned ucs_frag_list_count(ucs_frag_list_t *head)
{
return head->elem_count;
}
static inline int ucs_frag_list_empty(ucs_frag_list_t *head)
{
return ucs_queue_is_empty(&head->list) && ucs_queue_is_empty(&head->ready_list);
}
static inline ucs_frag_list_ooo_type_t
ucs_frag_list_insert(ucs_frag_list_t *head, ucs_frag_list_elem_t *elem,
ucs_frag_list_sn_t sn)
{
#ifdef ENABLE_STATS
ucs_frag_list_ooo_type_t ret;
if (UCS_FRAG_LIST_SN_CMP(sn, >, head->head_sn)) {
if (UCS_FRAG_LIST_SN_CMP(head->prev_sn + 1, !=,sn)) {
UCS_STATS_UPDATE_COUNTER(head->stats, UCS_FRAG_LIST_STAT_BURSTS, 1);
} else if (ucs_unlikely(UCS_STATS_GET_COUNTER(head->stats, UCS_FRAG_LIST_STAT_BURST_LEN) == 0)) {
UCS_STATS_SET_COUNTER(head->stats, UCS_FRAG_LIST_STAT_BURSTS, 1);
}
UCS_STATS_UPDATE_COUNTER(head->stats, UCS_FRAG_LIST_STAT_BURST_LEN, 1);
head->prev_sn = sn;
}
#endif
if (ucs_likely(UCS_FRAG_LIST_SN_CMP(sn, ==, head->head_sn + 1) && (head->elem_count == 0))) {
head->head_sn = sn;
return UCS_FRAG_LIST_INSERT_FAST;
}
#ifdef ENABLE_STATS
ret = ucs_frag_list_insert_slow(head, elem, sn);
UCS_STATS_UPDATE_COUNTER(head->stats, UCS_FRAG_LIST_STAT_GAP_OUT,
ret != UCS_FRAG_LIST_INSERT_DUP ? head->list_count : 0);
return ret;
#else
return ucs_frag_list_insert_slow(head, elem, sn);
#endif
}
static inline ucs_frag_list_elem_t *ucs_frag_list_pull(ucs_frag_list_t *head)
{
if (!ucs_queue_is_empty(&head->ready_list)) {
--head->elem_count;
return ucs_queue_pull_elem_non_empty(&head->ready_list, ucs_frag_list_elem_t, list);
} else if (!ucs_queue_is_empty(&head->list)) {
return ucs_frag_list_pull_slow(head);
} else {
return NULL;
}
}
#endif