用秒表手动分析大量膨胀执行时间

时间:2015-06-18 11:53:00

标签: c# profiling stopwatch

我已经实现了一个基本的二进制堆。我想看看它的表现如何,所以我写了一本快速手册' profiler':

public class MProfile : IDisposable
{
    private static Dictionary<string, ProfilerEntry> _funcs = new Dictionary<string, ProfilerEntry>();
    private Stopwatch _stopwatch;
    private ProfilerEntry _entry;

    public MProfile(string funcName)
    {
        if (!_funcs.ContainsKey(funcName))
        {
            _funcs.Add(funcName, new ProfilerEntry(funcName));
        }

        _entry = _funcs[funcName];

        _stopwatch = Stopwatch.StartNew();
    }

    public void Dispose()
    {
        _stopwatch.Stop();
        _entry.Record(_stopwatch.Elapsed.TotalMilliseconds);
    }
}

这个想法是用using将它包装在函数调用中,它会记录所花费的时间。 ProfileEntry类只是一些调用和总时间。通过将它们存储在名称中,我可以将它们添加起来。

现在,如果我把它包裹在我的整个测试中:

Random random = new Random();

int count = 20000;

using (MProfile profile = new MProfile("HeapTest"))
{
    PriorityHeap<PretendPathNode> heap = new PriorityHeap<PretendPathNode>(count);

    for (int i = 0; i < count; i++)
    {
        int next = random.Next(-1000, 1000);
        heap.Insert(new PretendPathNode(next));
    }

    while (heap.Count() > 0)
    {
        heap.Pop();
    }
}

它会告诉我这需要:40.6682ms

但是,如果我在InsertPop电话周围添加更多的探查器,即:

using (MProfile profile2 = new MProfile("Insert"))
{
    heap.Insert(new PretendPathNode(next));
}

using (MProfile profile3 = new MProfile("Pop"))
{
    heap.Pop();
}

现在所花费的总时间为:452毫秒,107毫秒来自插入,131毫秒来自Pop(注意:我已经在巨大的循环中运行这些测试并取平均值)。我认为我的额外分析&#39;代码显然会产生影响,但是如何将插入和弹出时间膨胀到原始执行时间以上?我认为他们完成一次性意味着 - 只有 - 内部执行时间会被记录下来,这仍然是完全一样的。额外创建一次性,查找字典中的func并处理插入/弹出调用的外部。

是否与JIT和编译/运行时优化等事情有关?扔掉那个一次性有效毁了吗?我想也许它与GC有关,但我尝试了一个不同的探测器(静态手动调用启动/停止),它有0个垃圾而且它是一样的......

编辑:我使用这个稍微更混乱的代码得到相同的时间,它缓存了MProfile对象和Stopwatch对象,因此创建/ GC的次数较少。

public class MProfile : IDisposable
{
    private static Dictionary<string, ProfilerEntry> _funcs = new Dictionary<string, ProfilerEntry>();
    private static Dictionary<string, Stopwatch> _stopwatches = new Dictionary<string, Stopwatch>();
    private static Dictionary<string, MProfile> _profiles = new Dictionary<string, MProfile>();


    private ProfilerEntry _entry;
    private string _name;

    public MProfile(string funcName)
    {
        _name = funcName;
        _entry = new ProfilerEntry(funcName);
        _funcs.Add(funcName, _entry);
    }

    public static MProfile GetProfiler(string funcName)
    {
        if (!_profiles.ContainsKey(funcName))
        {
            _profiles.Add(funcName, new MProfile(funcName));
            _stopwatches.Add(funcName, new Stopwatch());
        }

        _stopwatches[funcName].Restart();
        return _profiles[funcName];
    }



    public void Dispose()
    {
        _stopwatches[_name].Stop();
        _entry.Record(_stopwatches[_name].Elapsed.TotalMilliseconds);
    }
}

通过以下方式调用:

using (profile2 = MProfile.GetProfiler("Insert"))

0 个答案:

没有答案