|
| 1 | +// |
| 2 | +// ConvTest2.swift |
| 3 | +// Modification of ConvTest, to execute a fixed amount of work, and use dispatch |
| 4 | +// groups to wait for work to complete, rather than dispatch_main. |
| 5 | +// This was primarily while debugging the 'Linux process becomes a zombie' issue |
| 6 | +// with dispatch_main. |
| 7 | +// See: https://github.com/apple/swift-corelibs-libdispatch/pull/99 |
| 8 | +// |
| 9 | +// Created by David Jones (@djones6) on 08/06/2016 |
| 10 | +// |
| 11 | + |
| 12 | +import Foundation |
| 13 | +import Dispatch |
| 14 | + |
| 15 | +// Determine how many concurrent blocks to schedule (user specified, or 10) |
| 16 | +var CONCURRENCY:Int = 10 |
| 17 | + |
| 18 | +// Determines how many times to convert a string per block |
| 19 | +var EFFORT:Int = 1000 |
| 20 | + |
| 21 | +// Determines the length of the payload being converted |
| 22 | +var LENGTH:Int = 1000 |
| 23 | + |
| 24 | +// Determines how many times each block should be dispatched before terminating |
| 25 | +var NUM_LOOPS:Int = 100 |
| 26 | + |
| 27 | +// Debug |
| 28 | +var DEBUG = false |
| 29 | + |
| 30 | +func usage() { |
| 31 | + print("Options are:") |
| 32 | + print(" -c, --concurrency n: number of concurrent Dispatch blocks") |
| 33 | + print(" -e, --effort n: number of times to invoke conversion per block") |
| 34 | + print(" -l, --length n: length of String (in chars) to be converted") |
| 35 | + print(" -d, --debug: print a lot of debugging output") |
| 36 | + exit(1) |
| 37 | +} |
| 38 | + |
| 39 | +// Parse an expected int value provided on the command line |
| 40 | +func parseInt(param: String, value: String) -> Int { |
| 41 | + if let userInput = Int(value) { |
| 42 | + return userInput |
| 43 | + } else { |
| 44 | + print("Invalid value for \(param): '\(value)'") |
| 45 | + exit(1) |
| 46 | + } |
| 47 | +} |
| 48 | + |
| 49 | +// Parse command line options |
| 50 | +var param:String? = nil |
| 51 | +var remainingArgs = Process.arguments.dropFirst(1) |
| 52 | +for arg in remainingArgs { |
| 53 | + if let _param = param { |
| 54 | + param = nil |
| 55 | + switch _param { |
| 56 | + case "-c", "--concurrency": |
| 57 | + CONCURRENCY = parseInt(param: _param, value: arg) |
| 58 | + case "-e", "--effort": |
| 59 | + EFFORT = parseInt(param: _param, value: arg) |
| 60 | + case "-l", "--length": |
| 61 | + LENGTH = parseInt(param: _param, value: arg) |
| 62 | + default: |
| 63 | + print("Invalid option '\(arg)'") |
| 64 | + usage() |
| 65 | + } |
| 66 | + } else { |
| 67 | + switch arg { |
| 68 | + case "-c", "--concurrency", "-e", "--effort", "-l", "--length": |
| 69 | + param = arg |
| 70 | + case "-d", "--debug": |
| 71 | + DEBUG = true |
| 72 | + case "-?", "-h", "--help", "--?": |
| 73 | + usage() |
| 74 | + default: |
| 75 | + print("Invalid option '\(arg)'") |
| 76 | + usage() |
| 77 | + } |
| 78 | + } |
| 79 | +} |
| 80 | + |
| 81 | +if (DEBUG) { |
| 82 | + print("Concurrency: \(CONCURRENCY)") |
| 83 | + print("Effort: \(EFFORT)") |
| 84 | + print("Length: \(LENGTH)") |
| 85 | + print("Debug: \(DEBUG)") |
| 86 | +} |
| 87 | + |
| 88 | +// The string to convert |
| 89 | +let PAYLOAD:String |
| 90 | +var _payload = "Houston we have a problem" |
| 91 | +while _payload.characters.count < LENGTH { |
| 92 | + _payload = _payload + _payload |
| 93 | +} |
| 94 | +// Surely this isn't the best way to substring? but it works... |
| 95 | +PAYLOAD = String(_payload.characters.dropLast(_payload.characters.count - LENGTH)) |
| 96 | +if DEBUG { print("Payload is \(PAYLOAD.characters.count) chars") } |
| 97 | + |
| 98 | +// Create a queue to run blocks in parallel |
| 99 | +let queue = dispatch_queue_create("hello", DISPATCH_QUEUE_CONCURRENT) |
| 100 | +let group = dispatch_group_create() |
| 101 | + |
| 102 | +// Block to be scheduled |
| 103 | +func code(block: Int, loops: Int) -> () -> Void { |
| 104 | +return { |
| 105 | + for _ in 1...EFFORT { |
| 106 | + let _ = PAYLOAD.data(using: NSUTF8StringEncoding) |
| 107 | + } |
| 108 | + if DEBUG { print("Instance \(block) done") } |
| 109 | + // Dispatch a new block to replace this one |
| 110 | + if (loops < NUM_LOOPS) { |
| 111 | + dispatch_group_async(group, queue, code(block: block, loops: loops+1)) |
| 112 | + } else { |
| 113 | + print("Block \(block) completed \(loops) loops") |
| 114 | + } |
| 115 | +} |
| 116 | +} |
| 117 | + |
| 118 | +print("Queueing \(CONCURRENCY) blocks") |
| 119 | + |
| 120 | +// Queue the initial blocks |
| 121 | +for i in 1...CONCURRENCY { |
| 122 | + dispatch_group_async(group, queue, code(block: i, loops: 0)) |
| 123 | +} |
| 124 | + |
| 125 | +print("Go!") |
| 126 | + |
| 127 | +// Go |
| 128 | +//dispatch_main() |
| 129 | +dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 5000000000)) // 5 seconds |
| 130 | +print("Waited 5 seconds, or completed") |
0 commit comments