Ticket #1862: profiler2.2.patch
File profiler2.2.patch, 13.5 KB (added by , 10 years ago) |
---|
-
binaries/data/config/default.cfg
326 326 ; > PROFILER 327 327 hotkey.profile.toggle = "F11" ; Enable/disable real-time profiler 328 328 hotkey.profile.save = "Shift+F11" ; Save current profiler data to logs/profile.txt 329 hotkey.profile2. enable = "F11" ; Enable HTTP/GPU modes for new profiler329 hotkey.profile2.toggle = "Ctrl+F11" ; Enable/disable HTTP/GPU modes for new profiler 330 330 331 profiler2. http.autoenable = false; Enable HTTP server output at startup (default off for security/performance)331 profiler2.autoenable = false ; Enable HTTP server output at startup (default off for security/performance) 332 332 profiler2.script.enable = false ; Enable Javascript profiling. Needs to be set before startup and can't be changed later. (default off for performance) 333 profiler2.gpu.autoenable = false ; Enable GPU timing at startup (default off for performance/compatibility)334 333 profiler2.gpu.arb.enable = true ; Allow GL_ARB_timer_query timing mode when available 335 334 profiler2.gpu.ext.enable = true ; Allow GL_EXT_timer_query timing mode when available 336 335 profiler2.gpu.intel.enable = true ; Allow GL_INTEL_performance_queries timing mode when available -
source/main.cpp
161 161 #endif 162 162 return IN_HANDLED; 163 163 } 164 else if (hotkey == "profile2. enable")164 else if (hotkey == "profile2.toggle") 165 165 { 166 g_Profiler2.EnableGPU(); 167 g_Profiler2.EnableHTTP(); 166 g_Profiler2.Toggle(); 168 167 return IN_HANDLED; 169 168 } 170 169 break; … … 179 178 { 180 179 JSContext* cx = g_GUI->GetScriptInterface()->GetContext(); 181 180 JSAutoRequest rq(cx); 182 181 183 182 PROFILE3("dispatch events"); 184 183 185 184 SDL_Event_ ev; … … 294 293 bool need_update = true; 295 294 296 295 // If we are not running a multiplayer game, disable updates when the game is 297 // minimized or out of focus and relinquish the CPU a bit, in order to make 296 // minimized or out of focus and relinquish the CPU a bit, in order to make 298 297 // debugging easier. 299 298 if(g_PauseOnFocusLoss && !g_NetClient && !g_app_has_focus) 300 299 { -
source/ps/GameSetup/GameSetup.cpp
433 433 434 434 const size_t cacheSize = ChooseCacheSize(); 435 435 g_VFS = CreateVfs(cacheSize); 436 436 437 437 // Work out whether we are a dev version to make sure saved files 438 438 // (maps, etc) end up in version control. 439 439 const OsPath readonlyConfig = paths.RData()/"config"/""; … … 451 451 size_t priority = (i+1)*2; // mods are higher priority than regular mountings, which default to priority 0 452 452 size_t userFlags = VFS_MOUNT_WATCH|VFS_MOUNT_ARCHIVABLE|VFS_MOUNT_REPLACEABLE; 453 453 size_t baseFlags = userFlags|VFS_MOUNT_MUST_EXIST; 454 454 455 455 OsPath modName(mods[i]); 456 456 if (InDevelopmentCopy()) 457 457 { … … 565 565 SAFE_DELETE(g_GUI); 566 566 567 567 SAFE_DELETE(g_Console); 568 569 // This is needed to ensure that no callbacks from the JSAPI try to use 568 569 // This is needed to ensure that no callbacks from the JSAPI try to use 570 570 // the profiler when it's already destructed 571 571 g_ScriptRuntime.reset(); 572 572 … … 597 597 g_Renderer.SetOptionBool(CRenderer::OPT_WATERREFLECTION, g_WaterReflection); 598 598 g_Renderer.SetOptionBool(CRenderer::OPT_WATERREFRACTION, g_WaterRefraction); 599 599 g_Renderer.SetOptionBool(CRenderer::OPT_SHADOWSONWATER, g_WaterShadows); 600 600 601 601 g_Renderer.SetRenderPath(CRenderer::GetRenderPathByName(g_RenderPath)); 602 602 g_Renderer.SetOptionBool(CRenderer::OPT_SHADOWPCF, g_ShadowPCF); 603 603 g_Renderer.SetOptionBool(CRenderer::OPT_PARTICLES, g_Particles); … … 862 862 // This must come after VFS init, which sets the current directory 863 863 // (required for finding our output log files). 864 864 g_Logger = new CLogger; 865 865 866 866 // Workaround until Simulation and AI use their own threads and also their own runtimes 867 867 g_ScriptRuntime = ScriptInterface::CreateRuntime(384 * 1024 * 1024); 868 868 … … 906 906 // g_ConfigDB, command line args, globals 907 907 CONFIG_Init(args); 908 908 909 // before scripting 909 // before scripting 910 910 // JS debugger temporarily disabled during the SpiderMonkey upgrade (check trac ticket #2348 for details) 911 911 //if (g_JSDebuggerEnabled) 912 912 // g_DebuggingServer = new CDebuggingServer(); … … 914 914 // Optionally start profiler HTTP output automatically 915 915 // (By default it's only enabled by a hotkey, for security/performance) 916 916 bool profilerHTTPEnable = false; 917 CFG_GET_VAL("profiler2. http.autoenable", Bool, profilerHTTPEnable);917 CFG_GET_VAL("profiler2.autoenable", Bool, profilerHTTPEnable); 918 918 if (profilerHTTPEnable) 919 919 g_Profiler2.EnableHTTP(); 920 920 … … 950 950 // Optionally start profiler GPU timings automatically 951 951 // (By default it's only enabled by a hotkey, for performance/compatibility) 952 952 bool profilerGPUEnable = false; 953 CFG_GET_VAL("profiler2. gpu.autoenable", Bool, profilerGPUEnable);953 CFG_GET_VAL("profiler2.autoenable", Bool, profilerGPUEnable); 954 954 if (profilerGPUEnable) 955 955 g_Profiler2.EnableGPU(); 956 956 … … 1181 1181 seed = seedArg.ToULong(); 1182 1182 } 1183 1183 } 1184 1184 1185 1185 // Random map definition will be loaded from JSON file, so we need to parse it 1186 1186 std::wstring scriptPath = L"maps/" + autoStartName.FromUTF8() + L".json"; 1187 1187 JS::RootedValue scriptData(cx, scriptInterface.ReadJSONFile(scriptPath).get()); … … 1306 1306 { 1307 1307 scriptInterface.Eval("({})", &player); 1308 1308 } 1309 1309 1310 1310 int playerID = civArgs[i].BeforeFirst(":").ToInt(); 1311 1311 int difficulty = civArgs[i].AfterFirst(":").ToInt(); 1312 1312 1313 1313 scriptInterface.SetProperty(player, "AIDiff", difficulty); 1314 1314 scriptInterface.SetPropertyInt(playerData, playerID-1, player); 1315 1315 } … … 1326 1326 { 1327 1327 scriptInterface.Eval("({})", &player); 1328 1328 } 1329 1329 1330 1330 int playerID = civArgs[i].BeforeFirst(":").ToInt(); 1331 1331 CStr name = civArgs[i].AfterFirst(":"); 1332 1332 1333 1333 scriptInterface.SetProperty(player, "Civ", std::string(name)); 1334 1334 scriptInterface.SetPropertyInt(playerData, playerID-1, player); 1335 1335 } -
source/ps/Profiler2.cpp
7 7 * distribute, sublicense, and/or sell copies of the Software, and to 8 8 * permit persons to whom the Software is furnished to do so, subject to 9 9 * the following conditions: 10 * 10 * 11 11 * The above copyright notice and this permission notice shall be included 12 12 * in all copies or substantial portions of the Software. 13 * 13 * 14 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. … … 157 157 void CProfiler2::EnableHTTP() 158 158 { 159 159 ENSURE(m_Initialised); 160 debug_DisplayMessage(L"ATTENTION",L"Starting profiler2 HTTP server"); 160 161 161 162 // Ignore multiple enablings 162 163 if (m_MgContext) … … 175 176 { 176 177 ENSURE(m_Initialised); 177 178 if (!m_GPU) 178 InitialiseGPU(); 179 { 180 debug_DisplayMessage(L"ATTENTION",L"Starting profiler2_GPU"); 181 InitialiseGPU(); 182 } 179 183 } 180 184 181 185 void CProfiler2::ShutdownGPU() 182 186 { 187 debug_DisplayMessage(L"ATTENTION",L"Shutting down profiler2_GPU"); 183 188 SAFE_DELETE(m_GPU); 184 189 } 185 190 191 void CProfiler2::ShutDownHTTP() 192 { 193 debug_DisplayMessage(L"ATTENTION",L"Shutting down profiler2 HTTP server"); 194 if (m_MgContext) 195 { 196 mg_stop(m_MgContext); 197 m_MgContext = NULL; 198 } 199 } 200 201 void CProfiler2::Toggle() 202 { 203 //TODO: Maybe we can open the browser to the profiler page automatically 204 if(m_GPU && m_MgContext) 205 { 206 ShutdownGPU(); 207 ShutDownHTTP(); 208 } 209 else if(!m_GPU && !m_MgContext) 210 { 211 EnableGPU(); 212 EnableHTTP(); 213 } 214 } 215 186 216 void CProfiler2::Shutdown() 187 217 { 188 218 ENSURE(m_Initialised); … … 285 315 std::string CProfiler2::ThreadStorage::GetBuffer() 286 316 { 287 317 // Called from an arbitrary thread (not the one writing to the buffer). 288 // 318 // 289 319 // See comments on m_BufferPos0 etc. 290 320 291 321 shared_ptr<u8> buffer(new u8[BUFFER_SIZE], ArrayDeleter()); -
source/ps/Profiler2.h
7 7 * distribute, sublicense, and/or sell copies of the Software, and to 8 8 * permit persons to whom the Software is furnished to do so, subject to 9 9 * the following conditions: 10 * 10 * 11 11 * The above copyright notice and this permission notice shall be included 12 12 * in all copies or substantial portions of the Software. 13 * 13 * 14 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. … … 23 23 /** 24 24 * @file 25 25 * New profiler (complementing the older CProfileManager) 26 * 26 * 27 27 * The profiler is designed for analysing framerate fluctuations or glitches, 28 28 * and temporal relationships between threads. 29 29 * This contrasts with CProfilerManager and most external profiling tools, 30 30 * which are designed more for measuring average throughput over a number of 31 31 * frames. 32 * 32 * 33 33 * To view the profiler output, press F11 to enable the HTTP output mode 34 34 * and then open source/tools/profiler2/profiler2.html in a web browser. 35 * 35 * 36 36 * There is a single global CProfiler2 instance (g_Profiler2), 37 37 * providing the API used by the rest of the game. 38 38 * The game can record the entry/exit timings of a region of code … … 41 41 * Regions and events can be annotated with arbitrary string attributes, 42 42 * specified with printf-style format strings, using PROFILE2_ATTR 43 43 * (e.g. PROFILE2_ATTR("frame: %d", m_FrameNum) ). 44 * 44 * 45 45 * This is designed for relatively coarse-grained profiling, or for rare events. 46 46 * Don't use it for regions that are typically less than ~0.1msecs, or that are 47 47 * called hundreds of times per frame. (The old CProfilerManager is better 48 48 * for that.) 49 * 49 * 50 50 * New threads must call g_Profiler2.RegisterCurrentThread before any other 51 51 * profiler functions. 52 * 52 * 53 53 * The main thread should call g_Profiler2.RecordFrameStart at the start of 54 54 * each frame. 55 55 * Other threads should call g_Profiler2.RecordSyncMarker occasionally, 56 56 * especially if it's been a long time since their last call to the profiler, 57 57 * or if they've made thousands of calls since the last sync marker. 58 * 58 * 59 59 * The profiler is implemented with thread-local fixed-size ring buffers, 60 60 * which store a sequence of variable-length items indicating the time 61 61 * of the event and associated data (pointers to names, attribute strings, etc). … … 62 62 * An HTTP server provides access to the data: when requested, it will make 63 63 * a copy of a thread's buffer, then parse the items and return them in JSON 64 64 * format. The profiler2.html requests and processes and visualises this data. 65 * 65 * 66 66 * The RecordSyncMarker calls are necessary to correct for time drift and to 67 67 * let the buffer parser accurately detect the start of an item in the byte stream. 68 * 68 * 69 69 * This design aims to minimise the performance overhead of recording data, 70 70 * and to simplify the visualisation of the data by doing it externally in an 71 71 * environment with better UI tools (i.e. HTML) instead of within the game engine. 72 * 72 * 73 73 * The initial setup of g_Profiler2 must happen in the game's main thread. 74 74 * RegisterCurrentThread and the Record functions may be called from any thread. 75 75 * The HTTP server runs its own threads, which may call the ConstructJSON functions. … … 110 110 111 111 /// An arbitrary number to help resyncing with the item stream when parsing. 112 112 static const u8 RESYNC_MAGIC[8]; 113 113 114 114 /** 115 115 * An item with a relative time and an ID string pointer. 116 116 */ … … 134 134 public: 135 135 ThreadStorage(CProfiler2& profiler, const std::string& name); 136 136 ~ThreadStorage(); 137 137 138 138 void RecordSyncMarker(double t) 139 139 { 140 140 // Store the magic string followed by the absolute time … … 163 163 } 164 164 165 165 void RecordAttribute(const char* fmt, va_list argp) VPRINTF_ARGS(2); 166 166 167 167 void RecordAttributePrintf(const char* fmt, ...) PRINTF_ARGS(2) 168 168 { 169 169 va_list argp; … … 219 219 220 220 m_Buffer[start] = (u8)type; 221 221 memcpy(&m_Buffer[start + 1], item, itemSize); 222 222 223 223 COMPILER_FENCE; // must write m_BufferPos1 after m_Buffer 224 224 m_BufferPos1 = start + size; 225 225 } … … 239 239 // outside the range Pos1 <= x < Pos0 are safe to use. (Any in that range might 240 240 // be half-written and corrupted.) (All ranges are modulo BUFFER_SIZE.) 241 241 // Outside of Write(), these will always be equal. 242 // 242 // 243 243 // TODO: does this attempt at synchronisation (plus use of COMPILER_FENCE etc) 244 244 // actually work in practice? 245 245 u32 m_BufferPos0; … … 275 275 */ 276 276 void ShutdownGPU(); 277 277 278 /** 279 * Call in main thread to shut down the profiler's HTTP server 280 */ 281 void ShutDownHTTP(); 282 283 /** 284 * Call in main thread to enable/disable the profiler 285 */ 286 void Toggle(); 287 278 288 /** 279 289 * Call in main thread to shut everything down. 280 290 * All other profiled threads should have been terminated already. … … 387 397 bool m_Initialised; 388 398 389 399 int m_FrameNumber; 390 400 391 401 mg_context* m_MgContext; 392 402 393 403 pthread_key_t m_TLS; 394 404 395 405 CProfiler2GPU* m_GPU;