summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorchappedm@gmail.com <chappedm@gmail.com@6b5cf1ce-ec42-a296-1ba9-69fdba395a50>2012-12-22 20:06:47 +0000
committerchappedm@gmail.com <chappedm@gmail.com@6b5cf1ce-ec42-a296-1ba9-69fdba395a50>2012-12-22 20:06:47 +0000
commit84b983c8d43f43a3c7f71d45d51fc4adcc688cd9 (patch)
tree7976021f2984cb489d544634af4f45961299c8c2
parenta5dacccd6ae4cbfedb5263bfe0f325f03c7f0db8 (diff)
downloadgperftools-84b983c8d43f43a3c7f71d45d51fc4adcc688cd9.tar.gz
issue-465: Adding automagic support for __builtin_expect
Previously __builtin_ expect was based on a macro check against gcc version. Now we perform the check via AM which is a cleaner approach. There are also a number of code changes here to utilize LIKELY/UNLIKELY macros based on __builtin_expect to improve performance. git-svn-id: http://gperftools.googlecode.com/svn/trunk@189 6b5cf1ce-ec42-a296-1ba9-69fdba395a50
-rwxr-xr-xconfigure27
-rw-r--r--configure.ac8
-rw-r--r--src/base/basictypes.h17
-rw-r--r--src/common.h8
-rw-r--r--src/config.h.in3
-rw-r--r--src/tcmalloc.cc22
6 files changed, 57 insertions, 28 deletions
diff --git a/configure b/configure
index 8dc009a..a5c1763 100755
--- a/configure
+++ b/configure
@@ -16233,6 +16233,33 @@ fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
+# Check for __builtin_expect()
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __builtin_expect()" >&5
+$as_echo_n "checking for __builtin_expect()... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+return __builtin_expect(main != 0, 1)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+$as_echo "#define HAVE_BUILTIN_EXPECT 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
# Check if __environ is available (for GetenvBeforeMain)
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __environ" >&5
$as_echo_n "checking for __environ... " >&6; }
diff --git a/configure.ac b/configure.ac
index f4ca2de..efe3217 100644
--- a/configure.ac
+++ b/configure.ac
@@ -289,6 +289,14 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM(, [void *sp = __builtin_stack_pointer()])],
AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])])
+# Check for __builtin_expect()
+AC_MSG_CHECKING([for __builtin_expect()])
+AC_LINK_IFELSE([AC_LANG_PROGRAM(, return __builtin_expect(main != 0, 1))],
+ [AC_DEFINE(HAVE_BUILTIN_EXPECT, 1,
+ Define to 1 if compiler supports __builtin_expect)
+ AC_MSG_RESULT([yes])],
+ [AC_MSG_RESULT([no])])
+
# Check if __environ is available (for GetenvBeforeMain)
AC_MSG_CHECKING([for __environ])
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <unistd.h>],
diff --git a/src/base/basictypes.h b/src/base/basictypes.h
index a5f971e..b002aa5 100644
--- a/src/base/basictypes.h
+++ b/src/base/basictypes.h
@@ -360,21 +360,4 @@ namespace base {
enum LinkerInitialized { LINKER_INITIALIZED };
}
-// Macros for performing optimizations based on branch prediction.
-#if defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 303)
-#ifndef LIKELY
-# define LIKELY(x) __builtin_expect(!!(x), 1)
-#endif
-#ifndef UNLIKELY
-# define UNLIKELY(x) __builtin_expect(!!(x), 0)
-#endif
-#else // not !defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 303)
-#ifndef LIKELY
-# define LIKELY(x) (x)
-#endif
-#ifndef UNLIKELY
-# define UNLIKELY(x) (x)
-#endif
-#endif // defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 303)
-
#endif // _BASICTYPES_H_
diff --git a/src/common.h b/src/common.h
index 3e5cd19..b0c4877 100644
--- a/src/common.h
+++ b/src/common.h
@@ -43,6 +43,14 @@
#include "internal_logging.h" // for ASSERT, etc
#include "base/basictypes.h" // for LIKELY, etc
+#ifdef HAVE_BUILTIN_EXPECT
+#define LIKELY(x) __builtin_expect(!!(x), 1)
+#define UNLIKELY(x) __builtin_expect(!!(x), 0)
+#else
+#define LIKELY(x) (x)
+#define UNLIKELY(x) (x)
+#endif
+
// Type that can hold a page number
typedef uintptr_t PageID;
diff --git a/src/config.h.in b/src/config.h.in
index 4eed17a..b13d0c8 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -5,6 +5,9 @@
#define GPERFTOOLS_CONFIG_H_
+/* Define to 1 if compiler supports __builtin_expect */
+#undef HAVE_BUILTIN_EXPECT
+
/* Define to 1 if compiler supports __builtin_stack_pointer */
#undef HAVE_BUILTIN_STACK_POINTER
diff --git a/src/tcmalloc.cc b/src/tcmalloc.cc
index af04e04..857da14 100644
--- a/src/tcmalloc.cc
+++ b/src/tcmalloc.cc
@@ -969,13 +969,13 @@ static void* DoSampledAllocation(size_t size) {
SpinLockHolder h(Static::pageheap_lock());
// Allocate span
Span *span = Static::pageheap()->New(tcmalloc::pages(size == 0 ? 1 : size));
- if (span == NULL) {
+ if (UNLIKELY(span == NULL)) {
return NULL;
}
// Allocate stack trace
StackTrace *stack = Static::stacktrace_allocator()->New();
- if (stack == NULL) {
+ if (UNLIKELY(stack == NULL)) {
// Sampling failed because of lack of memory
return span;
}
@@ -1064,7 +1064,7 @@ inline void* do_malloc_pages(ThreadCache* heap, size_t size) {
} else {
SpinLockHolder h(Static::pageheap_lock());
Span* span = Static::pageheap()->New(num_pages);
- result = (span == NULL ? NULL : SpanToMallocResult(span));
+ result = (UNLIKELY(span == NULL) ? NULL : SpanToMallocResult(span));
report_large = should_report_large(num_pages);
}
@@ -1231,7 +1231,7 @@ inline size_t GetSizeWithCallback(const void* ptr,
return Static::sizemap()->ByteSizeForClass(cl);
} else {
const Span *span = Static::pageheap()->GetDescriptor(p);
- if (span == NULL) { // means we do not own this memory
+ if (UNLIKELY(span == NULL)) { // means we do not own this memory
return (*invalid_getsize_fn)(ptr);
} else if (span->sizeclass != 0) {
Static::pageheap()->CacheSizeClass(p, span->sizeclass);
@@ -1270,7 +1270,7 @@ inline void* do_realloc_with_callback(
// Either new_size is not a tiny increment, or last do_malloc failed.
new_ptr = do_malloc_or_cpp_alloc(new_size);
}
- if (new_ptr == NULL) {
+ if (UNLIKELY(new_ptr == NULL)) {
return NULL;
}
MallocHook::InvokeNewHook(new_ptr, new_size);
@@ -1313,7 +1313,7 @@ void* do_memalign(size_t align, size_t size) {
return p;
}
- if (Static::pageheap() == NULL) ThreadCache::InitModule();
+ if (UNLIKELY(Static::pageheap() == NULL)) ThreadCache::InitModule();
// Allocate at least one byte to avoid boundary conditions below
if (size == 0) size = 1;
@@ -1345,13 +1345,13 @@ void* do_memalign(size_t align, size_t size) {
// TODO: We could put the rest of this page in the appropriate
// TODO: cache but it does not seem worth it.
Span* span = Static::pageheap()->New(tcmalloc::pages(size));
- return span == NULL ? NULL : SpanToMallocResult(span);
+ return UNLIKELY(span == NULL) ? NULL : SpanToMallocResult(span);
}
// Allocate extra pages and carve off an aligned portion
const Length alloc = tcmalloc::pages(size + align);
Span* span = Static::pageheap()->New(alloc);
- if (span == NULL) return NULL;
+ if (UNLIKELY(span == NULL)) return NULL;
// Skip starting portion so that we end up aligned
Length skip = 0;
@@ -1421,7 +1421,7 @@ inline void* cpp_alloc(size_t size, bool nothrow) {
#else
for (;;) {
void* p = do_malloc_no_errno(size);
- if (p == NULL) { // allocation failed
+ if (UNLIKELY(p == NULL)) { // allocation failed
// Get the current new handler. NB: this function is not
// thread-safe. We make a feeble stab at making it so here, but
// this lock only protects against tcmalloc interfering with
@@ -1472,7 +1472,7 @@ void* cpp_memalign(size_t align, size_t size) {
#ifdef PREANSINEW
return p;
#else
- if (p == NULL) { // allocation failed
+ if (UNLIKELY(p == NULL)) { // allocation failed
// Get the current new handler. NB: this function is not
// thread-safe. We make a feeble stab at making it so here, but
// this lock only protects against tcmalloc interfering with
@@ -1672,7 +1672,7 @@ extern "C" PERFTOOLS_DLL_DECL int tc_posix_memalign(
void* result = do_memalign_or_cpp_memalign(align, size);
MallocHook::InvokeNewHook(result, size);
- if (result == NULL) {
+ if (UNLIKELY(result == NULL)) {
return ENOMEM;
} else {
*result_ptr = result;