From patchwork Tue Jun 21 16:17:39 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: tip-bot for Dave Martin X-Patchwork-Id: 902582 Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by demeter2.kernel.org (8.14.4/8.14.4) with ESMTP id p5LGJB4U022414 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Tue, 21 Jun 2011 16:19:32 GMT Received: from canuck.infradead.org ([2001:4978:20e::1]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QZ3fE-0000BC-05; Tue, 21 Jun 2011 16:18:56 +0000 Received: from localhost ([127.0.0.1] helo=canuck.infradead.org) by canuck.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1QZ3fD-0000MI-LH; Tue, 21 Jun 2011 16:18:55 +0000 Received: from casper.infradead.org ([2001:770:15f::2]) by canuck.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QZ3fB-0000Lo-0S for linux-arm-kernel@canuck.infradead.org; Tue, 21 Jun 2011 16:18:53 +0000 Received: from mail-wy0-f177.google.com ([74.125.82.177]) by casper.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QZ3f2-0007Un-OS for linux-arm-kernel@lists.infradead.org; Tue, 21 Jun 2011 16:18:46 +0000 Received: by wyf23 with SMTP id 23so4005841wyf.36 for ; Tue, 21 Jun 2011 09:17:54 -0700 (PDT) Received: by 10.227.12.18 with SMTP id v18mr1325036wbv.89.1308673074458; Tue, 21 Jun 2011 09:17:54 -0700 (PDT) Received: from arm.com (fw-lnat.cambridge.arm.com [217.140.96.63]) by mx.google.com with ESMTPS id ej7sm4120962wbb.36.2011.06.21.09.17.53 (version=SSLv3 cipher=OTHER); Tue, 21 Jun 2011 09:17:53 -0700 (PDT) Date: Tue, 21 Jun 2011 17:17:39 +0100 From: Dave Martin To: Nicolas Pitre Subject: Re: Git pull request: 64-bit atomic user helper Message-ID: <20110621161739.GA2519@arm.com> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.21 (2010-09-15) X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20110621_171844_897747_06DE795D X-CRM114-Status: GOOD ( 25.22 ) X-Spam-Score: -2.6 (--) X-Spam-Report: SpamAssassin version 3.3.2-r929478 on casper.infradead.org summary: Content analysis details: (-2.6 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [74.125.82.177 listed in list.dnswl.org] -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: Russell King - ARM Linux , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter2.kernel.org [140.211.167.43]); Tue, 21 Jun 2011 16:19:33 +0000 (UTC) On Mon, Jun 20, 2011 at 09:54:07PM -0400, Nicolas Pitre wrote: > Russell, please pull the following for the next merge window: > > git://git.linaro.org/people/nico/linux.git cmpxchg64 > > This series cleans up the kuser documentation, then it adds 64-bit > cmpxchg support as needed by some user space applications. > > Tested with the initial libgcc patches relying on this, using a > kernel that has this series applied, and another without those > patches to verify that the test for the availability of the needed > helper does work as intended. If you like: Tested-by: Dave Martin Here's my silly test program. It passed on a pandaboard (2-core A9) with -O3 -DITERATIONS=1000000000ULL -DBITS64 (Really, -O should not make a significant difference, though.) Since the test just loops around __kuser_cmpxchg64(), if the number of involuntary preemptions of a thread is non-trivial, some of those preemptions will occur inside the kuser helper. # ./tst-kuser __kuser_helper_version = 5 iterations * 8696638275910399085 = 7609822085224859648 Thread 0: 17992 preemptions Thread 1: 17636 preemptions Thread 2: 17885 preemptions Thread 3: 17517 preemptions OK --- /dev/null 2011-06-20 16:05:05.019195001 +0000 +++ tst-kuser.c 2011-06-20 17:45:12.000000000 +0000 @@ -0,0 +1,158 @@ +#include +#include +#include +#include +#include +#include + +#include "kuser.h" + +#ifndef ITERATIONS +#define ITERATIONS 1000000000ULL +#endif + +#ifndef INCREMENT +#ifdef BITS64 +/* + * So that target visits every value before repeating, + * INCREMENT should be an odd number. + * So that imperfect atomicity does not go unnoticed, + * INCREMENT should have plenty of non-zero bits, so that + * many bits of target change each time INCREMENT is added. + */ +#define INCREMENT 0x78B0AA6F67B4746DULL +#else +#define INCREMENT 0x67B4746DU +#endif +#endif + +#ifndef THREADS +#define THREADS 4 +#endif + +#ifdef BITS64 +static volatile long long target = 0; +#else +static volatile unsigned target = 0; +#endif + +struct thread_struct { + pthread_t thread; + volatile unsigned preemption_count; +}; + +#ifdef BITS64 +static void atomic_inc(long long volatile *p) +#else +static void atomic_inc(unsigned volatile *p) +#endif +{ +#ifdef BITS64 + long long i, j; +#else + int i, j; +#endif + + do { + + i = *p; + j = i + INCREMENT; +#ifdef BITS64 + } while(__kuser_cmpxchg64(&i, &j, p)); +#else + } while(__kuser_cmpxchg(i, j, p)); +#endif +} + +static unsigned thread_involuntary_switches(void) +{ + unsigned result = 0; + FILE *f = NULL; + char buf[80]; +#define FORMAT "/proc/%d/sched" + char namebuf[sizeof FORMAT + 10]; + pid_t tid; + + tid = syscall(__NR_gettid); + if(snprintf(namebuf, sizeof namebuf, FORMAT, tid) >= sizeof namebuf) + goto error; + f = fopen(namebuf, "r"); + if(!f) + goto error; + + while(fgets(buf, sizeof buf, f)) + if(sscanf(buf, "nr_involuntary_switches : %d", &result)) + goto done; + +error: + fprintf(stderr, + "Warning: %d: unable to read nr_involuntary_switches count\n", + tid); +done: + if(f) + fclose(f); + return result; +} + +static void *thread_func(void *arg) +{ + struct thread_struct *me = arg; + + unsigned i; + + for(i = 0; i < ITERATIONS; i++) + atomic_inc(&target); + + me->preemption_count = thread_involuntary_switches(); + + return me; +} + +int main(void) +{ + unsigned i; + struct thread_struct threads[THREADS]; + + fprintf(stderr, "__kuser_helper_version = %d\n", + __kuser_helper_version); +#ifdef BTIS64 + if(__kuser_helper_version < 5) { +#else + if(__kuser_helper_version < 3) { +#endif + fputs("Kernel too old\n", stderr); + exit(EXIT_FAILURE); + } + + for(i = 0; i < THREADS; i++) + pthread_create(&threads[i].thread, NULL, + thread_func, &threads[i]); + + for(i = 0; i < THREADS; i++) + pthread_join(threads[i].thread, NULL); + + /* + * For now, just leave the signaller threads running. + * They should be harmless. + */ + +#ifdef BITS64 + fprintf(stderr, "iterations * %llu = %llu\n", INCREMENT, target); +#else + fprintf(stderr, "iterations * %u = %u\n", INCREMENT, target); +#endif + + for(i = 0; i < THREADS; i++) + fprintf(stderr, "\tThread %u:\t%10u preemptions\n", + i, threads[i].preemption_count); + + if(ITERATIONS * INCREMENT * THREADS != target) { + fputs("Error: Wrong final value of target.\n", stderr); + return EXIT_FAILURE; + } else { + fputs("OK\n", stderr); + return EXIT_SUCCESS; + } + + return 0; +} --- /dev/null 2011-06-20 16:05:05.019195001 +0000 +++ kuser.h 2011-06-20 16:44:28.000000000 +0000 @@ -0,0 +1,18 @@ +#ifndef __ARM_KUSER_H +#define __ARM_KUSER_H + +#define __kuser_helper_version (*(int *)0xffff0ffc) + +#define __kuser_decl __attribute__ (( __unused__ )) static + +__kuser_decl int __kuser_cmpxchg64(const long long *oldval, const long long *newval, volatile long long *ptr) +{ + return ((int (*)(const long long *, const long long *, volatile long long *))0xffff0f60)(oldval, newval, ptr); +} + +__kuser_decl int __kuser_cmpxchg(int oldval, int newval, volatile int *ptr) +{ + return ((int (*)(int oldval, int newval, volatile int *))0xffff0fc0)(oldval, newval, ptr); +} + +#endif /* __ARM_KUSER_H */