From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by dpdk.space (Postfix) with ESMTP id A4235A0096 for ; Thu, 6 Jun 2019 15:43:03 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 893D71B95A; Thu, 6 Jun 2019 15:43:02 +0200 (CEST) Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by dpdk.org (Postfix) with ESMTP id 126101B958 for ; Thu, 6 Jun 2019 15:42:59 +0200 (CEST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 06 Jun 2019 06:42:58 -0700 X-ExtLoop1: 1 Received: from irsmsx105.ger.corp.intel.com ([163.33.3.28]) by orsmga005.jf.intel.com with ESMTP; 06 Jun 2019 06:42:56 -0700 Received: from irsmsx112.ger.corp.intel.com (10.108.20.5) by irsmsx105.ger.corp.intel.com (163.33.3.28) with Microsoft SMTP Server (TLS) id 14.3.408.0; Thu, 6 Jun 2019 14:42:56 +0100 Received: from irsmsx104.ger.corp.intel.com ([169.254.5.227]) by irsmsx112.ger.corp.intel.com ([169.254.1.197]) with mapi id 14.03.0415.000; Thu, 6 Jun 2019 14:42:55 +0100 From: "Ananyev, Konstantin" To: Phil Yang , "dev@dpdk.org" CC: "thomas@monjalon.net" , "jerinj@marvell.com" , "hemant.agrawal@nxp.com" , "Honnappa.Nagarahalli@arm.com" , "gavin.hu@arm.com" , "nd@arm.com" Thread-Topic: [dpdk-dev] [PATCH v1 3/3] test/mcslock: add mcs queued lock unit test Thread-Index: AQHVG7fOvf0KS7EIFUaGlqpd3klV2KaOol4g Date: Thu, 6 Jun 2019 13:42:55 +0000 Message-ID: <2601191342CEEE43887BDE71AB97725801688E11F3@IRSMSX104.ger.corp.intel.com> References: <1559750328-22377-1-git-send-email-phil.yang@arm.com> <1559750328-22377-4-git-send-email-phil.yang@arm.com> In-Reply-To: <1559750328-22377-4-git-send-email-phil.yang@arm.com> Accept-Language: en-IE, en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-titus-metadata-40: eyJDYXRlZ29yeUxhYmVscyI6IiIsIk1ldGFkYXRhIjp7Im5zIjoiaHR0cDpcL1wvd3d3LnRpdHVzLmNvbVwvbnNcL0ludGVsMyIsImlkIjoiNWFiZDMxMzUtMTFkOC00Y2ZkLWJkYWEtNjE0ZDk5ZDkxNTgwIiwicHJvcHMiOlt7Im4iOiJDVFBDbGFzc2lmaWNhdGlvbiIsInZhbHMiOlt7InZhbHVlIjoiQ1RQX05UIn1dfV19LCJTdWJqZWN0TGFiZWxzIjpbXSwiVE1DVmVyc2lvbiI6IjE3LjEwLjE4MDQuNDkiLCJUcnVzdGVkTGFiZWxIYXNoIjoiXC9qdWo2MytvdWc5QzR3ODNob1V3TElzN0dBZ3cxKzdUYmx4NEZFMnR3TzNGTFFaWStlMThNbWZKSlFPOE5wZmcifQ== x-ctpclassification: CTP_NT dlp-product: dlpe-windows dlp-version: 11.0.600.7 dlp-reaction: no-action x-originating-ip: [163.33.239.181] Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Subject: Re: [dpdk-dev] [PATCH v1 3/3] test/mcslock: add mcs queued lock unit test X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Hi, >=20 > Unit test and perf test for MCS queued lock. Perf test is important of course, but first I think we need more robust functional test to make sure that lock does work properly. At least something like ticketlock test but probably with bigger number of = iterations. 10K seems quite small here. In fact with this one we'll have 3 lock methods, I think it makes sense to = have=20 one united UT framework for them, so only actual lock/unlock would be diffe= rent. Konstantin >=20 > Signed-off-by: Phil Yang > Reviewed-by: Gavin Hu > Reviewed-by: Honnappa Nagarahalli >=20 > --- > MAINTAINERS | 1 + > app/test/Makefile | 1 + > app/test/autotest_data.py | 6 + > app/test/autotest_test_funcs.py | 32 ++++++ > app/test/meson.build | 2 + > app/test/test_mcslock.c | 248 ++++++++++++++++++++++++++++++++++= ++++++ > 6 files changed, 290 insertions(+) > create mode 100644 app/test/test_mcslock.c >=20 > diff --git a/MAINTAINERS b/MAINTAINERS > index 1390238..33fdc8f 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -225,6 +225,7 @@ F: app/test/test_ticketlock.c > MCSlock - EXPERIMENTAL > M: Phil Yang > F: lib/librte_eal/common/include/generic/rte_mcslock.h > +F: app/test/test_mcslock.c >=20 > ARM v7 > M: Jan Viktorin > diff --git a/app/test/Makefile b/app/test/Makefile > index 68d6b4f..be405cd 100644 > --- a/app/test/Makefile > +++ b/app/test/Makefile > @@ -64,6 +64,7 @@ SRCS-y +=3D test_atomic.c > SRCS-y +=3D test_barrier.c > SRCS-y +=3D test_malloc.c > SRCS-y +=3D test_cycles.c > +SRCS-y +=3D test_mcslock.c > SRCS-y +=3D test_spinlock.c > SRCS-y +=3D test_ticketlock.c > SRCS-y +=3D test_memory.c > diff --git a/app/test/autotest_data.py b/app/test/autotest_data.py > index 0f2c9a7..68ca23d 100644 > --- a/app/test/autotest_data.py > +++ b/app/test/autotest_data.py > @@ -177,6 +177,12 @@ > "Report": None, > }, > { > + "Name": "MCSlock autotest", > + "Command": "mcslock_autotest", > + "Func": mcslock_autotest, > + "Report": None, > + }, > + { > "Name": "Byte order autotest", > "Command": "byteorder_autotest", > "Func": default_autotest, > diff --git a/app/test/autotest_test_funcs.py b/app/test/autotest_test_fun= cs.py > index 31cc0f5..26688b7 100644 > --- a/app/test/autotest_test_funcs.py > +++ b/app/test/autotest_test_funcs.py > @@ -164,6 +164,38 @@ def ticketlock_autotest(child, test_name): >=20 > return 0, "Success" >=20 > +def mcslock_autotest(child, test_name): > + i =3D 0 > + ir =3D 0 > + child.sendline(test_name) > + while True: > + index =3D child.expect(["Test OK", > + "Test Failed", > + "lcore ([0-9]*) state: ([0-1])" > + "MCS lock taken on core ([0-9]*)", > + "MCS lock released on core ([0-9]*)", > + pexpect.TIMEOUT], timeout=3D5) > + # ok > + if index =3D=3D 0: > + break > + > + # message, check ordering > + elif index =3D=3D 2: > + if int(child.match.groups()[0]) < i: > + return -1, "Fail [Bad order]" > + i =3D int(child.match.groups()[0]) > + elif index =3D=3D 3: > + if int(child.match.groups()[0]) < ir: > + return -1, "Fail [Bad order]" > + ir =3D int(child.match.groups()[0]) > + > + # fail > + elif index =3D=3D 4: > + return -1, "Fail [Timeout]" > + elif index =3D=3D 1: > + return -1, "Fail" > + > + return 0, "Success" >=20 > def logs_autotest(child, test_name): > child.sendline(test_name) > diff --git a/app/test/meson.build b/app/test/meson.build > index 83391ce..3f5f17a 100644 > --- a/app/test/meson.build > +++ b/app/test/meson.build > @@ -75,6 +75,7 @@ test_sources =3D files('commands.c', > 'test_memzone.c', > 'test_meter.c', > 'test_metrics.c', > + 'test_mcslock.c', > 'test_mp_secondary.c', > 'test_pdump.c', > 'test_per_lcore.c', > @@ -167,6 +168,7 @@ fast_parallel_test_names =3D [ > 'lpm6_autotest', > 'malloc_autotest', > 'mbuf_autotest', > + 'mcslock_autotest', > 'memcpy_autotest', > 'memory_autotest', > 'mempool_autotest', > diff --git a/app/test/test_mcslock.c b/app/test/test_mcslock.c > new file mode 100644 > index 0000000..a2274e5 > --- /dev/null > +++ b/app/test/test_mcslock.c > @@ -0,0 +1,248 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2019 Arm Limited > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "test.h" > + > +/* > + * RTE MCS lock test > + * =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D > + * > + * These tests are derived from spin lock test cases. > + * > + * - The functional test takes all of these locks and launches the > + * ''test_mcslock_per_core()'' function on each core (except the maste= r). > + * > + * - The function takes the global lock, display something, then relea= ses > + * the global lock on each core. > + * > + * - A load test is carried out, with all cores attempting to lock a sin= gle > + * lock multiple times. > + */ > +#include > + > +RTE_DEFINE_PER_LCORE(rte_mcslock_t, _ml_me); > +RTE_DEFINE_PER_LCORE(rte_mcslock_t, _ml_try_me); > +RTE_DEFINE_PER_LCORE(rte_mcslock_t, _ml_perf_me); > + > +rte_mcslock_t *p_ml; > +rte_mcslock_t *p_ml_try; > +rte_mcslock_t *p_ml_perf; > + > +static unsigned int count; > + > +static rte_atomic32_t synchro; > + > +static int > +test_mcslock_per_core(__attribute__((unused)) void *arg) > +{ > + /* Per core me node. */ > + rte_mcslock_t ml_me =3D RTE_PER_LCORE(_ml_me); > + > + rte_mcslock_lock(&p_ml, &ml_me); > + printf("MCS lock taken on core %u\n", rte_lcore_id()); > + rte_mcslock_unlock(&p_ml, &ml_me); > + printf("MCS lock released on core %u\n", rte_lcore_id()); > + > + return 0; > +} > + > +static uint64_t time_count[RTE_MAX_LCORE] =3D {0}; > + > +#define MAX_LOOP 10000 > + > +static int > +load_loop_fn(void *func_param) > +{ > + uint64_t time_diff =3D 0, begin; > + uint64_t hz =3D rte_get_timer_hz(); > + volatile uint64_t lcount =3D 0; > + const int use_lock =3D *(int *)func_param; > + const unsigned int lcore =3D rte_lcore_id(); > + > + /**< Per core me node. */ > + rte_mcslock_t ml_perf_me =3D RTE_PER_LCORE(_ml_perf_me); > + > + /* wait synchro */ > + while (rte_atomic32_read(&synchro) =3D=3D 0) > + ; > + > + begin =3D rte_get_timer_cycles(); > + while (lcount < MAX_LOOP) { > + if (use_lock) > + rte_mcslock_lock(&p_ml_perf, &ml_perf_me); > + > + lcount++; > + if (use_lock) > + rte_mcslock_unlock(&p_ml_perf, &ml_perf_me); > + } > + time_diff =3D rte_get_timer_cycles() - begin; > + time_count[lcore] =3D time_diff * 1000000 / hz; > + return 0; > +} > + > +static int > +test_mcslock_perf(void) > +{ > + unsigned int i; > + uint64_t total =3D 0; > + int lock =3D 0; > + const unsigned int lcore =3D rte_lcore_id(); > + > + printf("\nTest with no lock on single core...\n"); > + rte_atomic32_set(&synchro, 1); > + load_loop_fn(&lock); > + printf("Core [%u] Cost Time =3D %"PRIu64" us\n", > + lcore, time_count[lcore]); > + memset(time_count, 0, sizeof(time_count)); > + > + printf("\nTest with lock on single core...\n"); > + lock =3D 1; > + rte_atomic32_set(&synchro, 1); > + load_loop_fn(&lock); > + printf("Core [%u] Cost Time =3D %"PRIu64" us\n", > + lcore, time_count[lcore]); > + memset(time_count, 0, sizeof(time_count)); > + > + printf("\nTest with lock on %u cores...\n", (rte_lcore_count()-1)); > + > + rte_atomic32_set(&synchro, 0); > + rte_eal_mp_remote_launch(load_loop_fn, &lock, SKIP_MASTER); > + rte_atomic32_set(&synchro, 1); > + > + rte_eal_mp_wait_lcore(); > + > + RTE_LCORE_FOREACH_SLAVE(i) { > + printf("Core [%u] Cost Time =3D %"PRIu64" us\n", > + i, time_count[i]); > + total +=3D time_count[i]; > + } > + > + printf("Total Cost Time =3D %"PRIu64" us\n", total); > + > + return 0; > +} > + > +/* > + * Use rte_mcslock_trylock() to trylock a mcs lock object, > + * If it could not lock the object successfully, it would > + * return immediately. > + */ > +static int > +test_mcslock_try(__attribute__((unused)) void *arg) > +{ > + /**< Per core me node. */ > + rte_mcslock_t ml_me =3D RTE_PER_LCORE(_ml_me); > + rte_mcslock_t ml_try_me =3D RTE_PER_LCORE(_ml_try_me); > + > + /* Locked ml_try in the master lcore, so it should fail > + * when trying to lock it in the slave lcore. > + */ > + if (rte_mcslock_trylock(&p_ml_try, &ml_try_me) =3D=3D 0) { > + rte_mcslock_lock(&p_ml, &ml_me); > + count++; > + rte_mcslock_unlock(&p_ml, &ml_me); > + } > + > + return 0; > +} > + > + > +/* > + * Test rte_eal_get_lcore_state() in addition to mcs locks > + * as we have "waiting" then "running" lcores. > + */ > +static int > +test_mcslock(void) > +{ > + int ret =3D 0; > + int i; > + > + /* Define per core me node. */ > + rte_mcslock_t ml_me =3D RTE_PER_LCORE(_ml_me); > + rte_mcslock_t ml_try_me =3D RTE_PER_LCORE(_ml_try_me); > + > + /* > + * Test mcs lock & unlock on each core > + */ > + > + /* slave cores should be waiting: print it */ > + RTE_LCORE_FOREACH_SLAVE(i) { > + printf("lcore %d state: %d\n", i, > + (int) rte_eal_get_lcore_state(i)); > + } > + > + rte_mcslock_lock(&p_ml, &ml_me); > + > + RTE_LCORE_FOREACH_SLAVE(i) { > + rte_eal_remote_launch(test_mcslock_per_core, NULL, i); > + } > + > + /* slave cores should be busy: print it */ > + RTE_LCORE_FOREACH_SLAVE(i) { > + printf("lcore %d state: %d\n", i, > + (int) rte_eal_get_lcore_state(i)); > + } > + > + rte_mcslock_unlock(&p_ml, &ml_me); > + > + rte_eal_mp_wait_lcore(); > + > + /* > + * Test if it could return immediately from try-locking a locked object= . > + * Here it will lock the mcs lock object first, then launch all the > + * slave lcores to trylock the same mcs lock object. > + * All the slave lcores should give up try-locking a locked object and > + * return immediately, and then increase the "count" initialized with > + * zero by one per times. > + * We can check if the "count" is finally equal to the number of all > + * slave lcores to see if the behavior of try-locking a locked > + * mcslock object is correct. > + */ > + if (rte_mcslock_trylock(&p_ml_try, &ml_try_me) =3D=3D 0) > + return -1; > + > + count =3D 0; > + RTE_LCORE_FOREACH_SLAVE(i) { > + rte_eal_remote_launch(test_mcslock_try, NULL, i); > + } > + rte_mcslock_unlock(&p_ml_try, &ml_try_me); > + rte_eal_mp_wait_lcore(); > + > + /* Test is_locked API */ > + if (rte_mcslock_is_locked(p_ml)) { > + printf("mcslock is locked but it should not be\n"); > + return -1; > + } > + > + /* Counting the locked times in each core */ > + rte_mcslock_lock(&p_ml, &ml_me); > + if (count !=3D (rte_lcore_count() - 1)) > + ret =3D -1; > + rte_mcslock_unlock(&p_ml, &ml_me); > + > + /* mcs lock perf test */ > + if (test_mcslock_perf() < 0) > + return -1; > + > + return ret; > +} > + > +REGISTER_TEST_COMMAND(mcslock_autotest, test_mcslock); > -- > 2.7.4