Merge pull request #5184 from pavlos256/loading-perf

Loading performance measurements
This commit is contained in:
Paul Chote
2014-04-26 11:17:21 +12:00
18 changed files with 200 additions and 70 deletions

View File

@@ -246,11 +246,17 @@ namespace OpenRA
{ {
BeforeGameStart(); BeforeGameStart();
var map = modData.PrepareMap(mapUID); Map map;
orderManager.world = new World(modData.Manifest, map, orderManager, isShellmap); using (new PerfTimer("PrepareMap"))
orderManager.world.Timestep = Timestep; map = modData.PrepareMap(mapUID);
using (new PerfTimer("NewWorld"))
{
orderManager.world = new World(modData.Manifest, map, orderManager, isShellmap);
orderManager.world.Timestep = Timestep;
}
worldRenderer = new WorldRenderer(orderManager.world); worldRenderer = new WorldRenderer(orderManager.world);
orderManager.world.LoadComplete(worldRenderer); using (new PerfTimer("LoadComplete"))
orderManager.world.LoadComplete(worldRenderer);
if (orderManager.GameStarted) if (orderManager.GameStarted)
return; return;
@@ -385,7 +391,8 @@ namespace OpenRA
modData = new ModData(mod); modData = new ModData(mod);
Renderer.InitializeFonts(modData.Manifest); Renderer.InitializeFonts(modData.Manifest);
modData.InitializeLoaders(); modData.InitializeLoaders();
modData.MapCache.LoadMaps(); using (new PerfTimer("LoadMaps"))
modData.MapCache.LoadMaps();
PerfHistory.items["render"].hasNormalTick = false; PerfHistory.items["render"].hasNormalTick = false;
PerfHistory.items["batches"].hasNormalTick = false; PerfHistory.items["batches"].hasNormalTick = false;
@@ -436,7 +443,10 @@ namespace OpenRA
public static void LoadShellMap() public static void LoadShellMap()
{ {
StartGame(ChooseShellmap(), true); var shellmap = ChooseShellmap();
using (new PerfTimer("StartGame"))
StartGame(shellmap, true);
} }
static string ChooseShellmap() static string ChooseShellmap()
@@ -478,7 +488,7 @@ namespace OpenRA
Tick(orderManager); Tick(orderManager);
var waitTime = Math.Min(idealFrameTime - sw.ElapsedTime(), 1); var waitTime = Math.Min(idealFrameTime - sw.Elapsed.TotalSeconds, 1);
if (waitTime > 0) if (waitTime > 0)
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(waitTime)); System.Threading.Thread.Sleep(TimeSpan.FromSeconds(waitTime));
} }

View File

@@ -431,13 +431,20 @@ namespace OpenRA
string ComputeHash() string ComputeHash()
{ {
// UID is calculated by taking an SHA1 of the yaml and binary data // UID is calculated by taking an SHA1 of the yaml and binary data
// Read the relevant data into a buffer
var data = Container.GetContent("map.yaml").ReadAllBytes()
.Concat(Container.GetContent("map.bin").ReadAllBytes()).ToArray();
// Take the SHA1 using (var ms = new MemoryStream())
using (var csp = SHA1.Create()) {
return new string(csp.ComputeHash(data).SelectMany(a => a.ToString("x2")).ToArray()); // Read the relevant data into the buffer
using (var s = Container.GetContent("map.yaml"))
s.CopyTo(ms);
using (var s = Container.GetContent("map.bin"))
s.CopyTo(ms);
// Take the SHA1
ms.Seek(0, SeekOrigin.Begin);
using (var csp = SHA1.Create())
return new string(csp.ComputeHash(ms).SelectMany(a => a.ToString("x2")).ToArray());
}
} }
public void MakeDefaultPlayers() public void MakeDefaultPlayers()

View File

