【问题标题】:Tracking Time Spent in Debugger跟踪在调试器中花费的时间
【发布时间】:2012-06-24 17:19:46
【问题描述】:

[ [ EDIT 2x ] 我认为我原来的问题措辞错误,所以我把它放在下面,并准确地重写了我想要得到的内容,以供未来的读者阅读。 ]

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~
[新的、闪亮的、清晰的问题,措辞更好]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

我有一个正在为模拟/游戏框架运行的循环。这个循环中有几个地方需要确定已经过去了多少时间 - 实际上 - 已经过去了,以便这些特殊地方的逻辑 - 特别是渲染和更新 - 可以正常工作。它可以选择固定时间步长(unfixed[update/render] 为假)。

当基于断点的调试在应用程序的任何点进行时,就会出现问题,因为它使用秒表来计算已经过去了多少实时(为了物理和动画以真实的速度移动,而不是基于关于计算机可以生成多少帧)。

它看起来(大致)像这样,对应用程序循环的每个“部分”使用多个秒表,需要知道自该“部分”上次发生以来已经过去了多少时间:

while ( RunningTheSimulation ) {
    /* ... Events and other fun awesome stuff */

    TimeSpan updatedifference = new TimeSpan( updatestopwatch.ElapsedTicks );

    if ( unfixedupdate || updatedifference > updateinterval ) {

        Time = new GameTime( updatedifference,
                                    new TimeSpan( gamestopwatch.ElapsedTicks ) );
        Update( Time );
        ++updatecount;
        updatestopwatch.Reset( );
        updatestopwatch.Start( );
    }

    TimeSpan renderdifference = new TimeSpan( renderstopwatch.ElapsedTicks );

    if ( unfixedrender || renderdifference > renderinterval ) {

        Time = new GameTime( renderdifference,
                                 new TimeSpan( gamestopwatch.ElapsedTicks ) );
        Render( Time );
        ++rendercount;
        renderstopwatch.Reset( );
        renderstopwatch.Start( );

    }
}   

关于变量的一些信息:

updatestopwatchStopwatch 用于在 Update() 函数之外花费的时间,

renderstopwatch 是一个 Stopwatch,表示在 Render() 函数之外花费的时间,并且

gamestopwatch 是一个Stopwatch,表示模拟/游戏本身的总经过时间。

当我在应用程序的任何地方进行调试时,就会出现问题。因为秒表是实时测量的,所以任何类型的基于断点的调试都将完全取消模拟,因为无论我是否在调试应用程序,秒表都会继续计算时间。我没有使用秒表来衡量性能:我使用它们来跟踪更新、渲染和其他事件(如上图所示)再次发生之间的时间。当我断点并分析并修复 Update() 中的错误时,这会变得非常令人沮丧,但是 Render() 时间完全关闭,以至于任何显示的模拟结果都会被报复性地踢到脸上。

