【问题标题】:High CPU usage with XNAXNA 的高 CPU 使用率
【发布时间】:2012-11-09 01:08:42
【问题描述】:

我今天刚刚注意到,当我编译并运行一个新的 XNA 4.0 游戏时,其中一个 CPU 线程以 100% 的速度运行,并且帧速率下降到 54 FPS。

奇怪的是,有时它以 60 FPS 的速度运行,但随后却下降到 54 FPS。

我之前没有注意到这种行为,所以我不知道这是否正常。我卸载了我的防病毒软件并重新安装了 XNA Game Studio、XNA Redistributable 和 .NET Framework 4。

如果我将 IsFixedTimeStep 设置为 false,则游戏以 60 FPS 运行并且 CPU 使用率最低 (1-2%)。但据我所知,这需要我使用 ElapsedGameTime 进行速度计算,但我不知道该怎么做,因为我对 XNA 还很陌生。但有人说将其设置为 false 会减少生涩的动画。

我已经查过this forum thread,但是没有人找到好的解决方案。

有人遇到过这个问题吗?

编辑: 我做了更多的研究,我实现了一个 FPS 计数器(直到现在,我用 Fraps 测量它),我的计数器显示游戏以 60 FPS 运行(IsFixedTimeStep = true),所以这解决了 FPS 问题,但是高 CPU用法仍然存在。这种情况可能发生在每个人身上吗?

【问题讨论】:

  • 也遇到了这个问题,试图确定它让我非常头疼,因为分析只会告诉我时间花在了框架代码的某个地方。有趣的是,如果程序不在前台,它会继续正确更新/绘图/运行,但 CPU 使用率会下降到正常水平。
  • 你有几个核心?一般来说,游戏循环 while(1) { update(); draw(); }"busy wait" 永远不会休眠(否则游戏会滞后),因此您应该期望至少 100% 的一个逻辑核心被使用。 (所以如果你有一个双核 CPU,它应该是 50%,双核超线程,应该是 25% 左右)

标签: c# windows xna cpu frame-rate


【解决方案1】:

根据this discussion on XBox Live Indie Games forum,显然在某些处理器(和操作系统)上,当使用默认值 Game.IsFixedTimeStep 时,XNA 在一个内核上占用100% CPU 时间 /strong>。

一个常见的解决方案(也适用于我)是将以下内容放入您的 Game 构造函数中:

IsFixedTimeStep = false;

什么意思?

Game.IsFixedTimeStep 属性,当 true 时,确保您的框架(Update()Draw(),...)以在Game.TargetElapsedTime 中指定的固定时间间隔调用.这默认为 每秒 60 次调用

Game.IsFixedTimeStep = false 时,对下一帧的调用将在前一帧完成时发生。如下图所示:


此更改对我的代码有何影响?

所有固定时间计算(运动计时等)都需要修改以适应可变时间步长。幸运的是,这很简单

假设你有

Vector3 velocity;
Vector3 position;

对于某些对象,您正在更新位置

position += velocity;

默认情况下,这意味着对象的速度为 60 * velocity.Length() 单位每秒。你每秒增加 60 次速度。

当你把那句话翻译成代码时,你会得到这个简单的修改

position += velocity * 60 * gameTime.ElapsedGameTime.TotalSeconds;

简单地说:您正在根据经过的时间来缩放添加的值

通过在您执行移动(或计时等)的位置进行这些修改,您将确保您的游戏在固定时间步长时运行。

【讨论】:

  • 这真的让一切变得更加困难。到目前为止,我只需要将速度添加到当前位置。真的没有其他方法可以解决这个问题吗?
  • 将我的更新与 GameTime 集成是我的 XNA 应用程序发生过的最好的事情之一,这绝对值得(非常小的)移植。
  • 亲爱的主,它使用忙循环来固定步数? 并且它默认使用它??微软,我以为你更清楚!
  • 关于您的“编辑 2”,我看不出固定的时间步长会如何影响速度——它仍然是相同的时间流逝,只是增量不同!
  • 您正在尝试解决一个非问题。游戏应用程序的一个内核的 CPU 使用率预计为 100%
【解决方案2】:

高 CPU 使用率(100% 在一个内核上)对于游戏来说是非问题。换句话说,这是预期的。您在编写游戏时使用 CPU 的方式要求您这样做。

打开代码环境,编写一个简单的程序

void main(){
    while(1) puts( "aaah" ) ;
}

打开 CPU 监视器,看到一个核心 100% 被使用。

现在你的游戏正在这样做:

void main(){
    while(1){
        update() ;
        draw() ;

        while( getTimeElapsedThisFrame() < 1.0/60.0 ) ; // busy wait, until 16ms have passed
    }
}

所以基本上你调用 update()draw(),这占用了你必须计算一个帧的大部分 16 毫秒(当你的游戏有很多时你占用大部分时间里面的东西)。

现在因为O/S sleep resolution is not exact(如果您调用sleep( 1ms ),它实际上可能会在您的应用再次唤醒之前休眠20ms),发生的情况是游戏永远不会调用操作系统系统函数SleepSleep 函数会导致您的游戏“睡过头”,并且游戏会显得迟钝和缓慢。

良好的 CPU 使用率不值得拥有无响应的游戏应用。所以标准是“忙等待”,在占用 CPU 的同时减少时间。

【讨论】:

  • 我不同意。游戏可以是GPU or CPU bound。如果它受 GPU 限制,很可能是用于图形繁重的游戏,那么 CPU 会将那部分时间花在空闲上。但是,即使您会在具有额外逻辑的那些中增加 CPU 时间,那也不会是您的输入逻辑,因为每帧调用一次 Update()。响应性将保持不变。此外,设置IsFixedTimeStep = false 告诉 XNA尽可能快地调用帧(更新、绘制),而不是在固定间隔内。
  • CPU bound 或 GPU bound 仅指瓶颈是 CPU 或 GPU。在这里没关系。我在上面显示的代码显示了在绘制框架时 XNA 框架内发生的情况,并显示了为什么您应该期望至少 100% 一个核心在您的游戏运行时始终处于使用状态。
  • 我还是不同意。创建一个 XNA 游戏项目并运行它。任何核心都需要100%吗?对我来说不是。在另一台 PC 上它确实如此,直到我做出改变。即使您发布的这个无限循环也从未使用 100% - check it out
  • 它正在使用 100% 的一个内核(1 core/8=您可用 CPU 总量的 12.5%)。您在那里看到的(100% 负载在您的 8 个内核之间重新分配)必须有一个名称,但我不知道它是什么。
  • 您的理由是:游戏应用程序有一个循环,因此它们必须在内核上使用 100% 的 CPU。但是如果你真的运行一个 XNA 游戏项目,你不会在核心上获得 100% 的使用率——所以你的推理是错误的。如果您不想自己检查,here's an example。因此,一个核心的 100% 使用上限实际上是一个真正的问题,这种问题很少发生,而且在某些配置上会发生。
猜你喜欢
  • 2014-08-26
  • 1970-01-01
  • 2021-12-09
  • 2014-07-16
  • 2014-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多