【问题标题】:Is Objective C fast enough for DSP/audio programmingObjective C 是否足够快用于 DSP/音频编程
【发布时间】:2011-02-15 05:24:47
【问题描述】:

我在 iPhone 音频编程方面取得了一些进展。现在我正在做一些性能调整,试图看看我是否可以从这台小机器中挤出更多的东西。运行 Shark,我发现我的 cpu 功率的很大一部分 (16%) 被 objc_msgSend 吃掉了。我知道我可以通过存储指向函数 (IMP) 的指针而不是使用 [object message] 表示法调用它们来加快速度。但如果我要经历所有这些麻烦,我想知道使用 C++ 是否会更好。

对此有什么想法吗?

【问题讨论】:

  • 您有性能问题吗?那是最低的果实吗?
  • objc_msgSend 在我看来确实是最容易实现的目标。

标签: iphone objective-c performance audio


【解决方案1】:

Objective C 对于 DSP/音频编程来说绝对足够快,因为 Objective C 是 C 的超集。您不需要(也不应该)将所有内容都变成消息。在性能至关重要的地方,使用普通的 C 函数调用(或者使用内联汇编,如果有硬件特性可以利用)。如果性能不重要,并且您的应用程序可以从消息间接的功能中受益,请使用方括号。

例如,OS X 上的 Accelerate 框架是一个出色的高性能 Objective C 库。它只使用标准的 C99 函数调用,您可以从 Objective C 代码中调用它们而无需任何包装或间接。

【讨论】:

  • 谢谢斯蒂芬。如果我想以面向对象的方式对音频进行编码,那么 Obj-C 似乎对我没有多大帮助。如果我想要模块化、可插拔的组件并且不想做杂技来调用我的对象上的方法,那么 C++ 可能更适合我的需求。
  • @morgancodes:在我遇到的大多数高性能代码中,模块化发生在相对较高的级别,而不是每个函数调用的级别。没有什么能阻止您使用 Objective-C 消息调度的高级模块化可插拔组件,其核心低级实现使用 C 函数调用。如果这在您的情况下确实不可能,但是 C++ 虚函数查找开销 is 在某种程度上可以接受,那么我想您应该使用 C++。然而,这似乎是一个非常狭窄的情况。
  • @StephenCanon 如果这在您的情况下确实不可能,但 C++ 虚函数查找开销在某种程度上是可以接受的,那么我想您应该使用 C++。然而,这似乎是一个非常狭窄的情况。 -- 这根本不是“狭窄的”。 C++ 的动态分派具有低且几乎不变的复杂性;即它就像使用函数指针。总是。 ObjC 的调度必须经过 ObjC 运行时。这可能(但通常不会)导致许多锁获取和/或分配。所以区别在于 C++ 动态调度具有一致且可预测的时间成本。
  • (续)从技术上讲,这可能已经在 ObjC 中为多达 16 个预定义选择器 (iirc) 完成。此外,在实时渲染中避免 throw 和 dynamic_cast-ing 并不罕见,因为它们的时间复杂度在不同实现中并不可靠(足够)。
  • @justin:这或多或少正是我的观点;如果您不打算使用 C++ 的“更高级”功能,那么它并没有真正为您购买任何您无法通过直接 C 函数调用(可能通过函数指针)轻松完成的东西,这也是目标的一部分-C 语言。
【解决方案2】:

Objective-C 和 DSP 等功能的问题不在于速度本身,而在于无法确定何时会出现不可避免的瓶颈。

所有语言都有瓶颈,但在 C++ 等静态链接语言中,您可以更好地预测它们将在代码中发生的时间和位置。在 Objective-C 的运行时耦合的情况下,找到合适的对象所花费的时间,发送消息所花费的时间不一定很慢,但它是可变的和不可预测的。在时间紧迫的任务中,Objective-C 在 UI、数据管理和重用方面的灵活性对其不利。

Apple API 中的大多数音频处理都是在 C 或 C++ 中完成的,因为需要确定代码执行所需的时间。然而,它很容易在同一个应用程序中混合使用 Objective-C、C 和 C++。这使您可以选择最适合手头任务的语言。

