You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucy.apache.org by nw...@apache.org on 2015/05/16 15:37:55 UTC
[09/10] lucy-clownfish git commit: Port threaded LFReg test to C
Port threaded LFReg test to C
Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/3ed5a19f
Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/3ed5a19f
Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/3ed5a19f
Branch: refs/heads/master
Commit: 3ed5a19f1448353cb0eae914867df6c30380c9c5
Parents: b083881
Author: Nick Wellnhofer <we...@aevum.de>
Authored: Sun May 10 01:48:29 2015 +0200
Committer: Nick Wellnhofer <we...@aevum.de>
Committed: Tue May 12 20:15:25 2015 +0200
----------------------------------------------------------------------
runtime/common/charmonizer.c | 1 -
runtime/common/charmonizer.main | 1 -
runtime/core/Clownfish/LockFreeRegistry.c | 11 +++
.../core/Clownfish/Test/TestLockFreeRegistry.c | 99 +++++++++++++++++++-
runtime/perl/t/binding/038-lock_free_registry.t | 82 ----------------
5 files changed, 108 insertions(+), 86 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3ed5a19f/runtime/common/charmonizer.c
----------------------------------------------------------------------
diff --git a/runtime/common/charmonizer.c b/runtime/common/charmonizer.c
index e3f4f2f..16156a2 100644
--- a/runtime/common/charmonizer.c
+++ b/runtime/common/charmonizer.c
@@ -8381,7 +8381,6 @@ S_need_libpthread(chaz_CLI *cli) {
chaz_CFlags *temp_cflags;
if (chaz_CLI_defined(cli, "disable-threads")
- || strcmp(chaz_CLI_strval(cli, "host"), "c") != 0
|| chaz_HeadCheck_check_header("windows.h")
) {
return 0;
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3ed5a19f/runtime/common/charmonizer.main
----------------------------------------------------------------------
diff --git a/runtime/common/charmonizer.main b/runtime/common/charmonizer.main
index a425d10..35500fc 100644
--- a/runtime/common/charmonizer.main
+++ b/runtime/common/charmonizer.main
@@ -622,7 +622,6 @@ S_need_libpthread(chaz_CLI *cli) {
chaz_CFlags *temp_cflags;
if (chaz_CLI_defined(cli, "disable-threads")
- || strcmp(chaz_CLI_strval(cli, "host"), "c") != 0
|| chaz_HeadCheck_check_header("windows.h")
) {
return 0;
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3ed5a19f/runtime/core/Clownfish/LockFreeRegistry.c
----------------------------------------------------------------------
diff --git a/runtime/core/Clownfish/LockFreeRegistry.c b/runtime/core/Clownfish/LockFreeRegistry.c
index 5c6315f..2385f02 100644
--- a/runtime/core/Clownfish/LockFreeRegistry.c
+++ b/runtime/core/Clownfish/LockFreeRegistry.c
@@ -86,9 +86,20 @@ FIND_END_OF_LINKED_LIST:
* while we were allocating that new node), the compare-and-swap will
* fail. If that happens, we have to go back and find the new end of the
* linked list, then try again. */
+#if 1
if (!Atomic_cas_ptr((void*volatile*)slot, NULL, new_entry)) {
goto FIND_END_OF_LINKED_LIST;
}
+#else
+ // This non-atomic version can be used to check whether the test suite
+ // catches any race conditions.
+ if (*slot == NULL) {
+ *slot = new_entry;
+ }
+ else {
+ goto FIND_END_OF_LINKED_LIST;
+ }
+#endif
return true;
}
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3ed5a19f/runtime/core/Clownfish/Test/TestLockFreeRegistry.c
----------------------------------------------------------------------
diff --git a/runtime/core/Clownfish/Test/TestLockFreeRegistry.c b/runtime/core/Clownfish/Test/TestLockFreeRegistry.c
index b030984..3e7edf1 100644
--- a/runtime/core/Clownfish/Test/TestLockFreeRegistry.c
+++ b/runtime/core/Clownfish/Test/TestLockFreeRegistry.c
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <stdlib.h>
#include <string.h>
#define CFISH_USE_SHORT_NAMES
@@ -21,11 +22,23 @@
#include "Clownfish/Test/TestLockFreeRegistry.h"
+#include "Clownfish/Class.h"
#include "Clownfish/LockFreeRegistry.h"
#include "Clownfish/String.h"
#include "Clownfish/Test.h"
#include "Clownfish/TestHarness/TestBatchRunner.h"
-#include "Clownfish/Class.h"
+#include "Clownfish/TestHarness/TestUtils.h"
+#include "Clownfish/Util/Memory.h"
+
+#define NUM_THREADS 5
+
+typedef struct ThreadArgs {
+ LockFreeRegistry *registry;
+ uint32_t *nums;
+ uint32_t num_objs;
+ uint64_t target_time;
+ uint32_t succeeded;
+} ThreadArgs;
TestLockFreeRegistry*
TestLFReg_new() {
@@ -63,10 +76,92 @@ test_all(TestBatchRunner *runner) {
LFReg_destroy(registry);
}
+static void
+S_register_many(void *varg) {
+ ThreadArgs *args = (ThreadArgs*)varg;
+
+ // Encourage contention, so that all threads try to register at the same
+ // time.
+
+ // Sleep until target_time.
+ uint64_t time = TestUtils_time();
+ if (args->target_time > time) {
+ TestUtils_usleep(args->target_time - time);
+ }
+
+ TestUtils_thread_yield();
+
+ uint32_t succeeded = 0;
+ for (uint32_t i = 0; i < args->num_objs; i++) {
+ String *obj = Str_newf("%u32", args->nums[i]);
+ if (LFReg_register(args->registry, obj, (Obj*)obj)) {
+ succeeded++;
+ }
+ DECREF(obj);
+ }
+
+ args->succeeded = succeeded;
+}
+
+static void
+test_threads(TestBatchRunner *runner) {
+ if (!TestUtils_has_threads) {
+ SKIP(runner, 1, "No thread support");
+ return;
+ }
+
+ LockFreeRegistry *registry = LFReg_new(32);
+ ThreadArgs thread_args[NUM_THREADS];
+ uint32_t num_objs = 10000;
+
+ for (uint32_t i = 0; i < NUM_THREADS; i++) {
+ uint32_t *nums = (uint32_t*)MALLOCATE(num_objs * sizeof(uint32_t));
+
+ for (uint32_t j = 0; j < num_objs; j++) {
+ nums[j] = j;
+ }
+
+ // Fisher-Yates shuffle.
+ for (uint32_t j = num_objs - 1; j > 0; j--) {
+ uint32_t r = TestUtils_random_u64() % (j + 1);
+ uint32_t tmp = nums[j];
+ nums[j] = nums[r];
+ nums[r] = tmp;
+ }
+
+ thread_args[i].registry = registry;
+ thread_args[i].nums = nums;
+ thread_args[i].num_objs = num_objs;
+ }
+
+ Thread *threads[NUM_THREADS];
+ uint64_t target_time = TestUtils_time() + 200 * 1000;
+
+ for (uint32_t i = 0; i < NUM_THREADS; i++) {
+ thread_args[i].target_time = target_time;
+ threads[i] = TestUtils_thread_create(S_register_many, &thread_args[i]);
+ }
+
+ uint32_t total_succeeded = 0;
+
+ for (uint32_t i = 0; i < NUM_THREADS; i++) {
+ TestUtils_thread_join(threads[i]);
+ total_succeeded += thread_args[i].succeeded;
+ FREEMEM(thread_args[i].nums);
+ }
+
+ TEST_INT_EQ(runner, total_succeeded, num_objs,
+ "registered exactly the right number of entries across all"
+ " threads");
+
+ LFReg_destroy(registry);
+}
+
void
TestLFReg_Run_IMP(TestLockFreeRegistry *self, TestBatchRunner *runner) {
- TestBatchRunner_Plan(runner, (TestBatch*)self, 6);
+ TestBatchRunner_Plan(runner, (TestBatch*)self, 7);
test_all(runner);
+ test_threads(runner);
}
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/3ed5a19f/runtime/perl/t/binding/038-lock_free_registry.t
----------------------------------------------------------------------
diff --git a/runtime/perl/t/binding/038-lock_free_registry.t b/runtime/perl/t/binding/038-lock_free_registry.t
deleted file mode 100644
index 4793884..0000000
--- a/runtime/perl/t/binding/038-lock_free_registry.t
+++ /dev/null
@@ -1,82 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-use strict;
-use warnings;
-
-use Config;
-use Test::More;
-BEGIN {
- if ( $ENV{LUCY_VALGRIND} ) {
- plan( skip_all => 'Known leaks' );
- }
- elsif ( !defined( $ENV{LUCY_DEBUG} ) ) {
- plan( skip_all => 'Debug-only test' );
- }
- elsif ( $Config{usethreads} and $^O !~ /mswin/i ) {
- plan( tests => 1 );
- }
- else {
- plan( skip_all => 'No thread support' );
- }
-}
-use threads;
-use threads::shared;
-use Time::HiRes qw( time usleep );
-use List::Util qw( shuffle );
-use Clownfish;
-
-package ImmortalString;
-use base qw(Clownfish::String);
-
-sub DESTROY {}
-
-package main;
-
-my $registry = Clownfish::LockFreeRegistry->new( capacity => 32 );
-
-sub register_many {
- my ( $nums, $delay ) = @_;
-
- # Encourage contention, so that all threads try to register at the same
- # time.
- sleep $delay;
- threads->yield();
-
- my $succeeded = 0;
- for my $number (@$nums) {
- my $obj = ImmortalString->new($number);
- $succeeded += $registry->register( key => $obj, value => $obj );
- }
-
- return $succeeded;
-}
-
-my @threads;
-
-my $target_time = time() + .5;
-my @num_sets = map { [ shuffle( 1 .. 10000 ) ] } 1 .. 5;
-for my $num ( 1 .. 5 ) {
- my $delay = $target_time - time();
- my $thread = threads->create( \®ister_many, pop @num_sets, $delay );
- push @threads, $thread;
-}
-
-my $total_succeeded = 0;
-$total_succeeded += $_->join for @threads;
-
-is( $total_succeeded, 10000,
- "registered exactly the right number of entries across all threads" );
-