4

我目前正在编写一个 C# 应用程序,该应用程序执行大量数字信号处理,其中涉及许多小型微调内存 xfer 操作。我使用不安全指针编写了这些例程,它们的性能似乎比我最初想象的要好得多。但是,我希望应用程序尽可能快。

我会从用 C 或 C++ 重写这些例程中获得任何性能优势,还是应该坚持使用不安全的指针?我想知道与 C/C++ 相比,不安全指针在性能方面带来了什么。

编辑:我在这些例程中没有做任何特别的事情,只是普通的 DSP 东西:缓存友好的数据从一个数组传输到另一个数组,其中有很多乘法、加法、位移等。我希望 C/C++ 例程看起来与 C# 对应的例程几乎相同(如果不相同)。

编辑:非常感谢大家所有聪明的答案。我了解到,除非进行某种 SSE 优化,否则仅通过直接移植不会显着提高性能。假设所有现代 C/C++ 编译器都可以利用它,我期待着尝试一下。如果有人对结果感兴趣,请告诉我,我会在某处发布。(虽然可能需要一段时间)。

4

13 回答 13

16

实际上,我几乎完全按照您的要求做了,只是在图像处理领域。我从 C# 不安全指针开始,然后转到 C++/CLI,现在我用 C++ 编写所有代码。事实上,从那里我从 C++ 中的指针更改为 SSE 处理器指令,所以我一直走下去。还没有达到汇编程序,虽然我不知道是否需要,但我在 CodeProject 上看到一篇文章显示 SSE 可以与内联汇编程序一样快,如果你想要我可以找到它。

在我进行的过程中发生的事情是,我的算法从使用不安全指针的 C# 中的每秒 1.5-2 帧左右变为现在的每秒 40 帧。C# 和 C++/CLI 肯定比 C++ 慢,即使使用指针,我也无法使用这些语言达到每秒 10 帧以上。切换到 C++ 后,我立即获得了每秒 15-20 帧的速度。一些更聪明的改变和 SSE 让我达到了每秒 40 帧。所以,是的,如果你想要我的经验中的速度,那么值得一试。有明显的性能提升。

于 2009-01-29T20:55:42.467 回答
9

优化 DSP 代码的另一种方法是使其缓存友好。如果您有很多过滤器要应用于您的信号,您应该将所有过滤器应用于每个点,即您的最内层循环应该在过滤器上而不是在数据上,例如:

for each n do t´[n] = h(g(f(t[n])))

这样,您将减少缓存的垃圾,并且很可能会获得良好的速度提升。

于 2008-11-04T13:03:52.310 回答
6

我认为你应该用 C++(托管或非托管)或 C# 编写你的 DSP 例程,使用可靠的设计,但不要从一开始就尝试优化所有内容,然后你应该分析你的代码并找到瓶颈并尝试优化那些离开。

试图从一开始就生成“最佳”代码会分散你编写工作代码的注意力。请记住,80% 的优化只会影响 20% 的代码,因为在很多情况下,只有 10% 的代码会占用 90% 的 CPU 时间。(YMMV,因为它取决于应用程序的类型)

当我试图优化我们在图形工具包中对 alpha 混合的使用时,我首先尝试以“裸机”方式使用 SIMD:内联汇编程序。很快我发现使用 SIMD 内在函数比纯汇编更好,因为编译器能够通过重新排列各个操作码并最大限度地利用 CPU 中的不同处理单元来进一步优化具有内在函数的可读 C++。

不要低估编译器的威力!

于 2008-11-04T11:56:55.173 回答
4

我会从用 C/C++ 重写这些例程中获得任何性能优势,还是应该坚持使用不安全的指针?

从理论上讲,这无关紧要——一个完美的编译器会将代码(无论是 C 还是 C++)优化为最好的汇编程序。

然而,在实践中,C 几乎总是更快,特别是对于指针类型算法 - 它尽可能接近机器代码而无需在汇编中编码。

C++ 在性能方面并没有带来任何好处——它被构建为 C 的面向对象版本,为程序员提供了更多的功能和易用性。虽然对于某些事情它会表现得更好,因为给定的应用程序将从面向对象的角度受益,但它并不是要表现得更好 - 它是为了提供另一个抽象级别,以便编写复杂的应用程序更容易。

所以,不,您可能不会看到通过切换到 C++ 来提高性能。

然而,对你来说,发现它可能比避免花时间更重要——我认为将它移植并分析它是一项值得的活动。很有可能,如果您的处理器具有某些 C++ 或 Java 使用指令,并且编译器知道它们,它可能能够利用 C 中不可用的功能。不太可能,但可能。

然而,众所周知,DSP 处理器是复杂的野兽,越接近汇编,就可以获得更好的性能(即,您的代码越是手动调整)。C 比 C++ 更接近汇编。

-亚当

于 2009-01-29T19:58:35.217 回答
3

首先让我回答关于“安全”与“不安全”的问题:您在帖子中说“我希望应用程序尽可能快”,这意味着您不想混淆“安全”或“托管”指针(甚至不提垃圾收集)。

