/** * @file lltextureinfo.cpp * @brief Object which handles local texture info * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, 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$ */ #include "llviewerprecompiledheaders.h" #include "llagent.h" #include "llmeshrepository.h" #include "llsdutil.h" #include "lltextureinfo.h" #include "lltexturecache.h" #include "lltexturefetch.h" #include "lltexturestats.h" #include "lltrace.h" #include "llviewercontrol.h" #include "llviewerregion.h" #include "llviewerstats.h" #include "llvocache.h" #include "llworld.h" static LLTrace::CountStatHandle<S32> sTextureDownloadsStarted("texture_downloads_started", "number of texture downloads initiated"); static LLTrace::CountStatHandle<S32> sTextureDownloadsCompleted("texture_downloads_completed", "number of texture downloads completed"); static LLTrace::CountStatHandle<S32Bytes > sTextureDataDownloaded("texture_data_downloaded", "amount of texture data downloaded"); static LLTrace::CountStatHandle<U32Milliseconds > sTexureDownloadTime("texture_download_time", "amount of time spent fetching textures"); LLTextureInfo::LLTextureInfo(bool postponeStartRecoreder) : mLoggingEnabled(false), mTextureDownloadProtocol("NONE") { if (!postponeStartRecoreder) { startRecording(); } } void LLTextureInfo::setLogging(bool log_info) { mLoggingEnabled = log_info; } LLTextureInfo::~LLTextureInfo() { std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator; for (iterator = mTextures.begin(); iterator != mTextures.end(); iterator++) { LLTextureInfoDetails *info = (*iterator).second; delete info; } mTextures.clear(); } void LLTextureInfo::addRequest(const LLUUID& id) { LLTextureInfoDetails *info = new LLTextureInfoDetails(); mTextures[id] = info; } U32 LLTextureInfo::getTextureInfoMapSize() { return static_cast<U32>(mTextures.size()); } bool LLTextureInfo::has(const LLUUID& id) { return mTextures.end() != mTextures.find(id); } void LLTextureInfo::setRequestStartTime(const LLUUID& id, U64 startTime) { if (!has(id)) { addRequest(id); } mTextures[id]->mStartTime = (U64Microseconds)startTime; add(sTextureDownloadsStarted, 1); } void LLTextureInfo::setRequestSize(const LLUUID& id, U32 size) { if (!has(id)) { addRequest(id); } mTextures[id]->mSize = (U32Bytes)size; } void LLTextureInfo::setRequestOffset(const LLUUID& id, U32 offset) { if (!has(id)) { addRequest(id); } mTextures[id]->mOffset = offset; } void LLTextureInfo::setRequestType(const LLUUID& id, LLTextureInfoDetails::LLRequestType type) { if (!has(id)) { addRequest(id); } mTextures[id]->mType = type; } void LLTextureInfo::setRequestCompleteTimeAndLog(const LLUUID& id, U64Microseconds completeTime) { if (!has(id)) { addRequest(id); } LLTextureInfoDetails& details = *mTextures[id]; details.mCompleteTime = completeTime; std::string protocol = "NONE"; switch(details.mType) { case LLTextureInfoDetails::REQUEST_TYPE_HTTP: protocol = "HTTP"; break; case LLTextureInfoDetails::REQUEST_TYPE_UDP: protocol = "UDP"; break; case LLTextureInfoDetails::REQUEST_TYPE_NONE: default: break; } if (mLoggingEnabled) { static LLCachedControl<bool> log_to_viewer_log(gSavedSettings, "LogTextureDownloadsToViewerLog", false); static LLCachedControl<bool> log_to_simulator(gSavedSettings, "LogTextureDownloadsToSimulator", false); static LLCachedControl<U32> texture_log_threshold(gSavedSettings, "TextureLoggingThreshold", 1); if (log_to_viewer_log) { LL_INFOS() << "texture=" << id << " start=" << details.mStartTime << " end=" << details.mCompleteTime << " size=" << details.mSize << " offset=" << details.mOffset << " length=" << U32Milliseconds(details.mCompleteTime - details.mStartTime) << " protocol=" << protocol << LL_ENDL; } if(log_to_simulator) { add(sTextureDataDownloaded, details.mSize); add(sTexureDownloadTime, details.mCompleteTime - details.mStartTime); add(sTextureDownloadsCompleted, 1); mTextureDownloadProtocol = protocol; if (mRecording.getSum(sTextureDataDownloaded) >= U32Bytes(texture_log_threshold)) { LLSD texture_data; std::stringstream startTime; startTime << mCurrentStatsBundleStartTime; texture_data["start_time"] = startTime.str(); std::stringstream endTime; endTime << completeTime; texture_data["end_time"] = endTime.str(); texture_data["averages"] = getAverages(); // Texture cache LLSD texture_cache; U32 cache_read = 0, cache_write = 0, res_wait = 0; F64 cache_hit_rate = 0; LLAppViewer::getTextureFetch()->getStateStats(&cache_read, &cache_write, &res_wait); if (cache_read > 0 || cache_write > 0) { cache_hit_rate = cache_read / (cache_read + cache_write); } texture_cache["cache_read"] = LLSD::Integer(cache_read); texture_cache["cache_write"] = LLSD::Integer(cache_write); texture_cache["hit_rate"] = LLSD::Real(cache_hit_rate); texture_cache["entries"] = LLSD::Integer(LLAppViewer::getTextureCache()->getEntries()); texture_cache["space_max"] = ll_sd_from_U64((U64)LLAppViewer::getTextureCache()->getMaxUsage().value()); // bytes texture_cache["space_used"] = ll_sd_from_U64((U64)LLAppViewer::getTextureCache()->getUsage().value()); // bytes texture_data["texture_cache"] = texture_cache; // VO and mesh cache LLSD object_cache; object_cache["vo_entries_max"] = LLSD::Integer(LLVOCache::getInstance()->getCacheEntriesMax()); object_cache["vo_entries_curent"] = LLSD::Integer(LLVOCache::getInstance()->getCacheEntries()); object_cache["vo_active_entries"] = LLSD::Integer(LLWorld::getInstance()->getNumOfActiveCachedObjects()); U64 region_hit_count = gAgent.getRegion() != NULL ? gAgent.getRegion()->getRegionCacheHitCount() : 0; U64 region_miss_count = gAgent.getRegion() != NULL ? gAgent.getRegion()->getRegionCacheMissCount() : 0; F64 region_vocache_hit_rate = 0; if (region_hit_count > 0 || region_miss_count > 0) { region_vocache_hit_rate = (F64)region_hit_count / (region_hit_count + region_miss_count); } object_cache["vo_region_hitcount"] = ll_sd_from_U64(region_hit_count); object_cache["vo_region_misscount"] = ll_sd_from_U64(region_miss_count); object_cache["vo_region_hitrate"] = LLSD::Real(region_vocache_hit_rate); object_cache["mesh_reads"] = LLSD::Integer(LLMeshRepository::sCacheReads); object_cache["mesh_writes"] = LLSD::Integer(LLMeshRepository::sCacheWrites); texture_data["object_cache"] = object_cache; send_texture_stats_to_sim(texture_data); resetTextureStatistics(); } } } mTextures.erase(id); } LLSD LLTextureInfo::getAverages() { LLSD averagedTextureData; S32 averageDownloadRate = 0; unsigned int download_time = mRecording.getSum(sTexureDownloadTime).valueInUnits<LLUnits::Seconds>(); if (0 != download_time) { averageDownloadRate = mRecording.getSum(sTextureDataDownloaded).valueInUnits<LLUnits::Bits>() / download_time; } averagedTextureData["bits_per_second"] = averageDownloadRate; averagedTextureData["bytes_downloaded"] = mRecording.getSum(sTextureDataDownloaded).valueInUnits<LLUnits::Bytes>(); averagedTextureData["texture_downloads_started"] = mRecording.getSum(sTextureDownloadsStarted); averagedTextureData["texture_downloads_completed"] = mRecording.getSum(sTextureDownloadsCompleted); averagedTextureData["transport"] = mTextureDownloadProtocol; return averagedTextureData; } void LLTextureInfo::startRecording() { mRecording.start(); } void LLTextureInfo::stopRecording() { mRecording.stop(); } void LLTextureInfo::resetTextureStatistics() { mRecording.restart(); mTextureDownloadProtocol = "NONE"; mCurrentStatsBundleStartTime = LLTimer::getTotalTime(); } U32Microseconds LLTextureInfo::getRequestStartTime(const LLUUID& id) { if (!has(id)) { return U32Microseconds(0); } else { std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator = mTextures.find(id); return (*iterator).second->mStartTime; } } U32Bytes LLTextureInfo::getRequestSize(const LLUUID& id) { if (!has(id)) { return U32Bytes(0); } else { std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator = mTextures.find(id); return (*iterator).second->mSize; } } U32 LLTextureInfo::getRequestOffset(const LLUUID& id) { if (!has(id)) { return 0; } else { std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator = mTextures.find(id); return (*iterator).second->mOffset; } } LLTextureInfoDetails::LLRequestType LLTextureInfo::getRequestType(const LLUUID& id) { if (!has(id)) { return LLTextureInfoDetails::REQUEST_TYPE_NONE; } else { std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator = mTextures.find(id); return (*iterator).second->mType; } } U32Microseconds LLTextureInfo::getRequestCompleteTime(const LLUUID& id) { if (!has(id)) { return U32Microseconds(0); } else { std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator = mTextures.find(id); return (*iterator).second->mCompleteTime; } }