a2e76eb7b2
The codebase had several namespace-level static data definitions and function definitions. Using namespace-level "static" in a .h file is near-always a bad idea, as follows: - for simple types, static is implied. Example: "const int x = 42;" is the same as "static const int x = 42;" - for aggregate types, static linkage implies that a copy of the aggregate will appear in every compilation unit that includes the header. - for functions, static means the function will have a separate body generated in each compilation unit including the header. - in several places functions were defined 'static inline', which is just as bad. 'inline' is just a hint which means the function may end up having a body (and actually more due to 'static'). True, gnu's linker has means to remove duplicate definition, but that's not always guaranteed or possible (think e.g. static functions that define static data inside, ouch). So static is useless at best and pernicious at worst. We should never, ever use static at namespace level in headers. I will create a bootcamp task for a lint rule. I expected the performance to be neutral after the change, but in fact there's a significant drop in instruction count and therefore a measurable reduction in CPU time: https://our.intern.facebook.com/intern/perflab/details.php?eq_id=431903
96 linhas
3.4 KiB
C++
96 linhas
3.4 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#ifndef incl_HPHP_ATOMIC_H_
|
|
#define incl_HPHP_ATOMIC_H_
|
|
|
|
#include <stdint.h>
|
|
#include <boost/type_traits/is_arithmetic.hpp>
|
|
#include <boost/type_traits/is_pointer.hpp>
|
|
|
|
#include "hphp/util/assertions.h"
|
|
#include "hphp/util/util.h"
|
|
|
|
namespace HPHP {
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
template<class T>
|
|
inline void assert_address_is_atomically_accessible(T* address) {
|
|
static_assert(
|
|
sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8,
|
|
"T must be a 1, 2, 4, or 8 byte object for atomic access");
|
|
static_assert(
|
|
boost::is_arithmetic<T>::value || boost::is_pointer<T>::value,
|
|
"Atomic operations only supported for built in integer, floating point "
|
|
"and pointer types.");
|
|
|
|
#ifdef __x86_64__
|
|
assert(((uintptr_t(address) + sizeof(T) - 1) & ~63ul) ==
|
|
( uintptr_t(address) & ~63ul) &&
|
|
"Atomically accessed addresses may not span cache lines");
|
|
#elif __AARCH64EL__
|
|
// N-byte accesses must be N-byte aligned
|
|
assert((uintptr_t(address) & (sizeof(T) - 1)) == 0);
|
|
#else
|
|
# error What kind of memory accesses are atomic on this architecture?
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
* Use of the functions below is DISCOURAGED.
|
|
* Prefer the std::atomic library in C++11.
|
|
*
|
|
* Not only does it relieve you of worrying about architecture and compiler
|
|
* portability issues, but it also encourages you to really reason through the
|
|
* concurrency you're aiming to manage, by treating atomically-accessed data as
|
|
* a distinct type.
|
|
*/
|
|
|
|
template<class T> inline T atomic_acquire_load(const T* address) {
|
|
assert_address_is_atomically_accessible(address);
|
|
|
|
T ret = *address; // acquire barrier on x64
|
|
Util::compiler_membar();
|
|
return ret;
|
|
}
|
|
|
|
template<class T, class U>
|
|
inline void atomic_release_store(T* address, U val) {
|
|
assert_address_is_atomically_accessible(address);
|
|
|
|
Util::compiler_membar();
|
|
*address = val; // release barrier on x64 (as long as no one is
|
|
// doing any non-temporal moves or whatnot).
|
|
}
|
|
|
|
template<typename T>
|
|
inline T atomic_inc(T &count) {
|
|
assert_address_is_atomically_accessible(&count);
|
|
return __sync_fetch_and_add(&count, 1) + 1;
|
|
}
|
|
|
|
template<typename T>
|
|
inline T atomic_dec(T &count) {
|
|
assert_address_is_atomically_accessible(&count);
|
|
return __sync_fetch_and_add(&count, -1) - 1;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
}
|
|
|
|
#endif // __ATOMIC_H__
|