You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by so...@apache.org on 2014/08/01 22:44:18 UTC
[05/20] TS-2950: Initial commit of libck.
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/f098175e/lib/ck/regressions/ck_pr/validate/ck_pr_unary.c
----------------------------------------------------------------------
diff --git a/lib/ck/regressions/ck_pr/validate/ck_pr_unary.c b/lib/ck/regressions/ck_pr/validate/ck_pr_unary.c
new file mode 100644
index 0000000..b2300cd
--- /dev/null
+++ b/lib/ck/regressions/ck_pr/validate/ck_pr_unary.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2011 David Joseph.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ck_pr.h>
+
+#define REPEAT 2000000
+
+#define TEST_UNARY(K, S, M, T, P, D, H) \
+ static void \
+ test_##K##_##S(M *target) \
+ { \
+ *target = *target P 1; \
+ \
+ return; \
+ } \
+ static void \
+ test_##K##_##S##_zero(M *target, bool *zero) \
+ { \
+ *zero = *target == H; \
+ *target = *target P 1; \
+ \
+ return; \
+ } \
+ static void \
+ run_test_##K##_##S(bool use_zero) \
+ { \
+ int i; \
+ T x = 1, y = 1; \
+ bool zero_x = false, zero_y = false; \
+ \
+ use_zero ? puts("***TESTING ck_pr_"#K"_"#S"_zero***") \
+ : puts("***TESTING ck_pr_"#K"_"#S"***"); \
+ for (i = 0; i < REPEAT; ++i) { \
+ if (use_zero) { \
+ test_##K##_##S##_zero(&x, &zero_x); \
+ ck_pr_##K##_##S##_zero(&y, &zero_y); \
+ } \
+ else { \
+ test_##K##_##S(&x); \
+ ck_pr_##K##_##S(&y); \
+ } \
+ \
+ if (x != y || zero_x != zero_y) { \
+ printf("Serial(%"#D") and ck_pr(%"#D")" \
+ #K"_"#S" do not match.\n" \
+ "FAILURE.\n", \
+ x, y); \
+ \
+ return; \
+ } \
+ \
+ if (zero_x) \
+ printf("Variables are zero at iteration %d\n", i); \
+ } \
+ \
+ \
+ printf("\tserial_"#K"_"#S": %"#D"\n" \
+ "\tck_pr_"#K"_"#S": %"#D"\n" \
+ "SUCCESS.\n", \
+ x, y); \
+ \
+ return; \
+ }
+
+#define GENERATE_TEST(K, P, Y, Z) \
+ TEST_UNARY(K, int, int, int, P, d, Y) \
+ TEST_UNARY(K, uint, unsigned int, unsigned int, P, u, Z) \
+ static void \
+ run_test_##K(void) \
+ { \
+ run_test_##K##_int(false); \
+ run_test_##K##_int(true); \
+ run_test_##K##_uint(false); \
+ run_test_##K##_uint(true); \
+ }
+
+GENERATE_TEST(inc, +, -1, UINT_MAX)
+GENERATE_TEST(dec, -, 1, 1)
+
+#undef GENERATE_TEST
+#undef TEST_UNARY
+
+int
+main(void)
+{
+ run_test_inc();
+ run_test_dec();
+
+ return (0);
+}
+
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/f098175e/lib/ck/regressions/ck_pr/validate/ck_pr_xor.c
----------------------------------------------------------------------
diff --git a/lib/ck/regressions/ck_pr/validate/ck_pr_xor.c b/lib/ck/regressions/ck_pr/validate/ck_pr_xor.c
new file mode 100644
index 0000000..4515cc4
--- /dev/null
+++ b/lib/ck/regressions/ck_pr/validate/ck_pr_xor.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2009 Samy Al Bahra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <ck_pr.h>
+
+#include "../../common.h"
+#ifndef R_REPEAT
+#define R_REPEAT 200000
+#endif
+
+#define BM(m, w) ((uint##m##_t)-1 << (w))
+
+#define CK_PR_XOR_T(w, v, d) \
+ { \
+ uint##w##_t t = v; \
+ ck_pr_xor_##w(&t, d); \
+ if (t != (uint##w##_t)(v ^ d)) { \
+ printf("FAIL ["); \
+ printf("%" PRIu##w " (%" PRIu##w ") -> %" PRIu##w "]\n",\
+ (uint##w##_t)v, d, t); \
+ exit(EXIT_FAILURE); \
+ } \
+ }
+
+#define CK_PR_XOR_B(w) \
+ { \
+ unsigned int __ck_i = 0; \
+ printf("ck_pr_xor_" #w ": "); \
+ if (w < 10) \
+ printf(" "); \
+ for (__ck_i = 0; __ck_i < R_REPEAT; __ck_i++) { \
+ uint##w##_t a = (uint##w##_t)common_rand(); \
+ uint##w##_t b = (uint##w##_t)common_rand(); \
+ CK_PR_XOR_T(w, a, b); \
+ } \
+ rg_width(w); \
+ printf(" SUCCESS\n"); \
+ }
+
+#define CK_PR_XOR_W(m, w) \
+ { \
+ uint##m##_t t = -1; \
+ ck_pr_xor_##w((uint##w##_t *)(void *)&t, -1); \
+ if (t != BM(m, w)) { \
+ printf(" FAIL [%#" PRIx##m " != %#" PRIx##m "]\n", t, BM(m, w)); \
+ exit(EXIT_FAILURE); \
+ } \
+ }
+
+static void
+rg_width(int m)
+{
+
+ /* Other architectures are bi-endian. */
+#if !defined(__x86__) && !defined(__x86_64__)
+ return;
+#endif
+
+#ifdef CK_F_PR_XOR_64
+ if (m == 64) {
+#if defined(CK_F_PR_XOR_32)
+ CK_PR_XOR_W(64, 32);
+#endif
+#if defined(CK_PR_XOR_16)
+ CK_PR_XOR_W(64, 16);
+#endif
+#if defined(CK_PR_XOR_8)
+ CK_PR_XOR_W(64, 8);
+#endif
+ }
+#endif /* CK_PR_XOR_64 */
+
+#ifdef CK_F_PR_XOR_32
+ if (m == 32) {
+#if defined(CK_F_PR_XOR_16)
+ CK_PR_XOR_W(32, 16);
+#endif
+#if defined(CK_PR_XOR_8)
+ CK_PR_XOR_W(32, 8);
+#endif
+ }
+#endif /* CK_PR_XOR_32 */
+
+#if defined(CK_F_PR_XOR_16) && defined(CK_PR_XOR_8)
+ if (m == 16) {
+ CK_PR_XOR_W(16, 8);
+ }
+#endif /* CK_PR_XOR_16 && CK_PR_XOR_8 */
+
+ return;
+}
+
+int
+main(void)
+{
+
+ common_srand((unsigned int)getpid());
+
+#ifdef CK_F_PR_XOR_64
+ CK_PR_XOR_B(64);
+#endif
+
+#ifdef CK_F_PR_XOR_32
+ CK_PR_XOR_B(32);
+#endif
+
+#ifdef CK_F_PR_XOR_16
+ CK_PR_XOR_B(16);
+#endif
+
+#ifdef CK_F_PR_XOR_8
+ CK_PR_XOR_B(8);
+#endif
+
+ return (0);
+}
+
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/f098175e/lib/ck/regressions/ck_queue/validate/Makefile
----------------------------------------------------------------------
diff --git a/lib/ck/regressions/ck_queue/validate/Makefile b/lib/ck/regressions/ck_queue/validate/Makefile
new file mode 100644
index 0000000..d6be3dc
--- /dev/null
+++ b/lib/ck/regressions/ck_queue/validate/Makefile
@@ -0,0 +1,26 @@
+.PHONY: check clean distribution
+
+HEADER=../../../include/ck_queue.h
+OBJECTS=ck_list ck_slist ck_stailq
+
+all: $(OBJECTS)
+
+check: all
+ ./ck_list $(CORES) 5
+ ./ck_slist $(CORES) 5
+ ./ck_stailq $(CORES) 1000000
+
+ck_list: $(HEADER) ck_list.c
+ $(CC) $(CFLAGS) -o ck_list ck_list.c
+
+ck_slist: $(HEADER) ck_slist.c
+ $(CC) $(CFLAGS) -o ck_slist ck_slist.c
+
+ck_stailq: $(HEADER) ck_stailq.c
+ $(CC) $(CFLAGS) -o ck_stailq ck_stailq.c
+
+clean:
+ rm -rf *~ *.o $(OBJECTS) *.dSYM *.exe
+
+include ../../../build/regressions.build
+CFLAGS+=$(PTHREAD_CFLAGS) -D_GNU_SOURCE
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/f098175e/lib/ck/regressions/ck_queue/validate/ck_list.c
----------------------------------------------------------------------
diff --git a/lib/ck/regressions/ck_queue/validate/ck_list.c b/lib/ck/regressions/ck_queue/validate/ck_list.c
new file mode 100644
index 0000000..2a29480
--- /dev/null
+++ b/lib/ck/regressions/ck_queue/validate/ck_list.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2012-2014 Samy Al Bahra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <ck_queue.h>
+
+#include "../../common.h"
+
+struct test {
+ int value;
+ CK_LIST_ENTRY(test) list_entry;
+};
+static CK_LIST_HEAD(test_list, test) head = CK_LIST_HEAD_INITIALIZER(head);
+
+static int goal;
+
+static void
+test_foreach(void)
+{
+ struct test *n, *next, *safe;
+ int i, s = 0, j = 0, k = 0;
+
+ for (i = goal; i != 0; i = goal) {
+ s = 0;
+
+ CK_LIST_FOREACH(n, &head, list_entry) {
+ j++;
+ if (s == 0)
+ s = n->value;
+ else
+ s = s - 1;
+
+ if (n->value != s) {
+ ck_error("\nExpected %d, but got %d.\n",
+ s, n->value);
+ }
+
+ next = CK_LIST_NEXT(n, list_entry);
+ if (next != NULL && next->value != s - 1) {
+ ck_error("\nExpected %d, but got %d.\n",
+ s, next->value);
+ }
+
+ i--;
+ }
+
+ if (i == 0)
+ break;
+
+ s = 0;
+ CK_LIST_FOREACH_SAFE(n, &head, list_entry, safe) {
+ k++;
+
+ if (s == 0)
+ s = n->value;
+ else
+ s = s - 1;
+
+ if (n->value != s) {
+ ck_error("\nExpected %d, but got %d.\n",
+ s, n->value);
+ }
+
+ next = CK_LIST_NEXT(n, list_entry);
+ if (next != NULL && next->value != s - 1) {
+ ck_error("\nExpected %d, but got %d.\n",
+ s, next->value);
+ }
+
+ i--;
+ }
+
+ if (i == 0 || CK_LIST_EMPTY(&head) == true)
+ break;
+ }
+
+ fprintf(stderr, "(%d, %d) ", j, k);
+ return;
+}
+
+static void *
+execute(void *c)
+{
+
+ (void)c;
+ test_foreach();
+ return NULL;
+}
+
+int
+main(int argc, char *argv[])
+{
+ pthread_t *thread;
+ struct test *n, a, b;
+ struct test_list target;
+ int n_threads, i;
+
+ if (argc != 3) {
+ ck_error("Usage: %s <number of threads> <number of list entries>\n", argv[0]);
+ }
+
+ n_threads = atoi(argv[1]);
+ if (n_threads < 1) {
+ ck_error("ERROR: Number of threads must be >= 1.\n");
+ }
+
+ thread = malloc(sizeof(pthread_t) * n_threads);
+ assert(thread != NULL);
+
+ goal = atoi(argv[2]);
+ if (goal < 4) {
+ ck_error("ERROR: Number of entries must be >= 4.\n");
+ }
+
+ fprintf(stderr, "Beginning serial test...");
+ CK_LIST_INIT(&head);
+
+ for (i = 1; i <= goal; i++) {
+ n = malloc(sizeof *n);
+ assert(n != NULL);
+ n->value = i;
+ CK_LIST_INSERT_HEAD(&head, n, list_entry);
+ }
+
+ test_foreach();
+
+ for (i = 1; i <= goal; i++) {
+ n = CK_LIST_FIRST(&head);
+ CK_LIST_REMOVE(n, list_entry);
+ free(n);
+ }
+
+ CK_LIST_INSERT_HEAD(&head, &a, list_entry);
+ CK_LIST_INSERT_HEAD(&head, &b, list_entry);
+ CK_LIST_REMOVE(&a, list_entry);
+ if (CK_LIST_FIRST(&head) != &b)
+ ck_error("List is in invalid state.\n");
+ CK_LIST_REMOVE(&b, list_entry);
+
+ if (CK_LIST_EMPTY(&head) == false) {
+ ck_error("List is not empty after bulk removal.\n");
+ }
+
+ CK_LIST_INSERT_HEAD(&head, &a, list_entry);
+ CK_LIST_INSERT_AFTER(&a, &b, list_entry);
+
+ if (CK_LIST_NEXT(&b, list_entry) != NULL)
+ ck_error("Inserted item after last, it should not have no next.\n");
+
+ CK_LIST_INIT(&head);
+
+ CK_LIST_INSERT_HEAD(&head, &a, list_entry);
+ CK_LIST_INSERT_BEFORE(&a, &b, list_entry);
+
+ if (CK_LIST_NEXT(&b, list_entry) != &a)
+ ck_error("Inserted item before last, it should point to last.\n");
+
+ CK_LIST_INIT(&head);
+ fprintf(stderr, "done (success)\n");
+
+ fprintf(stderr, "Beginning parallel traversal...");
+
+ n = malloc(sizeof *n);
+ assert(n != NULL);
+ n->value = 1;
+ CK_LIST_INSERT_HEAD(&head, n, list_entry);
+
+ for (i = 0; i < n_threads; i++) {
+ int r = pthread_create(&thread[i], NULL, execute, NULL);
+ assert(r == 0);
+ }
+
+ for (i = 2; i <= goal; i++) {
+ volatile int j;
+
+ n = malloc(sizeof *n);
+ assert(n != NULL);
+ n->value = i;
+ CK_LIST_INSERT_HEAD(&head, n, list_entry);
+ for (j = 0; j <= 1000; j++);
+ }
+
+ for (i = 0; i < n_threads; i++)
+ pthread_join(thread[i], NULL);
+
+ for (i = 0; i < n_threads; i++) {
+ int r = pthread_create(&thread[i], NULL, execute, NULL);
+ assert(r == 0);
+ }
+
+ CK_LIST_MOVE(&target, &head, list_entry);
+
+ for (i = 1; i <= goal; i++) {
+ volatile int j;
+
+ if (CK_LIST_EMPTY(&target) == false) {
+ struct test *r = CK_LIST_FIRST(&target);
+ CK_LIST_REMOVE(r, list_entry);
+ }
+
+ for (j = 0; j <= 1000; j++);
+ }
+
+ for (i = 0; i < n_threads; i++)
+ pthread_join(thread[i], NULL);
+
+ fprintf(stderr, "done (success)\n");
+ return (0);
+}
+
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/f098175e/lib/ck/regressions/ck_queue/validate/ck_slist.c
----------------------------------------------------------------------
diff --git a/lib/ck/regressions/ck_queue/validate/ck_slist.c b/lib/ck/regressions/ck_queue/validate/ck_slist.c
new file mode 100644
index 0000000..a26fe81
--- /dev/null
+++ b/lib/ck/regressions/ck_queue/validate/ck_slist.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2012-2014 Samy Al Bahra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <ck_queue.h>
+
+#include "../../common.h"
+
+struct test {
+ int value;
+ CK_SLIST_ENTRY(test) list_entry;
+};
+static CK_SLIST_HEAD(test_list, test) head = CK_SLIST_HEAD_INITIALIZER(head);
+
+static int goal;
+
+static void
+test_foreach(void)
+{
+ struct test *n, *next, *safe;
+ int i, s = 0, j = 0, k = 0;
+
+ for (i = goal; i != 0; i = goal) {
+ s = 0;
+
+ CK_SLIST_FOREACH(n, &head, list_entry) {
+ j++;
+ if (s == 0)
+ s = n->value;
+ else
+ s = s - 1;
+
+ if (n->value != s) {
+ ck_error("\nExpected %d, but got %d.\n",
+ s, n->value);
+ }
+
+ next = CK_SLIST_NEXT(n, list_entry);
+ if (next != NULL && next->value != s - 1) {
+ ck_error("\nExpected %d, but got %d.\n",
+ s, next->value);
+ }
+
+ i--;
+ }
+
+ if (i == 0)
+ break;
+
+ s = 0;
+ CK_SLIST_FOREACH_SAFE(n, &head, list_entry, safe) {
+ k++;
+
+ if (s == 0)
+ s = n->value;
+ else
+ s = s - 1;
+
+ if (n->value != s) {
+ ck_error("\nExpected %d, but got %d.\n",
+ s, n->value);
+ }
+
+ next = CK_SLIST_NEXT(n, list_entry);
+ if (next != NULL && next->value != s - 1) {
+ ck_error("\nExpected %d, but got %d.\n",
+ s, next->value);
+ }
+
+ i--;
+ }
+
+ if (i == 0 || CK_SLIST_EMPTY(&head) == true)
+ break;
+ }
+
+ fprintf(stderr, "(%d, %d) ", j, k);
+ return;
+}
+
+static void *
+execute(void *c)
+{
+
+ (void)c;
+ test_foreach();
+ return NULL;
+}
+
+int
+main(int argc, char *argv[])
+{
+ pthread_t *thread;
+ struct test *n;
+ struct test_list target;
+ int n_threads, i;
+
+ if (argc != 3) {
+ ck_error("Usage: %s <number of threads> <number of list entries>\n", argv[0]);
+ }
+
+ n_threads = atoi(argv[1]);
+ if (n_threads < 1) {
+ ck_error("ERROR: Number of threads must be >= 1.\n");
+ }
+
+ thread = malloc(sizeof(pthread_t) * n_threads);
+ assert(thread != NULL);
+
+ goal = atoi(argv[2]);
+ if (goal < 4) {
+ ck_error("ERROR: Number of entries must be >= 4.\n");
+ }
+
+ fprintf(stderr, "Beginning serial test...");
+ CK_SLIST_INIT(&head);
+
+ for (i = 1; i <= goal; i++) {
+ n = malloc(sizeof *n);
+ assert(n != NULL);
+ n->value = i;
+ CK_SLIST_INSERT_HEAD(&head, n, list_entry);
+ }
+
+ test_foreach();
+
+ for (i = 1; i <= goal; i++) {
+ n = CK_SLIST_FIRST(&head);
+ CK_SLIST_REMOVE_HEAD(&head, list_entry);
+ free(n);
+ }
+
+ if (CK_SLIST_EMPTY(&head) == false) {
+ ck_error("List is not empty after bulk removal.\n");
+ }
+
+ fprintf(stderr, "done (success)\n");
+
+ fprintf(stderr, "Beginning parallel traversal...");
+
+ n = malloc(sizeof *n);
+ assert(n != NULL);
+ n->value = 1;
+ CK_SLIST_INSERT_HEAD(&head, n, list_entry);
+
+ for (i = 0; i < n_threads; i++) {
+ int r = pthread_create(&thread[i], NULL, execute, NULL);
+ assert(r == 0);
+ }
+
+ for (i = 2; i <= goal; i++) {
+ volatile int j;
+
+ n = malloc(sizeof *n);
+ assert(n != NULL);
+ n->value = i;
+ CK_SLIST_INSERT_HEAD(&head, n, list_entry);
+ for (j = 0; j <= 1000; j++);
+ }
+
+ for (i = 0; i < n_threads; i++)
+ pthread_join(thread[i], NULL);
+
+ for (i = 0; i < n_threads; i++) {
+ int r = pthread_create(&thread[i], NULL, execute, NULL);
+ assert(r == 0);
+ }
+
+ CK_SLIST_MOVE(&target, &head, list_entry);
+
+ for (i = 1; i <= goal; i++) {
+ volatile int j;
+
+ if (CK_SLIST_EMPTY(&target) == false)
+ CK_SLIST_REMOVE_HEAD(&target, list_entry);
+
+ for (j = 0; j <= 1000; j++);
+
+ if (CK_SLIST_EMPTY(&target) == false) {
+ struct test *r = CK_SLIST_FIRST(&target);
+ CK_SLIST_REMOVE(&target, r, test, list_entry);
+ }
+ }
+
+ for (i = 0; i < n_threads; i++)
+ pthread_join(thread[i], NULL);
+
+ fprintf(stderr, "done (success)\n");
+ return (0);
+}
+
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/f098175e/lib/ck/regressions/ck_queue/validate/ck_stailq.c
----------------------------------------------------------------------
diff --git a/lib/ck/regressions/ck_queue/validate/ck_stailq.c b/lib/ck/regressions/ck_queue/validate/ck_stailq.c
new file mode 100644
index 0000000..1fafb0e
--- /dev/null
+++ b/lib/ck/regressions/ck_queue/validate/ck_stailq.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2012-2014 Samy Al Bahra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <ck_queue.h>
+#include "../../common.h"
+
+struct test {
+ int value;
+ CK_STAILQ_ENTRY(test) list_entry;
+};
+static CK_STAILQ_HEAD(test_list, test) head = CK_STAILQ_HEAD_INITIALIZER(head);
+
+static int goal;
+
+static void
+test_foreach(void)
+{
+ struct test *n, *next, *safe;
+ int i, s = 0, j = 0, k = 0;
+
+ for (i = goal; i != 0; i = goal) {
+ s = 0;
+
+ CK_STAILQ_FOREACH(n, &head, list_entry) {
+ j++;
+ if (s == 0)
+ s = n->value;
+ else
+ s = s - 1;
+
+ if (n->value != s) {
+ ck_error("\nExpected %d, but got %d.\n",
+ s, n->value);
+ }
+
+ next = CK_STAILQ_NEXT(n, list_entry);
+ if (next != NULL && next->value != s - 1) {
+ ck_error("\nExpected %d, but got %d.\n",
+ s, next->value);
+ }
+
+ i--;
+ }
+
+ if (i == 0)
+ break;
+
+ s = 0;
+ CK_STAILQ_FOREACH_SAFE(n, &head, list_entry, safe) {
+ k++;
+
+ if (s == 0)
+ s = n->value;
+ else
+ s = s - 1;
+
+ if (n->value != s) {
+ ck_error("\nExpected %d, but got %d.\n",
+ s, n->value);
+ }
+
+ next = CK_STAILQ_NEXT(n, list_entry);
+ if (next != NULL && next->value != s - 1) {
+ ck_error("\nExpected %d, but got %d.\n",
+ s, next->value);
+ }
+
+ i--;
+ }
+
+ if (i == 0 || CK_STAILQ_EMPTY(&head) == true)
+ break;
+ }
+
+ fprintf(stderr, "(%d, %d) ", j, k);
+ return;
+}
+
+static void *
+execute(void *c)
+{
+
+ (void)c;
+ test_foreach();
+ return NULL;
+}
+
+int
+main(int argc, char *argv[])
+{
+ pthread_t *thread;
+ struct test *n, a, b;
+ struct test_list target;
+ int n_threads, i;
+
+ if (argc != 3) {
+ ck_error("Usage: %s <number of threads> <number of list entries>\n", argv[0]);
+ }
+
+ n_threads = atoi(argv[1]);
+ if (n_threads < 1) {
+ ck_error("ERROR: Number of threads must be >= 1.\n");
+ }
+
+ thread = malloc(sizeof(pthread_t) * n_threads);
+ assert(thread != NULL);
+
+ goal = atoi(argv[2]);
+ if (goal < 4) {
+ ck_error("ERROR: Number of entries must be >= 4.\n");
+ }
+
+ fprintf(stderr, "Beginning serial test...");
+ CK_STAILQ_INIT(&head);
+
+ for (i = 1; i <= goal; i++) {
+ n = malloc(sizeof *n);
+ assert(n != NULL);
+ n->value = i;
+ CK_STAILQ_INSERT_HEAD(&head, n, list_entry);
+ }
+
+ test_foreach();
+
+ for (i = 1; i <= goal; i++) {
+ n = CK_STAILQ_FIRST(&head);
+ CK_STAILQ_REMOVE(&head, n, test, list_entry);
+ free(n);
+ }
+
+ if (CK_STAILQ_EMPTY(&head) == false) {
+ ck_error("List is not empty after bulk removal.\n");
+ }
+
+ for (i = 1; i <= goal; i++) {
+ n = malloc(sizeof *n);
+ assert(n != NULL);
+ n->value = goal - i;
+ CK_STAILQ_INSERT_TAIL(&head, n, list_entry);
+ }
+
+ test_foreach();
+
+ for (i = 1; i <= goal; i++) {
+ n = CK_STAILQ_FIRST(&head);
+ CK_STAILQ_REMOVE(&head, n, test, list_entry);
+ free(n);
+ }
+
+ if (CK_STAILQ_EMPTY(&head) == false) {
+ ck_error("List is not empty after bulk removal.\n");
+ }
+
+ CK_STAILQ_INSERT_HEAD(&head, &a, list_entry);
+ CK_STAILQ_INSERT_HEAD(&head, &b, list_entry);
+ CK_STAILQ_REMOVE(&head, &a, test, list_entry);
+ if (CK_STAILQ_FIRST(&head) != &b)
+ ck_error("List is in invalid state.\n");
+ CK_STAILQ_REMOVE(&head, &b, test, list_entry);
+
+ if (CK_STAILQ_EMPTY(&head) == false) {
+ ck_error("List is not empty after bulk removal.\n");
+ }
+
+ CK_STAILQ_INSERT_HEAD(&head, &a, list_entry);
+ CK_STAILQ_INSERT_AFTER(&head, &a, &b, list_entry);
+
+ if (CK_STAILQ_NEXT(&b, list_entry) != NULL)
+ ck_error("Inserted item after last, it should not have no next.\n");
+
+ CK_STAILQ_INIT(&head);
+
+ CK_STAILQ_INSERT_HEAD(&head, &a, list_entry);
+ if (CK_STAILQ_NEXT(&a, list_entry) != NULL)
+ ck_error("Inserted item as last, but it contains next pointer.\n");
+
+ CK_STAILQ_INIT(&head);
+ fprintf(stderr, "done (success)\n");
+
+ fprintf(stderr, "Beginning parallel traversal...");
+
+ n = malloc(sizeof *n);
+ assert(n != NULL);
+ n->value = 1;
+ CK_STAILQ_INSERT_HEAD(&head, n, list_entry);
+
+ for (i = 0; i < n_threads; i++) {
+ int r = pthread_create(&thread[i], NULL, execute, NULL);
+ assert(r == 0);
+ }
+
+ for (i = 2; i <= goal; i++) {
+ volatile int j;
+
+ n = malloc(sizeof *n);
+ assert(n != NULL);
+ n->value = i;
+ CK_STAILQ_INSERT_HEAD(&head, n, list_entry);
+ for (j = 0; j <= 1000; j++);
+ }
+
+ for (i = 0; i < n_threads; i++)
+ pthread_join(thread[i], NULL);
+
+ for (i = 0; i < n_threads; i++) {
+ int r = pthread_create(&thread[i], NULL, execute, NULL);
+ assert(r == 0);
+ }
+
+ CK_STAILQ_MOVE(&target, &head, list_entry);
+
+ for (i = 1; i <= goal; i++) {
+ volatile int j;
+
+ if (CK_STAILQ_EMPTY(&target) == false) {
+ struct test *r = CK_STAILQ_FIRST(&target);
+ CK_STAILQ_REMOVE(&target, r, test, list_entry);
+ }
+
+ for (j = 0; j <= 1000; j++);
+ }
+
+ for (i = 0; i < n_threads; i++)
+ pthread_join(thread[i], NULL);
+
+ fprintf(stderr, "done (success)\n");
+ return (0);
+}
+
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/f098175e/lib/ck/regressions/ck_rhs/benchmark/Makefile
----------------------------------------------------------------------
diff --git a/lib/ck/regressions/ck_rhs/benchmark/Makefile b/lib/ck/regressions/ck_rhs/benchmark/Makefile
new file mode 100644
index 0000000..e997993
--- /dev/null
+++ b/lib/ck/regressions/ck_rhs/benchmark/Makefile
@@ -0,0 +1,17 @@
+.PHONY: clean distribution
+
+OBJECTS=serial parallel_bytestring
+
+all: $(OBJECTS)
+
+serial: serial.c ../../../include/ck_rhs.h ../../../src/ck_rhs.c
+ $(CC) $(CFLAGS) -o serial serial.c ../../../src/ck_rhs.c
+
+parallel_bytestring: parallel_bytestring.c ../../../include/ck_rhs.h ../../../src/ck_rhs.c ../../../src/ck_epoch.c
+ $(CC) $(PTHREAD_CFLAGS) $(CFLAGS) -o parallel_bytestring parallel_bytestring.c ../../../src/ck_rhs.c ../../../src/ck_epoch.c
+
+clean:
+ rm -rf *~ *.o $(OBJECTS) *.dSYM *.exe
+
+include ../../../build/regressions.build
+CFLAGS+=-D_GNU_SOURCE
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/f098175e/lib/ck/regressions/ck_rhs/benchmark/parallel_bytestring.c
----------------------------------------------------------------------
diff --git a/lib/ck/regressions/ck_rhs/benchmark/parallel_bytestring.c b/lib/ck/regressions/ck_rhs/benchmark/parallel_bytestring.c
new file mode 100644
index 0000000..f99cc89
--- /dev/null
+++ b/lib/ck/regressions/ck_rhs/benchmark/parallel_bytestring.c
@@ -0,0 +1,599 @@
+/*
+ * Copyright 2012 Samy Al Bahra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyrighs
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyrighs
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include "../../common.h"
+#include <ck_rhs.h>
+#include "../../../src/ck_ht_hash.h"
+#include <assert.h>
+#include <ck_epoch.h>
+#include <ck_malloc.h>
+#include <ck_pr.h>
+#include <ck_spinlock.h>
+
+#include <errno.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+static ck_rhs_t hs CK_CC_CACHELINE;
+static char **keys;
+static size_t keys_length = 0;
+static size_t keys_capacity = 128;
+static ck_epoch_t epoch_hs;
+static ck_epoch_record_t epoch_wr;
+static int n_threads;
+static bool next_stage;
+
+enum state {
+ HS_STATE_STOP = 0,
+ HS_STATE_GET,
+ HS_STATE_STRICT_REPLACEMENT,
+ HS_STATE_DELETION,
+ HS_STATE_REPLACEMENT,
+ HS_STATE_COUNT
+};
+
+static ck_spinlock_t mtx = CK_SPINLOCK_INITIALIZER;
+static struct affinity affinerator = AFFINITY_INITIALIZER;
+static uint64_t accumulator[HS_STATE_COUNT];
+static int barrier[HS_STATE_COUNT];
+static int state;
+
+struct hs_epoch {
+ ck_epoch_entry_t epoch_entry;
+};
+
+COMMON_ALARM_DECLARE_GLOBAL(hs_alarm, alarm_event, next_stage)
+
+static void
+alarm_handler(int s)
+{
+
+ (void)s;
+ next_stage = true;
+ return;
+}
+
+static unsigned long
+hs_hash(const void *object, unsigned long seed)
+{
+ const char *c = object;
+ unsigned long h;
+
+ h = (unsigned long)MurmurHash64A(c, strlen(c), seed);
+ return h;
+}
+
+static bool
+hs_compare(const void *previous, const void *compare)
+{
+
+ return strcmp(previous, compare) == 0;
+}
+
+static void
+hs_destroy(ck_epoch_entry_t *e)
+{
+
+ free(e);
+ return;
+}
+
+static void *
+hs_malloc(size_t r)
+{
+ ck_epoch_entry_t *b;
+
+ b = malloc(sizeof(*b) + r);
+ return b + 1;
+}
+
+static void
+hs_free(void *p, size_t b, bool r)
+{
+ struct hs_epoch *e = p;
+
+ (void)b;
+
+ if (r == true) {
+ /* Destruction requires safe memory reclamation. */
+ ck_epoch_call(&epoch_hs, &epoch_wr, &(--e)->epoch_entry, hs_destroy);
+ } else {
+ free(--e);
+ }
+
+ return;
+}
+
+static struct ck_malloc my_allocator = {
+ .malloc = hs_malloc,
+ .free = hs_free
+};
+
+static void
+set_init(void)
+{
+ unsigned int mode = CK_RHS_MODE_OBJECT | CK_RHS_MODE_SPMC;
+
+
+ ck_epoch_init(&epoch_hs);
+ ck_epoch_register(&epoch_hs, &epoch_wr);
+ common_srand48((long int)time(NULL));
+ if (ck_rhs_init(&hs, mode, hs_hash, hs_compare, &my_allocator, 65536, common_lrand48()) == false) {
+ perror("ck_rhs_init");
+ exit(EXIT_FAILURE);
+ }
+
+ return;
+}
+
+static bool
+set_remove(const char *value)
+{
+ unsigned long h;
+
+ h = CK_RHS_HASH(&hs, hs_hash, value);
+ return (bool)ck_rhs_remove(&hs, h, value);
+}
+
+static bool
+set_replace(const char *value)
+{
+ unsigned long h;
+ void *previous;
+
+ h = CK_RHS_HASH(&hs, hs_hash, value);
+ return ck_rhs_set(&hs, h, value, &previous);
+}
+
+static bool
+set_swap(const char *value)
+{
+ unsigned long h;
+ void *previous;
+
+ h = CK_RHS_HASH(&hs, hs_hash, value);
+ return ck_rhs_fas(&hs, h, value, &previous);
+}
+
+static void *
+set_get(const char *value)
+{
+ unsigned long h;
+ void *v;
+
+ h = CK_RHS_HASH(&hs, hs_hash, value);
+ v = ck_rhs_get(&hs, h, value);
+ return v;
+}
+
+static bool
+set_insert(const char *value)
+{
+ unsigned long h;
+
+ h = CK_RHS_HASH(&hs, hs_hash, value);
+ return ck_rhs_put(&hs, h, value);
+}
+
+static size_t
+set_count(void)
+{
+
+ return ck_rhs_count(&hs);
+}
+
+static bool
+set_reset(void)
+{
+
+ return ck_rhs_reset(&hs);
+}
+
+static void *
+reader(void *unused)
+{
+ size_t i;
+ ck_epoch_record_t epoch_record;
+ int state_previous = HS_STATE_STOP;
+ int n_state = 0;
+ uint64_t s, j, a;
+
+ (void)unused;
+ if (aff_iterate(&affinerator) != 0)
+ perror("WARNING: Failed to affine thread");
+
+ s = j = a = 0;
+ ck_epoch_register(&epoch_hs, &epoch_record);
+ for (;;) {
+ j++;
+ ck_epoch_begin(&epoch_hs, &epoch_record);
+ s = rdtsc();
+ for (i = 0; i < keys_length; i++) {
+ char *r;
+
+ r = set_get(keys[i]);
+ if (r == NULL) {
+ if (n_state == HS_STATE_STRICT_REPLACEMENT) {
+ ck_error("ERROR: Did not find during replacement: %s\n", keys[i]);
+ }
+
+ continue;
+ }
+
+ if (strcmp(r, keys[i]) == 0)
+ continue;
+
+ ck_error("ERROR: Found invalid value: [%s] but expected [%s]\n", (char *)r, keys[i]);
+ }
+ a += rdtsc() - s;
+ ck_epoch_end(&epoch_hs, &epoch_record);
+
+ n_state = ck_pr_load_int(&state);
+ if (n_state != state_previous) {
+ ck_spinlock_lock(&mtx);
+ accumulator[state_previous] += a / (j * keys_length);
+ ck_spinlock_unlock(&mtx);
+
+ ck_pr_inc_int(&barrier[state_previous]);
+ while (ck_pr_load_int(&barrier[state_previous]) != n_threads + 1)
+ ck_pr_stall();
+
+ state_previous = n_state;
+ s = j = a = 0;
+ }
+ }
+
+ return NULL;
+}
+
+static uint64_t
+acc(size_t i)
+{
+ uint64_t r;
+
+ ck_spinlock_lock(&mtx);
+ r = accumulator[i];
+ ck_spinlock_unlock(&mtx);
+
+ return r;
+}
+
+int
+main(int argc, char *argv[])
+{
+ FILE *fp;
+ char buffer[512];
+ size_t i, j, r;
+ unsigned int d = 0;
+ uint64_t s, e, a, repeated;
+ char **t;
+ pthread_t *readers;
+ double p_r, p_d;
+
+ COMMON_ALARM_DECLARE_LOCAL(hs_alarm, alarm_event)
+
+ r = 20;
+ s = 8;
+ p_d = 0.5;
+ p_r = 0.5;
+ n_threads = CORES - 1;
+
+ if (argc < 2) {
+ ck_error("Usage: parallel <dictionary> [<interval length> <initial size> <readers>\n"
+ " <probability of replacement> <probability of deletion> <epoch threshold>]\n");
+ }
+
+ if (argc >= 3)
+ r = atoi(argv[2]);
+
+ if (argc >= 4)
+ s = (uint64_t)atoi(argv[3]);
+
+ if (argc >= 5) {
+ n_threads = atoi(argv[4]);
+ if (n_threads < 1) {
+ ck_error("ERROR: Number of readers must be >= 1.\n");
+ }
+ }
+
+ if (argc >= 6) {
+ p_r = atof(argv[5]) / 100.00;
+ if (p_r < 0) {
+ ck_error("ERROR: Probability of replacement must be >= 0 and <= 100.\n");
+ }
+ }
+
+ if (argc >= 7) {
+ p_d = atof(argv[6]) / 100.00;
+ if (p_d < 0) {
+ ck_error("ERROR: Probability of deletion must be >= 0 and <= 100.\n");
+ }
+ }
+
+ COMMON_ALARM_INIT(hs_alarm, alarm_event, r)
+
+ affinerator.delta = 1;
+ readers = malloc(sizeof(pthread_t) * n_threads);
+ assert(readers != NULL);
+
+ keys = malloc(sizeof(char *) * keys_capacity);
+ assert(keys != NULL);
+
+ fp = fopen(argv[1], "r");
+ assert(fp != NULL);
+
+ while (fgets(buffer, sizeof(buffer), fp) != NULL) {
+ buffer[strlen(buffer) - 1] = '\0';
+ keys[keys_length++] = strdup(buffer);
+ assert(keys[keys_length - 1] != NULL);
+
+ if (keys_length == keys_capacity) {
+ t = realloc(keys, sizeof(char *) * (keys_capacity *= 2));
+ assert(t != NULL);
+ keys = t;
+ }
+ }
+
+ t = realloc(keys, sizeof(char *) * keys_length);
+ assert(t != NULL);
+ keys = t;
+
+ set_init();
+
+ for (i = 0; i < (size_t)n_threads; i++) {
+ if (pthread_create(&readers[i], NULL, reader, NULL) != 0) {
+ ck_error("ERROR: Failed to create thread %zu.\n", i);
+ }
+ }
+
+ for (i = 0; i < keys_length; i++)
+ d += set_insert(keys[i]) == false;
+
+ fprintf(stderr, " [S] %d readers, 1 writer.\n", n_threads);
+ fprintf(stderr, " [S] %zu entries stored and %u duplicates.\n\n",
+ set_count(), d);
+
+ fprintf(stderr, " ,- BASIC TEST\n");
+ fprintf(stderr, " | Executing SMR test...");
+ a = 0;
+ for (j = 0; j < r; j++) {
+ if (set_reset() == false) {
+ ck_error("ERROR: Failed to reset hash table.\n");
+ }
+
+ s = rdtsc();
+ for (i = 0; i < keys_length; i++)
+ d += set_insert(keys[i]) == false;
+ e = rdtsc();
+ a += e - s;
+ }
+ fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length));
+
+ fprintf(stderr, " | Executing replacement test...");
+ a = 0;
+ for (j = 0; j < r; j++) {
+ s = rdtsc();
+ for (i = 0; i < keys_length; i++)
+ set_replace(keys[i]);
+ e = rdtsc();
+ a += e - s;
+ }
+ fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length));
+
+ fprintf(stderr, " | Executing get test...");
+ a = 0;
+ for (j = 0; j < r; j++) {
+ s = rdtsc();
+ for (i = 0; i < keys_length; i++) {
+ if (set_get(keys[i]) == NULL) {
+ ck_error("ERROR: Unexpected NULL value.\n");
+ }
+ }
+ e = rdtsc();
+ a += e - s;
+ }
+ fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length));
+
+ a = 0;
+ fprintf(stderr, " | Executing removal test...");
+ for (j = 0; j < r; j++) {
+ s = rdtsc();
+ for (i = 0; i < keys_length; i++)
+ set_remove(keys[i]);
+ e = rdtsc();
+ a += e - s;
+
+ for (i = 0; i < keys_length; i++)
+ set_insert(keys[i]);
+ }
+ fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length));
+
+ fprintf(stderr, " | Executing negative look-up test...");
+ a = 0;
+ for (j = 0; j < r; j++) {
+ s = rdtsc();
+ for (i = 0; i < keys_length; i++) {
+ set_get("\x50\x03\x04\x05\x06\x10");
+ }
+ e = rdtsc();
+ a += e - s;
+ }
+ fprintf(stderr, "done (%" PRIu64 " ticks)\n", a / (r * keys_length));
+
+ ck_epoch_record_t epoch_temporary = epoch_wr;
+ ck_epoch_synchronize(&epoch_hs, &epoch_wr);
+
+ fprintf(stderr, " '- Summary: %u pending, %u peak, %lu reclamations -> "
+ "%u pending, %u peak, %lu reclamations\n\n",
+ epoch_temporary.n_pending, epoch_temporary.n_peak, epoch_temporary.n_dispatch,
+ epoch_wr.n_pending, epoch_wr.n_peak, epoch_wr.n_dispatch);
+
+ fprintf(stderr, " ,- READER CONCURRENCY\n");
+ fprintf(stderr, " | Executing reader test...");
+
+ ck_pr_store_int(&state, HS_STATE_GET);
+ while (ck_pr_load_int(&barrier[HS_STATE_STOP]) != n_threads)
+ ck_pr_stall();
+ ck_pr_inc_int(&barrier[HS_STATE_STOP]);
+ common_sleep(r);
+ ck_pr_store_int(&state, HS_STATE_STRICT_REPLACEMENT);
+ while (ck_pr_load_int(&barrier[HS_STATE_GET]) != n_threads)
+ ck_pr_stall();
+
+ fprintf(stderr, "done (reader = %" PRIu64 " ticks)\n",
+ acc(HS_STATE_GET) / n_threads);
+
+ fprintf(stderr, " | Executing strict replacement test...");
+
+ a = repeated = 0;
+ common_alarm(alarm_handler, &alarm_event, r);
+
+ ck_pr_inc_int(&barrier[HS_STATE_GET]);
+ for (;;) {
+ repeated++;
+ s = rdtsc();
+ for (i = 0; i < keys_length; i++) {
+ if (i & 1) {
+ set_replace(keys[i]);
+ } else {
+ set_swap(keys[i]);
+ }
+ }
+ e = rdtsc();
+ a += e - s;
+
+ if (next_stage == true) {
+ next_stage = false;
+ break;
+ }
+ }
+
+ ck_pr_store_int(&state, HS_STATE_DELETION);
+ while (ck_pr_load_int(&barrier[HS_STATE_STRICT_REPLACEMENT]) != n_threads)
+ ck_pr_stall();
+ set_reset();
+ ck_epoch_synchronize(&epoch_hs, &epoch_wr);
+ fprintf(stderr, "done (writer = %" PRIu64 " ticks, reader = %" PRIu64 " ticks)\n",
+ a / (repeated * keys_length), acc(HS_STATE_STRICT_REPLACEMENT) / n_threads);
+
+ common_alarm(alarm_handler, &alarm_event, r);
+
+ fprintf(stderr, " | Executing deletion test (%.2f)...", p_d * 100);
+ a = repeated = 0;
+ ck_pr_inc_int(&barrier[HS_STATE_STRICT_REPLACEMENT]);
+ for (;;) {
+ double delete;
+
+ repeated++;
+ s = rdtsc();
+ for (i = 0; i < keys_length; i++) {
+ set_insert(keys[i]);
+ if (p_d != 0.0) {
+ delete = common_drand48();
+ if (delete <= p_d)
+ set_remove(keys[i]);
+ }
+ }
+ e = rdtsc();
+ a += e - s;
+
+ if (next_stage == true) {
+ next_stage = false;
+ break;
+ }
+ }
+ ck_pr_store_int(&state, HS_STATE_REPLACEMENT);
+ while (ck_pr_load_int(&barrier[HS_STATE_DELETION]) != n_threads)
+ ck_pr_stall();
+
+ set_reset();
+ ck_epoch_synchronize(&epoch_hs, &epoch_wr);
+ fprintf(stderr, "done (writer = %" PRIu64 " ticks, reader = %" PRIu64 " ticks)\n",
+ a / (repeated * keys_length), acc(HS_STATE_DELETION) / n_threads);
+
+ common_alarm(alarm_handler, &alarm_event, r);
+
+ fprintf(stderr, " | Executing replacement test (%.2f)...", p_r * 100);
+ a = repeated = 0;
+ ck_pr_inc_int(&barrier[HS_STATE_DELETION]);
+ for (;;) {
+ double delete, replace;
+
+ repeated++;
+ s = rdtsc();
+ for (i = 0; i < keys_length; i++) {
+ set_insert(keys[i]);
+ if (p_d != 0.0) {
+ delete = common_drand48();
+ if (delete <= p_d)
+ set_remove(keys[i]);
+ } else {
+ delete = 0.0;
+ }
+
+ if (p_r != 0.0) {
+ replace = common_drand48();
+ if (replace <= p_r) {
+ if ((i & 1) || (delete <= p_d)) {
+ set_replace(keys[i]);
+ } else {
+ set_swap(keys[i]);
+ }
+ }
+ }
+ }
+ e = rdtsc();
+ a += e - s;
+
+ if (next_stage == true) {
+ next_stage = false;
+ break;
+ }
+ }
+ ck_pr_store_int(&state, HS_STATE_STOP);
+ while (ck_pr_load_int(&barrier[HS_STATE_REPLACEMENT]) != n_threads)
+ ck_pr_stall();
+ set_reset();
+ ck_epoch_synchronize(&epoch_hs, &epoch_wr);
+ fprintf(stderr, "done (writer = %" PRIu64 " ticks, reader = %" PRIu64 " ticks)\n",
+ a / (repeated * keys_length), acc(HS_STATE_REPLACEMENT) / n_threads);
+
+ ck_pr_inc_int(&barrier[HS_STATE_REPLACEMENT]);
+ epoch_temporary = epoch_wr;
+ ck_epoch_synchronize(&epoch_hs, &epoch_wr);
+
+ fprintf(stderr, " '- Summary: %u pending, %u peak, %lu reclamations -> "
+ "%u pending, %u peak, %lu reclamations\n\n",
+ epoch_temporary.n_pending, epoch_temporary.n_peak, epoch_temporary.n_dispatch,
+ epoch_wr.n_pending, epoch_wr.n_peak, epoch_wr.n_dispatch);
+ return 0;
+}
+
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/f098175e/lib/ck/regressions/ck_rhs/benchmark/serial.c
----------------------------------------------------------------------
diff --git a/lib/ck/regressions/ck_rhs/benchmark/serial.c b/lib/ck/regressions/ck_rhs/benchmark/serial.c
new file mode 100644
index 0000000..18fa892
--- /dev/null
+++ b/lib/ck/regressions/ck_rhs/benchmark/serial.c
@@ -0,0 +1,517 @@
+/*
+ * Copyright 2012 Samy Al Bahra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyrighs
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyrighs
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <ck_rhs.h>
+
+#include <assert.h>
+#include <ck_malloc.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "../../common.h"
+#include "../../../src/ck_ht_hash.h"
+
+static ck_rhs_t hs;
+static char **keys;
+static size_t keys_length = 0;
+static size_t keys_capacity = 128;
+static unsigned long global_seed;
+
+static void *
+hs_malloc(size_t r)
+{
+
+ return malloc(r);
+}
+
+static void
+hs_free(void *p, size_t b, bool r)
+{
+
+ (void)b;
+ (void)r;
+
+ free(p);
+
+ return;
+}
+
+static struct ck_malloc my_allocator = {
+ .malloc = hs_malloc,
+ .free = hs_free
+};
+
+static unsigned long
+hs_hash(const void *object, unsigned long seed)
+{
+ const char *c = object;
+ unsigned long h;
+
+ h = (unsigned long)MurmurHash64A(c, strlen(c), seed);
+ return h;
+}
+
+static bool
+hs_compare(const void *previous, const void *compare)
+{
+
+ return strcmp(previous, compare) == 0;
+}
+
+static void
+set_destroy(void)
+{
+
+ ck_rhs_destroy(&hs);
+ return;
+}
+
+static void
+set_init(unsigned int size, unsigned int mode)
+{
+
+ if (ck_rhs_init(&hs, CK_RHS_MODE_OBJECT | CK_RHS_MODE_SPMC | mode, hs_hash, hs_compare,
+ &my_allocator, size, global_seed) == false) {
+ perror("ck_rhs_init");
+ exit(EXIT_FAILURE);
+ }
+
+ return;
+}
+
+static bool
+set_remove(const char *value)
+{
+ unsigned long h;
+
+ h = CK_RHS_HASH(&hs, hs_hash, value);
+ return ck_rhs_remove(&hs, h, value) != NULL;
+}
+
+static bool
+set_swap(const char *value)
+{
+ unsigned long h;
+ void *previous;
+
+ h = CK_RHS_HASH(&hs, hs_hash, value);
+ return ck_rhs_fas(&hs, h, value, &previous);
+}
+
+static bool
+set_replace(const char *value)
+{
+ unsigned long h;
+ void *previous;
+
+ h = CK_RHS_HASH(&hs, hs_hash, value);
+ ck_rhs_set(&hs, h, value, &previous);
+ return previous != NULL;
+}
+
+static void *
+set_get(const char *value)
+{
+ unsigned long h;
+ void *v;
+
+ h = CK_RHS_HASH(&hs, hs_hash, value);
+ v = ck_rhs_get(&hs, h, value);
+ return v;
+}
+
+static bool
+set_insert(const char *value)
+{
+ unsigned long h;
+
+ h = CK_RHS_HASH(&hs, hs_hash, value);
+ return ck_rhs_put(&hs, h, value);
+}
+
+static bool
+set_insert_unique(const char *value)
+{
+ unsigned long h;
+
+ h = CK_RHS_HASH(&hs, hs_hash, value);
+ return ck_rhs_put_unique(&hs, h, value);
+}
+
+static size_t
+set_count(void)
+{
+
+ return ck_rhs_count(&hs);
+}
+
+static bool
+set_reset(void)
+{
+
+ return ck_rhs_reset(&hs);
+}
+
+static void
+set_gc(void)
+{
+
+ ck_rhs_gc(&hs);
+ return;
+}
+
+static void
+set_rebuild(void)
+{
+
+ ck_rhs_rebuild(&hs);
+ return;
+}
+
+static void
+keys_shuffle(char **k)
+{
+ size_t i, j;
+ char *t;
+
+ for (i = keys_length; i > 1; i--) {
+ j = rand() % (i - 1);
+
+ if (j != i - 1) {
+ t = k[i - 1];
+ k[i - 1] = k[j];
+ k[j] = t;
+ }
+ }
+
+ return;
+}
+
+static void
+run_test(const char *file, size_t r, unsigned int size, unsigned int mode)
+{
+ FILE *fp;
+ char buffer[512];
+ size_t i, j;
+ unsigned int d = 0;
+ uint64_t s, e, a, ri, si, ai, sr, rg, sg, ag, sd, ng, ss, sts, su, sgc, sb;
+ struct ck_rhs_stat st;
+ char **t;
+
+ keys = malloc(sizeof(char *) * keys_capacity);
+ assert(keys != NULL);
+
+ fp = fopen(file, "r");
+ assert(fp != NULL);
+
+ while (fgets(buffer, sizeof(buffer), fp) != NULL) {
+ buffer[strlen(buffer) - 1] = '\0';
+ keys[keys_length++] = strdup(buffer);
+ assert(keys[keys_length - 1] != NULL);
+
+ if (keys_length == keys_capacity) {
+ t = realloc(keys, sizeof(char *) * (keys_capacity *= 2));
+ assert(t != NULL);
+ keys = t;
+ }
+ }
+
+ t = realloc(keys, sizeof(char *) * keys_length);
+ assert(t != NULL);
+ keys = t;
+
+ set_init(size, mode);
+ for (i = 0; i < keys_length; i++)
+ d += set_insert(keys[i]) == false;
+ ck_rhs_stat(&hs, &st);
+
+ fprintf(stderr, "# %zu entries stored, %u duplicates, %u probe.\n",
+ set_count(), d, st.probe_maximum);
+
+ a = 0;
+ for (j = 0; j < r; j++) {
+ if (set_reset() == false) {
+ ck_error("ERROR: Failed to reset hash table.\n");
+ }
+
+ s = rdtsc();
+ for (i = keys_length; i > 0; i--)
+ d += set_insert(keys[i - 1]) == false;
+ e = rdtsc();
+ a += e - s;
+ }
+ ri = a / (r * keys_length);
+
+ a = 0;
+ for (j = 0; j < r; j++) {
+ if (set_reset() == false) {
+ ck_error("ERROR: Failed to reset hash table.\n");
+ }
+
+ s = rdtsc();
+ for (i = 0; i < keys_length; i++)
+ d += set_insert(keys[i]) == false;
+ e = rdtsc();
+ a += e - s;
+ }
+ si = a / (r * keys_length);
+
+ a = 0;
+ for (j = 0; j < r; j++) {
+ keys_shuffle(keys);
+
+ if (set_reset() == false) {
+ ck_error("ERROR: Failed to reset hash table.\n");
+ }
+
+ s = rdtsc();
+ for (i = 0; i < keys_length; i++)
+ d += set_insert(keys[i]) == false;
+ e = rdtsc();
+ a += e - s;
+ }
+ ai = a / (r * keys_length);
+
+ a = 0;
+ for (j = 0; j < r; j++) {
+ s = rdtsc();
+ for (i = 0; i < keys_length; i++)
+ set_swap(keys[i]);
+ e = rdtsc();
+ a += e - s;
+ }
+ ss = a / (r * keys_length);
+
+ a = 0;
+ for (j = 0; j < r; j++) {
+ s = rdtsc();
+ for (i = 0; i < keys_length; i++)
+ set_replace(keys[i]);
+ e = rdtsc();
+ a += e - s;
+ }
+ sr = a / (r * keys_length);
+
+ set_reset();
+ for (i = 0; i < keys_length; i++)
+ set_insert(keys[i]);
+
+ a = 0;
+ for (j = 0; j < r; j++) {
+ s = rdtsc();
+ for (i = keys_length; i > 0; i--) {
+ if (set_get(keys[i - 1]) == NULL) {
+ ck_error("ERROR: Unexpected NULL value.\n");
+ }
+ }
+ e = rdtsc();
+ a += e - s;
+ }
+ rg = a / (r * keys_length);
+
+ a = 0;
+ for (j = 0; j < r; j++) {
+ s = rdtsc();
+ for (i = 0; i < keys_length; i++) {
+ if (set_get(keys[i]) == NULL) {
+ ck_error("ERROR: Unexpected NULL value.\n");
+ }
+ }
+ e = rdtsc();
+ a += e - s;
+ }
+ sg = a / (r * keys_length);
+
+ a = 0;
+ for (j = 0; j < r; j++) {
+ keys_shuffle(keys);
+
+ s = rdtsc();
+ for (i = 0; i < keys_length; i++) {
+ if (set_get(keys[i]) == NULL) {
+ ck_error("ERROR: Unexpected NULL value.\n");
+ }
+ }
+ e = rdtsc();
+ a += e - s;
+ }
+ ag = a / (r * keys_length);
+
+ a = 0;
+ for (j = 0; j < r; j++) {
+ s = rdtsc();
+ for (i = 0; i < keys_length; i++)
+ set_remove(keys[i]);
+ e = rdtsc();
+ a += e - s;
+
+ for (i = 0; i < keys_length; i++)
+ set_insert(keys[i]);
+ }
+ sd = a / (r * keys_length);
+
+ a = 0;
+ for (j = 0; j < r; j++) {
+ s = rdtsc();
+ for (i = 0; i < keys_length; i++) {
+ set_get("\x50\x03\x04\x05\x06\x10");
+ }
+ e = rdtsc();
+ a += e - s;
+ }
+ ng = a / (r * keys_length);
+
+ set_reset();
+ for (i = 0; i < keys_length; i++)
+ set_insert(keys[i]);
+ for (i = 0; i < keys_length; i++)
+ set_remove(keys[i]);
+
+ a = 0;
+ for (j = 0; j < r; j++) {
+ s = rdtsc();
+ for (i = 0; i < keys_length; i++)
+ set_insert(keys[i]);
+ e = rdtsc();
+ a += e - s;
+
+ for (i = 0; i < keys_length; i++)
+ set_remove(keys[i]);
+ }
+ sts = a / (r * keys_length);
+
+ set_reset();
+
+ /* Prune duplicates. */
+ for (i = 0; i < keys_length; i++) {
+ if (set_insert(keys[i]) == true)
+ continue;
+
+ free(keys[i]);
+ keys[i] = keys[--keys_length];
+ }
+
+ for (i = 0; i < keys_length; i++)
+ set_remove(keys[i]);
+
+ a = 0;
+ for (j = 0; j < r; j++) {
+ s = rdtsc();
+ for (i = 0; i < keys_length; i++)
+ set_insert_unique(keys[i]);
+ e = rdtsc();
+ a += e - s;
+
+ for (i = 0; i < keys_length; i++)
+ set_remove(keys[i]);
+ }
+ su = a / (r * keys_length);
+
+ for (i = 0; i < keys_length; i++)
+ set_insert_unique(keys[i]);
+
+ for (i = 0; i < keys_length / 2; i++)
+ set_remove(keys[i]);
+
+ a = 0;
+ for (j = 0; j < r; j++) {
+ s = rdtsc();
+ set_gc();
+ e = rdtsc();
+ a += e - s;
+ }
+ sgc = a / r;
+
+ a = 0;
+ for (j = 0; j < r; j++) {
+ s = rdtsc();
+ set_rebuild();
+ e = rdtsc();
+ a += e - s;
+ }
+ sb = a / r;
+
+ printf("%zu "
+ "%" PRIu64 " "
+ "%" PRIu64 " "
+ "%" PRIu64 " "
+ "%" PRIu64 " "
+ "%" PRIu64 " "
+ "%" PRIu64 " "
+ "%" PRIu64 " "
+ "%" PRIu64 " "
+ "%" PRIu64 " "
+ "%" PRIu64 " "
+ "%" PRIu64 " "
+ "%" PRIu64 " "
+ "%" PRIu64 " "
+ "%" PRIu64 "\n",
+ keys_length, ri, si, ai, ss, sr, rg, sg, ag, sd, ng, sts, su, sgc, sb);
+
+ fclose(fp);
+
+ for (i = 0; i < keys_length; i++) {
+ free(keys[i]);
+ }
+
+ free(keys);
+ keys_length = 0;
+ set_destroy();
+ return;
+}
+
+int
+main(int argc, char *argv[])
+{
+ unsigned int r, size;
+
+ common_srand48((long int)time(NULL));
+ if (argc < 2) {
+ ck_error("Usage: ck_rhs <dictionary> [<repetitions> <initial size>]\n");
+ }
+
+ r = 16;
+ if (argc >= 3)
+ r = atoi(argv[2]);
+
+ size = 8;
+ if (argc >= 4)
+ size = atoi(argv[3]);
+
+ global_seed = common_lrand48();
+ run_test(argv[1], r, size, 0);
+ run_test(argv[1], r, size, CK_RHS_MODE_READ_MOSTLY);
+ fprintf(stderr, "# reverse_insertion serial_insertion random_insertion serial_swap "
+ "serial_replace reverse_get serial_get random_get serial_remove negative_get tombstone "
+ "set_unique gc rebuild\n\n");
+
+ return 0;
+}
+
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/f098175e/lib/ck/regressions/ck_rhs/validate/Makefile
----------------------------------------------------------------------
diff --git a/lib/ck/regressions/ck_rhs/validate/Makefile b/lib/ck/regressions/ck_rhs/validate/Makefile
new file mode 100644
index 0000000..5987395
--- /dev/null
+++ b/lib/ck/regressions/ck_rhs/validate/Makefile
@@ -0,0 +1,17 @@
+.PHONY: check clean distribution
+
+OBJECTS=serial
+
+all: $(OBJECTS)
+
+serial: serial.c ../../../include/ck_rhs.h ../../../src/ck_rhs.c
+ $(CC) $(CFLAGS) -o serial serial.c ../../../src/ck_rhs.c
+
+check: all
+ ./serial
+
+clean:
+ rm -rf *~ *.o $(OBJECTS) *.dSYM *.exe
+
+include ../../../build/regressions.build
+CFLAGS+=-D_GNU_SOURCE
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/f098175e/lib/ck/regressions/ck_rhs/validate/serial.c
----------------------------------------------------------------------
diff --git a/lib/ck/regressions/ck_rhs/validate/serial.c b/lib/ck/regressions/ck_rhs/validate/serial.c
new file mode 100644
index 0000000..1dc4db1
--- /dev/null
+++ b/lib/ck/regressions/ck_rhs/validate/serial.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2012 Samy Al Bahra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyrighs
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyrighs
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <ck_rhs.h>
+
+#include <assert.h>
+#include <ck_malloc.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../../common.h"
+
+static void *
+hs_malloc(size_t r)
+{
+
+ return malloc(r);
+}
+
+static void
+hs_free(void *p, size_t b, bool r)
+{
+
+ (void)b;
+ (void)r;
+ free(p);
+ return;
+}
+
+static struct ck_malloc my_allocator = {
+ .malloc = hs_malloc,
+ .free = hs_free
+};
+
+const char *test[] = { "Samy", "Al", "Bahra", "dances", "in", "the", "wind.", "Once",
+ "upon", "a", "time", "his", "gypsy", "ate", "one", "itsy",
+ "bitsy", "spider.", "What", "goes", "up", "must",
+ "come", "down.", "What", "is", "down", "stays",
+ "down.", "A", "B", "C", "D", "E", "F", "G", "H",
+ "I", "J", "K", "L", "M", "N", "O", "P", "Q" };
+
+const char *negative = "negative";
+
+/* Purposefully crappy hash function. */
+static unsigned long
+hs_hash(const void *object, unsigned long seed)
+{
+ const char *c = object;
+ unsigned long h;
+
+ (void)seed;
+ h = c[0];
+ return h;
+}
+
+static bool
+hs_compare(const void *previous, const void *compare)
+{
+
+ return strcmp(previous, compare) == 0;
+}
+
+static void
+run_test(unsigned int is, unsigned int ad)
+{
+ ck_rhs_t hs[16];
+ const size_t size = sizeof(hs) / sizeof(*hs);
+ size_t i, j;
+ const char *blob = "#blobs";
+ unsigned long h;
+
+ if (ck_rhs_init(&hs[0], CK_RHS_MODE_SPMC | CK_RHS_MODE_OBJECT | ad, hs_hash, hs_compare, &my_allocator, is, 6602834) == false)
+ ck_error("ck_rhs_init\n");
+
+ for (j = 0; j < size; j++) {
+ for (i = 0; i < sizeof(test) / sizeof(*test); i++) {
+ h = test[i][0];
+ if (ck_rhs_get(&hs[j], h, test[i]) != NULL) {
+ continue;
+ }
+
+ if (ck_rhs_put_unique(&hs[j], h, test[i]) == false)
+ ck_error("ERROR [%zu]: Failed to insert unique (%s)\n", j, test[i]);
+
+ if (ck_rhs_remove(&hs[j], h, test[i]) == false)
+ ck_error("ERROR [%zu]: Failed to remove unique (%s)\n", j, test[i]);
+
+ break;
+ }
+
+ for (i = 0; i < sizeof(test) / sizeof(*test); i++) {
+ h = test[i][0];
+ ck_rhs_put(&hs[j], h, test[i]);
+ if (ck_rhs_put(&hs[j], h, test[i]) == true) {
+ ck_error("ERROR [%u] [1]: put must fail on collision (%s).\n", is, test[i]);
+ }
+ if (ck_rhs_get(&hs[j], h, test[i]) == NULL) {
+ ck_error("ERROR [%u]: get must not fail after put\n", is);
+ }
+ }
+
+ /* Test grow semantics. */
+ ck_rhs_grow(&hs[j], 128);
+ for (i = 0; i < sizeof(test) / sizeof(*test); i++) {
+ h = test[i][0];
+ if (ck_rhs_put(&hs[j], h, test[i]) == true) {
+ ck_error("ERROR [%u] [2]: put must fail on collision.\n", is);
+ }
+
+ if (ck_rhs_get(&hs[j], h, test[i]) == NULL) {
+ ck_error("ERROR [%u]: get must not fail\n", is);
+ }
+ }
+
+ h = blob[0];
+ if (ck_rhs_get(&hs[j], h, blob) == NULL) {
+ if (j > 0)
+ ck_error("ERROR [%u]: Blob must always exist after first.\n", is);
+
+ if (ck_rhs_put(&hs[j], h, blob) == false) {
+ ck_error("ERROR [%u]: A unique blob put failed.\n", is);
+ }
+ } else {
+ if (ck_rhs_put(&hs[j], h, blob) == true) {
+ ck_error("ERROR [%u]: Duplicate blob put succeeded.\n", is);
+ }
+ }
+
+ /* Grow set and check get semantics. */
+ ck_rhs_grow(&hs[j], 512);
+ for (i = 0; i < sizeof(test) / sizeof(*test); i++) {
+ h = test[i][0];
+ if (ck_rhs_get(&hs[j], h, test[i]) == NULL) {
+ ck_error("ERROR [%u]: get must not fail\n", is);
+ }
+ }
+
+ /* Delete and check negative membership. */
+ for (i = 0; i < sizeof(test) / sizeof(*test); i++) {
+ void *r;
+
+ h = test[i][0];
+ if (ck_rhs_get(&hs[j], h, test[i]) == NULL)
+ continue;
+
+ if (r = ck_rhs_remove(&hs[j], h, test[i]), r == NULL) {
+ ck_error("ERROR [%u]: remove must not fail\n", is);
+ }
+
+ if (strcmp(r, test[i]) != 0) {
+ ck_error("ERROR [%u]: Removed incorrect node (%s != %s)\n", (char *)r, test[i], is);
+ }
+ }
+
+ /* Test replacement semantics. */
+ for (i = 0; i < sizeof(test) / sizeof(*test); i++) {
+ void *r;
+ bool d;
+
+ h = test[i][0];
+ d = ck_rhs_get(&hs[j], h, test[i]) != NULL;
+ if (ck_rhs_set(&hs[j], h, test[i], &r) == false) {
+ ck_error("ERROR [%u]: Failed to set\n", is);
+ }
+
+ /* Expected replacement. */
+ if (d == true && (r == NULL || strcmp(r, test[i]) != 0)) {
+ ck_error("ERROR [%u]: Incorrect previous value: %s != %s\n",
+ is, test[i], (char *)r);
+ }
+
+ /* Replacement should succeed. */
+ if (ck_rhs_fas(&hs[j], h, test[i], &r) == false)
+ ck_error("ERROR [%u]: ck_rhs_fas must succeed.\n", is);
+
+ if (strcmp(r, test[i]) != 0) {
+ ck_error("ERROR [%u]: Incorrect replaced value: %s != %s\n",
+ is, test[i], (char *)r);
+ }
+
+ if (ck_rhs_fas(&hs[j], h, negative, &r) == true)
+ ck_error("ERROR [%u]: Replacement of negative should fail.\n", is);
+
+ if (ck_rhs_set(&hs[j], h, test[i], &r) == false) {
+ ck_error("ERROR [%u]: Failed to set [1]\n", is);
+ }
+
+ if (strcmp(r, test[i]) != 0) {
+ ck_error("ERROR [%u]: Invalid &hs[j]: %s != %s\n", (char *)r, test[i], is);
+ }
+ }
+
+ if (j == size - 1)
+ break;
+
+ if (ck_rhs_move(&hs[j + 1], &hs[j], hs_hash, hs_compare, &my_allocator) == false)
+ ck_error("Failed to move hash table");
+
+ ck_rhs_gc(&hs[j + 1]);
+
+ if (ck_rhs_rebuild(&hs[j + 1]) == false)
+ ck_error("Failed to rebuild");
+ }
+
+ return;
+}
+
+int
+main(void)
+{
+ unsigned int k;
+
+ for (k = 16; k <= 64; k <<= 1) {
+ run_test(k, 0);
+ break;
+ }
+
+ return 0;
+}
+
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/f098175e/lib/ck/regressions/ck_ring/benchmark/Makefile
----------------------------------------------------------------------
diff --git a/lib/ck/regressions/ck_ring/benchmark/Makefile b/lib/ck/regressions/ck_ring/benchmark/Makefile
new file mode 100644
index 0000000..4087ed1
--- /dev/null
+++ b/lib/ck/regressions/ck_ring/benchmark/Makefile
@@ -0,0 +1,14 @@
+.PHONY: clean distribution
+
+OBJECTS=latency
+
+all: $(OBJECTS)
+
+latency: latency.c ../../../include/ck_ring.h
+ $(CC) $(CFLAGS) -o latency latency.c
+
+clean:
+ rm -rf *~ *.o $(OBJECTS) *.dSYM *.exe
+
+include ../../../build/regressions.build
+CFLAGS+=-D_GNU_SOURCE
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/f098175e/lib/ck/regressions/ck_ring/benchmark/latency.c
----------------------------------------------------------------------
diff --git a/lib/ck/regressions/ck_ring/benchmark/latency.c b/lib/ck/regressions/ck_ring/benchmark/latency.c
new file mode 100644
index 0000000..5e46b1c
--- /dev/null
+++ b/lib/ck/regressions/ck_ring/benchmark/latency.c
@@ -0,0 +1,93 @@
+#include <ck_ring.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "../../common.h"
+
+#ifndef ITERATIONS
+#define ITERATIONS (128000)
+#endif
+
+struct entry {
+ int tid;
+ int value;
+};
+
+int
+main(int argc, char *argv[])
+{
+ int i, r, size;
+ uint64_t s, e, e_a, d_a;
+ struct entry entry = {0, 0};
+ ck_ring_buffer_t *buf;
+ ck_ring_t ring;
+
+ if (argc != 2) {
+ ck_error("Usage: latency <size>\n");
+ }
+
+ size = atoi(argv[1]);
+ if (size <= 4 || (size & (size - 1))) {
+ ck_error("ERROR: Size must be a power of 2 greater than 4.\n");
+ }
+
+ buf = malloc(sizeof(ck_ring_buffer_t) * size);
+ if (buf == NULL) {
+ ck_error("ERROR: Failed to allocate buffer\n");
+ }
+
+ ck_ring_init(&ring, size);
+
+ e_a = d_a = s = e = 0;
+ for (r = 0; r < ITERATIONS; r++) {
+ for (i = 0; i < size / 4; i += 4) {
+ s = rdtsc();
+ ck_ring_enqueue_spsc(&ring, buf, &entry);
+ ck_ring_enqueue_spsc(&ring, buf, &entry);
+ ck_ring_enqueue_spsc(&ring, buf, &entry);
+ ck_ring_enqueue_spsc(&ring, buf, &entry);
+ e = rdtsc();
+ }
+ e_a += (e - s) / 4;
+
+ for (i = 0; i < size / 4; i += 4) {
+ s = rdtsc();
+ ck_ring_dequeue_spsc(&ring, buf, &entry);
+ ck_ring_dequeue_spsc(&ring, buf, &entry);
+ ck_ring_dequeue_spsc(&ring, buf, &entry);
+ ck_ring_dequeue_spsc(&ring, buf, &entry);
+ e = rdtsc();
+ }
+ d_a += (e - s) / 4;
+ }
+
+ printf("spsc %10d %16" PRIu64 " %16" PRIu64 "\n", size, e_a / ITERATIONS, d_a / ITERATIONS);
+
+ e_a = d_a = s = e = 0;
+ for (r = 0; r < ITERATIONS; r++) {
+ for (i = 0; i < size / 4; i += 4) {
+ s = rdtsc();
+ ck_ring_enqueue_spmc(&ring, buf, &entry);
+ ck_ring_enqueue_spmc(&ring, buf, &entry);
+ ck_ring_enqueue_spmc(&ring, buf, &entry);
+ ck_ring_enqueue_spmc(&ring, buf, &entry);
+ e = rdtsc();
+ }
+ e_a += (e - s) / 4;
+
+ for (i = 0; i < size / 4; i += 4) {
+ s = rdtsc();
+ ck_ring_dequeue_spmc(&ring, buf, &entry);
+ ck_ring_dequeue_spmc(&ring, buf, &entry);
+ ck_ring_dequeue_spmc(&ring, buf, &entry);
+ ck_ring_dequeue_spmc(&ring, buf, &entry);
+ e = rdtsc();
+ }
+ d_a += (e - s) / 4;
+ }
+
+ printf("spmc %10d %16" PRIu64 " %16" PRIu64 "\n", size, e_a / ITERATIONS, d_a / ITERATIONS);
+ return (0);
+}
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/f098175e/lib/ck/regressions/ck_ring/validate/Makefile
----------------------------------------------------------------------
diff --git a/lib/ck/regressions/ck_ring/validate/Makefile b/lib/ck/regressions/ck_ring/validate/Makefile
new file mode 100644
index 0000000..8c00d80
--- /dev/null
+++ b/lib/ck/regressions/ck_ring/validate/Makefile
@@ -0,0 +1,29 @@
+.PHONY: check clean distribution
+
+OBJECTS=ck_ring_spsc ck_ring_spmc ck_ring_spmc_template
+SIZE=16384
+CFLAGS += -g2
+
+all: $(OBJECTS)
+
+check: all
+ ./ck_ring_spsc $(CORES) 1 $(SIZE)
+ ./ck_ring_spmc $(CORES) 1 $(SIZE)
+
+ck_ring_spsc: ck_ring_spsc.c ../../../include/ck_ring.h
+ $(CC) $(CFLAGS) -o ck_ring_spsc ck_ring_spsc.c \
+ ../../../src/ck_barrier_centralized.c
+
+ck_ring_spmc: ck_ring_spmc.c ../../../include/ck_ring.h
+ $(CC) $(CFLAGS) -g2 -o ck_ring_spmc ck_ring_spmc.c \
+ ../../../src/ck_barrier_centralized.c
+
+ck_ring_spmc_template: ck_ring_spmc_template.c ../../../include/ck_ring.h
+ $(CC) $(CFLAGS) -g2 -o ck_ring_spmc_template ck_ring_spmc.c \
+ ../../../src/ck_barrier_centralized.c
+
+clean:
+ rm -rf *~ *.o $(OBJECTS) *.dSYM *.exe
+
+include ../../../build/regressions.build
+CFLAGS+=$(PTHREAD_CFLAGS) -D_GNU_SOURCE
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/f098175e/lib/ck/regressions/ck_ring/validate/ck_ring_spmc.c
----------------------------------------------------------------------
diff --git a/lib/ck/regressions/ck_ring/validate/ck_ring_spmc.c b/lib/ck/regressions/ck_ring/validate/ck_ring_spmc.c
new file mode 100644
index 0000000..23fe0fa
--- /dev/null
+++ b/lib/ck/regressions/ck_ring/validate/ck_ring_spmc.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright 2011-2014 Samy Al Bahra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+
+#include <ck_barrier.h>
+#include <ck_ring.h>
+#include <ck_spinlock.h>
+#include "../../common.h"
+
+#ifndef ITERATIONS
+#define ITERATIONS 128
+#endif
+
+struct context {
+ unsigned int tid;
+ unsigned int previous;
+ unsigned int next;
+ ck_ring_buffer_t *buffer;
+};
+
+struct entry {
+ unsigned long value_long;
+ unsigned int magic;
+ unsigned int ref;
+ int tid;
+ int value;
+};
+
+static int nthr;
+static ck_ring_t *ring;
+static ck_ring_t ring_spmc CK_CC_CACHELINE;
+static struct affinity a;
+static int size;
+static int eb;
+static ck_barrier_centralized_t barrier = CK_BARRIER_CENTRALIZED_INITIALIZER;
+static struct context *_context;
+
+static void *
+test_spmc(void *c)
+{
+ unsigned int observed = 0;
+ unsigned long previous = 0;
+ unsigned int seed;
+ int i, k, j, tid;
+ struct context *context = c;
+ ck_ring_buffer_t *buffer;
+
+ buffer = context->buffer;
+ if (aff_iterate(&a)) {
+ perror("ERROR: Could not affine thread");
+ exit(EXIT_FAILURE);
+ }
+
+ tid = ck_pr_faa_int(&eb, 1);
+ ck_pr_fence_memory();
+ while (ck_pr_load_int(&eb) != nthr - 1);
+
+ for (i = 0; i < ITERATIONS; i++) {
+ for (j = 0; j < size; j++) {
+ struct entry *o;
+ int spin;
+
+ /* Keep trying until we encounter at least one node. */
+ if (j & 1) {
+ while (ck_ring_dequeue_spmc(&ring_spmc, buffer,
+ &o) == false);
+ } else {
+ while (ck_ring_trydequeue_spmc(&ring_spmc, buffer,
+ &o) == false);
+ }
+
+ observed++;
+ if (o->value < 0
+ || o->value != o->tid
+ || o->magic != 0xdead
+ || (previous != 0 && previous >= o->value_long)) {
+ ck_error("[0x%p] (%x) (%d, %d) >< (0, %d)\n",
+ (void *)o, o->magic, o->tid, o->value, size);
+ }
+
+ o->magic = 0xbeef;
+ o->value = -31337;
+ o->tid = -31338;
+ previous = o->value_long;
+
+ if (ck_pr_faa_uint(&o->ref, 1) != 0) {
+ ck_error("[%p] We dequeued twice.\n", (void *)o);
+ }
+
+ if ((i % 4) == 0) {
+ spin = common_rand_r(&seed) % 16384;
+ for (k = 0; k < spin; k++) {
+ ck_pr_stall();
+ }
+ }
+
+ free(o);
+ }
+ }
+
+ fprintf(stderr, "[%d] Observed %u\n", tid, observed);
+ return NULL;
+}
+
+static void *
+test(void *c)
+{
+ struct context *context = c;
+ struct entry *entry;
+ unsigned int s;
+ int i, j;
+ bool r;
+ ck_ring_buffer_t *buffer = context->buffer;
+ ck_barrier_centralized_state_t sense =
+ CK_BARRIER_CENTRALIZED_STATE_INITIALIZER;
+
+ if (aff_iterate(&a)) {
+ perror("ERROR: Could not affine thread");
+ exit(EXIT_FAILURE);
+ }
+
+ if (context->tid == 0) {
+ struct entry *entries;
+
+ entries = malloc(sizeof(struct entry) * size);
+ assert(entries != NULL);
+
+ if (ck_ring_size(ring) != 0) {
+ ck_error("More entries than expected: %u > 0\n",
+ ck_ring_size(ring));
+ }
+
+ for (i = 0; i < size; i++) {
+ entries[i].value = i;
+ entries[i].tid = 0;
+
+ if (i & 1) {
+ r = ck_ring_enqueue_spmc(ring, buffer,
+ entries + i);
+ } else {
+ r = ck_ring_enqueue_spmc_size(ring, buffer,
+ entries + i, &s);
+
+ if ((int)s != i) {
+ ck_error("Size is %u, expected %d.\n",
+ s, size);
+ }
+ }
+
+ assert(r != false);
+ }
+
+ if (ck_ring_size(ring) != (unsigned int)size) {
+ ck_error("Less entries than expected: %u < %d\n",
+ ck_ring_size(ring), size);
+ }
+
+ if (ck_ring_capacity(ring) != ck_ring_size(ring) + 1) {
+ ck_error("Capacity less than expected: %u < %u\n",
+ ck_ring_size(ring), ck_ring_capacity(ring));
+ }
+ }
+
+ /*
+ * Wait for all threads. The idea here is to maximize the contention.
+ */
+ ck_barrier_centralized(&barrier, &sense, nthr);
+
+ for (i = 0; i < ITERATIONS; i++) {
+ for (j = 0; j < size; j++) {
+ buffer = _context[context->previous].buffer;
+ while (ck_ring_dequeue_spmc(ring + context->previous,
+ buffer, &entry) == false);
+
+ if (context->previous != (unsigned int)entry->tid) {
+ ck_error("[%u:%p] %u != %u\n",
+ context->tid, (void *)entry, entry->tid, context->previous);
+ }
+
+ if (entry->value < 0 || entry->value >= size) {
+ ck_error("[%u:%p] %u </> %u\n",
+ context->tid, (void *)entry, entry->tid, context->previous);
+ }
+
+ entry->tid = context->tid;
+ buffer = context->buffer;
+
+ if (i & 1) {
+ r = ck_ring_enqueue_spmc(ring + context->tid,
+ buffer, entry);
+ } else {
+ r = ck_ring_enqueue_spmc_size(ring + context->tid,
+ buffer, entry, &s);
+
+ if ((int)s >= size) {
+ ck_error("Size %u out of range of %d\n",
+ s, size);
+ }
+ }
+ assert(r == true);
+ }
+ }
+
+ return NULL;
+}
+
+int
+main(int argc, char *argv[])
+{
+ int i, r;
+ unsigned long l;
+ pthread_t *thread;
+ ck_ring_buffer_t *buffer;
+
+ if (argc != 4) {
+ ck_error("Usage: validate <threads> <affinity delta> <size>\n");
+ }
+
+ a.request = 0;
+ a.delta = atoi(argv[2]);
+
+ nthr = atoi(argv[1]);
+ assert(nthr >= 1);
+
+ size = atoi(argv[3]);
+ assert(size >= 4 && (size & size - 1) == 0);
+ size -= 1;
+
+ ring = malloc(sizeof(ck_ring_t) * nthr);
+ assert(ring);
+
+ _context = malloc(sizeof(*_context) * nthr);
+ assert(_context);
+
+ thread = malloc(sizeof(pthread_t) * nthr);
+ assert(thread);
+
+ fprintf(stderr, "SPSC test:");
+ for (i = 0; i < nthr; i++) {
+ _context[i].tid = i;
+ if (i == 0) {
+ _context[i].previous = nthr - 1;
+ _context[i].next = i + 1;
+ } else if (i == nthr - 1) {
+ _context[i].next = 0;
+ _context[i].previous = i - 1;
+ } else {
+ _context[i].next = i + 1;
+ _context[i].previous = i - 1;
+ }
+
+ buffer = malloc(sizeof(ck_ring_buffer_t) * (size + 1));
+ assert(buffer);
+ memset(buffer, 0, sizeof(ck_ring_buffer_t) * (size + 1));
+ _context[i].buffer = buffer;
+ ck_ring_init(ring + i, size + 1);
+ r = pthread_create(thread + i, NULL, test, _context + i);
+ assert(r == 0);
+ }
+
+ for (i = 0; i < nthr; i++)
+ pthread_join(thread[i], NULL);
+
+ fprintf(stderr, " done\n");
+
+ fprintf(stderr, "SPMC test:\n");
+ buffer = malloc(sizeof(ck_ring_buffer_t) * (size + 1));
+ assert(buffer);
+ memset(buffer, 0, sizeof(void *) * (size + 1));
+ ck_ring_init(&ring_spmc, size + 1);
+ for (i = 0; i < nthr - 1; i++) {
+ _context[i].buffer = buffer;
+ r = pthread_create(thread + i, NULL, test_spmc, _context + i);
+ assert(r == 0);
+ }
+
+ for (l = 0; l < (unsigned long)size * ITERATIONS * (nthr - 1) ; l++) {
+ struct entry *entry = malloc(sizeof *entry);
+
+ assert(entry != NULL);
+ entry->value_long = l;
+ entry->value = (int)l;
+ entry->tid = (int)l;
+ entry->magic = 0xdead;
+ entry->ref = 0;
+
+ /* Wait until queue is not full. */
+ if (l & 1) {
+ while (ck_ring_enqueue_spmc(&ring_spmc,
+ buffer,
+ entry) == false)
+ ck_pr_stall();
+ } else {
+ unsigned int s;
+
+ while (ck_ring_enqueue_spmc_size(&ring_spmc,
+ buffer, entry, &s) == false) {
+ ck_pr_stall();
+ }
+
+ if ((int)s >= (size * ITERATIONS * (nthr - 1))) {
+ ck_error("MPMC: Unexpected size of %u\n", s);
+ }
+ }
+ }
+
+ for (i = 0; i < nthr - 1; i++)
+ pthread_join(thread[i], NULL);
+
+ return (0);
+}
+
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/f098175e/lib/ck/regressions/ck_ring/validate/ck_ring_spmc_template.c
----------------------------------------------------------------------
diff --git a/lib/ck/regressions/ck_ring/validate/ck_ring_spmc_template.c b/lib/ck/regressions/ck_ring/validate/ck_ring_spmc_template.c
new file mode 100644
index 0000000..9facbc7
--- /dev/null
+++ b/lib/ck/regressions/ck_ring/validate/ck_ring_spmc_template.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright 2011-2014 Samy Al Bahra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+
+#include <ck_barrier.h>
+#include <ck_ring.h>
+#include <ck_spinlock.h>
+#include "../../common.h"
+
+#ifndef ITERATIONS
+#define ITERATIONS 128
+#endif
+
+struct context {
+ unsigned int tid;
+ unsigned int previous;
+ unsigned int next;
+ struct entry *buffer;
+};
+
+struct entry {
+ unsigned long value_long;
+ unsigned int magic;
+ unsigned int ref;
+ int tid;
+ int value;
+};
+
+CK_RING_PROTOTYPE(entry, entry)
+
+static int nthr;
+static ck_ring_t *ring;
+static ck_ring_t ring_spmc CK_CC_CACHELINE;
+static struct affinity a;
+static int size;
+static int eb;
+static ck_barrier_centralized_t barrier = CK_BARRIER_CENTRALIZED_INITIALIZER;
+static struct context *_context;
+
+static void *
+test_spmc(void *c)
+{
+ unsigned int observed = 0;
+ unsigned long previous = 0;
+ unsigned int seed;
+ int i, k, j, tid;
+ struct context *context = c;
+ struct entry *buffer;
+
+ buffer = context->buffer;
+ if (aff_iterate(&a)) {
+ perror("ERROR: Could not affine thread");
+ exit(EXIT_FAILURE);
+ }
+
+ tid = ck_pr_faa_int(&eb, 1);
+ ck_pr_fence_memory();
+ while (ck_pr_load_int(&eb) != nthr - 1);
+
+ for (i = 0; i < ITERATIONS; i++) {
+ for (j = 0; j < size; j++) {
+ struct entry *o;
+ int spin;
+
+ /* Keep trying until we encounter at least one node. */
+ if (j & 1) {
+ while (CK_RING_DEQUEUE_SPMC(entry,
+ &ring_spmc, buffer, &o) == false);
+ } else {
+ while (CK_RING_TRYDEQUEUE_SPMC(entry,
+ &ring_spmc, buffer, &o) == false);
+ }
+
+ observed++;
+ if (o->value < 0
+ || o->value != o->tid
+ || o->magic != 0xdead
+ || (previous != 0 && previous >= o->value_long)) {
+ ck_error("[0x%p] (%x) (%d, %d) >< (0, %d)\n",
+ (void *)o, o->magic, o->tid, o->value, size);
+ }
+
+ o->magic = 0xbeef;
+ o->value = -31337;
+ o->tid = -31338;
+ previous = o->value_long;
+
+ if (ck_pr_faa_uint(&o->ref, 1) != 0) {
+ ck_error("[%p] We dequeued twice.\n", (void *)o);
+ }
+
+ if ((i % 4) == 0) {
+ spin = common_rand_r(&seed) % 16384;
+ for (k = 0; k < spin; k++) {
+ ck_pr_stall();
+ }
+ }
+
+ free(o);
+ }
+ }
+
+ fprintf(stderr, "[%d] Observed %u\n", tid, observed);
+ return NULL;
+}
+
+static void *
+test(void *c)
+{
+ struct context *context = c;
+ struct entry entry;
+ unsigned int s;
+ int i, j;
+ bool r;
+ ck_ring_buffer_t *buffer = context->buffer;
+ ck_barrier_centralized_state_t sense =
+ CK_BARRIER_CENTRALIZED_STATE_INITIALIZER;
+
+ if (aff_iterate(&a)) {
+ perror("ERROR: Could not affine thread");
+ exit(EXIT_FAILURE);
+ }
+
+ if (context->tid == 0) {
+ struct entry *entries;
+
+ entries = malloc(sizeof(struct entry) * size);
+ assert(entries != NULL);
+
+ if (ck_ring_size(ring) != 0) {
+ ck_error("More entries than expected: %u > 0\n",
+ ck_ring_size(ring));
+ }
+
+ for (i = 0; i < size; i++) {
+ entries[i].value = i;
+ entries[i].tid = 0;
+
+ if (i & 1) {
+ r = CK_RING_ENQUEUE_SPMC(entry, ring, buffer,
+ entries + i);
+ } else {
+ r = CK_RING_ENQUEUE_SPMC_SIZE(entry, ring,
+ buffer, entries + i, &s);
+
+ if ((int)s != i) {
+ ck_error("Size is %u, expected %d.\n",
+ s, size);
+ }
+ }
+
+ assert(r != false);
+ }
+
+ if (ck_ring_size(ring) != (unsigned int)size) {
+ ck_error("Less entries than expected: %u < %d\n",
+ ck_ring_size(ring), size);
+ }
+
+ if (ck_ring_capacity(ring) != ck_ring_size(ring) + 1) {
+ ck_error("Capacity less than expected: %u < %u\n",
+ ck_ring_size(ring), ck_ring_capacity(ring));
+ }
+ }
+
+ /*
+ * Wait for all threads. The idea here is to maximize the contention.
+ */
+ ck_barrier_centralized(&barrier, &sense, nthr);
+
+ for (i = 0; i < ITERATIONS; i++) {
+ for (j = 0; j < size; j++) {
+ buffer = _context[context->previous].buffer;
+ while (CK_RING_DEQUEUE_SPMC(entry,
+ ring + context->previous,
+ buffer, &entry) == false);
+
+ if (context->previous != (unsigned int)entry->tid) {
+ ck_error("[%u:%p] %u != %u\n",
+ context->tid, (void *)entry,
+ entry->tid, context->previous);
+ }
+
+ if (entry->value < 0 || entry->value >= size) {
+ ck_error("[%u:%p] %u </> %u\n",
+ context->tid, (void *)entry,
+ entry->tid, context->previous);
+ }
+
+ entry->tid = context->tid;
+ buffer = context->buffer;
+
+ if (i & 1) {
+ r = CK_RING_ENQUEUE_SPMC(entry,
+ ring + context->tid,
+ buffer, &entry);
+ } else {
+ r = CK_RING_ENQUEUE_SPMC_SIZE(entry,
+ ring + context->tid,
+ buffer, &entry, &s);
+
+ if ((int)s >= size) {
+ ck_error("Size %u out of range of %d\n",
+ s, size);
+ }
+ }
+ assert(r == true);
+ }
+ }
+
+ return NULL;
+}
+
+int
+main(int argc, char *argv[])
+{
+ int i, r;
+ unsigned long l;
+ pthread_t *thread;
+ struct entry *buffer;
+
+ if (argc != 4) {
+ ck_error("Usage: validate <threads> <affinity delta> <size>\n");
+ }
+
+ a.request = 0;
+ a.delta = atoi(argv[2]);
+
+ nthr = atoi(argv[1]);
+ assert(nthr >= 1);
+
+ size = atoi(argv[3]);
+ assert(size >= 4 && (size & size - 1) == 0);
+ size -= 1;
+
+ ring = malloc(sizeof(ck_ring_t) * nthr);
+ assert(ring);
+
+ _context = malloc(sizeof(*_context) * nthr);
+ assert(_context);
+
+ thread = malloc(sizeof(pthread_t) * nthr);
+ assert(thread);
+
+ fprintf(stderr, "SPSC test:");
+ for (i = 0; i < nthr; i++) {
+ _context[i].tid = i;
+ if (i == 0) {
+ _context[i].previous = nthr - 1;
+ _context[i].next = i + 1;
+ } else if (i == nthr - 1) {
+ _context[i].next = 0;
+ _context[i].previous = i - 1;
+ } else {
+ _context[i].next = i + 1;
+ _context[i].previous = i - 1;
+ }
+
+ buffer = malloc(sizeof(struct entry) * (size + 1));
+ assert(buffer);
+ memset(buffer, 0, sizeof(struct entry) * (size + 1));
+ _context[i].buffer = buffer;
+ ck_ring_init(ring + i, size + 1);
+ r = pthread_create(thread + i, NULL, test, _context + i);
+ assert(r == 0);
+ }
+
+ for (i = 0; i < nthr; i++)
+ pthread_join(thread[i], NULL);
+
+ fprintf(stderr, " done\n");
+
+ fprintf(stderr, "SPMC test:\n");
+ buffer = malloc(sizeof(ck_ring_buffer_t) * (size + 1));
+ assert(buffer);
+ memset(buffer, 0, sizeof(void *) * (size + 1));
+ ck_ring_init(&ring_spmc, size + 1);
+ for (i = 0; i < nthr - 1; i++) {
+ _context[i].buffer = buffer;
+ r = pthread_create(thread + i, NULL, test_spmc, _context + i);
+ assert(r == 0);
+ }
+
+ for (l = 0; l < (unsigned long)size * ITERATIONS * (nthr - 1) ; l++) {
+ struct entry *entry = malloc(sizeof *entry);
+
+ assert(entry != NULL);
+ entry->value_long = l;
+ entry->value = (int)l;
+ entry->tid = (int)l;
+ entry->magic = 0xdead;
+ entry->ref = 0;
+
+ /* Wait until queue is not full. */
+ if (l & 1) {
+ while (CK_RING_ENQUEUE_SPMC(entry, &ring_spmc,
+ buffer, entry) == false) {
+ ck_pr_stall();
+ }
+ } else {
+ unsigned int s;
+
+ while (CK_RING_ENQUEUE_SPMC_SIZE(entry, &ring_spmc,
+ buffer, entry, &s) == false) {
+ ck_pr_stall();
+ }
+
+ if ((int)s >= (size * ITERATIONS * (nthr - 1))) {
+ ck_error("MPMC: Unexpected size of %u\n", s);
+ }
+ }
+ }
+
+ for (i = 0; i < nthr - 1; i++)
+ pthread_join(thread[i], NULL);
+
+ return (0);
+}
+