/** * @file llviewerstats.cpp * @brief LLViewerStats class implementation * * Copyright (c) 2002-$CurrentYear$, Linden Research, Inc. * $License$ */ #include "llviewerprecompiledheaders.h" #include "llviewerstats.h" #include "llviewerthrottle.h" #include "message.h" #include "lltimer.h" LLViewerStats *gViewerStats = NULL; extern U32 gFrameCount; extern LLTimer gRenderStartTime; class StatAttributes { public: StatAttributes(const char *name, const BOOL enabled, const BOOL is_timer) : mName(name), mEnabled(enabled), mIsTimer(is_timer) { } const char *mName; const BOOL mEnabled; const BOOL mIsTimer; }; const StatAttributes STAT_INFO[LLViewerStats::ST_COUNT] = { // ST_VERSION StatAttributes("Version", TRUE, FALSE), // ST_AVATAR_EDIT_SECONDS StatAttributes("Seconds in Edit Appearence", FALSE, TRUE), // ST_TOOLBOX_SECONDS StatAttributes("Seconds using Toolbox", FALSE, TRUE), // ST_CHAT_COUNT StatAttributes("Chat messages sent", FALSE, FALSE), // ST_IM_COUNT StatAttributes("IMs sent", FALSE, FALSE), // ST_FULLSCREEN_BOOL StatAttributes("Fullscreen mode", FALSE, FALSE), // ST_RELEASE_COUNT StatAttributes("Object release count", FALSE, FALSE), // ST_CREATE_COUNT StatAttributes("Object create count", FALSE, FALSE), // ST_REZ_COUNT StatAttributes("Object rez count", FALSE, FALSE), // ST_FPS_10_SECONDS StatAttributes("Seconds below 10 FPS", FALSE, TRUE), // ST_FPS_2_SECONDS StatAttributes("Seconds below 2 FPS", FALSE, TRUE), // ST_MOUSELOOK_SECONDS StatAttributes("Seconds in Mouselook", FALSE, TRUE), // ST_FLY_COUNT StatAttributes("Fly count", FALSE, FALSE), // ST_TELEPORT_COUNT StatAttributes("Teleport count", FALSE, FALSE), // ST_OBJECT_DELETE_COUNT StatAttributes("Objects deleted", FALSE, FALSE), // ST_SNAPSHOT_COUNT StatAttributes("Snapshots taken", FALSE, FALSE), // ST_UPLOAD_SOUND_COUNT StatAttributes("Sounds uploaded", FALSE, FALSE), // ST_UPLOAD_TEXTURE_COUNT StatAttributes("Textures uploaded", FALSE, FALSE), // ST_EDIT_TEXTURE_COUNT StatAttributes("Changes to textures on objects", FALSE, FALSE), // ST_KILLED_COUNT StatAttributes("Number of times killed", FALSE, FALSE), // ST_FRAMETIME_JITTER StatAttributes("Average delta between sucessive frame times", FALSE, FALSE), // ST_FRAMETIME_SLEW StatAttributes("Average delta between frame time and mean", FALSE, FALSE), // ST_INVENTORY_TOO_LONG StatAttributes("Inventory took too long to load", FALSE, FALSE), // ST_WEARABLES_TOO_LONG StatAttributes("Wearables took too long to load", FALSE, FALSE), // ST_LOGIN_SECONDS StatAttributes("Time between LoginRequest and LoginReply", FALSE, FALSE), // ST_LOGIN_TIMEOUT_COUNT StatAttributes("Number of login attempts that timed out", FALSE, FALSE), // ST_HAS_BAD_TIMER StatAttributes("Known bad timer if != 0.0", FALSE, FALSE), // ST_DOWNLOAD_FAILED StatAttributes("Number of times LLAssetStorage::getAssetData() has failed", FALSE, FALSE), // ST_LSL_SAVE_COUNT StatAttributes("Number of times user has saved a script", FALSE, FALSE), // ST_UPLOAD_ANIM_COUNT StatAttributes("Animations uploaded", FALSE, FALSE), // ST_FPS_8_SECONDS StatAttributes("Seconds below 8 FPS", FALSE, TRUE), // ST_SIM_FPS_20_SECONDS StatAttributes("Seconds with sim FPS below 20", FALSE, TRUE), // ST_PHYS_FPS_20_SECONDS StatAttributes("Seconds with physics FPS below 20", FALSE, TRUE), // ST_LOSS_05_SECONDS StatAttributes("Seconds with packet loss > 5%", FALSE, TRUE), // ST_FPS_DROP_50_RATIO StatAttributes("Ratio of frames 2x longer than previous", FALSE, FALSE), // ST_ENABLE_VBO StatAttributes("Vertex Buffers Enabled", TRUE, FALSE), // ST_DELTA_BANDWIDTH StatAttributes("Increase/Decrease in bandwidth based on packet loss", FALSE, FALSE), // ST_MAX_BANDWIDTH StatAttributes("Max bandwidth setting", FALSE, FALSE), // ST_LIGHTING_DETAIL StatAttributes("Lighting Detail", FALSE, FALSE), // ST_VISIBLE_AVATARS StatAttributes("Visible Avatars", FALSE, FALSE), // ST_SHADER_OJECTS StatAttributes("Object Shaders", FALSE, FALSE), // ST_SHADER_ENVIRONMENT StatAttributes("Environment Shaders", FALSE, FALSE), // ST_VISIBLE_DRAW_DIST StatAttributes("Draw Distance", FALSE, FALSE), // ST_VISIBLE_CHAT_BUBBLES StatAttributes("Chat Bubbles Enabled", FALSE, FALSE), // ST_SHADER_AVATAR StatAttributes("Avatar Shaders", FALSE, FALSE), // ST_FRAME_SECS StatAttributes("FRAME_SECS", FALSE, FALSE), // ST_UPDATE_SECS StatAttributes("UPDATE_SECS", FALSE, FALSE), // ST_NETWORK_SECS StatAttributes("NETWORK_SECS", FALSE, FALSE), // ST_IMAGE_SECS StatAttributes("IMAGE_SECS", FALSE, FALSE), // ST_REBUILD_SECS StatAttributes("REBUILD_SECS", FALSE, FALSE), // ST_RENDER_SECS StatAttributes("RENDER_SECS", FALSE, FALSE), // ST_CROSSING_AVG StatAttributes("CROSSING_AVG", FALSE, FALSE), // ST_CROSSING_MAX StatAttributes("CROSSING_MAX", FALSE, FALSE), // ST_LIBXUL_WIDGET_USED StatAttributes("LibXUL Widget used", FALSE, FALSE), // ST_WINDOW_WIDTH StatAttributes("Window width", FALSE, FALSE), // ST_WINDOW_HEIGHT StatAttributes("Window height", FALSE, FALSE), // ST_TEX_BAKES StatAttributes("Texture Bakes", FALSE, FALSE), // ST_TEX_REBAKES StatAttributes("Texture Rebakes", FALSE, FALSE) }; LLViewerStats::LLViewerStats() : mPacketsLostPercentStat(64), mLastTimeDiff(0.0) { for (S32 i = 0; i < ST_COUNT; i++) { mStats[i] = 0.0; } if (LLTimer::knownBadTimer()) { mStats[ST_HAS_BAD_TIMER] = 1.0; } } LLViewerStats::~LLViewerStats() { } void LLViewerStats::resetStats() { gViewerStats->mKBitStat.reset(); gViewerStats->mLayersKBitStat.reset(); gViewerStats->mObjectKBitStat.reset(); gViewerStats->mTextureKBitStat.reset(); gViewerStats->mVFSPendingOperations.reset(); gViewerStats->mAssetKBitStat.reset(); gViewerStats->mPacketsInStat.reset(); gViewerStats->mPacketsLostStat.reset(); gViewerStats->mPacketsOutStat.reset(); gViewerStats->mFPSStat.reset(); gViewerStats->mTexturePacketsStat.reset(); } F64 LLViewerStats::getStat(EStatType type) const { return mStats[type]; } F64 LLViewerStats::setStat(EStatType type, F64 value) { mStats[type] = value; return mStats[type]; } F64 LLViewerStats::incStat(EStatType type, F64 value) { mStats[type] += value; return mStats[type]; } void LLViewerStats::updateFrameStats(const F64 time_diff) { if (mPacketsLostPercentStat.getCurrent() > 5.0) { incStat(LLViewerStats::ST_LOSS_05_SECONDS, time_diff); } if (mSimFPS.getCurrent() < 20.f && mSimFPS.getCurrent() > 0.f) { incStat(LLViewerStats::ST_SIM_FPS_20_SECONDS, time_diff); } if (mSimPhysicsFPS.getCurrent() < 20.f && mSimPhysicsFPS.getCurrent() > 0.f) { incStat(LLViewerStats::ST_PHYS_FPS_20_SECONDS, time_diff); } if (time_diff >= 0.5) { incStat(LLViewerStats::ST_FPS_2_SECONDS, time_diff); } if (time_diff >= 0.125) { incStat(LLViewerStats::ST_FPS_8_SECONDS, time_diff); } if (time_diff >= 0.1) { incStat(LLViewerStats::ST_FPS_10_SECONDS, time_diff); } if (gFrameCount && mLastTimeDiff > 0.0) { // new "stutter" meter setStat(LLViewerStats::ST_FPS_DROP_50_RATIO, (getStat(LLViewerStats::ST_FPS_DROP_50_RATIO) * (F64)(gFrameCount - 1) + (time_diff >= 2.0 * mLastTimeDiff ? 1.0 : 0.0)) / gFrameCount); // old stats that were never really used setStat(LLViewerStats::ST_FRAMETIME_JITTER, (getStat(LLViewerStats::ST_FRAMETIME_JITTER) * (gFrameCount - 1) + fabs(mLastTimeDiff - time_diff) / mLastTimeDiff) / gFrameCount); F32 average_frametime = gRenderStartTime.getElapsedTimeF32() / (F32)gFrameCount; setStat(LLViewerStats::ST_FRAMETIME_SLEW, (getStat(LLViewerStats::ST_FRAMETIME_SLEW) * (gFrameCount - 1) + fabs(average_frametime - time_diff) / average_frametime) / gFrameCount); F32 max_bandwidth = gViewerThrottle.getMaxBandwidth(); F32 delta_bandwidth = gViewerThrottle.getCurrentBandwidth() - max_bandwidth; setStat(LLViewerStats::ST_DELTA_BANDWIDTH, delta_bandwidth / 1024.f); setStat(LLViewerStats::ST_MAX_BANDWIDTH, max_bandwidth / 1024.f); } mLastTimeDiff = time_diff; } void LLViewerStats::addToMessage() const { for (S32 i = 0; i < ST_COUNT; i++) { if (STAT_INFO[i].mEnabled) { // TODO: send timer value so dataserver can normalize gMessageSystem->nextBlockFast(_PREHASH_MiscStats); gMessageSystem->addU32Fast(_PREHASH_Type, (U32)i); gMessageSystem->addF64Fast(_PREHASH_Value, mStats[i]); llinfos << "STAT: " << STAT_INFO[i].mName << ": " << mStats[i] << llendl; } } } // static const char *LLViewerStats::statTypeToText(EStatType type) { if (type >= 0 && type < ST_COUNT) { return STAT_INFO[type].mName; } else { return "Unknown statistic"; } }