How can I parallelize my macOS app tasks as much as possible without running out of memory?

BearOverflow

I have a Swift app running on macOS. It batch-processes images. I don't know ahead of time how big these images are going to be, and what hardware my app is going to run on - these are both user dependent.

I use GCD to parallelize the processing of the images as it can really accelerate the throughput.

However, in some cases, too much parallelization can hurt: if the user processes high resolution images, the parallelization creates too much memory pressure, and the system's performance becomes really poor.

So I'd like to find a way to "feed my parallel task processor" at a rate that maximizes parallelization while keeping the workload in RAM (so there aren't any triggers to paging & swapping: I want to avoid disk IO).

Any ideas on how to do that?

BearOverflow

I ended up implementing a TokenBucket-type of singleton that deals with admission control based on memory requirements. It gets initialized such that 80% of the RAM can be used by my app.

let memoryGate = MemoryGate(maxBytes: ProcessInfo.processInfo.physicalMemory*8/10)

When someone wants to perform a memory intensive operation, it has to request() memory from it. If there isn't enough memory, the call blocks until there is. After being done, the thread has to release() the memory.

Code:

class MemoryGate {

    private let maxBytes : UInt64
    private var availableBytes : Int64

    private let cv = NSCondition()

    init(maxBytes: UInt64) {
        self.maxBytes = maxBytes
        self.availableBytes = Int64(maxBytes)
        Log.debug?.message("maxBytes=\(maxBytes)")
    }

    public func request(amount: UInt64) {
        Log.debug?.message("Resquesting \(amount) bytes")
        cv.lock()

        // If the amount is bigger than the max allowed, no amount of waiting is going
        // to help, so we go through and let the other smaller jobs be held back until
        // memory is freed
        if (amount <= maxBytes) {
            while (availableBytes < Int64(amount)) {
                cv.wait()
            }
        }

        availableBytes -= Int64(amount)

        Log.debug?.message("Got \(amount) bytes. availableBytes=\(availableBytes)")
        cv.unlock()
    }

    public func release(amount: UInt64) {
        cv.lock()
        availableBytes += Int64(amount)
        Log.debug?.message("Released \(amount) bytes. availableBytes=\(availableBytes)")
        cv.broadcast()
        cv.unlock()
    }
}

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

How can I use randsample in Matlab without running out of memory?

How can I find out how much memory a UIImageView is using?

How can I query to find out if my MacOS/X app is in app-nap mode?

My App is not running on Genymotion, I get out of Memory error

How can I configure Spring to save as much memory as possible?

How do I make a puzzle app in droid without running out of memory?

Can I get how much memory for my program remains?

How can I read tsv files and store them as hdf5 without running out of memory?

How can I develop Safari App Extension without macOS app?

While my app is running, how can I update the current activity with the contents a GCM notification, without clicking on the notification?

How much memory can I use in javascript?

How can I have a live timer that updates every second to see for how much my programming is running? python

How can I find out how much space is used by my container images from the Google Container Registry

How can I keep my Azure WebJob running without "Always On"

I keep running out of memory and swapping but having a hard time figuring out what is using so much ram

How can I get prometheus exporters running in my grails app?

How can I detect, that my app is running on the Ripple Emulator?

How can I detect if my app is running on Windows 10

How can I programmatically determine if my app is running in the iphone simulator?

How can I detect if my Flutter app is running in the web?

How can I tell if my intent is running in the Shortcuts app?

How do I divide a very large OpenStreetMap file into smaller files in R without running out of memory?

How do I stream a large file from api to api without using disk and running out of memory?

How do I load the CelebA dataset on Google Colab, using torch vision, without running out of memory?

How do I iterate through a large file without running out of memory in python?

How do I store information for weighed graph without running out of memory?

Why does my prime factorization code in processing 3 use so much memory and how can I make it use less memory?

How can I parallelize sorting?

How can I parallelize combn()?