From: Johannes Stezenbach <js@convergence.de>
To: "Kevin D. Kissell" <kevink@mips.com>
Cc: linux-mips@oss.sgi.com
Subject: LL/SC benchmarking [was: Mipsel libc with LL/SC online anywhere?]
Date: Fri, 19 Jul 2002 14:38:29 +0200 [thread overview]
Message-ID: <20020719123828.GA5521@convergence.de> (raw)
In-Reply-To: <00ce01c229a4$a7d4ed40$10eca8c0@grendel>
On Fri, Jul 12, 2002 at 03:04:07PM +0200, Kevin D. Kissell wrote:
> I'm benchmarking some code that does lots of
> semaphores, and with the libc from the "standard"
> MIPS/SGI RH 7.1 distribution, those are done using
> sysmips, in the interest of universality.
I'm working on a platform without LL/SC, an embedded system/SOC
with a NEC VR4120A CPU core. To find out the effect of sysmips
vs. emulated LL/SC vs. the branch-likely trick posted by
Kevin D. Kissell <kevink@mips.com> on Tue, 22 Jan 2002 18:16:25 +0100
I created an experimental patch for glibc-2.2.5 which allows
run-time switching of the _test_and_set() and __compare_and_swap()
implementation based on the presence of two "switch files" in /etc/.
Despite its ugliness, I include the patch below for those interested.
(Note: I built my glibc with -mips2, so the patch lacks .set mips2
directives.)
One thing that caused me some headaches was that the __compare_and_swap()
implementation in glibc-2.2.5 is broken (but fixed in glibc CVS and H.J.Lu's
patch).
For lack of a better benchmark I used some of the examples from
glibc-2.2.5/linuxthreads/Examples. The numbers are from the third
of three successive runs of 'time exN >/dev/null'.
sysmips:
ex1 real 0m0.273s user 0m0.040s sys 0m0.230s
ex2 real 0m10.911s user 0m2.730s sys 0m8.180s
ex3 real 0m3.648s user 0m3.400s sys 0m0.250s
ex5 real 0m4.539s user 0m1.830s sys 0m2.710s
ll/sc emulation:
ex1 real 0m0.272s user 0m0.020s sys 0m0.250s
ex2 real 0m4.726s user 0m1.660s sys 0m3.060s
ex3 real 0m3.968s user 0m3.750s sys 0m0.220s
ex5 real 0m4.069s user 0m1.710s sys 0m2.360s
beql-hack:
ex1 real 0m0.268s user 0m0.010s sys 0m0.260s
ex2 real 0m3.988s user 0m1.620s sys 0m2.360s
ex3 real 0m3.965s user 0m3.740s sys 0m0.220s
ex5 real 0m2.606s user 0m1.000s sys 0m1.600s
I think the poor performance of sysmips is caused by the absence of
__compare_and_swap(), which forces libpthread to use less efficient
implementations for semaphore and lock functions.
Running each of the four tests three times yields around one million
LL/SC emulations in /proc/cpuinfo.
I think the beql-hack needs a kernel patch to guarantee k1 !=
MAGIC_COOKIE after each eret, but for a those few tests I was just
taking my chance.
Next, I'm trying to run the pthread tests from LTP. If someone
has a better benchmark code for pthread performance, I'm interested.
Regards,
Johannes
diff -uarN glibc-2.2.5.orig/linuxthreads/sysdeps/mips/pspinlock.c glibc-2.2.5/linuxthreads/sysdeps/mips/pspinlock.c
--- glibc-2.2.5.orig/linuxthreads/sysdeps/mips/pspinlock.c Thu Jul 18 14:28:07 2002
+++ glibc-2.2.5/linuxthreads/sysdeps/mips/pspinlock.c Thu Jul 18 18:35:46 2002
@@ -23,7 +23,93 @@
#include <sys/tas.h>
#include "internals.h"
-#if (_MIPS_ISA >= _MIPS_ISA_MIPS2)
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+static int
+_compare_and_swap_mips2 (long int *p, long int oldval, long int newval)
+{
+ long int ret;
+
+ __asm__ __volatile__
+ ("/* Inline compare & swap */\n\t"
+ "1:\n\t"
+ "ll %0,%4\n\t"
+ ".set push\n"
+ ".set noreorder\n\t"
+ "bne %0,%2,2f\n\t"
+ "move %0,$0\n\t"
+ "move %0,%3\n\t"
+ ".set pop\n\t"
+ "sc %0,%1\n\t"
+ "beqz %0,1b\n"
+ "2:\n\t"
+ "/* End compare & swap */"
+ : "=&r" (ret), "=m" (*p)
+ : "r" (oldval), "r" (newval), "m" (*p)
+ : "memory");
+
+ return ret;
+}
+
+static int
+_compare_and_swap_mips2_nollsc (long int *p, long int oldval, long int newval)
+{
+ long int r, t;
+
+ __asm__ __volatile__
+ (".set push\n\t"
+ ".set noreorder\n\t"
+ "li %1,0xffaaffaa\n\t" /* MAGIC_COOKIE */
+ "1:\n\t"
+ "move $27,%1\n\t" /* set k1 */
+ "lw %0,%5\n\t" /* r = *p */
+ "bne %0,%3,3f\n\t" /* if (r != oldval) return 0 */
+ "move %0,$0\n\t" /* r = 0 */
+ "move %0,%4\n\t" /* r = newval */
+ "beql $27,%1,2f\n\t" /* test k1 for change */
+ "sw %0,%2\n\t" /* *p = r; return 1 */
+ "b 1b\n\t" /* k1 changed, retry */
+ "nop\n\t"
+ ".set pop\n\t"
+ "2:\n"
+ "li %0,1\n\t" /* r = 1 */
+ "3:\n"
+ : "=&r" (r), "=&r" (t), "=m" (*p)
+ : "r" (oldval), "r" (newval), "m" (*p)
+ : "memory");
+
+ return r;
+}
+
+int
+compare_and_swap_is_available (void)
+{
+ int fp;
+ /* FIXME: write real test */
+ if ((fp =open ("/etc/mips2_cpu_without_llsc", O_RDONLY)) != -1)
+ {
+ close(fp);
+ _mips_compare_and_swap = _compare_and_swap_mips2_nollsc;
+ return 1;
+ }
+ if ((fp =open ("/etc/mips2_cpu_with_llsc", O_RDONLY)) != -1)
+ {
+ close(fp);
+ _mips_compare_and_swap = _compare_and_swap_mips2;
+ return 1;
+ }
+ return 0;
+}
+
+int (* _mips_compare_and_swap) (long int *p, long int oldval, long int newval)
+ = NULL;
+
+
+#if 0 && (_MIPS_ISA >= _MIPS_ISA_MIPS2)
+ /* don't nother, no one uses this... */
/* This implementation is similar to the one used in the Linux kernel. */
int
diff -uarN glibc-2.2.5.orig/linuxthreads/sysdeps/mips/pt-machine.h glibc-2.2.5/linuxthreads/sysdeps/mips/pt-machine.h
--- glibc-2.2.5.orig/linuxthreads/sysdeps/mips/pt-machine.h Thu Jul 18 14:28:13 2002
+++ glibc-2.2.5/linuxthreads/sysdeps/mips/pt-machine.h Thu Jul 18 16:27:15 2002
@@ -33,41 +33,11 @@
/* Spinlock implementation; required. */
-#if (_MIPS_ISA >= _MIPS_ISA_MIPS2)
-
-PT_EI long int
-testandset (int *spinlock)
-{
- long int ret, temp;
-
- __asm__ __volatile__
- ("/* Inline spinlock test & set */\n\t"
- "1:\n\t"
- "ll %0,%3\n\t"
- ".set push\n\t"
- ".set noreorder\n\t"
- "bnez %0,2f\n\t"
- " li %1,1\n\t"
- ".set pop\n\t"
- "sc %1,%2\n\t"
- "beqz %1,1b\n"
- "2:\n\t"
- "/* End spinlock test & set */"
- : "=&r" (ret), "=&r" (temp), "=m" (*spinlock)
- : "m" (*spinlock)
- : "memory");
-
- return ret;
-}
-
-#else /* !(_MIPS_ISA >= _MIPS_ISA_MIPS2) */
-
PT_EI long int
testandset (int *spinlock)
{
return _test_and_set (spinlock, 1);
}
-#endif /* !(_MIPS_ISA >= _MIPS_ISA_MIPS2) */
/* Get some notion of the current stack. Need not be exactly the top
@@ -78,32 +48,13 @@
/* Compare-and-swap for semaphores. */
-#if (_MIPS_ISA >= _MIPS_ISA_MIPS2)
-
#define HAS_COMPARE_AND_SWAP
+#define TEST_FOR_COMPARE_AND_SWAP
+extern int (* _mips_compare_and_swap) (long int *p, long int oldval, long int newval);
+extern int compare_and_swap_is_available (void);
+
PT_EI int
__compare_and_swap (long int *p, long int oldval, long int newval)
{
- long int ret;
-
- __asm__ __volatile__
- ("/* Inline compare & swap */\n\t"
- "1:\n\t"
- "ll %0,%4\n\t"
- ".set push\n"
- ".set noreorder\n\t"
- "bne %0,%2,2f\n\t"
- " move %0,%3\n\t"
- ".set pop\n\t"
- "sc %0,%1\n\t"
- "beqz %0,1b\n"
- "2:\n\t"
- "/* End compare & swap */"
- : "=&r" (ret), "=m" (*p)
- : "r" (oldval), "r" (newval), "m" (*p)
- : "memory");
-
- return ret;
+ return _mips_compare_and_swap (p, oldval, newval);
}
-
-#endif /* (_MIPS_ISA >= _MIPS_ISA_MIPS2) */
diff -uarN glibc-2.2.5.orig/sysdeps/unix/sysv/linux/mips/_test_and_set.c glibc-2.2.5/sysdeps/unix/sysv/linux/mips/_test_and_set.c
--- glibc-2.2.5.orig/sysdeps/unix/sysv/linux/mips/_test_and_set.c Thu Jul 18 00:21:15 2002
+++ glibc-2.2.5/sysdeps/unix/sysv/linux/mips/_test_and_set.c Thu Jul 18 14:39:01 2002
@@ -21,6 +21,12 @@
defined in sys/tas.h */
#include <features.h>
+#include <sgidefs.h>
+#include <sys/sysmips.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
#define _EXTERN_INLINE
#ifndef __USE_EXTERN_INLINES
@@ -28,3 +34,80 @@
#endif
#include "sys/tas.h"
+
+
+static int
+_test_and_set_mips2_nollsc (int *p, int v) __THROW
+{
+ int r, t;
+
+ __asm__ __volatile__
+ (".set push\n\t"
+ ".set noreorder\n\t"
+ "li %1,0xffaaffaa\n\t" /* MAGIC_COOKIE */
+ "1:\n\t"
+ "move $27,%1\n\t" /* set k1 */
+ "lw %0,%3\n\t" /* r = *p */
+ "beq %0,%4,2f\n\t" /* if (*p == v) return r */
+ "beql $27,%1,2f\n\t" /* test k1 for change */
+ "sw %4,%2\n\t" /* *p = v; return r */
+ "b 1b\n\t" /* retry */
+ "nop\n\t"
+ ".set pop\n\t"
+ "2:\n"
+ : "=&r" (r), "=&r" (t), "=m" (*p)
+ : "m" (*p), "r" (v)
+ : "memory");
+
+ return r;
+}
+
+static int
+_test_and_set_mips2 (int *p, int v) __THROW
+{
+ int r, t;
+
+ __asm__ __volatile__
+ ("1:\n\t"
+ "ll %0,%3\n\t"
+ ".set push\n\t"
+ ".set noreorder\n\t"
+ "beq %0,%4,2f\n\t"
+ " move %1,%4\n\t"
+ ".set pop\n\t"
+ "sc %1,%2\n\t"
+ "beqz %1,1b\n"
+ "2:\n"
+ : "=&r" (r), "=&r" (t), "=m" (*p)
+ : "m" (*p), "r" (v)
+ : "memory");
+
+ return r;
+}
+
+static int
+_test_and_set_mips1 (int *p, int v) __THROW
+{
+ return sysmips (MIPS_ATOMIC_SET, (int) p, v, 0);
+}
+
+static int
+_mips_test_and_set_init (int *p, int v) __THROW
+{
+ int fp;
+ _mips_test_and_set = _test_and_set_mips1;
+ /* FIXME: write real test */
+ if ((fp =open ("/etc/mips2_cpu_without_llsc", O_RDONLY)) != -1)
+ {
+ close(fp);
+ _mips_test_and_set = _test_and_set_mips2_nollsc;
+ }
+ else if ((fp =open ("/etc/mips2_cpu_with_llsc", O_RDONLY)) != -1)
+ {
+ close(fp);
+ _mips_test_and_set = _test_and_set_mips2;
+ }
+ return _mips_test_and_set (p, v);
+}
+
+int (* _mips_test_and_set) (int *p, int v) __THROW = _mips_test_and_set_init;
diff -uarN glibc-2.2.5.orig/sysdeps/unix/sysv/linux/mips/sys/tas.h glibc-2.2.5/sysdeps/unix/sysv/linux/mips/sys/tas.h
--- glibc-2.2.5.orig/sysdeps/unix/sysv/linux/mips/sys/tas.h Thu Jul 18 00:13:21 2002
+++ glibc-2.2.5/sysdeps/unix/sysv/linux/mips/sys/tas.h Thu Jul 18 00:26:54 2002
@@ -27,6 +27,7 @@
__BEGIN_DECLS
extern int _test_and_set (int *p, int v) __THROW;
+extern int (* _mips_test_and_set) (int *p, int v) __THROW;
#ifdef __USE_EXTERN_INLINES
@@ -34,40 +35,11 @@
# define _EXTERN_INLINE extern __inline
# endif
-# if (_MIPS_ISA >= _MIPS_ISA_MIPS2)
-
-_EXTERN_INLINE int
-_test_and_set (int *p, int v) __THROW
-{
- int r, t;
-
- __asm__ __volatile__
- ("1:\n\t"
- "ll %0,%3\n\t"
- ".set push\n\t"
- ".set noreorder\n\t"
- "beq %0,%4,2f\n\t"
- " move %1,%4\n\t"
- ".set pop\n\t"
- "sc %1,%2\n\t"
- "beqz %1,1b\n"
- "2:\n"
- : "=&r" (r), "=&r" (t), "=m" (*p)
- : "m" (*p), "r" (v)
- : "memory");
-
- return r;
-}
-
-# else /* !(_MIPS_ISA >= _MIPS_ISA_MIPS2) */
-
_EXTERN_INLINE int
_test_and_set (int *p, int v) __THROW
{
- return sysmips (MIPS_ATOMIC_SET, (int) p, v, 0);
+ return _mips_test_and_set (p, v);
}
-
-# endif /* !(_MIPS_ISA >= _MIPS_ISA_MIPS2) */
#endif /* __USE_EXTERN_INLINES */
next prev parent reply other threads:[~2002-07-19 12:39 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2002-07-12 13:04 Mipsel libc with LL/SC online anywhere? Kevin D. Kissell
2002-07-12 13:04 ` Kevin D. Kissell
2002-07-19 12:38 ` Johannes Stezenbach [this message]
2002-07-19 15:54 ` LL/SC benchmarking [was: Mipsel libc with LL/SC online anywhere?] Richard Hodges
2002-07-22 10:35 ` Johannes Stezenbach
2002-07-25 16:25 ` Johannes Stezenbach
2002-07-25 17:06 ` Jun Sun
2002-07-25 18:45 ` Johannes Stezenbach
2002-07-25 18:56 ` Jun Sun
2002-07-25 19:24 ` Johannes Stezenbach
2002-07-25 21:49 ` Kevin D. Kissell
2002-07-26 19:35 ` Kevin D. Kissell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20020719123828.GA5521@convergence.de \
--to=js@convergence.de \
--cc=kevink@mips.com \
--cc=linux-mips@oss.sgi.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox