Skip to content

Instantly share code, notes, and snippets.

@dmcrodrigues
Created January 4, 2017 01:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dmcrodrigues/e879828a665dd3a723789a7516bf6933 to your computer and use it in GitHub Desktop.
Save dmcrodrigues/e879828a665dd3a723789a7516bf6933 to your computer and use it in GitHub Desktop.
[Benchmark] Lock using a recursive pthread_mutex_t
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