Skip to content
Snippets Groups Projects
Commit 8b744f43 authored by Vijay Pai's avatar Vijay Pai
Browse files

Merge pull request #5662 from ctiller/timer_list

Fix comparison direction - fixes timer_list_test flakiness
parents 76ee82c3 5f3ba8c8
Branches
Tags
No related merge requests found
/*
*
* Copyright 2015, Google Inc.
* Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -46,7 +46,7 @@
static void adjust_upwards(grpc_timer **first, uint32_t i, grpc_timer *t) {
while (i > 0) {
uint32_t parent = (uint32_t)(((int)i - 1) / 2);
if (gpr_time_cmp(first[parent]->deadline, t->deadline) >= 0) break;
if (gpr_time_cmp(first[parent]->deadline, t->deadline) <= 0) break;
first[i] = first[parent];
first[i]->heap_index = i;
i = parent;
......@@ -62,16 +62,14 @@ static void adjust_downwards(grpc_timer **first, uint32_t i, uint32_t length,
grpc_timer *t) {
for (;;) {
uint32_t left_child = 1u + 2u * i;
uint32_t right_child;
uint32_t next_i;
if (left_child >= length) break;
right_child = left_child + 1;
next_i = right_child < length &&
gpr_time_cmp(first[left_child]->deadline,
first[right_child]->deadline) < 0
? right_child
: left_child;
if (gpr_time_cmp(t->deadline, first[next_i]->deadline) >= 0) break;
uint32_t right_child = left_child + 1;
uint32_t next_i = right_child < length &&
gpr_time_cmp(first[left_child]->deadline,
first[right_child]->deadline) > 0
? right_child
: left_child;
if (gpr_time_cmp(t->deadline, first[next_i]->deadline) <= 0) break;
first[i] = first[next_i];
first[i]->heap_index = i;
i = next_i;
......@@ -95,7 +93,7 @@ static void maybe_shrink(grpc_timer_heap *heap) {
static void note_changed_priority(grpc_timer_heap *heap, grpc_timer *timer) {
uint32_t i = timer->heap_index;
uint32_t parent = (uint32_t)(((int)i - 1) / 2);
if (gpr_time_cmp(heap->timers[parent]->deadline, timer->deadline) < 0) {
if (gpr_time_cmp(heap->timers[parent]->deadline, timer->deadline) > 0) {
adjust_upwards(heap->timers, i, timer);
} else {
adjust_downwards(heap->timers, i, heap->timer_count, timer);
......
/*
*
* Copyright 2015, Google Inc.
* Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -38,6 +38,8 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/useful.h>
#include "test/core/util/test_config.h"
static gpr_timespec random_deadline(void) {
......@@ -57,79 +59,6 @@ static grpc_timer *create_test_elements(size_t num_elements) {
return elems;
}
static int cmp_elem(const void *a, const void *b) {
int i = *(const int *)a;
int j = *(const int *)b;
return i - j;
}
static size_t *all_top(grpc_timer_heap *pq, size_t *n) {
size_t *vec = NULL;
size_t *need_to_check_children;
size_t num_need_to_check_children = 0;
*n = 0;
if (pq->timer_count == 0) return vec;
need_to_check_children =
gpr_malloc(pq->timer_count * sizeof(*need_to_check_children));
need_to_check_children[num_need_to_check_children++] = 0;
vec = gpr_malloc(pq->timer_count * sizeof(*vec));
while (num_need_to_check_children > 0) {
size_t ind = need_to_check_children[0];
size_t leftchild, rightchild;
num_need_to_check_children--;
memmove(need_to_check_children, need_to_check_children + 1,
num_need_to_check_children * sizeof(*need_to_check_children));
vec[(*n)++] = ind;
leftchild = 1u + 2u * ind;
if (leftchild < pq->timer_count) {
if (gpr_time_cmp(pq->timers[leftchild]->deadline,
pq->timers[ind]->deadline) >= 0) {
need_to_check_children[num_need_to_check_children++] = leftchild;
}
rightchild = leftchild + 1;
if (rightchild < pq->timer_count &&
gpr_time_cmp(pq->timers[rightchild]->deadline,
pq->timers[ind]->deadline) >= 0) {
need_to_check_children[num_need_to_check_children++] = rightchild;
}
}
}
gpr_free(need_to_check_children);
return vec;
}
static void check_pq_top(grpc_timer *elements, grpc_timer_heap *pq,
uint8_t *inpq, size_t num_elements) {
gpr_timespec max_deadline = gpr_inf_past(GPR_CLOCK_REALTIME);
size_t *max_deadline_indices =
gpr_malloc(num_elements * sizeof(*max_deadline_indices));
size_t *top_elements;
size_t num_max_deadline_indices = 0;
size_t num_top_elements;
size_t i;
for (i = 0; i < num_elements; ++i) {
if (inpq[i] && gpr_time_cmp(elements[i].deadline, max_deadline) >= 0) {
if (gpr_time_cmp(elements[i].deadline, max_deadline) > 0) {
num_max_deadline_indices = 0;
max_deadline = elements[i].deadline;
}
max_deadline_indices[num_max_deadline_indices++] = elements[i].heap_index;
}
}
qsort(max_deadline_indices, num_max_deadline_indices,
sizeof(*max_deadline_indices), cmp_elem);
top_elements = all_top(pq, &num_top_elements);
GPR_ASSERT(num_top_elements == num_max_deadline_indices);
for (i = 0; i < num_top_elements; i++) {
GPR_ASSERT(max_deadline_indices[i] == top_elements[i]);
}
gpr_free(max_deadline_indices);
gpr_free(top_elements);
}
static int contains(grpc_timer_heap *pq, grpc_timer *el) {
size_t i;
for (i = 0; i < pq->timer_count; i++) {
......@@ -145,15 +74,19 @@ static void check_valid(grpc_timer_heap *pq) {
size_t right_child = left_child + 1u;
if (left_child < pq->timer_count) {
GPR_ASSERT(gpr_time_cmp(pq->timers[i]->deadline,
pq->timers[left_child]->deadline) >= 0);
pq->timers[left_child]->deadline) <= 0);
}
if (right_child < pq->timer_count) {
GPR_ASSERT(gpr_time_cmp(pq->timers[i]->deadline,
pq->timers[right_child]->deadline) >= 0);
pq->timers[right_child]->deadline) <= 0);
}
}
}
/*******************************************************************************
* test1
*/
static void test1(void) {
grpc_timer_heap pq;
const size_t num_test_elements = 200;
......@@ -162,6 +95,8 @@ static void test1(void) {
grpc_timer *test_elements = create_test_elements(num_test_elements);
uint8_t *inpq = gpr_malloc(num_test_elements);
gpr_log(GPR_INFO, "test1");
grpc_timer_heap_init(&pq);
memset(inpq, 0, num_test_elements);
GPR_ASSERT(grpc_timer_heap_is_empty(&pq));
......@@ -172,7 +107,6 @@ static void test1(void) {
check_valid(&pq);
GPR_ASSERT(contains(&pq, &test_elements[i]));
inpq[i] = 1;
check_pq_top(test_elements, &pq, inpq, num_test_elements);
}
for (i = 0; i < num_test_elements; ++i) {
/* Test that check still succeeds even for element that wasn't just
......@@ -182,7 +116,7 @@ static void test1(void) {
GPR_ASSERT(pq.timer_count == num_test_elements);
check_pq_top(test_elements, &pq, inpq, num_test_elements);
check_valid(&pq);
for (i = 0; i < num_test_operations; ++i) {
size_t elem_num = (size_t)rand() % num_test_elements;
......@@ -193,14 +127,12 @@ static void test1(void) {
grpc_timer_heap_add(&pq, el);
GPR_ASSERT(contains(&pq, el));
inpq[elem_num] = 1;
check_pq_top(test_elements, &pq, inpq, num_test_elements);
check_valid(&pq);
} else {
GPR_ASSERT(contains(&pq, el));
grpc_timer_heap_remove(&pq, el);
GPR_ASSERT(!contains(&pq, el));
inpq[elem_num] = 0;
check_pq_top(test_elements, &pq, inpq, num_test_elements);
check_valid(&pq);
}
}
......@@ -210,7 +142,108 @@ static void test1(void) {
gpr_free(inpq);
}
/*******************************************************************************
* test2
*/
typedef struct {
grpc_timer elem;
bool inserted;
} elem_struct;
static elem_struct *search_elems(elem_struct *elems, size_t count,
bool inserted) {
size_t *search_order = gpr_malloc(count * sizeof(*search_order));
for (size_t i = 0; i < count; i++) {
search_order[i] = i;
}
for (size_t i = 0; i < count * 2; i++) {
size_t a = (size_t)rand() % count;
size_t b = (size_t)rand() % count;
GPR_SWAP(size_t, search_order[a], search_order[b]);
}
elem_struct *out = NULL;
for (size_t i = 0; out == NULL && i < count; i++) {
if (elems[search_order[i]].inserted == inserted) {
out = &elems[search_order[i]];
}
}
gpr_free(search_order);
return out;
}
static void test2(void) {
gpr_log(GPR_INFO, "test2");
grpc_timer_heap pq;
elem_struct elems[1000];
size_t num_inserted = 0;
grpc_timer_heap_init(&pq);
memset(elems, 0, sizeof(elems));
for (size_t round = 0; round < 10000; round++) {
int r = rand() % 1000;
if (r <= 550) {
/* 55% of the time we try to add something */
elem_struct *el = search_elems(elems, GPR_ARRAY_SIZE(elems), false);
if (el != NULL) {
el->elem.deadline = random_deadline();
grpc_timer_heap_add(&pq, &el->elem);
el->inserted = true;
num_inserted++;
check_valid(&pq);
}
} else if (r <= 650) {
/* 10% of the time we try to remove something */
elem_struct *el = search_elems(elems, GPR_ARRAY_SIZE(elems), true);
if (el != NULL) {
grpc_timer_heap_remove(&pq, &el->elem);
el->inserted = false;
num_inserted--;
check_valid(&pq);
}
} else {
/* the remaining times we pop */
if (num_inserted > 0) {
grpc_timer *top = grpc_timer_heap_top(&pq);
grpc_timer_heap_pop(&pq);
for (size_t i = 0; i < GPR_ARRAY_SIZE(elems); i++) {
if (top == &elems[i].elem) {
GPR_ASSERT(elems[i].inserted);
elems[i].inserted = false;
}
}
num_inserted--;
check_valid(&pq);
}
}
if (num_inserted) {
gpr_timespec *min_deadline = NULL;
for (size_t i = 0; i < GPR_ARRAY_SIZE(elems); i++) {
if (elems[i].inserted) {
if (min_deadline == NULL) {
min_deadline = &elems[i].elem.deadline;
} else {
if (gpr_time_cmp(elems[i].elem.deadline, *min_deadline) < 0) {
min_deadline = &elems[i].elem.deadline;
}
}
}
}
GPR_ASSERT(
0 == gpr_time_cmp(grpc_timer_heap_top(&pq)->deadline, *min_deadline));
}
}
grpc_timer_heap_destroy(&pq);
}
static void shrink_test(void) {
gpr_log(GPR_INFO, "shrink_test");
grpc_timer_heap pq;
size_t i;
size_t expected_size;
......@@ -274,6 +307,7 @@ int main(int argc, char **argv) {
for (i = 0; i < 5; i++) {
test1();
test2();
shrink_test();
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment