Swift Beta性能:排序数组

Easter79
• 阅读 517

问题:

I was implementing an algorithm in Swift Beta and noticed that the performance was very poor. 我在Swift Beta中实现了一个算法,并注意到性能非常差。 After digging deeper I realized that one of the bottlenecks was something as simple as sorting arrays. 在深入挖掘之后,我意识到其中一个瓶颈就像排序数组一样简单。 The relevant part is here: 相关部分在这里:

let n = 1000000
var x =  [Int](repeating: 0, count: n)
for i in 0..<n {
    x[i] = random()
}
// start clock here
let y = sort(x)
// stop clock here

In C++, a similar operation takes 0.06s on my computer. 在C ++中,类似的操作在我的计算机上需要0.06秒** 。**

In Python, it takes 0.6s (no tricks, just y = sorted(x) for a list of integers). 在Python中,它需要0.6秒** (没有技巧,只有y =排序(x)表示整数列表)。**

In Swift it takes 6s if I compile it with the following command: 在Swift中,如果我使用以下命令编译它需要6秒** :**

xcrun swift -O3 -sdk `xcrun --show-sdk-path --sdk macosx`

And it takes as much as 88s if I compile it with the following command: 如果我使用以下命令编译它需要多达88秒** :**

xcrun swift -O0 -sdk `xcrun --show-sdk-path --sdk macosx`

Timings in Xcode with "Release" vs. "Debug" builds are similar. Xcode中的“释放”与“调试”版本的计时相似。

What is wrong here? 这有什么不对? I could understand some performance loss in comparison with C++, but not a 10-fold slowdown in comparison with pure Python. 与C ++相比,我可以理解一些性能损失,但与纯Python相比,速度没有降低10倍。


Edit: weather noticed that changing -O3 to -Ofast makes this code run almost as fast as the C++ version! 编辑:天气注意到将-O3更改为-Ofast使得此代码的运行速度几乎与C ++版本一样快!** However, -Ofast changes the semantics of the language a lot — in my testing, it disabled the checks for integer overflows and array indexing overflows . 但是, -Ofast改变了语言的语义 - 在我的测试中,它禁止检查整数溢出和数组索引溢出** 。 For example, with -Ofast the following Swift code runs silently without crashing (and prints out some garbage): 例如,使用-Ofast ,以下Swift代码以静默方式运行而不会崩溃(并打印出一些垃圾):

let n = 10000000
print(n*n*n*n*n)
let x =  [Int](repeating: 10, count: n)
print(x[n])

So -Ofast is not what we want; 所以-Ofast不是我们想要的; the whole point of Swift is that we have the safety nets in place. 斯威夫特的全部意义在于我们有安全网。 Of course, the safety nets have some impact on the performance, but they should not make the programs 100 times slower. 当然,安全网对性能有一些影响,但它们不应该使程序慢100倍。 Remember that Java already checks for array bounds, and in typical cases, the slowdown is by a factor much less than 2. And in Clang and GCC we have got -ftrapv for checking (signed) integer overflows, and it is not that slow, either. 请记住,Java已经检查了数组边界,并且在典型情况下,减速是一个远小于2的因素。在Clang和GCC中,我们有-ftrapv用于检查(签名)整数溢出,并且它不是那么慢,无论是。

Hence the question: how can we get reasonable performance in Swift without losing the safety nets? 因此,问题是:如何在不丢失安全网的情况下在Swift中获得合理的性能?


Edit 2: I did some more benchmarking, with very simple loops along the lines of *编辑2:我做了一些基准测试,非常简单的循环*

for i in 0..<n {
    x[i] = x[i] ^ 12345678
}

(Here the xor operation is there just so that I can more easily find the relevant loop in the assembly code. I tried to pick an operation that is easy to spot but also "harmless" in the sense that it should not require any checks related to integer overflows.) (这里的xor操作只是为了让我可以更容易地在汇编代码中找到相关的循环。我试图选择一个易于发现但也“无害”的操作,因为它不需要任何相关的检查到整数溢出。)

Again, there was a huge difference in the performance between -O3 and -Ofast . 同样, -O3-Ofast之间的性能差异-Ofast So I had a look at the assembly code: 所以我看了一下汇编代码:

  • With -Ofast I get pretty much what I would expect. 随着-Ofast我得到了我所期望的。 The relevant part is a loop with 5 machine language instructions. 相关部分是一个包含5个机器语言指令的循环。

  • With -O3 I get something that was beyond my wildest imagination. 有了-O3我得到的东西超出了我的想象力。 The inner loop spans 88 lines of assembly code. 内环跨越88行汇编代码。 I did not try to understand all of it, but the most suspicious parts are 13 invocations of "callq _swift_retain" and another 13 invocations of "callq _swift_release". 我没有尝试理解所有这些,但最可疑的部分是13次调用“callq _swift_retain”和另外13次调用“callq _swift_release”。 That is, 26 subroutine calls in the inner loop ! 也就是说, 内循环中有26个子程序调用


