akielaries / openGPMP

Hardware Accelerated General Purpose Mathematics Package
https://akielaries.github.io/openGPMP/
MIT License
8 stars 3 forks source link

ThreadPool class as an end user utility and innate use within functions #45

Closed akielaries closed 10 months ago

akielaries commented 1 year ago

Currently a ThreadPool class is being built as an end user utility allowing to submit functions to the thread pool using a connected dispatch() function. This works, of course if used correctly, and speeds up times in some cases 2.5 - 3x as much. A proper implementation of the ThreadPool could be utilized within the openMTPK functions as well as its end user interface. The interface for end users features much of the C++ standard syntax that comes with the queue and thread related libraries so some optimal abstraction could be used before porting to the Python API.

This is an example of how to dispatch the miller_rabin_prime function to the ThreadPool to iterate through a vector of integers of 64 bit width, spawning 8 total threads.

Note The ThreadPool class can be referenced simply as a class object ThreadPool pool(8) without allocating it to memory. However, this does mean the ThreadPool class object will only be killed when it is no longer in scope, allocating it to memory allows for fine tuned usage.

    std::vector<int64_t> nums = {
        9223372036854775803,   9223372036854775807,
        9223372036854775303,   4567890123456789LL,
        5678901234567890LL,    6789012345678901LL,
        7890123456789012LL,    8901234567890123LL};

    mtpk::ThreadPool *pool = new mtpk::ThreadPool(8);
    std::vector<std::future<bool>> miller_results;

    for (auto n : nums) {
        // enqueue the function call to the thread pool using the
        // ThreadDispatch.dispatch() function
        miller_results.emplace_back(mtpk::ThreadDispatch().dispatch(
            *pool, &mtpk::PrimalityTest::miller_rabin_prime, &prim, n,
            120000));
    }
Time elapsed: 18340 ms

While a traditional call for a non-threaded solution would look like this

    std::vector<int64_t> nums = {
        9223372036854775803,   9223372036854775807,
        9223372036854775303,   4567890123456789LL,
        5678901234567890LL,    6789012345678901LL,
        7890123456789012LL,    8901234567890123LL};

    for (uint64_t n : nums) {
        if (prims.miller_rabin_prime(n, 120000))
            std::cout << n << " is prime" << std::endl;
        else
            std::cout << n << " is composite" << std::endl;
    }
Time elapsed: 48516 ms

Overall, this is great for submitting functions to execute in parallel but implementing the ThreadPool within openMTPK's functions could improve times and effecieny. Some improvements could include implementing a utility timer function to the ThreadPool or Dispatch classes, design around the ThreadPool/Dispatch classes, the latter could extend the former?

This issue will require some knowledge of threading and research into how to properly implement and utilize thread pools.