关于您选择的语言:C/C++ 让您可以更轻松地处理底层数据,而不会产生与如今每个人都在使用的精美容器相关的任何开销。是的,被容器拥抱是件好事,这些容器可以防止你发生段错误......但是与容器相关的更高级别的抽象会破坏你的性能。

在我的工作中,我们的代码必须快速运行。一个例子是我们在工作中的多相重采样器,它使用指针和屏蔽操作以及定点 DSP 过滤......如果没有对内存和位操作的低级控制,这些聪明的技巧都不可能真正实现 ==> 所以我说坚持C/C++。

如果你真的想变得聪明,用低级 C 编写所有的 DSP 代码。然后将它与更安全的容器/托管指针混合在一起......当它达到速度时,你需要取下训练轮......它们会减慢你倒太多了。

(仅供参考,关于取下训练轮:您需要额外离线测试您的 C DSP 代码,以确保它们的指针使用良好...... o/w 它会出现段错误。)

编辑:ps“seg faulting”对所有 PC/x86 开发人员来说都是一种奢侈品。当您编写嵌入式代码时……段错误仅意味着您的处理器将进入 wuides 并且只能通过电源循环来恢复;)。

于 2009-01-29T20:41:55.020 回答
2

为了了解如何获得性能提升,最好了解可能导致瓶颈的代码部分。

由于您谈论的是内存传输,我假设所有数据都适合 CPU 的缓存。在这种情况下,你能获得的唯一好处就是知道如何使用 CPU 的内在函数。通常,最熟悉 CPU 内在函数的编译器是 C 编译器。所以在这里,我认为你可以通过移植来提高性能。

另一个瓶颈将出现在 CPU 和内存之间的路径上 - 由于应用程序中的大量内存传输导致缓存未命中。最大的收获将在于最大限度地减少缓存未命中,这取决于您使用的平台以及数据的布局(它是本地的还是通过内存分散的?)。

但是由于您已经在使用不安全的指针,因此您可以自己控制该位,所以我的猜测是:在这方面,您不会从移植到 C(或 C++)中受益匪浅。

结论:您可能希望将应用程序的一小部分移植到 C 中。

于 2009-01-29T20:51:14.050 回答
1

看到您已经在编写不安全的代码,我认为将其转换为 C dll 并从 C# 中调用它们会相对容易。在确定程序中最慢的部分后执行此操作,然后用 C 替换它们。

于 2009-02-02T04:49:41.760 回答
1

你的问题主要是哲学问题。答案是这样的:在你分析之前不要优化。

你问你是否会有所改善。好的,您将获得 N% 的改进。如果这足够了(就像您需要在某些嵌入式系统上在 20 毫秒内执行 200 次的代码),那您就可以了。但如果还不够怎么办?

您必须先进行测量,然后确定代码的某些部分是否可以用相同的语言重写但速度更快。也许您可以重新设计数据结构以避免不必要的计算。也许你可以跳过一些内存重新分配。当可以用线性复杂度完成时,也许可以用二次复杂度完成某些事情。在你测量它之前你不会看到它。这通常比用另一种语言重写所有内容浪费的时间要少得多。

于 2009-02-02T05:35:53.570 回答
1

C# 不支持 SSE(但是,有一个用于 SSE 操作的单声道项目)。因此,带有 SSE 的 C/C++ 肯定会更快。

但是,您必须小心托管到本机和本机到托管的转换,因为它们非常昂贵。尽可能长时间地呆在任何一个世界。

于 2009-02-02T20:26:36.813 回答
1

您真的希望应用程序尽可能快还是足够快?这告诉你下一步应该做什么。

于 2009-02-03T00:58:59.320 回答
1

如果您坚持使用您的手卷,而不在汇编程序或类似程序中进行手动优化,那么 C# 应该没问题。不幸的是,这种问题只能通过实验来真正回答。您已经在非托管指针空间中,所以我的直觉是直接移植到 C++ 不会在速度上看到显着差异。

不过,我应该说,我最近遇到了类似的问题,在尝试了英特尔集成性能基元库后,我们最终放弃了手卷。我们在那里看到的性能改进令人印象深刻。

于 2009-02-03T01:11:56.923 回答
1

Mono 2.2 现在有了SIMD支持,您可以拥有两全其美的托管代码和原始速度。

您可能还想看看在 c# 中使用 SSE 是否可能?

于 2009-02-04T03:28:25.540 回答
0

我建议如果您的 DSP 代码中有任何算法需要优化,那么您真的应该用汇编语言编写它们,而不是 C 或 C++。

一般来说,使用现代处理器和硬件,没有多少场景需要或保证优化所涉及的工作。您是否确实发现了任何性能问题?如果没有,那么最好坚持你所拥有的。在大多数简单算术的情况下,不安全的 C# 不太可能比 C/C++ 慢得多。

你考虑过 C++/CLI 吗?那时你可以两全其美。如果需要,它甚至允许您使用内联汇编程序。

于 2008-11-04T11:45:43.870 回答