也就是说,当我完全停止调试时,这显然不是问题,但是我有很多开发工作要做,而且我要调试很长时间,所以只是假装这不是不方便就赢了不工作,不幸的是。 =[

我查看了性能计数器,但我似乎无法理解如何让它们在我正在尝试做的事情的上下文中工作:渲染和更新可以包含任意数量的任意代码(它们'特定于在此while 循环之上运行的任何模拟),这意味着我无法稳定地为循环的各个组件执行PerformanceCounter.Increment()

我将继续探讨 System.Diagnostics 和其他 .NET 命名空间,但到目前为止,我对如何“忽略”在附加的调试器中花费的时间一无所知...

有人有什么想法或见解吗?

[ [ EDITS 5x ] 更正了拼写错误并确保所有内容的格式正确。对于那个很抱歉。 ]

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[原始的,不太清楚的问题]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

我在 C# 应用程序中运行了一个恒定循环,我一直在调试它。我目前正在使用秒表,但我可以使用任何其他机制来跟踪经过的时间。当我在这个循环中的某处使用断点之类的事情时,我的问题就开始了(包含在典型的while (true) { ... }中:

if ( unfixedupdate || updatedifference > updateinterval ) 
{
    Time = new GameTime( updatedifference, 
                        new TimeSpan( gamestopwatch.ElapsedTicks ) );
    Update( Time );
    ++updatecount;
    updatestopwatch.Reset( );
    updatestopwatch.Start( );
}

时间测量本身很好,但它测量实际实时 - 包括我花在调试上的任何时间。这意味着如果我在updatestopwatch.Reset() 之后闲逛 17 秒,这会在我的循环中复杂化,并且 - 对于该循环的至少 1 次重新运行 - 我必须处理我在实时考虑到所有我的计算。

有什么方法可以连接到调试器以了解它何时冻结应用程序,以便我可以反测量时间并相应地减去它?正如所标记的那样,我为此使用 .NET 和 C#,但与 Visual Studio 相关的任何内容都可能有助于我朝着正确的方向前进。

[编辑] 为了提供更多信息,我使用了几个秒表(用于更新、渲染和其他一些事件,它们都在不同的消息队列中)。如果我在 Update() 或应用程序的任何其他部分设置断点,秒表将准确测量它们之间花费的实时时间。这包括我花在调试应用程序的各种完全不相关的组件上的时间,这些组件被称为Update()Render()Input() 等的下游。显然模拟的时间(由传递到顶层更新、渲染等的 GameTime 参数控制) .functions) 将无法正常工作,即使 CPU 只用了 13 毫秒来完成更新功能,我也花费了 13 秒的额外调试时间(查看变量然后继续模拟);问题是我会看到其他秒表突然占了 13 额外 秒的时间。如果还是不明白,我再补充。

【问题讨论】:

  • 您能描述一下您希望如何处理这些性能数据吗?调试器开销可能会以更微妙的方式干扰性能测量,而不是简单地将 UI 等待时间添加到 Stopwatch 实例。如果您尝试优化此循环,最好不要在进行测量时使用调试器。
  • 你不能在 Update() 之后但在 updatestopwatch.Reset() 调用之前设置断点吗?
  • 我拥有的不仅仅是更新循环;有一个渲染循环以及其他被捕获和使用的事件。因此,将断点放在其他地方并不是真正的解决方案。

标签: c# .net breakpoints visual-studio-debugging


【解决方案1】:

改用性能计数器。进程 CPU 时间应该提供一个很好的指标(但不如实时秒表准确)并且不应该干扰调试。

【讨论】:

  • 我从来不知道性能计数器。如果 ti 成功,我会试一试,然后回来标记答案。感谢您的帮助。
  • @ThePhD:另一个好处是即使系统的其余部分处于负载状态,它也可以获得实际的 CPU 时间。在这些情况下,实时并没有多大意义:)
  • @ThePhD:你可以在这里看到一些示例代码:github.com/leppie/IronScheme/blob/master/IronScheme/IronScheme/…
  • 感谢您提供代码示例,但我不太确定我是否了解性能计数器以在我遇到的情况下使用它们。我将继续研究它们,但我已经修改了我原来的问题,以更清楚地解释我想要了解的内容。抱歉,如果我没有足够快地理解所有内容......我会继续尝试使用性能计数器来让它做我想做的事情。
  • 秒表和 Processor.GetTime 的组合成功了。谢谢你给我看!
【解决方案2】:

一个可能的解决方案是使用 Debug.WriteLine() 将本地变量(或您尝试调试的任何数据)写入输出。

【讨论】:

  • 这是一件好事,无论我是否设置断点,我都会这样做。我只需要知道在计算上花费了多少时间来执行更新(或渲染或主循环的任何其他组件)之类的事情,而不需要额外的调试时间。
【解决方案3】:

您未能解释您实际尝试调试的内容以及为什么动画计时器完全按照预期使用经过的时间进行调试是一个问题。要知道,当你休息时,时间会继续。实际问题是什么?

另外,请记住,在启用了优化的版本中运行时,调试时的计时不会接近测量值。如果您想逐帧测量时间范围,请使用商业分析工具。找出一个方法或函数花费了多长时间正是它们的目的。

如果您想调试动画是否正常工作,请使用依赖注入和时间提供程序接口创建一个确定性测试,在其中提供时间而不是依赖于挂钟。

这篇文章有一个很好的例子: https://www.toptal.com/qa/how-to-write-testable-code-and-why-it-matters

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-25
    相关资源
    最近更新 更多