OOX: Out-of-Order Executor library. Yet another approach to efficient and scalable tasking API and task scheduling.

OOX

Out-of-Order Executor library. Yet another approach to efficient and scalable tasking API and task scheduling.

Try it

  • Requirements: Install cmake, make, googletest, google benchmark, and optionally TBB (recommended), and TaskFlow libraries into your environment.
  • Build & run: make
  • Install: make install

Continuation-focus design

With nested parallelism, blocking style programming is deadlock-prone and has latency problems. OOX provides semantic way out of these issues.

std::future is not intended for continuation tasks. Even with existing proposals like .then(), the continuation-style is limited - while OOX offers:

  • Implicitly collapse template recursion of 'futures': future x = async(async(async(…)));
  • Implicitly unpack 'futures' to a value in arguments: async([](int a){}, async(…));
  • Implicit value conversion for a 'future' variable. e.g.: future<int> x{2};
  • Implicitly build dependencies based on arguments: No blocking synchronization in the algorithm

This approach enables beautifully concise recursive parallelism programming like:

oox::var<int> Fib(int n) {         // OOX: High-level continuation style programming
    if(n < 2) return n;
    auto left = oox::run(Fib, n-1);
    return oox::run(std::plus<int>(), std::move(left), Fib(n-2));
}

In contrast, both Intel Threading Building Blocks (TBB) and TaskFlow examples do block, which makes them slower than OOX besides requiring verboser coding:

int Fib(int n) {                    // TBB: High-level blocking style programming
    if(n < 2) return n;
    int left, right;
    tbb::parallel_invoke(           // blocks here
        [&] { left = Fib(n-1); },
        [&] { right = Fib(n-2); }
    );
    return left + right;
}

and

int Fib(int n, tf::Subflow& sbf) {  // TaskFlow: High-level blocking style programming
    if (n < 2) return n;
    int res1, res2;
    sbf.emplace([&res1, n] (tf::Subflow& sbf) { res1 = Fib(n - 1, sbf); } );
    sbf.emplace([&res2, n] (tf::Subflow& sbf) { res2 = Fib(n - 2, sbf); } );
    sbf.join();                     // blocks here
    return res1 + res2;
}

Quick Reference

  • oox::var<T>: Basic representation of data in the OOX graph. In concept, a new form of std::future for continuations. It carries both: a value and dependency info
    • using oox::node = oox::var<void>: carries solely dependency info
  • oox::var<T> oox::run(T(Func&)(...), Args...): Basic tasking API, spawns a task when arguments are ready and returns oox::var as a promise to provide the result of Func in future. If there are oox::var arguments, which are not ready yet (i.e. they are "promises" themselves), it makes a continuation task, which depends on completion of pending oox::var arguments.

Design

Pillars:

  • Abstract user functor from async dependencies: oox::run([](functor args...){}, dependency args...)
  • Reuse functor and runner arg types matching for dependency type specification
    • Flow, output, and anti-dependencies are deduced
    • Makes duplication of arguments finally useful
  • Have clear serialization semantics for ease of debugging

Matching rules:

  • plain arguments:
    • Follow C++ rules: everything is passed as decay copy
    • Use std::ref and std::cref for passing by reference (and take responsibility for the lifetime)
  • oox::var arguments:
    • Similar to std::ref: usually passed by reference but it cares about lifetime and access sync
    • oox::var usage has to be indifferent from plain types

Stored types:

  • oox::run returns oox::var for decay type of functor return type, copy- or move-initialized.
  • oox::var doesn't store references. Use std::reference_wrapper or pointer types instead
  • Don't compile oox_var if not is_same<T, std::decay<T>::type>
  • oox::var is reference-counted, it is safe for end of scope

Access types of oox::var's stored value:

  • Read-Write: Exclusive access: both matching arguments are passed by reference
  • Read-Only: Shared access: auto f = [](const A&){} with oox::var<A>& a or const oox::var<A>& a while running oox::run(f, a)
  • Copy-Only: Copy access: like read-only but does not hold off following read-write access after a copy is done, auto f = [](A){} or auto f = [](A&&){} with oox::var<A>& a or const oox::var<A>& a while running oox::run(f, a)
  • Final: dispose after use: oox::var<A>&& a

More resources

Owner
Similar Resources

C++14 coroutine-based task library for games

SquidTasks Squid::Tasks is a header-only C++14 coroutine-based task library for games. Full project and source code available at https://github.com/we

Nov 30, 2022

this repo will introduce you the mechanism and approach of gaussian blur

this repo will introduce you the mechanism and approach of gaussian blur

浅谈高斯模糊原理与实现 简介   早在高中,图像模糊就勾起我的兴趣:为什么近视眼看东西会模糊、透过毛玻璃的像为什么会模糊、以及win7的毛玻璃模糊特效是如何实现的,当时也有方式去查资料去实现这样的一个效果。转眼本科毕业,最近又出现一个比较热门的话题:国内安卓魔改系统的的实时模糊在高帧率下的表现,实时

Nov 16, 2022

A General-purpose Parallel and Heterogeneous Task Programming System

A General-purpose Parallel and Heterogeneous Task Programming System

Taskflow Taskflow helps you quickly write parallel and heterogeneous tasks programs in modern C++ Why Taskflow? Taskflow is faster, more expressive, a

Dec 31, 2022

A General-purpose Parallel and Heterogeneous Task Programming System

A General-purpose Parallel and Heterogeneous Task Programming System

Taskflow Taskflow helps you quickly write parallel and heterogeneous task programs in modern C++ Why Taskflow? Taskflow is faster, more expressive, an

Dec 26, 2022

Arcana.cpp - Arcana.cpp is a collection of helpers and utility code for low overhead, cross platform C++ implementation of task-based asynchrony.

Arcana.cpp Arcana is a collection of general purpose C++ utilities with no code that is specific to a particular project or specialized technology are

Nov 23, 2022

EnkiTS - A permissively licensed C and C++ Task Scheduler for creating parallel programs. Requires C++11 support.

EnkiTS - A permissively licensed C and C++ Task Scheduler for creating parallel programs. Requires C++11 support.

Support development of enkiTS through Github Sponsors or Patreon enkiTS Master branch Dev branch enki Task Scheduler A permissively licensed C and C++

Dec 27, 2022

A hybrid thread / fiber task scheduler written in C++ 11

Marl Marl is a hybrid thread / fiber task scheduler written in C++ 11. About Marl is a C++ 11 library that provides a fluent interface for running tas

Jan 4, 2023

Task System presented in "Better Code: Concurrency - Sean Parent"

Task System presented in

task_system task_system provides a task scheduler for modern C++. The scheduler manages an array of concurrent queues A task, when scheduled, is enque

Dec 7, 2022

Jobxx - Lightweight C++ task system

jobxx License Copyright (c) 2017 Sean Middleditch [email protected] This is free and unencumbered software released into the public domain. A

May 28, 2022
Comments
  • Support strictly lazy (deferred) execution

    Support strictly lazy (deferred) execution

    There are two ways to implement it.

    1. Rely on "deferring" oox::var. When all the execution is dependent on some empty oox var, which is not marked as ready until assigned a value that unlocks the whole dependent graph.
    2. Implement executor/scheduler objects on which oox::run is invoked. E.g. oox::lazy_scheduler oo; oo.run(...);
  • Introduce shared access synchronization via oox::shared_var

    Introduce shared access synchronization via oox::shared_var

    Current oox::var is not ready to be accessed concurrently from multiple threads. Wrapping it with a lock is also not a good idea as it contradicts to concepts of OOX, which wants to replace everything that blocks as much as possible. Since the synchronization is not cheap, let's introduce a special type of oox::var according to the pay-as-you-go principle. Let it be oox::shared_var, and the use case is like this:

    concurrent_unordered_map<std::string, oox::shared_var<money_t>> db;
    
    // thread-safe function for money transfer
    void transfer(std::string from, std::string to, money_t amount) {
      oox::run(
        [](money_t& src, money_t& dst, money_t n){
            src -= n; dst += n;
        }, db[from], db[to], amount);
    }
    
  • Introduce data-parallelism to oox::run via oox::for_each decorator

    Introduce data-parallelism to oox::run via oox::for_each decorator

    Define and implement data-parallelism as Numpy-style vectorized functions. For Example:

    // oox::range is implementation of C++20 range concept
    oox::range<int> r1{100}, r2{100,200}; // view for iota ?
    
    auto f1 = [](int i){ noop(); };
    auto f2 = [](oox::range<int> r){ for(auto i : r) noop(); };
    
    oox::run(f1, oox::for_each(r1) );        // call f1() for each iteration of 
    oox::run(f2, oox::for_each(r1, 10));   // call f2() for each subrange of size 10
    oox::run(f1, r1 | oox::for_each() );     // same for c++20
    oox::run(f1, r1 | oox::for_each(10) ); // same for c++20
    
    auto f3 = [](int i, int x, int a){};         // functor does not know which argument is parallelized
    oox::run(f3, oox::for_each(r1), 1, oox::for_each(r2));
    
    auto f4 = [](int i){ return i; };
    oox::run(f1, oox::for_each( oox::run(f4, oox::for_each(r1) )) );   // continuation for each iteration of f4()
    
    auto a = oox::reduce( f, 0, oox::for_each( oox::run(...) ));        // reduction can be implemented like this
    
    a = oox::map_reduce(reduce_f, map_f, 1, oox::for_each(a))  //  map-reduce
    

    Your ideas are welcome!

A library for enabling task-based multi-threading. It allows execution of task graphs with arbitrary dependencies.

Fiber Tasking Lib This is a library for enabling task-based multi-threading. It allows execution of task graphs with arbitrary dependencies. Dependenc

Dec 30, 2022
Yet Another Concurrency Library

YACLib YACLib (Yet Another Concurrency Library) is a C++ library for concurrent tasks execution. Documentation Install guide About dependencies Target

Dec 28, 2022
capcom-like executor for any physmem driver
capcom-like executor for any physmem driver

dolboeb-executor Arbitrary code execution inside of vulnerable driver How's this works? Dolboeb-executor will replace a function inside vulnerable dri

Nov 23, 2022
Scheduler - Modern C++ Scheduling Library

Scheduler Modern C++ Header-Only Scheduling Library. Tasks run in thread pool. Requires C++11 and ctpl_stl.h in the path. Inspired by the Rufus-Schedu

Dec 21, 2022
Sqrt OS is a simulation of an OS scheduler and memory manager using different scheduling algorithms including Highest Priority First (non-preemptive), Shortest Remaining Time Next, and Round Robin
Sqrt OS is a simulation of an OS scheduler and memory manager using different scheduling algorithms including Highest Priority First (non-preemptive), Shortest Remaining Time Next, and Round Robin

A CPU scheduler determines an order for the execution of its scheduled processes; it decides which process will run according to a certain data structure that keeps track of the processes in the system and their status.

Sep 7, 2022
Operating system project - implementing scheduling algorithms and some system calls for XV6 OS

About XV6 xv6 is a modern reimplementation of Sixth Edition Unix in ANSI C for multiprocessor x86 and RISC-V systems. It was created for pedagogical p

Dec 22, 2022
Bistro: A fast, flexible toolkit for scheduling and running distributed tasks

Bistro is a flexible distributed scheduler, a high-performance framework supporting multiple paradigms while retaining ease of configuration, management, and monitoring.

Dec 19, 2022
Px - Single header C++ Libraries for Thread Scheduling, Rendering, and so on...

px 'PpluX' Single header C++(11/14) Libraries Name Code Description px_sched px_sched.h Task oriented scheduler. See more px_render px_render.h Multit

Dec 9, 2022
A header-only C++ library for task concurrency
A header-only C++ library for task concurrency

transwarp Doxygen documentation transwarp is a header-only C++ library for task concurrency. It allows you to easily create a graph of tasks where eve

Dec 19, 2022
Cpp-taskflow - Modern C++ Parallel Task Programming Library
Cpp-taskflow - Modern C++ Parallel Task Programming Library

Cpp-Taskflow A fast C++ header-only library to help you quickly write parallel programs with complex task dependencies Why Cpp-Taskflow? Cpp-Taskflow

Mar 30, 2021