一个“if”可以产生多大的影响(时间)?语句有一个紧密的循环吗?

发布于 2024-10-05 20:05:47 字数 409 浏览 1 评论 0原文

我正在开发一个 C++ 应用程序,它使用紧密循环来迭代 FSM。目前,由于循环紧密,它使用 100% CPU,而我们的客户不喜欢这样。我想尝试在紧密循环中放入 sleep(1) 来放松它,但我们担心这会使其在我们的大客户(其状态变化很大)之间睡眠时间过长。迅速地!)。我正在考虑尝试这样的事情:

if(smallcustomer)
{
    sleep(1);
}

当程序启动时,smallcustomer 将在其他地方定义。这个“如果”的陈述是否会像睡眠一样减慢事情的速度,并违背其自身的目的?

I'm working on an application in C++ that uses a tight loop to iterate through states in our FSM. Right now, because of the tight loop, it uses 100% CPU, and our customers don't like that. I wanted to try putting a sleep(1) in the tight loop to loosen it up, but we're worried that that will make it sleep too long between states for our large customers (whose states change very quickly!). I was thinking of trying something like this:

if(smallcustomer)
{
    sleep(1);
}

And smallcustomer would be defined somewhere else when the program started up. Does that 'if' statement just slow things down as much as sleep would, and defeating its own purpose?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

污味仙女 2024-10-12 20:05:47

你的意思是,FSM 实际上不应该需要 100% 的 CPU,这让我假设你花了很多时间除了检查是否需要移动到下一个之外什么都不做。状态与否。你说你担心对于大客户来说“睡得太久”,这意味着你担心会错过一些事件:队列填充、鼠标点击、接收到数据包、磁盘 I/O 完成、某个关键事件压,无论如何。您应该重构为异步触发该事件(或多个事件),而不是占用 CPU 在循环中不执行任何操作。

Your implication is that the FSM shouldn't actually need 100% of the CPU, which leads me to assume you are spending a lot of time doing nothing except checking to see if you need to move to the next state or not. You say you are worried about sleeping "too long" for larger customers, which means you are concerned that some event will be missed: a queue filling, a mouse click, a packet being received, completion of disk I/O, a key being pressed, whatever. You should refactor to trigger asynchronously on that event (or events) instead of hogging the CPU doing nothing in a loop.

我要还你自由 2024-10-12 20:05:47

简短的回答:我怀疑简单的 if() 语句不会造成太大伤害。然而,优化的黄金法则是测试测试。

更长的答案:一种更干净(尽管更困难)的方法是将耗时的 FSM 处理移动到单独的/后台线程,也许具有较低的调度优先级。这可能会给您带来两全其美的好处:CPU 空闲时处理速度快,并且由于优先级较低而减少对系统的占用。

只是我的2分钱...

Short answer: I suspect that the simple if() statement won't hurt much. However, the golden rule of optimization is Test Test Test.

Longer answer: A somewhat cleaner (though more difficult) approach would be to move the time-consuming FSM processing to a separate / background thread, perhaps with lower scheduling priority. This might give you the best of both worlds: Fast processing when CPU is free, and less hogging of the system, due to lower priority.

Just my 2 cents...

我很OK 2024-10-12 20:05:47

像这样的简单 if 语句应该编译为比较和分支指令(在某些平台上,您将得到一个;在其他平台上,您将得到两个),它将执行得非常快。

不要强制您的应用程序进入睡眠状态,而是查看您的平台是否支持协作式多任务处理(以便您的进程可以执行)或降低进程的调度优先级的方法。

如果平台支持,usleep会给你比睡眠更精细的控制。

A simple if statement like that should compile to a compare and branch instruction(s) (on some platforms, you'll get one; on others, you'll get two), which will execute very quickly.

Rather than forcing your app to sleep, see if your platform supports cooperative multitasking (so your process can yield execution) or a way of lowering the scheduling priority for your process.

If the platform supports it, usleep will give you finer grain control than sleep.

小糖芽 2024-10-12 20:05:47

假设您的 FSM 按设计工作,应该可以向受影响的客户解释空闲 CPU 并不表示程序设计良好。任何从不进入等待状态的代码都将在其时间片内使用 100% CPU。在很多情况下,这将是一个卖点。

您所做的事情将会降低应用程序的性能。你确定这就是你想要的吗?

如果 FSM 循环过度,或者持续导致其他程序的 CPU 不足,那就另当别论了。在这种情况下,对应用程序进行分析以启用目标代码审查和修改可能会有所帮助。

Assuming your FSM is working as designed, it ought to be possible to explain to the affected customers that idle CPUs are not indicative of a well-designed program. Any code that never hits a wait state is going to use 100% CPU during its time slice. That would be a selling point, in many cases.

What you are doing is going to decrease the performance of your app. Are you sure that's what you want?

