#include "astcenccli_internal.h"
#if defined(_WIN32) && !defined(__CYGWIN__)
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#include <Processthreadsapi.h>
#include <algorithm>
#include <cstring>
typedef HANDLE pthread_t;
typedef int pthread_attr_t;
static int pthread_create(
pthread_t* thread,
const pthread_attr_t* attribs,
void* (*threadfunc)(void*),
void* thread_arg
) {
static_cast<void>(attribs);
LPTHREAD_START_ROUTINE func = reinterpret_cast<LPTHREAD_START_ROUTINE>(threadfunc);
*thread = CreateThread(nullptr, 0, func, thread_arg, 0, nullptr);
if (*thread == NULL)
{
return 1;
}
return 0;
}
static void set_group_affinity(
pthread_t thread,
int thread_index
) {
int group_count = GetActiveProcessorGroupCount();
if (group_count == 1)
{
return;
}
int assign_index = thread_index % get_cpu_count();
int assign_group { 0 };
int assign_group_cpu_count { 0 };
int group_cpu_count_sum { 0 };
for (int group = 0; group < group_count; group++)
{
int group_cpu_count = static_cast<int>(GetMaximumProcessorCount(group));
group_cpu_count_sum += group_cpu_count;
if (assign_index < group_cpu_count_sum)
{
assign_group = group;
assign_group_cpu_count = group_cpu_count;
break;
}
}
GROUP_AFFINITY affinity {};
affinity.Mask = (1 << assign_group_cpu_count) - 1;
affinity.Group = assign_group;
SetThreadGroupAffinity(thread, &affinity, nullptr);
}
static int pthread_join(
pthread_t thread,
void** value
) {
static_cast<void>(value);
WaitForSingleObject(thread, INFINITE);
return 0;
}
int get_cpu_count()
{
DWORD cpu_count = GetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
return static_cast<int>(cpu_count);
}
double get_time()
{
FILETIME tv;
GetSystemTimePreciseAsFileTime(&tv);
unsigned long long ticks = tv.dwHighDateTime;
ticks = (ticks << 32) | tv.dwLowDateTime;
return static_cast<double>(ticks) / 1.0e7;
}
void set_thread_name(
const char* name
) {
wchar_t wname [16] { 0 };
size_t name_len = std::strlen(name);
size_t clamp_len = std::min<size_t>(name_len, 15);
for (size_t i = 0; i < clamp_len; i++)
{
wname[i] = static_cast<wchar_t>(name[i]);
}
SetThreadDescription(GetCurrentThread(), wname);
}
#else
#include <pthread.h>
#include <sys/time.h>
#include <unistd.h>
int get_cpu_count()
{
return static_cast<int>(sysconf(_SC_NPROCESSORS_ONLN));
}
double get_time()
{
timeval tv;
gettimeofday(&tv, 0);
return static_cast<double>(tv.tv_sec) + static_cast<double>(tv.tv_usec) * 1.0e-6;
}
void set_thread_name(
const char* name
) {
#if defined(__linux__)
pthread_setname_np(pthread_self(), name);
#elif defined(__APPLE__)
pthread_setname_np(name);
#else
(void)name;
#endif
}
#endif
struct launch_desc
{
pthread_t thread_handle;
int thread_count;
int thread_id;
void (*func)(int, int, void*);
void* payload;
};
static void* launch_threads_helper(
void *p
) {
launch_desc* ltd = reinterpret_cast<launch_desc*>(p);
ltd->func(ltd->thread_count, ltd->thread_id, ltd->payload);
return nullptr;
}
void launch_threads(
const char* operation,
int thread_count,
void (*func)(int, int, void*),
void *payload
) {
if (thread_count <= 1)
{
func(1, 0, payload);
return;
}
launch_desc *thread_descs = new launch_desc[thread_count];
int actual_thread_count { 0 };
for (int i = 0; i < thread_count; i++)
{
thread_descs[actual_thread_count].thread_count = thread_count;
thread_descs[actual_thread_count].thread_id = actual_thread_count;
thread_descs[actual_thread_count].payload = payload;
thread_descs[actual_thread_count].func = func;
int error = pthread_create(
&(thread_descs[actual_thread_count].thread_handle),
nullptr,
launch_threads_helper,
reinterpret_cast<void*>(thread_descs + actual_thread_count));
if (!error)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
set_group_affinity(
thread_descs[actual_thread_count].thread_handle,
actual_thread_count);
#endif
actual_thread_count++;
}
}
if (actual_thread_count != thread_count)
{
int log_count = actual_thread_count == 0 ? 1 : actual_thread_count;
const char* log_s = log_count == 1 ? "" : "s";
printf("WARNING: %s using %d thread%s due to thread creation error\n\n",
operation, log_count, log_s);
}
if (actual_thread_count != 0)
{
for (int i = 0; i < actual_thread_count; i++)
{
pthread_join(thread_descs[i].thread_handle, nullptr);
}
}
else
{
func(1, 0, payload);
}
delete[] thread_descs;
}