| 899 | } |
| 900 | |
| 901 | void host_kernel::execute_host(const kernel_func_wrapper& func, |
| 902 | const uint32_t& cpu_count, |
| 903 | const uint3& group_dim, |
| 904 | const uint3& group_size, |
| 905 | const uint3& global_dim, |
| 906 | const uint3& local_dim, |
| 907 | const uint32_t& work_dim) const { |
| 908 | // #work-groups |
| 909 | const auto group_count = group_dim.x * group_dim.y * group_dim.z; |
| 910 | // #work-items per group |
| 911 | const uint32_t local_size = local_dim.x * local_dim.y * local_dim.z; |
| 912 | // group ticketing system, each worker thread will grab a new group id, once it's done with one group |
| 913 | atomic<uint32_t> group_idx { 0 }; |
| 914 | |
| 915 | // start worker threads |
| 916 | #if defined(FLOOR_HOST_KERNEL_ENABLE_TIMING) |
| 917 | const auto time_start = floor_timer::start(); |
| 918 | #endif |
| 919 | vector<unique_ptr<thread>> worker_threads(cpu_count); |
| 920 | for (uint32_t cpu_idx = 0; cpu_idx < cpu_count; ++cpu_idx) { |
| 921 | worker_threads[cpu_idx] = make_unique<thread>([this, &func, cpu_idx, |
| 922 | &group_idx, group_count, group_dim, group_size, |
| 923 | global_dim, local_size, local_dim, work_dim] { |
| 924 | // set cpu affinity for this thread to a particular cpu to prevent this thread from being constantly moved/scheduled |
| 925 | // on different cpus (starting at index 1, with 0 representing no affinity) |
| 926 | core::set_thread_affinity(cpu_idx + 1); |
| 927 | |
| 928 | // get and init host execution context |
| 929 | auto& exec_ctx = host_exec_context; |
| 930 | exec_ctx.ids = { |
| 931 | .instance_global_idx = { 0, 0, 0 }, |
| 932 | .instance_global_work_size = global_dim, |
| 933 | .instance_local_idx = { 0, 0, 0 }, |
| 934 | .instance_local_work_size = local_dim, |
| 935 | .instance_group_idx = { 0, 0, 0 }, |
| 936 | .instance_group_size = group_size, |
| 937 | .instance_work_dim = work_dim, |
| 938 | .instance_local_linear_idx = 0u, |
| 939 | }; |
| 940 | exec_ctx.linear_local_work_size = local_size; |
| 941 | exec_ctx.kernel_func = &func; |
| 942 | exec_ctx.thread_local_memory_offset = cpu_idx * floor_local_memory_max_size; |
| 943 | |
| 944 | // init contexts (aka fibers) |
| 945 | floor_fiber_context main_ctx; |
| 946 | main_ctx.init(nullptr, 0, nullptr, ~0u, nullptr, nullptr); |
| 947 | auto items = make_unique<floor_fiber_context[]>(local_size); |
| 948 | exec_ctx.item_contexts = items.get(); |
| 949 | |
| 950 | // init fibers |
| 951 | for (uint32_t i = 0; i < local_size; ++i) { |
| 952 | items[i].init(&floor_stack_memory_data.get()[(i + local_size * cpu_idx) * floor_fiber_context::min_stack_size], |
| 953 | floor_fiber_context::min_stack_size, |
| 954 | run_host_group_item, i, |
| 955 | // continue with next on return, or return to main ctx when the last item returns |
| 956 | // TODO: add option to use randomized order? |
| 957 | (i + 1 < local_size ? &items[i + 1] : &main_ctx), |
| 958 | &main_ctx); |
nothing calls this directly
no test coverage detected