Skip to content

Instantly share code, notes, and snippets.

@michaeleisel
Created November 10, 2019 21:18
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 michaeleisel/d3968bf00b7fe519088c344221222807 to your computer and use it in GitHub Desktop.
Save michaeleisel/d3968bf00b7fe519088c344221222807 to your computer and use it in GitHub Desktop.
//Copyright (c) 2018 Michael Eisel. All rights reserved.
import Foundation
import QuartzCore
// import IkigaJSON
import ZippyJSON
import os
func dataFromFile(_ file: String) -> Data {
return try! String(contentsOfFile: Bundle.main.path(forResource: file, ofType: nil)!).data(using: .utf8)!
}
var shouldContinue = true
func standardDeviation(_ arr : [CFTimeInterval]) -> CFTimeInterval {
let length = CFTimeInterval(arr.count)
let avg = arr.reduce(0, {$0 + $1}) / length
let sumOfSquaredAvgDiff = arr.map { pow($0 - avg, 2.0)}.reduce(0, {$0 + $1})
return sqrt(sumOfSquaredAvgDiff / length)
}
func threadTime() -> CFTimeInterval {
var tp: timespec = timespec()
if #available(macOS 10.12, *) {
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp)
} else {
abort()
}
return Double(tp.tv_sec) + Double(tp.tv_nsec) / 1e9;
}
func time(_ closure: () -> ()) -> CFTimeInterval {
let start = threadTime()
let _: Int = autoreleasepool {
closure()
return 0
}
let end = threadTime()
return end - start
}
func prettify(_ time: CFTimeInterval) -> String {
return String(format: "%.2e", time)
}
func profile(runAfter: Bool, testClosure: () -> (), appleClosure: () -> (), otherClosure: () -> ()) {
/*print("Ikiga")
profile(runAfter: false, otherClosure)*/
print("Apple")
profile(runAfter: false, appleClosure)
print("Jaunt")
profile(runAfter: false, testClosure)
}
func pp(_ time: CFTimeInterval) -> String {
return String(format: "%.2e", time)
}
func p(_ times: [CFTimeInterval], _ percent: Double) -> CFTimeInterval {
let idx = Int(Double(times.count) * percent / 100)
return times.sorted()[idx]
}
func summary(_ times: [CFTimeInterval]) {
let average = times.reduce(+)! / CFTimeInterval(times.count)
print("\(pp(average)), \(pp(p(times, 25))), \(pp(p(times, 50))), \(pp(p(times, 75))), standard deviation: \(String(format: "%.02lf", standardDeviation(times) / average * 100))%, min: \(pp(times.min()!)), max: \(pp(times.max()!))")
}
var allTimes: [CFTimeInterval] = []
func profile(runAfter: Bool, _ closure: () -> ()) {
var times: [CFTimeInterval] = []
for _ in 0..<50 {
times.append(time(closure))
}
allTimes += times
// print(times)
summary(times)
if runAfter {
for _ in 0..<500 {
closure()
}
}
}
var twitterData = dataFromFile("twitter.json")
var canadaData = dataFromFile("canada.json")
var githubData = dataFromFile("github_events.json")
var apacheData = dataFromFile("apache_builds.json")
// var data = canadaData
var data = twitterData
// var data = githubData
// var data = apacheData
typealias ToDecode = Twitter
// typealias ToDecode = Canada
// typealias ToDecode = ghEvents
// typealias ToDecode = ApacheBuilds
/*let iDecoder = IkigaJSONDecoder()
//iDecoder.settings.keyDecodingStrategy = .convertFromSnakeCase
let ikigaBlock = {() -> TwitterPayload in
return try! iDecoder.decode(TwitterPayload.self, from: data)
}*/
let testDecoder = ZippyJSONDecoder()
let testBlock = {() -> ToDecode in
return try! testDecoder.decode(ToDecode.self, from: data)
}
let appleDecoder = Foundation.JSONDecoder()
//appleDecoder.keyDecodingStrategy = .convertFromSnakeCase
let appleBlock = {() -> ToDecode in
return try! appleDecoder.decode(ToDecode.self, from: data)
}
func eq(_ o1: Any, _ o2: Any) {
if let array1 = o1 as? Array<Any>, let array2 = o2 as? Array<Any> {
assert(array1.count == array2.count)
for (element1, element2) in array1.zzip(array2) {
eq(element1, element2)
}
} else if let dictionary1 = o1 as? Dictionary<String, Any>, let dictionary2 = o2 as? Dictionary<String, Any> {
assert(dictionary1.count == dictionary2.count)
for key in dictionary1.keys.sorted() {
eq(dictionary1[key]!, dictionary2[key]!)
}
} else if let string1 = o1 as? String, let string2 = o2 as? String {
assert(string1 == string2)
} else if let int1 = o1 as? Int, let int2 = o2 as? Int {
assert(int1 == int2)
} else if let null1 = o1 as? NSNull, let null2 = o2 as? NSNull {
assert(null1 == null2)
} else if let bool1 = o1 as? Bool, let bool2 = o2 as? Bool {
assert(bool1 == bool2)
} else if let d1 = o1 as? Double, let d2 = o2 as? Double {
assert(d1 == d2)
} else {
}
}
func test<T: Equatable>(_ a: [T], _ b: [T]) {
if let zz = a.zzip(b).first(where: { (x, y) in x != y }) {
print("\(zz)")
abort()
}
}
func runTests() {
let a = testBlock()
let b = appleBlock()
assert(a == b)
}
extension DecodingError: Equatable {
public static func == (lhs: DecodingError, rhs: DecodingError) -> Bool {
switch lhs {
case .typeMismatch(let lType, let lContext):
if case let DecodingError.typeMismatch(rType, rContext) = rhs {
return lType == rType && rContext == lContext
}
case .valueNotFound(let lType, let lContext):
if case let DecodingError.valueNotFound(rType, rContext) = rhs {
return lType == rType && rContext == lContext
}
case .keyNotFound(let lKey, let lContext):
if case let DecodingError.keyNotFound(rKey, rContext) = rhs {
return keysEqual(lKey, rKey) && rContext == lContext
}
case .dataCorrupted(let lContext):
if case let DecodingError.dataCorrupted(rContext) = rhs {
return rContext == lContext
}
@unknown default:
return false
}
return false
}
}
func keysEqual(_ lhs: CodingKey, _ rhs: CodingKey) -> Bool {
return lhs.stringValue == rhs.stringValue || (lhs.intValue != nil && lhs.intValue == rhs.intValue)
}
fileprivate struct JSONKey : CodingKey {
public var stringValue: String
public var intValue: Int?
public init?(stringValue: String) {
self.stringValue = stringValue
self.intValue = nil
}
public init?(intValue: Int) {
self.stringValue = "\(intValue)"
self.intValue = intValue
}
public init(stringValue: String, intValue: Int?) {
self.stringValue = stringValue
self.intValue = intValue
}
fileprivate init(index: Int) {
self.stringValue = "Index \(index)"
self.intValue = index
}
fileprivate static let `super` = JSONKey(stringValue: "super")!
}
extension DecodingError.Context: Equatable {
public static func == (lhs: DecodingError.Context, rhs: DecodingError.Context) -> Bool {
let pathsEqual = lhs.codingPath.count == rhs.codingPath.count && zip(lhs.codingPath, rhs.codingPath).allSatisfy { (a, b) in
keysEqual(a, b)
}
return pathsEqual && lhs.debugDescription == rhs.debugDescription
}
}
public func benchmark() {
//testDecoder.keyDecodingStrategy = .convertFromSnakeCase
//appleDecoder.keyDecodingStrategy = .convertFromSnakeCase
if #available(OSX 10.12, *) {
testDecoder.dateDecodingStrategy = .iso8601
appleDecoder.dateDecodingStrategy = .iso8601
}
assert(testBlock() == appleBlock())
for _ in 0..<30 {
profile(runAfter: true, testClosure: {
testBlock()
}, appleClosure: {
appleBlock()
}, otherClosure: {
})
}
summary(allTimes)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment