Merge branch 'master' of https://vcs.firestormviewer.org/viewer-merges/phoenix-firestorm-546
# Conflicts: # autobuild.xml # indra/llcommon/CMakeLists.txt # indra/llrender/llgl.cpp # indra/newview/llappviewer.cpp # indra/newview/llface.cpp # indra/newview/llflexibleobject.cpp # indra/newview/llvovolume.cppmaster
commit
6ccdf5545d
|
|
@ -24,6 +24,7 @@ build-vc100/
|
|||
build-vc120/
|
||||
build-vc[0-9]*-32*/
|
||||
build-vc[0-9]*-64*/
|
||||
build-vc160-64/
|
||||
indra/CMakeFiles
|
||||
indra/build-vc[0-9]*
|
||||
indra/lib/mono/1.0/*.dll
|
||||
|
|
|
|||
246
autobuild.xml
246
autobuild.xml
|
|
@ -391,35 +391,69 @@
|
|||
<key>version</key>
|
||||
<string>1.2.15</string>
|
||||
</map>
|
||||
<key>Tracy</key>
|
||||
<key>tracy</key>
|
||||
<map>
|
||||
<key>canonical_repo</key>
|
||||
<string>https://bitbucket.org/lindenlab/3p-tracy</string>
|
||||
<key>copyright</key>
|
||||
<string>Copyright (c) 2017-2021, Bartosz Taudul</string>
|
||||
<string>Copyright (c) 2017-2021, Bartosz Taudul (wolf@nereid.pl)</string>
|
||||
<key>description</key>
|
||||
<string>A real time, nanosecond resolution, remote telemetry, hybrid frame and sampling profiler for games and other applications.</string>
|
||||
<string>Tracy Profiler Library</string>
|
||||
<key>license</key>
|
||||
<string>BSD</string>
|
||||
<string>bsd</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/Tracy.txt</string>
|
||||
<string>LICENSES/tracy_license.txt</string>
|
||||
<key>name</key>
|
||||
<string>Tracy</string>
|
||||
<string>tracy</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>common</key>
|
||||
<key>darwin64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>b0a0fc6b7bda02fe14cccea2dd342058</string>
|
||||
<string>da7317e4a81609f624f84780f28b07de</string>
|
||||
<key>url</key>
|
||||
<string>http://3p.firestormviewer.org/Tracy-0.7.6-windows-210902110.tar.bz2</string>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/86972/801630/tracy-v0.7.8.563351-darwin64-563351.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>common</string>
|
||||
<string>darwin64</string>
|
||||
</map>
|
||||
<key>windows</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>47c696cd2966c5cc3c8ba6115dd1f886</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>md5</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/86973/801641/tracy-v0.7.8.563351-windows-563351.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>b649ee6591e67d2341e886b3fc3484a7</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>md5</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/86974/801642/tracy-v0.7.8.563351-windows64-563351.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>source</key>
|
||||
<string>https://bitbucket.org/lindenlab/3p-tracy</string>
|
||||
<key>source_type</key>
|
||||
<string>git</string>
|
||||
<key>version</key>
|
||||
<string>0.7.6</string>
|
||||
<string>v0.7.8.563351</string>
|
||||
</map>
|
||||
<key>apr_suite</key>
|
||||
<map>
|
||||
|
|
@ -1220,9 +1254,9 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>650e836255b6c2ecb93d3f1f7220051c</string>
|
||||
<string>dce3f3c01fddb400cb143c3283fe9259</string>
|
||||
<key>url</key>
|
||||
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/55011/511905/glh_linear-0.0.0-common-538981.tar.bz2</string>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/82754/775367/glh_linear-0.0.0-common-560278.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>common</string>
|
||||
|
|
@ -1231,72 +1265,6 @@
|
|||
<key>version</key>
|
||||
<string>0.0.0</string>
|
||||
</map>
|
||||
<key>glod</key>
|
||||
<map>
|
||||
<key>copyright</key>
|
||||
<string>Copyright 2003 Jonathan Cohen, Nat Duca, David Luebke, Brenden Schubert - Johns Hopkins University and University of Virginia</string>
|
||||
<key>license</key>
|
||||
<string>GLOD Open-Source License Version 1.0</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/GLOD.txt</string>
|
||||
<key>name</key>
|
||||
<string>glod</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>darwin64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>94fc457c46e1fb94b31251bd4747d10f</string>
|
||||
<key>url</key>
|
||||
<string>http://3p.firestormviewer.org/glod-1.0pre3.171101143-darwin64-171101143.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
</map>
|
||||
<key>linux64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>acc1181cd31ef32c3724eda84ae4b580</string>
|
||||
<key>url</key>
|
||||
<string>http://3p.firestormviewer.org/glod-1.0pre3.180990827-linux64-180990827.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>linux64</string>
|
||||
</map>
|
||||
<key>windows</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>e1f8da12a2b7a6c31830b4bb86d31ed6</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>md5</string>
|
||||
<key>url</key>
|
||||
<string>http://3p.firestormviewer.org/glod-1.0pre3.vs2017-1906061512-windows-vs2017-1906061512.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>e906cf08bfbfbd9d4fc78557e021e7d0</string>
|
||||
<key>url</key>
|
||||
<string>http://3p.firestormviewer.org/glod-1.0pre3.vs2017-1906061512-windows64-vs2017-1906061512.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>1.0pre3.532346</string>
|
||||
</map>
|
||||
<key>googlemock</key>
|
||||
<map>
|
||||
<key>copyright</key>
|
||||
|
|
@ -2256,6 +2224,62 @@
|
|||
<key>version</key>
|
||||
<string>7.11.1.297294</string>
|
||||
</map>
|
||||
<key>meshoptimizer</key>
|
||||
<map>
|
||||
<key>canonical_repo</key>
|
||||
<string>https://bitbucket.org/lindenlab/3p-meshoptimizer</string>
|
||||
<key>copyright</key>
|
||||
<string>Copyright (c) 2016-2021 Arseny Kapoulkine</string>
|
||||
<key>description</key>
|
||||
<string>Meshoptimizer. Mesh optimization library.</string>
|
||||
<key>license</key>
|
||||
<string>meshoptimizer</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/meshoptimizer.txt</string>
|
||||
<key>name</key>
|
||||
<string>meshoptimizer</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>darwin64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>30bc37db57bbd87c4b5f62634964242a</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/84218/784918/meshoptimizer-0.16.561408-darwin64-561408.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
</map>
|
||||
<key>windows</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>ca3684bcf0447746cd2844e94f6d1fc7</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/84219/784924/meshoptimizer-0.16.561408-windows-561408.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>aef28c089d20f69d13c9c3e113fb3895</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/84220/784931/meshoptimizer-0.16.561408-windows64-561408.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>0.16.561408</string>
|
||||
</map>
|
||||
<key>minizip-ng</key>
|
||||
<map>
|
||||
<key>canonical_repo</key>
|
||||
|
|
@ -2903,6 +2927,70 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>version</key>
|
||||
<string>0.132.2</string>
|
||||
</map>
|
||||
<key>tracy</key>
|
||||
<map>
|
||||
<key>canonical_repo</key>
|
||||
<string>https://bitbucket.org/lindenlab/3p-tracy</string>
|
||||
<key>copyright</key>
|
||||
<string>Copyright (c) 2017-2021, Bartosz Taudul (wolf@nereid.pl)</string>
|
||||
<key>description</key>
|
||||
<string>Tracy Profiler Library</string>
|
||||
<key>license</key>
|
||||
<string>bsd</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/tracy_license.txt</string>
|
||||
<key>name</key>
|
||||
<string>tracy</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>darwin64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>da7317e4a81609f624f84780f28b07de</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/86972/801630/tracy-v0.7.8.563351-darwin64-563351.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
</map>
|
||||
<key>windows</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>47c696cd2966c5cc3c8ba6115dd1f886</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>md5</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/86973/801641/tracy-v0.7.8.563351-windows-563351.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>b649ee6591e67d2341e886b3fc3484a7</string>
|
||||
<key>hash_algorithm</key>
|
||||
<string>md5</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/86974/801642/tracy-v0.7.8.563351-windows64-563351.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>source</key>
|
||||
<string>https://bitbucket.org/lindenlab/3p-tracy</string>
|
||||
<key>source_type</key>
|
||||
<string>git</string>
|
||||
<key>version</key>
|
||||
<string>v0.7.8.563351</string>
|
||||
</map>
|
||||
<key>tut</key>
|
||||
<map>
|
||||
<key>copyright</key>
|
||||
|
|
|
|||
12
build.sh
12
build.sh
|
|
@ -155,7 +155,11 @@ pre_build()
|
|||
fi
|
||||
set -x
|
||||
|
||||
"$autobuild" configure --quiet -c $variant -- \
|
||||
# honor autobuild_configure_parameters same as sling-buildscripts
|
||||
eval_autobuild_configure_parameters=$(eval $(echo echo $autobuild_configure_parameters))
|
||||
|
||||
"$autobuild" configure --quiet -c $variant \
|
||||
${eval_autobuild_configure_parameters:---} \
|
||||
-DPACKAGE:BOOL=ON \
|
||||
-DHAVOK:BOOL="$HAVOK" \
|
||||
-DRELEASE_CRASH_REPORTING:BOOL="$RELEASE_CRASH_REPORTING" \
|
||||
|
|
@ -205,7 +209,11 @@ build()
|
|||
if $build_viewer
|
||||
then
|
||||
begin_section "autobuild $variant"
|
||||
"$autobuild" build --no-configure -c $variant || fatal "failed building $variant"
|
||||
# honor autobuild_build_parameters same as sling-buildscripts
|
||||
eval_autobuild_build_parameters=$(eval $(echo echo $autobuild_build_parameters))
|
||||
"$autobuild" build --no-configure -c $variant \
|
||||
$eval_autobuild_build_parameters \
|
||||
|| fatal "failed building $variant"
|
||||
echo true >"$build_dir"/build_ok
|
||||
end_section "autobuild $variant"
|
||||
|
||||
|
|
|
|||
|
|
@ -280,7 +280,9 @@ Beq Janus
|
|||
SL-14766
|
||||
SL-14927
|
||||
SL-11300
|
||||
SL-15709
|
||||
SL-16021
|
||||
SL-16027
|
||||
Beth Walcher
|
||||
Bezilon Kasei
|
||||
Biancaluce Robbiani
|
||||
|
|
@ -1378,7 +1380,7 @@ Sovereign Engineer
|
|||
MAINT-7343
|
||||
SL-11079
|
||||
OPEN-343
|
||||
SL-11625
|
||||
SL-11625
|
||||
BUG-229030
|
||||
SL-14705
|
||||
SL-14706
|
||||
|
|
@ -1386,6 +1388,7 @@ Sovereign Engineer
|
|||
SL-14731
|
||||
SL-14732
|
||||
SL-15096
|
||||
SL-16127
|
||||
SpacedOut Frye
|
||||
VWR-34
|
||||
VWR-45
|
||||
|
|
|
|||
|
|
@ -77,12 +77,12 @@ endif (USE_AVX_OPTIMIZATION)
|
|||
add_subdirectory(cmake)
|
||||
|
||||
# <FS:Beq> Tracy Profiler support
|
||||
option(USE_TRACY_PROFILER "Tracy Profiler support" OFF)
|
||||
if (USE_TRACY_PROFILER)
|
||||
option(USE_TRACY "Tracy Profiler support" OFF)
|
||||
if (USE_TRACY)
|
||||
message(STATUS "Compiling with Tracy profiler")
|
||||
else (USE_TRACY_PROFILER)
|
||||
else (USE_TRACY)
|
||||
message(STATUS "Compiling without Tracy profiler")
|
||||
endif (USE_TRACY_PROFILER)
|
||||
endif (USE_TRACY)
|
||||
# </FS:Beq> Tracy Profiler support
|
||||
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llaudio)
|
||||
|
|
@ -95,6 +95,7 @@ add_subdirectory(${LIBS_OPEN_PREFIX}llkdu)
|
|||
add_subdirectory(${LIBS_OPEN_PREFIX}llimagej2coj)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llinventory)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llmath)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llmeshoptimizer)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llmessage)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llprimitive)
|
||||
add_subdirectory(${LIBS_OPEN_PREFIX}llrender)
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@ if(NON_RELEASE_CRASH_REPORTING)
|
|||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DLL_SEND_CRASH_REPORTS=1")
|
||||
endif()
|
||||
|
||||
# Don't bother with a MinSizeRel build.
|
||||
set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Release;Debug" CACHE STRING
|
||||
# Don't bother with MinSizeRel or Debug builds.
|
||||
set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Release" CACHE STRING
|
||||
"Supported build types." FORCE)
|
||||
|
||||
|
||||
|
|
@ -87,12 +87,18 @@ if (WINDOWS)
|
|||
#if( ADDRESS_SIZE EQUAL 32 )
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /p:PreferredToolArchitecture=x64")
|
||||
#endif()
|
||||
|
||||
# Preserve first-pass-through versions (ie no FORCE overwrite). Prevents recursive addition of /Zo (04/2021)
|
||||
set(OG_CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} CACHE STRING "OG_CXX_FLAGS_RELEASE")
|
||||
set(OG_CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO} CACHE STRING "OG_CXX_FLAGS_RELWITHDEBINFO")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO
|
||||
"${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Zo"
|
||||
"${OG_CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Zo"
|
||||
CACHE STRING "C++ compiler release-with-debug options" FORCE)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE
|
||||
"${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /Zo"
|
||||
"${OG_CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /Zo"
|
||||
CACHE STRING "C++ compiler release options" FORCE)
|
||||
|
||||
# zlib has assembly-language object files incompatible with SAFESEH
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LARGEADDRESSAWARE /SAFESEH:NO /NODEFAULTLIB:LIBCMT /IGNORE:4099")
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ set(cmake_SOURCE_FILES
|
|||
FreeType.cmake
|
||||
GLEXT.cmake
|
||||
GLH.cmake
|
||||
GLOD.cmake
|
||||
## GStreamer010Plugin.cmake
|
||||
GoogleMock.cmake
|
||||
Growl.cmake
|
||||
|
|
@ -60,6 +59,7 @@ set(cmake_SOURCE_FILES
|
|||
LLKDU.cmake
|
||||
LLLogin.cmake
|
||||
LLMath.cmake
|
||||
LLMeshOptimizer.cmake
|
||||
LLMessage.cmake
|
||||
LLPhysicsExtensions.cmake
|
||||
LLPlugin.cmake
|
||||
|
|
@ -73,6 +73,7 @@ set(cmake_SOURCE_FILES
|
|||
LLXML.cmake
|
||||
Linking.cmake
|
||||
MediaPluginBase.cmake
|
||||
MESHOPTIMIZER.cmake
|
||||
NDOF.cmake
|
||||
OPENAL.cmake
|
||||
OpenGL.cmake
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ if(WINDOWS)
|
|||
libaprutil-1.dll
|
||||
libapriconv-1.dll
|
||||
nghttp2.dll
|
||||
glod.dll
|
||||
libhunspell.dll
|
||||
uriparser.dll
|
||||
)
|
||||
|
|
@ -151,6 +150,7 @@ if(WINDOWS)
|
|||
msvcp${MSVC_VER}.dll
|
||||
#msvcr${MSVC_VER}.dll # <FS:Ansariel> Can't build with older VS versions anyway - no need trying to copy this file
|
||||
vcruntime${MSVC_VER}.dll
|
||||
vcruntime${MSVC_VER}_1.dll
|
||||
)
|
||||
# <FS:Ansariel> Try using the VC runtime redistributables that came with the VS installation first
|
||||
if(redist_path AND EXISTS "${redist_path}/${release_msvc_file}")
|
||||
|
|
@ -198,7 +198,6 @@ elseif(DARWIN)
|
|||
libaprutil-1.0.dylib
|
||||
libaprutil-1.dylib
|
||||
${EXPAT_COPY}
|
||||
libGLOD.dylib
|
||||
libhunspell-1.3.0.dylib
|
||||
libndofdev.dylib
|
||||
libnghttp2.dylib
|
||||
|
|
@ -247,7 +246,6 @@ elseif(LINUX)
|
|||
set(release_files
|
||||
#libdb-5.1.so
|
||||
${EXPAT_COPY}
|
||||
#libGLOD.so
|
||||
libhunspell-1.3.so.0.0.0
|
||||
libopenal.so
|
||||
#libopenjpeg.so
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
# -*- cmake -*-
|
||||
|
||||
#if (USESYSTEMLIBS)
|
||||
# set(GLOD_FIND_REQUIRED true)
|
||||
# include(FindGLOD)
|
||||
#else (USESYSTEMLIBS)
|
||||
include(Prebuilt)
|
||||
use_prebuilt_binary(glod)
|
||||
set(GLOD_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
|
||||
if(LINUX)
|
||||
set(GLOD_LIBRARIES GLOD vds)
|
||||
else()
|
||||
set(GLOD_LIBRARIES GLOD)
|
||||
endif()
|
||||
#endif (USESYSTEMLIBS)
|
||||
|
|
@ -39,7 +39,8 @@ else (LINUX)
|
|||
${BOOST_FIBER_LIBRARY}
|
||||
${BOOST_CONTEXT_LIBRARY}
|
||||
${BOOST_THREAD_LIBRARY}
|
||||
${BOOST_SYSTEM_LIBRARY} )
|
||||
${BOOST_SYSTEM_LIBRARY}
|
||||
)
|
||||
endif (LINUX)
|
||||
|
||||
set(LLCOMMON_LINK_SHARED OFF CACHE BOOL "Build the llcommon target as a static library.")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
# -*- cmake -*-
|
||||
|
||||
set(LLMESHOPTIMIZER_INCLUDE_DIRS
|
||||
${LIBS_OPEN_DIR}/llmeshoptimizer
|
||||
)
|
||||
|
||||
set(LLMESHOPTIMIZER_LIBRARIES llmeshoptimizer)
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
# -*- cmake -*-
|
||||
|
||||
include(Linking)
|
||||
include(Prebuilt)
|
||||
|
||||
use_prebuilt_binary(meshoptimizer)
|
||||
|
||||
if (WINDOWS)
|
||||
set(MESHOPTIMIZER_LIBRARIES meshoptimizer.lib)
|
||||
elseif (LINUX)
|
||||
set(MESHOPTIMIZER_LIBRARIES meshoptimizer.o)
|
||||
elseif (DARWIN)
|
||||
set(MESHOPTIMIZER_LIBRARIES libmeshoptimizer.a)
|
||||
endif (WINDOWS)
|
||||
|
||||
set(MESHOPTIMIZER_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/meshoptimizer)
|
||||
|
|
@ -1,16 +1,29 @@
|
|||
# Tracy Profiler support.
|
||||
if (USE_TRACY_PROFILER)
|
||||
include(Prebuilt)
|
||||
use_prebuilt_binary(Tracy)
|
||||
if (WINDOWS)
|
||||
# set(TRACY_LIBRARIES
|
||||
# ${ARCH_PREBUILT_DIRS_RELEASE}/Tracy.lib
|
||||
add_definitions(-DTRACY_ENABLE=1 -DTRACY_NO_FASTTIMERS -DWINVER=0x0601 )
|
||||
set(TRACY_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/tracy)
|
||||
elseif (DARWIN)
|
||||
message(FATAL_ERROR "Tracy is not yet implemented in FS for OSX.")
|
||||
else (WINDOWS)
|
||||
add_definitions(-DTRACY_ENABLE=1 -DTRACY_NO_FASTTIMERS )
|
||||
set(TRACY_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/tracy)
|
||||
endif (WINDOWS)
|
||||
endif (USE_TRACY_PROFILER)
|
||||
# -*- cmake -*-
|
||||
include(Prebuilt)
|
||||
|
||||
set(USE_TRACY OFF CACHE BOOL "Use Tracy profiler.")
|
||||
|
||||
if (USE_TRACY)
|
||||
set(TRACY_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/tracy)
|
||||
|
||||
# See: indra/llcommon/llprofiler.h
|
||||
add_definitions(-DLL_PROFILER_CONFIGURATION=3)
|
||||
use_prebuilt_binary(tracy)
|
||||
|
||||
# if (WINDOWS)
|
||||
# MESSAGE(STATUS "Including Tracy for Windows: '${TRACY_INCLUDE_DIR}'")
|
||||
# endif (WINDOWS)
|
||||
|
||||
# if (DARWIN)
|
||||
# MESSAGE(STATUS "Including Tracy for Darwin: '${TRACY_INCLUDE_DIR}'")
|
||||
# endif (DARWIN)
|
||||
|
||||
# if (LINUX)
|
||||
# MESSAGE(STATUS "Including Tracy for Linux: '${TRACY_INCLUDE_DIR}'")
|
||||
# endif (LINUX)
|
||||
else (USE_TRACY)
|
||||
# Tracy.cmake should not set LLCOMMON_INCLUDE_DIRS, let LLCommon.cmake do that
|
||||
set(TRACY_INCLUDE_DIR "")
|
||||
set(TRACY_LIBRARY "")
|
||||
endif (USE_TRACY)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
euclid 5/29/2020
|
||||
euclid 7/23/2020
|
||||
euclid 4/29/2021
|
||||
euclid 10/5/2021 DRTVWR-546
|
||||
|
|
|
|||
|
|
@ -899,6 +899,49 @@ class LLManifest(object, metaclass=LLManifestRegistry):
|
|||
# particular, let caller notice 0.
|
||||
return count
|
||||
|
||||
def path_optional(self, src, dst=None):
|
||||
sys.stdout.flush()
|
||||
if src == None:
|
||||
raise ManifestError("No source file, dst is " + dst)
|
||||
if dst == None:
|
||||
dst = src
|
||||
dst = os.path.join(self.get_dst_prefix(), dst)
|
||||
sys.stdout.write("Processing %s => %s ... " % (src, self._relative_dst_path(dst)))
|
||||
|
||||
def try_path(src):
|
||||
# expand globs
|
||||
count = 0
|
||||
if self.wildcard_pattern.search(src):
|
||||
for s,d in self.expand_globs(src, dst):
|
||||
assert(s != d)
|
||||
count += self.process_file(s, d)
|
||||
else:
|
||||
# if we're specifying a single path (not a glob),
|
||||
# we should error out if it doesn't exist
|
||||
self.check_file_exists(src)
|
||||
count += self.process_either(src, dst)
|
||||
return count
|
||||
|
||||
try_prefixes = [self.get_src_prefix(), self.get_artwork_prefix(), self.get_build_prefix()]
|
||||
for pfx in try_prefixes:
|
||||
try:
|
||||
count = try_path(os.path.join(pfx, src))
|
||||
except MissingError:
|
||||
# if we produce MissingError, just try the next prefix
|
||||
continue
|
||||
# If we actually found nonzero files, stop looking
|
||||
if count:
|
||||
break
|
||||
else:
|
||||
sys.stdout.write("Skipping %s\n" % (src))
|
||||
return 0
|
||||
|
||||
print("%d files" % count)
|
||||
|
||||
# Let caller check whether we processed as many files as expected. In
|
||||
# particular, let caller notice 0.
|
||||
return count
|
||||
|
||||
def do(self, *actions):
|
||||
self.actions = actions
|
||||
self.construct()
|
||||
|
|
|
|||
|
|
@ -1620,7 +1620,7 @@ BOOL LLAvatarAppearance::allocateCollisionVolumes( U32 num )
|
|||
delete_and_clear_array(mCollisionVolumes);
|
||||
mNumCollisionVolumes = 0;
|
||||
|
||||
mCollisionVolumes = new(std::nothrow) LLAvatarJointCollisionVolume[num];
|
||||
mCollisionVolumes = new LLAvatarJointCollisionVolume[num];
|
||||
if (!mCollisionVolumes)
|
||||
{
|
||||
LL_WARNS() << "Failed to allocate collision volumes" << LL_ENDL;
|
||||
|
|
|
|||
|
|
@ -77,81 +77,71 @@ protected:
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
LL_ALIGN_PREFIX(16)
|
||||
class LLDriverParam : public LLViewerVisualParam
|
||||
class alignas(16) LLDriverParam : public LLViewerVisualParam
|
||||
{
|
||||
LL_ALIGN_NEW
|
||||
private:
|
||||
// Hide the default constructor. Force construction with LLAvatarAppearance.
|
||||
LLDriverParam() {}
|
||||
// Hide the default constructor. Force construction with LLAvatarAppearance.
|
||||
LLDriverParam() {}
|
||||
public:
|
||||
LLDriverParam(LLAvatarAppearance *appearance, LLWearable* wearable = NULL);
|
||||
~LLDriverParam();
|
||||
LLDriverParam(LLAvatarAppearance* appearance, LLWearable* wearable = NULL);
|
||||
~LLDriverParam();
|
||||
|
||||
void* operator new(size_t size)
|
||||
{
|
||||
return ll_aligned_malloc_16(size);
|
||||
}
|
||||
// Special: These functions are overridden by child classes
|
||||
LLDriverParamInfo* getInfo() const { return (LLDriverParamInfo*)mInfo; }
|
||||
// This sets mInfo and calls initialization functions
|
||||
BOOL setInfo(LLDriverParamInfo* info);
|
||||
|
||||
void operator delete(void* ptr)
|
||||
{
|
||||
ll_aligned_free_16(ptr);
|
||||
}
|
||||
LLAvatarAppearance* getAvatarAppearance() { return mAvatarAppearance; }
|
||||
const LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; }
|
||||
|
||||
// Special: These functions are overridden by child classes
|
||||
LLDriverParamInfo* getInfo() const { return (LLDriverParamInfo*)mInfo; }
|
||||
// This sets mInfo and calls initialization functions
|
||||
BOOL setInfo(LLDriverParamInfo *info);
|
||||
void updateCrossDrivenParams(LLWearableType::EType driven_type);
|
||||
|
||||
LLAvatarAppearance* getAvatarAppearance() { return mAvatarAppearance; }
|
||||
const LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; }
|
||||
/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
|
||||
|
||||
void updateCrossDrivenParams(LLWearableType::EType driven_type);
|
||||
// LLVisualParam Virtual functions
|
||||
/*virtual*/ void apply(ESex sex) {} // apply is called separately for each driven param.
|
||||
// <FS:Ansariel> [Legacy Bake]
|
||||
///*virtual*/ void setWeight(F32 weight);
|
||||
///*virtual*/ void setAnimationTarget(F32 target_value);
|
||||
///*virtual*/ void stopAnimating();
|
||||
/*virtual*/ void setWeight(F32 weight, BOOL upload_bake);
|
||||
/*virtual*/ void setAnimationTarget(F32 target_value, BOOL upload_bake);
|
||||
/*virtual*/ void stopAnimating(BOOL upload_bake);
|
||||
// </FS:Ansariel> [Legacy Bake]
|
||||
/*virtual*/ BOOL linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params);
|
||||
/*virtual*/ void resetDrivenParams();
|
||||
|
||||
/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
|
||||
// LLViewerVisualParam Virtual functions
|
||||
/*virtual*/ F32 getTotalDistortion();
|
||||
/*virtual*/ const LLVector4a& getAvgDistortion();
|
||||
/*virtual*/ F32 getMaxDistortion();
|
||||
/*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh* poly_mesh);
|
||||
/*virtual*/ const LLVector4a* getFirstDistortion(U32* index, LLPolyMesh** poly_mesh);
|
||||
/*virtual*/ const LLVector4a* getNextDistortion(U32* index, LLPolyMesh** poly_mesh);
|
||||
|
||||
// LLVisualParam Virtual functions
|
||||
/*virtual*/ void apply( ESex sex ) {} // apply is called separately for each driven param.
|
||||
// <FS:Ansariel> [Legacy Bake]
|
||||
///*virtual*/ void setWeight(F32 weight);
|
||||
///*virtual*/ void setAnimationTarget( F32 target_value);
|
||||
///*virtual*/ void stopAnimating();
|
||||
/*virtual*/ void setWeight(F32 weight, BOOL upload_bake);
|
||||
/*virtual*/ void setAnimationTarget( F32 target_value, BOOL upload_bake);
|
||||
/*virtual*/ void stopAnimating(BOOL upload_bake);
|
||||
// </FS:Ansariel> [Legacy Bake]
|
||||
/*virtual*/ BOOL linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params);
|
||||
/*virtual*/ void resetDrivenParams();
|
||||
|
||||
// LLViewerVisualParam Virtual functions
|
||||
/*virtual*/ F32 getTotalDistortion();
|
||||
/*virtual*/ const LLVector4a& getAvgDistortion();
|
||||
/*virtual*/ F32 getMaxDistortion();
|
||||
/*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh);
|
||||
/*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh);
|
||||
/*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh);
|
||||
S32 getDrivenParamsCount() const;
|
||||
const LLViewerVisualParam* getDrivenParam(S32 index) const;
|
||||
|
||||
S32 getDrivenParamsCount() const;
|
||||
const LLViewerVisualParam* getDrivenParam(S32 index) const;
|
||||
|
||||
typedef std::vector<LLDrivenEntry> entry_list_t;
|
||||
entry_list_t& getDrivenList() { return mDriven; }
|
||||
typedef std::vector<LLDrivenEntry> entry_list_t;
|
||||
entry_list_t& getDrivenList() { return mDriven; }
|
||||
void setDrivenList(entry_list_t& driven_list) { mDriven = driven_list; }
|
||||
|
||||
protected:
|
||||
LLDriverParam(const LLDriverParam& pOther);
|
||||
F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight);
|
||||
// <FS:Ansariel> [Legacy Bake]
|
||||
//void setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight);
|
||||
void setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake);
|
||||
// </FS:Ansariel> [Legacy Bake]
|
||||
LLDriverParam(const LLDriverParam& pOther);
|
||||
F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight);
|
||||
// <FS:Ansariel> [Legacy Bake]
|
||||
//void setDrivenWeight(LLDrivenEntry* driven, F32 driven_weight);
|
||||
void setDrivenWeight(LLDrivenEntry* driven, F32 driven_weight, bool upload_bake);
|
||||
// </FS:Ansariel> [Legacy Bake]
|
||||
|
||||
|
||||
LL_ALIGN_16(LLVector4a mDefaultVec); // temp holder
|
||||
entry_list_t mDriven;
|
||||
LLViewerVisualParam* mCurrentDistortionParam;
|
||||
// Backlink only; don't make this an LLPointer.
|
||||
LLAvatarAppearance* mAvatarAppearance;
|
||||
LLWearable* mWearablep;
|
||||
} LL_ALIGN_POSTFIX(16);
|
||||
LL_ALIGN_16(LLVector4a mDefaultVec); // temp holder
|
||||
entry_list_t mDriven;
|
||||
LLViewerVisualParam* mCurrentDistortionParam;
|
||||
// Backlink only; don't make this an LLPointer.
|
||||
LLAvatarAppearance* mAvatarAppearance;
|
||||
LLWearable* mWearablep;
|
||||
};
|
||||
|
||||
#endif // LL_LLDRIVERPARAM_H
|
||||
|
|
|
|||
|
|
@ -541,8 +541,6 @@ F32 LLPolyMorphTarget::getMaxDistortion()
|
|||
//-----------------------------------------------------------------------------
|
||||
// apply()
|
||||
//-----------------------------------------------------------------------------
|
||||
static LLTrace::BlockTimerStatHandle FTM_APPLY_MORPH_TARGET("Apply Morph");
|
||||
|
||||
void LLPolyMorphTarget::apply( ESex avatar_sex )
|
||||
{
|
||||
if (!mMorphData || mNumMorphMasksPending > 0)
|
||||
|
|
@ -550,7 +548,7 @@ void LLPolyMorphTarget::apply( ESex avatar_sex )
|
|||
return;
|
||||
}
|
||||
|
||||
LL_RECORD_BLOCK_TIME(FTM_APPLY_MORPH_TARGET);
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
|
||||
mLastSex = avatar_sex;
|
||||
|
||||
|
|
|
|||
|
|
@ -41,24 +41,14 @@ class LLWearable;
|
|||
//-----------------------------------------------------------------------------
|
||||
// LLPolyMorphData()
|
||||
//-----------------------------------------------------------------------------
|
||||
LL_ALIGN_PREFIX(16)
|
||||
class LLPolyMorphData
|
||||
class alignas(16) LLPolyMorphData
|
||||
{
|
||||
LL_ALIGN_NEW
|
||||
public:
|
||||
LLPolyMorphData(const std::string& morph_name);
|
||||
~LLPolyMorphData();
|
||||
LLPolyMorphData(const LLPolyMorphData &rhs);
|
||||
|
||||
void* operator new(size_t size)
|
||||
{
|
||||
return ll_aligned_malloc_16(size);
|
||||
}
|
||||
|
||||
void operator delete(void* ptr)
|
||||
{
|
||||
ll_aligned_free_16(ptr);
|
||||
}
|
||||
|
||||
BOOL loadBinary(LLFILE* fp, LLPolyMeshSharedData *mesh);
|
||||
const std::string& getName() { return mName; }
|
||||
|
||||
|
|
@ -76,7 +66,7 @@ public:
|
|||
|
||||
F32 mTotalDistortion; // vertex distortion summed over entire morph
|
||||
F32 mMaxDistortion; // maximum single vertex distortion in a given morph
|
||||
LL_ALIGN_16(LLVector4a mAvgDistortion); // average vertex distortion, to infer directionality of the morph
|
||||
LLVector4a mAvgDistortion; // average vertex distortion, to infer directionality of the morph
|
||||
LLPolyMeshSharedData* mMesh;
|
||||
|
||||
private:
|
||||
|
|
@ -154,8 +144,9 @@ protected:
|
|||
// These morph targets must be topologically consistent with a given Polymesh
|
||||
// (share face sets)
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLPolyMorphTarget : public LLViewerVisualParam
|
||||
class alignas(16) LLPolyMorphTarget : public LLViewerVisualParam
|
||||
{
|
||||
LL_ALIGN_NEW
|
||||
public:
|
||||
LLPolyMorphTarget(LLPolyMesh *poly_mesh);
|
||||
~LLPolyMorphTarget();
|
||||
|
|
@ -184,16 +175,6 @@ public:
|
|||
|
||||
void applyVolumeChanges(F32 delta_weight); // SL-315 - for resetSkeleton()
|
||||
|
||||
void* operator new(size_t size)
|
||||
{
|
||||
return ll_aligned_malloc_16(size);
|
||||
}
|
||||
|
||||
void operator delete(void* ptr)
|
||||
{
|
||||
ll_aligned_free_16(ptr);
|
||||
}
|
||||
|
||||
protected:
|
||||
LLPolyMorphTarget(const LLPolyMorphTarget& pOther);
|
||||
|
||||
|
|
|
|||
|
|
@ -190,11 +190,9 @@ BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)
|
|||
//-----------------------------------------------------------------------------
|
||||
// apply()
|
||||
//-----------------------------------------------------------------------------
|
||||
static LLTrace::BlockTimerStatHandle FTM_POLYSKELETAL_DISTORTION_APPLY("Skeletal Distortion");
|
||||
|
||||
void LLPolySkeletalDistortion::apply( ESex avatar_sex )
|
||||
{
|
||||
LL_RECORD_BLOCK_TIME(FTM_POLYSKELETAL_DISTORTION_APPLY);
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
|
||||
F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight();
|
||||
|
||||
|
|
|
|||
|
|
@ -62,9 +62,9 @@ struct LLPolySkeletalBoneInfo
|
|||
BOOL mHasPositionDeformation;
|
||||
};
|
||||
|
||||
LL_ALIGN_PREFIX(16)
|
||||
class LLPolySkeletalDistortionInfo : public LLViewerVisualParamInfo
|
||||
class alignas(16) LLPolySkeletalDistortionInfo : public LLViewerVisualParamInfo
|
||||
{
|
||||
LL_ALIGN_NEW
|
||||
friend class LLPolySkeletalDistortion;
|
||||
public:
|
||||
|
||||
|
|
@ -73,19 +73,6 @@ public:
|
|||
|
||||
/*virtual*/ BOOL parseXml(LLXmlTreeNode* node);
|
||||
|
||||
|
||||
|
||||
void* operator new(size_t size)
|
||||
{
|
||||
return ll_aligned_malloc_16(size);
|
||||
}
|
||||
|
||||
void operator delete(void* ptr)
|
||||
{
|
||||
ll_aligned_free_16(ptr);
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
typedef std::vector<LLPolySkeletalBoneInfo> bone_info_list_t;
|
||||
bone_info_list_t mBoneInfoList;
|
||||
|
|
@ -95,19 +82,10 @@ protected:
|
|||
// LLPolySkeletalDeformation
|
||||
// A set of joint scale data for deforming the avatar mesh
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLPolySkeletalDistortion : public LLViewerVisualParam
|
||||
class alignas(16) LLPolySkeletalDistortion : public LLViewerVisualParam
|
||||
{
|
||||
LL_ALIGN_NEW
|
||||
public:
|
||||
void* operator new(size_t size)
|
||||
{
|
||||
return ll_aligned_malloc_16(size);
|
||||
}
|
||||
|
||||
void operator delete(void* ptr)
|
||||
{
|
||||
ll_aligned_free_16(ptr);
|
||||
}
|
||||
|
||||
LLPolySkeletalDistortion(LLAvatarAppearance *avatarp);
|
||||
~LLPolySkeletalDistortion();
|
||||
|
||||
|
|
|
|||
|
|
@ -142,17 +142,8 @@ BOOL LLTexLayerSetBuffer::renderTexLayerSet(LLRenderTarget* bound_target)
|
|||
|
||||
BOOL success = TRUE;
|
||||
|
||||
bool use_shaders = LLGLSLShader::sNoFixedFunction;
|
||||
|
||||
if (use_shaders)
|
||||
{
|
||||
gAlphaMaskProgram.bind();
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.004f);
|
||||
}
|
||||
else
|
||||
{
|
||||
gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.00f);
|
||||
}
|
||||
gAlphaMaskProgram.bind();
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.004f);
|
||||
|
||||
LLVertexBuffer::unbind();
|
||||
|
||||
|
|
@ -167,10 +158,7 @@ BOOL LLTexLayerSetBuffer::renderTexLayerSet(LLRenderTarget* bound_target)
|
|||
midRenderTexLayerSet(success, bound_target);
|
||||
// </FS:Ansariel> [Legacy Bake]
|
||||
|
||||
if (use_shaders)
|
||||
{
|
||||
gAlphaMaskProgram.unbind();
|
||||
}
|
||||
gAlphaMaskProgram.unbind();
|
||||
|
||||
LLVertexBuffer::unbind();
|
||||
|
||||
|
|
@ -397,8 +385,6 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height, LLRenderTarget*
|
|||
}
|
||||
}
|
||||
|
||||
bool use_shaders = LLGLSLShader::sNoFixedFunction;
|
||||
|
||||
LLGLSUIDefault gls_ui;
|
||||
LLGLDepthTest gls_depth(GL_FALSE, GL_FALSE);
|
||||
gGL.setColorMask(true, true);
|
||||
|
|
@ -407,20 +393,14 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height, LLRenderTarget*
|
|||
{
|
||||
gGL.flush();
|
||||
LLGLDisable no_alpha(GL_ALPHA_TEST);
|
||||
if (use_shaders)
|
||||
{
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.0f);
|
||||
}
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.0f);
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
gGL.color4f( 0.f, 0.f, 0.f, 1.f );
|
||||
|
||||
gl_rect_2d_simple( width, height );
|
||||
|
||||
gGL.flush();
|
||||
if (use_shaders)
|
||||
{
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.004f);
|
||||
}
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.004f);
|
||||
}
|
||||
|
||||
if (mIsVisible)
|
||||
|
|
@ -447,10 +427,7 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height, LLRenderTarget*
|
|||
|
||||
gGL.setSceneBlendType(LLRender::BT_REPLACE);
|
||||
LLGLDisable no_alpha(GL_ALPHA_TEST);
|
||||
if (use_shaders)
|
||||
{
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
||||
}
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
||||
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
gGL.color4f( 0.f, 0.f, 0.f, 0.f );
|
||||
|
|
@ -459,10 +436,7 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height, LLRenderTarget*
|
|||
gGL.setSceneBlendType(LLRender::BT_ALPHA);
|
||||
|
||||
gGL.flush();
|
||||
if (use_shaders)
|
||||
{
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.004f);
|
||||
}
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.004f);
|
||||
}
|
||||
|
||||
return success;
|
||||
|
|
@ -501,10 +475,9 @@ const LLTexLayerSetBuffer* LLTexLayerSet::getComposite() const
|
|||
return mComposite;
|
||||
}
|
||||
|
||||
static LLTrace::BlockTimerStatHandle FTM_GATHER_MORPH_MASK_ALPHA("gatherMorphMaskAlpha");
|
||||
void LLTexLayerSet::gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S32 width, S32 height, LLRenderTarget* bound_target)
|
||||
{
|
||||
LL_RECORD_BLOCK_TIME(FTM_GATHER_MORPH_MASK_ALPHA);
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
memset(data, 255, width * height);
|
||||
|
||||
for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ )
|
||||
|
|
@ -517,14 +490,11 @@ void LLTexLayerSet::gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S
|
|||
renderAlphaMaskTextures(origin_x, origin_y, width, height, bound_target, true);
|
||||
}
|
||||
|
||||
static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MASK_TEXTURES("renderAlphaMaskTextures");
|
||||
void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target, bool forceClear)
|
||||
{
|
||||
LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK_TEXTURES);
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
const LLTexLayerSetInfo *info = getInfo();
|
||||
|
||||
bool use_shaders = LLGLSLShader::sNoFixedFunction;
|
||||
|
||||
gGL.setColorMask(false, true);
|
||||
gGL.setSceneBlendType(LLRender::BT_REPLACE);
|
||||
|
||||
|
|
@ -538,7 +508,6 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height,
|
|||
{
|
||||
LLGLSUIDefault gls_ui;
|
||||
gGL.getTexUnit(0)->bind(tex);
|
||||
gGL.getTexUnit(0)->setTextureBlendType( LLTexUnit::TB_REPLACE );
|
||||
gl_rect_2d_simple_tex( width, height );
|
||||
}
|
||||
}
|
||||
|
|
@ -549,20 +518,14 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height,
|
|||
// Set the alpha channel to one (clean up after previous blending)
|
||||
gGL.flush();
|
||||
LLGLDisable no_alpha(GL_ALPHA_TEST);
|
||||
if (use_shaders)
|
||||
{
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
||||
}
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
gGL.color4f( 0.f, 0.f, 0.f, 1.f );
|
||||
|
||||
gl_rect_2d_simple( width, height );
|
||||
|
||||
gGL.flush();
|
||||
if (use_shaders)
|
||||
{
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.004f);
|
||||
}
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.004f);
|
||||
}
|
||||
|
||||
// (Optional) Mask out part of the baked texture with alpha masks
|
||||
|
|
@ -570,7 +533,6 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height,
|
|||
if (mMaskLayerList.size() > 0)
|
||||
{
|
||||
gGL.setSceneBlendType(LLRender::BT_MULT_ALPHA);
|
||||
gGL.getTexUnit(0)->setTextureBlendType( LLTexUnit::TB_REPLACE );
|
||||
for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++)
|
||||
{
|
||||
LLTexLayerInterface* layer = *iter;
|
||||
|
|
@ -583,7 +545,6 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height,
|
|||
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
|
||||
gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
|
||||
gGL.setColorMask(true, true);
|
||||
gGL.setSceneBlendType(LLRender::BT_ALPHA);
|
||||
}
|
||||
|
|
@ -1109,13 +1070,6 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bou
|
|||
// *TODO: Is this correct?
|
||||
//gPipeline.disableLights();
|
||||
stop_glerror();
|
||||
if (!LLGLSLShader::sNoFixedFunction)
|
||||
{
|
||||
glDisable(GL_LIGHTING);
|
||||
}
|
||||
stop_glerror();
|
||||
|
||||
bool use_shaders = LLGLSLShader::sNoFixedFunction;
|
||||
|
||||
LLColor4 net_color;
|
||||
BOOL color_specified = findNetColor(&net_color);
|
||||
|
|
@ -1202,10 +1156,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bou
|
|||
LLGLDisable alpha_test(no_alpha_test ? GL_ALPHA_TEST : 0);
|
||||
if (no_alpha_test)
|
||||
{
|
||||
if (use_shaders)
|
||||
{
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
||||
}
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
||||
}
|
||||
|
||||
LLTexUnit::eTextureAddressMode old_mode = tex->getAddressMode();
|
||||
|
|
@ -1219,10 +1170,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bou
|
|||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
if (no_alpha_test)
|
||||
{
|
||||
if (use_shaders)
|
||||
{
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.004f);
|
||||
}
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.004f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1256,18 +1204,12 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bou
|
|||
color_specified )
|
||||
{
|
||||
LLGLDisable no_alpha(GL_ALPHA_TEST);
|
||||
if (use_shaders)
|
||||
{
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.000f);
|
||||
}
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.000f);
|
||||
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
gGL.color4fv( net_color.mV );
|
||||
gl_rect_2d_simple( width, height );
|
||||
if (use_shaders)
|
||||
{
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.004f);
|
||||
}
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.004f);
|
||||
}
|
||||
|
||||
if( alpha_mask_specified || getInfo()->mWriteAllChannels )
|
||||
|
|
@ -1355,25 +1297,17 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height)
|
|||
|
||||
gGL.flush();
|
||||
|
||||
bool use_shaders = LLGLSLShader::sNoFixedFunction;
|
||||
|
||||
if( !getInfo()->mStaticImageFileName.empty() )
|
||||
{
|
||||
LLGLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture( getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask );
|
||||
if( tex )
|
||||
{
|
||||
LLGLSNoAlphaTest gls_no_alpha_test;
|
||||
if (use_shaders)
|
||||
{
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
||||
}
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
||||
gGL.getTexUnit(0)->bind(tex, TRUE);
|
||||
gl_rect_2d_simple_tex( width, height );
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
if (use_shaders)
|
||||
{
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.004f);
|
||||
}
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.004f);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1388,18 +1322,11 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height)
|
|||
if (tex)
|
||||
{
|
||||
LLGLSNoAlphaTest gls_no_alpha_test;
|
||||
if (use_shaders)
|
||||
{
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
||||
}
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
||||
gGL.getTexUnit(0)->bind(tex);
|
||||
gl_rect_2d_simple_tex( width, height );
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
success = TRUE;
|
||||
if (use_shaders)
|
||||
{
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.004f);
|
||||
}
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.004f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1412,7 +1339,6 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height)
|
|||
addAlphaMask(data, originX, originY, width, height, bound_target);
|
||||
}
|
||||
|
||||
static LLTrace::BlockTimerStatHandle FTM_RENDER_MORPH_MASKS("renderMorphMasks");
|
||||
void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color, LLRenderTarget* bound_target, bool force_render)
|
||||
{
|
||||
if (!force_render && !hasMorph())
|
||||
|
|
@ -1420,18 +1346,12 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
|
|||
LL_DEBUGS() << "skipping renderMorphMasks for " << getUUID() << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
LL_RECORD_BLOCK_TIME(FTM_RENDER_MORPH_MASKS);
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
BOOL success = TRUE;
|
||||
|
||||
llassert( !mParamAlphaList.empty() );
|
||||
|
||||
bool use_shaders = LLGLSLShader::sNoFixedFunction;
|
||||
|
||||
if (use_shaders)
|
||||
{
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
||||
}
|
||||
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.f);
|
||||
gGL.setColorMask(false, true);
|
||||
|
||||
LLTexLayerParamAlpha* first_param = *mParamAlphaList.begin();
|
||||
|
|
@ -1516,10 +1436,7 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
|
|||
gl_rect_2d_simple( width, height );
|
||||
}
|
||||
|
||||
if (use_shaders)
|
||||
{
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.004f);
|
||||
}
|
||||
gAlphaMaskProgram.setMinimumAlpha(0.004f);
|
||||
|
||||
LLGLSUIDefault gls_ui;
|
||||
|
||||
|
|
@ -1678,10 +1595,9 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
|
|||
}
|
||||
}
|
||||
|
||||
static LLTrace::BlockTimerStatHandle FTM_ADD_ALPHA_MASK("addAlphaMask");
|
||||
void LLTexLayer::addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target)
|
||||
{
|
||||
LL_RECORD_BLOCK_TIME(FTM_ADD_ALPHA_MASK);
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
S32 size = width * height;
|
||||
const U8* alphaData = getAlphaData();
|
||||
if (!alphaData && hasAlphaParams())
|
||||
|
|
@ -2022,10 +1938,9 @@ void LLTexLayerStaticImageList::deleteCachedImages()
|
|||
|
||||
// Returns an LLImageTGA that contains the encoded data from a tga file named file_name.
|
||||
// Caches the result to speed identical subsequent requests.
|
||||
static LLTrace::BlockTimerStatHandle FTM_LOAD_STATIC_TGA("getImageTGA");
|
||||
LLImageTGA* LLTexLayerStaticImageList::getImageTGA(const std::string& file_name)
|
||||
{
|
||||
LL_RECORD_BLOCK_TIME(FTM_LOAD_STATIC_TGA);
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
const char *namekey = mImageNames.addString(file_name);
|
||||
image_tga_map_t::const_iterator iter = mStaticImageListTGA.find(namekey);
|
||||
if( iter != mStaticImageListTGA.end() )
|
||||
|
|
@ -2052,10 +1967,9 @@ LLImageTGA* LLTexLayerStaticImageList::getImageTGA(const std::string& file_name)
|
|||
|
||||
// Returns a GL Image (without a backing ImageRaw) that contains the decoded data from a tga file named file_name.
|
||||
// Caches the result to speed identical subsequent requests.
|
||||
static LLTrace::BlockTimerStatHandle FTM_LOAD_STATIC_TEXTURE("getTexture");
|
||||
LLGLTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name, BOOL is_mask)
|
||||
{
|
||||
LL_RECORD_BLOCK_TIME(FTM_LOAD_STATIC_TEXTURE);
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
LLPointer<LLGLTexture> tex;
|
||||
const char *namekey = mImageNames.addString(file_name);
|
||||
|
||||
|
|
@ -2102,10 +2016,9 @@ LLGLTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name,
|
|||
|
||||
// Reads a .tga file, decodes it, and puts the decoded data in image_raw.
|
||||
// Returns TRUE if successful.
|
||||
static LLTrace::BlockTimerStatHandle FTM_LOAD_IMAGE_RAW("loadImageRaw");
|
||||
BOOL LLTexLayerStaticImageList::loadImageRaw(const std::string& file_name, LLImageRaw* image_raw)
|
||||
{
|
||||
LL_RECORD_BLOCK_TIME(FTM_LOAD_IMAGE_RAW);
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
BOOL success = FALSE;
|
||||
std::string path;
|
||||
path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,file_name);
|
||||
|
|
|
|||
|
|
@ -279,10 +279,9 @@ BOOL LLTexLayerParamAlpha::getSkip() const
|
|||
}
|
||||
|
||||
|
||||
static LLTrace::BlockTimerStatHandle FTM_TEX_LAYER_PARAM_ALPHA("alpha render");
|
||||
BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height)
|
||||
{
|
||||
LL_RECORD_BLOCK_TIME(FTM_TEX_LAYER_PARAM_ALPHA);
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
BOOL success = TRUE;
|
||||
|
||||
if (!mTexLayer)
|
||||
|
|
|
|||
|
|
@ -63,23 +63,14 @@ protected:
|
|||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
LL_ALIGN_PREFIX(16)
|
||||
class LLTexLayerParamAlpha : public LLTexLayerParam
|
||||
class alignas(16) LLTexLayerParamAlpha : public LLTexLayerParam
|
||||
{
|
||||
LL_ALIGN_NEW
|
||||
public:
|
||||
LLTexLayerParamAlpha( LLTexLayerInterface* layer );
|
||||
LLTexLayerParamAlpha( LLAvatarAppearance* appearance );
|
||||
/*virtual*/ ~LLTexLayerParamAlpha();
|
||||
|
||||
void* operator new(size_t size)
|
||||
{
|
||||
return ll_aligned_malloc_16(size);
|
||||
}
|
||||
|
||||
void operator delete(void* ptr)
|
||||
{
|
||||
ll_aligned_free_16(ptr);
|
||||
}
|
||||
|
||||
/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable = NULL) const;
|
||||
|
||||
// LLVisualParam Virtual functions
|
||||
|
|
@ -157,9 +148,9 @@ private:
|
|||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
LL_ALIGN_PREFIX(16)
|
||||
class LLTexLayerParamColor : public LLTexLayerParam
|
||||
class alignas(16) LLTexLayerParamColor : public LLTexLayerParam
|
||||
{
|
||||
LL_ALIGN_NEW
|
||||
public:
|
||||
enum EColorOperation
|
||||
{
|
||||
|
|
@ -172,16 +163,6 @@ public:
|
|||
LLTexLayerParamColor( LLTexLayerInterface* layer );
|
||||
LLTexLayerParamColor( LLAvatarAppearance* appearance );
|
||||
|
||||
void* operator new(size_t size)
|
||||
{
|
||||
return ll_aligned_malloc_16(size);
|
||||
}
|
||||
|
||||
void operator delete(void* ptr)
|
||||
{
|
||||
ll_aligned_free_16(ptr);
|
||||
}
|
||||
|
||||
/* virtual */ ~LLTexLayerParamColor();
|
||||
|
||||
/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable = NULL) const;
|
||||
|
|
@ -216,8 +197,8 @@ protected:
|
|||
//virtual void onGlobalColorChanged() {}
|
||||
virtual void onGlobalColorChanged(bool upload_bake) {}
|
||||
private:
|
||||
LL_ALIGN_16(LLVector4a mAvgDistortionVec);
|
||||
} LL_ALIGN_POSTFIX(16);
|
||||
LLVector4a mAvgDistortionVec;
|
||||
};
|
||||
|
||||
class LLTexLayerParamColorInfo : public LLViewerVisualParamInfo
|
||||
{
|
||||
|
|
|
|||
|
|
@ -196,20 +196,15 @@ void LLCharacter::requestStopMotion( LLMotion* motion)
|
|||
//-----------------------------------------------------------------------------
|
||||
// updateMotions()
|
||||
//-----------------------------------------------------------------------------
|
||||
static LLTrace::BlockTimerStatHandle FTM_UPDATE_ANIMATION("Update Animation");
|
||||
static LLTrace::BlockTimerStatHandle FTM_UPDATE_HIDDEN_ANIMATION("Update Hidden Anim");
|
||||
static LLTrace::BlockTimerStatHandle FTM_UPDATE_MOTIONS("Update Motions");
|
||||
|
||||
void LLCharacter::updateMotions(e_update_t update_type)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
|
||||
if (update_type == HIDDEN_UPDATE)
|
||||
{
|
||||
LL_RECORD_BLOCK_TIME(FTM_UPDATE_HIDDEN_ANIMATION);
|
||||
mMotionController.updateMotionsMinimal();
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_RECORD_BLOCK_TIME(FTM_UPDATE_ANIMATION);
|
||||
// unpause if the number of outstanding pause requests has dropped to the initial one
|
||||
if (mMotionController.isPaused() && mPauseRequest->getNumRefs() == 1)
|
||||
{
|
||||
|
|
@ -217,7 +212,6 @@ void LLCharacter::updateMotions(e_update_t update_type)
|
|||
}
|
||||
bool force_update = (update_type == FORCE_UPDATE);
|
||||
{
|
||||
LL_RECORD_BLOCK_TIME(FTM_UPDATE_MOTIONS);
|
||||
mMotionController.updateMotions(force_update);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,6 +163,7 @@ BOOL LLEditingMotion::onActivate()
|
|||
//-----------------------------------------------------------------------------
|
||||
BOOL LLEditingMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
LLVector3 focus_pt;
|
||||
LLVector3* pointAtPt = (LLVector3*)mCharacter->getAnimationData("PointAtPoint");
|
||||
|
||||
|
|
|
|||
|
|
@ -42,9 +42,11 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// class LLEditingMotion
|
||||
//-----------------------------------------------------------------------------
|
||||
LL_ALIGN_PREFIX(16)
|
||||
class LLEditingMotion :
|
||||
public LLMotion
|
||||
{
|
||||
LL_ALIGN_NEW
|
||||
public:
|
||||
// Constructor
|
||||
LLEditingMotion(const LLUUID &id);
|
||||
|
|
@ -108,6 +110,13 @@ public:
|
|||
//-------------------------------------------------------------------------
|
||||
// joint states to be animated
|
||||
//-------------------------------------------------------------------------
|
||||
LL_ALIGN_16(LLJoint mParentJoint);
|
||||
LL_ALIGN_16(LLJoint mShoulderJoint);
|
||||
LL_ALIGN_16(LLJoint mElbowJoint);
|
||||
LL_ALIGN_16(LLJoint mWristJoint);
|
||||
LL_ALIGN_16(LLJoint mTarget);
|
||||
LLJointSolverRP3 mIKSolver;
|
||||
|
||||
LLCharacter *mCharacter;
|
||||
LLVector3 mWristOffset;
|
||||
|
||||
|
|
@ -117,17 +126,10 @@ public:
|
|||
LLPointer<LLJointState> mWristState;
|
||||
LLPointer<LLJointState> mTorsoState;
|
||||
|
||||
LLJoint mParentJoint;
|
||||
LLJoint mShoulderJoint;
|
||||
LLJoint mElbowJoint;
|
||||
LLJoint mWristJoint;
|
||||
LLJoint mTarget;
|
||||
LLJointSolverRP3 mIKSolver;
|
||||
|
||||
static S32 sHandPose;
|
||||
static S32 sHandPosePriority;
|
||||
LLVector3 mLastSelectPt;
|
||||
};
|
||||
} LL_ALIGN_POSTFIX(16);
|
||||
|
||||
#endif // LL_LLKEYFRAMEMOTION_H
|
||||
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@ BOOL LLHandMotion::onActivate()
|
|||
//-----------------------------------------------------------------------------
|
||||
BOOL LLHandMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
eHandPose *requestedHandPose;
|
||||
|
||||
F32 timeDelta = time - mLastTime;
|
||||
|
|
|
|||
|
|
@ -175,6 +175,7 @@ BOOL LLHeadRotMotion::onActivate()
|
|||
//-----------------------------------------------------------------------------
|
||||
BOOL LLHeadRotMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
|
||||
LLQuaternion targetHeadRotWorld;
|
||||
LLQuaternion currentRootRotWorld = mRootJoint->getWorldRotation();
|
||||
LLQuaternion currentInvRootRotWorld = ~currentRootRotWorld;
|
||||
|
|
@ -461,6 +462,7 @@ void LLEyeMotion::adjustEyeTarget(LLVector3* targetPos, LLJointState& left_eye_s
|
|||
//-----------------------------------------------------------------------------
|
||||
BOOL LLEyeMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
|
||||
//calculate jitter
|
||||
if (mEyeJitterTimer.getElapsedTimeF32() > mEyeJitterTime)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -944,6 +944,13 @@ const LLMatrix4 &LLJoint::getWorldMatrix()
|
|||
return mXform.getWorldMatrix();
|
||||
}
|
||||
|
||||
const LLMatrix4a& LLJoint::getWorldMatrix4a()
|
||||
{
|
||||
updateWorldMatrixParent();
|
||||
|
||||
return mWorldMatrix;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// setWorldMatrix()
|
||||
|
|
@ -1025,6 +1032,7 @@ void LLJoint::updateWorldMatrix()
|
|||
{
|
||||
sNumUpdates++;
|
||||
mXform.updateMatrix(FALSE);
|
||||
mWorldMatrix.loadu(mXform.getWorldMatrix());
|
||||
mDirtyFlags = 0x0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include "m4math.h"
|
||||
#include "llquaternion.h"
|
||||
#include "xform.h"
|
||||
#include "llmatrix4a.h"
|
||||
|
||||
//<FS:ND> Query by JointKey rather than just a string, the key can be a U32 index for faster lookup
|
||||
struct JointKey
|
||||
|
|
@ -111,8 +112,10 @@ inline bool operator!=(const LLVector3OverrideMap& a, const LLVector3OverrideMap
|
|||
//-----------------------------------------------------------------------------
|
||||
// class LLJoint
|
||||
//-----------------------------------------------------------------------------
|
||||
LL_ALIGN_PREFIX(16)
|
||||
class LLJoint
|
||||
{
|
||||
LL_ALIGN_NEW
|
||||
public:
|
||||
// priority levels, from highest to lowest
|
||||
enum JointPriority
|
||||
|
|
@ -140,16 +143,17 @@ public:
|
|||
SUPPORT_EXTENDED
|
||||
};
|
||||
protected:
|
||||
std::string mName;
|
||||
// explicit transformation members
|
||||
LL_ALIGN_16(LLMatrix4a mWorldMatrix);
|
||||
LLXformMatrix mXform;
|
||||
|
||||
std::string mName;
|
||||
|
||||
SupportCategory mSupport;
|
||||
|
||||
// parent joint
|
||||
LLJoint *mParent;
|
||||
|
||||
// explicit transformation members
|
||||
LLXformMatrix mXform;
|
||||
|
||||
LLVector3 mDefaultPosition;
|
||||
LLVector3 mDefaultScale;
|
||||
|
||||
|
|
@ -285,6 +289,8 @@ public:
|
|||
const LLMatrix4 &getWorldMatrix();
|
||||
void setWorldMatrix( const LLMatrix4& mat );
|
||||
|
||||
const LLMatrix4a& getWorldMatrix4a();
|
||||
|
||||
void updateWorldMatrixChildren();
|
||||
void updateWorldMatrixParent();
|
||||
|
||||
|
|
@ -322,6 +328,6 @@ public:
|
|||
// These are used in checks of whether a pos/scale override is considered significant.
|
||||
bool aboveJointPosThreshold(const LLVector3& pos) const;
|
||||
bool aboveJointScaleThreshold(const LLVector3& scale) const;
|
||||
};
|
||||
} LL_ALIGN_POSTFIX(16);
|
||||
#endif // LL_LLJOINT_H
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* @file lljointsolverrp3.cpp
|
||||
* @brief Implementation of LLJointSolverRP3 class.
|
||||
* @brief Implementation of Joint Solver in 3D Real Projective space (RP3). See: https://en.wikipedia.org/wiki/Real_projective_space
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
|
|
@ -35,6 +35,11 @@
|
|||
|
||||
#define F_EPSILON 0.00001f
|
||||
|
||||
#if LL_RELEASE
|
||||
#define DEBUG_JOINT_SOLVER 0
|
||||
#else
|
||||
#define DEBUG_JOINT_SOLVER 1
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constructor
|
||||
|
|
@ -150,6 +155,7 @@ void LLJointSolverRP3::solve()
|
|||
LLVector3 cPos = mJointC->getWorldPosition();
|
||||
LLVector3 gPos = mJointGoal->getWorldPosition();
|
||||
|
||||
#if DEBUG_JOINT_SOLVER
|
||||
LL_DEBUGS("JointSolver") << "LLJointSolverRP3::solve()" << LL_NEWLINE
|
||||
<< "bPosLocal = " << mJointB->getPosition() << LL_NEWLINE
|
||||
<< "cPosLocal = " << mJointC->getPosition() << LL_NEWLINE
|
||||
|
|
@ -159,6 +165,7 @@ void LLJointSolverRP3::solve()
|
|||
<< "bPos : " << bPos << LL_NEWLINE
|
||||
<< "cPos : " << cPos << LL_NEWLINE
|
||||
<< "gPos : " << gPos << LL_ENDL;
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// get the poleVector in world space
|
||||
|
|
@ -194,6 +201,7 @@ void LLJointSolverRP3::solve()
|
|||
//-------------------------------------------------------------------------
|
||||
LLVector3 abacCompOrthoVec = abVec - acVec * ((abVec * acVec)/(acVec * acVec));
|
||||
|
||||
#if DEBUG_JOINT_SOLVER
|
||||
LL_DEBUGS("JointSolver") << "abVec : " << abVec << LL_NEWLINE
|
||||
<< "bcVec : " << bcVec << LL_NEWLINE
|
||||
<< "acVec : " << acVec << LL_NEWLINE
|
||||
|
|
@ -202,6 +210,7 @@ void LLJointSolverRP3::solve()
|
|||
<< "bcLen : " << bcLen << LL_NEWLINE
|
||||
<< "agLen : " << agLen << LL_NEWLINE
|
||||
<< "abacCompOrthoVec : " << abacCompOrthoVec << LL_ENDL;
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// compute the normal of the original ABC plane (and store for later)
|
||||
|
|
@ -269,6 +278,7 @@ void LLJointSolverRP3::solve()
|
|||
|
||||
LLQuaternion bRot(theta - abbcAng, abbcOrthoVec);
|
||||
|
||||
#if DEBUG_JOINT_SOLVER
|
||||
LL_DEBUGS("JointSolver") << "abbcAng : " << abbcAng << LL_NEWLINE
|
||||
<< "abbcOrthoVec : " << abbcOrthoVec << LL_NEWLINE
|
||||
<< "agLenSq : " << agLenSq << LL_NEWLINE
|
||||
|
|
@ -280,6 +290,7 @@ void LLJointSolverRP3::solve()
|
|||
<< abbcAng*180.0f/F_PI << " "
|
||||
<< (theta - abbcAng)*180.0f/F_PI
|
||||
<< LL_ENDL;
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// compute rotation that rotates new A->C to A->G
|
||||
|
|
@ -293,9 +304,11 @@ void LLJointSolverRP3::solve()
|
|||
LLQuaternion cgRot;
|
||||
cgRot.shortestArc( acVec, agVec );
|
||||
|
||||
#if DEBUG_JOINT_SOLVER
|
||||
LL_DEBUGS("JointSolver") << "bcVec : " << bcVec << LL_NEWLINE
|
||||
<< "acVec : " << acVec << LL_NEWLINE
|
||||
<< "cgRot : " << cgRot << LL_ENDL;
|
||||
#endif
|
||||
|
||||
// update A->B and B->C with rotation from C to G
|
||||
abVec = abVec * cgRot;
|
||||
|
|
@ -358,11 +371,13 @@ void LLJointSolverRP3::solve()
|
|||
//-------------------------------------------------------------------------
|
||||
LLQuaternion twistRot( mTwist, agVec );
|
||||
|
||||
#if DEBUG_JOINT_SOLVER
|
||||
LL_DEBUGS("JointSolver") << "abcNorm = " << abcNorm << LL_NEWLINE
|
||||
<< "apgNorm = " << apgNorm << LL_NEWLINE
|
||||
<< "pRot = " << pRot << LL_NEWLINE
|
||||
<< "twist : " << mTwist*180.0/F_PI << LL_NEWLINE
|
||||
<< "twistRot : " << twistRot << LL_ENDL;
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// compute rotation of A
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@ BOOL LLKeyframeFallMotion::onActivate()
|
|||
//-----------------------------------------------------------------------------
|
||||
BOOL LLKeyframeFallMotion::onUpdate(F32 activeTime, U8* joint_mask)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
|
||||
BOOL result = LLKeyframeMotion::onUpdate(activeTime, joint_mask);
|
||||
F32 slerp_amt = clamp_rescale(activeTime / getDuration(), 0.5f, 0.75f, 0.f, 1.f);
|
||||
|
||||
|
|
|
|||
|
|
@ -680,6 +680,7 @@ BOOL LLKeyframeMotion::onActivate()
|
|||
//-----------------------------------------------------------------------------
|
||||
BOOL LLKeyframeMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
|
||||
// llassert(time >= 0.f); // This will fire
|
||||
time = llmax(0.f, time);
|
||||
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ BOOL LLKeyframeMotionParam::onActivate()
|
|||
//-----------------------------------------------------------------------------
|
||||
BOOL LLKeyframeMotionParam::onUpdate(F32 time, U8* joint_mask)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
F32 weightFactor = 1.f / (F32)mParameterizedMotions.size();
|
||||
|
||||
// zero out all pose weights
|
||||
|
|
|
|||
|
|
@ -37,9 +37,11 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// class LLKeyframeStandMotion
|
||||
//-----------------------------------------------------------------------------
|
||||
LL_ALIGN_PREFIX(16)
|
||||
class LLKeyframeStandMotion :
|
||||
public LLKeyframeMotion
|
||||
{
|
||||
LL_ALIGN_NEW
|
||||
public:
|
||||
// Constructor
|
||||
LLKeyframeStandMotion(const LLUUID &id);
|
||||
|
|
@ -69,6 +71,18 @@ public:
|
|||
//-------------------------------------------------------------------------
|
||||
// Member Data
|
||||
//-------------------------------------------------------------------------
|
||||
LLJoint mPelvisJoint;
|
||||
|
||||
LLJoint mHipLeftJoint;
|
||||
LLJoint mKneeLeftJoint;
|
||||
LLJoint mAnkleLeftJoint;
|
||||
LLJoint mTargetLeft;
|
||||
|
||||
LLJoint mHipRightJoint;
|
||||
LLJoint mKneeRightJoint;
|
||||
LLJoint mAnkleRightJoint;
|
||||
LLJoint mTargetRight;
|
||||
|
||||
LLCharacter *mCharacter;
|
||||
|
||||
BOOL mFlipFeet;
|
||||
|
|
@ -83,18 +97,6 @@ public:
|
|||
LLPointer<LLJointState> mKneeRightState;
|
||||
LLPointer<LLJointState> mAnkleRightState;
|
||||
|
||||
LLJoint mPelvisJoint;
|
||||
|
||||
LLJoint mHipLeftJoint;
|
||||
LLJoint mKneeLeftJoint;
|
||||
LLJoint mAnkleLeftJoint;
|
||||
LLJoint mTargetLeft;
|
||||
|
||||
LLJoint mHipRightJoint;
|
||||
LLJoint mKneeRightJoint;
|
||||
LLJoint mAnkleRightJoint;
|
||||
LLJoint mTargetRight;
|
||||
|
||||
LLJointSolverRP3 mIKLeft;
|
||||
LLJointSolverRP3 mIKRight;
|
||||
|
||||
|
|
@ -110,7 +112,7 @@ public:
|
|||
BOOL mTrackAnkles;
|
||||
|
||||
S32 mFrameNum;
|
||||
};
|
||||
} LL_ALIGN_POSTFIX(16);
|
||||
|
||||
#endif // LL_LLKEYFRAMESTANDMOTION_H
|
||||
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ void LLKeyframeWalkMotion::onDeactivate()
|
|||
//-----------------------------------------------------------------------------
|
||||
BOOL LLKeyframeWalkMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
// compute time since last update
|
||||
F32 deltaTime = time - mRealTimeLast;
|
||||
|
||||
|
|
@ -198,6 +199,7 @@ BOOL LLWalkAdjustMotion::onActivate()
|
|||
//-----------------------------------------------------------------------------
|
||||
BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
// delta_time is guaranteed to be non zero
|
||||
F32 delta_time = llclamp(time - mLastTime, TIME_EPSILON, MAX_TIME_DELTA);
|
||||
mLastTime = time;
|
||||
|
|
@ -376,6 +378,7 @@ BOOL LLFlyAdjustMotion::onActivate()
|
|||
//-----------------------------------------------------------------------------
|
||||
BOOL LLFlyAdjustMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
LLVector3 ang_vel = mCharacter->getCharacterAngularVelocity() * mCharacter->getTimeDilation();
|
||||
F32 speed = mCharacter->getCharacterVelocity().magVec();
|
||||
|
||||
|
|
|
|||
|
|
@ -513,6 +513,7 @@ void LLMotionController::resetJointSignatures()
|
|||
//-----------------------------------------------------------------------------
|
||||
void LLMotionController::updateIdleMotion(LLMotion* motionp)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
|
||||
if (motionp->isStopped() && mAnimTime > motionp->getStopTime() + motionp->getEaseOutDuration())
|
||||
{
|
||||
deactivateMotionInstance(motionp);
|
||||
|
|
@ -551,6 +552,7 @@ void LLMotionController::updateIdleMotion(LLMotion* motionp)
|
|||
//-----------------------------------------------------------------------------
|
||||
void LLMotionController::updateIdleActiveMotions()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
|
||||
for (motion_list_t::iterator iter = mActiveMotions.begin();
|
||||
iter != mActiveMotions.end(); )
|
||||
{
|
||||
|
|
@ -563,10 +565,9 @@ void LLMotionController::updateIdleActiveMotions()
|
|||
//-----------------------------------------------------------------------------
|
||||
// updateMotionsByType()
|
||||
//-----------------------------------------------------------------------------
|
||||
static LLTrace::BlockTimerStatHandle FTM_MOTION_ON_UPDATE("Motion onUpdate");
|
||||
|
||||
void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_type)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
|
||||
BOOL update_result = TRUE;
|
||||
U8 last_joint_signature[LL_CHARACTER_MAX_ANIMATED_JOINTS];
|
||||
|
||||
|
|
@ -722,7 +723,6 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
|
|||
|
||||
// perform motion update
|
||||
{
|
||||
LL_RECORD_BLOCK_TIME(FTM_MOTION_ON_UPDATE);
|
||||
update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature);
|
||||
}
|
||||
}
|
||||
|
|
@ -778,6 +778,7 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
|
|||
//-----------------------------------------------------------------------------
|
||||
void LLMotionController::updateLoadingMotions()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
|
||||
// query pending motions for completion
|
||||
for (motion_set_t::iterator iter = mLoadingMotions.begin();
|
||||
iter != mLoadingMotions.end(); )
|
||||
|
|
@ -825,6 +826,7 @@ void LLMotionController::updateLoadingMotions()
|
|||
//-----------------------------------------------------------------------------
|
||||
void LLMotionController::updateMotions(bool force_update)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
|
||||
// SL-763: "Distant animated objects run at super fast speed"
|
||||
// The use_quantum optimization or possibly the associated code in setTimeStamp()
|
||||
// does not work as implemented.
|
||||
|
|
@ -920,6 +922,7 @@ void LLMotionController::updateMotions(bool force_update)
|
|||
//-----------------------------------------------------------------------------
|
||||
void LLMotionController::updateMotionsMinimal()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
|
||||
// Always update mPrevTimerElapsed
|
||||
mPrevTimerElapsed = mTimer.getElapsedTimeF32();
|
||||
|
||||
|
|
@ -937,6 +940,7 @@ void LLMotionController::updateMotionsMinimal()
|
|||
//-----------------------------------------------------------------------------
|
||||
BOOL LLMotionController::activateMotionInstance(LLMotion *motion, F32 time)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
|
||||
// It's not clear why the getWeight() line seems to be crashing this, but
|
||||
// hopefully this fixes it.
|
||||
if (motion == NULL || motion->getPose() == NULL)
|
||||
|
|
|
|||
|
|
@ -80,8 +80,10 @@ public:
|
|||
|
||||
const S32 JSB_NUM_JOINT_STATES = 6;
|
||||
|
||||
LL_ALIGN_PREFIX(16)
|
||||
class LLJointStateBlender
|
||||
{
|
||||
LL_ALIGN_NEW
|
||||
protected:
|
||||
LLPointer<LLJointState> mJointStates[JSB_NUM_JOINT_STATES];
|
||||
S32 mPriorities[JSB_NUM_JOINT_STATES];
|
||||
|
|
@ -96,8 +98,8 @@ public:
|
|||
void resetCachedJoint();
|
||||
|
||||
public:
|
||||
LLJoint mJointCache;
|
||||
};
|
||||
LL_ALIGN_16(LLJoint mJointCache);
|
||||
} LL_ALIGN_POSTFIX(16);
|
||||
|
||||
class LLMotion;
|
||||
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ BOOL LLTargetingMotion::onActivate()
|
|||
//-----------------------------------------------------------------------------
|
||||
BOOL LLTargetingMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
F32 slerp_amt = LLSmoothInterpolation::getInterpolant(TORSO_TARGET_HALF_LIFE);
|
||||
|
||||
LLVector3 target;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ include(JsonCpp)
|
|||
include(Copy3rdPartyLibs)
|
||||
include(ZLIBNG)
|
||||
include(URIPARSER)
|
||||
include(Tracy)
|
||||
|
||||
include_directories( SYSTEM
|
||||
${EXPAT_INCLUDE_DIRS}
|
||||
|
|
@ -19,6 +20,7 @@ include_directories( SYSTEM
|
|||
${JSONCPP_INCLUDE_DIR}
|
||||
${ZLIBNG_INCLUDE_DIRS}
|
||||
${URIPARSER_INCLUDE_DIRS}
|
||||
${TRACY_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
# add_executable(lltreeiterators lltreeiterators.cpp)
|
||||
|
|
@ -117,14 +119,16 @@ set(llcommon_SOURCE_FILES
|
|||
lluriparser.cpp
|
||||
lluuid.cpp
|
||||
llworkerthread.cpp
|
||||
timing.cpp
|
||||
u64.cpp
|
||||
threadpool.cpp
|
||||
workqueue.cpp
|
||||
StackWalker.cpp
|
||||
)
|
||||
|
||||
set(llcommon_HEADER_FILES
|
||||
CMakeLists.txt
|
||||
|
||||
chrono.h
|
||||
classic_callback.h
|
||||
ctype_workaround.h
|
||||
fix_macros.h
|
||||
|
|
@ -198,6 +202,8 @@ set(llcommon_HEADER_FILES
|
|||
llmortician.h
|
||||
llnametable.h
|
||||
llpointer.h
|
||||
llprofiler.h
|
||||
llprofilercategories.h
|
||||
llpounceable.h
|
||||
llpredicate.h
|
||||
llpreprocessor.h
|
||||
|
|
@ -252,19 +258,20 @@ set(llcommon_HEADER_FILES
|
|||
lockstatic.h
|
||||
stdtypes.h
|
||||
stringize.h
|
||||
threadpool.h
|
||||
threadsafeschedule.h
|
||||
timer.h
|
||||
tuple.h
|
||||
u64.h
|
||||
workqueue.h
|
||||
StackWalker.h
|
||||
)
|
||||
|
||||
# <FS:Beq> Tracy Profiler support
|
||||
list(APPEND llcommon_SOURCE_FILES fstelemetry.cpp)
|
||||
if (USE_TRACY_PROFILER)
|
||||
list(APPEND llcommon_SOURCE_FILES fstracyclient.cpp)
|
||||
endif()
|
||||
# </FS:Beq> Tracy Profiler support
|
||||
|
||||
# <FS:ND> Add all nd* files. memory pool, intrinsics, ...
|
||||
# <FS:Beq/> Tracy Profiler support
|
||||
list(APPEND llcommon_SOURCE_FILES llprofiler.cpp)
|
||||
|
||||
# <FS:ND> Add all nd* files. memory pool, intrinsics, ...
|
||||
|
||||
SET( llcommon_ND_SOURCE_FILES
|
||||
nd/ndexceptions.cpp
|
||||
nd/ndlogthrottle.cpp
|
||||
|
|
@ -342,6 +349,7 @@ target_link_libraries(
|
|||
${BOOST_SYSTEM_LIBRARY}
|
||||
${GOOGLE_PERFTOOLS_LIBRARIES}
|
||||
${URIPARSER_LIBRARIES}
|
||||
${TRACY_LIBRARY}
|
||||
)
|
||||
|
||||
if (DARWIN)
|
||||
|
|
@ -399,6 +407,9 @@ if (LL_TESTS)
|
|||
LL_ADD_INTEGRATION_TEST(llunits "" "${test_libs}")
|
||||
LL_ADD_INTEGRATION_TEST(lluri "" "${test_libs}")
|
||||
LL_ADD_INTEGRATION_TEST(stringize "" "${test_libs}")
|
||||
LL_ADD_INTEGRATION_TEST(threadsafeschedule "" "${test_libs}")
|
||||
LL_ADD_INTEGRATION_TEST(tuple "" "${test_libs}")
|
||||
LL_ADD_INTEGRATION_TEST(workqueue "" "${test_libs}")
|
||||
|
||||
## llexception_test.cpp isn't a regression test, and doesn't need to be run
|
||||
## every build. It's to help a developer make implementation choices about
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
* @file chrono.h
|
||||
* @author Nat Goodspeed
|
||||
* @date 2021-10-05
|
||||
* @brief supplement <chrono> with utility functions
|
||||
*
|
||||
* $LicenseInfo:firstyear=2021&license=viewerlgpl$
|
||||
* Copyright (c) 2021, Linden Research, Inc.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#if ! defined(LL_CHRONO_H)
|
||||
#define LL_CHRONO_H
|
||||
|
||||
#include <chrono>
|
||||
#include <type_traits> // std::enable_if
|
||||
|
||||
namespace LL
|
||||
{
|
||||
|
||||
// time_point_cast() is derived from https://stackoverflow.com/a/35293183
|
||||
// without the iteration: we think errors in the ~1 microsecond range are
|
||||
// probably acceptable.
|
||||
|
||||
// This variant is for the optimal case when the source and dest use the same
|
||||
// clock: that case is handled by std::chrono.
|
||||
template <typename DestTimePoint, typename SrcTimePoint,
|
||||
typename std::enable_if<std::is_same<typename DestTimePoint::clock,
|
||||
typename SrcTimePoint::clock>::value,
|
||||
bool>::type = true>
|
||||
DestTimePoint time_point_cast(const SrcTimePoint& time)
|
||||
{
|
||||
return std::chrono::time_point_cast<typename DestTimePoint::duration>(time);
|
||||
}
|
||||
|
||||
// This variant is for when the source and dest use different clocks -- see
|
||||
// the linked StackOverflow answer, also Howard Hinnant's, for more context.
|
||||
template <typename DestTimePoint, typename SrcTimePoint,
|
||||
typename std::enable_if<! std::is_same<typename DestTimePoint::clock,
|
||||
typename SrcTimePoint::clock>::value,
|
||||
bool>::type = true>
|
||||
DestTimePoint time_point_cast(const SrcTimePoint& time)
|
||||
{
|
||||
// The basic idea is that we must adjust the passed time_point by the
|
||||
// difference between the clocks' epochs. But since time_point doesn't
|
||||
// expose its epoch, we fall back on what each of them thinks is now().
|
||||
// However, since we necessarily make sequential calls to those now()
|
||||
// functions, the answers differ not only by the cycles spent executing
|
||||
// those calls, but by potential OS interruptions between them. Try to
|
||||
// reduce that error by capturing the source clock time both before and
|
||||
// after the dest clock, and splitting the difference. Of course an
|
||||
// interruption between two of these now() calls without a comparable
|
||||
// interruption between the other two will skew the result, but better is
|
||||
// more expensive.
|
||||
const auto src_before = typename SrcTimePoint::clock::now();
|
||||
const auto dest_now = typename DestTimePoint::clock::now();
|
||||
const auto src_after = typename SrcTimePoint::clock::now();
|
||||
const auto src_diff = src_after - src_before;
|
||||
const auto src_now = src_before + src_diff / 2;
|
||||
return dest_now + (time - src_now);
|
||||
}
|
||||
|
||||
} // namespace LL
|
||||
|
||||
#endif /* ! defined(LL_CHRONO_H) */
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
#pragma once
|
||||
#ifndef FS_TELEMETRY_H_INCLUDED
|
||||
#define FS_TELEMETRY_H_INCLUDED
|
||||
/**
|
||||
* @file fstelemetry.h
|
||||
* @brief fstelemetry Telemetry abstraction for FS
|
||||
*
|
||||
* $LicenseInfo:firstyear=2021&license=fsviewerlgpl$
|
||||
* Phoenix Firestorm Viewer Source Code
|
||||
* Copyright (C) 2021, The Phoenix Firestorm Project, Inc.
|
||||
*
|
||||
* This 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;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This 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 this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA
|
||||
* http://www.firestormviewer.org
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
// define a simple set of empty macros that allow us to build without the Tracy profiler installed in 3p
|
||||
// this is similar to the profiler abstraction used by LL but as they have no plans to release that any time soon we'll replace it
|
||||
// Just a minimal set at the moment will add locks/gpu/memory and other stuff later.
|
||||
|
||||
// generic switch (in case we ever add others or incorporate commercial tools like RAD Games if LL were to share a license)
|
||||
// turn off in the else statement below.
|
||||
#define FS_HAS_TELEMETRY_SUPPORT
|
||||
|
||||
#ifdef TRACY_ENABLE // (Tracy open source telemetry)
|
||||
#include "Tracy.hpp"
|
||||
|
||||
#define FSZone ZoneNamed( ___tracy_scoped_zone, FSTelemetry::active)
|
||||
#define FSZoneN( name ) ZoneNamedN( ___tracy_scoped_zone, name, FSTelemetry::active)
|
||||
#define FSZoneC( color ) ZoneNamedC( ___tracy_scoped_zone, color, FSTelemetry::active)
|
||||
#define FSZoneNC( name, color ) ZoneNamedNC( ___tracy_scoped_zone, name, color, FSTelemetry::active)
|
||||
#define FSZoneText( text, size ) ZoneText( text, size )
|
||||
#define FSZoneValue( num_uint64 ) ZoneValue( num_uint64 )
|
||||
#define FSPlot( name, value ) TracyPlot( name, value)
|
||||
#define FSPlotSq( name, lastval, newval ) TracyPlot( name, lastval);TracyPlot( name, newval);
|
||||
#define FSFrameMark FrameMark
|
||||
#define FSFrameMarkStart( name ) FrameMarkStart( name )
|
||||
#define FSFrameMarkEnd( name ) FrameMarkEnd( name )
|
||||
#define FSThreadName( name ) tracy::SetThreadName( name )
|
||||
#define FSMessageL ( message ) tracy::Profiler::Message( message, 0 )
|
||||
#define FSTelemetryIsConnected TracyIsConnected
|
||||
|
||||
#else // (no telemetry)
|
||||
|
||||
// No we don't want no stinkin' telemetry. move along
|
||||
#undef FS_HAS_TELEMETRY_SUPPORT
|
||||
|
||||
#define FSZone
|
||||
#define FSZoneN( name )
|
||||
#define FSZoneC( color )
|
||||
#define FSZoneNC( name, color )
|
||||
#define FSZoneText( text, size )
|
||||
#define FSZoneValue( num_uint64 )
|
||||
#define FSPlot( name, value )
|
||||
#define FSPlotSq( name, lastval, newval )
|
||||
#define FSFrameMark
|
||||
#define FSFrameMarkStart( name )
|
||||
#define FSFrameMarkEnd( name )
|
||||
#define FSThreadName( name )
|
||||
#define FSMessageL( message )
|
||||
#define FSTelemetryIsConnected
|
||||
#endif // TRACY_ENABLE
|
||||
|
||||
#include <chrono>
|
||||
#include <array>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace FSTelemetry
|
||||
{
|
||||
extern bool active;
|
||||
|
||||
}// namespace FSTelemetry
|
||||
|
||||
#endif
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
//
|
||||
// Tracy profiler
|
||||
// ----------------
|
||||
//
|
||||
// For fast integration, compile and
|
||||
// link with this source file (and none
|
||||
// other) in your executable (or in the
|
||||
// main DLL / shared object on multi-DLL
|
||||
// projects).
|
||||
//
|
||||
|
||||
// Define TRACY_ENABLE to enable profiler.
|
||||
#include "common/TracySystem.cpp"
|
||||
|
||||
#ifdef TRACY_ENABLE
|
||||
|
||||
#ifdef LL_WINDOWS
|
||||
# pragma warning(push, 0)
|
||||
#endif
|
||||
|
||||
#include "common/tracy_lz4.cpp"
|
||||
#include "client/TracyProfiler.cpp"
|
||||
#include "client/TracyCallstack.cpp"
|
||||
#include "client/TracySysTime.cpp"
|
||||
|
||||
#include "client/TracySysTrace.cpp"
|
||||
|
||||
#include "common/TracySocket.cpp"
|
||||
#include "client/tracy_rpmalloc.cpp"
|
||||
#include "client/TracyDxt1.cpp"
|
||||
|
||||
#if TRACY_HAS_CALLSTACK == 2 || TRACY_HAS_CALLSTACK == 3 || TRACY_HAS_CALLSTACK == 4 || TRACY_HAS_CALLSTACK == 6
|
||||
# include "libbacktrace/alloc.cpp"
|
||||
# include "libbacktrace/dwarf.cpp"
|
||||
# include "libbacktrace/fileline.cpp"
|
||||
# include "libbacktrace/mmapio.cpp"
|
||||
# include "libbacktrace/posix.cpp"
|
||||
# include "libbacktrace/sort.cpp"
|
||||
# include "libbacktrace/state.cpp"
|
||||
# if TRACY_HAS_CALLSTACK == 4
|
||||
# include "libbacktrace/macho.cpp"
|
||||
# else
|
||||
# include "libbacktrace/elf.cpp"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef LL_WINDOWS
|
||||
# pragma comment(lib, "ws2_32.lib")
|
||||
# pragma comment(lib, "dbghelp.lib")
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -27,6 +27,14 @@
|
|||
#ifndef LL_LINDEN_COMMON_H
|
||||
#define LL_LINDEN_COMMON_H
|
||||
|
||||
#include "llprofiler.h"
|
||||
#if TRACY_ENABLE // hooks for memory profiling
|
||||
void *tracy_aligned_malloc(size_t size, size_t alignment);
|
||||
void tracy_aligned_free(void *memblock);
|
||||
#define _aligned_malloc(X, Y) tracy_aligned_malloc((X), (Y))
|
||||
#define _aligned_free(X) tracy_aligned_free((X))
|
||||
#endif
|
||||
|
||||
// *NOTE: Please keep includes here to a minimum!
|
||||
//
|
||||
// Files included here are included in every library .cpp file and
|
||||
|
|
|
|||
|
|
@ -33,6 +33,67 @@
|
|||
#include "lltracethreadrecorder.h"
|
||||
#include "llcleanup.h"
|
||||
|
||||
thread_local bool gProfilerEnabled = false;
|
||||
|
||||
// <FS:Beq/> #if (TRACY_ENABLE)
|
||||
#if (TRACY_ENABLE) && LL_PROFILER_ENABLE_TRACY_MEMORY
|
||||
// Override new/delete for tracy memory profiling
|
||||
void *operator new(size_t size)
|
||||
{
|
||||
void* ptr;
|
||||
if (gProfilerEnabled)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
|
||||
ptr = (malloc)(size);
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr = (malloc)(size);
|
||||
}
|
||||
if (!ptr)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
TracyAlloc(ptr, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void operator delete(void *ptr) noexcept
|
||||
{
|
||||
TracyFree(ptr);
|
||||
if (gProfilerEnabled)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
|
||||
(free)(ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
(free)(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// C-style malloc/free can't be so easily overridden, so we define tracy versions and use
|
||||
// a pre-processor #define in linden_common.h to redirect to them. The parens around the native
|
||||
// functions below prevents recursive substitution by the preprocessor.
|
||||
//
|
||||
// Unaligned mallocs are rare in LL code but hooking them causes problems in 3p lib code (looking at
|
||||
// you, Havok), so we'll only capture the aligned version.
|
||||
|
||||
void *tracy_aligned_malloc(size_t size, size_t alignment)
|
||||
{
|
||||
auto ptr = ll_aligned_malloc_fallback(size, alignment);
|
||||
if (ptr) TracyAlloc(ptr, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void tracy_aligned_free(void *memblock)
|
||||
{
|
||||
TracyFree(memblock);
|
||||
ll_aligned_free_fallback(memblock);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//static
|
||||
BOOL LLCommon::sAprInitialized = FALSE;
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,8 @@ private:
|
|||
LLCoros::Mutex mMutex;
|
||||
// Use LLCoros::ConditionVariable for the same reason.
|
||||
LLCoros::ConditionVariable mCond;
|
||||
using LockType = LLCoros::LockType;
|
||||
using cv_status = LLCoros::cv_status;
|
||||
|
||||
public:
|
||||
/// LLCond can be explicitly initialized with a specific value for mData if
|
||||
|
|
@ -65,10 +67,29 @@ public:
|
|||
LLCond(const LLCond&) = delete;
|
||||
LLCond& operator=(const LLCond&) = delete;
|
||||
|
||||
/// get() returns a const reference to the stored DATA. The only way to
|
||||
/// get a non-const reference -- to modify the stored DATA -- is via
|
||||
/// update_one() or update_all().
|
||||
const value_type& get() const { return mData; }
|
||||
/**
|
||||
* get() returns the stored DATA by value -- so to use get(), DATA must
|
||||
* be copyable. The only way to get a non-const reference -- to modify
|
||||
* the stored DATA -- is via update_one() or update_all().
|
||||
*/
|
||||
value_type get()
|
||||
{
|
||||
LockType lk(mMutex);
|
||||
return mData;
|
||||
}
|
||||
|
||||
/**
|
||||
* get(functor) returns whatever the functor returns. It allows us to peek
|
||||
* at the stored DATA without copying the whole thing. The functor must
|
||||
* accept a const reference to DATA. If you want to modify DATA, call
|
||||
* update_one() or update_all() instead.
|
||||
*/
|
||||
template <typename FUNC>
|
||||
auto get(FUNC&& func)
|
||||
{
|
||||
LockType lk(mMutex);
|
||||
return std::forward<FUNC>(func)(const_data());
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass update_one() an invocable accepting non-const (DATA&). The
|
||||
|
|
@ -80,11 +101,11 @@ public:
|
|||
* update_one() when DATA is a struct or class.
|
||||
*/
|
||||
template <typename MODIFY>
|
||||
void update_one(MODIFY modify)
|
||||
void update_one(MODIFY&& modify)
|
||||
{
|
||||
{ // scope of lock can/should end before notify_one()
|
||||
LLCoros::LockType lk(mMutex);
|
||||
modify(mData);
|
||||
LockType lk(mMutex);
|
||||
std::forward<MODIFY>(modify)(mData);
|
||||
}
|
||||
mCond.notify_one();
|
||||
}
|
||||
|
|
@ -99,11 +120,11 @@ public:
|
|||
* update_all() when DATA is a struct or class.
|
||||
*/
|
||||
template <typename MODIFY>
|
||||
void update_all(MODIFY modify)
|
||||
void update_all(MODIFY&& modify)
|
||||
{
|
||||
{ // scope of lock can/should end before notify_all()
|
||||
LLCoros::LockType lk(mMutex);
|
||||
modify(mData);
|
||||
LockType lk(mMutex);
|
||||
std::forward<MODIFY>(modify)(mData);
|
||||
}
|
||||
mCond.notify_all();
|
||||
}
|
||||
|
|
@ -116,9 +137,9 @@ public:
|
|||
* wait() on the condition_variable.
|
||||
*/
|
||||
template <typename Pred>
|
||||
void wait(Pred pred)
|
||||
void wait(Pred&& pred)
|
||||
{
|
||||
LLCoros::LockType lk(mMutex);
|
||||
LockType lk(mMutex);
|
||||
// We must iterate explicitly since the predicate accepted by
|
||||
// condition_variable::wait() requires a different signature:
|
||||
// condition_variable::wait() calls its predicate with no arguments.
|
||||
|
|
@ -127,7 +148,7 @@ public:
|
|||
// But what if they instead pass a predicate accepting non-const
|
||||
// (DATA&)? Such a predicate could modify mData, which would be Bad.
|
||||
// Forbid that.
|
||||
while (! pred(const_cast<const value_type&>(mData)))
|
||||
while (! std::forward<Pred>(pred)(const_data()))
|
||||
{
|
||||
mCond.wait(lk);
|
||||
}
|
||||
|
|
@ -144,7 +165,7 @@ public:
|
|||
* returning true.
|
||||
*/
|
||||
template <typename Rep, typename Period, typename Pred>
|
||||
bool wait_for(const std::chrono::duration<Rep, Period>& timeout_duration, Pred pred)
|
||||
bool wait_for(const std::chrono::duration<Rep, Period>& timeout_duration, Pred&& pred)
|
||||
{
|
||||
// Instead of replicating wait_until() logic, convert duration to
|
||||
// time_point and just call wait_until().
|
||||
|
|
@ -153,7 +174,8 @@ public:
|
|||
// wrong! We'd keep pushing the timeout time farther and farther into
|
||||
// the future. This way, we establish a definite timeout time and
|
||||
// stick to it.
|
||||
return wait_until(std::chrono::steady_clock::now() + timeout_duration, pred);
|
||||
return wait_until(std::chrono::steady_clock::now() + timeout_duration,
|
||||
std::forward<Pred>(pred));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -163,9 +185,9 @@ public:
|
|||
* generic wait_for() method.
|
||||
*/
|
||||
template <typename Pred>
|
||||
bool wait_for(F32Milliseconds timeout_duration, Pred pred)
|
||||
bool wait_for(F32Milliseconds timeout_duration, Pred&& pred)
|
||||
{
|
||||
return wait_for(convert(timeout_duration), pred);
|
||||
return wait_for(convert(timeout_duration), std::forward<Pred>(pred));
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
@ -183,6 +205,10 @@ protected:
|
|||
}
|
||||
|
||||
private:
|
||||
// It's important to pass a const ref to certain user-specified functors
|
||||
// that aren't supposed to be able to modify mData.
|
||||
const value_type& const_data() const { return mData; }
|
||||
|
||||
/**
|
||||
* Pass wait_until() a chrono::time_point, indicating the time at which we
|
||||
* should stop waiting, and a predicate accepting (const DATA&), returning
|
||||
|
|
@ -203,21 +229,21 @@ private:
|
|||
* honoring a fixed timeout.
|
||||
*/
|
||||
template <typename Clock, typename Duration, typename Pred>
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, Pred pred)
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, Pred&& pred)
|
||||
{
|
||||
LLCoros::LockType lk(mMutex);
|
||||
LockType lk(mMutex);
|
||||
// We advise the caller to pass a predicate accepting (const DATA&).
|
||||
// But what if they instead pass a predicate accepting non-const
|
||||
// (DATA&)? Such a predicate could modify mData, which would be Bad.
|
||||
// Forbid that.
|
||||
while (! pred(const_cast<const value_type&>(mData)))
|
||||
while (! std::forward<Pred>(pred)(const_data()))
|
||||
{
|
||||
if (LLCoros::cv_status::timeout == mCond.wait_until(lk, timeout_time))
|
||||
if (cv_status::timeout == mCond.wait_until(lk, timeout_time))
|
||||
{
|
||||
// It's possible that wait_until() timed out AND the predicate
|
||||
// became true more or less simultaneously. Even though
|
||||
// wait_until() timed out, check the predicate one more time.
|
||||
return pred(const_cast<const value_type&>(mData));
|
||||
return std::forward<Pred>(pred)(const_data());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -86,11 +86,9 @@ std::string LLDate::asRFC1123() const
|
|||
return toHTTPDateString (std::string ("%A, %d %b %Y %H:%M:%S GMT"));
|
||||
}
|
||||
|
||||
LLTrace::BlockTimerStatHandle FT_DATE_FORMAT("Date Format");
|
||||
|
||||
std::string LLDate::toHTTPDateString (std::string fmt) const
|
||||
{
|
||||
LL_RECORD_BLOCK_TIME(FT_DATE_FORMAT);
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
|
||||
time_t locSeconds = (time_t) mSecondsSinceEpoch;
|
||||
struct tm * gmt = gmtime (&locSeconds);
|
||||
|
|
@ -99,7 +97,7 @@ std::string LLDate::toHTTPDateString (std::string fmt) const
|
|||
|
||||
std::string LLDate::toHTTPDateString (tm * gmt, std::string fmt)
|
||||
{
|
||||
LL_RECORD_BLOCK_TIME(FT_DATE_FORMAT);
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
|
||||
// avoid calling setlocale() unnecessarily - it's expensive.
|
||||
static std::string prev_locale = "";
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ namespace {
|
|||
virtual void recordMessage(LLError::ELevel level,
|
||||
const std::string& message) override
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
|
||||
int syslogPriority = LOG_CRIT;
|
||||
switch (level) {
|
||||
case LLError::LEVEL_DEBUG: syslogPriority = LOG_DEBUG; break;
|
||||
|
|
@ -168,6 +169,7 @@ namespace {
|
|||
virtual void recordMessage(LLError::ELevel level,
|
||||
const std::string& message) override
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
|
||||
if (LLError::getAlwaysFlush())
|
||||
{
|
||||
mFile << message << std::endl;
|
||||
|
|
@ -196,7 +198,7 @@ namespace {
|
|||
{
|
||||
return LLError::getEnabledLogTypesMask() & 0x04;
|
||||
}
|
||||
|
||||
|
||||
LL_FORCE_INLINE std::string createBoldANSI()
|
||||
{
|
||||
std::string ansi_code;
|
||||
|
|
@ -222,10 +224,10 @@ namespace {
|
|||
LL_FORCE_INLINE std::string createANSI(const std::string& color)
|
||||
{
|
||||
std::string ansi_code;
|
||||
ansi_code += '\033';
|
||||
ansi_code += "[";
|
||||
ansi_code += '\033';
|
||||
ansi_code += "[";
|
||||
ansi_code += "38;5;";
|
||||
ansi_code += color;
|
||||
ansi_code += color;
|
||||
ansi_code += "m";
|
||||
|
||||
return ansi_code;
|
||||
|
|
@ -234,6 +236,7 @@ namespace {
|
|||
virtual void recordMessage(LLError::ELevel level,
|
||||
const std::string& message) override
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
|
||||
// The default colors for error, warn and debug are now a bit more pastel
|
||||
// and easier to read on the default (black) terminal background but you
|
||||
// now have the option to set the color of each via an environment variables:
|
||||
|
|
@ -263,6 +266,7 @@ namespace {
|
|||
}
|
||||
else
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED("fprintf");
|
||||
fprintf(stderr, "%s\n", message.c_str());
|
||||
}
|
||||
#if LL_WINDOWS
|
||||
|
|
@ -275,6 +279,7 @@ namespace {
|
|||
|
||||
LL_FORCE_INLINE void writeANSI(const std::string& ansi_code, const std::string& message)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
|
||||
static std::string s_ansi_bold = createBoldANSI(); // bold text
|
||||
static std::string s_ansi_reset = createResetANSI(); // reset
|
||||
// ANSI color code escape sequence, message, and reset in one fprintf call
|
||||
|
|
@ -311,6 +316,7 @@ namespace {
|
|||
virtual void recordMessage(LLError::ELevel level,
|
||||
const std::string& message) override
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
|
||||
mBuffer->addLine(message);
|
||||
}
|
||||
|
||||
|
|
@ -337,6 +343,7 @@ namespace {
|
|||
virtual void recordMessage(LLError::ELevel level,
|
||||
const std::string& message) override
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
|
||||
debugger_print(message);
|
||||
}
|
||||
};
|
||||
|
|
@ -1221,6 +1228,7 @@ namespace
|
|||
|
||||
void writeToRecorders(const LLError::CallSite& site, const std::string& message)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
|
||||
LLError::ELevel level = site.mLevel;
|
||||
SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig();
|
||||
|
||||
|
|
@ -1362,6 +1370,7 @@ namespace LLError
|
|||
|
||||
bool Log::shouldLog(CallSite& site)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
|
||||
LLMutexTrylock lock(getMutex<LOG_MUTEX>(), 5);
|
||||
if (!lock.isLocked())
|
||||
{
|
||||
|
|
@ -1406,6 +1415,7 @@ namespace LLError
|
|||
|
||||
void Log::flush(const std::ostringstream& out, const CallSite& site)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
|
||||
LLMutexTrylock lock(getMutex<LOG_MUTEX>(),5);
|
||||
if (!lock.isLocked())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -35,7 +35,9 @@
|
|||
|
||||
#include "stdtypes.h"
|
||||
|
||||
#include "llprofiler.h"
|
||||
#include "llpreprocessor.h"
|
||||
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
// <FS:ND> Supress some false positives of PVS Studio.
|
||||
|
|
@ -354,7 +356,8 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
|
|||
// if (condition) LL_INFOS() << "True" << LL_ENDL; else LL_INFOS()() << "False" << LL_ENDL;
|
||||
|
||||
#define lllog(level, once, ...) \
|
||||
do { \
|
||||
do { \
|
||||
LL_PROFILE_ZONE_NAMED("lllog"); \
|
||||
const char* tags[] = {"", ##__VA_ARGS__}; \
|
||||
static LLError::CallSite _site(lllog_site_args_(level, once, tags)); \
|
||||
lllog_test_()
|
||||
|
|
|
|||
|
|
@ -190,6 +190,7 @@ namespace LLError
|
|||
{}
|
||||
void recordMessage(LLError::ELevel level, const std::string& message) override
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
mCallable(level, message);
|
||||
}
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -67,6 +67,8 @@ LLEventMatching::LLEventMatching(LLEventPump& source, const LLSD& pattern):
|
|||
|
||||
bool LLEventMatching::post(const LLSD& event)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
if (! llsd_matches(mPattern, event).empty())
|
||||
return false;
|
||||
|
||||
|
|
@ -88,6 +90,8 @@ LLEventTimeoutBase::LLEventTimeoutBase(LLEventPump& source):
|
|||
|
||||
void LLEventTimeoutBase::actionAfter(F32 seconds, const Action& action)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
setCountdown(seconds);
|
||||
mAction = action;
|
||||
if (! mMainloop.connected())
|
||||
|
|
@ -126,6 +130,8 @@ public:
|
|||
|
||||
void operator()()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
mPump.post(mEvent);
|
||||
}
|
||||
|
||||
|
|
@ -136,6 +142,8 @@ private:
|
|||
|
||||
void LLEventTimeoutBase::eventAfter(F32 seconds, const LLSD& event)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
actionAfter(seconds, EventAfter(*this, event));
|
||||
}
|
||||
|
||||
|
|
@ -152,6 +160,8 @@ void LLEventTimeoutBase::cancel()
|
|||
|
||||
bool LLEventTimeoutBase::tick(const LLSD&)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
if (countdownElapsed())
|
||||
{
|
||||
cancel();
|
||||
|
|
@ -189,7 +199,9 @@ LLEventTimer* LLEventTimeout::post_every(F32 period, const std::string& pump, co
|
|||
{
|
||||
return LLEventTimer::run_every(
|
||||
period,
|
||||
[pump, data](){ LLEventPumps::instance().obtain(pump).post(data); });
|
||||
[pump, data](){
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
LLEventPumps::instance().obtain(pump).post(data); });
|
||||
}
|
||||
|
||||
LLEventTimer* LLEventTimeout::post_at(const LLDate& time, const std::string& pump, const LLSD& data)
|
||||
|
|
@ -221,6 +233,8 @@ LLEventBatch::LLEventBatch(LLEventPump& source, std::size_t size):
|
|||
|
||||
void LLEventBatch::flush()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
// copy and clear mBatch BEFORE posting to avoid weird circularity effects
|
||||
LLSD batch(mBatch);
|
||||
mBatch.clear();
|
||||
|
|
@ -229,6 +243,8 @@ void LLEventBatch::flush()
|
|||
|
||||
bool LLEventBatch::post(const LLSD& event)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
mBatch.append(event);
|
||||
// calling setSize(same) performs the very check we want
|
||||
setSize(mBatchSize);
|
||||
|
|
@ -267,6 +283,8 @@ void LLEventThrottleBase::flush()
|
|||
// post() anything but an isUndefined(). This is what mPosts is for.
|
||||
if (mPosts)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
mPosts = 0;
|
||||
alarmCancel();
|
||||
// This is not to set our alarm; we are not yet requesting
|
||||
|
|
@ -288,6 +306,8 @@ LLSD LLEventThrottleBase::pending() const
|
|||
|
||||
bool LLEventThrottleBase::post(const LLSD& event)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
// Always capture most recent post() event data. If caller wants to
|
||||
// aggregate multiple events, let them retrieve pending() and modify
|
||||
// before calling post().
|
||||
|
|
@ -411,6 +431,8 @@ LLEventBatchThrottle::LLEventBatchThrottle(LLEventPump& source, F32 interval, st
|
|||
|
||||
bool LLEventBatchThrottle::post(const LLSD& event)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
// simply retrieve pending value and append the new event to it
|
||||
LLSD partial = pending();
|
||||
partial.append(event);
|
||||
|
|
@ -447,6 +469,8 @@ LLEventLogProxy::LLEventLogProxy(LLEventPump& source, const std::string& name, b
|
|||
|
||||
bool LLEventLogProxy::post(const LLSD& event) /* override */
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
auto counter = mCounter++;
|
||||
auto eventplus = event;
|
||||
if (eventplus.type() == LLSD::TypeMap)
|
||||
|
|
|
|||
|
|
@ -429,6 +429,8 @@ public:
|
|||
// path, then stores it to mTarget.
|
||||
virtual bool post(const LLSD& event)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
// Extract the element specified by 'mPath' from 'event'. To perform a
|
||||
// generic type-appropriate store through mTarget, construct an
|
||||
// LLSDParam<T> and store that, thus engaging LLSDParam's custom
|
||||
|
|
|
|||
|
|
@ -93,6 +93,8 @@ struct LLStopWhenHandled
|
|||
template<typename InputIterator>
|
||||
result_type operator()(InputIterator first, InputIterator last) const
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
for (InputIterator si = first; si != last; ++si)
|
||||
{
|
||||
try
|
||||
|
|
|
|||
|
|
@ -97,6 +97,11 @@ static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific
|
|||
|
||||
U32 msc_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop)
|
||||
{
|
||||
const auto stack = to_string(boost::stacktrace::stacktrace());
|
||||
LL_WARNS() << "SEH Exception handled (that probably shouldn't be): Code " << code
|
||||
<< "\n Stack trace: \n"
|
||||
<< stack << LL_ENDL;
|
||||
|
||||
if (code == STATUS_MSC_EXCEPTION)
|
||||
{
|
||||
// C++ exception, go on
|
||||
|
|
|
|||
|
|
@ -196,29 +196,30 @@ TimeBlockTreeNode& BlockTimerStatHandle::getTreeNode() const
|
|||
}
|
||||
|
||||
|
||||
|
||||
void BlockTimer::bootstrapTimerTree()
|
||||
{
|
||||
for (auto& base : BlockTimerStatHandle::instance_snapshot())
|
||||
{
|
||||
// because of indirect derivation from LLInstanceTracker, have to downcast
|
||||
BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(base);
|
||||
if (&timer == &BlockTimer::getRootTimeBlock()) continue;
|
||||
for (auto& base : BlockTimerStatHandle::instance_snapshot())
|
||||
{
|
||||
// because of indirect derivation from LLInstanceTracker, have to downcast
|
||||
BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(base);
|
||||
if (&timer == &BlockTimer::getRootTimeBlock()) continue;
|
||||
|
||||
// bootstrap tree construction by attaching to last timer to be on stack
|
||||
// when this timer was called
|
||||
if (timer.getParent() == &BlockTimer::getRootTimeBlock())
|
||||
{
|
||||
TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator();
|
||||
// bootstrap tree construction by attaching to last timer to be on stack
|
||||
// when this timer was called
|
||||
if (timer.getParent() == &BlockTimer::getRootTimeBlock())
|
||||
{
|
||||
TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator();
|
||||
|
||||
if (accumulator.mLastCaller)
|
||||
{
|
||||
timer.setParent(accumulator.mLastCaller);
|
||||
accumulator.mParent = accumulator.mLastCaller;
|
||||
}
|
||||
// no need to push up tree on first use, flag can be set spuriously
|
||||
accumulator.mMoveUpTree = false;
|
||||
}
|
||||
}
|
||||
if (accumulator.mLastCaller)
|
||||
{
|
||||
timer.setParent(accumulator.mLastCaller);
|
||||
accumulator.mParent = accumulator.mLastCaller;
|
||||
}
|
||||
// no need to push up tree on first use, flag can be set spuriously
|
||||
accumulator.mMoveUpTree = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bump timers up tree if they have been flagged as being in the wrong place
|
||||
|
|
@ -226,6 +227,7 @@ void BlockTimer::bootstrapTimerTree()
|
|||
// this preserves partial order derived from current frame's observations
|
||||
void BlockTimer::incrementalUpdateTimerTree()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
for(block_timer_tree_df_post_iterator_t it = begin_block_timer_tree_df_post(BlockTimer::getRootTimeBlock());
|
||||
it != end_block_timer_tree_df_post();
|
||||
++it)
|
||||
|
|
@ -265,7 +267,8 @@ void BlockTimer::incrementalUpdateTimerTree()
|
|||
|
||||
|
||||
void BlockTimer::updateTimes()
|
||||
{
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
// walk up stack of active timers and accumulate current time while leaving timing structures active
|
||||
BlockTimerStackRecord* stack_record = LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance();
|
||||
if (!stack_record) return;
|
||||
|
|
@ -276,7 +279,7 @@ void BlockTimer::updateTimes()
|
|||
|
||||
while(cur_timer
|
||||
&& cur_timer->mParentTimerData.mActiveTimer != cur_timer) // root defined by parent pointing to self
|
||||
{
|
||||
{
|
||||
U64 cumulative_time_delta = cur_time - cur_timer->mStartTime;
|
||||
cur_timer->mStartTime = cur_time;
|
||||
|
||||
|
|
|
|||
|
|
@ -38,27 +38,10 @@
|
|||
#define LL_FAST_TIMER_ON 1
|
||||
#define LL_FASTTIMER_USE_RDTSC 1
|
||||
|
||||
// <FS:Beq> Add Tracy profiler support
|
||||
/*
|
||||
#define LL_RECORD_BLOCK_TIME(timer_stat) \
|
||||
const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(timer_stat)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
|
||||
*/
|
||||
#include "fstelemetry.h"
|
||||
#ifdef TRACY_ENABLE
|
||||
// #undef TRACY_NO_FASTTIMERS // Uncomment if you want FASTTIMERS as well.
|
||||
#ifdef TRACY_NO_FASTTIMERS
|
||||
#define LL_RECORD_BLOCK_TIME(timer_stat) \
|
||||
FSZoneN( #timer_stat );
|
||||
#else // TRACY_NO_FASTTIMERS
|
||||
#define LL_RECORD_BLOCK_TIME(timer_stat) \
|
||||
FSZoneN( #timer_stat ); \
|
||||
const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(timer_stat)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
|
||||
#endif // TRACY_NO_FASTTIMERS
|
||||
#else // TRACY_ENABLE
|
||||
#define LL_RECORD_BLOCK_TIME(timer_stat) \
|
||||
const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(timer_stat)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
|
||||
#endif // TRACY_ENABLE
|
||||
// </FS:Beq>
|
||||
// NOTE: Also see llprofiler.h
|
||||
#if !defined(LL_PROFILER_CONFIGURATION)
|
||||
#define LL_RECORD_BLOCK_TIME(timer_stat) const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(timer_stat)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
|
||||
#endif // LL_PROFILER_CONFIGURATION
|
||||
|
||||
namespace LLTrace
|
||||
{
|
||||
|
|
|
|||
|
|
@ -29,6 +29,11 @@
|
|||
|
||||
#include "llframetimer.h"
|
||||
|
||||
// We don't bother building a stand alone lib; we just need to include the one source file for Tracy support
|
||||
#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY || LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER
|
||||
#include "TracyClient.cpp"
|
||||
#endif // LL_PROFILER_CONFIGURATION
|
||||
|
||||
// Static members
|
||||
//LLTimer LLFrameTimer::sInternalTimer;
|
||||
U64 LLFrameTimer::sStartTotalTime = totalTime();
|
||||
|
|
|
|||
|
|
@ -83,13 +83,34 @@ class LLInstanceTracker
|
|||
typedef llthread::LockStatic<StaticData> LockStatic;
|
||||
|
||||
public:
|
||||
using ptr_t = std::shared_ptr<T>;
|
||||
using weak_t = std::weak_ptr<T>;
|
||||
|
||||
/**
|
||||
* Storing a dumb T* somewhere external is a bad idea, since
|
||||
* LLInstanceTracker subclasses are explicitly destroyed rather than
|
||||
* managed by smart pointers. It's legal to declare stack instances of an
|
||||
* LLInstanceTracker subclass. But it's reasonable to store a
|
||||
* std::weak_ptr<T>, which will become invalid when the T instance is
|
||||
* destroyed.
|
||||
*/
|
||||
weak_t getWeak()
|
||||
{
|
||||
return mSelf;
|
||||
}
|
||||
|
||||
static S32 instanceCount()
|
||||
{
|
||||
return LockStatic()->mMap.size();
|
||||
}
|
||||
|
||||
// snapshot of std::pair<const KEY, std::shared_ptr<T>> pairs
|
||||
class snapshot
|
||||
{
|
||||
// It's very important that what we store in this snapshot are
|
||||
// weak_ptrs, NOT shared_ptrs. That's how we discover whether any
|
||||
// instance has been deleted during the lifespan of a snapshot.
|
||||
typedef std::vector<std::pair<const KEY, std::weak_ptr<T>>> VectorType;
|
||||
typedef std::vector<std::pair<const KEY, weak_t>> VectorType;
|
||||
// Dereferencing our iterator produces a std::shared_ptr for each
|
||||
// instance that still exists. Since we store weak_ptrs, that involves
|
||||
// two chained transformations:
|
||||
|
|
@ -98,7 +119,7 @@ public:
|
|||
// It is very important that we filter lazily, that is, during
|
||||
// traversal. Any one of our stored weak_ptrs might expire during
|
||||
// traversal.
|
||||
typedef std::pair<const KEY, std::shared_ptr<T>> strong_pair;
|
||||
typedef std::pair<const KEY, ptr_t> strong_pair;
|
||||
// Note for future reference: nat has not yet had any luck (up to
|
||||
// Boost 1.67) trying to use boost::transform_iterator with a hand-
|
||||
// coded functor, only with actual functions. In my experience, an
|
||||
|
|
@ -202,17 +223,12 @@ public:
|
|||
iterator end() { return iterator(snapshot::end(), key_getter); }
|
||||
};
|
||||
|
||||
static T* getInstance(const KEY& k)
|
||||
static ptr_t getInstance(const KEY& k)
|
||||
{
|
||||
LockStatic lock;
|
||||
const InstanceMap& map(lock->mMap);
|
||||
typename InstanceMap::const_iterator found = map.find(k);
|
||||
return (found == map.end()) ? NULL : found->second.get();
|
||||
}
|
||||
|
||||
static S32 instanceCount()
|
||||
{
|
||||
return LockStatic()->mMap.size();
|
||||
return (found == map.end()) ? NULL : found->second;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
@ -222,7 +238,9 @@ protected:
|
|||
// shared_ptr, so give it a no-op deleter. We store shared_ptrs in our
|
||||
// InstanceMap specifically so snapshot can store weak_ptrs so we can
|
||||
// detect deletions during traversals.
|
||||
std::shared_ptr<T> ptr(static_cast<T*>(this), [](T*){});
|
||||
ptr_t ptr(static_cast<T*>(this), [](T*){});
|
||||
// save corresponding weak_ptr for future reference
|
||||
mSelf = ptr;
|
||||
LockStatic lock;
|
||||
add_(lock, key, ptr);
|
||||
}
|
||||
|
|
@ -257,7 +275,7 @@ private:
|
|||
static std::string report(const char* key) { return report(std::string(key)); }
|
||||
|
||||
// caller must instantiate LockStatic
|
||||
void add_(LockStatic& lock, const KEY& key, const std::shared_ptr<T>& ptr)
|
||||
void add_(LockStatic& lock, const KEY& key, const ptr_t& ptr)
|
||||
{
|
||||
mInstanceKey = key;
|
||||
InstanceMap& map = lock->mMap;
|
||||
|
|
@ -281,7 +299,7 @@ private:
|
|||
break;
|
||||
}
|
||||
}
|
||||
std::shared_ptr<T> remove_(LockStatic& lock)
|
||||
ptr_t remove_(LockStatic& lock)
|
||||
{
|
||||
InstanceMap& map = lock->mMap;
|
||||
typename InstanceMap::iterator iter = map.find(mInstanceKey);
|
||||
|
|
@ -295,6 +313,9 @@ private:
|
|||
}
|
||||
|
||||
private:
|
||||
// Storing a weak_ptr to self is a bit like deriving from
|
||||
// std::enable_shared_from_this(), except more explicit.
|
||||
weak_t mSelf;
|
||||
KEY mInstanceKey;
|
||||
};
|
||||
|
||||
|
|
@ -326,6 +347,9 @@ class LLInstanceTracker<T, void, KEY_COLLISION_BEHAVIOR>
|
|||
typedef llthread::LockStatic<StaticData> LockStatic;
|
||||
|
||||
public:
|
||||
using ptr_t = std::shared_ptr<T>;
|
||||
using weak_t = std::weak_ptr<T>;
|
||||
|
||||
/**
|
||||
* Storing a dumb T* somewhere external is a bad idea, since
|
||||
* LLInstanceTracker subclasses are explicitly destroyed rather than
|
||||
|
|
@ -334,12 +358,15 @@ public:
|
|||
* std::weak_ptr<T>, which will become invalid when the T instance is
|
||||
* destroyed.
|
||||
*/
|
||||
std::weak_ptr<T> getWeak()
|
||||
weak_t getWeak()
|
||||
{
|
||||
return mSelf;
|
||||
}
|
||||
|
||||
static S32 instanceCount() { return LockStatic()->mSet.size(); }
|
||||
static S32 instanceCount()
|
||||
{
|
||||
return LockStatic()->mSet.size();
|
||||
}
|
||||
|
||||
// snapshot of std::shared_ptr<T> pointers
|
||||
class snapshot
|
||||
|
|
@ -347,7 +374,7 @@ public:
|
|||
// It's very important that what we store in this snapshot are
|
||||
// weak_ptrs, NOT shared_ptrs. That's how we discover whether any
|
||||
// instance has been deleted during the lifespan of a snapshot.
|
||||
typedef std::vector<std::weak_ptr<T>> VectorType;
|
||||
typedef std::vector<weak_t> VectorType;
|
||||
// Dereferencing our iterator produces a std::shared_ptr for each
|
||||
// instance that still exists. Since we store weak_ptrs, that involves
|
||||
// two chained transformations:
|
||||
|
|
@ -453,7 +480,7 @@ protected:
|
|||
private:
|
||||
// Storing a weak_ptr to self is a bit like deriving from
|
||||
// std::enable_shared_from_this(), except more explicit.
|
||||
std::weak_ptr<T> mSelf;
|
||||
weak_t mSelf;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -220,7 +220,7 @@ void LLLeapListener::getAPI(const LLSD& request) const
|
|||
{
|
||||
Response reply(LLSD(), request);
|
||||
|
||||
LLEventAPI* found = LLEventAPI::getInstance(request["api"]);
|
||||
auto found = LLEventAPI::getInstance(request["api"]);
|
||||
if (found)
|
||||
{
|
||||
reply["name"] = found->getName();
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ void LLMemory::initMaxHeapSizeGB(F32Gigabytes max_heap_size)
|
|||
//static
|
||||
void LLMemory::updateMemoryInfo()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
#if LL_WINDOWS
|
||||
PROCESS_MEMORY_COUNTERS counters;
|
||||
|
||||
|
|
@ -145,6 +146,7 @@ void* LLMemory::tryToAlloc(void* address, U32 size)
|
|||
//static
|
||||
void LLMemory::logMemoryInfo(BOOL update)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
if(update)
|
||||
{
|
||||
updateMemoryInfo() ;
|
||||
|
|
|
|||
|
|
@ -101,6 +101,29 @@ template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address)
|
|||
|
||||
#define LL_ALIGN_16(var) LL_ALIGN_PREFIX(16) var LL_ALIGN_POSTFIX(16)
|
||||
|
||||
#define LL_ALIGN_NEW \
|
||||
public: \
|
||||
void* operator new(size_t size) \
|
||||
{ \
|
||||
return ll_aligned_malloc_16(size); \
|
||||
} \
|
||||
\
|
||||
void operator delete(void* ptr) \
|
||||
{ \
|
||||
ll_aligned_free_16(ptr); \
|
||||
} \
|
||||
\
|
||||
void* operator new[](size_t size) \
|
||||
{ \
|
||||
return ll_aligned_malloc_16(size); \
|
||||
} \
|
||||
\
|
||||
void operator delete[](void* ptr) \
|
||||
{ \
|
||||
ll_aligned_free_16(ptr); \
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// for enable buffer overrun detection predefine LL_DEBUG_BUFFER_OVERRUN in current library
|
||||
|
|
@ -113,8 +136,9 @@ template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address)
|
|||
#else
|
||||
inline void* ll_aligned_malloc_fallback( size_t size, int align )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
|
||||
#if defined(LL_WINDOWS)
|
||||
return _aligned_malloc(size, align);
|
||||
void* ret = (_aligned_malloc)(size, align);
|
||||
#else
|
||||
char* aligned = NULL;
|
||||
void* mem = malloc( size + (align - 1) + sizeof(void*) );
|
||||
|
|
@ -125,14 +149,18 @@ template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address)
|
|||
|
||||
((void**)aligned)[-1] = mem;
|
||||
}
|
||||
return aligned;
|
||||
void* ret = aligned;
|
||||
#endif
|
||||
LL_PROFILE_ALLOC(ret, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline void ll_aligned_free_fallback( void* ptr )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
|
||||
LL_PROFILE_FREE(ptr);
|
||||
#if defined(LL_WINDOWS)
|
||||
_aligned_free(ptr);
|
||||
(_aligned_free)(ptr);
|
||||
#else
|
||||
if (ptr)
|
||||
{
|
||||
|
|
@ -146,21 +174,24 @@ template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address)
|
|||
|
||||
inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed with ll_aligned_free_16().
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
|
||||
#if defined(LL_WINDOWS)
|
||||
return _aligned_malloc(size, 16);
|
||||
void* ret = _aligned_malloc(size, 16);
|
||||
#elif defined(LL_DARWIN)
|
||||
return malloc(size); // default osx malloc is 16 byte aligned.
|
||||
void* ret = malloc(size); // default osx malloc is 16 byte aligned.
|
||||
#else
|
||||
void *rtn;
|
||||
if (LL_LIKELY(0 == posix_memalign(&rtn, 16, size)))
|
||||
return rtn;
|
||||
else // bad alignment requested, or out of memory
|
||||
return NULL;
|
||||
void *ret;
|
||||
if (0 != posix_memalign(&ret, 16, size))
|
||||
return nullptr;
|
||||
#endif
|
||||
LL_PROFILE_ALLOC(ret, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline void ll_aligned_free_16(void *p)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
|
||||
LL_PROFILE_FREE(p);
|
||||
#if defined(LL_WINDOWS)
|
||||
_aligned_free(p);
|
||||
#elif defined(LL_DARWIN)
|
||||
|
|
@ -172,10 +203,12 @@ inline void ll_aligned_free_16(void *p)
|
|||
|
||||
inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // returned hunk MUST be freed with ll_aligned_free_16().
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
|
||||
LL_PROFILE_FREE(ptr);
|
||||
#if defined(LL_WINDOWS)
|
||||
return _aligned_realloc(ptr, size, 16);
|
||||
void* ret = _aligned_realloc(ptr, size, 16);
|
||||
#elif defined(LL_DARWIN)
|
||||
return realloc(ptr,size); // default osx malloc is 16 byte aligned.
|
||||
void* ret = realloc(ptr,size); // default osx malloc is 16 byte aligned.
|
||||
#else
|
||||
//FIXME: memcpy is SLOW
|
||||
void* ret = ll_aligned_malloc_16(size);
|
||||
|
|
@ -188,27 +221,31 @@ inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // r
|
|||
}
|
||||
ll_aligned_free_16(ptr);
|
||||
}
|
||||
return ret;
|
||||
#endif
|
||||
LL_PROFILE_ALLOC(ptr, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed with ll_aligned_free_32().
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
|
||||
#if defined(LL_WINDOWS)
|
||||
return _aligned_malloc(size, 32);
|
||||
void* ret = _aligned_malloc(size, 32);
|
||||
#elif defined(LL_DARWIN)
|
||||
return ll_aligned_malloc_fallback( size, 32 );
|
||||
void* ret = ll_aligned_malloc_fallback( size, 32 );
|
||||
#else
|
||||
void *rtn;
|
||||
if (LL_LIKELY(0 == posix_memalign(&rtn, 32, size)))
|
||||
return rtn;
|
||||
else // bad alignment requested, or out of memory
|
||||
return NULL;
|
||||
void *ret;
|
||||
if (0 != posix_memalign(&ret, 32, size))
|
||||
return nullptr;
|
||||
#endif
|
||||
LL_PROFILE_ALLOC(ret, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline void ll_aligned_free_32(void *p)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
|
||||
LL_PROFILE_FREE(p);
|
||||
#if defined(LL_WINDOWS)
|
||||
_aligned_free(p);
|
||||
#elif defined(LL_DARWIN)
|
||||
|
|
@ -222,29 +259,35 @@ inline void ll_aligned_free_32(void *p)
|
|||
template<size_t ALIGNMENT>
|
||||
LL_FORCE_INLINE void* ll_aligned_malloc(size_t size)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
|
||||
void* ret;
|
||||
if (LL_DEFAULT_HEAP_ALIGN % ALIGNMENT == 0)
|
||||
{
|
||||
return malloc(size);
|
||||
ret = malloc(size);
|
||||
LL_PROFILE_ALLOC(ret, size);
|
||||
}
|
||||
else if (ALIGNMENT == 16)
|
||||
{
|
||||
return ll_aligned_malloc_16(size);
|
||||
ret = ll_aligned_malloc_16(size);
|
||||
}
|
||||
else if (ALIGNMENT == 32)
|
||||
{
|
||||
return ll_aligned_malloc_32(size);
|
||||
ret = ll_aligned_malloc_32(size);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ll_aligned_malloc_fallback(size, ALIGNMENT);
|
||||
ret = ll_aligned_malloc_fallback(size, ALIGNMENT);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<size_t ALIGNMENT>
|
||||
LL_FORCE_INLINE void ll_aligned_free(void* ptr)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
|
||||
if (ALIGNMENT == LL_DEFAULT_HEAP_ALIGN)
|
||||
{
|
||||
LL_PROFILE_FREE(ptr);
|
||||
free(ptr);
|
||||
}
|
||||
else if (ALIGNMENT == 16)
|
||||
|
|
@ -266,6 +309,7 @@ LL_FORCE_INLINE void ll_aligned_free(void* ptr)
|
|||
//
|
||||
inline void ll_memcpy_nonaliased_aligned_16(char* __restrict dst, const char* __restrict src, size_t bytes)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY;
|
||||
assert(src != NULL);
|
||||
assert(dst != NULL);
|
||||
assert(bytes > 0);
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ LLMutex::~LLMutex()
|
|||
|
||||
void LLMutex::lock()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
|
||||
if(isSelfLocked())
|
||||
{ //redundant lock
|
||||
mCount++;
|
||||
|
|
@ -65,6 +66,7 @@ void LLMutex::lock()
|
|||
|
||||
void LLMutex::unlock()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
|
||||
if (mCount > 0)
|
||||
{ //not the root unlock
|
||||
mCount--;
|
||||
|
|
@ -85,6 +87,7 @@ void LLMutex::unlock()
|
|||
|
||||
bool LLMutex::isLocked()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
|
||||
if (!mMutex.try_lock())
|
||||
{
|
||||
return true;
|
||||
|
|
@ -108,6 +111,7 @@ LLThread::id_t LLMutex::lockingThread() const
|
|||
|
||||
bool LLMutex::trylock()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
|
||||
if(isSelfLocked())
|
||||
{ //redundant lock
|
||||
mCount++;
|
||||
|
|
@ -146,17 +150,20 @@ LLCondition::~LLCondition()
|
|||
|
||||
void LLCondition::wait()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
|
||||
std::unique_lock< std::mutex > lock(mMutex);
|
||||
mCond.wait(lock);
|
||||
}
|
||||
|
||||
void LLCondition::signal()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
|
||||
mCond.notify_one();
|
||||
}
|
||||
|
||||
void LLCondition::broadcast()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
|
||||
mCond.notify_all();
|
||||
}
|
||||
|
||||
|
|
@ -166,6 +173,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex)
|
|||
: mMutex(mutex),
|
||||
mLocked(false)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
|
||||
if (mMutex)
|
||||
mLocked = mMutex->trylock();
|
||||
}
|
||||
|
|
@ -174,6 +182,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms)
|
|||
: mMutex(mutex),
|
||||
mLocked(false)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
|
||||
if (!mMutex)
|
||||
return;
|
||||
|
||||
|
|
@ -188,6 +197,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms)
|
|||
|
||||
LLMutexTrylock::~LLMutexTrylock()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
|
||||
if (mMutex && mLocked)
|
||||
mMutex->unlock();
|
||||
}
|
||||
|
|
@ -199,6 +209,7 @@ LLMutexTrylock::~LLMutexTrylock()
|
|||
//
|
||||
LLScopedLock::LLScopedLock(std::mutex* mutex) : mMutex(mutex)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
|
||||
if(mutex)
|
||||
{
|
||||
mutex->lock();
|
||||
|
|
@ -217,6 +228,7 @@ LLScopedLock::~LLScopedLock()
|
|||
|
||||
void LLScopedLock::unlock()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
|
||||
if(mLocked)
|
||||
{
|
||||
mMutex->unlock();
|
||||
|
|
|
|||
|
|
@ -187,7 +187,9 @@
|
|||
#define LL_DLLIMPORT
|
||||
#endif // LL_WINDOWS
|
||||
|
||||
#if ! defined(LL_WINDOWS)
|
||||
#if __clang__ || ! defined(LL_WINDOWS)
|
||||
// Only on Windows, and only with the Microsoft compiler (vs. clang) is
|
||||
// wchar_t potentially not a distinct type.
|
||||
#define LL_WCHAR_T_NATIVE 1
|
||||
#else // LL_WINDOWS
|
||||
// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
|
||||
|
|
|
|||
|
|
@ -44,20 +44,6 @@
|
|||
|
||||
#include "llsd.h"
|
||||
|
||||
#if LL_MSVC && _M_X64
|
||||
# define LL_X86_64 1
|
||||
# define LL_X86 1
|
||||
#elif LL_MSVC && _M_IX86
|
||||
# define LL_X86 1
|
||||
#elif LL_GNUC && ( defined(__amd64__) || defined(__x86_64__) )
|
||||
# define LL_X86_64 1
|
||||
# define LL_X86 1
|
||||
#elif LL_GNUC && ( defined(__i386__) )
|
||||
# define LL_X86 1
|
||||
#elif LL_GNUC && ( defined(__powerpc__) || defined(__ppc__) )
|
||||
# define LL_PPC 1
|
||||
#endif
|
||||
|
||||
class LLProcessorInfoImpl; // foward declaration for the mImpl;
|
||||
|
||||
namespace
|
||||
|
|
|
|||
|
|
@ -29,6 +29,20 @@
|
|||
#define LLPROCESSOR_H
|
||||
#include "llunits.h"
|
||||
|
||||
#if LL_MSVC && _M_X64
|
||||
# define LL_X86_64 1
|
||||
# define LL_X86 1
|
||||
#elif LL_MSVC && _M_IX86
|
||||
# define LL_X86 1
|
||||
#elif LL_GNUC && ( defined(__amd64__) || defined(__x86_64__) )
|
||||
# define LL_X86_64 1
|
||||
# define LL_X86 1
|
||||
#elif LL_GNUC && ( defined(__i386__) )
|
||||
# define LL_X86 1
|
||||
#elif LL_GNUC && ( defined(__powerpc__) || defined(__ppc__) )
|
||||
# define LL_PPC 1
|
||||
#endif
|
||||
|
||||
class LLProcessorInfoImpl;
|
||||
|
||||
class LL_COMMON_API LLProcessorInfo
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* @file fstelemetry.cpp
|
||||
* @brief fstelemetry Telemetry abstraction for FS
|
||||
* @file llprofiler.cpp
|
||||
* @brief llprofiler Telemetry abstraction
|
||||
*
|
||||
* $LicenseInfo:firstyear=2021&license=fsviewerlgpl$
|
||||
* Phoenix Firestorm Viewer Source Code
|
||||
|
|
@ -24,8 +24,8 @@
|
|||
* http://www.firestormviewer.org
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#include "fstelemetry.h"
|
||||
namespace FSTelemetry
|
||||
#include "llprofiler.h"
|
||||
namespace LLProfiler
|
||||
{
|
||||
bool active{false};
|
||||
|
||||
|
|
@ -0,0 +1,218 @@
|
|||
/**
|
||||
* @file llprofiler.h
|
||||
* @brief Wrapper for Tracy and/or other profilers
|
||||
*
|
||||
* $LicenseInfo:firstyear=2021&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2021, Linden Research, Inc.
|
||||
*
|
||||
* This 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;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This 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 this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_PROFILER_H
|
||||
#define LL_PROFILER_H
|
||||
|
||||
// If you use the default macros LL_PROFILE_ZONE_SCOPED and LL_PROFILE_ZONE_NAMED to profile code ...
|
||||
//
|
||||
// void foo()
|
||||
// {
|
||||
// LL_PROFILE_ZONE_SCOPED;
|
||||
// :
|
||||
//
|
||||
// {
|
||||
// LL_PROFILE_ZONE_NAMED("widget bar");
|
||||
// :
|
||||
// }
|
||||
// {
|
||||
// LL_PROFILE_ZONE_NAMED("widget qux");
|
||||
// :
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// ... please be aware that ALL these will show up in a Tracy capture which can quickly exhaust memory.
|
||||
// Instead, use LL_PROFILE_ZONE_SCOPED_CATEGORY_* and LL_PROFILE_ZONE_NAMED_CATEGORY_* to profile code ...
|
||||
//
|
||||
// void foo()
|
||||
// {
|
||||
// LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
|
||||
// :
|
||||
//
|
||||
// {
|
||||
// LL_PROFILE_ZONE_NAMED_CATEGORY_UI("widget bar");
|
||||
// :
|
||||
// }
|
||||
// {
|
||||
// LL_PROFILE_ZONE_NAMED_CATEGORY_UI("widget qux");
|
||||
// :
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// ... as these can be selectively turned on/off. This will minimize memory usage and visual clutter in a Tracy capture.
|
||||
// See llprofiler_categories.h for more details on profiling categories.
|
||||
|
||||
#define LL_PROFILER_CONFIG_NONE 0 // No profiling
|
||||
#define LL_PROFILER_CONFIG_FAST_TIMER 1 // Profiling on: Only Fast Timers
|
||||
#define LL_PROFILER_CONFIG_TRACY 2 // Profiling on: Only Tracy
|
||||
#define LL_PROFILER_CONFIG_TRACY_FAST_TIMER 3 // Profiling on: Fast Timers + Tracy
|
||||
|
||||
#ifndef LL_PROFILER_CONFIGURATION
|
||||
#define LL_PROFILER_CONFIGURATION LL_PROFILER_CONFIG_FAST_TIMER
|
||||
#endif
|
||||
|
||||
extern thread_local bool gProfilerEnabled;
|
||||
|
||||
#if defined(LL_PROFILER_CONFIGURATION) && (LL_PROFILER_CONFIGURATION > LL_PROFILER_CONFIG_NONE)
|
||||
#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY || LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER
|
||||
#define TRACY_ENABLE 1
|
||||
// Normally these would be enabled but we want to be able to build any viewer with Tracy enabled and run the Tracy server on another machine
|
||||
// They must be undefined in order to work across multiple machines
|
||||
// #define TRACY_NO_BROADCAST 1
|
||||
// #define TRACY_ONLY_LOCALHOST 1
|
||||
#define TRACY_ONLY_IPV4 1
|
||||
#include "Tracy.hpp"
|
||||
// <FS:Beq> Fixed mutual exclusion issues with RAM and GPU. NOTE: This might still break on Apple in which case we'll need to restrict that platform
|
||||
//// GPU Mutually exclusive with detailed memory tracing
|
||||
// #define LL_PROFILER_ENABLE_TRACY_OPENGL 0
|
||||
#define LL_PROFILER_ENABLE_TRACY_MEMORY 1
|
||||
#define LL_PROFILER_ENABLE_TRACY_OPENGL 1
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY
|
||||
#define LL_PROFILER_FRAME_END FrameMark
|
||||
#define LL_PROFILER_SET_THREAD_NAME( name ) tracy::SetThreadName( name ); gProfilerEnabled = true;
|
||||
#define LL_PROFILER_THREAD_BEGIN(name) FrameMarkStart( name ) // C string
|
||||
#define LL_PROFILER_THREAD_END(name) FrameMarkEnd( name ) // C string
|
||||
// <FS:Beq> revert change that obscures custom FTM zones. We may want to may FTM Zones unique in future.
|
||||
// #define LL_RECORD_BLOCK_TIME(name) ZoneScoped // Want descriptive names; was: ZoneNamedN( ___tracy_scoped_zone, #name, gProfilerEnabled );
|
||||
#define LL_RECORD_BLOCK_TIME(name) ZoneNamedN( ___tracy_scoped_zone, #name, gProfilerEnabled )
|
||||
// </FS:Beq>
|
||||
|
||||
// <FS:Beq>
|
||||
// #define LL_PROFILE_ZONE_NAMED(name) ZoneNamedN( ___tracy_scoped_zone, name, true )
|
||||
// #define LL_PROFILE_ZONE_NAMED_COLOR(name,color) ZoneNamedNC( ___tracy_scopped_zone, name, color, true ) // RGB
|
||||
// #define LL_PROFILE_ZONE_SCOPED ZoneScoped
|
||||
#define LL_PROFILE_ZONE_NAMED(name) ZoneNamedN( ___tracy_scoped_zone, name, gProfilerEnabled )
|
||||
#define LL_PROFILE_ZONE_NAMED_COLOR(name,color) ZoneNamedNC( ___tracy_scopped_zone, name, color, gProfilerEnabled ) // RGB
|
||||
#define LL_PROFILE_ZONE_SCOPED ZoneNamed( ___tracy_scoped_zone, gProfilerEnabled ) // <FS:Beq/> Enable deferred collection through filters
|
||||
// </FS:Beq>
|
||||
|
||||
#define LL_PROFILE_ZONE_NUM( val ) ZoneValue( val )
|
||||
#define LL_PROFILE_ZONE_TEXT( text, size ) ZoneText( text, size )
|
||||
|
||||
#define LL_PROFILE_ZONE_ERR(name) LL_PROFILE_ZONE_NAMED_COLOR( name, 0XFF0000 ) // RGB yellow
|
||||
#define LL_PROFILE_ZONE_INFO(name) LL_PROFILE_ZONE_NAMED_COLOR( name, 0X00FFFF ) // RGB cyan
|
||||
#define LL_PROFILE_ZONE_WARN(name) LL_PROFILE_ZONE_NAMED_COLOR( name, 0x0FFFF00 ) // RGB red
|
||||
#define LL_PROFILE_ALLOC(ptr, size) TracyAlloc(ptr, size)
|
||||
#define LL_PROFILE_FREE(ptr) TracyFree(ptr)
|
||||
|
||||
// <FS:Beq> Additional FS Tracy macros
|
||||
#define LL_PROFILE_ZONE_COLOR(color) ZoneNamedC( ___tracy_scoped_zone, color, gProfilerEnabled ) // <FS:Beq/> Additional Tracy macro
|
||||
#define LL_PROFILE_PLOT( name, value ) TracyPlot( name, value)
|
||||
#define LL_PROFILE_PLOT_SQ( name, prev, value ) TracyPlot(name,prev);TracyPlot( name, value)
|
||||
#define LL_PROFILE_IS_CONNECTED TracyIsConnected
|
||||
// </FS:Beq>
|
||||
#endif
|
||||
#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_FAST_TIMER
|
||||
#define LL_PROFILER_FRAME_END
|
||||
#define LL_PROFILER_SET_THREAD_NAME( name ) (void)(name);
|
||||
#define LL_PROFILER_THREAD_BEGIN(name) (void)(name); // Not supported
|
||||
#define LL_PROFILER_THREAD_END(name) (void)(name); // Not supported
|
||||
|
||||
#define LL_RECORD_BLOCK_TIME(name) const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(name)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
|
||||
#define LL_PROFILE_ZONE_NAMED(name) // LL_PROFILE_ZONE_NAMED is a no-op when Tracy is disabled
|
||||
#define LL_PROFILE_ZONE_NAMED_COLOR(name,color) // LL_RECORD_BLOCK_TIME(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED // LL_PROFILE_ZONE_SCOPED is a no-op when Tracy is disabled
|
||||
|
||||
#define LL_PROFILE_ZONE_NUM( val ) (void)( val ); // Not supported
|
||||
#define LL_PROFILE_ZONE_TEXT( text, size ) (void)( text ); void( size ); // Not supported
|
||||
|
||||
#define LL_PROFILE_ZONE_ERR(name) (void)(name); // Not supported
|
||||
#define LL_PROFILE_ZONE_INFO(name) (void)(name); // Not supported
|
||||
#define LL_PROFILE_ZONE_WARN(name) (void)(name); // Not supported
|
||||
#define LL_PROFILE_ALLOC(ptr, size) (void)(ptr); (void)(size);
|
||||
#define LL_PROFILE_FREE(ptr) (void)(ptr);
|
||||
// <FS:Beq> Additional FS Tracy macros
|
||||
#define LL_PROFILE_ZONE_COLOR(color)
|
||||
#define LL_PROFILE_PLOT( name, value )
|
||||
#define LL_PROFILE_PLOT_SQ( name, prev, value )
|
||||
#define LL_PROFILE_IS_CONNECTED
|
||||
// </FS:Beq>
|
||||
#endif
|
||||
#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER
|
||||
#define LL_PROFILER_FRAME_END FrameMark
|
||||
#define LL_PROFILER_SET_THREAD_NAME( name ) tracy::SetThreadName( name ); gProfilerEnabled = true;
|
||||
#define LL_PROFILER_THREAD_BEGIN(name) FrameMarkStart( name ) // C string
|
||||
#define LL_PROFILER_THREAD_END(name) FrameMarkEnd( name ) // C string
|
||||
|
||||
// <FS:Beq> revert change that obscures custom FTM zones.
|
||||
// #define LL_RECORD_BLOCK_TIME(name) ZoneScoped const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(name)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
|
||||
#define LL_RECORD_BLOCK_TIME(name) ZoneNamedN( ___tracy_scoped_zone, #name, gProfilerEnabled ); const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(name)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__);
|
||||
// </FS:Beq>
|
||||
// <FS:Beq>
|
||||
// #define LL_PROFILE_ZONE_NAMED(name) ZoneNamedN( ___tracy_scoped_zone, name, true )
|
||||
// #define LL_PROFILE_ZONE_NAMED_COLOR(name,color) ZoneNamedNC( ___tracy_scopped_zone, name, color, true ) // RGB
|
||||
// #define LL_PROFILE_ZONE_SCOPED ZoneScoped
|
||||
#define LL_PROFILE_ZONE_NAMED(name) ZoneNamedN( ___tracy_scoped_zone, name, gProfilerEnabled );
|
||||
#define LL_PROFILE_ZONE_NAMED_COLOR(name,color) ZoneNamedNC( ___tracy_scopped_zone, name, color, gProfilerEnabled ) // RGB
|
||||
#define LL_PROFILE_ZONE_SCOPED ZoneNamed( ___tracy_scoped_zone, gProfilerEnabled ) // <FS:Beq/> Enable deferred collection through filters
|
||||
// </FS:Beq>
|
||||
|
||||
#define LL_PROFILE_ZONE_NUM( val ) ZoneValue( val )
|
||||
#define LL_PROFILE_ZONE_TEXT( text, size ) ZoneText( text, size )
|
||||
|
||||
#define LL_PROFILE_ZONE_ERR(name) LL_PROFILE_ZONE_NAMED_COLOR( name, 0XFF0000 ) // RGB yellow
|
||||
#define LL_PROFILE_ZONE_INFO(name) LL_PROFILE_ZONE_NAMED_COLOR( name, 0X00FFFF ) // RGB cyan
|
||||
#define LL_PROFILE_ZONE_WARN(name) LL_PROFILE_ZONE_NAMED_COLOR( name, 0x0FFFF00 ) // RGB red
|
||||
#define LL_PROFILE_ALLOC(ptr, size) TracyAlloc(ptr, size)
|
||||
#define LL_PROFILE_FREE(ptr) TracyFree(ptr)
|
||||
// <FS:Beq> Additional FS Tracy macros
|
||||
#define LL_PROFILE_ZONE_COLOR(color) ZoneNamedC( ___tracy_scoped_zone, color, gProfilerEnabled )
|
||||
#define LL_PROFILE_PLOT( name, value ) TracyPlot( name, value)
|
||||
#define LL_PROFILE_PLOT_SQ( name, prev, value ) TracyPlot( name, prev );TracyPlot( name, value )
|
||||
#define LL_PROFILE_IS_CONNECTED TracyIsConnected
|
||||
// </FS:Beq>
|
||||
#endif
|
||||
#else
|
||||
#define LL_PROFILER_FRAME_END
|
||||
#define LL_PROFILER_SET_THREAD_NAME(name)
|
||||
#define LL_PROFILER_THREAD_BEGIN(name)
|
||||
#define LL_PROFILER_THREAD_END(name)
|
||||
|
||||
#define LL_RECORD_BLOCK_TIME(name)
|
||||
#define LL_PROFILE_ZONE_NAMED(name)
|
||||
#define LL_PROFILE_ZONE_NAMED_COLOR(name,color)
|
||||
#define LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
#define LL_PROFILE_ZONE_NUM(val)
|
||||
#define LL_PROFILE_ZONE_TEXT(text, size)
|
||||
|
||||
#define LL_PROFILE_ZONE_ERR(name)
|
||||
#define LL_PROFILE_ZONE_INFO(name)
|
||||
#define LL_PROFILE_ZONE_WARN(name)
|
||||
|
||||
// <FS:Ansariel> Additional FS Tracy macros
|
||||
#define LL_PROFILE_ZONE_COLOR(color)
|
||||
#define LL_PROFILE_PLOT( name, value )
|
||||
#define LL_PROFILE_PLOT_SQ( name, prev, value )
|
||||
#define LL_PROFILE_IS_CONNECTED
|
||||
// </FS:Ansariel>
|
||||
#endif // LL_PROFILER
|
||||
|
||||
#include "llprofilercategories.h"
|
||||
|
||||
#endif // LL_PROFILER_H
|
||||
|
|
@ -0,0 +1,280 @@
|
|||
/**
|
||||
* @file llprofiler_ategories.h
|
||||
* @brief Profiling categories to minimize Tracy memory usage when viewing captures.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2022, Linden Research, Inc.
|
||||
*
|
||||
* This 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;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This 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 this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_PROFILER_CATEGORIES_H
|
||||
#define LL_PROFILER_CATEGORIES_H
|
||||
|
||||
// A Tracy capture can quickly consume memory. Use these defines to selectively turn on/off Tracy profiling for these categories.
|
||||
// The biggest memory usage ones are:
|
||||
//
|
||||
// LL_PROFILER_CATEGORY_ENABLE_DRAWPOOL
|
||||
// LL_PROFILER_CATEGORY_ENABLE_LLSD
|
||||
// LL_PROFILER_CATEGORY_ENABLE_MEMORY
|
||||
// LL_PROFILER_CATEGORY_ENABLE_SHADERS
|
||||
//
|
||||
// NOTE: You can still manually use:
|
||||
// LL_PROFILE_ZONE_SCOPED();
|
||||
// LL_PROFILE_ZONE_NAMED("name");
|
||||
// but just be aware that those will ALWAYS show up in a Tracy capture
|
||||
// a) using more memory, and
|
||||
// b) adding visual clutter.
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_APP 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_AVATAR 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_DISPLAY 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_DRAWABLE 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_DRAWPOOL 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_ENVIRONMENT 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_FACE 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_LLSD 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_LOGGING 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_MATERIAL 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_MEDIA 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_MEMORY 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_NETWORK 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_OCTREE 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_PIPELINE 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_SHADER 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_SPATIAL 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_STATS 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_STRING 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_TEXTURE 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_THREAD 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_UI 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_VIEWER 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_VERTEX 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_VOLUME 1
|
||||
#define LL_PROFILER_CATEGORY_ENABLE_WIN32 1
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_APP
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_APP LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_APP LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_APP(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_APP
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_AVATAR
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_AVATAR LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_AVATAR(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_DISPLAY
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_DRAWABLE
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWABLE LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWABLE(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_DRAWPOOL
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_ENVIRONMENT
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_ENVIRONMENT LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_ENVIRONMENT(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_FACE
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_FACE LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_FACE(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_LLSD
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_LLSD LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_LLSD(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_LOGGING
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_LOGGING LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_LOGGING(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_MATERIAL
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_MATERIAL LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_MATERIAL(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_MEDIA
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_MEMORY
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_MEMORY LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_MEMORY(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_NETWORK
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_OCTREE
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_PIPELINE
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_SHADER
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_SHADER LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_SHADER(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_SPATIAL
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_SPATIAL LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_SPATIAL(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_STATS
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_STATS LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_STATS(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_STRING
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_STRING LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_STRING LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_STRING(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_STRING
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_TEXTURE
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_THREAD
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_UI
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_UI LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_UI LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_UI(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_VERTEX
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_VIEWER
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_VIEWER LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_VIEWER LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_VIEWER(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_VIEWER
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_VOLUME
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME
|
||||
#endif
|
||||
|
||||
#if LL_PROFILER_CATEGORY_ENABLE_WIN32
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32 LL_PROFILE_ZONE_NAMED
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32 LL_PROFILE_ZONE_SCOPED
|
||||
#else
|
||||
#define LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32(name)
|
||||
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32
|
||||
#endif
|
||||
|
||||
#endif // LL_PROFILER_CATEGORIES_H
|
||||
|
||||
|
|
@ -112,6 +112,8 @@ void LLQueuedThread::shutdown()
|
|||
// virtual
|
||||
S32 LLQueuedThread::update(F32 max_time_ms)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
if (!mStarted)
|
||||
{
|
||||
if (!mThreaded)
|
||||
|
|
@ -125,6 +127,8 @@ S32 LLQueuedThread::update(F32 max_time_ms)
|
|||
|
||||
S32 LLQueuedThread::updateQueue(F32 max_time_ms)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
F64 max_time = (F64)max_time_ms * .001;
|
||||
LLTimer timer;
|
||||
S32 pending = 1;
|
||||
|
|
@ -147,11 +151,14 @@ S32 LLQueuedThread::updateQueue(F32 max_time_ms)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return pending;
|
||||
}
|
||||
|
||||
void LLQueuedThread::incQueue()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
// Something has been added to the queue
|
||||
if (!isPaused())
|
||||
{
|
||||
|
|
@ -166,6 +173,8 @@ void LLQueuedThread::incQueue()
|
|||
// May be called from any thread
|
||||
S32 LLQueuedThread::getPending()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
S32 res;
|
||||
lockData();
|
||||
res = mRequestQueue.size();
|
||||
|
|
@ -176,6 +185,8 @@ S32 LLQueuedThread::getPending()
|
|||
// MAIN thread
|
||||
void LLQueuedThread::waitOnPending()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
while(1)
|
||||
{
|
||||
update(0);
|
||||
|
|
@ -195,6 +206,8 @@ void LLQueuedThread::waitOnPending()
|
|||
// MAIN thread
|
||||
void LLQueuedThread::printQueueStats()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
lockData();
|
||||
if (!mRequestQueue.empty())
|
||||
{
|
||||
|
|
@ -211,6 +224,8 @@ void LLQueuedThread::printQueueStats()
|
|||
// MAIN thread
|
||||
LLQueuedThread::handle_t LLQueuedThread::generateHandle()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
lockData();
|
||||
while ((mNextHandle == nullHandle()) || (mRequestHash.find(mNextHandle)))
|
||||
{
|
||||
|
|
@ -224,6 +239,8 @@ LLQueuedThread::handle_t LLQueuedThread::generateHandle()
|
|||
// MAIN thread
|
||||
bool LLQueuedThread::addRequest(QueuedRequest* req)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
if (mStatus == QUITTING)
|
||||
{
|
||||
return false;
|
||||
|
|
@ -246,6 +263,8 @@ bool LLQueuedThread::addRequest(QueuedRequest* req)
|
|||
// MAIN thread
|
||||
bool LLQueuedThread::waitForResult(LLQueuedThread::handle_t handle, bool auto_complete)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
llassert (handle != nullHandle());
|
||||
bool res = false;
|
||||
bool waspaused = isPaused();
|
||||
|
|
@ -281,12 +300,15 @@ bool LLQueuedThread::waitForResult(LLQueuedThread::handle_t handle, bool auto_co
|
|||
{
|
||||
pause();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// MAIN thread
|
||||
LLQueuedThread::QueuedRequest* LLQueuedThread::getRequest(handle_t handle)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
if (handle == nullHandle())
|
||||
{
|
||||
return 0;
|
||||
|
|
@ -299,6 +321,8 @@ LLQueuedThread::QueuedRequest* LLQueuedThread::getRequest(handle_t handle)
|
|||
|
||||
LLQueuedThread::status_t LLQueuedThread::getRequestStatus(handle_t handle)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
status_t res = STATUS_EXPIRED;
|
||||
lockData();
|
||||
QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle);
|
||||
|
|
@ -312,6 +336,8 @@ LLQueuedThread::status_t LLQueuedThread::getRequestStatus(handle_t handle)
|
|||
|
||||
void LLQueuedThread::abortRequest(handle_t handle, bool autocomplete)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
lockData();
|
||||
QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle);
|
||||
if (req)
|
||||
|
|
@ -324,6 +350,8 @@ void LLQueuedThread::abortRequest(handle_t handle, bool autocomplete)
|
|||
// MAIN thread
|
||||
void LLQueuedThread::setFlags(handle_t handle, U32 flags)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
lockData();
|
||||
QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle);
|
||||
if (req)
|
||||
|
|
@ -335,6 +363,8 @@ void LLQueuedThread::setFlags(handle_t handle, U32 flags)
|
|||
|
||||
void LLQueuedThread::setPriority(handle_t handle, U32 priority)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
lockData();
|
||||
QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle);
|
||||
if (req)
|
||||
|
|
@ -357,6 +387,8 @@ void LLQueuedThread::setPriority(handle_t handle, U32 priority)
|
|||
|
||||
bool LLQueuedThread::completeRequest(handle_t handle)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
bool res = false;
|
||||
lockData();
|
||||
QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle);
|
||||
|
|
@ -401,6 +433,8 @@ bool LLQueuedThread::check()
|
|||
|
||||
S32 LLQueuedThread::processNextRequest()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
QueuedRequest *req;
|
||||
// Get next request from pool
|
||||
lockData();
|
||||
|
|
@ -517,9 +551,11 @@ void LLQueuedThread::run()
|
|||
|
||||
mIdleThread = FALSE;
|
||||
|
||||
LL_PROFILER_THREAD_BEGIN(mName.c_str())
|
||||
threadedUpdate();
|
||||
|
||||
|
||||
int pending_work = processNextRequest();
|
||||
LL_PROFILER_THREAD_END(mName.c_str())
|
||||
|
||||
if (pending_work == 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@
|
|||
|
||||
#include "llerror.h"
|
||||
|
||||
// maximum reference count before sounding memory leak alarm
|
||||
const S32 gMaxRefCount = 65536;
|
||||
|
||||
LLRefCount::LLRefCount(const LLRefCount& other)
|
||||
: mRef(0)
|
||||
{
|
||||
|
|
@ -47,7 +50,7 @@ LLRefCount::LLRefCount() :
|
|||
|
||||
LLRefCount::~LLRefCount()
|
||||
{
|
||||
if (mRef != 0)
|
||||
if (mRef != LL_REFCOUNT_FREE && mRef != 0)
|
||||
{
|
||||
LL_ERRS() << "deleting non-zero reference" << LL_ENDL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,10 @@ class LLMutex;
|
|||
// see llthread.h for LLThreadSafeRefCount
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
//nonsense but recognizable value for freed LLRefCount (aids in debugging)
|
||||
#define LL_REFCOUNT_FREE 1234567890
|
||||
extern const S32 gMaxRefCount;
|
||||
|
||||
class LL_COMMON_API LLRefCount
|
||||
{
|
||||
protected:
|
||||
|
|
@ -47,17 +51,25 @@ protected:
|
|||
public:
|
||||
LLRefCount();
|
||||
|
||||
inline void validateRefCount() const
|
||||
{
|
||||
llassert(mRef > 0); // ref count below 0, likely corrupted
|
||||
llassert(mRef < gMaxRefCount); // ref count excessive, likely memory leak
|
||||
}
|
||||
|
||||
inline void ref() const
|
||||
{
|
||||
mRef++;
|
||||
validateRefCount();
|
||||
}
|
||||
|
||||
inline S32 unref() const
|
||||
{
|
||||
llassert(mRef >= 1);
|
||||
validateRefCount();
|
||||
if (0 == --mRef)
|
||||
{
|
||||
delete this;
|
||||
mRef = LL_REFCOUNT_FREE; // set to nonsense yet recognizable value to aid in debugging
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return mRef;
|
||||
|
|
|
|||
|
|
@ -400,6 +400,7 @@ namespace
|
|||
|
||||
ImplMap& ImplMap::makeMap(LLSD::Impl*& var)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
|
||||
if (shared())
|
||||
{
|
||||
ImplMap* i = new ImplMap(mData);
|
||||
|
|
@ -414,18 +415,21 @@ namespace
|
|||
|
||||
bool ImplMap::has(const LLSD::String& k) const
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
|
||||
DataMap::const_iterator i = mData.find(k);
|
||||
return i != mData.end();
|
||||
}
|
||||
|
||||
LLSD ImplMap::get(const LLSD::String& k) const
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
|
||||
DataMap::const_iterator i = mData.find(k);
|
||||
return (i != mData.end()) ? i->second : LLSD();
|
||||
}
|
||||
|
||||
LLSD ImplMap::getKeys() const
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
|
||||
LLSD keys = LLSD::emptyArray();
|
||||
DataMap::const_iterator iter = mData.begin();
|
||||
while (iter != mData.end())
|
||||
|
|
@ -438,11 +442,13 @@ namespace
|
|||
|
||||
void ImplMap::insert(const LLSD::String& k, const LLSD& v)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
|
||||
mData.insert(DataMap::value_type(k, v));
|
||||
}
|
||||
|
||||
void ImplMap::erase(const LLSD::String& k)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
|
||||
mData.erase(k);
|
||||
}
|
||||
|
||||
|
|
@ -684,6 +690,7 @@ const LLSD::Impl& LLSD::Impl::safe(const Impl* impl)
|
|||
|
||||
ImplMap& LLSD::Impl::makeMap(Impl*& var)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
|
||||
ImplMap* im = new ImplMap;
|
||||
reset(var, im);
|
||||
return *im;
|
||||
|
|
@ -887,11 +894,16 @@ LLSD& LLSD::with(const String& k, const LLSD& v)
|
|||
}
|
||||
void LLSD::erase(const String& k) { makeMap(impl).erase(k); }
|
||||
|
||||
LLSD& LLSD::operator[](const String& k)
|
||||
{ return makeMap(impl).ref(k); }
|
||||
LLSD& LLSD::operator[](const String& k)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
|
||||
return makeMap(impl).ref(k);
|
||||
}
|
||||
const LLSD& LLSD::operator[](const String& k) const
|
||||
{ return safe(impl).ref(k); }
|
||||
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
|
||||
return safe(impl).ref(k);
|
||||
}
|
||||
|
||||
LLSD LLSD::emptyArray()
|
||||
{
|
||||
|
|
@ -914,10 +926,16 @@ LLSD& LLSD::with(Integer i, const LLSD& v)
|
|||
LLSD& LLSD::append(const LLSD& v) { return makeArray(impl).append(v); }
|
||||
void LLSD::erase(Integer i) { makeArray(impl).erase(i); }
|
||||
|
||||
LLSD& LLSD::operator[](Integer i)
|
||||
{ return makeArray(impl).ref(i); }
|
||||
LLSD& LLSD::operator[](Integer i)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
|
||||
return makeArray(impl).ref(i);
|
||||
}
|
||||
const LLSD& LLSD::operator[](Integer i) const
|
||||
{ return safe(impl).ref(i); }
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
|
||||
return safe(impl).ref(i);
|
||||
}
|
||||
|
||||
static const char *llsd_dump(const LLSD &llsd, bool useXMLFormat)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -290,9 +290,17 @@ public:
|
|||
LLSD& with(const String&, const LLSD&);
|
||||
|
||||
LLSD& operator[](const String&);
|
||||
LLSD& operator[](const char* c) { return (*this)[String(c)]; }
|
||||
LLSD& operator[](const char* c)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
|
||||
return (*this)[String(c)];
|
||||
}
|
||||
const LLSD& operator[](const String&) const;
|
||||
const LLSD& operator[](const char* c) const { return (*this)[String(c)]; }
|
||||
const LLSD& operator[](const char* c) const
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
|
||||
return (*this)[String(c)];
|
||||
}
|
||||
//@}
|
||||
|
||||
/** @name Array Values */
|
||||
|
|
|
|||
|
|
@ -37,8 +37,6 @@ static LLInitParam::Parser::parser_write_func_map_t sWriteFuncs;
|
|||
static LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs;
|
||||
static const LLSD NO_VALUE_MARKER;
|
||||
|
||||
LLTrace::BlockTimerStatHandle FTM_SD_PARAM_ADAPTOR("LLSD to LLInitParam conversion");
|
||||
|
||||
//
|
||||
// LLParamSDParser
|
||||
//
|
||||
|
|
|
|||
|
|
@ -110,7 +110,6 @@ private:
|
|||
};
|
||||
|
||||
|
||||
extern LL_COMMON_API LLTrace::BlockTimerStatHandle FTM_SD_PARAM_ADAPTOR;
|
||||
template<typename T>
|
||||
class LLSDParamAdapter : public T
|
||||
{
|
||||
|
|
@ -118,7 +117,7 @@ public:
|
|||
LLSDParamAdapter() {}
|
||||
LLSDParamAdapter(const LLSD& sd)
|
||||
{
|
||||
LL_RECORD_BLOCK_TIME(FTM_SD_PARAM_ADAPTOR);
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
LLParamSDParser parser;
|
||||
// don't spam for implicit parsing of LLSD, as we want to allow arbitrary freeform data and ignore most of it
|
||||
bool parse_silently = true;
|
||||
|
|
|
|||
|
|
@ -221,6 +221,8 @@ BOOL compare_llsd_with_template(
|
|||
const LLSD& template_llsd,
|
||||
LLSD& resultant_llsd)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
if (
|
||||
llsd_to_test.isUndefined() &&
|
||||
template_llsd.isDefined() )
|
||||
|
|
@ -342,6 +344,8 @@ bool filter_llsd_with_template(
|
|||
const LLSD & template_llsd,
|
||||
LLSD & resultant_llsd)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
if (llsd_to_test.isUndefined() && template_llsd.isDefined())
|
||||
{
|
||||
resultant_llsd = template_llsd;
|
||||
|
|
@ -536,6 +540,8 @@ class TypeLookup
|
|||
public:
|
||||
TypeLookup()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
for (const Data *di(boost::begin(typedata)), *dend(boost::end(typedata)); di != dend; ++di)
|
||||
{
|
||||
mMap[di->type] = di->name;
|
||||
|
|
@ -544,6 +550,8 @@ public:
|
|||
|
||||
std::string lookup(LLSD::Type type) const
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
MapType::const_iterator found = mMap.find(type);
|
||||
if (found != mMap.end())
|
||||
{
|
||||
|
|
@ -594,6 +602,8 @@ static std::string match_types(LLSD::Type expect, // prototype.type()
|
|||
LLSD::Type actual, // type we're checking
|
||||
const std::string& pfx) // as for llsd_matches
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
// Trivial case: if the actual type is exactly what we expect, we're good.
|
||||
if (actual == expect)
|
||||
return "";
|
||||
|
|
@ -631,6 +641,8 @@ static std::string match_types(LLSD::Type expect, // prototype.type()
|
|||
// see docstring in .h file
|
||||
std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
// An undefined prototype means that any data is valid.
|
||||
// An undefined slot in an array or map prototype means that any data
|
||||
// may fill that slot.
|
||||
|
|
@ -763,6 +775,8 @@ std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::str
|
|||
|
||||
bool llsd_equals(const LLSD& lhs, const LLSD& rhs, int bits)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
// We're comparing strict equality of LLSD representation rather than
|
||||
// performing any conversions. So if the types aren't equal, the LLSD
|
||||
// values aren't equal.
|
||||
|
|
@ -871,6 +885,8 @@ namespace llsd
|
|||
|
||||
LLSD& drill_ref(LLSD& blob, const LLSD& rawPath)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
// Treat rawPath uniformly as an array. If it's not already an array,
|
||||
// store it as the only entry in one. (But let's say Undefined means an
|
||||
// empty array.)
|
||||
|
|
@ -896,6 +912,8 @@ LLSD& drill_ref(LLSD& blob, const LLSD& rawPath)
|
|||
// path entry that's bad.
|
||||
for (LLSD::Integer i = 0; i < path.size(); ++i)
|
||||
{
|
||||
LL_PROFILE_ZONE_NUM( i )
|
||||
|
||||
const LLSD& key{path[i]};
|
||||
if (key.isString())
|
||||
{
|
||||
|
|
@ -924,6 +942,8 @@ LLSD& drill_ref(LLSD& blob, const LLSD& rawPath)
|
|||
|
||||
LLSD drill(const LLSD& blob, const LLSD& path)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
// drill_ref() does exactly what we want. Temporarily cast away
|
||||
// const-ness and use that.
|
||||
return drill_ref(const_cast<LLSD&>(blob), path);
|
||||
|
|
@ -936,6 +956,8 @@ LLSD drill(const LLSD& blob, const LLSD& path)
|
|||
// filter may be include to exclude/include keys in a map.
|
||||
LLSD llsd_clone(LLSD value, LLSD filter)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
|
||||
LLSD clone;
|
||||
bool has_filter(filter.isMap());
|
||||
|
||||
|
|
|
|||
|
|
@ -496,6 +496,7 @@ public:
|
|||
|
||||
static DERIVED_TYPE* getInstance()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
// We know the viewer has LLSingleton dependency circularities. If you
|
||||
// feel strongly motivated to eliminate them, cheers and good luck.
|
||||
// (At that point we could consider a much simpler locking mechanism.)
|
||||
|
|
@ -879,4 +880,36 @@ private: \
|
|||
/* LLSINGLETON() is carefully implemented to permit exactly this */ \
|
||||
LLSINGLETON_C11(DERIVED_CLASS) {}
|
||||
|
||||
// Relatively unsafe singleton implementation that is much faster
|
||||
// and simpler than LLSingleton, but has no dependency tracking
|
||||
// or inherent thread safety and requires manual invocation of
|
||||
// createInstance before first use.
|
||||
template<class T>
|
||||
class LLSimpleton
|
||||
{
|
||||
public:
|
||||
template <typename... ARGS>
|
||||
static void createInstance(ARGS&&... args)
|
||||
{
|
||||
llassert(sInstance == nullptr);
|
||||
sInstance = new T(std::forward<ARGS>(args)...);
|
||||
}
|
||||
|
||||
static inline T* getInstance() { return sInstance; }
|
||||
static inline T& instance() { return *getInstance(); }
|
||||
static inline bool instanceExists() { return sInstance != nullptr; }
|
||||
|
||||
static void deleteSingleton()
|
||||
{
|
||||
delete sInstance;
|
||||
sInstance = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
static T* sInstance;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
T* LLSimpleton<T>::sInstance{ nullptr };
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -37,9 +37,6 @@
|
|||
#include <winnls.h> // for WideCharToMultiByte
|
||||
#endif
|
||||
|
||||
LLTrace::BlockTimerStatHandle FT_STRING_FORMAT("String Format");
|
||||
|
||||
|
||||
std::string ll_safe_string(const char* in)
|
||||
{
|
||||
if(in) return std::string(in);
|
||||
|
|
@ -215,7 +212,7 @@ S32 utf16chars_to_wchar(const U16* inchars, llwchar* outchar)
|
|||
return inchars - base;
|
||||
}
|
||||
|
||||
llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len)
|
||||
llutf16string wstring_to_utf16str(const llwchar* utf32str, size_t len)
|
||||
{
|
||||
llutf16string out;
|
||||
|
||||
|
|
@ -237,27 +234,19 @@ llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len)
|
|||
return out;
|
||||
}
|
||||
|
||||
llutf16string wstring_to_utf16str(const LLWString &utf32str)
|
||||
llutf16string utf8str_to_utf16str( const char* utf8str, size_t len )
|
||||
{
|
||||
const S32 len = (S32)utf32str.length();
|
||||
return wstring_to_utf16str(utf32str, len);
|
||||
}
|
||||
|
||||
llutf16string utf8str_to_utf16str ( const std::string& utf8str )
|
||||
{
|
||||
LLWString wstr = utf8str_to_wstring ( utf8str );
|
||||
LLWString wstr = utf8str_to_wstring ( utf8str, len );
|
||||
return wstring_to_utf16str ( wstr );
|
||||
}
|
||||
|
||||
|
||||
LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len)
|
||||
LLWString utf16str_to_wstring(const U16* utf16str, size_t len)
|
||||
{
|
||||
LLWString wout;
|
||||
if((len <= 0) || utf16str.empty()) return wout;
|
||||
if (len == 0) return wout;
|
||||
|
||||
S32 i = 0;
|
||||
// craziness to make gcc happy (llutf16string.c_str() is tweaked on linux):
|
||||
const U16* chars16 = &(*(utf16str.begin()));
|
||||
const U16* chars16 = utf16str;
|
||||
while (i < len)
|
||||
{
|
||||
llwchar cur_char;
|
||||
|
|
@ -267,12 +256,6 @@ LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len)
|
|||
return wout;
|
||||
}
|
||||
|
||||
LLWString utf16str_to_wstring(const llutf16string &utf16str)
|
||||
{
|
||||
const S32 len = (S32)utf16str.length();
|
||||
return utf16str_to_wstring(utf16str, len);
|
||||
}
|
||||
|
||||
// Length in llwchar (UTF-32) of the first len units (16 bits) of the given UTF-16 string.
|
||||
S32 utf16str_wstring_length(const llutf16string &utf16str, const S32 utf16_len)
|
||||
{
|
||||
|
|
@ -392,8 +375,7 @@ S32 wstring_utf8_length(const LLWString& wstr)
|
|||
return len;
|
||||
}
|
||||
|
||||
|
||||
LLWString utf8str_to_wstring(const std::string& utf8str, S32 len)
|
||||
LLWString utf8str_to_wstring(const char* utf8str, size_t len)
|
||||
{
|
||||
LLWString wout;
|
||||
|
||||
|
|
@ -481,13 +463,7 @@ LLWString utf8str_to_wstring(const std::string& utf8str, S32 len)
|
|||
return wout;
|
||||
}
|
||||
|
||||
LLWString utf8str_to_wstring(const std::string& utf8str)
|
||||
{
|
||||
const S32 len = (S32)utf8str.length();
|
||||
return utf8str_to_wstring(utf8str, len);
|
||||
}
|
||||
|
||||
std::string wstring_to_utf8str(const LLWString& utf32str, S32 len)
|
||||
std::string wstring_to_utf8str(const llwchar* utf32str, size_t len)
|
||||
{
|
||||
std::string out;
|
||||
|
||||
|
|
@ -503,20 +479,9 @@ std::string wstring_to_utf8str(const LLWString& utf32str, S32 len)
|
|||
return out;
|
||||
}
|
||||
|
||||
std::string wstring_to_utf8str(const LLWString& utf32str)
|
||||
std::string utf16str_to_utf8str(const U16* utf16str, size_t len)
|
||||
{
|
||||
const S32 len = (S32)utf32str.length();
|
||||
return wstring_to_utf8str(utf32str, len);
|
||||
}
|
||||
|
||||
std::string utf16str_to_utf8str(const llutf16string& utf16str)
|
||||
{
|
||||
return wstring_to_utf8str(utf16str_to_wstring(utf16str));
|
||||
}
|
||||
|
||||
std::string utf16str_to_utf8str(const llutf16string& utf16str, S32 len)
|
||||
{
|
||||
return wstring_to_utf8str(utf16str_to_wstring(utf16str, len), len);
|
||||
return wstring_to_utf8str(utf16str_to_wstring(utf16str, len));
|
||||
}
|
||||
|
||||
std::string utf8str_trim(const std::string& utf8str)
|
||||
|
|
@ -729,17 +694,16 @@ std::string utf8str_removeCRLF(const std::string& utf8str)
|
|||
}
|
||||
|
||||
#if LL_WINDOWS
|
||||
std::string ll_convert_wide_to_string(const wchar_t* in)
|
||||
unsigned int ll_wstring_default_code_page()
|
||||
{
|
||||
return ll_convert_wide_to_string(in, CP_UTF8);
|
||||
return CP_UTF8;
|
||||
}
|
||||
|
||||
std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page)
|
||||
std::string ll_convert_wide_to_string(const wchar_t* in, size_t len_in, unsigned int code_page)
|
||||
{
|
||||
std::string out;
|
||||
if(in)
|
||||
{
|
||||
int len_in = wcslen(in);
|
||||
int len_out = WideCharToMultiByte(
|
||||
code_page,
|
||||
0,
|
||||
|
|
@ -771,12 +735,7 @@ std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page)
|
|||
return out;
|
||||
}
|
||||
|
||||
std::wstring ll_convert_string_to_wide(const std::string& in)
|
||||
{
|
||||
return ll_convert_string_to_wide(in, CP_UTF8);
|
||||
}
|
||||
|
||||
std::wstring ll_convert_string_to_wide(const std::string& in, unsigned int code_page)
|
||||
std::wstring ll_convert_string_to_wide(const char* in, size_t len, unsigned int code_page)
|
||||
{
|
||||
// From review:
|
||||
// We can preallocate a wide char buffer that is the same length (in wchar_t elements) as the utf8 input,
|
||||
|
|
@ -788,10 +747,10 @@ std::wstring ll_convert_string_to_wide(const std::string& in, unsigned int code_
|
|||
|
||||
// reserve an output buffer that will be destroyed on exit, with a place
|
||||
// to put NULL terminator
|
||||
std::vector<wchar_t> w_out(in.length() + 1);
|
||||
std::vector<wchar_t> w_out(len + 1);
|
||||
|
||||
memset(&w_out[0], 0, w_out.size());
|
||||
int real_output_str_len = MultiByteToWideChar(code_page, 0, in.c_str(), in.length(),
|
||||
int real_output_str_len = MultiByteToWideChar(code_page, 0, in, len,
|
||||
&w_out[0], w_out.size() - 1);
|
||||
|
||||
//looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858.
|
||||
|
|
@ -801,30 +760,32 @@ std::wstring ll_convert_string_to_wide(const std::string& in, unsigned int code_
|
|||
return {&w_out[0]};
|
||||
}
|
||||
|
||||
LLWString ll_convert_wide_to_wstring(const std::wstring& in)
|
||||
LLWString ll_convert_wide_to_wstring(const wchar_t* in, size_t len)
|
||||
{
|
||||
// This function, like its converse, is a placeholder, encapsulating a
|
||||
// guilty little hack: the only "official" way nat has found to convert
|
||||
// between std::wstring (16 bits on Windows) and LLWString (UTF-32) is
|
||||
// by using iconv, which we've avoided so far. It kinda sorta works to
|
||||
// just copy individual characters...
|
||||
// The point is that if/when we DO introduce some more official way to
|
||||
// perform such conversions, we should only have to call it here.
|
||||
return { in.begin(), in.end() };
|
||||
// Whether or not std::wstring and llutf16string are distinct types, they
|
||||
// both hold UTF-16LE characters. (See header file comments.) Pretend this
|
||||
// wchar_t* sequence is really a U16* sequence and use the conversion we
|
||||
// define above.
|
||||
return utf16str_to_wstring(reinterpret_cast<const U16*>(in), len);
|
||||
}
|
||||
|
||||
std::wstring ll_convert_wstring_to_wide(const LLWString& in)
|
||||
std::wstring ll_convert_wstring_to_wide(const llwchar* in, size_t len)
|
||||
{
|
||||
// See comments in ll_convert_wide_to_wstring()
|
||||
return { in.begin(), in.end() };
|
||||
// first, convert to llutf16string, for which we have a real implementation
|
||||
auto utf16str{ wstring_to_utf16str(in, len) };
|
||||
// then, because each U16 char must be UTF-16LE encoded, pretend the U16*
|
||||
// string pointer is a wchar_t* and instantiate a std::wstring of the same
|
||||
// length.
|
||||
return { reinterpret_cast<const wchar_t*>(utf16str.c_str()), utf16str.length() };
|
||||
}
|
||||
|
||||
std::string ll_convert_string_to_utf8_string(const std::string& in)
|
||||
{
|
||||
auto w_mesg = ll_convert_string_to_wide(in, CP_ACP);
|
||||
std::string out_utf8(ll_convert_wide_to_string(w_mesg.c_str(), CP_UTF8));
|
||||
|
||||
return out_utf8;
|
||||
// If you pass code_page, you must also pass length, otherwise the code
|
||||
// page parameter will be mistaken for length.
|
||||
auto w_mesg = ll_convert_string_to_wide(in, in.length(), CP_ACP);
|
||||
// CP_UTF8 is default -- see ll_wstring_default_code_page() above.
|
||||
return ll_convert_wide_to_string(w_mesg);
|
||||
}
|
||||
|
||||
namespace
|
||||
|
|
@ -1483,7 +1444,7 @@ bool LLStringUtil::formatDatetime(std::string& replacement, std::string token,
|
|||
template<>
|
||||
S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions)
|
||||
{
|
||||
LL_RECORD_BLOCK_TIME(FT_STRING_FORMAT);
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STRING;
|
||||
S32 res = 0;
|
||||
|
||||
std::string output;
|
||||
|
|
@ -1556,7 +1517,7 @@ S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions)
|
|||
template<>
|
||||
S32 LLStringUtil::format(std::string& s, const LLSD& substitutions)
|
||||
{
|
||||
LL_RECORD_BLOCK_TIME(FT_STRING_FORMAT);
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STRING;
|
||||
S32 res = 0;
|
||||
|
||||
if (!substitutions.isMap())
|
||||
|
|
|
|||
|
|
@ -27,9 +27,11 @@
|
|||
#ifndef LL_LLSTRING_H
|
||||
#define LL_LLSTRING_H
|
||||
|
||||
#include <boost/call_traits.hpp>
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <cwchar> // std::wcslen()
|
||||
//#include <locale>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
|
|
@ -535,14 +537,71 @@ struct ll_convert_impl<T, T>
|
|||
T operator()(const T& in) const { return in; }
|
||||
};
|
||||
|
||||
// simple construction from char*
|
||||
template<typename T>
|
||||
struct ll_convert_impl<T, const typename T::value_type*>
|
||||
{
|
||||
T operator()(const typename T::value_type* in) const { return { in }; }
|
||||
};
|
||||
|
||||
// specialize ll_convert_impl<TO, FROM> to return EXPR
|
||||
#define ll_convert_alias(TO, FROM, EXPR) \
|
||||
template<> \
|
||||
struct ll_convert_impl<TO, FROM> \
|
||||
{ \
|
||||
TO operator()(const FROM& in) const { return EXPR; } \
|
||||
/* param_type optimally passes both char* and string */ \
|
||||
TO operator()(typename boost::call_traits<FROM>::param_type in) const { return EXPR; } \
|
||||
}
|
||||
|
||||
// If all we're doing is copying characters, pass this to ll_convert_alias as
|
||||
// EXPR. Since it expands into the 'return EXPR' slot in the ll_convert_impl
|
||||
// specialization above, it implies TO{ in.begin(), in.end() }.
|
||||
#define LL_CONVERT_COPY_CHARS { in.begin(), in.end() }
|
||||
|
||||
// Generic name for strlen() / wcslen() - the default implementation should
|
||||
// (!) work with U16 and llwchar, but we don't intend to engage it.
|
||||
template <typename CHARTYPE>
|
||||
size_t ll_convert_length(const CHARTYPE* zstr)
|
||||
{
|
||||
const CHARTYPE* zp;
|
||||
// classic C string scan
|
||||
for (zp = zstr; *zp; ++zp)
|
||||
;
|
||||
return (zp - zstr);
|
||||
}
|
||||
|
||||
// specialize where we have a library function; may use intrinsic operations
|
||||
template <>
|
||||
inline size_t ll_convert_length<wchar_t>(const wchar_t* zstr) { return std::wcslen(zstr); }
|
||||
template <>
|
||||
inline size_t ll_convert_length<char> (const char* zstr) { return std::strlen(zstr); }
|
||||
|
||||
// ll_convert_forms() is short for a bunch of boilerplate. It defines
|
||||
// longname(const char*, len), longname(const char*), longname(const string&)
|
||||
// and longname(const string&, len) so calls written pre-ll_convert() will
|
||||
// work. Most of these overloads will be unified once we turn on C++17 and can
|
||||
// use std::string_view.
|
||||
// It also uses aliasmacro to ensure that both ll_convert<OUTSTR>(const char*)
|
||||
// and ll_convert<OUTSTR>(const string&) will work.
|
||||
#define ll_convert_forms(aliasmacro, OUTSTR, INSTR, longname) \
|
||||
LL_COMMON_API OUTSTR longname(const INSTR::value_type* in, size_t len); \
|
||||
inline auto longname(const INSTR& in, size_t len) \
|
||||
{ \
|
||||
return longname(in.c_str(), len); \
|
||||
} \
|
||||
inline auto longname(const INSTR::value_type* in) \
|
||||
{ \
|
||||
return longname(in, ll_convert_length(in)); \
|
||||
} \
|
||||
inline auto longname(const INSTR& in) \
|
||||
{ \
|
||||
return longname(in.c_str(), in.length()); \
|
||||
} \
|
||||
/* string param */ \
|
||||
aliasmacro(OUTSTR, INSTR, longname(in)); \
|
||||
/* char* param */ \
|
||||
aliasmacro(OUTSTR, const INSTR::value_type*, longname(in))
|
||||
|
||||
// Make the incoming string a utf8 string. Replaces any unknown glyph
|
||||
// with the UNKNOWN_CHARACTER. Once any unknown glyph is found, the rest
|
||||
// of the data may not be recovered.
|
||||
|
|
@ -579,63 +638,47 @@ LL_COMMON_API std::string rawstr_to_utf8(const std::string& raw);
|
|||
// LL_WCHAR_T_NATIVE.
|
||||
typedef std::basic_string<U16> llutf16string;
|
||||
|
||||
#if ! defined(LL_WCHAR_T_NATIVE)
|
||||
// wchar_t is identical to U16, and std::wstring is identical to llutf16string.
|
||||
// Defining an ll_convert alias involving llutf16string would collide with the
|
||||
// comparable preferred alias involving std::wstring. (In this scenario, if
|
||||
// you pass llutf16string, it will engage the std::wstring specialization.)
|
||||
#define ll_convert_u16_alias(TO, FROM, EXPR) // nothing
|
||||
#else // defined(LL_WCHAR_T_NATIVE)
|
||||
// wchar_t is a distinct native type, so llutf16string is also a distinct
|
||||
// type, and there IS a point to converting separately to/from llutf16string.
|
||||
// (But why? Windows APIs are still defined in terms of wchar_t, and
|
||||
// in this scenario llutf16string won't work for them!)
|
||||
#define ll_convert_u16_alias(TO, FROM, EXPR) ll_convert_alias(TO, FROM, EXPR)
|
||||
// Considering wchar_t, llwchar and U16, there are three relevant cases:
|
||||
#if LLWCHAR_IS_WCHAR_T // every which way but Windows
|
||||
// llwchar is identical to wchar_t, LLWString is identical to std::wstring.
|
||||
// U16 is distinct, llutf16string is distinct (though pretty useless).
|
||||
// Given conversions to/from LLWString and to/from llutf16string, conversions
|
||||
// involving std::wstring would collide.
|
||||
#define ll_convert_wstr_alias(TO, FROM, EXPR) // nothing
|
||||
// but we can define conversions involving llutf16string without collisions
|
||||
#define ll_convert_u16_alias(TO, FROM, EXPR) ll_convert_alias(TO, FROM, EXPR)
|
||||
|
||||
#if LL_WINDOWS
|
||||
// LL_WCHAR_T_NATIVE is defined on non-Windows systems because, in fact,
|
||||
// wchar_t is native. Everywhere but Windows, we use it for llwchar (see
|
||||
// stdtypes.h). That makes LLWString identical to std::wstring, so these
|
||||
// aliases for std::wstring would collide with those for LLWString. Only
|
||||
// define on Windows, where converting between std::wstring and llutf16string
|
||||
// means copying chars.
|
||||
ll_convert_alias(llutf16string, std::wstring, llutf16string(in.begin(), in.end()));
|
||||
ll_convert_alias(std::wstring, llutf16string, std::wstring(in.begin(), in.end()));
|
||||
#endif // LL_WINDOWS
|
||||
#endif // defined(LL_WCHAR_T_NATIVE)
|
||||
#elif defined(LL_WCHAR_T_NATIVE) // Windows, either clang or MS /Zc:wchar_t
|
||||
// llwchar (32-bit), wchar_t (16-bit) and U16 are all different types.
|
||||
// Conversions to/from LLWString, to/from std::wstring and to/from llutf16string
|
||||
// can all be defined.
|
||||
#define ll_convert_wstr_alias(TO, FROM, EXPR) ll_convert_alias(TO, FROM, EXPR)
|
||||
#define ll_convert_u16_alias(TO, FROM, EXPR) ll_convert_alias(TO, FROM, EXPR)
|
||||
|
||||
LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len);
|
||||
LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str);
|
||||
ll_convert_u16_alias(LLWString, llutf16string, utf16str_to_wstring(in));
|
||||
#else // ! LL_WCHAR_T_NATIVE: Windows with MS /Zc:wchar_t-
|
||||
// wchar_t is identical to U16, std::wstring is identical to llutf16string.
|
||||
// Given conversions to/from LLWString and to/from std::wstring, conversions
|
||||
// involving llutf16string would collide.
|
||||
#define ll_convert_u16_alias(TO, FROM, EXPR) // nothing
|
||||
// but we can define conversions involving std::wstring without collisions
|
||||
#define ll_convert_wstr_alias(TO, FROM, EXPR) ll_convert_alias(TO, FROM, EXPR)
|
||||
#endif
|
||||
|
||||
LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len);
|
||||
LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str);
|
||||
ll_convert_u16_alias(llutf16string, LLWString, wstring_to_utf16str(in));
|
||||
ll_convert_forms(ll_convert_u16_alias, LLWString, llutf16string, utf16str_to_wstring);
|
||||
ll_convert_forms(ll_convert_u16_alias, llutf16string, LLWString, wstring_to_utf16str);
|
||||
ll_convert_forms(ll_convert_u16_alias, llutf16string, std::string, utf8str_to_utf16str);
|
||||
ll_convert_forms(ll_convert_alias, LLWString, std::string, utf8str_to_wstring);
|
||||
|
||||
LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str, S32 len);
|
||||
LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str );
|
||||
ll_convert_u16_alias(llutf16string, std::string, utf8str_to_utf16str(in));
|
||||
|
||||
LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str, S32 len);
|
||||
LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str);
|
||||
// Same function, better name. JC
|
||||
inline LLWString utf8string_to_wstring(const std::string& utf8_string) { return utf8str_to_wstring(utf8_string); }
|
||||
// best name of all
|
||||
ll_convert_alias(LLWString, std::string, utf8string_to_wstring(in));
|
||||
|
||||
//
|
||||
LL_COMMON_API S32 wchar_to_utf8chars(llwchar inchar, char* outchars);
|
||||
|
||||
LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str, S32 len);
|
||||
LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str);
|
||||
ll_convert_alias(std::string, LLWString, wstring_to_utf8str(in));
|
||||
LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len);
|
||||
LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str);
|
||||
ll_convert_u16_alias(std::string, llutf16string, utf16str_to_utf8str(in));
|
||||
ll_convert_forms(ll_convert_alias, std::string, LLWString, wstring_to_utf8str);
|
||||
ll_convert_forms(ll_convert_u16_alias, std::string, llutf16string, utf16str_to_utf8str);
|
||||
|
||||
#if LL_WINDOWS
|
||||
// an older alias for utf16str_to_utf8str(llutf16string)
|
||||
inline std::string wstring_to_utf8str(const llutf16string &utf16str) { return utf16str_to_utf8str(utf16str);}
|
||||
#endif
|
||||
|
||||
// Length of this UTF32 string in bytes when transformed to UTF8
|
||||
LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr);
|
||||
|
|
@ -714,42 +757,48 @@ LL_COMMON_API std::string utf8str_removeCRLF(const std::string& utf8str);
|
|||
//@{
|
||||
|
||||
/**
|
||||
* @brief Convert a wide string to std::string
|
||||
* @brief Convert a wide string to/from std::string
|
||||
* Convert a Windows wide string to/from our LLWString
|
||||
*
|
||||
* This replaces the unsafe W2A macro from ATL.
|
||||
*/
|
||||
LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page);
|
||||
LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in); // default CP_UTF8
|
||||
inline std::string ll_convert_wide_to_string(const std::wstring& in, unsigned int code_page)
|
||||
{
|
||||
return ll_convert_wide_to_string(in.c_str(), code_page);
|
||||
}
|
||||
inline std::string ll_convert_wide_to_string(const std::wstring& in)
|
||||
{
|
||||
return ll_convert_wide_to_string(in.c_str());
|
||||
}
|
||||
ll_convert_alias(std::string, std::wstring, ll_convert_wide_to_string(in));
|
||||
// Avoid requiring this header to #include the Windows header file declaring
|
||||
// our actual default code_page by delegating this function to our .cpp file.
|
||||
LL_COMMON_API unsigned int ll_wstring_default_code_page();
|
||||
|
||||
/**
|
||||
* Converts a string to wide string.
|
||||
*/
|
||||
LL_COMMON_API std::wstring ll_convert_string_to_wide(const std::string& in,
|
||||
unsigned int code_page);
|
||||
LL_COMMON_API std::wstring ll_convert_string_to_wide(const std::string& in);
|
||||
// default CP_UTF8
|
||||
ll_convert_alias(std::wstring, std::string, ll_convert_string_to_wide(in));
|
||||
// This is like ll_convert_forms(), with the added complexity of a code page
|
||||
// parameter that may or may not be passed.
|
||||
#define ll_convert_cp_forms(aliasmacro, OUTSTR, INSTR, longname) \
|
||||
/* declare the only nontrivial implementation (in .cpp file) */ \
|
||||
LL_COMMON_API OUTSTR longname( \
|
||||
const INSTR::value_type* in, \
|
||||
size_t len, \
|
||||
unsigned int code_page=ll_wstring_default_code_page()); \
|
||||
/* if passed only a char pointer, scan for nul terminator */ \
|
||||
inline auto longname(const INSTR::value_type* in) \
|
||||
{ \
|
||||
return longname(in, ll_convert_length(in)); \
|
||||
} \
|
||||
/* if passed string and length, extract its char pointer */ \
|
||||
inline auto longname( \
|
||||
const INSTR& in, \
|
||||
size_t len, \
|
||||
unsigned int code_page=ll_wstring_default_code_page()) \
|
||||
{ \
|
||||
return longname(in.c_str(), len, code_page); \
|
||||
} \
|
||||
/* if passed only a string object, no scan, pass known length */ \
|
||||
inline auto longname(const INSTR& in) \
|
||||
{ \
|
||||
return longname(in.c_str(), in.length()); \
|
||||
} \
|
||||
aliasmacro(OUTSTR, INSTR, longname(in)); \
|
||||
aliasmacro(OUTSTR, const INSTR::value_type*, longname(in))
|
||||
|
||||
/**
|
||||
* Convert a Windows wide string to our LLWString
|
||||
*/
|
||||
LL_COMMON_API LLWString ll_convert_wide_to_wstring(const std::wstring& in);
|
||||
ll_convert_alias(LLWString, std::wstring, ll_convert_wide_to_wstring(in));
|
||||
|
||||
/**
|
||||
* Convert LLWString to Windows wide string
|
||||
*/
|
||||
LL_COMMON_API std::wstring ll_convert_wstring_to_wide(const LLWString& in);
|
||||
ll_convert_alias(std::wstring, LLWString, ll_convert_wstring_to_wide(in));
|
||||
ll_convert_cp_forms(ll_convert_wstr_alias, std::string, std::wstring, ll_convert_wide_to_string);
|
||||
ll_convert_cp_forms(ll_convert_wstr_alias, std::wstring, std::string, ll_convert_string_to_wide);
|
||||
ll_convert_forms(ll_convert_wstr_alias, LLWString, std::wstring, ll_convert_wide_to_wstring);
|
||||
ll_convert_forms(ll_convert_wstr_alias, std::wstring, LLWString, ll_convert_wstring_to_wide);
|
||||
|
||||
/**
|
||||
* Converts incoming string into utf8 string
|
||||
|
|
@ -1950,4 +1999,14 @@ void LLStringUtilBase<T>::truncate(string_type& string, size_type count)
|
|||
string.resize(count < cur_size ? count : cur_size);
|
||||
}
|
||||
|
||||
// The good thing about *declaration* macros, vs. usage macros, is that now
|
||||
// we're done with them: we don't need them to bleed into the consuming source
|
||||
// file.
|
||||
#undef ll_convert_alias
|
||||
#undef ll_convert_u16_alias
|
||||
#undef ll_convert_wstr_alias
|
||||
#undef LL_CONVERT_COPY_CHARS
|
||||
#undef ll_convert_forms
|
||||
#undef ll_convert_cp_forms
|
||||
|
||||
#endif // LL_STRING_H
|
||||
|
|
|
|||
|
|
@ -881,6 +881,7 @@ LLSD LLMemoryInfo::getStatsMap() const
|
|||
|
||||
LLMemoryInfo& LLMemoryInfo::refresh()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED
|
||||
mStatsMap = loadStatsMap();
|
||||
|
||||
LL_DEBUGS("LLMemoryInfo") << "Populated mStatsMap:\n";
|
||||
|
|
@ -890,11 +891,9 @@ LLMemoryInfo& LLMemoryInfo::refresh()
|
|||
return *this;
|
||||
}
|
||||
|
||||
static LLTrace::BlockTimerStatHandle FTM_MEMINFO_LOAD_STATS("MemInfo Load Stats");
|
||||
|
||||
LLSD LLMemoryInfo::loadStatsMap()
|
||||
{
|
||||
LL_RECORD_BLOCK_TIME(FTM_MEMINFO_LOAD_STATS);
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
|
||||
// This implementation is derived from stream() code (as of 2011-06-29).
|
||||
Stats stats;
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@
|
|||
#include "lltrace.h"
|
||||
#include "lltracethreadrecorder.h"
|
||||
#include "llexception.h"
|
||||
#include "fstelemetry.h" // <FS:Beq> allow thread naming
|
||||
|
||||
#if LL_LINUX
|
||||
#include <sched.h>
|
||||
|
|
@ -136,6 +135,8 @@ void LLThread::threadRun()
|
|||
set_thread_name(-1, mName.c_str());
|
||||
#endif
|
||||
|
||||
LL_PROFILER_SET_THREAD_NAME( mName.c_str() );
|
||||
|
||||
// this is the first point at which we're actually running in the new thread
|
||||
mID = currentID();
|
||||
|
||||
|
|
@ -143,14 +144,16 @@ void LLThread::threadRun()
|
|||
mRecorder = new LLTrace::ThreadRecorder(*LLTrace::get_master_thread_recorder());
|
||||
// <FS:Beq> - Add threadnames to telemetry
|
||||
LL_INFOS("THREAD") << "Started thread " << mName << LL_ENDL;
|
||||
FSThreadName( mName.c_str() );
|
||||
LL_PROFILER_SET_THREAD_NAME( mName.c_str() );
|
||||
// </FS:Beq>
|
||||
// Run the user supplied function
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
LL_PROFILER_THREAD_BEGIN(mName.c_str())
|
||||
run();
|
||||
LL_PROFILER_THREAD_END(mName.c_str())
|
||||
}
|
||||
catch (const LLContinueError &e)
|
||||
{
|
||||
|
|
@ -335,6 +338,8 @@ bool LLThread::runCondition(void)
|
|||
// Stop thread execution if requested until unpaused.
|
||||
void LLThread::checkPause()
|
||||
{
|
||||
LL_PROFILER_THREAD_BEGIN(mName.c_str())
|
||||
|
||||
mDataLock->lock();
|
||||
|
||||
// This is in a while loop because the pthread API allows for spurious wakeups.
|
||||
|
|
@ -347,6 +352,8 @@ void LLThread::checkPause()
|
|||
}
|
||||
|
||||
mDataLock->unlock();
|
||||
|
||||
LL_PROFILER_THREAD_END(mName.c_str())
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
|
@ -367,27 +374,34 @@ void LLThread::setQuitting()
|
|||
// <FS:Beq> give this a better chance to inline
|
||||
// LLThread::id_t LLThread::currentID()
|
||||
// {
|
||||
// LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
|
||||
// return std::this_thread::get_id();
|
||||
// }
|
||||
|
||||
// static
|
||||
void LLThread::yield()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
|
||||
std::this_thread::yield();
|
||||
}
|
||||
|
||||
void LLThread::wake()
|
||||
{
|
||||
LL_PROFILER_THREAD_BEGIN(mName.c_str())
|
||||
|
||||
mDataLock->lock();
|
||||
if(!shouldSleep())
|
||||
{
|
||||
mRunCondition->signal();
|
||||
}
|
||||
mDataLock->unlock();
|
||||
|
||||
LL_PROFILER_THREAD_END(mName.c_str())
|
||||
}
|
||||
|
||||
void LLThread::wakeLocked()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
|
||||
if(!shouldSleep())
|
||||
{
|
||||
mRunCondition->signal();
|
||||
|
|
@ -396,11 +410,13 @@ void LLThread::wakeLocked()
|
|||
|
||||
void LLThread::lockData()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
|
||||
mDataLock->lock();
|
||||
}
|
||||
|
||||
void LLThread::unlockData()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD
|
||||
mDataLock->unlock();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* @file llthreadsafequeue.h
|
||||
* @brief Base classes for thread, mutex and condition handling.
|
||||
* @brief Queue protected with mutexes for cross-thread use
|
||||
*
|
||||
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
|
|
@ -27,16 +27,19 @@
|
|||
#ifndef LL_LLTHREADSAFEQUEUE_H
|
||||
#define LL_LLTHREADSAFEQUEUE_H
|
||||
|
||||
#include "llexception.h"
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include "mutex.h"
|
||||
#include "llcoros.h"
|
||||
#include LLCOROS_MUTEX_HEADER
|
||||
#include <boost/fiber/timed_mutex.hpp>
|
||||
#include LLCOROS_CONDVAR_HEADER
|
||||
#include "llexception.h"
|
||||
#include "mutex.h"
|
||||
#include <chrono>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
|
||||
/*****************************************************************************
|
||||
* LLThreadSafeQueue
|
||||
*****************************************************************************/
|
||||
//
|
||||
// A general queue exception.
|
||||
//
|
||||
|
|
@ -66,70 +69,116 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Implements a thread safe FIFO.
|
||||
//
|
||||
template<typename ElementT>
|
||||
/**
|
||||
* Implements a thread safe FIFO.
|
||||
*/
|
||||
// Let the default std::queue default to underlying std::deque. Override if
|
||||
// desired.
|
||||
template<typename ElementT, typename QueueT=std::queue<ElementT>>
|
||||
class LLThreadSafeQueue
|
||||
{
|
||||
public:
|
||||
typedef ElementT value_type;
|
||||
|
||||
// If the pool is set to NULL one will be allocated and managed by this
|
||||
// queue.
|
||||
|
||||
// Limiting the number of pending items prevents unbounded growth of the
|
||||
// underlying queue.
|
||||
LLThreadSafeQueue(U32 capacity = 1024);
|
||||
|
||||
// Add an element to the front of queue (will block if the queue has
|
||||
// reached capacity).
|
||||
virtual ~LLThreadSafeQueue() {}
|
||||
|
||||
// Add an element to the queue (will block if the queue has reached
|
||||
// capacity).
|
||||
//
|
||||
// This call will raise an interrupt error if the queue is closed while
|
||||
// the caller is blocked.
|
||||
void pushFront(ElementT const & element);
|
||||
|
||||
// Try to add an element to the front of queue without blocking. Returns
|
||||
// true only if the element was actually added.
|
||||
bool tryPushFront(ElementT const & element);
|
||||
template <typename T>
|
||||
void push(T&& element);
|
||||
// legacy name
|
||||
void pushFront(ElementT const & element) { return push(element); }
|
||||
|
||||
// Try to add an element to the front of queue, blocking if full but with
|
||||
// timeout. Returns true if the element was added.
|
||||
// Add an element to the queue (will block if the queue has reached
|
||||
// capacity). Return false if the queue is closed before push is possible.
|
||||
template <typename T>
|
||||
bool pushIfOpen(T&& element);
|
||||
|
||||
// Try to add an element to the queue without blocking. Returns
|
||||
// true only if the element was actually added.
|
||||
template <typename T>
|
||||
bool tryPush(T&& element);
|
||||
// legacy name
|
||||
bool tryPushFront(ElementT const & element) { return tryPush(element); }
|
||||
|
||||
// Try to add an element to the queue, blocking if full but with timeout
|
||||
// after specified duration. Returns true if the element was added.
|
||||
// There are potentially two different timeouts involved: how long to try
|
||||
// to lock the mutex, versus how long to wait for the queue to stop being
|
||||
// full. Careful settings for each timeout might be orders of magnitude
|
||||
// apart. However, this method conflates them.
|
||||
template <typename Rep, typename Period, typename T>
|
||||
bool tryPushFor(const std::chrono::duration<Rep, Period>& timeout,
|
||||
T&& element);
|
||||
// legacy name
|
||||
template <typename Rep, typename Period>
|
||||
bool tryPushFrontFor(const std::chrono::duration<Rep, Period>& timeout,
|
||||
ElementT const & element);
|
||||
ElementT const & element) { return tryPushFor(timeout, element); }
|
||||
|
||||
// Pop the element at the end of the queue (will block if the queue is
|
||||
// Try to add an element to the queue, blocking if full but with
|
||||
// timeout at specified time_point. Returns true if the element was added.
|
||||
template <typename Clock, typename Duration, typename T>
|
||||
bool tryPushUntil(const std::chrono::time_point<Clock, Duration>& until,
|
||||
T&& element);
|
||||
// no legacy name because this is a newer method
|
||||
|
||||
// Pop the element at the head of the queue (will block if the queue is
|
||||
// empty).
|
||||
//
|
||||
// This call will raise an interrupt error if the queue is closed while
|
||||
// the caller is blocked.
|
||||
ElementT popBack(void);
|
||||
|
||||
// Pop an element from the end of the queue if there is one available.
|
||||
ElementT pop(void);
|
||||
// legacy name
|
||||
ElementT popBack(void) { return pop(); }
|
||||
|
||||
// Pop an element from the head of the queue if there is one available.
|
||||
// Returns true only if an element was popped.
|
||||
bool tryPopBack(ElementT & element);
|
||||
|
||||
bool tryPop(ElementT & element);
|
||||
// legacy name
|
||||
bool tryPopBack(ElementT & element) { return tryPop(element); }
|
||||
|
||||
// Pop the element at the head of the queue, blocking if empty, with
|
||||
// timeout after specified duration. Returns true if an element was popped.
|
||||
template <typename Rep, typename Period>
|
||||
bool tryPopFor(const std::chrono::duration<Rep, Period>& timeout, ElementT& element);
|
||||
// no legacy name because this is a newer method
|
||||
|
||||
// Pop the element at the head of the queue, blocking if empty, with
|
||||
// timeout at specified time_point. Returns true if an element was popped.
|
||||
template <typename Clock, typename Duration>
|
||||
bool tryPopUntil(const std::chrono::time_point<Clock, Duration>& until,
|
||||
ElementT& element);
|
||||
// no legacy name because this is a newer method
|
||||
|
||||
// Returns the size of the queue.
|
||||
size_t size();
|
||||
|
||||
//Returns the capacity of the queue.
|
||||
U32 capacity() { return mCapacity; }
|
||||
|
||||
// closes the queue:
|
||||
// - every subsequent pushFront() call will throw LLThreadSafeQueueInterrupt
|
||||
// - every subsequent tryPushFront() call will return false
|
||||
// - popBack() calls will return normally until the queue is drained, then
|
||||
// every subsequent popBack() will throw LLThreadSafeQueueInterrupt
|
||||
// - tryPopBack() calls will return normally until the queue is drained,
|
||||
// then every subsequent tryPopBack() call will return false
|
||||
// - every subsequent push() call will throw LLThreadSafeQueueInterrupt
|
||||
// - every subsequent tryPush() call will return false
|
||||
// - pop() calls will return normally until the queue is drained, then
|
||||
// every subsequent pop() will throw LLThreadSafeQueueInterrupt
|
||||
// - tryPop() calls will return normally until the queue is drained,
|
||||
// then every subsequent tryPop() call will return false
|
||||
void close();
|
||||
|
||||
// detect closed state
|
||||
// producer end: are we prevented from pushing any additional items?
|
||||
bool isClosed();
|
||||
// inverse of isClosed()
|
||||
explicit operator bool();
|
||||
// consumer end: are we done, is the queue entirely drained?
|
||||
bool done();
|
||||
|
||||
private:
|
||||
std::deque< ElementT > mStorage;
|
||||
protected:
|
||||
typedef QueueT queue_type;
|
||||
QueueT mStorage;
|
||||
U32 mCapacity;
|
||||
bool mClosed;
|
||||
|
||||
|
|
@ -137,37 +186,154 @@ private:
|
|||
typedef std::unique_lock<decltype(mLock)> lock_t;
|
||||
boost::fibers::condition_variable_any mCapacityCond;
|
||||
boost::fibers::condition_variable_any mEmptyCond;
|
||||
|
||||
enum pop_result { EMPTY, DONE, WAITING, POPPED };
|
||||
// implementation logic, suitable for passing to tryLockUntil()
|
||||
template <typename Clock, typename Duration>
|
||||
pop_result tryPopUntil_(lock_t& lock,
|
||||
const std::chrono::time_point<Clock, Duration>& until,
|
||||
ElementT& element);
|
||||
// if we're able to lock immediately, do so and run the passed callable,
|
||||
// which must accept lock_t& and return bool
|
||||
template <typename CALLABLE>
|
||||
bool tryLock(CALLABLE&& callable);
|
||||
// if we're able to lock before the passed time_point, do so and run the
|
||||
// passed callable, which must accept lock_t& and return bool
|
||||
template <typename Clock, typename Duration, typename CALLABLE>
|
||||
bool tryLockUntil(const std::chrono::time_point<Clock, Duration>& until,
|
||||
CALLABLE&& callable);
|
||||
// while lock is locked, really push the passed element, if we can
|
||||
template <typename T>
|
||||
bool push_(lock_t& lock, T&& element);
|
||||
// while lock is locked, really pop the head element, if we can
|
||||
pop_result pop_(lock_t& lock, ElementT& element);
|
||||
// Is the current head element ready to pop? We say yes; subclass can
|
||||
// override as needed.
|
||||
virtual bool canPop(const ElementT& head) const { return true; }
|
||||
};
|
||||
|
||||
// LLThreadSafeQueue
|
||||
//-----------------------------------------------------------------------------
|
||||
/*****************************************************************************
|
||||
* PriorityQueueAdapter
|
||||
*****************************************************************************/
|
||||
namespace LL
|
||||
{
|
||||
/**
|
||||
* std::priority_queue's API is almost like std::queue, intentionally of
|
||||
* course, but you must access the element about to pop() as top() rather
|
||||
* than as front(). Make an adapter for use with LLThreadSafeQueue.
|
||||
*/
|
||||
template <typename T, typename Container=std::vector<T>,
|
||||
typename Compare=std::less<typename Container::value_type>>
|
||||
class PriorityQueueAdapter
|
||||
{
|
||||
public:
|
||||
// publish all the same types
|
||||
typedef std::priority_queue<T, Container, Compare> queue_type;
|
||||
typedef typename queue_type::container_type container_type;
|
||||
typedef typename queue_type::value_compare value_compare;
|
||||
typedef typename queue_type::value_type value_type;
|
||||
typedef typename queue_type::size_type size_type;
|
||||
typedef typename queue_type::reference reference;
|
||||
typedef typename queue_type::const_reference const_reference;
|
||||
|
||||
template<typename ElementT>
|
||||
LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(U32 capacity) :
|
||||
// Although std::queue defines both const and non-const front()
|
||||
// methods, std::priority_queue defines only const top().
|
||||
const_reference front() const { return mQ.top(); }
|
||||
// std::priority_queue has no equivalent to back(), so it's good that
|
||||
// LLThreadSafeQueue doesn't use it.
|
||||
|
||||
// All the rest of these merely forward to the corresponding
|
||||
// queue_type methods.
|
||||
bool empty() const { return mQ.empty(); }
|
||||
size_type size() const { return mQ.size(); }
|
||||
void push(const value_type& value) { mQ.push(value); }
|
||||
void push(value_type&& value) { mQ.push(std::move(value)); }
|
||||
template <typename... Args>
|
||||
void emplace(Args&&... args) { mQ.emplace(std::forward<Args>(args)...); }
|
||||
void pop() { mQ.pop(); }
|
||||
|
||||
private:
|
||||
queue_type mQ;
|
||||
};
|
||||
} // namespace LL
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* LLThreadSafeQueue implementation
|
||||
*****************************************************************************/
|
||||
template<typename ElementT, typename QueueT>
|
||||
LLThreadSafeQueue<ElementT, QueueT>::LLThreadSafeQueue(U32 capacity) :
|
||||
mCapacity(capacity),
|
||||
mClosed(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
template<typename ElementT>
|
||||
void LLThreadSafeQueue<ElementT>::pushFront(ElementT const & element)
|
||||
// if we're able to lock immediately, do so and run the passed callable, which
|
||||
// must accept lock_t& and return bool
|
||||
template <typename ElementT, typename QueueT>
|
||||
template <typename CALLABLE>
|
||||
bool LLThreadSafeQueue<ElementT, QueueT>::tryLock(CALLABLE&& callable)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
lock_t lock1(mLock, std::defer_lock);
|
||||
if (!lock1.try_lock())
|
||||
return false;
|
||||
|
||||
return std::forward<CALLABLE>(callable)(lock1);
|
||||
}
|
||||
|
||||
|
||||
// if we're able to lock before the passed time_point, do so and run the
|
||||
// passed callable, which must accept lock_t& and return bool
|
||||
template <typename ElementT, typename QueueT>
|
||||
template <typename Clock, typename Duration, typename CALLABLE>
|
||||
bool LLThreadSafeQueue<ElementT, QueueT>::tryLockUntil(
|
||||
const std::chrono::time_point<Clock, Duration>& until,
|
||||
CALLABLE&& callable)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
lock_t lock1(mLock, std::defer_lock);
|
||||
if (!lock1.try_lock_until(until))
|
||||
return false;
|
||||
|
||||
return std::forward<CALLABLE>(callable)(lock1);
|
||||
}
|
||||
|
||||
|
||||
// while lock is locked, really push the passed element, if we can
|
||||
template <typename ElementT, typename QueueT>
|
||||
template <typename T>
|
||||
bool LLThreadSafeQueue<ElementT, QueueT>::push_(lock_t& lock, T&& element)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
if (mStorage.size() >= mCapacity)
|
||||
return false;
|
||||
|
||||
mStorage.push(std::forward<T>(element));
|
||||
lock.unlock();
|
||||
// now that we've pushed, if somebody's been waiting to pop, signal them
|
||||
mEmptyCond.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <typename ElementT, typename QueueT>
|
||||
template <typename T>
|
||||
bool LLThreadSafeQueue<ElementT, QueueT>::pushIfOpen(T&& element)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
lock_t lock1(mLock);
|
||||
while (true)
|
||||
{
|
||||
// On the producer side, it doesn't matter whether the queue has been
|
||||
// drained or not: the moment either end calls close(), further push()
|
||||
// operations will fail.
|
||||
if (mClosed)
|
||||
{
|
||||
LLTHROW(LLThreadSafeQueueInterrupt());
|
||||
}
|
||||
return false;
|
||||
|
||||
if (mStorage.size() < mCapacity)
|
||||
{
|
||||
mStorage.push_front(element);
|
||||
lock1.unlock();
|
||||
mEmptyCond.notify_one();
|
||||
return;
|
||||
}
|
||||
if (push_(lock1, std::forward<T>(element)))
|
||||
return true;
|
||||
|
||||
// Storage Full. Wait for signal.
|
||||
mCapacityCond.wait(lock1);
|
||||
|
|
@ -175,39 +341,205 @@ void LLThreadSafeQueue<ElementT>::pushFront(ElementT const & element)
|
|||
}
|
||||
|
||||
|
||||
template <typename ElementT>
|
||||
template <typename Rep, typename Period>
|
||||
bool LLThreadSafeQueue<ElementT>::tryPushFrontFor(const std::chrono::duration<Rep, Period>& timeout,
|
||||
ElementT const & element)
|
||||
template <typename ElementT, typename QueueT>
|
||||
template<typename T>
|
||||
void LLThreadSafeQueue<ElementT, QueueT>::push(T&& element)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
if (! pushIfOpen(std::forward<T>(element)))
|
||||
{
|
||||
LLTHROW(LLThreadSafeQueueInterrupt());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename ElementT, typename QueueT>
|
||||
template<typename T>
|
||||
bool LLThreadSafeQueue<ElementT, QueueT>::tryPush(T&& element)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
return tryLock(
|
||||
[this, element=std::move(element)](lock_t& lock)
|
||||
{
|
||||
if (mClosed)
|
||||
return false;
|
||||
return push_(lock, std::move(element));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
template <typename ElementT, typename QueueT>
|
||||
template <typename Rep, typename Period, typename T>
|
||||
bool LLThreadSafeQueue<ElementT, QueueT>::tryPushFor(
|
||||
const std::chrono::duration<Rep, Period>& timeout,
|
||||
T&& element)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
// Convert duration to time_point: passing the same timeout duration to
|
||||
// each of multiple calls is wrong.
|
||||
auto endpoint = std::chrono::steady_clock::now() + timeout;
|
||||
return tryPushUntil(std::chrono::steady_clock::now() + timeout,
|
||||
std::forward<T>(element));
|
||||
}
|
||||
|
||||
lock_t lock1(mLock, std::defer_lock);
|
||||
if (!lock1.try_lock_until(endpoint))
|
||||
return false;
|
||||
|
||||
template <typename ElementT, typename QueueT>
|
||||
template <typename Clock, typename Duration, typename T>
|
||||
bool LLThreadSafeQueue<ElementT, QueueT>::tryPushUntil(
|
||||
const std::chrono::time_point<Clock, Duration>& until,
|
||||
T&& element)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
return tryLockUntil(
|
||||
until,
|
||||
[this, until, element=std::move(element)](lock_t& lock)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (mClosed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (push_(lock, std::move(element)))
|
||||
return true;
|
||||
|
||||
// Storage Full. Wait for signal.
|
||||
if (LLCoros::cv_status::timeout == mCapacityCond.wait_until(lock, until))
|
||||
{
|
||||
// timed out -- formally we might recheck both conditions above
|
||||
return false;
|
||||
}
|
||||
// If we didn't time out, we were notified for some reason. Loop back
|
||||
// to check.
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// while lock is locked, really pop the head element, if we can
|
||||
template <typename ElementT, typename QueueT>
|
||||
typename LLThreadSafeQueue<ElementT, QueueT>::pop_result
|
||||
LLThreadSafeQueue<ElementT, QueueT>::pop_(lock_t& lock, ElementT& element)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
// If mStorage is empty, there's no head element.
|
||||
if (mStorage.empty())
|
||||
return mClosed? DONE : EMPTY;
|
||||
|
||||
// If there's a head element, pass it to canPop() to see if it's ready to pop.
|
||||
if (! canPop(mStorage.front()))
|
||||
return WAITING;
|
||||
|
||||
// std::queue::front() is the element about to pop()
|
||||
element = mStorage.front();
|
||||
mStorage.pop();
|
||||
lock.unlock();
|
||||
// now that we've popped, if somebody's been waiting to push, signal them
|
||||
mCapacityCond.notify_one();
|
||||
return POPPED;
|
||||
}
|
||||
|
||||
|
||||
template<typename ElementT, typename QueueT>
|
||||
ElementT LLThreadSafeQueue<ElementT, QueueT>::pop(void)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
lock_t lock1(mLock);
|
||||
ElementT value;
|
||||
while (true)
|
||||
{
|
||||
if (mClosed)
|
||||
// On the consumer side, we always try to pop before checking mClosed
|
||||
// so we can finish draining the queue.
|
||||
pop_result popped = pop_(lock1, value);
|
||||
if (popped == POPPED)
|
||||
return std::move(value);
|
||||
|
||||
// Once the queue is DONE, there will never be any more coming.
|
||||
if (popped == DONE)
|
||||
{
|
||||
return false;
|
||||
LLTHROW(LLThreadSafeQueueInterrupt());
|
||||
}
|
||||
|
||||
if (mStorage.size() < mCapacity)
|
||||
// If we didn't pop because WAITING, i.e. canPop() returned false,
|
||||
// then even if the producer end has been closed, there's still at
|
||||
// least one item to drain: wait for it. Or we might be EMPTY, with
|
||||
// the queue still open. Either way, wait for signal.
|
||||
mEmptyCond.wait(lock1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename ElementT, typename QueueT>
|
||||
bool LLThreadSafeQueue<ElementT, QueueT>::tryPop(ElementT & element)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
return tryLock(
|
||||
[this, &element](lock_t& lock)
|
||||
{
|
||||
mStorage.push_front(element);
|
||||
lock1.unlock();
|
||||
mEmptyCond.notify_one();
|
||||
return true;
|
||||
// conflate EMPTY, DONE, WAITING: tryPop() behavior when the queue
|
||||
// is closed is implemented by simple inability to push any new
|
||||
// elements
|
||||
return pop_(lock, element) == POPPED;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
template <typename ElementT, typename QueueT>
|
||||
template <typename Rep, typename Period>
|
||||
bool LLThreadSafeQueue<ElementT, QueueT>::tryPopFor(
|
||||
const std::chrono::duration<Rep, Period>& timeout,
|
||||
ElementT& element)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
// Convert duration to time_point: passing the same timeout duration to
|
||||
// each of multiple calls is wrong.
|
||||
return tryPopUntil(std::chrono::steady_clock::now() + timeout, element);
|
||||
}
|
||||
|
||||
|
||||
template <typename ElementT, typename QueueT>
|
||||
template <typename Clock, typename Duration>
|
||||
bool LLThreadSafeQueue<ElementT, QueueT>::tryPopUntil(
|
||||
const std::chrono::time_point<Clock, Duration>& until,
|
||||
ElementT& element)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
return tryLockUntil(
|
||||
until,
|
||||
[this, until, &element](lock_t& lock)
|
||||
{
|
||||
// conflate EMPTY, DONE, WAITING
|
||||
return tryPopUntil_(lock, until, element) == POPPED;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// body of tryPopUntil(), called once we have the lock
|
||||
template <typename ElementT, typename QueueT>
|
||||
template <typename Clock, typename Duration>
|
||||
typename LLThreadSafeQueue<ElementT, QueueT>::pop_result
|
||||
LLThreadSafeQueue<ElementT, QueueT>::tryPopUntil_(
|
||||
lock_t& lock,
|
||||
const std::chrono::time_point<Clock, Duration>& until,
|
||||
ElementT& element)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
while (true)
|
||||
{
|
||||
pop_result popped = pop_(lock, element);
|
||||
if (popped == POPPED || popped == DONE)
|
||||
{
|
||||
// If we succeeded, great! If we've drained the last item, so be
|
||||
// it. Either way, break the loop and tell caller.
|
||||
return popped;
|
||||
}
|
||||
|
||||
// Storage Full. Wait for signal.
|
||||
if (LLCoros::cv_status::timeout == mCapacityCond.wait_until(lock1, endpoint))
|
||||
// EMPTY or WAITING: wait for signal.
|
||||
if (LLCoros::cv_status::timeout == mEmptyCond.wait_until(lock, until))
|
||||
{
|
||||
// timed out -- formally we might recheck both conditions above
|
||||
return false;
|
||||
// timed out -- formally we might recheck
|
||||
// as it is, break loop
|
||||
return popped;
|
||||
}
|
||||
// If we didn't time out, we were notified for some reason. Loop back
|
||||
// to check.
|
||||
|
|
@ -215,102 +547,44 @@ bool LLThreadSafeQueue<ElementT>::tryPushFrontFor(const std::chrono::duration<Re
|
|||
}
|
||||
|
||||
|
||||
template<typename ElementT>
|
||||
bool LLThreadSafeQueue<ElementT>::tryPushFront(ElementT const & element)
|
||||
{
|
||||
lock_t lock1(mLock, std::defer_lock);
|
||||
if (!lock1.try_lock())
|
||||
return false;
|
||||
|
||||
if (mClosed)
|
||||
return false;
|
||||
|
||||
if (mStorage.size() >= mCapacity)
|
||||
return false;
|
||||
|
||||
mStorage.push_front(element);
|
||||
lock1.unlock();
|
||||
mEmptyCond.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template<typename ElementT>
|
||||
ElementT LLThreadSafeQueue<ElementT>::popBack(void)
|
||||
{
|
||||
lock_t lock1(mLock);
|
||||
while (true)
|
||||
{
|
||||
if (!mStorage.empty())
|
||||
{
|
||||
ElementT value = mStorage.back();
|
||||
mStorage.pop_back();
|
||||
lock1.unlock();
|
||||
mCapacityCond.notify_one();
|
||||
return value;
|
||||
}
|
||||
|
||||
if (mClosed)
|
||||
{
|
||||
LLTHROW(LLThreadSafeQueueInterrupt());
|
||||
}
|
||||
|
||||
// Storage empty. Wait for signal.
|
||||
mEmptyCond.wait(lock1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename ElementT>
|
||||
bool LLThreadSafeQueue<ElementT>::tryPopBack(ElementT & element)
|
||||
{
|
||||
lock_t lock1(mLock, std::defer_lock);
|
||||
if (!lock1.try_lock())
|
||||
return false;
|
||||
|
||||
// no need to check mClosed: tryPopBack() behavior when the queue is
|
||||
// closed is implemented by simple inability to push any new elements
|
||||
if (mStorage.empty())
|
||||
return false;
|
||||
|
||||
element = mStorage.back();
|
||||
mStorage.pop_back();
|
||||
lock1.unlock();
|
||||
mCapacityCond.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template<typename ElementT>
|
||||
size_t LLThreadSafeQueue<ElementT>::size(void)
|
||||
template<typename ElementT, typename QueueT>
|
||||
size_t LLThreadSafeQueue<ElementT, QueueT>::size(void)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
lock_t lock(mLock);
|
||||
return mStorage.size();
|
||||
}
|
||||
|
||||
template<typename ElementT>
|
||||
void LLThreadSafeQueue<ElementT>::close()
|
||||
|
||||
template<typename ElementT, typename QueueT>
|
||||
void LLThreadSafeQueue<ElementT, QueueT>::close()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
lock_t lock(mLock);
|
||||
mClosed = true;
|
||||
lock.unlock();
|
||||
// wake up any blocked popBack() calls
|
||||
// wake up any blocked pop() calls
|
||||
mEmptyCond.notify_all();
|
||||
// wake up any blocked pushFront() calls
|
||||
// wake up any blocked push() calls
|
||||
mCapacityCond.notify_all();
|
||||
}
|
||||
|
||||
template<typename ElementT>
|
||||
bool LLThreadSafeQueue<ElementT>::isClosed()
|
||||
|
||||
template<typename ElementT, typename QueueT>
|
||||
bool LLThreadSafeQueue<ElementT, QueueT>::isClosed()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
lock_t lock(mLock);
|
||||
return mClosed && mStorage.size() == 0;
|
||||
return mClosed;
|
||||
}
|
||||
|
||||
template<typename ElementT>
|
||||
LLThreadSafeQueue<ElementT>::operator bool()
|
||||
|
||||
template<typename ElementT, typename QueueT>
|
||||
bool LLThreadSafeQueue<ElementT, QueueT>::done()
|
||||
{
|
||||
return ! isClosed();
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
|
||||
lock_t lock(mLock);
|
||||
return mClosed && mStorage.empty();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ TimeBlockTreeNode::TimeBlockTreeNode()
|
|||
|
||||
void TimeBlockTreeNode::setParent( BlockTimerStatHandle* parent )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
llassert_always(parent != mBlock);
|
||||
llassert_always(parent != NULL);
|
||||
|
||||
|
|
|
|||
|
|
@ -245,6 +245,7 @@ public:
|
|||
|
||||
void setName(const char* name)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
mName = name;
|
||||
setKey(name);
|
||||
}
|
||||
|
|
@ -252,12 +253,14 @@ public:
|
|||
/*virtual*/ const char* getUnitLabel() const { return "KB"; }
|
||||
|
||||
StatType<MemAccumulator::AllocationFacet>& allocations()
|
||||
{
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return static_cast<StatType<MemAccumulator::AllocationFacet>&>(*(StatType<MemAccumulator>*)this);
|
||||
}
|
||||
|
||||
StatType<MemAccumulator::DeallocationFacet>& deallocations()
|
||||
{
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return static_cast<StatType<MemAccumulator::DeallocationFacet>&>(*(StatType<MemAccumulator>*)this);
|
||||
}
|
||||
};
|
||||
|
|
@ -279,6 +282,7 @@ struct MeasureMem<T, typename T::mem_trackable_tag_t, IS_BYTES>
|
|||
{
|
||||
static size_t measureFootprint(const T& value)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return sizeof(T) + value.getMemFootprint();
|
||||
}
|
||||
};
|
||||
|
|
@ -288,6 +292,7 @@ struct MeasureMem<T, IS_MEM_TRACKABLE, typename T::is_unit_t>
|
|||
{
|
||||
static size_t measureFootprint(const T& value)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return U32Bytes(value).value();
|
||||
}
|
||||
};
|
||||
|
|
@ -297,6 +302,7 @@ struct MeasureMem<T*, IS_MEM_TRACKABLE, IS_BYTES>
|
|||
{
|
||||
static size_t measureFootprint(const T* value)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
if (!value)
|
||||
{
|
||||
return 0;
|
||||
|
|
@ -341,6 +347,7 @@ struct MeasureMem<std::basic_string<T>, IS_MEM_TRACKABLE, IS_BYTES>
|
|||
{
|
||||
static size_t measureFootprint(const std::basic_string<T>& value)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return value.capacity() * sizeof(T);
|
||||
}
|
||||
};
|
||||
|
|
@ -349,6 +356,7 @@ struct MeasureMem<std::basic_string<T>, IS_MEM_TRACKABLE, IS_BYTES>
|
|||
template<typename T>
|
||||
inline void claim_alloc(MemStatHandle& measurement, const T& value)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
#if LL_TRACE_ENABLED
|
||||
S32 size = MeasureMem<T>::measureFootprint(value);
|
||||
if(size == 0) return;
|
||||
|
|
@ -361,6 +369,7 @@ inline void claim_alloc(MemStatHandle& measurement, const T& value)
|
|||
template<typename T>
|
||||
inline void disclaim_alloc(MemStatHandle& measurement, const T& value)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
#if LL_TRACE_ENABLED
|
||||
S32 size = MeasureMem<T>::measureFootprint(value);
|
||||
if(size == 0) return;
|
||||
|
|
@ -370,141 +379,6 @@ inline void disclaim_alloc(MemStatHandle& measurement, const T& value)
|
|||
#endif
|
||||
}
|
||||
|
||||
template<typename DERIVED, size_t ALIGNMENT = LL_DEFAULT_HEAP_ALIGN>
|
||||
class MemTrackableNonVirtual
|
||||
{
|
||||
public:
|
||||
typedef void mem_trackable_tag_t;
|
||||
|
||||
MemTrackableNonVirtual(const char* name)
|
||||
#if LL_TRACE_ENABLED
|
||||
: mMemFootprint(0)
|
||||
#endif
|
||||
{
|
||||
#if LL_TRACE_ENABLED
|
||||
static bool name_initialized = false;
|
||||
if (!name_initialized)
|
||||
{
|
||||
name_initialized = true;
|
||||
sMemStat.setName(name);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if LL_TRACE_ENABLED
|
||||
~MemTrackableNonVirtual()
|
||||
{
|
||||
disclaimMem(mMemFootprint);
|
||||
}
|
||||
|
||||
static MemStatHandle& getMemStatHandle()
|
||||
{
|
||||
return sMemStat;
|
||||
}
|
||||
|
||||
S32 getMemFootprint() const { return mMemFootprint; }
|
||||
#endif
|
||||
|
||||
void* operator new(size_t size)
|
||||
{
|
||||
#if LL_TRACE_ENABLED
|
||||
claim_alloc(sMemStat, size);
|
||||
#endif
|
||||
return ll_aligned_malloc<ALIGNMENT>(size);
|
||||
}
|
||||
|
||||
template<int CUSTOM_ALIGNMENT>
|
||||
static void* aligned_new(size_t size)
|
||||
{
|
||||
#if LL_TRACE_ENABLED
|
||||
claim_alloc(sMemStat, size);
|
||||
#endif
|
||||
return ll_aligned_malloc<CUSTOM_ALIGNMENT>(size);
|
||||
}
|
||||
|
||||
void operator delete(void* ptr, size_t size)
|
||||
{
|
||||
#if LL_TRACE_ENABLED
|
||||
disclaim_alloc(sMemStat, size);
|
||||
#endif
|
||||
ll_aligned_free<ALIGNMENT>(ptr);
|
||||
}
|
||||
|
||||
template<int CUSTOM_ALIGNMENT>
|
||||
static void aligned_delete(void* ptr, size_t size)
|
||||
{
|
||||
#if LL_TRACE_ENABLED
|
||||
disclaim_alloc(sMemStat, size);
|
||||
#endif
|
||||
ll_aligned_free<CUSTOM_ALIGNMENT>(ptr);
|
||||
}
|
||||
|
||||
void* operator new [](size_t size)
|
||||
{
|
||||
#if LL_TRACE_ENABLED
|
||||
claim_alloc(sMemStat, size);
|
||||
#endif
|
||||
return ll_aligned_malloc<ALIGNMENT>(size);
|
||||
}
|
||||
|
||||
void operator delete[](void* ptr, size_t size)
|
||||
{
|
||||
#if LL_TRACE_ENABLED
|
||||
disclaim_alloc(sMemStat, size);
|
||||
#endif
|
||||
ll_aligned_free<ALIGNMENT>(ptr);
|
||||
}
|
||||
|
||||
// claim memory associated with other objects/data as our own, adding to our calculated footprint
|
||||
template<typename CLAIM_T>
|
||||
void claimMem(const CLAIM_T& value) const
|
||||
{
|
||||
#if LL_TRACE_ENABLED
|
||||
S32 size = MeasureMem<CLAIM_T>::measureFootprint(value);
|
||||
claim_alloc(sMemStat, size);
|
||||
mMemFootprint += size;
|
||||
#endif
|
||||
}
|
||||
|
||||
// remove memory we had claimed from our calculated footprint
|
||||
template<typename CLAIM_T>
|
||||
void disclaimMem(const CLAIM_T& value) const
|
||||
{
|
||||
#if LL_TRACE_ENABLED
|
||||
S32 size = MeasureMem<CLAIM_T>::measureFootprint(value);
|
||||
disclaim_alloc(sMemStat, size);
|
||||
mMemFootprint -= size;
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
#if LL_TRACE_ENABLED
|
||||
// use signed values so that we can temporarily go negative
|
||||
// and reconcile in destructor
|
||||
// NB: this assumes that no single class is responsible for > 2GB of allocations
|
||||
mutable S32 mMemFootprint;
|
||||
|
||||
static MemStatHandle sMemStat;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#if LL_TRACE_ENABLED
|
||||
template<typename DERIVED, size_t ALIGNMENT>
|
||||
MemStatHandle MemTrackableNonVirtual<DERIVED, ALIGNMENT>::sMemStat(typeid(MemTrackableNonVirtual<DERIVED, ALIGNMENT>).name());
|
||||
#endif
|
||||
|
||||
template<typename DERIVED, size_t ALIGNMENT = LL_DEFAULT_HEAP_ALIGN>
|
||||
class MemTrackable : public MemTrackableNonVirtual<DERIVED, ALIGNMENT>
|
||||
{
|
||||
public:
|
||||
MemTrackable(const char* name)
|
||||
: MemTrackableNonVirtual<DERIVED, ALIGNMENT>(name)
|
||||
{}
|
||||
|
||||
virtual ~MemTrackable()
|
||||
{}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // LL_LLTRACE_H
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ extern MemStatHandle gTraceMemStat;
|
|||
|
||||
AccumulatorBufferGroup::AccumulatorBufferGroup()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
claim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator));
|
||||
claim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator));
|
||||
claim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator));
|
||||
|
|
@ -55,6 +56,7 @@ AccumulatorBufferGroup::AccumulatorBufferGroup(const AccumulatorBufferGroup& oth
|
|||
mStackTimers(other.mStackTimers),
|
||||
mMemStats(other.mMemStats)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
claim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator));
|
||||
claim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator));
|
||||
claim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator));
|
||||
|
|
@ -64,6 +66,7 @@ AccumulatorBufferGroup::AccumulatorBufferGroup(const AccumulatorBufferGroup& oth
|
|||
|
||||
AccumulatorBufferGroup::~AccumulatorBufferGroup()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
disclaim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator));
|
||||
disclaim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator));
|
||||
disclaim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator));
|
||||
|
|
@ -73,6 +76,7 @@ AccumulatorBufferGroup::~AccumulatorBufferGroup()
|
|||
|
||||
void AccumulatorBufferGroup::handOffTo(AccumulatorBufferGroup& other)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
other.mCounts.reset(&mCounts);
|
||||
other.mSamples.reset(&mSamples);
|
||||
other.mEvents.reset(&mEvents);
|
||||
|
|
@ -82,6 +86,7 @@ void AccumulatorBufferGroup::handOffTo(AccumulatorBufferGroup& other)
|
|||
|
||||
void AccumulatorBufferGroup::makeCurrent()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
mCounts.makeCurrent();
|
||||
mSamples.makeCurrent();
|
||||
mEvents.makeCurrent();
|
||||
|
|
@ -104,6 +109,7 @@ void AccumulatorBufferGroup::makeCurrent()
|
|||
//static
|
||||
void AccumulatorBufferGroup::clearCurrent()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
AccumulatorBuffer<CountAccumulator>::clearCurrent();
|
||||
AccumulatorBuffer<SampleAccumulator>::clearCurrent();
|
||||
AccumulatorBuffer<EventAccumulator>::clearCurrent();
|
||||
|
|
@ -118,6 +124,7 @@ bool AccumulatorBufferGroup::isCurrent() const
|
|||
|
||||
void AccumulatorBufferGroup::append( const AccumulatorBufferGroup& other )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
mCounts.addSamples(other.mCounts, SEQUENTIAL);
|
||||
mSamples.addSamples(other.mSamples, SEQUENTIAL);
|
||||
mEvents.addSamples(other.mEvents, SEQUENTIAL);
|
||||
|
|
@ -127,6 +134,7 @@ void AccumulatorBufferGroup::append( const AccumulatorBufferGroup& other )
|
|||
|
||||
void AccumulatorBufferGroup::merge( const AccumulatorBufferGroup& other)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
mCounts.addSamples(other.mCounts, NON_SEQUENTIAL);
|
||||
mSamples.addSamples(other.mSamples, NON_SEQUENTIAL);
|
||||
mEvents.addSamples(other.mEvents, NON_SEQUENTIAL);
|
||||
|
|
@ -137,6 +145,7 @@ void AccumulatorBufferGroup::merge( const AccumulatorBufferGroup& other)
|
|||
|
||||
void AccumulatorBufferGroup::reset(AccumulatorBufferGroup* other)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
mCounts.reset(other ? &other->mCounts : NULL);
|
||||
mSamples.reset(other ? &other->mSamples : NULL);
|
||||
mEvents.reset(other ? &other->mEvents : NULL);
|
||||
|
|
@ -146,6 +155,7 @@ void AccumulatorBufferGroup::reset(AccumulatorBufferGroup* other)
|
|||
|
||||
void AccumulatorBufferGroup::sync()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
if (isCurrent())
|
||||
{
|
||||
F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds();
|
||||
|
|
@ -190,7 +200,7 @@ F64 SampleAccumulator::mergeSumsOfSquares(const SampleAccumulator& a, const Samp
|
|||
|
||||
void SampleAccumulator::addSamples( const SampleAccumulator& other, EBufferAppendType append_type )
|
||||
{
|
||||
if (append_type == NON_SEQUENTIAL)
|
||||
if (append_type == NON_SEQUENTIAL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -289,7 +299,7 @@ void EventAccumulator::addSamples( const EventAccumulator& other, EBufferAppendT
|
|||
|
||||
void EventAccumulator::reset( const EventAccumulator* other )
|
||||
{
|
||||
mNumSamples = 0;
|
||||
mNumSamples = 0;
|
||||
mSum = 0;
|
||||
mMin = F32(NaN);
|
||||
mMax = F32(NaN);
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ namespace LLTrace
|
|||
: mStorageSize(0),
|
||||
mStorage(NULL)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
const AccumulatorBuffer& other = *getDefaultBuffer();
|
||||
resize(sNextStorageSlot);
|
||||
for (S32 i = 0; i < sNextStorageSlot; i++)
|
||||
|
|
@ -76,6 +77,7 @@ namespace LLTrace
|
|||
|
||||
~AccumulatorBuffer()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
if (isCurrent())
|
||||
{
|
||||
LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL);
|
||||
|
|
@ -98,6 +100,7 @@ namespace LLTrace
|
|||
: mStorageSize(0),
|
||||
mStorage(NULL)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
resize(sNextStorageSlot);
|
||||
for (S32 i = 0; i < sNextStorageSlot; i++)
|
||||
{
|
||||
|
|
@ -107,6 +110,7 @@ namespace LLTrace
|
|||
|
||||
void addSamples(const AccumulatorBuffer<ACCUMULATOR>& other, EBufferAppendType append_type)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot);
|
||||
for (size_t i = 0; i < sNextStorageSlot; i++)
|
||||
{
|
||||
|
|
@ -116,6 +120,7 @@ namespace LLTrace
|
|||
|
||||
void copyFrom(const AccumulatorBuffer<ACCUMULATOR>& other)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot);
|
||||
for (size_t i = 0; i < sNextStorageSlot; i++)
|
||||
{
|
||||
|
|
@ -125,6 +130,7 @@ namespace LLTrace
|
|||
|
||||
void reset(const AccumulatorBuffer<ACCUMULATOR>* other = NULL)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
llassert(mStorageSize >= sNextStorageSlot);
|
||||
for (size_t i = 0; i < sNextStorageSlot; i++)
|
||||
{
|
||||
|
|
@ -134,6 +140,7 @@ namespace LLTrace
|
|||
|
||||
void sync(F64SecondsImplicit time_stamp)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
llassert(mStorageSize >= sNextStorageSlot);
|
||||
for (size_t i = 0; i < sNextStorageSlot; i++)
|
||||
{
|
||||
|
|
@ -153,12 +160,13 @@ namespace LLTrace
|
|||
|
||||
static void clearCurrent()
|
||||
{
|
||||
LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL);
|
||||
LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL);
|
||||
}
|
||||
|
||||
// NOTE: this is not thread-safe. We assume that slots are reserved in the main thread before any child threads are spawned
|
||||
size_t reserveSlot()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
size_t next_slot = sNextStorageSlot++;
|
||||
if (next_slot >= mStorageSize)
|
||||
{
|
||||
|
|
@ -172,6 +180,7 @@ namespace LLTrace
|
|||
|
||||
void resize(size_t new_size)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
if (new_size <= mStorageSize) return;
|
||||
|
||||
ACCUMULATOR* old_storage = mStorage;
|
||||
|
|
@ -212,6 +221,7 @@ namespace LLTrace
|
|||
|
||||
static self_t* getDefaultBuffer()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
static bool sInitialized = false;
|
||||
if (!sInitialized)
|
||||
{
|
||||
|
|
@ -326,6 +336,7 @@ namespace LLTrace
|
|||
|
||||
void sample(F64 value)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds();
|
||||
|
||||
// store effect of last value
|
||||
|
|
@ -444,9 +455,9 @@ namespace LLTrace
|
|||
S32 mNumSamples;
|
||||
};
|
||||
|
||||
class TimeBlockAccumulator
|
||||
class alignas(32) TimeBlockAccumulator
|
||||
{
|
||||
public:
|
||||
public:
|
||||
typedef F64Seconds value_t;
|
||||
static F64Seconds getDefaultValue() { return F64Seconds(0); }
|
||||
|
||||
|
|
@ -539,6 +550,7 @@ namespace LLTrace
|
|||
|
||||
void addSamples(const MemAccumulator& other, EBufferAppendType append_type)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
mAllocations.addSamples(other.mAllocations, append_type);
|
||||
mDeallocations.addSamples(other.mDeallocations, append_type);
|
||||
|
||||
|
|
@ -557,6 +569,7 @@ namespace LLTrace
|
|||
|
||||
void reset(const MemAccumulator* other)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
mSize.reset(other ? &other->mSize : NULL);
|
||||
mAllocations.reset(other ? &other->mAllocations : NULL);
|
||||
mDeallocations.reset(other ? &other->mDeallocations : NULL);
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ Recording::Recording(EPlayState state)
|
|||
: mElapsedSeconds(0),
|
||||
mActiveBuffers(NULL)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
claim_alloc(gTraceMemStat, this);
|
||||
mBuffers = new AccumulatorBufferGroup();
|
||||
claim_alloc(gTraceMemStat, mBuffers);
|
||||
|
|
@ -59,12 +60,14 @@ Recording::Recording(EPlayState state)
|
|||
Recording::Recording( const Recording& other )
|
||||
: mActiveBuffers(NULL)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
claim_alloc(gTraceMemStat, this);
|
||||
*this = other;
|
||||
}
|
||||
|
||||
Recording& Recording::operator = (const Recording& other)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
// this will allow us to seamlessly start without affecting any data we've acquired from other
|
||||
setPlayState(PAUSED);
|
||||
|
||||
|
|
@ -85,6 +88,7 @@ Recording& Recording::operator = (const Recording& other)
|
|||
|
||||
Recording::~Recording()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
disclaim_alloc(gTraceMemStat, this);
|
||||
disclaim_alloc(gTraceMemStat, mBuffers);
|
||||
|
||||
|
|
@ -103,6 +107,7 @@ void Recording::update()
|
|||
#if LL_TRACE_ENABLED
|
||||
if (isStarted())
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
|
||||
|
||||
// must have
|
||||
|
|
@ -123,6 +128,7 @@ void Recording::update()
|
|||
|
||||
void Recording::handleReset()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
#if LL_TRACE_ENABLED
|
||||
mBuffers.write()->reset();
|
||||
|
||||
|
|
@ -133,6 +139,7 @@ void Recording::handleReset()
|
|||
|
||||
void Recording::handleStart()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
#if LL_TRACE_ENABLED
|
||||
mSamplingTimer.reset();
|
||||
mBuffers.setStayUnique(true);
|
||||
|
|
@ -144,6 +151,7 @@ void Recording::handleStart()
|
|||
|
||||
void Recording::handleStop()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
#if LL_TRACE_ENABLED
|
||||
mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
|
||||
// must have thread recorder running on this thread
|
||||
|
|
@ -273,7 +281,7 @@ F64Kilobytes Recording::getMean(const StatType<MemAccumulator>& stat)
|
|||
|
||||
F64Kilobytes Recording::getMax(const StatType<MemAccumulator>& stat)
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
|
||||
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
|
||||
return F64Bytes(llmax(accumulator.mSize.getMax(), active_accumulator && active_accumulator->mSize.hasValue() ? active_accumulator->mSize.getMax() : F32_MIN));
|
||||
|
|
@ -281,7 +289,7 @@ F64Kilobytes Recording::getMax(const StatType<MemAccumulator>& stat)
|
|||
|
||||
F64Kilobytes Recording::getStandardDeviation(const StatType<MemAccumulator>& stat)
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
|
||||
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
|
||||
if (active_accumulator && active_accumulator->hasValue())
|
||||
|
|
@ -297,7 +305,7 @@ F64Kilobytes Recording::getStandardDeviation(const StatType<MemAccumulator>& sta
|
|||
|
||||
F64Kilobytes Recording::getLastValue(const StatType<MemAccumulator>& stat)
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
|
||||
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
|
||||
return F64Bytes(active_accumulator ? active_accumulator->mSize.getLastValue() : accumulator.mSize.getLastValue());
|
||||
|
|
@ -305,7 +313,7 @@ F64Kilobytes Recording::getLastValue(const StatType<MemAccumulator>& stat)
|
|||
|
||||
bool Recording::hasValue(const StatType<MemAccumulator::AllocationFacet>& stat)
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
|
||||
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
|
||||
return accumulator.mAllocations.hasValue() || (active_accumulator ? active_accumulator->mAllocations.hasValue() : false);
|
||||
|
|
@ -313,7 +321,7 @@ bool Recording::hasValue(const StatType<MemAccumulator::AllocationFacet>& stat)
|
|||
|
||||
F64Kilobytes Recording::getSum(const StatType<MemAccumulator::AllocationFacet>& stat)
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
|
||||
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
|
||||
return F64Bytes(accumulator.mAllocations.getSum() + (active_accumulator ? active_accumulator->mAllocations.getSum() : 0));
|
||||
|
|
@ -321,7 +329,7 @@ F64Kilobytes Recording::getSum(const StatType<MemAccumulator::AllocationFacet>&
|
|||
|
||||
F64Kilobytes Recording::getPerSec(const StatType<MemAccumulator::AllocationFacet>& stat)
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
|
||||
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
|
||||
return F64Bytes((accumulator.mAllocations.getSum() + (active_accumulator ? active_accumulator->mAllocations.getSum() : 0)) / mElapsedSeconds.value());
|
||||
|
|
@ -329,7 +337,7 @@ F64Kilobytes Recording::getPerSec(const StatType<MemAccumulator::AllocationFacet
|
|||
|
||||
S32 Recording::getSampleCount(const StatType<MemAccumulator::AllocationFacet>& stat)
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
|
||||
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
|
||||
return accumulator.mAllocations.getSampleCount() + (active_accumulator ? active_accumulator->mAllocations.getSampleCount() : 0);
|
||||
|
|
@ -337,7 +345,7 @@ S32 Recording::getSampleCount(const StatType<MemAccumulator::AllocationFacet>& s
|
|||
|
||||
bool Recording::hasValue(const StatType<MemAccumulator::DeallocationFacet>& stat)
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
|
||||
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
|
||||
return accumulator.mDeallocations.hasValue() || (active_accumulator ? active_accumulator->mDeallocations.hasValue() : false);
|
||||
|
|
@ -346,7 +354,7 @@ bool Recording::hasValue(const StatType<MemAccumulator::DeallocationFacet>& stat
|
|||
|
||||
F64Kilobytes Recording::getSum(const StatType<MemAccumulator::DeallocationFacet>& stat)
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
|
||||
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
|
||||
return F64Bytes(accumulator.mDeallocations.getSum() + (active_accumulator ? active_accumulator->mDeallocations.getSum() : 0));
|
||||
|
|
@ -354,7 +362,7 @@ F64Kilobytes Recording::getSum(const StatType<MemAccumulator::DeallocationFacet>
|
|||
|
||||
F64Kilobytes Recording::getPerSec(const StatType<MemAccumulator::DeallocationFacet>& stat)
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
|
||||
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
|
||||
return F64Bytes((accumulator.mDeallocations.getSum() + (active_accumulator ? active_accumulator->mDeallocations.getSum() : 0)) / mElapsedSeconds.value());
|
||||
|
|
@ -362,7 +370,7 @@ F64Kilobytes Recording::getPerSec(const StatType<MemAccumulator::DeallocationFac
|
|||
|
||||
S32 Recording::getSampleCount(const StatType<MemAccumulator::DeallocationFacet>& stat)
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
|
||||
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
|
||||
return accumulator.mDeallocations.getSampleCount() + (active_accumulator ? active_accumulator->mDeallocations.getSampleCount() : 0);
|
||||
|
|
@ -370,7 +378,7 @@ S32 Recording::getSampleCount(const StatType<MemAccumulator::DeallocationFacet>&
|
|||
|
||||
bool Recording::hasValue(const StatType<CountAccumulator>& stat)
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()];
|
||||
const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL;
|
||||
return accumulator.hasValue() || (active_accumulator ? active_accumulator->hasValue() : false);
|
||||
|
|
@ -378,7 +386,7 @@ bool Recording::hasValue(const StatType<CountAccumulator>& stat)
|
|||
|
||||
F64 Recording::getSum(const StatType<CountAccumulator>& stat)
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()];
|
||||
const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL;
|
||||
return accumulator.getSum() + (active_accumulator ? active_accumulator->getSum() : 0);
|
||||
|
|
@ -386,7 +394,7 @@ F64 Recording::getSum(const StatType<CountAccumulator>& stat)
|
|||
|
||||
F64 Recording::getPerSec( const StatType<CountAccumulator>& stat )
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()];
|
||||
const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL;
|
||||
F64 sum = accumulator.getSum() + (active_accumulator ? active_accumulator->getSum() : 0);
|
||||
|
|
@ -395,7 +403,7 @@ F64 Recording::getPerSec( const StatType<CountAccumulator>& stat )
|
|||
|
||||
S32 Recording::getSampleCount( const StatType<CountAccumulator>& stat )
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()];
|
||||
const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL;
|
||||
return accumulator.getSampleCount() + (active_accumulator ? active_accumulator->getSampleCount() : 0);
|
||||
|
|
@ -403,7 +411,7 @@ S32 Recording::getSampleCount( const StatType<CountAccumulator>& stat )
|
|||
|
||||
bool Recording::hasValue(const StatType<SampleAccumulator>& stat)
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
|
||||
const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
|
||||
return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue());
|
||||
|
|
@ -411,7 +419,7 @@ bool Recording::hasValue(const StatType<SampleAccumulator>& stat)
|
|||
|
||||
F64 Recording::getMin( const StatType<SampleAccumulator>& stat )
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
|
||||
const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
|
||||
return llmin(accumulator.getMin(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMin() : F32_MAX);
|
||||
|
|
@ -419,7 +427,7 @@ F64 Recording::getMin( const StatType<SampleAccumulator>& stat )
|
|||
|
||||
F64 Recording::getMax( const StatType<SampleAccumulator>& stat )
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
|
||||
const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
|
||||
return llmax(accumulator.getMax(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMax() : F32_MIN);
|
||||
|
|
@ -427,7 +435,7 @@ F64 Recording::getMax( const StatType<SampleAccumulator>& stat )
|
|||
|
||||
F64 Recording::getMean( const StatType<SampleAccumulator>& stat )
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
|
||||
const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
|
||||
if (active_accumulator && active_accumulator->hasValue())
|
||||
|
|
@ -448,7 +456,7 @@ F64 Recording::getMean( const StatType<SampleAccumulator>& stat )
|
|||
|
||||
F64 Recording::getStandardDeviation( const StatType<SampleAccumulator>& stat )
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
|
||||
const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
|
||||
|
||||
|
|
@ -465,7 +473,7 @@ F64 Recording::getStandardDeviation( const StatType<SampleAccumulator>& stat )
|
|||
|
||||
F64 Recording::getLastValue( const StatType<SampleAccumulator>& stat )
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
|
||||
const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
|
||||
return (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getLastValue() : accumulator.getLastValue());
|
||||
|
|
@ -473,7 +481,7 @@ F64 Recording::getLastValue( const StatType<SampleAccumulator>& stat )
|
|||
|
||||
S32 Recording::getSampleCount( const StatType<SampleAccumulator>& stat )
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
|
||||
const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
|
||||
return accumulator.getSampleCount() + (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getSampleCount() : 0);
|
||||
|
|
@ -481,7 +489,7 @@ S32 Recording::getSampleCount( const StatType<SampleAccumulator>& stat )
|
|||
|
||||
bool Recording::hasValue(const StatType<EventAccumulator>& stat)
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
|
||||
const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
|
||||
return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue());
|
||||
|
|
@ -489,7 +497,7 @@ bool Recording::hasValue(const StatType<EventAccumulator>& stat)
|
|||
|
||||
F64 Recording::getSum( const StatType<EventAccumulator>& stat)
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
|
||||
const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
|
||||
return (F64)(accumulator.getSum() + (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getSum() : 0));
|
||||
|
|
@ -497,7 +505,7 @@ F64 Recording::getSum( const StatType<EventAccumulator>& stat)
|
|||
|
||||
F64 Recording::getMin( const StatType<EventAccumulator>& stat )
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
|
||||
const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
|
||||
return llmin(accumulator.getMin(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMin() : F32_MAX);
|
||||
|
|
@ -505,7 +513,7 @@ F64 Recording::getMin( const StatType<EventAccumulator>& stat )
|
|||
|
||||
F64 Recording::getMax( const StatType<EventAccumulator>& stat )
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
|
||||
const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
|
||||
return llmax(accumulator.getMax(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMax() : F32_MIN);
|
||||
|
|
@ -513,7 +521,7 @@ F64 Recording::getMax( const StatType<EventAccumulator>& stat )
|
|||
|
||||
F64 Recording::getMean( const StatType<EventAccumulator>& stat )
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
|
||||
const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
|
||||
if (active_accumulator && active_accumulator->hasValue())
|
||||
|
|
@ -534,7 +542,7 @@ F64 Recording::getMean( const StatType<EventAccumulator>& stat )
|
|||
|
||||
F64 Recording::getStandardDeviation( const StatType<EventAccumulator>& stat )
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
|
||||
const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
|
||||
|
||||
|
|
@ -551,7 +559,7 @@ F64 Recording::getStandardDeviation( const StatType<EventAccumulator>& stat )
|
|||
|
||||
F64 Recording::getLastValue( const StatType<EventAccumulator>& stat )
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
|
||||
const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
|
||||
return active_accumulator ? active_accumulator->getLastValue() : accumulator.getLastValue();
|
||||
|
|
@ -559,7 +567,7 @@ F64 Recording::getLastValue( const StatType<EventAccumulator>& stat )
|
|||
|
||||
S32 Recording::getSampleCount( const StatType<EventAccumulator>& stat )
|
||||
{
|
||||
update();
|
||||
update();
|
||||
const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
|
||||
const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
|
||||
return accumulator.getSampleCount() + (active_accumulator ? active_accumulator->getSampleCount() : 0);
|
||||
|
|
@ -575,17 +583,20 @@ PeriodicRecording::PeriodicRecording( S32 num_periods, EPlayState state)
|
|||
mNumRecordedPeriods(0),
|
||||
mRecordingPeriods(num_periods ? num_periods : 1)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
setPlayState(state);
|
||||
claim_alloc(gTraceMemStat, this);
|
||||
}
|
||||
|
||||
PeriodicRecording::~PeriodicRecording()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
disclaim_alloc(gTraceMemStat, this);
|
||||
}
|
||||
|
||||
void PeriodicRecording::nextPeriod()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
if (mAutoResize)
|
||||
{
|
||||
mRecordingPeriods.push_back(Recording());
|
||||
|
|
@ -600,6 +611,7 @@ void PeriodicRecording::nextPeriod()
|
|||
|
||||
void PeriodicRecording::appendRecording(Recording& recording)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
getCurRecording().appendRecording(recording);
|
||||
nextPeriod();
|
||||
}
|
||||
|
|
@ -607,6 +619,7 @@ void PeriodicRecording::appendRecording(Recording& recording)
|
|||
|
||||
void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
if (other.mRecordingPeriods.empty()) return;
|
||||
|
||||
getCurRecording().update();
|
||||
|
|
@ -680,6 +693,7 @@ void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other )
|
|||
|
||||
F64Seconds PeriodicRecording::getDuration() const
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
F64Seconds duration;
|
||||
S32 num_periods = mRecordingPeriods.size();
|
||||
for (S32 i = 1; i <= num_periods; i++)
|
||||
|
|
@ -693,6 +707,7 @@ F64Seconds PeriodicRecording::getDuration() const
|
|||
|
||||
LLTrace::Recording PeriodicRecording::snapshotCurRecording() const
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
Recording recording_copy(getCurRecording());
|
||||
recording_copy.stop();
|
||||
return recording_copy;
|
||||
|
|
@ -735,16 +750,19 @@ const Recording& PeriodicRecording::getPrevRecording( S32 offset ) const
|
|||
|
||||
void PeriodicRecording::handleStart()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
getCurRecording().start();
|
||||
}
|
||||
|
||||
void PeriodicRecording::handleStop()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
getCurRecording().pause();
|
||||
}
|
||||
|
||||
void PeriodicRecording::handleReset()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
getCurRecording().stop();
|
||||
|
||||
if (mAutoResize)
|
||||
|
|
@ -768,11 +786,13 @@ void PeriodicRecording::handleReset()
|
|||
|
||||
void PeriodicRecording::handleSplitTo(PeriodicRecording& other)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
getCurRecording().splitTo(other.getCurRecording());
|
||||
}
|
||||
|
||||
F64 PeriodicRecording::getPeriodMin( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
bool has_value = false;
|
||||
|
|
@ -794,6 +814,7 @@ F64 PeriodicRecording::getPeriodMin( const StatType<EventAccumulator>& stat, S32
|
|||
|
||||
F64 PeriodicRecording::getPeriodMax( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
bool has_value = false;
|
||||
|
|
@ -816,6 +837,7 @@ F64 PeriodicRecording::getPeriodMax( const StatType<EventAccumulator>& stat, S32
|
|||
// calculates means using aggregates per period
|
||||
F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
F64 mean = 0;
|
||||
|
|
@ -836,9 +858,9 @@ F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, S3
|
|||
: NaN;
|
||||
}
|
||||
|
||||
|
||||
F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
F64 period_mean = getPeriodMean(stat, num_periods);
|
||||
|
|
@ -863,6 +885,7 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulat
|
|||
|
||||
F64 PeriodicRecording::getPeriodMin( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
bool has_value = false;
|
||||
|
|
@ -884,6 +907,7 @@ F64 PeriodicRecording::getPeriodMin( const StatType<SampleAccumulator>& stat, S3
|
|||
|
||||
F64 PeriodicRecording::getPeriodMax(const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
bool has_value = false;
|
||||
|
|
@ -906,6 +930,7 @@ F64 PeriodicRecording::getPeriodMax(const StatType<SampleAccumulator>& stat, S32
|
|||
|
||||
F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
S32 valid_period_count = 0;
|
||||
|
|
@ -926,8 +951,35 @@ F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, S
|
|||
: NaN;
|
||||
}
|
||||
|
||||
F64 PeriodicRecording::getPeriodMedian( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
std::vector<F64> buf;
|
||||
for (S32 i = 1; i <= num_periods; i++)
|
||||
{
|
||||
Recording& recording = getPrevRecording(i);
|
||||
if (recording.getDuration() > (F32Seconds)0.f)
|
||||
{
|
||||
if (recording.hasValue(stat))
|
||||
{
|
||||
buf.push_back(recording.getMean(stat));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (buf.size()==0)
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
std::sort(buf.begin(), buf.end());
|
||||
|
||||
return F64((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]);
|
||||
}
|
||||
|
||||
F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
F64 period_mean = getPeriodMean(stat, num_periods);
|
||||
|
|
@ -953,6 +1005,7 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumula
|
|||
|
||||
F64Kilobytes PeriodicRecording::getPeriodMin( const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
F64Kilobytes min_val(std::numeric_limits<F64>::max());
|
||||
|
|
@ -972,6 +1025,7 @@ F64Kilobytes PeriodicRecording::getPeriodMin(const MemStatHandle& stat, S32 num_
|
|||
|
||||
F64Kilobytes PeriodicRecording::getPeriodMax(const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
F64Kilobytes max_val(0.0);
|
||||
|
|
@ -991,6 +1045,7 @@ F64Kilobytes PeriodicRecording::getPeriodMax(const MemStatHandle& stat, S32 num_
|
|||
|
||||
F64Kilobytes PeriodicRecording::getPeriodMean( const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
F64Kilobytes mean(0);
|
||||
|
|
@ -1011,6 +1066,7 @@ F64Kilobytes PeriodicRecording::getPeriodMean(const MemStatHandle& stat, S32 num
|
|||
|
||||
F64Kilobytes PeriodicRecording::getPeriodStandardDeviation( const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/ )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
F64Kilobytes period_mean = getPeriodMean(stat, num_periods);
|
||||
|
|
@ -1044,6 +1100,7 @@ F64Kilobytes PeriodicRecording::getPeriodStandardDeviation(const MemStatHandle&
|
|||
|
||||
void ExtendableRecording::extend()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
// push the data back to accepted recording
|
||||
mAcceptedRecording.appendRecording(mPotentialRecording);
|
||||
// flush data, so we can start from scratch
|
||||
|
|
@ -1052,22 +1109,26 @@ void ExtendableRecording::extend()
|
|||
|
||||
void ExtendableRecording::handleStart()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
mPotentialRecording.start();
|
||||
}
|
||||
|
||||
void ExtendableRecording::handleStop()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
mPotentialRecording.pause();
|
||||
}
|
||||
|
||||
void ExtendableRecording::handleReset()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
mAcceptedRecording.reset();
|
||||
mPotentialRecording.reset();
|
||||
}
|
||||
|
||||
void ExtendableRecording::handleSplitTo(ExtendableRecording& other)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
mPotentialRecording.splitTo(other.mPotentialRecording);
|
||||
}
|
||||
|
||||
|
|
@ -1084,6 +1145,7 @@ ExtendablePeriodicRecording::ExtendablePeriodicRecording()
|
|||
|
||||
void ExtendablePeriodicRecording::extend()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
// push the data back to accepted recording
|
||||
mAcceptedRecording.appendPeriodicRecording(mPotentialRecording);
|
||||
// flush data, so we can start from scratch
|
||||
|
|
@ -1093,22 +1155,26 @@ void ExtendablePeriodicRecording::extend()
|
|||
|
||||
void ExtendablePeriodicRecording::handleStart()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
mPotentialRecording.start();
|
||||
}
|
||||
|
||||
void ExtendablePeriodicRecording::handleStop()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
mPotentialRecording.pause();
|
||||
}
|
||||
|
||||
void ExtendablePeriodicRecording::handleReset()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
mAcceptedRecording.reset();
|
||||
mPotentialRecording.reset();
|
||||
}
|
||||
|
||||
void ExtendablePeriodicRecording::handleSplitTo(ExtendablePeriodicRecording& other)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
mPotentialRecording.splitTo(other.mPotentialRecording);
|
||||
}
|
||||
|
||||
|
|
@ -1123,6 +1189,7 @@ PeriodicRecording& get_frame_recording()
|
|||
|
||||
void LLStopWatchControlsMixinCommon::start()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
switch (mPlayState)
|
||||
{
|
||||
case STOPPED:
|
||||
|
|
@ -1144,6 +1211,7 @@ void LLStopWatchControlsMixinCommon::start()
|
|||
|
||||
void LLStopWatchControlsMixinCommon::stop()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
switch (mPlayState)
|
||||
{
|
||||
case STOPPED:
|
||||
|
|
@ -1163,6 +1231,7 @@ void LLStopWatchControlsMixinCommon::stop()
|
|||
|
||||
void LLStopWatchControlsMixinCommon::pause()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
switch (mPlayState)
|
||||
{
|
||||
case STOPPED:
|
||||
|
|
@ -1182,6 +1251,7 @@ void LLStopWatchControlsMixinCommon::pause()
|
|||
|
||||
void LLStopWatchControlsMixinCommon::unpause()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
switch (mPlayState)
|
||||
{
|
||||
case STOPPED:
|
||||
|
|
@ -1201,6 +1271,7 @@ void LLStopWatchControlsMixinCommon::unpause()
|
|||
|
||||
void LLStopWatchControlsMixinCommon::resume()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
switch (mPlayState)
|
||||
{
|
||||
case STOPPED:
|
||||
|
|
@ -1221,6 +1292,7 @@ void LLStopWatchControlsMixinCommon::resume()
|
|||
|
||||
void LLStopWatchControlsMixinCommon::restart()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
switch (mPlayState)
|
||||
{
|
||||
case STOPPED:
|
||||
|
|
@ -1244,11 +1316,13 @@ void LLStopWatchControlsMixinCommon::restart()
|
|||
|
||||
void LLStopWatchControlsMixinCommon::reset()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
handleReset();
|
||||
}
|
||||
|
||||
void LLStopWatchControlsMixinCommon::setPlayState( EPlayState state )
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
switch(state)
|
||||
{
|
||||
case STOPPED:
|
||||
|
|
|
|||
|
|
@ -355,6 +355,7 @@ namespace LLTrace
|
|||
template <typename T>
|
||||
S32 getSampleCount(const StatType<T>& stat, S32 num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
S32 num_samples = 0;
|
||||
|
|
@ -374,6 +375,7 @@ namespace LLTrace
|
|||
template <typename T>
|
||||
typename T::value_t getPeriodMin(const StatType<T>& stat, S32 num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
bool has_value = false;
|
||||
|
|
@ -396,6 +398,7 @@ namespace LLTrace
|
|||
template<typename T>
|
||||
T getPeriodMin(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return T(getPeriodMin(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
|
|
@ -403,6 +406,7 @@ namespace LLTrace
|
|||
template<typename T>
|
||||
T getPeriodMin(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return T(getPeriodMin(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
|
|
@ -410,6 +414,7 @@ namespace LLTrace
|
|||
template<typename T>
|
||||
T getPeriodMin(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return T(getPeriodMin(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
|
|
@ -419,6 +424,7 @@ namespace LLTrace
|
|||
template <typename T>
|
||||
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMinPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
typename RelatedTypes<typename T::value_t>::fractional_t min_val(std::numeric_limits<F64>::max());
|
||||
|
|
@ -433,6 +439,7 @@ namespace LLTrace
|
|||
template<typename T>
|
||||
typename RelatedTypes<T>::fractional_t getPeriodMinPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return typename RelatedTypes<T>::fractional_t(getPeriodMinPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
|
|
@ -444,6 +451,7 @@ namespace LLTrace
|
|||
template <typename T>
|
||||
typename T::value_t getPeriodMax(const StatType<T>& stat, S32 num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
bool has_value = false;
|
||||
|
|
@ -466,6 +474,7 @@ namespace LLTrace
|
|||
template<typename T>
|
||||
T getPeriodMax(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return T(getPeriodMax(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
|
|
@ -473,6 +482,7 @@ namespace LLTrace
|
|||
template<typename T>
|
||||
T getPeriodMax(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return T(getPeriodMax(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
|
|
@ -480,6 +490,7 @@ namespace LLTrace
|
|||
template<typename T>
|
||||
T getPeriodMax(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return T(getPeriodMax(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
|
|
@ -489,6 +500,7 @@ namespace LLTrace
|
|||
template <typename T>
|
||||
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMaxPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
F64 max_val = std::numeric_limits<F64>::min();
|
||||
|
|
@ -503,6 +515,7 @@ namespace LLTrace
|
|||
template<typename T>
|
||||
typename RelatedTypes<T>::fractional_t getPeriodMaxPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return typename RelatedTypes<T>::fractional_t(getPeriodMaxPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
|
|
@ -514,6 +527,7 @@ namespace LLTrace
|
|||
template <typename T>
|
||||
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMean(const StatType<T >& stat, S32 num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
typename RelatedTypes<typename T::value_t>::fractional_t mean(0);
|
||||
|
|
@ -534,12 +548,14 @@ namespace LLTrace
|
|||
template<typename T>
|
||||
typename RelatedTypes<T>::fractional_t getPeriodMean(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
F64 getPeriodMean(const StatType<SampleAccumulator>& stat, S32 num_periods = S32_MAX);
|
||||
template<typename T>
|
||||
typename RelatedTypes<T>::fractional_t getPeriodMean(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
|
|
@ -547,6 +563,7 @@ namespace LLTrace
|
|||
template<typename T>
|
||||
typename RelatedTypes<T>::fractional_t getPeriodMean(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
|
|
@ -556,6 +573,7 @@ namespace LLTrace
|
|||
template <typename T>
|
||||
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMeanPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
typename RelatedTypes<typename T::value_t>::fractional_t mean = 0;
|
||||
|
|
@ -577,12 +595,16 @@ namespace LLTrace
|
|||
template<typename T>
|
||||
typename RelatedTypes<T>::fractional_t getPeriodMeanPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return typename RelatedTypes<T>::fractional_t(getPeriodMeanPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
F64 getPeriodMedian( const StatType<SampleAccumulator>& stat, S32 num_periods = S32_MAX);
|
||||
|
||||
template <typename T>
|
||||
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMedianPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
num_periods = llmin(num_periods, getNumRecordedPeriods());
|
||||
|
||||
std::vector <typename RelatedTypes<typename T::value_t>::fractional_t> buf;
|
||||
|
|
@ -602,6 +624,7 @@ namespace LLTrace
|
|||
template<typename T>
|
||||
typename RelatedTypes<T>::fractional_t getPeriodMedianPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return typename RelatedTypes<T>::fractional_t(getPeriodMedianPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
|
|
@ -614,6 +637,7 @@ namespace LLTrace
|
|||
template<typename T>
|
||||
typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
|
|
@ -621,6 +645,7 @@ namespace LLTrace
|
|||
template<typename T>
|
||||
typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -274,12 +274,10 @@ void ThreadRecorder::pushToParent()
|
|||
}
|
||||
|
||||
|
||||
static LLTrace::BlockTimerStatHandle FTM_PULL_TRACE_DATA_FROM_CHILDREN("Pull child thread trace data");
|
||||
|
||||
void ThreadRecorder::pullFromChildren()
|
||||
{
|
||||
#if LL_TRACE_ENABLED
|
||||
LL_RECORD_BLOCK_TIME(FTM_PULL_TRACE_DATA_FROM_CHILDREN);
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
|
||||
if (mActiveRecordings.empty()) return;
|
||||
|
||||
{ LLMutexLock lock(&mChildListMutex);
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
#include "lltimer.h"
|
||||
#include "llthread.h"
|
||||
#include "llmutex.h"
|
||||
#include "fstelemetry.h"
|
||||
#include "llprofiler.h"
|
||||
const LLUUID LLUUID::null;
|
||||
const LLTransactionID LLTransactionID::tnull;
|
||||
|
||||
|
|
@ -156,7 +156,7 @@ U32 janky_fast_random_seeded_bytes(U32 seed, U32 val)
|
|||
// Common to all UUID implementations
|
||||
void LLUUID::toString(std::string& out) const
|
||||
{
|
||||
FSZone;
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
out = llformat(
|
||||
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
(U8)(mData[0]),
|
||||
|
|
@ -219,7 +219,7 @@ BOOL LLUUID::set(const char* in_string, BOOL emit)
|
|||
|
||||
BOOL LLUUID::set(const std::string& in_string, BOOL emit)
|
||||
{
|
||||
FSZone;
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
BOOL broken_format = FALSE;
|
||||
|
||||
// empty strings should make NULL uuid
|
||||
|
|
@ -1030,7 +1030,7 @@ LLUUID::LLUUID()
|
|||
// Copy constructor
|
||||
LLUUID::LLUUID(const LLUUID& rhs)
|
||||
{
|
||||
FSZone;
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
// <FS> Fix for misaligned unsigned ints in LLUUID; by Sovereign Engineer / Shyotl Kuhr
|
||||
//U32 *tmp = (U32 *)mData;
|
||||
//U32 *rhstmp = (U32 *)rhs.mData;
|
||||
|
|
@ -1049,7 +1049,7 @@ LLUUID::LLUUID()
|
|||
// Assignment
|
||||
LLUUID& LLUUID::operator=(const LLUUID& rhs)
|
||||
{
|
||||
FSZone;
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
// <FS> Fix for misaligned unsigned ints in LLUUID; by Sovereign Engineer / Shyotl Kuhr
|
||||
//// No need to check the case where this==&rhs. The branch is slower than the write.
|
||||
//U32 *tmp = (U32 *)mData;
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
#include "stdtypes.h"
|
||||
#include "llpreprocessor.h"
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include "fstelemetry.h"
|
||||
#include "llprofiler.h"
|
||||
class LLMutex;
|
||||
|
||||
const S32 UUID_BYTES = 16;
|
||||
|
|
@ -57,9 +57,9 @@ public:
|
|||
explicit LLUUID(const char *in_string); // Convert from string.
|
||||
explicit LLUUID(const std::string& in_string); // Convert from string.
|
||||
LLUUID(const LLUUID &in);
|
||||
LLUUID(LLUUID&& rhs) noexcept { FSZone; std::memmove(mData, rhs.mData, sizeof(mData));};
|
||||
LLUUID(LLUUID&& rhs) noexcept { LL_PROFILE_ZONE_SCOPED; std::memmove(mData, rhs.mData, sizeof(mData));};
|
||||
LLUUID &operator=(const LLUUID &rhs);
|
||||
LLUUID &operator=(LLUUID &&rhs) noexcept {FSZone; std::memmove(mData, rhs.mData, sizeof(mData));return *this;};
|
||||
LLUUID &operator=(LLUUID &&rhs) noexcept { LL_PROFILE_ZONE_SCOPED; std::memmove(mData, rhs.mData, sizeof(mData));return *this;};
|
||||
|
||||
~LLUUID();
|
||||
|
||||
|
|
@ -120,7 +120,7 @@ public:
|
|||
# define hexnybl(N) (N)>9?((N)-10)+'a':(N)+'0'
|
||||
inline char * toShortString(char *out) const
|
||||
{
|
||||
FSZone;
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
out[0] = hexnybl(mData[14]>>4);
|
||||
out[1] = hexnybl(mData[14]&15);
|
||||
out[2] = hexnybl(mData[15]>>4);
|
||||
|
|
@ -130,7 +130,7 @@ public:
|
|||
// full uuid - Much lighterweight than default, no allocation, or nul-term added - provide your own, ensure min 36 bytes.
|
||||
inline char * toStringFast(char *out) const
|
||||
{
|
||||
FSZone;
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
out[0] = hexnybl(mData[0]>>4);
|
||||
out[1] = hexnybl(mData[0]&15);
|
||||
out[2] = hexnybl(mData[1]>>4);
|
||||
|
|
@ -259,6 +259,17 @@ struct FSUUIDHash
|
|||
};
|
||||
// </FS:Ansariel> UUID hash calculation
|
||||
|
||||
// Adapt boost hash to std hash
|
||||
namespace std
|
||||
{
|
||||
template<> struct hash<LLUUID>
|
||||
{
|
||||
std::size_t operator()(LLUUID const& s) const noexcept
|
||||
{
|
||||
return boost::hash<LLUUID>()(s);
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -42,10 +42,17 @@ typedef unsigned int U32;
|
|||
// Windows wchar_t is 16-bit, whichever way /Zc:wchar_t is set. In effect,
|
||||
// Windows wchar_t is always a typedef, either for unsigned short or __wchar_t.
|
||||
// (__wchar_t, available either way, is Microsoft's native 2-byte wchar_t type.)
|
||||
// The version of clang available with VS 2019 also defines wchar_t as __wchar_t
|
||||
// which is also 16 bits.
|
||||
// In any case, llwchar should be a UTF-32 type.
|
||||
typedef U32 llwchar;
|
||||
#else
|
||||
typedef wchar_t llwchar;
|
||||
// What we'd actually want is a simple module-scope 'if constexpr' to test
|
||||
// std::is_same<wchar_t, llwchar>::value and use that to define, or not
|
||||
// define, string conversion specializations. Since we don't have that, we'll
|
||||
// have to rely on #if instead. Sorry, Dr. Stroustrup.
|
||||
#define LLWCHAR_IS_WCHAR_T 1
|
||||
#endif
|
||||
|
||||
#if LL_WINDOWS
|
||||
|
|
|
|||
|
|
@ -31,58 +31,109 @@
|
|||
|
||||
#include <sstream>
|
||||
#include <llstring.h>
|
||||
#include <boost/call_traits.hpp>
|
||||
|
||||
/**
|
||||
* gstringize(item) encapsulates an idiom we use constantly, using
|
||||
* operator<<(std::ostringstream&, TYPE) followed by std::ostringstream::str()
|
||||
* or their wstring equivalents
|
||||
* to render a string expressing some item.
|
||||
* stream_to(std::ostream&, items, ...) streams each item in the parameter list
|
||||
* to the passed std::ostream using the insertion operator <<. This can be
|
||||
* used, for instance, to make a simple print() function, e.g.:
|
||||
*
|
||||
* @code
|
||||
* template <typename... Items>
|
||||
* void print(Items&&... items)
|
||||
* {
|
||||
* stream_to(std::cout, std::forward<Items>(items)...);
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
template <typename CHARTYPE, typename T>
|
||||
std::basic_string<CHARTYPE> gstringize(const T& item)
|
||||
// recursion tail
|
||||
template <typename CHARTYPE>
|
||||
void stream_to(std::basic_ostream<CHARTYPE>& out) {}
|
||||
// stream one or more items
|
||||
template <typename CHARTYPE, typename T, typename... Items>
|
||||
void stream_to(std::basic_ostream<CHARTYPE>& out, T&& item, Items&&... items)
|
||||
{
|
||||
out << std::forward<T>(item);
|
||||
stream_to(out, std::forward<Items>(items)...);
|
||||
}
|
||||
|
||||
// why we use function overloads, not function template specializations:
|
||||
// http://www.gotw.ca/publications/mill17.htm
|
||||
|
||||
/**
|
||||
* gstringize(item, ...) encapsulates an idiom we use constantly, using
|
||||
* operator<<(std::ostringstream&, TYPE) followed by std::ostringstream::str()
|
||||
* or their wstring equivalents to render a string expressing one or more items.
|
||||
*/
|
||||
// two or more args - the case of a single argument is handled separately
|
||||
template <typename CHARTYPE, typename T0, typename T1, typename... Items>
|
||||
auto gstringize(T0&& item0, T1&& item1, Items&&... items)
|
||||
{
|
||||
std::basic_ostringstream<CHARTYPE> out;
|
||||
out << item;
|
||||
stream_to(out, std::forward<T0>(item0), std::forward<T1>(item1),
|
||||
std::forward<Items>(items)...);
|
||||
return out.str();
|
||||
}
|
||||
|
||||
/**
|
||||
*partial specialization of stringize for handling wstring
|
||||
*TODO: we should have similar specializations for wchar_t[] but not until it is needed.
|
||||
*/
|
||||
inline std::string stringize(const std::wstring& item)
|
||||
// generic single argument: stream to out, as above
|
||||
template <typename CHARTYPE, typename T>
|
||||
struct gstringize_impl
|
||||
{
|
||||
return wstring_to_utf8str(item);
|
||||
auto operator()(typename boost::call_traits<T>::param_type arg)
|
||||
{
|
||||
std::basic_ostringstream<CHARTYPE> out;
|
||||
out << arg;
|
||||
return out.str();
|
||||
}
|
||||
};
|
||||
|
||||
// partially specialize for a single STRING argument -
|
||||
// note that ll_convert<T>(T) already handles the trivial case
|
||||
template <typename OUTCHAR, typename INCHAR>
|
||||
struct gstringize_impl<OUTCHAR, std::basic_string<INCHAR>>
|
||||
{
|
||||
auto operator()(const std::basic_string<INCHAR>& arg)
|
||||
{
|
||||
return ll_convert<std::basic_string<OUTCHAR>>(arg);
|
||||
}
|
||||
};
|
||||
|
||||
// partially specialize for a single CHARTYPE* argument -
|
||||
// since it's not a basic_string and we do want to optimize this common case
|
||||
template <typename OUTCHAR, typename INCHAR>
|
||||
struct gstringize_impl<OUTCHAR, INCHAR*>
|
||||
{
|
||||
auto operator()(const INCHAR* arg)
|
||||
{
|
||||
return ll_convert<std::basic_string<OUTCHAR>>(arg);
|
||||
}
|
||||
};
|
||||
|
||||
// gstringize(single argument)
|
||||
template <typename CHARTYPE, typename T>
|
||||
auto gstringize(T&& item)
|
||||
{
|
||||
// use decay<T> so we don't require separate specializations
|
||||
// for T, const T, T&, const T& ...
|
||||
return gstringize_impl<CHARTYPE, std::decay_t<T>>()(std::forward<T>(item));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialization of gstringize for std::string return types
|
||||
*/
|
||||
template <typename T>
|
||||
std::string stringize(const T& item)
|
||||
template <typename... Items>
|
||||
auto stringize(Items&&... items)
|
||||
{
|
||||
return gstringize<char>(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialization for generating wstring from string.
|
||||
* Both a convenience function and saves a miniscule amount of overhead.
|
||||
*/
|
||||
inline std::wstring wstringize(const std::string& item)
|
||||
{
|
||||
// utf8str_to_wstring() returns LLWString, which isn't necessarily the
|
||||
// same as std::wstring
|
||||
LLWString s(utf8str_to_wstring(item));
|
||||
return std::wstring(s.begin(), s.end());
|
||||
return gstringize<char>(std::forward<Items>(items)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialization of gstringize for std::wstring return types
|
||||
*/
|
||||
template <typename T>
|
||||
std::wstring wstringize(const T& item)
|
||||
template <typename... Items>
|
||||
auto wstringize(Items&&... items)
|
||||
{
|
||||
return gstringize<wchar_t>(item);
|
||||
return gstringize<wchar_t>(std::forward<Items>(items)...);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -146,11 +197,9 @@ void destringize_f(std::basic_string<CHARTYPE> const & str, Functor const & f)
|
|||
* std::istringstream in(str);
|
||||
* in >> item1 >> item2 >> item3 ... ;
|
||||
* @endcode
|
||||
* @NOTE - once we get generic lambdas, we shouldn't need DEWSTRINGIZE() any
|
||||
* more since DESTRINGIZE() should do the right thing with a std::wstring. But
|
||||
* until then, the lambda we pass must accept the right std::basic_istream.
|
||||
*/
|
||||
#define DESTRINGIZE(STR, EXPRESSION) (destringize_f((STR), [&](std::istream& in){in >> EXPRESSION;}))
|
||||
#define DEWSTRINGIZE(STR, EXPRESSION) (destringize_f((STR), [&](std::wistream& in){in >> EXPRESSION;}))
|
||||
#define DESTRINGIZE(STR, EXPRESSION) (destringize_f((STR), [&](auto& in){in >> EXPRESSION;}))
|
||||
// legacy name, just use DESTRINGIZE() going forward
|
||||
#define DEWSTRINGIZE(STR, EXPRESSION) DESTRINGIZE(STR, EXPRESSION)
|
||||
|
||||
#endif /* ! defined(LL_STRINGIZE_H) */
|
||||
|
|
|
|||
|
|
@ -90,19 +90,19 @@ namespace tut
|
|||
{
|
||||
Keyed one("one");
|
||||
ensure_equals(Keyed::instanceCount(), 1);
|
||||
Keyed* found = Keyed::getInstance("one");
|
||||
ensure("couldn't find stack Keyed", found);
|
||||
ensure_equals("found wrong Keyed instance", found, &one);
|
||||
auto found = Keyed::getInstance("one");
|
||||
ensure("couldn't find stack Keyed", bool(found));
|
||||
ensure_equals("found wrong Keyed instance", found.get(), &one);
|
||||
{
|
||||
boost::scoped_ptr<Keyed> two(new Keyed("two"));
|
||||
ensure_equals(Keyed::instanceCount(), 2);
|
||||
Keyed* found = Keyed::getInstance("two");
|
||||
ensure("couldn't find heap Keyed", found);
|
||||
ensure_equals("found wrong Keyed instance", found, two.get());
|
||||
auto found = Keyed::getInstance("two");
|
||||
ensure("couldn't find heap Keyed", bool(found));
|
||||
ensure_equals("found wrong Keyed instance", found.get(), two.get());
|
||||
}
|
||||
ensure_equals(Keyed::instanceCount(), 1);
|
||||
}
|
||||
Keyed* found = Keyed::getInstance("one");
|
||||
auto found = Keyed::getInstance("one");
|
||||
ensure("Keyed key lives too long", ! found);
|
||||
ensure_equals(Keyed::instanceCount(), 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -356,14 +356,15 @@ namespace tut
|
|||
|
||||
// Create a script file in a temporary place.
|
||||
NamedTempFile script("py",
|
||||
"from __future__ import print_function" EOL
|
||||
"import sys" EOL
|
||||
"import time" EOL
|
||||
EOL
|
||||
"time.sleep(2)" EOL
|
||||
"print('stdout after wait', file=sys.stdout)" EOL
|
||||
"print('stdout after wait',file=sys.stdout)" EOL
|
||||
"sys.stdout.flush()" EOL
|
||||
"time.sleep(2)" EOL
|
||||
"print('stderr after wait', file=sys.stderr)" EOL
|
||||
"print('stderr after wait',file=sys.stderr)" EOL
|
||||
"sys.stderr.flush()" EOL
|
||||
);
|
||||
|
||||
|
|
@ -572,12 +573,12 @@ namespace tut
|
|||
{
|
||||
set_test_name("arguments");
|
||||
PythonProcessLauncher py(get_test_name(),
|
||||
"from __future__ import with_statement\n"
|
||||
"from __future__ import with_statement, print_function\n"
|
||||
"import sys\n"
|
||||
// note nonstandard output-file arg!
|
||||
"with open(sys.argv[3], 'w') as f:\n"
|
||||
" for arg in sys.argv[1:]:\n"
|
||||
" print(arg, file=f)\n");
|
||||
" print(arg,file=f)\n");
|
||||
// We expect that PythonProcessLauncher has already appended
|
||||
// its own NamedTempFile to mParams.args (sys.argv[0]).
|
||||
py.mParams.args.add("first arg"); // sys.argv[1]
|
||||
|
|
@ -861,6 +862,7 @@ namespace tut
|
|||
set_test_name("'bogus' test");
|
||||
CaptureLog recorder;
|
||||
PythonProcessLauncher py(get_test_name(),
|
||||
"from __future__ import print_function\n"
|
||||
"print('Hello world')\n");
|
||||
py.mParams.files.add(LLProcess::FileParam("bogus"));
|
||||
py.mPy = LLProcess::create(py.mParams);
|
||||
|
|
@ -876,6 +878,7 @@ namespace tut
|
|||
// Replace this test with one or more real 'file' tests when we
|
||||
// implement 'file' support
|
||||
PythonProcessLauncher py(get_test_name(),
|
||||
"from __future__ import print_function\n"
|
||||
"print('Hello world')\n");
|
||||
py.mParams.files.add(LLProcess::FileParam());
|
||||
py.mParams.files.add(LLProcess::FileParam("file"));
|
||||
|
|
@ -891,6 +894,7 @@ namespace tut
|
|||
// implement 'tpipe' support
|
||||
CaptureLog recorder;
|
||||
PythonProcessLauncher py(get_test_name(),
|
||||
"from __future__ import print_function\n"
|
||||
"print('Hello world')\n");
|
||||
py.mParams.files.add(LLProcess::FileParam());
|
||||
py.mParams.files.add(LLProcess::FileParam("tpipe"));
|
||||
|
|
@ -908,6 +912,7 @@ namespace tut
|
|||
// implement 'npipe' support
|
||||
CaptureLog recorder;
|
||||
PythonProcessLauncher py(get_test_name(),
|
||||
"from __future__ import print_function\n"
|
||||
"print('Hello world')\n");
|
||||
py.mParams.files.add(LLProcess::FileParam());
|
||||
py.mParams.files.add(LLProcess::FileParam());
|
||||
|
|
@ -984,7 +989,8 @@ namespace tut
|
|||
{
|
||||
set_test_name("get*Pipe() validation");
|
||||
PythonProcessLauncher py(get_test_name(),
|
||||
"print('this output is expected)'\n");
|
||||
"from __future__ import print_function\n"
|
||||
"print('this output is expected')\n");
|
||||
py.mParams.files.add(LLProcess::FileParam("pipe")); // pipe for stdin
|
||||
py.mParams.files.add(LLProcess::FileParam()); // inherit stdout
|
||||
py.mParams.files.add(LLProcess::FileParam("pipe")); // pipe for stderr
|
||||
|
|
@ -1004,6 +1010,7 @@ namespace tut
|
|||
{
|
||||
set_test_name("talk to stdin/stdout");
|
||||
PythonProcessLauncher py(get_test_name(),
|
||||
"from __future__ import print_function\n"
|
||||
"import sys, time\n"
|
||||
"print('ok')\n"
|
||||
"sys.stdout.flush()\n"
|
||||
|
|
@ -1122,6 +1129,7 @@ namespace tut
|
|||
{
|
||||
set_test_name("ReadPipe \"eof\" event");
|
||||
PythonProcessLauncher py(get_test_name(),
|
||||
"from __future__ import print_function\n"
|
||||
"print('Hello from Python!')\n");
|
||||
py.mParams.files.add(LLProcess::FileParam()); // stdin
|
||||
py.mParams.files.add(LLProcess::FileParam("pipe")); // stdout
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
/**
|
||||
* @file threadsafeschedule_test.cpp
|
||||
* @author Nat Goodspeed
|
||||
* @date 2021-10-04
|
||||
* @brief Test for threadsafeschedule.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2021&license=viewerlgpl$
|
||||
* Copyright (c) 2021, Linden Research, Inc.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
// Precompiled header
|
||||
#include "linden_common.h"
|
||||
// associated header
|
||||
#include "threadsafeschedule.h"
|
||||
// STL headers
|
||||
// std headers
|
||||
#include <chrono>
|
||||
// external library headers
|
||||
// other Linden headers
|
||||
#include "../test/lltut.h"
|
||||
|
||||
using namespace std::literals::chrono_literals; // ms suffix
|
||||
using namespace std::literals::string_literals; // s suffix
|
||||
using Queue = LL::ThreadSafeSchedule<std::string>;
|
||||
|
||||
/*****************************************************************************
|
||||
* TUT
|
||||
*****************************************************************************/
|
||||
namespace tut
|
||||
{
|
||||
struct threadsafeschedule_data
|
||||
{
|
||||
Queue queue;
|
||||
};
|
||||
typedef test_group<threadsafeschedule_data> threadsafeschedule_group;
|
||||
typedef threadsafeschedule_group::object object;
|
||||
threadsafeschedule_group threadsafeschedulegrp("threadsafeschedule");
|
||||
|
||||
template<> template<>
|
||||
void object::test<1>()
|
||||
{
|
||||
set_test_name("push");
|
||||
// Simply calling push() a few times might result in indeterminate
|
||||
// delivery order if the resolution of steady_clock is coarser than
|
||||
// the real time required for each push() call. Explicitly increment
|
||||
// the timestamp for each one -- but since we're passing explicit
|
||||
// timestamps, make the queue reorder them.
|
||||
queue.push(Queue::TimeTuple(Queue::Clock::now() + 200ms, "ghi"));
|
||||
// Given the various push() overloads, you have to match the type
|
||||
// exactly: conversions are ambiguous.
|
||||
queue.push("abc"s);
|
||||
queue.push(Queue::Clock::now() + 100ms, "def");
|
||||
queue.close();
|
||||
auto entry = queue.pop();
|
||||
ensure_equals("failed to pop first", std::get<0>(entry), "abc"s);
|
||||
entry = queue.pop();
|
||||
ensure_equals("failed to pop second", std::get<0>(entry), "def"s);
|
||||
ensure("queue not closed", queue.isClosed());
|
||||
ensure("queue prematurely done", ! queue.done());
|
||||
std::string s;
|
||||
bool popped = queue.tryPopFor(1s, s);
|
||||
ensure("failed to pop third", popped);
|
||||
ensure_equals("third is wrong", s, "ghi"s);
|
||||
popped = queue.tryPop(s);
|
||||
ensure("queue not empty", ! popped);
|
||||
ensure("queue not done", queue.done());
|
||||
}
|
||||
} // namespace tut
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* @file tuple_test.cpp
|
||||
* @author Nat Goodspeed
|
||||
* @date 2021-10-04
|
||||
* @brief Test for tuple.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2021&license=viewerlgpl$
|
||||
* Copyright (c) 2021, Linden Research, Inc.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
// Precompiled header
|
||||
#include "linden_common.h"
|
||||
// associated header
|
||||
#include "tuple.h"
|
||||
// STL headers
|
||||
// std headers
|
||||
// external library headers
|
||||
// other Linden headers
|
||||
#include "../test/lltut.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* TUT
|
||||
*****************************************************************************/
|
||||
namespace tut
|
||||
{
|
||||
struct tuple_data
|
||||
{
|
||||
};
|
||||
typedef test_group<tuple_data> tuple_group;
|
||||
typedef tuple_group::object object;
|
||||
tuple_group tuplegrp("tuple");
|
||||
|
||||
template<> template<>
|
||||
void object::test<1>()
|
||||
{
|
||||
set_test_name("tuple");
|
||||
std::tuple<std::string, int> tup{ "abc", 17 };
|
||||
std::tuple<int, std::string, int> ptup{ tuple_cons(34, tup) };
|
||||
std::tuple<std::string, int> tup2;
|
||||
int i;
|
||||
std::tie(i, tup2) = tuple_split(ptup);
|
||||
ensure_equals("tuple_car() fail", i, 34);
|
||||
ensure_equals("tuple_cdr() (0) fail", std::get<0>(tup2), "abc");
|
||||
ensure_equals("tuple_cdr() (1) fail", std::get<1>(tup2), 17);
|
||||
}
|
||||
} // namespace tut
|
||||
|
|
@ -0,0 +1,235 @@
|
|||
/**
|
||||
* @file workqueue_test.cpp
|
||||
* @author Nat Goodspeed
|
||||
* @date 2021-10-07
|
||||
* @brief Test for workqueue.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2021&license=viewerlgpl$
|
||||
* Copyright (c) 2021, Linden Research, Inc.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
// Precompiled header
|
||||
#include "linden_common.h"
|
||||
// associated header
|
||||
#include "workqueue.h"
|
||||
// STL headers
|
||||
// std headers
|
||||
#include <chrono>
|
||||
#include <deque>
|
||||
// external library headers
|
||||
// other Linden headers
|
||||
#include "../test/lltut.h"
|
||||
#include "../test/catch_and_store_what_in.h"
|
||||
#include "llcond.h"
|
||||
#include "llcoros.h"
|
||||
#include "lleventcoro.h"
|
||||
#include "llstring.h"
|
||||
#include "stringize.h"
|
||||
|
||||
using namespace LL;
|
||||
using namespace std::literals::chrono_literals; // ms suffix
|
||||
using namespace std::literals::string_literals; // s suffix
|
||||
|
||||
/*****************************************************************************
|
||||
* TUT
|
||||
*****************************************************************************/
|
||||
namespace tut
|
||||
{
|
||||
struct workqueue_data
|
||||
{
|
||||
WorkQueue queue{"queue"};
|
||||
};
|
||||
typedef test_group<workqueue_data> workqueue_group;
|
||||
typedef workqueue_group::object object;
|
||||
workqueue_group workqueuegrp("workqueue");
|
||||
|
||||
template<> template<>
|
||||
void object::test<1>()
|
||||
{
|
||||
set_test_name("name");
|
||||
ensure_equals("didn't capture name", queue.getKey(), "queue");
|
||||
ensure("not findable", WorkQueue::getInstance("queue") == queue.getWeak().lock());
|
||||
WorkQueue q2;
|
||||
ensure("has no name", LLStringUtil::startsWith(q2.getKey(), "WorkQueue"));
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void object::test<2>()
|
||||
{
|
||||
set_test_name("post");
|
||||
bool wasRun{ false };
|
||||
// We only get away with binding a simple bool because we're running
|
||||
// the work on the same thread.
|
||||
queue.post([&wasRun](){ wasRun = true; });
|
||||
queue.close();
|
||||
ensure("ran too soon", ! wasRun);
|
||||
queue.runUntilClose();
|
||||
ensure("didn't run", wasRun);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void object::test<3>()
|
||||
{
|
||||
set_test_name("postEvery");
|
||||
// record of runs
|
||||
using Shared = std::deque<WorkQueue::TimePoint>;
|
||||
// This is an example of how to share data between the originator of
|
||||
// postEvery(work) and the work item itself, since usually a WorkQueue
|
||||
// is used to dispatch work to a different thread. Neither of them
|
||||
// should call any of LLCond's wait methods: you don't want to stall
|
||||
// either the worker thread or the originating thread (conventionally
|
||||
// main). Use LLCond or a subclass even if all you want to do is
|
||||
// signal the work item that it can quit; consider LLOneShotCond.
|
||||
LLCond<Shared> data;
|
||||
auto start = WorkQueue::TimePoint::clock::now();
|
||||
auto interval = 100ms;
|
||||
queue.postEvery(
|
||||
interval,
|
||||
[&data, count = 0]
|
||||
() mutable
|
||||
{
|
||||
// record the timestamp at which this instance is running
|
||||
data.update_one(
|
||||
[](Shared& data)
|
||||
{
|
||||
data.push_back(WorkQueue::TimePoint::clock::now());
|
||||
});
|
||||
// by the 3rd call, return false to stop
|
||||
return (++count < 3);
|
||||
});
|
||||
// no convenient way to close() our queue while we've got a
|
||||
// postEvery() running, so run until we have exhausted the iterations
|
||||
// or we time out waiting
|
||||
for (auto finish = start + 10*interval;
|
||||
WorkQueue::TimePoint::clock::now() < finish &&
|
||||
data.get([](const Shared& data){ return data.size(); }) < 3; )
|
||||
{
|
||||
queue.runPending();
|
||||
std::this_thread::sleep_for(interval/10);
|
||||
}
|
||||
// Take a copy of the captured deque.
|
||||
Shared result = data.get();
|
||||
ensure_equals("called wrong number of times", result.size(), 3);
|
||||
// postEvery() assumes you want the first call to happen right away.
|
||||
// Pretend our start time was (interval) earlier than that, to make
|
||||
// our too early/too late tests uniform for all entries.
|
||||
start -= interval;
|
||||
for (size_t i = 0; i < result.size(); ++i)
|
||||
{
|
||||
auto diff = result[i] - start;
|
||||
start += interval;
|
||||
try
|
||||
{
|
||||
ensure(STRINGIZE("call " << i << " too soon"), diff >= interval);
|
||||
ensure(STRINGIZE("call " << i << " too late"), diff < interval*1.5);
|
||||
}
|
||||
catch (const tut::failure&)
|
||||
{
|
||||
auto interval_ms = interval / 1ms;
|
||||
auto diff_ms = diff / 1ms;
|
||||
std::cerr << "interval " << interval_ms
|
||||
<< "ms; diff " << diff_ms << "ms" << std::endl;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void object::test<4>()
|
||||
{
|
||||
set_test_name("postTo");
|
||||
WorkQueue main("main");
|
||||
auto qptr = WorkQueue::getInstance("queue");
|
||||
int result = 0;
|
||||
main.postTo(
|
||||
qptr,
|
||||
[](){ return 17; },
|
||||
// Note that a postTo() *callback* can safely bind a reference to
|
||||
// a variable on the invoking thread, because the callback is run
|
||||
// on the invoking thread. (Of course the bound variable must
|
||||
// survive until the callback is called.)
|
||||
[&result](int i){ result = i; });
|
||||
// this should post the callback to main
|
||||
qptr->runOne();
|
||||
// this should run the callback
|
||||
main.runOne();
|
||||
ensure_equals("failed to run int callback", result, 17);
|
||||
|
||||
std::string alpha;
|
||||
// postTo() handles arbitrary return types
|
||||
main.postTo(
|
||||
qptr,
|
||||
[](){ return "abc"s; },
|
||||
[&alpha](const std::string& s){ alpha = s; });
|
||||
qptr->runPending();
|
||||
main.runPending();
|
||||
ensure_equals("failed to run string callback", alpha, "abc");
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void object::test<5>()
|
||||
{
|
||||
set_test_name("postTo with void return");
|
||||
WorkQueue main("main");
|
||||
auto qptr = WorkQueue::getInstance("queue");
|
||||
std::string observe;
|
||||
main.postTo(
|
||||
qptr,
|
||||
// The ONLY reason we can get away with binding a reference to
|
||||
// 'observe' in our work callable is because we're directly
|
||||
// calling qptr->runOne() on this same thread. It would be a
|
||||
// mistake to do that if some other thread were servicing 'queue'.
|
||||
[&observe](){ observe = "queue"; },
|
||||
[&observe](){ observe.append(";main"); });
|
||||
qptr->runOne();
|
||||
main.runOne();
|
||||
ensure_equals("failed to run both lambdas", observe, "queue;main");
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void object::test<6>()
|
||||
{
|
||||
set_test_name("waitForResult");
|
||||
std::string stored;
|
||||
// Try to call waitForResult() on this thread's main coroutine. It
|
||||
// should throw because the main coroutine must service the queue.
|
||||
auto what{ catch_what<WorkQueue::Error>(
|
||||
[this, &stored](){ stored = queue.waitForResult(
|
||||
[](){ return "should throw"; }); }) };
|
||||
ensure("lambda should not have run", stored.empty());
|
||||
ensure_not("waitForResult() should have thrown", what.empty());
|
||||
ensure(STRINGIZE("should mention waitForResult: " << what),
|
||||
what.find("waitForResult") != std::string::npos);
|
||||
|
||||
// Call waitForResult() on a coroutine, with a string result.
|
||||
LLCoros::instance().launch(
|
||||
"waitForResult string",
|
||||
[this, &stored]()
|
||||
{ stored = queue.waitForResult(
|
||||
[](){ return "string result"; }); });
|
||||
llcoro::suspend();
|
||||
// Nothing will have happened yet because, even if the coroutine did
|
||||
// run immediately, all it did was to queue the inner lambda on
|
||||
// 'queue'. Service it.
|
||||
queue.runOne();
|
||||
llcoro::suspend();
|
||||
ensure_equals("bad waitForResult return", stored, "string result");
|
||||
|
||||
// Call waitForResult() on a coroutine, with a void callable.
|
||||
stored.clear();
|
||||
bool done = false;
|
||||
LLCoros::instance().launch(
|
||||
"waitForResult void",
|
||||
[this, &stored, &done]()
|
||||
{
|
||||
queue.waitForResult([&stored](){ stored = "ran"; });
|
||||
done = true;
|
||||
});
|
||||
llcoro::suspend();
|
||||
queue.runOne();
|
||||
llcoro::suspend();
|
||||
ensure_equals("didn't run coroutine", stored, "ran");
|
||||
ensure("void waitForResult() didn't return", done);
|
||||
}
|
||||
} // namespace tut
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
/**
|
||||
* @file threadpool.cpp
|
||||
* @author Nat Goodspeed
|
||||
* @date 2021-10-21
|
||||
* @brief Implementation for threadpool.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2021&license=viewerlgpl$
|
||||
* Copyright (c) 2021, Linden Research, Inc.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
// Precompiled header
|
||||
#include "linden_common.h"
|
||||
// associated header
|
||||
#include "threadpool.h"
|
||||
// STL headers
|
||||
// std headers
|
||||
// external library headers
|
||||
// other Linden headers
|
||||
#include "llerror.h"
|
||||
#include "llevents.h"
|
||||
#include "stringize.h"
|
||||
|
||||
LL::ThreadPool::ThreadPool(const std::string& name, size_t threads, size_t capacity):
|
||||
mQueue(name, capacity),
|
||||
mName("ThreadPool:" + name),
|
||||
mThreadCount(threads)
|
||||
{}
|
||||
|
||||
void LL::ThreadPool::start()
|
||||
{
|
||||
for (size_t i = 0; i < mThreadCount; ++i)
|
||||
{
|
||||
std::string tname{ stringize(mName, ':', (i+1), '/', mThreadCount) };
|
||||
mThreads.emplace_back(tname, [this, tname]()
|
||||
{
|
||||
LL_PROFILER_SET_THREAD_NAME(tname.c_str());
|
||||
run(tname);
|
||||
});
|
||||
}
|
||||
// Listen on "LLApp", and when the app is shutting down, close the queue
|
||||
// and join the workers.
|
||||
LLEventPumps::instance().obtain("LLApp").listen(
|
||||
mName,
|
||||
[this](const LLSD& stat)
|
||||
{
|
||||
std::string status(stat["status"]);
|
||||
if (status != "running")
|
||||
{
|
||||
// viewer is starting shutdown -- proclaim the end is nigh!
|
||||
LL_DEBUGS("ThreadPool") << mName << " saw " << status << LL_ENDL;
|
||||
close();
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
LL::ThreadPool::~ThreadPool()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void LL::ThreadPool::close()
|
||||
{
|
||||
if (! mQueue.isClosed())
|
||||
{
|
||||
LL_DEBUGS("ThreadPool") << mName << " closing queue and joining threads" << LL_ENDL;
|
||||
mQueue.close();
|
||||
for (auto& pair: mThreads)
|
||||
{
|
||||
LL_DEBUGS("ThreadPool") << mName << " waiting on thread " << pair.first << LL_ENDL;
|
||||
pair.second.join();
|
||||
}
|
||||
LL_DEBUGS("ThreadPool") << mName << " shutdown complete" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
void LL::ThreadPool::run(const std::string& name)
|
||||
{
|
||||
LL_DEBUGS("ThreadPool") << name << " starting" << LL_ENDL;
|
||||
run();
|
||||
LL_DEBUGS("ThreadPool") << name << " stopping" << LL_ENDL;
|
||||
}
|
||||
|
||||
void LL::ThreadPool::run()
|
||||
{
|
||||
mQueue.runUntilClose();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue