Skip to content

Commit

Permalink
powerpc: Add the lock elision using HTM
Browse files Browse the repository at this point in the history
This patch adds support for lock elision using ISA 2.07 hardware
transactional memory instructions for pthread_mutex primitives.
Similar to s390 version, the for elision logic defined in
'force-elision.h' is only enabled if ENABLE_LOCK_ELISION is defined.

Also, the lock elision code should be able to be built even with
a compiler that does not provide HTM support with builtins.
However I have noted the performance is sub-optimal due scheduling
pressures.
  • Loading branch information
Adhemerval Zanella committed Jan 12, 2015
1 parent ec4fbd4 commit 8d2c0a5
Show file tree
Hide file tree
Showing 17 changed files with 709 additions and 5 deletions.
30 changes: 30 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,33 @@
2014-01-12 Adhemerval Zanella <azanella@linux.vnet.ibm.com>

* sysdeps/unix/sysv/linux/powerpc/Makefile [nptl]
(sysdep_routines): Add lock elision objects.
* sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h
[pthread_mutex_t] (__spins): Rework to add lock elision field.
[pthread_mutex_t] (__elision): Add field.
[__PTHREAD_SPINS]: Adjust to init lock elision field.
* sysdeps/unix/sysv/linux/powerpc/elision-conf.c: New file: lock
elision definitions for powerpc.
* sysdeps/unix/sysv/linux/powerpc/elision-lock.c: New file:
implementation of lock elision for powerpc.
* sysdeps/unix/sysv/linux/powerpc/elision-timed.c: New file:
implementation of timed lock elision for powerpc.
* sysdeps/unix/sysv/linux/powerpc/elision-trylock.c: New file:
implementation of trylock with lock elision for powerpc.
* sysdeps/unix/sysv/linux/powerpc/elision-unlock.c: New file:
implementaion of unlock for lock elision for powerpc.
* sysdeps/unix/sysv/linux/powerpc/force-elision.h: New file:
automatic enable lock elision for mutexes.
* sysdeps/unix/sysv/linux/powerpc/htm.h: New file: hardware
transaction execution definitions for powerpc.
* sysdeps/unix/sysv/linux/powerpc/lowlevellock.h: New file: add TLE
definitions.
* sysdeps/unix/sysv/linux/powerpc/pthread_mutex_cond_lock.c: New file.
* sysdeps/unix/sysv/linux/powerpc/pthread_mutex_lock.c: Likewise.
* sysdeps/unix/sysv/linux/powerpc/pthread_mutex_timedlock.c: Likewise.
* sysdeps/unix/sysv/linux/powerpc/pthread_mutex_trylock.c: Likewise.
* NEWS: Update.

2015-01-09 Roland McGrath <roland@hack.frob.com>

* sysdeps/posix/shm-directory.c: Use <> rather than ""
Expand Down
7 changes: 7 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ Version 2.21
17745, 17746, 17747, 17748, 17775, 17777, 17780, 17781, 17782, 17791,
17793, 17796, 17797, 17806

* Added support for TSX lock elision of pthread mutexes on powerpc32, powerpc64
and powerpc64le. This may improve lock scaling of existing programs on
HTM capable systems. The lock elision code is only enabled with
--enable-lock-elision=yes. Also, the TSX lock elision implementation for
powerpc will issue a transaction abort on every syscall to avoid side
effects being visible outside transactions.

* Optimized strcpy, stpcpy, strchrnul and strrchr implementations for
AArch64. Contributed by ARM Ltd.

Expand Down
2 changes: 2 additions & 0 deletions sysdeps/unix/sysv/linux/powerpc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,6 @@ endif

ifeq ($(subdir),nptl)
libpthread-routines += sysdep
libpthread-sysdep_routines += elision-lock elision-unlock elision-timed \
elision-trylock
endif
16 changes: 11 additions & 5 deletions sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,23 @@ typedef union
binary compatibility. */
int __kind;
#if __WORDSIZE == 64
int __spins;
short __spins;
short __elision;
__pthread_list_t __list;
# define __PTHREAD_MUTEX_HAVE_PREV 1
# define __PTHREAD_SPINS 0, 0
#else
unsigned int __nusers;
__extension__ union
{
int __spins;
struct
{
short __espins;
short __elision;
# define __spins __elision_data.__espins
# define __elision __elision_data.__elision
# define __PTHREAD_SPINS { 0, 0 }
} __elision_data;
__pthread_slist_t __list;
};
#endif
Expand All @@ -106,9 +115,6 @@ typedef union
long int __align;
} pthread_mutex_t;

/* Mutex __spins initializer used by PTHREAD_MUTEX_INITIALIZER. */
#define __PTHREAD_SPINS 0

typedef union
{
char __size[__SIZEOF_PTHREAD_MUTEXATTR_T];
Expand Down
80 changes: 80 additions & 0 deletions sysdeps/unix/sysv/linux/powerpc/elision-conf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/* elision-conf.c: Lock elision tunable parameters.
Copyright (C) 2014 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */

#include "config.h"
#include <pthreadP.h>
#include <elision-conf.h>
#include <unistd.h>
#include <dl-procinfo.h>

/* Reasonable initial tuning values, may be revised in the future.
This is a conservative initial value. */

struct elision_config __elision_aconf =
{
/* How many times to use a non-transactional lock after a transactional
failure has occurred because the lock is already acquired. Expressed
in number of lock acquisition attempts. */
.skip_lock_busy = 3,
/* How often to not attempt to use elision if a transaction aborted due
to reasons other than other threads' memory accesses. Expressed in
number of lock acquisition attempts. */
.skip_lock_internal_abort = 3,
/* How often to not attempt to use elision if a lock used up all retries
without success. Expressed in number of lock acquisition attempts. */
.skip_lock_out_of_tbegin_retries = 3,
/* How often we retry using elision if there is chance for the transaction
to finish execution (e.g., it wasn't aborted due to the lock being
already acquired. */
.try_tbegin = 3,
/* Same as SKIP_LOCK_INTERNAL_ABORT but for trylock. */
.skip_trylock_internal_abort = 3,
};

/* Force elision for all new locks. This is used to decide whether existing
DEFAULT locks should be automatically use elision in pthread_mutex_lock().
Disabled for suid programs. Only used when elision is available. */

int __pthread_force_elision attribute_hidden;

/* Initialize elision. */

static void
elision_init (int argc __attribute__ ((unused)),
char **argv __attribute__ ((unused)),
char **environ)
{
#ifdef ENABLE_LOCK_ELISION
int elision_available = (GLRO (dl_hwcap2) & PPC_FEATURE2_HAS_HTM) ? 1 : 0;
__pthread_force_elision = __libc_enable_secure ? 0 : elision_available;
#endif
}

#ifdef SHARED
# define INIT_SECTION ".init_array"
# define MAYBE_CONST
#else
# define INIT_SECTION ".preinit_array"
# define MAYBE_CONST const
#endif

void (*MAYBE_CONST __pthread_init_array []) (int, char **, char **)
__attribute__ ((section (INIT_SECTION), aligned (sizeof (void *)))) =
{
&elision_init
};
42 changes: 42 additions & 0 deletions sysdeps/unix/sysv/linux/powerpc/elision-conf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* elision-conf.h: Lock elision tunable parameters.
Copyright (C) 2014 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */

#ifndef _ELISION_CONF_H
#define _ELISION_CONF_H 1

#include <pthread.h>
#include <time.h>

/* Should make sure there is no false sharing on this. */
struct elision_config
{
int skip_lock_busy;
int skip_lock_internal_abort;
int skip_lock_out_of_tbegin_retries;
int try_tbegin;
int skip_trylock_internal_abort;
} __attribute__ ((__aligned__ (128)));

extern struct elision_config __elision_aconf attribute_hidden;

extern int __pthread_force_elision attribute_hidden;

/* Tell the test suite to test elision for this architecture. */
#define HAVE_ELISION 1

#endif
107 changes: 107 additions & 0 deletions sysdeps/unix/sysv/linux/powerpc/elision-lock.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/* elision-lock.c: Elided pthread mutex lock.
Copyright (C) 2014 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */

#include <stdio.h>
#include <pthread.h>
#include <pthreadP.h>
#include <lowlevellock.h>
#include <elision-conf.h>
#include "htm.h"

/* PowerISA 2.0.7 Section B.5.5 defines isync to be insufficient as a
barrier in acquire mechanism for HTM operations, a strong 'sync' is
required. */
#undef __arch_compare_and_exchange_val_32_acq
#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \
({ \
__typeof (*(mem)) __tmp; \
__typeof (mem) __memp = (mem); \
__asm __volatile ( \
"1: lwarx %0,0,%1" MUTEX_HINT_ACQ "\n" \
" cmpw %0,%2\n" \
" bne 2f\n" \
" stwcx. %3,0,%1\n" \
" bne- 1b\n" \
"2: sync" \
: "=&r" (__tmp) \
: "b" (__memp), "r" (oldval), "r" (newval) \
: "cr0", "memory"); \
__tmp; \
})

#if !defined(LLL_LOCK) && !defined(EXTRAARG)
/* Make sure the configuration code is always linked in for static
libraries. */
#include "elision-conf.c"
#endif

#ifndef EXTRAARG
# define EXTRAARG
#endif
#ifndef LLL_LOCK
# define LLL_LOCK(a,b) lll_lock(a,b), 0
#endif

#define aconf __elision_aconf

/* Adaptive lock using transactions.
By default the lock region is run as a transaction, and when it
aborts or the lock is busy the lock adapts itself. */

int
__lll_lock_elision (int *lock, short *adapt_count, EXTRAARG int pshared)
{
if (*adapt_count > 0)
{
(*adapt_count)--;
goto use_lock;
}

int try_begin = aconf.try_tbegin;
while (1)
{
if (__builtin_tbegin (0))
{
if (*lock == 0)
return 0;
/* Lock was busy. Fall back to normal locking. */
__builtin_tabort (_ABORT_LOCK_BUSY);
}
else
{
/* A persistent failure indicates that a retry will probably
result in another failure. Use normal locking now and
for the next couple of calls. */
if (try_begin-- <= 0
|| _TEXASRU_FAILURE_PERSISTENT (__builtin_get_texasru ()))
{
if (aconf.skip_lock_internal_abort > 0)
*adapt_count = aconf.skip_lock_internal_abort;
goto use_lock;
}
/* Same logic as above, but for for a number of temporary failures
in a row. */
else if (aconf.skip_lock_out_of_tbegin_retries > 0
&& aconf.try_tbegin > 0)
*adapt_count = aconf.skip_lock_out_of_tbegin_retries;
}
}

use_lock:
return LLL_LOCK ((*lock), pshared);
}
28 changes: 28 additions & 0 deletions sysdeps/unix/sysv/linux/powerpc/elision-timed.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* elision-timed.c: Lock elision timed lock.
Copyright (C) 2014 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */

#include <time.h>
#include <elision-conf.h>
#include "lowlevellock.h"

#define __lll_lock_elision __lll_timedlock_elision
#define EXTRAARG const struct timespec *t,
#undef LLL_LOCK
#define LLL_LOCK(a, b) lll_timedlock(a, t, b)

#include "elision-lock.c"
Loading

0 comments on commit 8d2c0a5

Please sign in to comment.