Skip to content

Instantly share code, notes, and snippets.

@alin23
Last active April 25, 2023 13:16
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alin23/51baae490406b9f1c4e6f0a55b100d4e to your computer and use it in GitHub Desktop.
Save alin23/51baae490406b9f1c4e6f0a55b100d4e to your computer and use it in GitHub Desktop.
Run processes on the "Icestorm" efficiency cores of the M1 Mac chip
#!/usr/bin/env swift
// Inspired by: https://eclecticlight.co/2021/09/14/how-to-run-commands-and-scripts-on-efficiency-cores/
// Run directly:
// chmod +x runbg.swift
// ./runbg.swift
//
// Compile to static binary:
// swiftc runbg.swift -o runbg
// ./runbg
//
// Or download already compiled binary:
// curl https://files.alinpanaitiu.com/runbg > /usr/local/bin/runbg
// chmod +x /usr/local/bin/runbg
// runbg
// Usage examples:
// Optimize all images on the desktop: runbg imageoptim ~/Desktop
// Re-encode video with ffmpeg to squeeze more bytes: runbg ffmpeg -i big-video.mp4 smaller-video.mp4
// Compile project in background: runbg make -j 4
import Foundation
if CommandLine.arguments.count <= 1 {
print(CommandLine.arguments[0], "executable args...")
exit(1)
}
let SHELL = ProcessInfo.processInfo.environment["SHELL"] ?? "/bin/zsh"
let FM = FileManager()
@discardableResult func asyncNow(timeout: TimeInterval, _ action: @escaping () -> Void) -> DispatchTimeoutResult {
let task = DispatchWorkItem { action() }
DispatchQueue.global().async(execute: task)
let result = task.wait(timeout: DispatchTime.now() + timeout)
if result == .timedOut {
task.cancel()
}
return result
}
// MARK: - ProcessStatus
struct ProcessStatus {
var output: Data?
var error: Data?
var success: Bool
var o: String? {
output?.s?.trimmed
}
var e: String? {
error?.s?.trimmed
}
}
func stdout(of process: Process) -> Data? {
let stdout = process.standardOutput as! FileHandle
try? stdout.close()
guard let path = process.environment?["__swift_stdout"],
let stdoutFile = FileHandle(forReadingAtPath: path) else { return nil }
return try! stdoutFile.readToEnd()
}
func stderr(of process: Process) -> Data? {
let stderr = process.standardOutput as! FileHandle
try? stderr.close()
guard let path = process.environment?["__swift_stderr"],
let stderrFile = FileHandle(forReadingAtPath: path) else { return nil }
return try! stderrFile.readToEnd()
}
func shellProc(_ launchPath: String = "/bin/zsh", args: [String], env: [String: String]? = nil) -> Process? {
let outputDir = try! FM.url(
for: .itemReplacementDirectory,
in: .userDomainMask,
appropriateFor: FM.homeDirectoryForCurrentUser,
create: true
)
let stdoutFilePath = outputDir.appendingPathComponent("stdout").path
FM.createFile(atPath: stdoutFilePath, contents: nil, attributes: nil)
let stderrFilePath = outputDir.appendingPathComponent("stderr").path
FM.createFile(atPath: stderrFilePath, contents: nil, attributes: nil)
guard let stdoutFile = FileHandle(forWritingAtPath: stdoutFilePath),
let stderrFile = FileHandle(forWritingAtPath: stderrFilePath)
else {
return nil
}
let task = Process()
task.standardOutput = stdoutFile
task.standardError = stderrFile
task.launchPath = launchPath
task.arguments = args
var env = env ?? ProcessInfo.processInfo.environment
env["__swift_stdout"] = stdoutFilePath
env["__swift_stderr"] = stderrFilePath
task.environment = env
do {
try task.run()
} catch {
print("Error running \(launchPath) \(args): \(error)")
return nil
}
return task
}
func shell(
_ launchPath: String = "/bin/zsh",
command: String,
timeout: TimeInterval? = nil,
env _: [String: String]? = nil
) -> ProcessStatus {
shell(launchPath, args: ["-c", command], timeout: timeout)
}
func shell(
_ launchPath: String = "/bin/zsh",
args: [String],
timeout: TimeInterval? = nil,
env: [String: String]? = nil
) -> ProcessStatus {
guard let task = shellProc(launchPath, args: args, env: env) else {
return ProcessStatus(output: nil, error: nil, success: false)
}
guard let timeout = timeout else {
task.waitUntilExit()
return ProcessStatus(
output: stdout(of: task),
error: stderr(of: task),
success: task.terminationStatus == 0
)
}
let result = asyncNow(timeout: timeout) {
task.waitUntilExit()
}
if result == .timedOut {
task.terminate()
}
return ProcessStatus(
output: stdout(of: task),
error: stderr(of: task),
success: task.terminationStatus == 0
)
}
extension String {
@inline(__always) var trimmed: String {
trimmingCharacters(in: .whitespacesAndNewlines)
}
}
extension Data {
var s: String? { String(data: self, encoding: .utf8) }
}
var executable = (CommandLine.arguments[1] as NSString).expandingTildeInPath
if !FM.fileExists(atPath: executable) {
let which = shell(SHELL, command: "which '\(CommandLine.arguments[1])'")
guard which.success, let output = which.o else {
if let err = which.e {
print(err)
}
print("\(executable) not found")
exit(1)
}
executable = output
}
let p = Process()
p.qualityOfService = .background
p.executableURL = URL(fileURLWithPath: executable)
p.arguments = CommandLine.arguments.suffix(from: 2).map { $0 }
try! p.run()
signal(SIGINT) { _ in p.terminate() }
signal(SIGTERM) { _ in p.terminate() }
signal(SIGKILL) { _ in p.terminate() }
p.waitUntilExit()
exit(p.terminationStatus)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment