diff options
Diffstat (limited to 'indra/llcommon')
-rw-r--r-- | indra/llcommon/apply.h | 115 | ||||
-rw-r--r-- | indra/llcommon/llalignedarray.h | 10 | ||||
-rw-r--r-- | indra/llcommon/llcoros.cpp | 37 | ||||
-rw-r--r-- | indra/llcommon/llcoros.h | 35 | ||||
-rw-r--r-- | indra/llcommon/llprocessor.cpp | 139 | ||||
-rw-r--r-- | indra/llcommon/llprocessor.h | 5 | ||||
-rw-r--r-- | indra/llcommon/llsd.h | 12 | ||||
-rw-r--r-- | indra/llcommon/llstl.h | 81 | ||||
-rw-r--r-- | indra/llcommon/llsys.cpp | 69 | ||||
-rw-r--r-- | indra/llcommon/llsys.h | 12 | ||||
-rw-r--r-- | indra/llcommon/tests/llleap_test.cpp | 14 |
11 files changed, 454 insertions, 75 deletions
diff --git a/indra/llcommon/apply.h b/indra/llcommon/apply.h new file mode 100644 index 0000000000..7c58d63bc0 --- /dev/null +++ b/indra/llcommon/apply.h @@ -0,0 +1,115 @@ +/** + * @file apply.h + * @author Nat Goodspeed + * @date 2022-06-18 + * @brief C++14 version of std::apply() + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Copyright (c) 2022, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_APPLY_H) +#define LL_APPLY_H + +#include <boost/type_traits/function_traits.hpp> +#include <tuple> + +namespace LL +{ + +/** + * USAGE NOTE: + * https://stackoverflow.com/a/40523474/5533635 + * + * If you're trying to pass apply() a variadic function, the compiler + * complains that it can't deduce the callable type, presumably because it + * doesn't know which arity to reify to pass. + * + * But it works to wrap the variadic function in a generic lambda, e.g.: + * + * @CODE + * LL::apply( + * [](auto&&... args) + * { + * return variadic(std::forward<decltype(args)>(args)...); + * }, + * args); + * @ENDCODE + * + * Presumably this is because there's only one instance of the generic lambda + * @em type, with a variadic <tt>operator()()</tt>. + * + * It's pointless to provide a wrapper @em function that implicitly supplies + * the generic lambda. You couldn't pass your variadic function to our wrapper + * function, for the same original reason! + * + * Instead we provide a wrapper @em macro. Sorry, Dr. Stroustrup. + */ +#define VAPPLY(FUNC, ARGS) \ + LL::apply( \ + [](auto&&... args) \ + { \ + return (FUNC)(std::forward<decltype(args)>(args)...); \ + }, \ + (ARGS)) + +#if __cplusplus >= 201703L + +// C++17 implementation +using std::apply; + +#else // C++14 + +// Derived from https://stackoverflow.com/a/20441189 +// and https://en.cppreference.com/w/cpp/utility/apply +template <typename CALLABLE, typename TUPLE, std::size_t... I> +auto apply_impl(CALLABLE&& func, TUPLE&& args, std::index_sequence<I...>) +{ + // call func(unpacked args) + return std::forward<CALLABLE>(func)(std::move(std::get<I>(args))...); +} + +template <typename CALLABLE, typename... ARGS> +auto apply(CALLABLE&& func, const std::tuple<ARGS...>& args) +{ + // std::index_sequence_for is the magic sauce here, generating an argument + // pack of indexes for each entry in args. apply_impl() can then pass + // those to std::get() to unpack args into individual arguments. + return apply_impl(std::forward<CALLABLE>(func), + args, + std::index_sequence_for<ARGS...>{}); +} + +// per https://stackoverflow.com/a/57510428/5533635 +template <typename CALLABLE, typename T, size_t SIZE> +auto apply(CALLABLE&& func, const std::array<T, SIZE>& args) +{ + return apply(std::forward<CALLABLE>(func), std::tuple_cat(args)); +} + +// per https://stackoverflow.com/a/28411055/5533635 +template <typename CALLABLE, typename T, std::size_t... I> +auto apply_impl(CALLABLE&& func, const std::vector<T>& args, std::index_sequence<I...>) +{ + return apply_impl(std::forward<CALLABLE>(func), + std::make_tuple(std::forward<T>(args[I])...), + I...); +} + +// this goes beyond C++17 std::apply() +template <typename CALLABLE, typename T> +auto apply(CALLABLE&& func, const std::vector<T>& args) +{ + constexpr auto arity = boost::function_traits<CALLABLE>::arity; + assert(args.size() == arity); + return apply_impl(std::forward<CALLABLE>(func), + args, + std::make_index_sequence<arity>()); +} + +#endif // C++14 + +} // namespace LL + +#endif /* ! defined(LL_APPLY_H) */ diff --git a/indra/llcommon/llalignedarray.h b/indra/llcommon/llalignedarray.h index b68e9e0f82..da9d98c16c 100644 --- a/indra/llcommon/llalignedarray.h +++ b/indra/llcommon/llalignedarray.h @@ -116,14 +116,20 @@ void LLAlignedArray<T, alignment>::resize(U32 size) template <class T, U32 alignment> T& LLAlignedArray<T, alignment>::operator[](int idx) { - llassert(idx < mElementCount); + if(idx >= mElementCount || idx < 0) + { + LL_ERRS() << "Out of bounds LLAlignedArray, requested: " << (S32)idx << " size: " << mElementCount << LL_ENDL; + } return mArray[idx]; } template <class T, U32 alignment> const T& LLAlignedArray<T, alignment>::operator[](int idx) const { - llassert(idx < mElementCount); + if (idx >= mElementCount || idx < 0) + { + LL_ERRS() << "Out of bounds LLAlignedArray, requested: " << (S32)idx << " size: " << mElementCount << LL_ENDL; + } return mArray[idx]; } diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index c2d353b0fc..14bfb98629 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -35,6 +35,7 @@ // STL headers // std headers #include <atomic> +#include <stdexcept> // external library headers #include <boost/bind.hpp> #include <boost/fiber/fiber.hpp> @@ -214,6 +215,22 @@ std::string LLCoros::logname() return data.mName.empty()? data.getKey() : data.mName; } +void LLCoros::saveException(const std::string& name, std::exception_ptr exc) +{ + mExceptionQueue.emplace(name, exc); +} + +void LLCoros::rethrow() +{ + if (! mExceptionQueue.empty()) + { + ExceptionData front = mExceptionQueue.front(); + mExceptionQueue.pop(); + LL_WARNS("LLCoros") << "Rethrowing exception from coroutine " << front.name << LL_ENDL; + std::rethrow_exception(front.exception); + } +} + void LLCoros::setStackSize(S32 stacksize) { LL_DEBUGS("LLCoros") << "Setting coroutine stack size to " << stacksize << LL_ENDL; @@ -302,11 +319,11 @@ U32 cpp_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop, } } -void LLCoros::winlevel(const std::string& name, const callable_t& callable) +void LLCoros::sehHandle(const std::string& name, const LLCoros::callable_t& callable) { __try { - toplevelTryWrapper(name, callable); + LLCoros::toplevelTryWrapper(name, callable); } __except (cpp_exception_filter(GetExceptionCode(), GetExceptionInformation(), name)) { @@ -321,7 +338,6 @@ void LLCoros::winlevel(const std::string& name, const callable_t& callable) throw std::exception(integer_string); } } - #endif void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& callable) @@ -350,11 +366,19 @@ void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& call } catch (...) { +#if LL_WINDOWS // Any OTHER kind of uncaught exception will cause the viewer to - // crash, hopefully informatively. + // crash, SEH handling should catch it and report to bugsplat. LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << name)); // to not modify callstack throw; +#else + // Stash any OTHER kind of uncaught exception in the rethrow() queue + // to be rethrown by the main fiber. + LL_WARNS("LLCoros") << "Capturing uncaught exception in coroutine " + << name << LL_ENDL; + LLCoros::instance().saveException(name, std::current_exception()); +#endif } } @@ -364,8 +388,9 @@ void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& call void LLCoros::toplevel(std::string name, callable_t callable) { #if LL_WINDOWS - // Can not use __try in functions that require unwinding, so use one more wrapper - winlevel(name, callable); + // Because SEH can's have unwinding, need to call a wrapper + // 'try' is inside SEH handling to not catch LLContinue + sehHandle(name, callable); #else toplevelTryWrapper(name, callable); #endif diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index a94cfca19f..dbff921f16 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -38,6 +38,8 @@ #include "llinstancetracker.h" #include <boost/function.hpp> #include <string> +#include <exception> +#include <queue> // e.g. #include LLCOROS_MUTEX_HEADER #define LLCOROS_MUTEX_HEADER <boost/fiber/mutex.hpp> @@ -156,6 +158,19 @@ public: * LLCoros::launch()). */ static std::string getName(); + + /** + * rethrow() is called by the thread's main fiber to propagate an + * exception from any coroutine into the main fiber, where it can engage + * the normal unhandled-exception machinery, up to and including crash + * reporting. + * + * LLCoros maintains a queue of otherwise-uncaught exceptions from + * terminated coroutines. Each call to rethrow() pops the first of those + * and rethrows it. When the queue is empty (normal case), rethrow() is a + * no-op. + */ + void rethrow(); /** * This variation returns a name suitable for log messages: the explicit @@ -292,13 +307,27 @@ public: private: std::string generateDistinctName(const std::string& prefix) const; + void toplevelTryWrapper(const std::string& name, const callable_t& callable); #if LL_WINDOWS - void winlevel(const std::string& name, const callable_t& callable); + void sehHandle(const std::string& name, const callable_t& callable); // calls toplevelTryWrapper #endif - void toplevelTryWrapper(const std::string& name, const callable_t& callable); - void toplevel(std::string name, callable_t callable); + void toplevel(std::string name, callable_t callable); // calls sehHandle or toplevelTryWrapper struct CoroData; static CoroData& get_CoroData(const std::string& caller); + void saveException(const std::string& name, std::exception_ptr exc); + + struct ExceptionData + { + ExceptionData(const std::string& nm, std::exception_ptr exc): + name(nm), + exception(exc) + {} + // name of coroutine that originally threw this exception + std::string name; + // the thrown exception + std::exception_ptr exception; + }; + std::queue<ExceptionData> mExceptionQueue; S32 mStackSize; diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp index 818df07bb2..4a1a81f083 100644 --- a/indra/llcommon/llprocessor.cpp +++ b/indra/llcommon/llprocessor.cpp @@ -118,7 +118,11 @@ namespace eMONTIOR_MWAIT=33, eCPLDebugStore=34, eThermalMonitor2=35, - eAltivec=36 + eAltivec=36, + eSSE3S_Features = 37, + eSSE4_1_Features = 38, + eSSE4_2_Features = 39, + eSSE4a_Features = 40, }; const char* cpu_feature_names[] = @@ -161,7 +165,11 @@ namespace "CPL Qualified Debug Store", "Thermal Monitor 2", - "Altivec" + "Altivec", + "SSE3S Instructions", + "SSE4.1 Instructions", + "SSE4.2 Instructions", + "SSE4a Instructions", }; std::string intel_CPUFamilyName(int composed_family) @@ -250,6 +258,31 @@ public: return hasExtension(cpu_feature_names[eSSE2_Ext]); } + bool hasSSE3() const + { + return hasExtension(cpu_feature_names[eSSE3_Features]); + } + + bool hasSSE3S() const + { + return hasExtension(cpu_feature_names[eSSE3S_Features]); + } + + bool hasSSE41() const + { + return hasExtension(cpu_feature_names[eSSE4_1_Features]); + } + + bool hasSSE42() const + { + return hasExtension(cpu_feature_names[eSSE4_2_Features]); + } + + bool hasSSE4a() const + { + return hasExtension(cpu_feature_names[eSSE4a_Features]); + } + bool hasAltivec() const { return hasExtension("Altivec"); @@ -473,6 +506,12 @@ private: *((int*)(cpu_vendor+4)) = cpu_info[3]; *((int*)(cpu_vendor+8)) = cpu_info[2]; setInfo(eVendor, cpu_vendor); + std::string cmp_vendor(cpu_vendor); + bool is_amd = false; + if (cmp_vendor == "AuthenticAMD") + { + is_amd = true; + } // Get the information associated with each valid Id for(unsigned int i=0; i<=ids; ++i) @@ -504,6 +543,7 @@ private: if(cpu_info[2] & 0x8) { + // intel specific SSE3 suplements setExtension(cpu_feature_names[eMONTIOR_MWAIT]); } @@ -516,7 +556,22 @@ private: { setExtension(cpu_feature_names[eThermalMonitor2]); } - + + if (cpu_info[2] & 0x200) + { + setExtension(cpu_feature_names[eSSE3S_Features]); + } + + if (cpu_info[2] & 0x80000) + { + setExtension(cpu_feature_names[eSSE4_1_Features]); + } + + if (cpu_info[2] & 0x100000) + { + setExtension(cpu_feature_names[eSSE4_2_Features]); + } + unsigned int feature_info = (unsigned int) cpu_info[3]; for(unsigned int index = 0, bit = 1; index < eSSE3_Features; ++index, bit <<= 1) { @@ -543,8 +598,17 @@ private: __cpuid(cpu_info, i); // Interpret CPU brand string and cache information. - if (i == 0x80000002) - memcpy(cpu_brand_string, cpu_info, sizeof(cpu_info)); + if (i == 0x80000001) + { + if (is_amd) + { + setExtension(cpu_feature_names[eSSE4a_Features]); + } + } + else if (i == 0x80000002) + { + memcpy(cpu_brand_string, cpu_info, sizeof(cpu_info)); + } else if (i == 0x80000003) memcpy(cpu_brand_string + 16, cpu_info, sizeof(cpu_info)); else if (i == 0x80000004) @@ -690,6 +754,41 @@ private: uint64_t ext_feature_info = getSysctlInt64("machdep.cpu.extfeature_bits"); S32 *ext_feature_infos = (S32*)(&ext_feature_info); setConfig(eExtFeatureBits, ext_feature_infos[0]); + + + char cpu_features[1024]; + len = sizeof(cpu_features); + memset(cpu_features, 0, len); + sysctlbyname("machdep.cpu.features", (void*)cpu_features, &len, NULL, 0); + + std::string cpu_features_str(cpu_features); + cpu_features_str = " " + cpu_features_str + " "; + + if (cpu_features_str.find(" SSE3 ") != std::string::npos) + { + setExtension(cpu_feature_names[eSSE3_Features]); + } + + if (cpu_features_str.find(" SSSE3 ") != std::string::npos) + { + setExtension(cpu_feature_names[eSSE3S_Features]); + } + + if (cpu_features_str.find(" SSE4.1 ") != std::string::npos) + { + setExtension(cpu_feature_names[eSSE4_1_Features]); + } + + if (cpu_features_str.find(" SSE4.2 ") != std::string::npos) + { + setExtension(cpu_feature_names[eSSE4_2_Features]); + } + + if (cpu_features_str.find(" SSE4A ") != std::string::npos) + { + // Not supposed to happen? + setExtension(cpu_feature_names[eSSE4a_Features]); + } } }; @@ -800,6 +899,31 @@ private: { setExtension(cpu_feature_names[eSSE2_Ext]); } + + if (flags.find(" pni ") != std::string::npos) + { + setExtension(cpu_feature_names[eSSE3_Features]); + } + + if (flags.find(" ssse3 ") != std::string::npos) + { + setExtension(cpu_feature_names[eSSE3S_Features]); + } + + if (flags.find(" sse4_1 ") != std::string::npos) + { + setExtension(cpu_feature_names[eSSE4_1_Features]); + } + + if (flags.find(" sse4_2 ") != std::string::npos) + { + setExtension(cpu_feature_names[eSSE4_2_Features]); + } + + if (flags.find(" sse4a ") != std::string::npos) + { + setExtension(cpu_feature_names[eSSE4a_Features]); + } # endif // LL_X86 } @@ -860,6 +984,11 @@ LLProcessorInfo::~LLProcessorInfo() {} F64MegahertzImplicit LLProcessorInfo::getCPUFrequency() const { return mImpl->getCPUFrequency(); } bool LLProcessorInfo::hasSSE() const { return mImpl->hasSSE(); } bool LLProcessorInfo::hasSSE2() const { return mImpl->hasSSE2(); } +bool LLProcessorInfo::hasSSE3() const { return mImpl->hasSSE3(); } +bool LLProcessorInfo::hasSSE3S() const { return mImpl->hasSSE3S(); } +bool LLProcessorInfo::hasSSE41() const { return mImpl->hasSSE41(); } +bool LLProcessorInfo::hasSSE42() const { return mImpl->hasSSE42(); } +bool LLProcessorInfo::hasSSE4a() const { return mImpl->hasSSE4a(); } bool LLProcessorInfo::hasAltivec() const { return mImpl->hasAltivec(); } std::string LLProcessorInfo::getCPUFamilyName() const { return mImpl->getCPUFamilyName(); } std::string LLProcessorInfo::getCPUBrandName() const { return mImpl->getCPUBrandName(); } diff --git a/indra/llcommon/llprocessor.h b/indra/llcommon/llprocessor.h index b77eb22c3a..1a473ddc97 100644 --- a/indra/llcommon/llprocessor.h +++ b/indra/llcommon/llprocessor.h @@ -54,6 +54,11 @@ public: F64MegahertzImplicit getCPUFrequency() const; bool hasSSE() const; bool hasSSE2() const; + bool hasSSE3() const; + bool hasSSE3S() const; + bool hasSSE41() const; + bool hasSSE42() const; + bool hasSSE4a() const; bool hasAltivec() const; std::string getCPUFamilyName() const; std::string getCPUBrandName() const; diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h index 24cb9bbce1..3daaef44fc 100644 --- a/indra/llcommon/llsd.h +++ b/indra/llcommon/llsd.h @@ -421,42 +421,42 @@ public: static std::string typeString(Type type); // Return human-readable type as a string }; -struct llsd_select_bool : public std::unary_function<LLSD, LLSD::Boolean> +struct llsd_select_bool { LLSD::Boolean operator()(const LLSD& sd) const { return sd.asBoolean(); } }; -struct llsd_select_integer : public std::unary_function<LLSD, LLSD::Integer> +struct llsd_select_integer { LLSD::Integer operator()(const LLSD& sd) const { return sd.asInteger(); } }; -struct llsd_select_real : public std::unary_function<LLSD, LLSD::Real> +struct llsd_select_real { LLSD::Real operator()(const LLSD& sd) const { return sd.asReal(); } }; -struct llsd_select_float : public std::unary_function<LLSD, F32> +struct llsd_select_float { F32 operator()(const LLSD& sd) const { return (F32)sd.asReal(); } }; -struct llsd_select_uuid : public std::unary_function<LLSD, LLSD::UUID> +struct llsd_select_uuid { LLSD::UUID operator()(const LLSD& sd) const { return sd.asUUID(); } }; -struct llsd_select_string : public std::unary_function<LLSD, LLSD::String> +struct llsd_select_string { LLSD::String operator()(const LLSD& sd) const { diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index a90c2c7e08..25131291f9 100644 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -142,7 +142,7 @@ struct DeletePairedPointerArray // llselect2nd<map_type::value_type>())); template<typename T> -struct DeletePointerFunctor : public std::unary_function<T*, bool> +struct DeletePointerFunctor { bool operator()(T* ptr) const { @@ -153,7 +153,7 @@ struct DeletePointerFunctor : public std::unary_function<T*, bool> // See notes about DeleteArray for why you should consider avoiding this. template<typename T> -struct DeleteArrayFunctor : public std::unary_function<T*, bool> +struct DeleteArrayFunctor { bool operator()(T* ptr) const { @@ -395,16 +395,17 @@ OutputIter ll_transform_n( // select... with the stl. Look up usage on the sgi website. template <class _Pair> -struct _LLSelect1st : public std::unary_function<_Pair, typename _Pair::first_type> { - const typename _Pair::first_type& operator()(const _Pair& __x) const { +struct _LLSelect1st +{ + const auto& operator()(const _Pair& __x) const { return __x.first; } }; template <class _Pair> -struct _LLSelect2nd : public std::unary_function<_Pair, typename _Pair::second_type> +struct _LLSelect2nd { - const typename _Pair::second_type& operator()(const _Pair& __x) const { + const auto& operator()(const _Pair& __x) const { return __x.second; } }; @@ -416,9 +417,7 @@ template <class _Pair> struct llselect2nd : public _LLSelect2nd<_Pair> {}; // compose... with the stl. Look up usage on the sgi website. template <class _Operation1, class _Operation2> -class ll_unary_compose : - public std::unary_function<typename _Operation2::argument_type, - typename _Operation1::result_type> +class ll_unary_compose { protected: _Operation1 __op1; @@ -426,8 +425,9 @@ protected: public: ll_unary_compose(const _Operation1& __x, const _Operation2& __y) : __op1(__x), __op2(__y) {} - typename _Operation1::result_type - operator()(const typename _Operation2::argument_type& __x) const { + template <typename _Op2Arg> + auto + operator()(const _Op2Arg& __x) const { return __op1(__op2(__x)); } }; @@ -441,8 +441,7 @@ llcompose1(const _Operation1& __op1, const _Operation2& __op2) template <class _Operation1, class _Operation2, class _Operation3> class ll_binary_compose - : public std::unary_function<typename _Operation2::argument_type, - typename _Operation1::result_type> { +{ protected: _Operation1 _M_op1; _Operation2 _M_op2; @@ -451,8 +450,9 @@ public: ll_binary_compose(const _Operation1& __x, const _Operation2& __y, const _Operation3& __z) : _M_op1(__x), _M_op2(__y), _M_op3(__z) { } - typename _Operation1::result_type - operator()(const typename _Operation2::argument_type& __x) const { + template<typename OP2ARG> + auto + operator()(const OP2ARG& __x) const { return _M_op1(_M_op2(__x), _M_op3(__x)); } }; @@ -468,54 +468,51 @@ llcompose2(const _Operation1& __op1, const _Operation2& __op2, // helpers to deal with the fact that MSDev does not package // bind... with the stl. Again, this is from sgi. -template <class _Operation> -class llbinder1st : - public std::unary_function<typename _Operation::second_argument_type, - typename _Operation::result_type> { +template <class _Operation, typename _Arg1> +class llbinder1st +{ protected: _Operation op; - typename _Operation::first_argument_type value; + _Arg1 value; public: - llbinder1st(const _Operation& __x, - const typename _Operation::first_argument_type& __y) + llbinder1st(const _Operation& __x, const _Arg1& __y) : op(__x), value(__y) {} - typename _Operation::result_type - operator()(const typename _Operation::second_argument_type& __x) const { - return op(value, __x); - } + template <typename _Arg2> + auto + operator()(const _Arg2& __x) const { + return op(value, __x); + } }; template <class _Operation, class _Tp> -inline llbinder1st<_Operation> +inline auto llbind1st(const _Operation& __oper, const _Tp& __x) { - typedef typename _Operation::first_argument_type _Arg1_type; - return llbinder1st<_Operation>(__oper, _Arg1_type(__x)); + return llbinder1st<_Operation, _Tp>(__oper, __x); } -template <class _Operation> +template <class _Operation, typename _Arg2> class llbinder2nd - : public std::unary_function<typename _Operation::first_argument_type, - typename _Operation::result_type> { +{ protected: _Operation op; - typename _Operation::second_argument_type value; + _Arg2 value; public: llbinder2nd(const _Operation& __x, - const typename _Operation::second_argument_type& __y) + const _Arg2& __y) : op(__x), value(__y) {} - typename _Operation::result_type - operator()(const typename _Operation::first_argument_type& __x) const { + template <typename _Arg1> + auto + operator()(const _Arg1& __x) const { return op(__x, value); } }; template <class _Operation, class _Tp> -inline llbinder2nd<_Operation> +inline auto llbind2nd(const _Operation& __oper, const _Tp& __x) { - typedef typename _Operation::second_argument_type _Arg2_type; - return llbinder2nd<_Operation>(__oper, _Arg2_type(__x)); + return llbinder2nd<_Operation, _Tp>(__oper, __x); } /** @@ -548,8 +545,7 @@ bool before(const std::type_info* lhs, const std::type_info* rhs) namespace std { template <> - struct less<const std::type_info*>: - public std::binary_function<const std::type_info*, const std::type_info*, bool> + struct less<const std::type_info*> { bool operator()(const std::type_info* lhs, const std::type_info* rhs) const { @@ -558,8 +554,7 @@ namespace std }; template <> - struct less<std::type_info*>: - public std::binary_function<std::type_info*, std::type_info*, bool> + struct less<std::type_info*> { bool operator()(std::type_info* lhs, std::type_info* rhs) const { diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 9b6bb3826c..26a0fa1b1c 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -597,6 +597,11 @@ LLCPUInfo::LLCPUInfo() // proc.WriteInfoTextFile("procInfo.txt"); mHasSSE = proc.hasSSE(); mHasSSE2 = proc.hasSSE2(); + mHasSSE3 = proc.hasSSE3(); + mHasSSE3S = proc.hasSSE3S(); + mHasSSE41 = proc.hasSSE41(); + mHasSSE42 = proc.hasSSE42(); + mHasSSE4a = proc.hasSSE4a(); mHasAltivec = proc.hasAltivec(); mCPUMHz = (F64)proc.getCPUFrequency(); mFamily = proc.getCPUFamilyName(); @@ -609,6 +614,35 @@ LLCPUInfo::LLCPUInfo() } mCPUString = out.str(); LLStringUtil::trim(mCPUString); + + if (mHasSSE) + { + mSSEVersions.append("1"); + } + if (mHasSSE2) + { + mSSEVersions.append("2"); + } + if (mHasSSE3) + { + mSSEVersions.append("3"); + } + if (mHasSSE3S) + { + mSSEVersions.append("3S"); + } + if (mHasSSE41) + { + mSSEVersions.append("4.1"); + } + if (mHasSSE42) + { + mSSEVersions.append("4.2"); + } + if (mHasSSE4a) + { + mSSEVersions.append("4a"); + } } bool LLCPUInfo::hasAltivec() const @@ -626,6 +660,31 @@ bool LLCPUInfo::hasSSE2() const return mHasSSE2; } +bool LLCPUInfo::hasSSE3() const +{ + return mHasSSE3; +} + +bool LLCPUInfo::hasSSE3S() const +{ + return mHasSSE3S; +} + +bool LLCPUInfo::hasSSE41() const +{ + return mHasSSE41; +} + +bool LLCPUInfo::hasSSE42() const +{ + return mHasSSE42; +} + +bool LLCPUInfo::hasSSE4a() const +{ + return mHasSSE4a; +} + F64 LLCPUInfo::getMHz() const { return mCPUMHz; @@ -636,6 +695,11 @@ std::string LLCPUInfo::getCPUString() const return mCPUString; } +const LLSD& LLCPUInfo::getSSEVersions() const +{ + return mSSEVersions; +} + void LLCPUInfo::stream(std::ostream& s) const { // gather machine information. @@ -645,6 +709,11 @@ void LLCPUInfo::stream(std::ostream& s) const // CPU's attributes regardless of platform s << "->mHasSSE: " << (U32)mHasSSE << std::endl; s << "->mHasSSE2: " << (U32)mHasSSE2 << std::endl; + s << "->mHasSSE3: " << (U32)mHasSSE3 << std::endl; + s << "->mHasSSE3S: " << (U32)mHasSSE3S << std::endl; + s << "->mHasSSE41: " << (U32)mHasSSE41 << std::endl; + s << "->mHasSSE42: " << (U32)mHasSSE42 << std::endl; + s << "->mHasSSE4a: " << (U32)mHasSSE4a << std::endl; s << "->mHasAltivec: " << (U32)mHasAltivec << std::endl; s << "->mCPUMHz: " << mCPUMHz << std::endl; s << "->mCPUString: " << mCPUString << std::endl; diff --git a/indra/llcommon/llsys.h b/indra/llcommon/llsys.h index cb92cb0ac6..5ffbf5a732 100644 --- a/indra/llcommon/llsys.h +++ b/indra/llcommon/llsys.h @@ -80,10 +80,16 @@ public: void stream(std::ostream& s) const; std::string getCPUString() const; + const LLSD& getSSEVersions() const; bool hasAltivec() const; bool hasSSE() const; bool hasSSE2() const; + bool hasSSE3() const; + bool hasSSE3S() const; + bool hasSSE41() const; + bool hasSSE42() const; + bool hasSSE4a() const; F64 getMHz() const; // Family is "AMD Duron" or "Intel Pentium Pro" @@ -92,10 +98,16 @@ public: private: bool mHasSSE; bool mHasSSE2; + bool mHasSSE3; + bool mHasSSE3S; + bool mHasSSE41; + bool mHasSSE42; + bool mHasSSE4a; bool mHasAltivec; F64 mCPUMHz; std::string mFamily; std::string mCPUString; + LLSD mSSEVersions; }; //============================================================================= diff --git a/indra/llcommon/tests/llleap_test.cpp b/indra/llcommon/tests/llleap_test.cpp index 9754353ab0..7ee36a9ea6 100644 --- a/indra/llcommon/tests/llleap_test.cpp +++ b/indra/llcommon/tests/llleap_test.cpp @@ -15,10 +15,10 @@ #include "llleap.h" // STL headers // std headers +#include <functional> // external library headers #include <boost/assign/list_of.hpp> #include <boost/phoenix/core/argument.hpp> -#include <boost/foreach.hpp> // other Linden headers #include "../test/lltut.h" #include "../test/namedtempfile.h" @@ -29,7 +29,6 @@ #include "llstring.h" #include "stringize.h" #include "StringVec.h" -#include <functional> using boost::assign::list_of; @@ -110,11 +109,6 @@ namespace tut "import os\n" "import sys\n" "\n" - // Don't forget that this Python script is written to some - // temp directory somewhere! Its __file__ is useless in - // finding indra/lib/python. Use our __FILE__, with - // raw-string syntax to deal with Windows pathnames. - "mydir = os.path.dirname(r'" << __FILE__ << "')\n" "from llbase import llsd\n" "\n" "class ProtocolError(Exception):\n" @@ -241,9 +235,9 @@ namespace tut "import sys\n" "sys.stderr.write('''Hello from Python!\n" "note partial line''')\n"); + StringVec vcommand{ PYTHON, script.getName() }; CaptureLog log(LLError::LEVEL_INFO); - waitfor(LLLeap::create(get_test_name(), - sv(list_of(PYTHON)(script.getName())))); + waitfor(LLLeap::create(get_test_name(), vcommand)); log.messageWith("Hello from Python!"); log.messageWith("note partial line"); } @@ -531,7 +525,7 @@ namespace tut result.ensure(); } - struct TestLargeMessage: public std::binary_function<size_t, size_t, bool> + struct TestLargeMessage { TestLargeMessage(const std::string& PYTHON_, const std::string& reader_module_, const std::string& test_name_): |