From patchwork Wed Jun 9 13:09:11 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gaetan Rivet X-Patchwork-Id: 1489860 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=u256.net header.i=@u256.net header.a=rsa-sha256 header.s=fm2 header.b=mM/7J85T; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.a=rsa-sha256 header.s=fm3 header.b=tSBFjXh3; dkim-atps=neutral Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4G0SBl4tglz9sW8 for ; Wed, 9 Jun 2021 23:10:07 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 68A9160A6D; Wed, 9 Jun 2021 13:10:01 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id rTDnmUi_zoiR; Wed, 9 Jun 2021 13:09:57 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp3.osuosl.org (Postfix) with ESMTPS id 6F0E4608EF; Wed, 9 Jun 2021 13:09:56 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 0BE35C000B; Wed, 9 Jun 2021 13:09:55 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) by lists.linuxfoundation.org (Postfix) with ESMTP id D80BDC002A for ; Wed, 9 Jun 2021 13:09:53 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id B402C404FC for ; Wed, 9 Jun 2021 13:09:53 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Authentication-Results: smtp2.osuosl.org (amavisd-new); dkim=pass (2048-bit key) header.d=u256.net header.b="mM/7J85T"; dkim=pass (2048-bit key) header.d=messagingengine.com header.b="tSBFjXh3" Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id MNdLPWkFzQPm for ; Wed, 9 Jun 2021 13:09:50 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.8.0 Received: from wout3-smtp.messagingengine.com (wout3-smtp.messagingengine.com [64.147.123.19]) by smtp2.osuosl.org (Postfix) with ESMTPS id 2822440137 for ; Wed, 9 Jun 2021 13:09:50 +0000 (UTC) Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailout.west.internal (Postfix) with ESMTP id 5679C2663; Wed, 9 Jun 2021 09:09:49 -0400 (EDT) Received: from mailfrontend1 ([10.202.2.162]) by compute5.internal (MEProxy); Wed, 09 Jun 2021 09:09:49 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=u256.net; h=from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm2; bh=cb9+vyzif3gFc Hl40kdd94+ajBmkdCFd/ecwuCDXrLM=; b=mM/7J85T8e9ijEwEo+olhQGJVIeoE 5SzAEqOlP3cPH1qdYdilPS8rK7aTdM4ZL4qU2L3gltWUUDkkUQTLSE6JlPRNZcFl NtSZ8m6nsuxK+TgivJ2osFAVQj+VBdVn7a/10mKJv1UiiiljgtCezkGOuFIW0vxB JqU0KBLRpQKHSi0PFRrNrB14VpeP9cs2AFuaIEEg7wAKxL+XUslZt2FgRcW6HGz9 2VRBKit+w1UbtoxBUzogsjCaxaWkwWElcvZ5M7aGwIOQVbbpPBx1d/y74JUOYID4 +5Znvx1OSvLWlT1Nm97PQQ6JmaKyXIvOck6FBQGWXAEFhUIsbj2MY3yYg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; bh=cb9+vyzif3gFcHl40kdd94+ajBmkdCFd/ecwuCDXrLM=; b=tSBFjXh3 1RbuqUy64sNybh44Wn9EbOePbf78astg/LLeV2nBwnFmMmXrJaS/UloLPwv87f3T hlSG3ia+pclLkcBI3lPVRqxAeFCREJixMccJVPMchHpu7ZzsWvFRJyjEszhNz6rx 9kyNpwNMaL+vyhFwYgpqe+NVMHcceYyFesJpfSZxgRgwZB0RVcHKM/5IpkGVACwG AE3lXibz2oNMlF2uHWLqZMB4KJQlJhMa4Nuy/qotMu9HSpPHuItkudkSFIbpvolH 1bltR66Inw+oBnGiMPOknObafu8IrwB0PlRQf2dwZ8ghdgWfv8XZv+yxxnDnK8g0 4Nbi2+QQFoZg1Q== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduledrfeduuddgiedvucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpefirggvthgr nhcutfhivhgvthcuoehgrhhivhgvsehuvdehiedrnhgvtheqnecuggftrfgrthhtvghrnh epudfhfeeikeeiiedutefgheekledukedtkeejheduheffteeiudehiefgkedvleefnecu ffhomhgrihhnpegrphgrtghhvgdrohhrghenucevlhhushhtvghrufhiiigvpedtnecurf grrhgrmhepmhgrihhlfhhrohhmpehgrhhivhgvsehuvdehiedrnhgvth X-ME-Proxy: Received: by mail.messagingengine.com (Postfix) with ESMTPA; Wed, 9 Jun 2021 09:09:48 -0400 (EDT) From: Gaetan Rivet To: ovs-dev@openvswitch.org Date: Wed, 9 Jun 2021 15:09:11 +0200 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Cc: Maxime Coquelin Subject: [ovs-dev] [PATCH v4 03/27] tests: Add ovs-barrier unit test X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" No unit test exist currently for the ovs-barrier type. It is however crucial as a building block and should be verified to work as expected. Create a simple test verifying the basic function of ovs-barrier. Integrate the test as part of the test suite. Signed-off-by: Gaetan Rivet Reviewed-by: Maxime Coquelin --- tests/automake.mk | 1 + tests/library.at | 5 + tests/test-barrier.c | 264 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 270 insertions(+) create mode 100644 tests/test-barrier.c diff --git a/tests/automake.mk b/tests/automake.mk index 1a528aa39..a32abd41c 100644 --- a/tests/automake.mk +++ b/tests/automake.mk @@ -448,6 +448,7 @@ tests_ovstest_SOURCES = \ tests/ovstest.h \ tests/test-aes128.c \ tests/test-atomic.c \ + tests/test-barrier.c \ tests/test-bundle.c \ tests/test-byte-order.c \ tests/test-classifier.c \ diff --git a/tests/library.at b/tests/library.at index 1702b7556..e572c22e3 100644 --- a/tests/library.at +++ b/tests/library.at @@ -246,6 +246,11 @@ AT_SETUP([ofpbuf module]) AT_CHECK([ovstest test-ofpbuf], [0], []) AT_CLEANUP +AT_SETUP([barrier module]) +AT_KEYWORDS([barrier]) +AT_CHECK([ovstest test-barrier], [0], []) +AT_CLEANUP + AT_SETUP([rcu]) AT_CHECK([ovstest test-rcu-quiesce], [0], []) AT_CLEANUP diff --git a/tests/test-barrier.c b/tests/test-barrier.c new file mode 100644 index 000000000..3bc5291cc --- /dev/null +++ b/tests/test-barrier.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2021 NVIDIA Corporation. + * + * Licensed 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. + */ + +#include + +#include + +#include "ovs-thread.h" +#include "ovs-rcu.h" +#include "ovstest.h" +#include "random.h" +#include "util.h" + +#define DEFAULT_N_THREADS 4 +#define NB_STEPS 4 + +static bool verbose; +static struct ovs_barrier barrier; + +struct blocker_aux { + unsigned int tid; + bool leader; + int step; +}; + +static void * +basic_blocker_main(void *aux_) +{ + struct blocker_aux *aux = aux_; + size_t i; + + aux->step = 0; + for (i = 0; i < NB_STEPS; i++) { + ovs_barrier_block(&barrier); + aux->step++; + ovs_barrier_block(&barrier); + } + + return NULL; +} + +static void +basic_block_check(struct blocker_aux *aux, size_t n, int expected) +{ + size_t i; + + for (i = 0; i < n; i++) { + if (verbose) { + printf("aux[%" PRIuSIZE "]=%d == %d", i, aux[i].step, expected); + if (aux[i].step != expected) { + printf(" <--- X"); + } + printf("\n"); + } else { + ovs_assert(aux[i].step == expected); + } + } + ovs_barrier_block(&barrier); + ovs_barrier_block(&barrier); +} + +/* + * Basic barrier test. + * + * N writers and 1 reader participate in the test. + * Each thread goes through M steps (=NB_STEPS). + * The main thread participates as the reader. + * + * A Step is divided in three parts: + * 1. before + * (barrier) + * 2. during + * (barrier) + * 3. after + * + * Each writer updates a thread-local variable with the + * current step number within part 2 and waits. + * + * The reader checks all variables during part 3, expecting + * all variables to be equal. If any variable differs, it means + * its thread was not properly blocked by the barrier. + */ +static void +test_barrier_basic(size_t n_threads) +{ + struct blocker_aux *aux; + pthread_t *threads; + size_t i; + + ovs_barrier_init(&barrier, n_threads + 1); + + aux = xcalloc(n_threads, sizeof *aux); + threads = xmalloc(n_threads * sizeof *threads); + for (i = 0; i < n_threads; i++) { + threads[i] = ovs_thread_create("ovs-barrier", + basic_blocker_main, &aux[i]); + } + + for (i = 0; i < NB_STEPS; i++) { + basic_block_check(aux, n_threads, i); + } + ovs_barrier_destroy(&barrier); + + for (i = 0; i < n_threads; i++) { + xpthread_join(threads[i], NULL); + } + + free(threads); + free(aux); +} + +static unsigned int *shared_mem; + +static void * +lead_blocker_main(void *aux_) +{ + struct blocker_aux *aux = aux_; + size_t i; + + aux->step = 0; + for (i = 0; i < NB_STEPS; i++) { + if (aux->leader) { + shared_mem = xmalloc(sizeof *shared_mem); + if (verbose) { + printf("*T1: allocated shmem\n"); + } + } + xnanosleep(random_range(100) * 1000); + + ovs_barrier_block(&barrier); + + if (verbose) { + printf("%cT%u: ENTER, writing\n", + (aux->leader ? '*' : ' '), aux->tid); + } + + shared_mem[0] = 42; + + ovs_barrier_block(&barrier); + + if (verbose) { + printf("%cT%u: EXIT\n", + (aux->leader ? '*' : ' '), aux->tid); + } + + if (aux->leader) { + free(shared_mem); + if (verbose) { + printf("*T1: freed shmem\n"); + } + } + xnanosleep(random_range(100) * 1000); + } + + return NULL; +} + +/* + * Leader barrier test. + * + * N threads participates, one of which is marked as + * the leader (thread 0). The main thread does not + * participate. + * + * The test is divided in M steps (=NB_STEPS). + * A Step is divided in three parts: + * 1. before + * (barrier) + * 2. during + * (barrier) + * 3. after + * + * Part 1, the leader allocates a block of shared memory. + * Part 2, all threads write to the shared memory. + * Part 3: the leader frees the shared memory. + * + * If any thread is improperly blocked by the barrier, + * the shared memory accesses will trigger a segfault + * or a use-after-free if ASAN is enabled. + */ +static void +test_barrier_lead(size_t n_threads) +{ + struct blocker_aux *aux; + pthread_t *threads; + size_t i; + + ovs_barrier_init(&barrier, n_threads); + + aux = xcalloc(n_threads, sizeof *aux); + threads = xmalloc(n_threads * sizeof *threads); + + aux[0].leader = true; + + for (i = 0; i < n_threads; i++) { + aux[i].tid = i + 1; + threads[i] = ovs_thread_create("ovs-barrier", + lead_blocker_main, &aux[i]); + } + + for (i = 0; i < n_threads; i++) { + xpthread_join(threads[i], NULL); + } + + /* If the main thread does not participate in the barrier, + * it must wait for all threads to join before destroying it. + */ + ovs_barrier_destroy(&barrier); + + free(threads); + free(aux); +} + +static void +usage(char *test_name) +{ + fprintf(stderr, "Usage: %s [n_threads=%d] [-v]\n", + test_name, DEFAULT_N_THREADS); +} + +static void +test_barrier(int argc, char *argv[]) +{ + size_t n_threads = DEFAULT_N_THREADS; + char **args = argv + optind - 1; + + set_program_name(argv[0]); + + argc -= optind; + if (argc > 2) { + usage(args[0]); + return; + } + + while (argc-- > 0) { + args++; + if (!strcmp(args[0], "-v")) { + verbose = true; + } else { + n_threads = strtol(args[0], NULL, 10); + if (n_threads > 20) { + n_threads = 20; + } + } + } + + test_barrier_basic(n_threads); + test_barrier_lead(n_threads); +} + +OVSTEST_REGISTER("test-barrier", test_barrier);