Edit 3: In comments, Ferruccio asked for benchmarks that are fair in the sense that they do not rely on built-in functions (eg sort). *编辑3:在评论中,Ferruccio要求提供公平的基准,因为他们不依赖于内置函数(例如排序)。* I think the following program is a fairly good example: 我认为以下程序是一个相当好的例子:

let n = 10000
var x = [Int](repeating: 1, count: n)
for i in 0..<n {
    for j in 0..<n {
        x[i] = x[j]
    }
}

There is no arithmetic, so we do not need to worry about integer overflows. 没有算术,所以我们不需要担心整数溢出。 The only thing that we do is just lots of array references. 我们唯一做的就是大量的数组引用。 And the results are here—Swift -O3 loses by a factor almost 500 in comparison with -Ofast: 结果在这里 - 与-Ofast相比,Swift -O3损失了近500倍:

  • C++ -O3: 0.05 s C ++ -O3: 0.05秒
  • C++ -O0: 0.4 s C ++ -O0:0.4秒
  • Java: 0.2 s Java: 0.2秒
  • Python with PyPy: 0.5 s 使用PyPy的Python:0.5秒
  • Python: 12 s Python: 12秒
  • Swift -Ofast: 0.05 s Swift -Ofast:0.05秒
  • Swift -O3: 23 s Swift -O3: 23秒
  • Swift -O0: 443 s Swift -O0:443秒

(If you are concerned that the compiler might optimize out the pointless loops entirely, you can change it to eg x[i] ^= x[j] , and add a print statement that outputs x[0] . This does not change anything; the timings will be very similar.) (如果您担心编译器可能会完全优化无意义循环,您可以将其更改为例如x[i] ^= x[j] ,并添加一个输出x[0]的print语句。这不会改变任何内容;时间将非常相似。)

And yes, here the Python implementation was a stupid pure Python implementation with a list of ints and nested for loops. 是的,这里的Python实现是一个愚蠢的纯Python实现,带有一个int列表和嵌套for循环。 It should be much slower than unoptimized Swift. 它应该比未优化雨燕慢得多** 。** Something seems to be seriously broken with Swift and array indexing. 使用Swift和数组索引似乎严重破坏了某些东西。


Edit 4: These issues (as well as some other performance issues) seems to have been fixed in Xcode 6 beta 5. *编辑4:这些问题(以及一些其他性能问题)似乎已在Xcode 6 beta 5中得到修复。*

For sorting, I now have the following timings: 为了排序,我现在有以下时间:

  • clang++ -O3: 0.06 s clang ++ -O3:0.06 s
  • swiftc -Ofast: 0.1 s swiftc -Ofast:0.1秒
  • swiftc -O: 0.1 s swiftc -O:0.1秒
  • swiftc: 4 s swiftc:4秒

For nested loops: 对于嵌套循环:

  • clang++ -O3: 0.06 s clang ++ -O3:0.06 s
  • swiftc -Ofast: 0.3 s swiftc -Ofast:0.3秒
  • swiftc -O: 0.4 s swiftc -O:0.4 s
  • swiftc: 540 s swiftc:540秒

It seems that there is no reason anymore to use the unsafe -Ofast (aka -Ounchecked ); 似乎没有理由再使用unsafe -Ofast (aka -Ounchecked ); plain -O produces equally good code. plain -O产生同样好的代码。


解决方案:

参考一: https://stackoom.com/question/1d7xO/Swift-Beta性能-排序数组
参考二: https://oldbug.net/q/1d7xO/Swift-Beta-performance-sorting-arrays

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
2年前
java将前端的json数组字符串转换为列表
记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang
Easter79 Easter79
2年前
swap空间的增减方法
(1)增大swap空间去激活swap交换区:swapoff v /dev/vg00/lvswap扩展交换lv:lvextend L 10G /dev/vg00/lvswap重新生成swap交换区:mkswap /dev/vg00/lvswap激活新生成的交换区:swapon v /dev/vg00/lvswap
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
ES6 新增的数组的方法
给定一个数组letlist\//wu:武力zhi:智力{id:1,name:'张飞',wu:97,zhi:10},{id:2,name:'诸葛亮',wu:55,zhi:99},{id:3,name:'赵云',wu:97,zhi:66},{id:4,na
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
Easter79
Easter79
Lv1
今生可爱与温柔,每一样都不能少。
文章
2.8k
粉丝
5
获赞
1.2k