If the FSM is looping excessively, or consistently starving other programs of CPU, that's a different discussion. Profiling the app to enable a target code review and modifications could help out in this case.

随风而去 2024-10-12 20:05:47

首先,您应尽可能避免繁忙的等待。在实时嵌入式应用程序之外,它们很少被证明是合理的。即使如此,如果您的控制器并行执行不止一件事,如果可能的话,您将通过中断来实现它。

无论你的原因是什么,你都可以将 if 移出 for 循环,如下所示:

template<bool flag> void myf() {
    for(;;) {
        // your loop goes here

        if(flag)
            sleep(1);
    }
}

void f() {
    smallcustomer ? myf<true>() : myf<false>();
}

这样你就可以强制编译器实例化 myf 的两个副本,并且在每个副本中 flag 是编译时常量。在这两种情况下,编译器都会消除紧密循环内的条件。

这是一种众所周知的编译器优化,称为循环取消切换。大多数现代编译器已经可以从原始代码中自动执行此操作。然而,他们需要某种形式的提示来确定性能增益是否证明重复的机器代码是合理的,这通常以配置文件引导优化的形式出现。

First, you shall avoid busy waits wherever possible. They are rarely justified outside of real-time embedded applications. Even then, if your controller does more than one thing in parallel, you're going to implement it with interrupts, if possible.

Whatever your reason, you can take that if out of the for loop as follows:

template<bool flag> void myf() {
    for(;;) {
        // your loop goes here

        if(flag)
            sleep(1);
    }
}

void f() {
    smallcustomer ? myf<true>() : myf<false>();
}

This way you force the compiler to instantiate two copies of myf, and within each copy flag is a compile-time constant. In both cases the compiler will eliminate the condition inside of the tight loop.

This is a well known compiler optimization called Loop unswitching. Most modern compilers can already do this automatically from your original code. However they need some form of a hint to determine that the performance gain justifies the duplicated machine code, that usually comes in a form of profile-guided optimization.

节枝 2024-10-12 20:05:47

您应该使用比 sleep() 更具体的同步工具 - 例如,Win32 中的可等待计时器,尽管我没有适用于 Linux/Mac 的等效工具。 Sleep() 风格的函数因非常不可靠而臭名昭著。最好的是您可以允许客户更改计时器周期。

You should use a more specific synchronization tool than just sleep()- for example, waitable timers in Win32, although I don't have an equivalent for Linux/Mac. Sleep() style functions are quite notorious for being quite unreliable. What would be best is if you could allow the customer to alter the timer period.

空心空情空意 2024-10-12 20:05:47

现代 CPU 使用相当复杂的条件链来猜测条件分支后面将执行什么指令。由于 CPU 与许多其他指令并行解码和处理每条指令,因此猜测错误的成本可能是灾难性的。只需重新排序分支中的测试,甚至是紧邻之前或之后的代码,都可能导致预测发生变化。不幸的是,没有简单的方法可以预测哪种方法效果更好。

因此,就优化 CPU 密集型代码(如您所描述的)做出明智决策的唯一方法是测量代码实际在做什么,进行小的更改,然后再次测量以查看是否有任何改进。

如果您确实正在运行一个软实时应用程序并且它使用 100% 的 cpu,这可能并不意味着您应该尝试缩减使用量,而是提供更多的 cpu 供其使用,因为输入超出了应用程序跟上的能力。事实上,扩展或缩小可能比提高代码性能更便宜,与开发人员时间相比,服务器硬件更便宜。

Modern CPU's use a rather complex chain of conditions to guess what instruction will follow a conditional branch. Because the CPU decodes and process each instruction in parallel with many other instructions, the cost of getting guessing wrong can be disastrous. Just reordering the tests in the branch, or even the code that comes immediately before or after, can cause the prediction to change. Unfortunately, there's no easy way to predict what will work better.

For this reason, the only way to make informed decisions about optimizing CPU bound code (as you are describing) is to measure what the code is actually doing, making small changes, and measuring again to see if there was any improvement.

If you're really running a soft real-time application and it is using 100% cpu that probably doesn't mean that you should try to scale the usage back, but provide more cpu for it to use, because the input is outrunning the application's ability to keep up. In fact, scaling up or out is probably cheaper than improving the code's performance, server hardware is cheap compared to developer time.

小嗲 2024-10-12 20:05:47

如果您真的担心条件,请尝试此建议在 GCC 中进行分支预测:

#define likely(x)       __builtin_expect((x),1)
#define unlikely(x)     __builtin_expect((x),0)

if(likely(smallcustomer))
{
    sleep(1);
}

If you are really worried about conditionals, try this suggestion for branch prediction in GCC:

#define likely(x)       __builtin_expect((x),1)
#define unlikely(x)     __builtin_expect((x),0)

if(likely(smallcustomer))
{
    sleep(1);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文