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( \&register_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" );
-