【讨论】:

  • 感谢 TechZen。我认为现在可能是我更多地进入 C++ 领域的时候了。
【解决方案3】:

objc_msgSend 只是一个实用程序。 发送消息的成本不仅仅是发送消息的成本。 这是做消息发起的所有事情的成本。 (就像函数调用的真正成本是它的 inclusive 成本,包括 I/O(如果有的话)。)

您需要知道的是占主导地位的消息从哪里来和去往哪里以及为什么Stack samples 会告诉你哪些例程/方法被频繁调用,你应该弄清楚如何更有效地调用它们。

你可能会发现你打电话给他们的次数超出了你的要求。

特别是如果您发现许多调用是用于创建和删除数据结构,您可能会找到更好的方法来做到这一点。

【讨论】:

  • 谢谢邓拉维先生。让我确保我没有感到困惑。当我在 Shark 中分析我的代码时,我在 objc_msgSend 旁边看到“15%”,这对我来说似乎是一个优化的机会。我认为 15% 是发送消息的实际费用,而不是执行消息启动的代码。正确的?所以在一个紧密的循环中,我确实可以通过避免 objc_msgSend 来获得一些性能,对吧?
  • @morgancodes:不要专注于那个例行公事。这是要做的事情:在它运行时,暂停它大约 20 次并记录调用堆栈。在其中 3 个(大致)上,您应该在 objc_msgSend 中看到它。在这 3 个堆栈上,如果您查看一个级别,您将看到负责该时间的确切代码行。当你在做的时候,寻找出现在多个堆栈上的其他东西,看看你还能摆脱什么。根据我的经验,调整前的代码比 15% 的改进空间要大得多。
  • @morgancodes:Shark 说它在 10 秒内需要 10,000 个样本。假设一行代码有 20% 的时间在堆栈上,因此删除它可以节省总时间。如果你取 20 个样本,那么你会在 20%(4) 的样本上看到它,给或取 9%(1.8)。如果抽取 10,000 个样本,则该行将显示 20% (2000) 的样本,给出或抽取 0.4% (40)。不管怎样,你会想念吗? Shark 的问题在于它给您带来了不必要的精确度,但无法让您通过查看特定样本获得洞察力。
  • 嗯。 XCode 中的调试器没有给我一个有用的调用堆栈。我也没有从仪器中获得任何有用的分析信息,必须使用 Shark。我怀疑这与我的所有音频代码都由来自音频单元的 c 回调调用这一事实有关,而不是来自 iPhone 的主运行循环。所以,我会调查一下,然后试试你的想法。
【解决方案4】:

对于 DSP/音频编程来说,Objective C 是否足够快

实时渲染

绝对不是。 Objective-C 运行时及其库根本不是为实时音频渲染的需求而设计的。事实是,几乎不可能保证使用 ObjC 运行时或 Foundation(甚至 CoreFoundation)等库不会导致您的渲染器错过最后期限。

常见的情况是锁——即使是简单的堆分配(mallocnew/new[][[NSObject alloc] init])也可能需要锁。

使用 ObjC 就是利用库和运行时,这些库和运行时假定锁在其执行过程中的任何时候都是可接受的。锁可以在等待获取锁时暂停渲染线程的执行(例如,在渲染回调期间)。然后,您可能会因为渲染线程被阻塞而错过渲染截止日期,最终导致丢失/故障。

询问专业音频插件开发人员:他们会告诉您在实时渲染域内禁止阻塞。你不能,例如运行到文件系统或创建堆分配,因为您没有关于完成时间的实际上限。

这里有一个很好的介绍:http://www.rossbencina.com/code/real-time-audio-programming-101-time-waits-for-nothing

离线渲染

是的,在大多数高级消息传递的场景中,它的速度是可以接受的。在较低级别,我建议不要使用 ObjC,因为它会很浪费——如果在该级别使用 ObjC 消息传递(与 C 或 C++ 实现相比),渲染时间可能会长很多很多倍。

另见:Will my iPhone app take a performance hit if I use Objective-C for low level code?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-11
    • 1970-01-01
    • 1970-01-01
    • 2015-10-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多