Merge branch 'profiling' into actually_profiling

This commit is contained in:
Andy Adshead 2019-02-02 11:07:14 +00:00
commit 7fcc63c1b1
3 changed files with 52 additions and 15 deletions

View file

@ -1,9 +1,8 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using Ryujinx.Common; using Ryujinx.Common;
namespace Ryujinx.Profiler namespace Ryujinx.Profiler
@ -48,38 +47,44 @@ namespace Ryujinx.Profiler
_history = history; _history = history;
_cleanupRunning = true; _cleanupRunning = true;
// Create low priority cleanup thread, it only cleans up RAM hence the low priority // Create cleanup thread.
_cleanupThread = new Thread(CleanupLoop) _cleanupThread = new Thread(CleanupLoop);
{
Priority = ThreadPriority.Lowest
};
_cleanupThread.Start(); _cleanupThread.Start();
} }
private void CleanupLoop() private void CleanupLoop()
{ {
bool queueCleared = false;
while (_cleanupRunning) while (_cleanupRunning)
{ {
// Ensure we only ever have 1 instance modifying timers or timerQueue // Ensure we only ever have 1 instance modifying timers or timerQueue
if (Monitor.TryEnter(_timerQueueClearLock)) if (Monitor.TryEnter(_timerQueueClearLock))
{ {
ClearTimerQueue(); queueCleared = ClearTimerQueue();
foreach (var timer in Timers) // Calculate before foreach to mitigate redundant calculations
{ long cleanupBefore = PerformanceCounter.ElapsedTicks - _history;
timer.Value.Cleanup(PerformanceCounter.ElapsedTicks - _history, _preserve - _history, _preserve); long preserveStart = _preserve - _history;
}
// Each cleanup is self contained so run in parallel for maximum efficiency
Parallel.ForEach(Timers, (t) => t.Value.Cleanup(cleanupBefore, preserveStart, _preserve));
Monitor.Exit(_timerQueueClearLock); Monitor.Exit(_timerQueueClearLock);
} }
// No need to run too often // Only sleep if queue was sucessfully cleared
if (queueCleared)
{
Thread.Sleep(5); Thread.Sleep(5);
} }
} }
}
private void ClearTimerQueue() private bool ClearTimerQueue()
{ {
int count = 0;
while (_timerQueue.TryDequeue(out var item)) while (_timerQueue.TryDequeue(out var item))
{ {
if (!Timers.TryGetValue(item.Config, out var value)) if (!Timers.TryGetValue(item.Config, out var value))
@ -96,9 +101,17 @@ namespace Ryujinx.Profiler
{ {
value.End(item.Time); value.End(item.Time);
} }
// Don't block for too long as memory disposal is blocked while this function runs
if (count++ > 10000)
{
return false;
} }
} }
return true;
}
public void FlagTime(TimingFlagType flagType) public void FlagTime(TimingFlagType flagType)
{ {
_timingFlags[_timingFlagIndex] = new TimingFlag() _timingFlags[_timingFlagIndex] = new TimingFlag()

View file

@ -69,6 +69,27 @@ namespace Ryujinx.Profiler
return _cachedSession; return _cachedSession;
} }
} }
/// <summary>
/// This equals overload is vital
/// The default comparison is far too slow for the number of comparisons needed because it doesn't know what's important to compare
/// </summary>
/// <param name="obj">Object to compare to</param>
/// <returns></returns>
public override bool Equals(object obj)
{
if (!(obj is ProfileConfig))
return false;
ProfileConfig cmpObj = (ProfileConfig)obj;
// Order here is important.
// Multiple entries with the same item is considerable less likely that multiple items with the same group.
// Likewise for group and category.
return (cmpObj.SessionItem == SessionItem &&
cmpObj.SessionGroup == SessionGroup &&
cmpObj.Category == Category);
}
} }
/// <summary> /// <summary>

View file

@ -62,7 +62,10 @@ namespace Ryujinx.Profiler.UI
// Skip rendering out of bounds bars // Skip rendering out of bounds bars
if (top < 0 || bottom > Height) if (top < 0 || bottom > Height)
{
verticalIndex++;
continue; continue;
}
GL.Color3(Color.Green); GL.Color3(Color.Green);