Skip to content

Commit 8678ead

Browse files
committed
[Linux] Improve backtracer ELF/DWARF parsing performance.
On Linux we use FileImageSource to read data from ELF images. We were doing this in a fairly naive manner, which turns out to be a performance issue with larger statically linked binaries on Linux. Change FileImageSource to use mmap() instead. rdar://117590155
1 parent 8a1eefa commit 8678ead

File tree

2 files changed

+31
-24
lines changed

2 files changed

+31
-24
lines changed

stdlib/public/Backtracing/FileImageSource.swift

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,51 +20,54 @@ import Swift
2020

2121
enum FileImageSourceError: Error {
2222
case posixError(Int32)
23-
case truncatedRead
23+
case outOfRangeRead
2424
}
2525

2626
class FileImageSource: ImageSource {
27-
private var fd: Int32
27+
private var _fd: Int32
28+
private var _mapping: UnsafeRawBufferPointer
2829

2930
public var isMappedImage: Bool { return false }
3031

3132
private var _path: String
3233
public var path: String? { return _path }
3334

34-
public lazy var bounds: Bounds? = {
35-
let size = lseek(fd, 0, SEEK_END)
36-
if size < 0 {
37-
return nil
38-
}
39-
return Bounds(base: 0, size: Size(size))
40-
}()
35+
public var bounds: Bounds? {
36+
return Bounds(base: 0, size: Size(_mapping.count))
37+
}
4138

4239
public init(path: String) throws {
4340
_path = path
44-
fd = _swift_open(path, O_RDONLY, 0)
45-
if fd < 0 {
41+
_fd = _swift_open(path, O_RDONLY, 0)
42+
if _fd < 0 {
43+
throw FileImageSourceError.posixError(_swift_get_errno())
44+
}
45+
let size = lseek(_fd, 0, SEEK_END)
46+
if size < 0 {
4647
throw FileImageSourceError.posixError(_swift_get_errno())
4748
}
49+
let base = mmap(nil, Int(size), PROT_READ, MAP_FILE|MAP_PRIVATE, _fd, 0)
50+
if base == nil || base! == UnsafeRawPointer(bitPattern: -1)! {
51+
throw FileImageSourceError.posixError(_swift_get_errno())
52+
}
53+
_mapping = UnsafeRawBufferPointer(start: base, count: Int(size))
4854
}
4955

5056
deinit {
51-
close(fd)
57+
munmap(UnsafeMutableRawPointer(mutating: _mapping.baseAddress),
58+
_mapping.count)
59+
close(_fd)
5260
}
5361

5462
public func fetch<T>(from addr: Address,
5563
into buffer: UnsafeMutableBufferPointer<T>) throws {
56-
while true {
57-
let size = MemoryLayout<T>.stride * buffer.count
58-
let result = pread(fd, buffer.baseAddress, size, off_t(addr))
59-
60-
if result < 0 {
61-
throw FileImageSourceError.posixError(_swift_get_errno())
62-
}
63-
64-
if result != size {
65-
throw FileImageSourceError.truncatedRead
66-
}
67-
break
64+
let size = buffer.count * MemoryLayout<T>.stride
65+
guard Int(addr) < _mapping.count && _mapping.count - Int(addr) >= size else {
66+
throw FileImageSourceError.outOfRangeRead
67+
}
68+
let slice = _mapping[Int(addr)...]
69+
_ = buffer.withMemoryRebound(to: UInt8.self) { byteBuf in
70+
byteBuf.update(from: slice)
6871
}
6972
}
7073
}

stdlib/public/Backtracing/modules/OS/Libc.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
#include <sys/types.h>
2222
#include <sys/stat.h>
2323

24+
#if __has_include(<sys/mman.h>)
25+
#include <sys/mman.h>
26+
#endif
27+
2428
#if __has_include(<dlfcn.h>)
2529
#include <dlfcn.h>
2630
#endif

0 commit comments

Comments
 (0)