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

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

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

编辑:非常感谢大家所有聪明的答案。我所学到的是,除非进行某种SSE优化,否则我只会通过直接端口获得性能上的任何显着提升。假设所有现代C / C ++编译器都可以利用它,我期待着尝试一下。如果有人对结果感兴趣,请告诉我,我会将它们发布到某个地方。 (可能需要一段时间)。

有帮助吗?

解决方案

我实际上已经完成了你所要求的,只是在图像处理领域。我从C#unsafe指针开始,然后进入C ++ / CLI,现在我用C ++编写所有代码。事实上,从那里我改变了从C ++中的指针到SSE处理器指令,所以我一路走了。尚未到达汇编程序,虽然我不知道是否需要,但我看到一篇关于CodeProject的文章显示SSE可以像内联汇编程序一样快,如果你想要我,我可以找到它。

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

其他提示

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

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

通过这种方式,您可以减少垃圾邮件的数量,并且最有可能获得良好的速度提升。

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

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

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

不要低估编译器的强大功能!

  

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

理论上无关紧要 - 完美的编译器会将代码(无论是C还是C ++)优化为最佳的汇编程序。

然而,在实践中,C几乎总是更快,特别是对于指针类型算法 - 它就像你可以在没有编译的情况下获得机器代码一样接近。

C ++在性能方面没有带来任何东西 - 它是作为面向对象的C版本构建的,具有更多的功能和程序员的易用性。虽然对于某些事情它会表现得更好,因为给定的应用程序将从面向对象的角度受益,但它并不意味着更好地执行 - 它旨在提供另一层次的抽象,以便编写复杂的应用程序更容易。

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

然而,找出答案可能比避免花时间更重要 - 我认为将其移植并进行分析是值得的。很可能如果你的处理器有关于C ++或Java使用的某些指令,并且编译器知道它们,它可能能够利用C中不可用的功能。不太可能,但可能。

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

- 亚当

首先让我回答一下“安全”的问题。 vs“unsafe”:你在帖子中说“我希望应用尽可能快”这意味着你不想搞砸“安全”或“管理”指针(甚至不提垃圾收集)。

关于您选择的语言: C / C ++使您可以更轻松地使用底层数据,而不会产生任何与目前每个人都在使用的花式容器相关的开销。是的很好被容器阻塞,这些容器会阻止你进行分段错误......但是与容器相关的更高层次的抽象 RUINS 你的表现。

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

如果你真的想要聪明,请在低级别C中编写所有DSP代码。然后将它与更安全的容器/托管指针混合......当它加速时你需要取下训练轮..他们让你减速太多了。

(仅供参考,关于取消训练轮:你需要额外离线测试你的C DSP代码以确保它们的指针使用良好... o / w它会导致故障。)

编辑:p.s. “seg faulting”是所有PC / x86开发人员的奢侈品。当您编写嵌入式代码时...段故障只意味着您的处理器将进入wuides并且只能通过电源循环恢复;)。

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

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

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

但是既然你已经在使用不安全的指针,那么你就可以控制它了,所以我的猜测是:在这方面,你不会从端口到C(或C ++)中受益很多。

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

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

你的问题在很大程度上是哲学上的。答案是这样的:在你描述之前不要优化。

你问你是否会有所改善。好的,你将获得N%的提升。如果这就足够了(就像你需要在某个嵌入式系统上在20毫秒内执行200次的代码),那你就没事了。但如果还不够呢?

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

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

但是,您必须小心托管到本机和本机到托管的转换,因为它们非常昂贵。在这两个世界中保持尽可能长的时间。

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

如果您坚持使用手卷,没有手动优化装配器或类似装置,C#应该没问题。不幸的是,这是一个只能通过实验回答的问题。你已经处于非托管指针空间,所以我的直觉是C ++的直接端口不会看到速度上的显着差异。

我应该说,最近我遇到了类似的问题,我们在尝试 Intel Integrated Performance Primitives 库。我们看到的性能改进非常令人印象深刻。

Mono 2.2现在有 SIMD 支持,你可以拥有最好的两个世界的托管代码和原始速度。

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

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

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top