Created
January 4, 2017 01:28
-
-
Save dmcrodrigues/e879828a665dd3a723789a7516bf6933 to your computer and use it in GitHub Desktop.
[Benchmark] Lock using a recursive pthread_mutex_t
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import XCTest | |
import Foundation | |
let iterationCount = 10_000_000 | |
class BenchmarksTests: XCTestCase { | |
func testRecursiveLock_NoRecursion() { | |
self.measure { | |
invoke(RecursiveLock<Int>(), times: iterationCount) | |
} | |
} | |
func testRecursiveLock_Recursion2() { | |
self.measure { | |
invoke(RecursiveLock<Int>(), times: iterationCount, recursionLevel: 2) | |
} | |
} | |
func testRecursiveLock_Recursion4() { | |
self.measure { | |
invoke(RecursiveLock<Int>(), times: iterationCount, recursionLevel: 4) | |
} | |
} | |
func testRecursiveLock_Recursion8() { | |
self.measure { | |
invoke(RecursiveLock<Int>(), times: iterationCount, recursionLevel: 8) | |
} | |
} | |
func testRecursivePThreadLock_NoRecursion() { | |
self.measure { | |
invoke(RecursivePThreadLock<Int>(), times: iterationCount) | |
} | |
} | |
func testRecursivePThreadLock_Recursion2() { | |
self.measure { | |
invoke(RecursivePThreadLock<Int>(), times: iterationCount, recursionLevel: 2) | |
} | |
} | |
func testRecursivePThreadLock_Recursion4() { | |
self.measure { | |
invoke(RecursivePThreadLock<Int>(), times: iterationCount, recursionLevel: 4) | |
} | |
} | |
func testRecursivePThreadLock_Recursion8() { | |
self.measure { | |
invoke(RecursivePThreadLock<Int>(), times: iterationCount, recursionLevel: 8) | |
} | |
} | |
} | |
func invoke<A: Testable>(_ target: A, times: Int, recursionLevel: Int = 0) { | |
for _ in 0 ..< times { | |
target.evaluateN(recursionLevel) | |
} | |
} | |
protocol Testable: class { | |
func evaluateN(_ n: Int) | |
} | |
private final class Lock { | |
private var mutex: pthread_mutex_t | |
private init(_ mutex: pthread_mutex_t) { | |
self.mutex = mutex | |
} | |
deinit { | |
let result = pthread_mutex_destroy(&mutex) | |
precondition(result == 0, "Failed to destroy mutex with error \(result).") | |
} | |
@inline(__always) | |
fileprivate func lock() { | |
let result = pthread_mutex_lock(&mutex) | |
precondition(result == 0, "Failed to lock \(self) with error \(result).") | |
} | |
@inline(__always) | |
fileprivate func unlock() { | |
let result = pthread_mutex_unlock(&mutex) | |
precondition(result == 0, "Failed to unlock \(self) with error \(result).") | |
} | |
fileprivate static var nonRecursive: Lock { | |
var mutex = pthread_mutex_t() | |
let result = pthread_mutex_init(&mutex, nil) | |
precondition(result == 0, "Failed to initialize mutex with error \(result).") | |
return self.init(mutex) | |
} | |
fileprivate static var recursive: Lock { | |
func checkSuccess(_ instruction: @autoclosure () -> Int32, _ label: String) { | |
let result = instruction() | |
precondition(result == 0, "Failed to initialize \(label) with error: \(result).") | |
} | |
var attr = pthread_mutexattr_t() | |
checkSuccess(pthread_mutexattr_init(&attr), "mutex attributes") | |
checkSuccess(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE), "mutex attributes") | |
defer { pthread_mutexattr_destroy(&attr) } | |
var mutex = pthread_mutex_t() | |
checkSuccess(pthread_mutex_init(&mutex, &attr), "mutex") | |
return self.init(mutex) | |
} | |
} | |
final class RecursiveLock<Value>: Testable { | |
private let lock = NSRecursiveLock() | |
func evaluateN(_ n: Int) { | |
lock.lock() | |
if n > 0 { evaluateN(n - 1) } | |
lock.unlock() | |
} | |
} | |
final class RecursivePThreadLock<Value>: Testable { | |
private let lock = Lock.recursive | |
func evaluateN(_ n: Int) { | |
lock.lock() | |
if n > 0 { evaluateN(n - 1) } | |
lock.unlock() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment