智者不为愚者谋,勇者不为怯者死。这篇文章主要讲述为什么Apple Accelerate框架有时会很慢?相关的知识,希望能为你提供帮助。
我正在使用C和Swift 3.0代码,使用来自Apple的vecLib和Accelerate framework作为基于C lang的项目和Swift playground中的动态库+我的代码。
并且,当函数从接近1.000倍的循环调用时,从SIMD指令的框架调用Apple的包装器与1或<
4元素计算函数(如vvcospif()
)的情况比简单的标准cos(x * PI)
慢。
我知道vvcospif()
和cos()
之间的区别,我应该使用vvcospif()
为x * PI
。
在游乐场中的示例,您只需复制代码并运行它:
import Cocoa
import Acceleratefunc cosine_interpolate(alpha: Float, a: Float, b: Float) ->
Float {
let ft: Float = alpha * 3.1415927;
let f: Float = (1 - cos(ft)) * 0.5;
return a + f*(b - a);
}var start: Date = NSDate() as Datevar interp: Float;
for index in 0..<
1000 {
interp = cosine_interpolate(alpha: 0.25, a: 1.0, b: 0.75)
}var end = NSDate();
var timeInterval: Double = end.timeIntervalSince(start);
print("cosine_interpolate in (timeInterval) seconds")func fast_cosine_interpolate(alpha: Float, a: Float, b: Float) ->
Float {
var x: Float = alpha
var count: Int32 = 1var result: Float = 0
vvcospif(&
result, &
x, &
count)let SINSIN_HALF_X: Float = (1 - result) * 0.5;
return a + SINSIN_HALF_X * (b - a);
}start = NSDate() as Datefor index in 0..<
1000 {
interp = fast_cosine_interpolate(alpha: 0.25, a: 1.0, b: 0.75)
}end = NSDate();
timeInterval = end.timeIntervalSince(start);
print("fast_cosine_interpolate in (timeInterval) seconds")
我的问题是:
为什么
vvcospif()
在这个例子中很慢?可能是因为vvcospif()
它是Objective-C运行时下的包装器,并且转换数据结构/从Intel SIMD复制内存 - >
Objective-C- >
Swift运行时比微小的cos()
慢?我也有C代码+的性能问题
#include <
Accelerate/Accelerate.h>
vvcospif(resultVector, inputVector, &
count);
当
inputVector
和resultVector
是带有1或2个元素的小数组或者只是浮点变量时,并且循环调用~1.000.000次。cos(x * PI)
计算时间接近20毫秒。和
vvcospif(x)
处理一个float
或float array[2]
- 计算时间接近80毫秒!加速在哪里? :)是的,在Xcode中我使用编译器
-O -whole-module-optimization
优化与整个模块opt。启用。答案有关示例的更详细讨论,请参阅"Introduction to Fast Bezier (and Trying the Accelerate.framework)"。
第一个基本问题是非内联函数调用非常昂贵。如果您可以在性能关键代码中提供帮助,则不需要函数调用。在模块中,编译器通常可以为您内联函数,并且可以为您内联部分stdlib。但是当你开始跨越模块障碍时,Swift通常无法优化呼叫。
SIMD功能的关键在于您以正确的格式设置所有数据,然后只调用一次。这样,函数调用的成本由您调用的SIMD优化代码组成。
但请记住,您不必调用Accelerate来获得SIMD优化。编译器完全能够注意到你已经编写了一个循环并将其转换为内联SIMD算法本身(并且它一直这样做)。因此,对于许多简单的问题,编译器无论如何都会赢。想一想:如果调用
vvcospif
计数为1比调用cos
更快,他们不会这样实现cos
吗?我没有太多使用你的代码,但是如果你想用Accelerate改进它的性能,你想要考虑如何安排所有的输入数据,这样你就可以用大N调用
vvcospif
一次。很可能在那里一个循环(因为cos
不是微不足道)会快得多的情况。【为什么Apple Accelerate框架有时会很慢()】如果您想在实践中获得Accelerate的示例,以及如何组织数据,请参阅PinchText。此代码通过动画实现最多10次触摸的几千个字形页面的计算偏移(有关结果的信息,请参阅PinchText.mov)。特别是看看
adjustViewPositions:count:forTouchPoint:
。注意count
是如何大的,并且数据是逐步转换的,没有循环。即使抛入(非常昂贵的)ObjC方法调用该方法并不重要,因为它只进行了一次。摆脱循环中的函数调用是性能编程的重要组成部分。推荐阅读
- 错误(不兼容的类型:如果使用android室((__cursor.isNull(null)),则无法转换为int)
- 在Google App Script中使用导入的模块
- 在apply函数中访问索引
- 如何正确使用mapPartitions函数
- 找不到adb请设置ANDROID_HOME异常 - Visual Studio
- Mac中的Android工作室路径错误
- 如何从app delegate访问NSViewController()
- 如何从Android中的图像数组创建视频()
- android异常,即使jdom库存在