@@ -47,9 +47,12 @@ namespace OpenRA
{ {
try try
{ {
var map = new Map(path, manifest.Mod.Id); using (new Support.PerfTimer(path))
if (manifest.MapCompatibility.Contains(map.RequiresMod)) {
previews[map.Uid].UpdateFromMap(map); var map = new Map(path, manifest.Mod.Id);
if (manifest.MapCompatibility.Contains(map.RequiresMod))
previews[map.Uid].UpdateFromMap(map);
}
} }
catch (Exception e) catch (Exception e)
{ {

View File

@@ -118,11 +118,15 @@ namespace OpenRA
// Mount map package so custom assets can be used. TODO: check priority. // Mount map package so custom assets can be used. TODO: check priority.
GlobalFileSystem.Mount(GlobalFileSystem.OpenPackage(map.Path, null, int.MaxValue)); GlobalFileSystem.Mount(GlobalFileSystem.OpenPackage(map.Path, null, int.MaxValue));
Rules.LoadRules(Manifest, map); using (new Support.PerfTimer("LoadRules"))
Rules.LoadRules(Manifest, map);
SpriteLoader = new SpriteLoader(Rules.TileSets[map.Tileset].Extensions, SheetBuilder); SpriteLoader = new SpriteLoader(Rules.TileSets[map.Tileset].Extensions, SheetBuilder);
// TODO: Don't load the sequences for assets that are not used in this tileset. Maybe use the existing EditorTilesetFilters. using (new Support.PerfTimer("SequenceProvider.Initialize"))
SequenceProvider.Initialize(Manifest.Sequences, map.Sequences); {
// TODO: Don't load the sequences for assets that are not used in this tileset. Maybe use the existing EditorTilesetFilters.
SequenceProvider.Initialize(Manifest.Sequences, map.Sequences);
}
VoxelProvider.Initialize(Manifest.VoxelSequences, map.VoxelSequences); VoxelProvider.Initialize(Manifest.VoxelSequences, map.VoxelSequences);
return map; return map;
} }

View File

@@ -293,7 +293,7 @@
<Compile Include="Primitives\Set.cs" /> <Compile Include="Primitives\Set.cs" />
<Compile Include="Support\Log.cs" /> <Compile Include="Support\Log.cs" />
<Compile Include="Support\Stopwatch.cs" /> <Compile Include="Support\Stopwatch.cs" />
<Compile Include="Support\Timer.cs" /> <Compile Include="Support\PerfTimer.cs" />
<Compile Include="Exts.cs" /> <Compile Include="Exts.cs" />
<Compile Include="Hotkey.cs" /> <Compile Include="Hotkey.cs" />
<Compile Include="Keycode.cs" /> <Compile Include="Keycode.cs" />

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information #region Copyright & License Information
/* /*
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS) * Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made * This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -71,7 +71,7 @@ namespace OpenRA
public bool BotDebug = false; public bool BotDebug = false;
public bool PerfText = false; public bool PerfText = false;
public bool PerfGraph = false; public bool PerfGraph = false;
public float LongTickThreshold = 0.001f; public TimeSpan LongTickThreshold = TimeSpan.FromMilliseconds(1d);
public bool SanityCheckUnsyncedCode = false; public bool SanityCheckUnsyncedCode = false;
public int Samples = 25; public int Samples = 25;
public bool IgnoreVersionMismatch = false; public bool IgnoreVersionMismatch = false;

View File

@@ -46,6 +46,12 @@ namespace OpenRA
{ {
if (Channels.ContainsKey(channelName)) return; if (Channels.ContainsKey(channelName)) return;
if (string.IsNullOrEmpty(baseFilename))
{
Channels.Add(channelName, new ChannelInfo());
return;
}
foreach (var filename in FilenamesForChannel(channelName, baseFilename)) foreach (var filename in FilenamesForChannel(channelName, baseFilename))
try try
{ {
@@ -70,6 +76,9 @@ namespace OpenRA
if (!Channels.TryGetValue(channel, out info)) if (!Channels.TryGetValue(channel, out info))
throw new Exception("Tried logging to non-existant channel " + channel); throw new Exception("Tried logging to non-existant channel " + channel);
if (info.Writer == null)
return;
info.Writer.WriteLine(format, args); info.Writer.WriteLine(format, args);
} }
} }

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information #region Copyright & License Information
/* /*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made * This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -116,7 +116,7 @@ namespace OpenRA.Support
public void Dispose() public void Dispose()
{ {
PerfHistory.Increment(Item, sw.ElapsedTime() * 1000); PerfHistory.Increment(Item, sw.Elapsed.TotalMilliseconds);
} }
} }
} }

117
OpenRA.Game/Support/PerfTimer.cs Executable file
View File

@@ -0,0 +1,117 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Linq;
using System.Threading;
namespace OpenRA.Support
{
public class PerfTimer : IDisposable
{
readonly Stopwatch sw = new Stopwatch();
readonly string Name;
//
// Hacks to give the output a tree-like structure
//
static ThreadLocal<int> depth = new ThreadLocal<int>();
static ThreadLocal<string> prevHeader = new ThreadLocal<string>();
const int MaxWidth = 60, Digits = 6;
const int MaxIndentedLabel = MaxWidth - Digits;
const string IndentationString = "| ";
readonly string FormatString = "{0," + MaxIndentedLabel + "} {1," + Digits + "} ms";
public PerfTimer(string name)
{
if (prevHeader.Value != null)
{
Log.Write("perf", prevHeader.Value);
prevHeader.Value = null;
}
this.Name = name;
prevHeader.Value = GetHeader(Indentation, this.Name);
depth.Value++;
}
public void Dispose()
{
depth.Value--;
string s;
if (prevHeader.Value == null)
{
s = GetFooter(Indentation);
}
else
{
s = GetOneLiner(Indentation, this.Name);
prevHeader.Value = null;
}
Log.Write("perf", FormatString, s, Math.Round(this.sw.Elapsed.TotalMilliseconds));
}
static string GetHeader(string indentation, string label)
{
return string.Concat(indentation, LimitLength(label, MaxIndentedLabel - indentation.Length));
}
static string GetOneLiner(string indentation, string label)
{
return string.Concat(indentation, SetLength(label, MaxIndentedLabel - indentation.Length));
}
static string GetFooter(string indentation)
{
return string.Concat(indentation, new string('-', MaxIndentedLabel - indentation.Length));
}
static string LimitLength(string s, int length, int minLength = 8)
{
length = Math.Max(length, minLength);
if (s == null || s.Length <= length)
return s;
return s.Substring(0, length);
}
static string SetLength(string s, int length, int minLength = 8)
{
length = Math.Max(length, minLength);
if (s == null || s.Length == length)
return s;
if (s.Length < length)
return s.PadRight(length);
return s.Substring(0, length);
}
static string Indentation
{
get
{
var d = depth.Value;
if (d == 1)
return IndentationString;
else if (d <= 0)
return string.Empty;
else
return string.Concat(Enumerable.Repeat(IndentationString, depth.Value));
}
}
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information #region Copyright & License Information
/* /*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made * This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -13,14 +13,15 @@ namespace OpenRA.Support
public class Stopwatch public class Stopwatch
{ {
System.Diagnostics.Stopwatch sw; System.Diagnostics.Stopwatch sw;
public Stopwatch ()
public Stopwatch()
{ {
Reset(); Reset();
} }
public double ElapsedTime() public System.TimeSpan Elapsed
{ {
return sw.Elapsed.TotalMilliseconds / 1000.0; get { return this.sw.Elapsed; }
} }
public void Reset() public void Reset()

View File

@@ -1,27 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
namespace OpenRA.Support
{
public static class Timer
{
static Stopwatch sw = new Stopwatch();
static double lastTime = 0;
public static void Time( string message )
{
var time = sw.ElapsedTime();
var dt = time - lastTime;
if( dt > 0.0001 )
Log.Write("perf", message, dt );
lastTime = time;
}
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information #region Copyright & License Information
/* /*
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS) * Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made * This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -83,9 +83,9 @@ namespace OpenRA.Traits
var sw = new Stopwatch(); var sw = new Stopwatch();
act = act.Tick(self); act = act.Tick(self);
var dt = sw.ElapsedTime(); var dt = sw.Elapsed;
if (dt > Game.Settings.Debug.LongTickThreshold) if (dt > Game.Settings.Debug.LongTickThreshold)
Log.Write("perf", "[{2}] Activity: {0} ({1:0.000} ms)", prev, dt * 1000, Game.LocalTick); Log.Write("perf", "[{2}] Activity: {0} ({1:0.000} ms)", prev, dt.TotalMilliseconds, Game.LocalTick);
if (prev == act) if (prev == act)
break; break;

View File

@@ -148,7 +148,10 @@ namespace OpenRA
public void LoadComplete(WorldRenderer wr) public void LoadComplete(WorldRenderer wr)
{ {
foreach (var wlh in WorldActor.TraitsImplementing<IWorldLoaded>()) foreach (var wlh in WorldActor.TraitsImplementing<IWorldLoaded>())
wlh.WorldLoaded(this, wr); {
using (new Support.PerfTimer(wlh.GetType().Name + ".WorldLoaded"))
wlh.WorldLoaded(this, wr);
}
} }
public Actor CreateActor(string name, TypeDictionary initDict) public Actor CreateActor(string name, TypeDictionary initDict)

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information #region Copyright & License Information
/* /*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made * This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -171,17 +171,17 @@ namespace OpenRA
} }
} }
public static void DoTimed<T>(this IEnumerable<T> e, Action<T> a, string text, double time) public static void DoTimed<T>(this IEnumerable<T> e, Action<T> a, string text, TimeSpan time)
{ {
var sw = new Stopwatch(); var sw = new Stopwatch();
e.Do(x => e.Do(x =>
{ {
var t = sw.ElapsedTime(); var t = sw.Elapsed;
a(x); a(x);
var dt = sw.ElapsedTime() - t; var dt = sw.Elapsed - t;
if (dt > time) if (dt > time)
Log.Write("perf", text, x, dt * 1000, Game.LocalTick); Log.Write("perf", text, x, dt.TotalMilliseconds, Game.LocalTick);
}); });
} }

View File

@@ -11,6 +11,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.IO;
using OpenRA.FileSystem; using OpenRA.FileSystem;
using OpenRA.Traits; using OpenRA.Traits;
@@ -41,6 +42,8 @@ namespace OpenRA.Lint
try try
{ {
Log.AddChannel("perf", null);
var options = args.Where(a => a.StartsWith("-")); var options = args.Where(a => a.StartsWith("-"));
var mod = args.Where(a => !options.Contains(a)).First(); var mod = args.Where(a => !options.Contains(a)).First();
var map = args.Where(a => !options.Contains(a)).Skip(1).FirstOrDefault(); var map = args.Where(a => !options.Contains(a)).Skip(1).FirstOrDefault();

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information #region Copyright & License Information
/* /*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made * This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -76,7 +76,7 @@ namespace OpenRA.Mods.Cnc
public void Display() public void Display()
{ {
if (r == null || loadTimer.ElapsedTime() < 0.25) if (r == null || loadTimer.Elapsed.TotalSeconds < 0.25)
return; return;
loadTimer.Reset(); loadTimer.Reset();

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information #region Copyright & License Information
/* /*
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS) * Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made * This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -55,7 +55,7 @@ namespace OpenRA.Mods.RA
return; return;
// Update text at most every 0.5 seconds // Update text at most every 0.5 seconds
if (lastUpdate.ElapsedTime() < 0.5) if (lastUpdate.Elapsed.TotalSeconds < 0.5)
return; return;
if (r.Fonts == null) if (r.Fonts == null)

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information #region Copyright & License Information
/* /*
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS) * Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made * This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -241,7 +241,7 @@ namespace OpenRA.Mods.RA
domain += 1; domain += 1;
} }
Log.Write("debug", "{0}: Found {1} domains. Took {2} s", map.Title, domain-1, timer.ElapsedTime()); Log.Write("debug", "{0}: Found {1} domains. Took {2} s", map.Title, domain-1, timer.Elapsed.TotalSeconds);
} }
} }
} }