5

[ [ 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( );

    }
}   

关于变量的一些信息:

updatestopwatch是在 Update() 函数之外花费的时间的秒表,

renderstopwatch是在 Render() 函数之外花费的时间的秒表,并且

gamestopwatch是模拟/游戏本身的总经过时间的秒表

当我在应用程序的任何位置进行调试时,就会出现问题。因为秒表是实时测量的,所以任何类型的基于断点的调试都将完全取消模拟,因为无论我是否在调试应用程序,秒表都会继续计算时间。我没有使用秒表来衡量性能:我使用它们来跟踪更新、渲染和其他事件(如上图所示)再次发生之间的时间。当我断点并分析并修复 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( );
}

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

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

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

4

3 回答 3

2

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

于 2012-06-22T12:11:51.933 回答
0

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

于 2012-06-22T12:10:12.337 回答
0

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

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

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

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

于 2018-07-10T15:20:18.500 回答