From d069409282cf65b9723b32ca0096ec5ea8646522 Mon Sep 17 00:00:00 2001 From: komark06 Date: Fri, 8 Mar 2024 12:06:45 +0800 Subject: [PATCH 1/5] Implement multiple functions in queue Implement all interfaces of listed in queue.h. Currently, 'make test' won't pass may due to dudect implementation error. --- queue.c | 256 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 244 insertions(+), 12 deletions(-) diff --git a/queue.c b/queue.c index ce85f7d16..9e1f6a8ce 100644 --- a/queue.c +++ b/queue.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -10,50 +11,210 @@ * cppcheck-suppress nullPointer */ +typedef int (*list_cmp_func_t)(const struct list_head *, + const struct list_head *); + +/* Test if a queue is empty */ +static inline bool q_empty(struct list_head *head) +{ + if (!head || list_empty(head)) + return true; + return false; +} + +/* Initialize an element */ +static element_t *e_new(const char *s) +{ + if (!s) + return NULL; + element_t *e = malloc(sizeof(*e)); + if (!e) + return NULL; + size_t len = strlen(s) + 1; + e->value = malloc(len); + if (!e->value) { + free(e); + return NULL; + } + memcpy(e->value, s, len); + return e; +} + +/* Release an element */ +static inline void e_release(element_t *e) +{ + if (e) + q_release_element(e); +} + +/* Compare two elements. */ +static inline int e_compare(const struct list_head *a, + const struct list_head *b) +{ + return strcmp(list_entry(a, element_t, list)->value, + container_of(b, element_t, list)->value); +} + +/* Compare two elements in descending order. */ +static inline int e_compare_des(const struct list_head *a, + const struct list_head *b) +{ + return strcmp(list_entry(b, element_t, list)->value, + container_of(a, element_t, list)->value); +} + +/* Return compare function according to 'descend' */ +static inline list_cmp_func_t e_cmp_func(bool descend) +{ + if (descend) + return e_compare_des; + return e_compare; +} + +static struct list_head *merge_two_queue(struct list_head *L1, + struct list_head *L2, + list_cmp_func_t cmp) +{ + struct list_head *head = NULL, **ptr = &head; + for (struct list_head **cur = NULL; L1 && L2; *cur = (*cur)->next) { + if (cmp(L1, L2) >= 0) + cur = &L2; + else + cur = &L1; + *ptr = *cur; + ptr = &(*ptr)->next; + } + *ptr = (struct list_head *) (void *) ((uintptr_t) (void *) L1 | + (uintptr_t) (void *) L2); + return head; +} + +static struct list_head *merge_sort(struct list_head *head, list_cmp_func_t cmp) +{ + if (!head || !head->next) + return head; + struct list_head *slow = head, *fast = head->next; + for (; fast && fast->next; fast = fast->next->next, slow = slow->next) + ; + fast = slow->next; + slow->next = NULL; + return merge_two_queue(merge_sort(head, cmp), merge_sort(fast, cmp), cmp); +} + +/* Helper function for q_ascend and q_descend */ +static int q_remove_order(struct list_head *head, bool descend) +{ + if (!head) + return 0; + int len = 0; + list_cmp_func_t cmp = e_cmp_func(descend); + struct list_head *cur = head->prev; + while (cur != head) { + len++; + struct list_head *prev = cur->prev; + if (prev == head) + break; + if (cmp(cur, prev) < 0) { + list_del(prev); + e_release(list_entry(prev, element_t, list)); + len--; + } else { + cur = prev; + } + } + return len; +} /* Create an empty queue */ struct list_head *q_new() { - return NULL; + struct list_head *q = malloc(sizeof(*q)); + if (!q) + return NULL; + INIT_LIST_HEAD(q); + return q; } /* Free all storage used by queue */ -void q_free(struct list_head *head) {} +void q_free(struct list_head *head) +{ + if (!head) + return; + element_t *entry, *safe; + list_for_each_entry_safe (entry, safe, head, list) { + e_release(entry); + } + free(head); +} /* Insert an element at head of queue */ bool q_insert_head(struct list_head *head, char *s) { + if (!head) + return false; + element_t *e = e_new(s); + if (!e) + return false; + list_add(&e->list, head); return true; } /* Insert an element at tail of queue */ bool q_insert_tail(struct list_head *head, char *s) { - return true; + return q_insert_head(head->prev, s); } /* Remove an element from head of queue */ element_t *q_remove_head(struct list_head *head, char *sp, size_t bufsize) { - return NULL; + if (q_empty(head)) + return NULL; + element_t *e = list_first_entry(head, element_t, list); + list_del_init(&e->list); + if (!sp) + return e; + /* Copy the remove string to *sp */ + size_t len = strlen(e->value) + 1; + if (len > bufsize) + len = bufsize; + memcpy(sp, e->value, len); + sp[len - 1] = '\0'; + return e; } /* Remove an element from tail of queue */ element_t *q_remove_tail(struct list_head *head, char *sp, size_t bufsize) { - return NULL; + return q_remove_head(head->prev->prev, sp, bufsize); } /* Return number of elements in queue */ int q_size(struct list_head *head) { - return -1; + if (q_empty(head)) + return 0; + int size = 0; + struct list_head *node; + list_for_each (node, head) { + size++; + } + return size; } /* Delete the middle node in queue */ bool q_delete_mid(struct list_head *head) { // https://leetcode.com/problems/delete-the-middle-node-of-a-linked-list/ + if (q_empty(head)) + return false; + struct list_head *tail = head->prev, *fast = head->next, *slow = fast; + while (fast != tail && fast->next != tail) { + fast = fast->next->next; + slow = slow->next; + } + list_del(slow); + e_release(list_entry(slow, element_t, list)); return true; } @@ -61,6 +222,20 @@ bool q_delete_mid(struct list_head *head) bool q_delete_dup(struct list_head *head) { // https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/ + if (!head) + return false; + element_t *entry, *safe, *ready = NULL; + list_for_each_entry_safe (entry, safe, head, list) { + if (&safe->list != head && !strcmp(entry->value, safe->value)) { + list_del(&entry->list); + e_release(entry); + ready = safe; + } else if (ready) { + list_del(&ready->list); + e_release(ready); + ready = NULL; + } + } return true; } @@ -68,26 +243,71 @@ bool q_delete_dup(struct list_head *head) void q_swap(struct list_head *head) { // https://leetcode.com/problems/swap-nodes-in-pairs/ + if (!head) + return; + for (struct list_head **cur = &head->next; + *cur != head && (*cur)->next != head; cur = &(*cur)->next->next) { + struct list_head *first = *cur, *second = first->next; + first->next = second->next; + second->next = first; + second->prev = first->prev; + first->prev = second; + *cur = second; + } } /* Reverse elements in queue */ -void q_reverse(struct list_head *head) {} +void q_reverse(struct list_head *head) +{ + q_reverseK(head, q_size(head)); +} /* Reverse the nodes of the list k at a time */ void q_reverseK(struct list_head *head, int k) { // https://leetcode.com/problems/reverse-nodes-in-k-group/ + if (!head || k <= 1) + return; + LIST_HEAD(dummy); + int count = 0; + struct list_head *cur, *safe, *start = head; + list_for_each_safe (cur, safe, head) { + count++; + if (count == k) { + list_cut_position(&dummy, start, cur); + struct list_head *c, *s; + list_for_each_safe (c, s, &dummy) { + list_move(c, &dummy); + } + list_splice_init(&dummy, start); + count = 0; + start = safe->prev; + } + } } /* Sort elements of queue in ascending/descending order */ -void q_sort(struct list_head *head, bool descend) {} +void q_sort(struct list_head *head, bool descend) +{ + if (q_empty(head) || list_is_singular(head)) + return; + list_cmp_func_t cmp = e_cmp_func(descend); + head->prev->next = NULL; + head->next = merge_sort(head->next, cmp); + struct list_head *ptr = head; + for (; ptr->next; ptr = ptr->next) + ptr->next->prev = ptr; + ptr->next = head; + head->prev = ptr; +} + /* Remove every node which has a node with a strictly less value anywhere to * the right side of it */ int q_ascend(struct list_head *head) { // https://leetcode.com/problems/remove-nodes-from-linked-list/ - return 0; + return q_remove_order(head, false); } /* Remove every node which has a node with a strictly greater value anywhere to @@ -95,13 +315,25 @@ int q_ascend(struct list_head *head) int q_descend(struct list_head *head) { // https://leetcode.com/problems/remove-nodes-from-linked-list/ - return 0; + return q_remove_order(head, true); } /* Merge all the queues into one sorted queue, which is in ascending/descending * order */ int q_merge(struct list_head *head, bool descend) { - // https://leetcode.com/problems/merge-k-sorted-lists/ - return 0; + if (!head || list_empty(head)) + return 0; + queue_contex_t *fir = list_entry(head->next, queue_contex_t, chain); + if (head->next == head->prev) + return fir->size; + for (struct list_head *cur = head->next->next; cur != head; + cur = cur->next) { + queue_contex_t *que = list_entry(cur, queue_contex_t, chain); + list_splice_init(que->q, fir->q); + que->size = 0; + } + q_sort(fir->q, false); + fir->size = q_size(fir->q); + return fir->size; } From 05616ff4010e39bac3220daf56dcb6703164c833 Mon Sep 17 00:00:00 2001 From: komark06 Date: Fri, 8 Mar 2024 16:24:18 +0800 Subject: [PATCH 2/5] Replace function name for consistency --- queue.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/queue.c b/queue.c index 9e1f6a8ce..a3f55678b 100644 --- a/queue.c +++ b/queue.c @@ -52,7 +52,7 @@ static inline int e_compare(const struct list_head *a, const struct list_head *b) { return strcmp(list_entry(a, element_t, list)->value, - container_of(b, element_t, list)->value); + list_entry(b, element_t, list)->value); } /* Compare two elements in descending order. */ @@ -60,7 +60,7 @@ static inline int e_compare_des(const struct list_head *a, const struct list_head *b) { return strcmp(list_entry(b, element_t, list)->value, - container_of(a, element_t, list)->value); + list_entry(a, element_t, list)->value); } /* Return compare function according to 'descend' */ From c0ccf8924393f6608c528e9b577a6ea460f5e1fe Mon Sep 17 00:00:00 2001 From: komark06 Date: Fri, 8 Mar 2024 16:45:20 +0800 Subject: [PATCH 3/5] Refactor q_swap for code reuse Use q_reverseK to implement q_swap , so we can reuse code. --- queue.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/queue.c b/queue.c index a3f55678b..90bb0c83a 100644 --- a/queue.c +++ b/queue.c @@ -243,17 +243,7 @@ bool q_delete_dup(struct list_head *head) void q_swap(struct list_head *head) { // https://leetcode.com/problems/swap-nodes-in-pairs/ - if (!head) - return; - for (struct list_head **cur = &head->next; - *cur != head && (*cur)->next != head; cur = &(*cur)->next->next) { - struct list_head *first = *cur, *second = first->next; - first->next = second->next; - second->next = first; - second->prev = first->prev; - first->prev = second; - *cur = second; - } + q_reverseK(head, 2); } /* Reverse elements in queue */ From ef3cfa7e08369a68b7f2728fe8e24fef1a22a070 Mon Sep 17 00:00:00 2001 From: komark06 Date: Fri, 8 Mar 2024 17:01:16 +0800 Subject: [PATCH 4/5] Refactor q_reverse In order to save one walk through the queue, q_reverse does not rely on q_reverseK and q_size. --- queue.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/queue.c b/queue.c index 90bb0c83a..1b6f520d2 100644 --- a/queue.c +++ b/queue.c @@ -249,7 +249,11 @@ void q_swap(struct list_head *head) /* Reverse elements in queue */ void q_reverse(struct list_head *head) { - q_reverseK(head, q_size(head)); + if (!head) + return; + struct list_head *cur, *safe; + list_for_each_safe (cur, safe, head) + list_move(cur, head); } /* Reverse the nodes of the list k at a time */ From 16516c37c26fa1fef937ebd6265d3400c1273887 Mon Sep 17 00:00:00 2001 From: komark06 Date: Sat, 16 Mar 2024 13:11:08 +0800 Subject: [PATCH 5/5] Apply post-processing to each measurement In this commit, we enhance the post-processing of measurements by implementing a filtering mechanism to remove outliers. We discard measurements that exceed the specified percentile threshold 'p', thereby focusing on testing within a restricted distribution range, particularly in the lower cycle count tail. This approach is aimed at minimizing the influence of data-independent noise, particularly prevalent in the upper tail of the distribution. --- dudect/fixture.c | 89 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 79 insertions(+), 10 deletions(-) diff --git a/dudect/fixture.c b/dudect/fixture.c index 2f30291dd..bda335095 100644 --- a/dudect/fixture.c +++ b/dudect/fixture.c @@ -42,8 +42,16 @@ #define ENOUGH_MEASURE 10000 #define TEST_TRIES 10 +#define DUDECT_NUMBER_PERCENTILES (100) -static t_context_t *t; +/* perform this many tests in total: + - 1 first order uncropped test, + - DUDECT_NUMBER_PERCENTILES tests + - 1 second order test +*/ +#define DUDECT_TESTS (1 + DUDECT_NUMBER_PERCENTILES + 1) + +static t_context_t *ttest_ctxs[DUDECT_TESTS]; /* threshold values for Welch's t-test */ enum { @@ -64,7 +72,31 @@ static void differentiate(int64_t *exec_times, exec_times[i] = after_ticks[i] - before_ticks[i]; } -static void update_statistics(const int64_t *exec_times, uint8_t *classes) +static int cmp(const int64_t *a, const int64_t *b) +{ + return (int) (*a - *b); +} + +static int64_t percentile(int64_t *a_sorted, double which) +{ + size_t array_position = (size_t) ((double) N_MEASURES * (double) which); + assert(array_position < N_MEASURES); + return a_sorted[array_position]; +} +static void prepare_percentiles(int64_t *exec_times, int64_t *percentiles) +{ + qsort(exec_times, N_MEASURES, sizeof(int64_t), + (int (*)(const void *, const void *)) cmp); + for (size_t i = 0; i < DUDECT_NUMBER_PERCENTILES; i++) { + percentiles[i] = percentile( + exec_times, + 1 - (pow(0.5, 10 * (double) (i + 1) / DUDECT_NUMBER_PERCENTILES))); + } +} + +static void update_statistics(const int64_t *percentiles, + const int64_t *exec_times, + uint8_t *classes) { for (size_t i = 0; i < N_MEASURES; i++) { int64_t difference = exec_times[i]; @@ -73,12 +105,35 @@ static void update_statistics(const int64_t *exec_times, uint8_t *classes) continue; /* do a t-test on the execution time */ - t_push(t, difference, classes[i]); + t_push(ttest_ctxs[0], difference, classes[i]); + // t-test on cropped execution times, for several cropping thresholds. + for (size_t crop_index = 0; crop_index < DUDECT_NUMBER_PERCENTILES; + crop_index++) { + if (difference < percentiles[crop_index]) { + t_push(ttest_ctxs[crop_index + 1], difference, classes[i]); + } + } } } +static t_context_t *max_test() +{ + size_t ret = 0; + double max = 0; + for (size_t i = 0; i < DUDECT_TESTS; i++) { + if (ttest_ctxs[i]->n[0] > ENOUGH_MEASURE) { + double x = fabs(t_compute(ttest_ctxs[i])); + if (max < x) { + max = x; + ret = i; + } + } + } + return ttest_ctxs[ret]; +} static bool report(void) { + t_context_t *t = max_test(); double max_t = fabs(t_compute(t)); double number_traces_max_t = t->n[0] + t->n[1]; double max_tau = max_t / sqrt(number_traces_max_t); @@ -121,11 +176,13 @@ static bool doit(int mode) int64_t *before_ticks = calloc(N_MEASURES + 1, sizeof(int64_t)); int64_t *after_ticks = calloc(N_MEASURES + 1, sizeof(int64_t)); int64_t *exec_times = calloc(N_MEASURES, sizeof(int64_t)); + int64_t *percentiles = + (int64_t *) calloc(DUDECT_NUMBER_PERCENTILES, sizeof(int64_t)); uint8_t *classes = calloc(N_MEASURES, sizeof(uint8_t)); uint8_t *input_data = calloc(N_MEASURES * CHUNK_SIZE, sizeof(uint8_t)); if (!before_ticks || !after_ticks || !exec_times || !classes || - !input_data) { + !input_data || !percentiles) { die(); } @@ -133,7 +190,8 @@ static bool doit(int mode) bool ret = measure(before_ticks, after_ticks, input_data, mode); differentiate(exec_times, before_ticks, after_ticks); - update_statistics(exec_times, classes); + prepare_percentiles(exec_times, percentiles); + update_statistics(percentiles, exec_times, classes); ret &= report(); free(before_ticks); @@ -141,6 +199,7 @@ static bool doit(int mode) free(exec_times); free(classes); free(input_data); + free(percentiles); return ret; } @@ -148,13 +207,18 @@ static bool doit(int mode) static void init_once(void) { init_dut(); - t_init(t); + for (int i = 0; i < DUDECT_TESTS; i++) + t_init(ttest_ctxs[i]); } static bool test_const(char *text, int mode) { bool result = false; - t = malloc(sizeof(t_context_t)); + for (int i = 0; i < DUDECT_TESTS; i++) { + ttest_ctxs[i] = calloc(1, sizeof(t_context_t)); + assert(ttest_ctxs[i]); + t_init(ttest_ctxs[i]); + } for (int cnt = 0; cnt < TEST_TRIES; ++cnt) { printf("Testing %s...(%d/%d)\n\n", text, cnt, TEST_TRIES); @@ -166,12 +230,17 @@ static bool test_const(char *text, int mode) if (result) break; } - free(t); + for (int i = 0; i < DUDECT_TESTS; i++) { + free(ttest_ctxs[i]); + } return result; } -#define DUT_FUNC_IMPL(op) \ - bool is_##op##_const(void) { return test_const(#op, DUT(op)); } +#define DUT_FUNC_IMPL(op) \ + bool is_##op##_const(void) \ + { \ + return test_const(#op, DUT(op)); \ + } #define _(x) DUT_FUNC_IMPL(x) DUT_FUNCS