|
@@ -0,0 +1,720 @@
|
|
|
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
|
|
|
+ *
|
|
|
+ * Copyright (C) 2015 Université de Bordeaux
|
|
|
+ * Copyright (C) 2015 INRIA
|
|
|
+ * Copyright (C) 2015 CNRS
|
|
|
+ *
|
|
|
+ * StarPU is free software; you can redistribute it and/or modify
|
|
|
+ * it under the terms of the GNU Lesser General Public License as published by
|
|
|
+ * the Free Software Foundation; either version 2.1 of the License, or (at
|
|
|
+ * your option) any later version.
|
|
|
+ *
|
|
|
+ * StarPU is distributed in the hope that it will be useful, but
|
|
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
+ *
|
|
|
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
|
|
|
+ */
|
|
|
+
|
|
|
+/* This file creates an interface to manage clustering resources and make use
|
|
|
+ * of parallel tasks. It entirely depends on the hwloc software. */
|
|
|
+
|
|
|
+#include "starpu_clusters_create.h"
|
|
|
+
|
|
|
+starpu_binding_function _starpu_cluster_type_get_func(starpu_cluster_types type)
|
|
|
+{
|
|
|
+ starpu_binding_function prologue_func;
|
|
|
+
|
|
|
+ switch (type)
|
|
|
+ {
|
|
|
+ case OPENMP:
|
|
|
+ prologue_func = &starpu_openmp_prologue;
|
|
|
+ break;
|
|
|
+ case INTEL_OPENMP_MKL:
|
|
|
+ prologue_func = &starpu_intel_openmp_mkl_prologue;
|
|
|
+ break;
|
|
|
+#ifdef STARPU_MKL
|
|
|
+ case GNU_OPENMP_MKL:
|
|
|
+ prologue_func = &starpu_gnu_openmp_mkl_prologue;
|
|
|
+ break;
|
|
|
+#endif
|
|
|
+ default:
|
|
|
+ prologue_func = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return prologue_func;
|
|
|
+}
|
|
|
+
|
|
|
+void starpu_openmp_prologue(void * sched_ctx_id)
|
|
|
+{
|
|
|
+ int sched_ctx = *(int*)sched_ctx_id;
|
|
|
+ int *cpuids = NULL;
|
|
|
+ int ncpuids = 0;
|
|
|
+ int workerid = starpu_worker_get_id();
|
|
|
+
|
|
|
+ if (starpu_worker_get_type(workerid) == STARPU_CPU_WORKER)
|
|
|
+ {
|
|
|
+ starpu_sched_ctx_get_available_cpuids(sched_ctx, &cpuids, &ncpuids);
|
|
|
+ omp_set_num_threads(ncpuids);
|
|
|
+#pragma omp parallel
|
|
|
+ {
|
|
|
+ starpu_sched_ctx_bind_current_thread_to_cpuid(cpuids[omp_get_thread_num()]);
|
|
|
+ }
|
|
|
+ free(cpuids);
|
|
|
+ }
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+#ifdef STARPU_MKL
|
|
|
+void starpu_gnu_openmp_mkl_prologue(void * sched_ctx_id)
|
|
|
+{
|
|
|
+ int sched_ctx = *(int*)sched_ctx_id;
|
|
|
+ int *cpuids = NULL;
|
|
|
+ int ncpuids = 0;
|
|
|
+ int workerid = starpu_worker_get_id();
|
|
|
+
|
|
|
+ if (starpu_worker_get_type(workerid) == STARPU_CPU_WORKER)
|
|
|
+ {
|
|
|
+ starpu_sched_ctx_get_available_cpuids(sched_ctx, &cpuids, &ncpuids);
|
|
|
+ omp_set_num_threads(ncpuids);
|
|
|
+ mkl_set_num_threads(ncpuids);
|
|
|
+ mkl_set_dynamic(0);
|
|
|
+#pragma omp parallel
|
|
|
+ {
|
|
|
+ starpu_sched_ctx_bind_current_thread_to_cpuid(cpuids[omp_get_thread_num()]);
|
|
|
+ }
|
|
|
+ free(cpuids);
|
|
|
+ }
|
|
|
+ return;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+/* Main interface function to create a cluster view of the machine.
|
|
|
+ * Its job is to capture what the user wants and store it in a standard view. */
|
|
|
+struct starpu_cluster_machine* starpu_cluster_machine(hwloc_obj_type_t cluster_level, ...)
|
|
|
+{
|
|
|
+ va_list varg_list;
|
|
|
+ int arg_type;
|
|
|
+ struct _starpu_cluster_parameters *params;
|
|
|
+ struct starpu_cluster_machine* machine = malloc(sizeof(struct starpu_cluster_machine));
|
|
|
+ machine->params = malloc(sizeof(struct _starpu_cluster_parameters));
|
|
|
+ machine->groups = _starpu_cluster_group_list_new();
|
|
|
+
|
|
|
+ _starpu_cluster_init_parameters(machine->params);
|
|
|
+ params = machine->params;
|
|
|
+
|
|
|
+ va_start(varg_list, cluster_level);
|
|
|
+ while ((arg_type = va_arg(varg_list, int)) != 0)
|
|
|
+ {
|
|
|
+ if (arg_type == STARPU_CLUSTER_MIN_NB)
|
|
|
+ {
|
|
|
+ params->min_nb = va_arg(varg_list, int);
|
|
|
+ if (params->min_nb <= 0)
|
|
|
+ fprintf(stderr, "Caution min number of contexts shouldn't "
|
|
|
+ "be negative or null\n");
|
|
|
+ }
|
|
|
+ else if (arg_type == STARPU_CLUSTER_MAX_NB)
|
|
|
+ {
|
|
|
+ params->max_nb = va_arg(varg_list, int);
|
|
|
+ if (params->max_nb <= 0)
|
|
|
+ fprintf(stderr, "Caution max number of contexts shouldn't "
|
|
|
+ "be negative or null\n");
|
|
|
+ }
|
|
|
+ else if (arg_type == STARPU_CLUSTER_NB)
|
|
|
+ {
|
|
|
+ params->nb = va_arg(varg_list, int);
|
|
|
+ if (params->nb <= 0)
|
|
|
+ fprintf(stderr, "Caution number of contexts shouldn't "
|
|
|
+ "be negative or null\n");
|
|
|
+ }
|
|
|
+ else if (arg_type == STARPU_CLUSTER_POLICY_NAME)
|
|
|
+ {
|
|
|
+ params->sched_policy_name = va_arg(varg_list, char*);
|
|
|
+ }
|
|
|
+ else if (arg_type == STARPU_CLUSTER_POLICY_STRUCT)
|
|
|
+ {
|
|
|
+ params->sched_policy_struct = va_arg(varg_list,
|
|
|
+ struct starpu_sched_policy*);
|
|
|
+ }
|
|
|
+ else if (arg_type == STARPU_CLUSTER_KEEP_HOMOGENEOUS)
|
|
|
+ {
|
|
|
+ params->keep_homogeneous = va_arg(varg_list, int); /* 0=off, other=on */
|
|
|
+ }
|
|
|
+ else if (arg_type == STARPU_CLUSTER_PREFERE_MIN)
|
|
|
+ {
|
|
|
+ params->prefere_min = va_arg(varg_list, int); /* 0=off, other=on */
|
|
|
+ }
|
|
|
+ else if (arg_type == STARPU_CLUSTER_CREATE_FUNC)
|
|
|
+ {
|
|
|
+ params->create_func = va_arg(varg_list, void (*)(void*));
|
|
|
+ }
|
|
|
+ else if (arg_type == STARPU_CLUSTER_CREATE_FUNC_ARG)
|
|
|
+ {
|
|
|
+ params->create_func_arg = va_arg(varg_list, void*);
|
|
|
+ }
|
|
|
+ else if (arg_type == STARPU_CLUSTER_TYPE)
|
|
|
+ {
|
|
|
+ params->type = va_arg(varg_list, starpu_cluster_types);
|
|
|
+ }
|
|
|
+ else if (arg_type == STARPU_CLUSTER_AWAKE_WORKERS)
|
|
|
+ {
|
|
|
+ params->awake_workers = va_arg(varg_list, unsigned);
|
|
|
+ }
|
|
|
+ else if (arg_type == STARPU_CLUSTER_PARTITION_ONE)
|
|
|
+ {
|
|
|
+ struct _starpu_cluster_group* group = _starpu_cluster_group_new();
|
|
|
+ _starpu_cluster_group_init(group, machine);
|
|
|
+ _starpu_cluster_group_list_push_back(machine->groups, group);
|
|
|
+ params = group->params;
|
|
|
+ }
|
|
|
+ else if (arg_type == STARPU_CLUSTER_NEW)
|
|
|
+ {
|
|
|
+ struct _starpu_cluster* cluster = _starpu_cluster_new();
|
|
|
+ struct _starpu_cluster_group* group = _starpu_cluster_group_list_back(machine->groups);
|
|
|
+ if (group == NULL)
|
|
|
+ {
|
|
|
+ group = _starpu_cluster_group_new();
|
|
|
+ _starpu_cluster_group_init(group, machine);
|
|
|
+ _starpu_cluster_group_list_push_back(machine->groups, group);
|
|
|
+ }
|
|
|
+ _starpu_cluster_init(cluster, group);
|
|
|
+ _starpu_cluster_list_push_back(group->clusters, cluster);
|
|
|
+ params = cluster->params;
|
|
|
+ }
|
|
|
+ else if (arg_type == STARPU_CLUSTER_NCORES)
|
|
|
+ {
|
|
|
+ struct _starpu_cluster_group* group =
|
|
|
+ _starpu_cluster_group_list_back(machine->groups);
|
|
|
+ struct _starpu_cluster* cluster =
|
|
|
+ _starpu_cluster_list_back(group->clusters);
|
|
|
+ cluster->ncores = va_arg(varg_list, unsigned);
|
|
|
+
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ STARPU_ABORT_MSG("Unrecognized argument %d\n", arg_type);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ va_end(varg_list);
|
|
|
+
|
|
|
+ switch(cluster_level)
|
|
|
+ {
|
|
|
+ case HWLOC_OBJ_MISC:
|
|
|
+ case HWLOC_OBJ_BRIDGE:
|
|
|
+ case HWLOC_OBJ_PCI_DEVICE:
|
|
|
+ case HWLOC_OBJ_OS_DEVICE:
|
|
|
+ STARPU_ABORT_MSG("Cluster aggregation isn't supported for level %s\n",
|
|
|
+ hwloc_obj_type_string(cluster_level));
|
|
|
+ break;
|
|
|
+ default: /* others can pass */
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ _starpu_cluster_machine(cluster_level, machine);
|
|
|
+ return machine;
|
|
|
+}
|
|
|
+
|
|
|
+int starpu_uncluster_machine(struct starpu_cluster_machine* machine)
|
|
|
+{
|
|
|
+ struct _starpu_cluster_group *g, *tmp;
|
|
|
+ struct _starpu_cluster_group_list* group_list = machine->groups;
|
|
|
+ starpu_sched_ctx_delete(machine->id);
|
|
|
+ g = _starpu_cluster_group_list_begin(group_list);
|
|
|
+ while (g != _starpu_cluster_group_list_end(group_list))
|
|
|
+ {
|
|
|
+ tmp = g;
|
|
|
+ g = _starpu_cluster_group_list_next(g);
|
|
|
+ _starpu_cluster_group_remove(group_list, tmp);
|
|
|
+ }
|
|
|
+ hwloc_topology_destroy(machine->topology);
|
|
|
+ free(machine->params);
|
|
|
+ free(machine);
|
|
|
+ starpu_sched_ctx_set_context(0);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+void starpu_cluster_print(struct starpu_cluster_machine* clusters)
|
|
|
+{
|
|
|
+ int cnt, w;
|
|
|
+ struct _starpu_cluster_group *group;
|
|
|
+ struct _starpu_cluster *cluster;
|
|
|
+
|
|
|
+ printf("Number of clusters created: %d\n", clusters->nclusters);
|
|
|
+ cnt=0;
|
|
|
+ for (group = _starpu_cluster_group_list_begin(clusters->groups);
|
|
|
+ group != _starpu_cluster_group_list_end(clusters->groups);
|
|
|
+ group = _starpu_cluster_group_list_next(group))
|
|
|
+ {
|
|
|
+ for (cluster = _starpu_cluster_list_begin(group->clusters);
|
|
|
+ cluster != _starpu_cluster_list_end(group->clusters);
|
|
|
+ cluster = _starpu_cluster_list_next(cluster))
|
|
|
+ {
|
|
|
+ printf("Cluster %d contains the following logical indexes:\n\t", cnt);
|
|
|
+ for (w=0; w < cluster->ncores; w++)
|
|
|
+ printf("%d ", cluster->cores[w]);
|
|
|
+ printf("\n");
|
|
|
+ cnt++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+void _starpu_cluster_create(struct _starpu_cluster* cluster)
|
|
|
+{
|
|
|
+ unsigned main_ctx_id = cluster->father->father->id;
|
|
|
+ if (cluster->params->awake_workers)
|
|
|
+ cluster->id = starpu_sched_ctx_create(cluster->workerids, cluster->ncores,
|
|
|
+ "clusters", STARPU_SCHED_CTX_NESTED,
|
|
|
+ main_ctx_id,
|
|
|
+ STARPU_SCHED_CTX_AWAKE_WORKERS,
|
|
|
+ 0);
|
|
|
+ else
|
|
|
+ cluster->id = starpu_sched_ctx_create(cluster->workerids, cluster->ncores,
|
|
|
+ "clusters", STARPU_SCHED_CTX_NESTED,
|
|
|
+ main_ctx_id,
|
|
|
+ 0);
|
|
|
+
|
|
|
+ /* cluster priority can be the lowest, so let's enforce it */
|
|
|
+ starpu_sched_ctx_set_priority(cluster->workerids, cluster->ncores, cluster->id, 0);
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+void _starpu_cluster_group_create(struct _starpu_cluster_group *group)
|
|
|
+{
|
|
|
+ struct _starpu_cluster* c;
|
|
|
+ for (c = _starpu_cluster_list_begin(group->clusters) ;
|
|
|
+ c != _starpu_cluster_list_end(group->clusters) ;
|
|
|
+ c = _starpu_cluster_list_next(c))
|
|
|
+ {
|
|
|
+ _starpu_cluster_create(c);
|
|
|
+ if (!c->params->awake_workers)
|
|
|
+ _starpu_cluster_bind(c);
|
|
|
+ }
|
|
|
+
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+int _starpu_cluster_bind(struct _starpu_cluster* cluster)
|
|
|
+{
|
|
|
+ starpu_binding_function func;
|
|
|
+ void* func_arg;
|
|
|
+ if (cluster->params->create_func)
|
|
|
+ {
|
|
|
+ func = cluster->params->create_func;
|
|
|
+ func_arg = (void*) cluster->params->create_func_arg;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ func = _starpu_cluster_type_get_func(cluster->params->type);
|
|
|
+ func_arg = (void*) &cluster->id;
|
|
|
+ }
|
|
|
+
|
|
|
+ return starpu_task_insert(&_starpu_cluster_bind_cl,
|
|
|
+ STARPU_SCHED_CTX, cluster->id,
|
|
|
+ STARPU_POSSIBLY_PARALLEL, 1,
|
|
|
+ STARPU_PROLOGUE_CALLBACK_POP, func,
|
|
|
+ STARPU_PROLOGUE_CALLBACK_POP_ARG, func_arg,
|
|
|
+ 0);
|
|
|
+}
|
|
|
+
|
|
|
+void _starpu_cluster_group_init(struct _starpu_cluster_group* group,
|
|
|
+ struct starpu_cluster_machine* father)
|
|
|
+{
|
|
|
+ group->id = 0;
|
|
|
+ group->nclusters = 0;
|
|
|
+ group->clusters = _starpu_cluster_list_new();
|
|
|
+ group->father = father;
|
|
|
+ group->params = malloc(sizeof(struct _starpu_cluster_parameters));
|
|
|
+ _starpu_cluster_copy_parameters(group->params,
|
|
|
+ father->params);
|
|
|
+
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+void _starpu_cluster_init(struct _starpu_cluster* cluster,
|
|
|
+ struct _starpu_cluster_group* father)
|
|
|
+{
|
|
|
+ cluster->id = 0;
|
|
|
+ cluster->cpuset = hwloc_bitmap_alloc();
|
|
|
+ cluster->ncores = 0;
|
|
|
+ cluster->cores = NULL;
|
|
|
+ cluster->workerids = NULL;
|
|
|
+ cluster->father = father;
|
|
|
+ cluster->params = malloc(sizeof(struct _starpu_cluster_parameters));
|
|
|
+ _starpu_cluster_copy_parameters(cluster->params,
|
|
|
+ father->params);
|
|
|
+}
|
|
|
+
|
|
|
+int _starpu_cluster_remove(struct _starpu_cluster_list* cluster_list,
|
|
|
+ struct _starpu_cluster* cluster)
|
|
|
+{
|
|
|
+ if (cluster && cluster->id != STARPU_NMAX_SCHED_CTXS)
|
|
|
+ starpu_sched_ctx_delete(cluster->id);
|
|
|
+ else
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ if (cluster->cores != NULL)
|
|
|
+ free(cluster->cores);
|
|
|
+ if (cluster->workerids != NULL)
|
|
|
+ free(cluster->workerids);
|
|
|
+ hwloc_bitmap_free(cluster->cpuset);
|
|
|
+ free(cluster->params);
|
|
|
+ _starpu_cluster_list_erase(cluster_list, cluster);
|
|
|
+ _starpu_cluster_delete(cluster);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int _starpu_cluster_group_remove(struct _starpu_cluster_group_list* group_list,
|
|
|
+ struct _starpu_cluster_group* group)
|
|
|
+{
|
|
|
+ struct _starpu_cluster* tmp;
|
|
|
+ struct _starpu_cluster_list* cluster_list = group->clusters;
|
|
|
+ struct _starpu_cluster* c = _starpu_cluster_list_begin(cluster_list);
|
|
|
+ while (c != _starpu_cluster_list_end(cluster_list))
|
|
|
+ {
|
|
|
+ tmp = c;
|
|
|
+ c = _starpu_cluster_list_next(c);
|
|
|
+ _starpu_cluster_remove(cluster_list, tmp);
|
|
|
+ }
|
|
|
+ free(group->params);
|
|
|
+ _starpu_cluster_group_list_erase(group_list, group);
|
|
|
+ _starpu_cluster_group_delete(group);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+void _starpu_cluster_init_parameters(struct _starpu_cluster_parameters* params)
|
|
|
+{
|
|
|
+ params->min_nb = 0;
|
|
|
+ params->max_nb = 0;
|
|
|
+ params->nb = 0;
|
|
|
+ params->sched_policy_name = NULL;
|
|
|
+ params->sched_policy_struct = NULL;
|
|
|
+ params->keep_homogeneous = 0;
|
|
|
+ params->prefere_min = 0;
|
|
|
+ params->create_func = NULL;
|
|
|
+ params->create_func_arg = NULL;
|
|
|
+ params->type = OPENMP;
|
|
|
+ params->awake_workers = 0;
|
|
|
+
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+void _starpu_cluster_copy_parameters(struct _starpu_cluster_parameters* dst,
|
|
|
+ struct _starpu_cluster_parameters* src)
|
|
|
+{
|
|
|
+ dst->min_nb = src->min_nb;
|
|
|
+ dst->max_nb = src->max_nb;
|
|
|
+ dst->nb = src->nb;
|
|
|
+ dst->sched_policy_name = src->sched_policy_name;
|
|
|
+ dst->sched_policy_struct = src->sched_policy_struct;
|
|
|
+ dst->keep_homogeneous = src->keep_homogeneous;
|
|
|
+ dst->prefere_min = src->prefere_min;
|
|
|
+ dst->create_func = src->create_func;
|
|
|
+ dst->create_func_arg = src->create_func_arg;
|
|
|
+ dst->type = src->type;
|
|
|
+ dst->awake_workers = src->awake_workers;
|
|
|
+
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+/* Considering the resources and parameters, how many clusters should we take? */
|
|
|
+int _starpu_cluster_analyze_parameters(struct _starpu_cluster_parameters* params, int npus)
|
|
|
+{
|
|
|
+ int nb_clusters = 1, j;
|
|
|
+ if (params->nb)
|
|
|
+ {
|
|
|
+ nb_clusters = params->nb;
|
|
|
+ }
|
|
|
+ else if (params->min_nb && params->max_nb)
|
|
|
+ {
|
|
|
+ if (!params->keep_homogeneous)
|
|
|
+ {
|
|
|
+ if (params->prefere_min)
|
|
|
+ nb_clusters = params->min_nb;
|
|
|
+ else
|
|
|
+ nb_clusters = params->max_nb;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ int begin = params->prefere_min? params->min_nb:params->max_nb;
|
|
|
+ int end = params->prefere_min? params->max_nb+1:params->min_nb-1;
|
|
|
+ j=begin;
|
|
|
+ int best = 0, second_best = 0, cpu_loss = INT_MAX;
|
|
|
+ while (j != end)
|
|
|
+ {
|
|
|
+ if (npus%j == 0)
|
|
|
+ {
|
|
|
+ best = j;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (npus%j < cpu_loss)
|
|
|
+ {
|
|
|
+ cpu_loss = npus%j;
|
|
|
+ second_best = j;
|
|
|
+ }
|
|
|
+ j = params->prefere_min? j++:j--;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (best)
|
|
|
+ nb_clusters = best;
|
|
|
+ else if (second_best)
|
|
|
+ nb_clusters = second_best;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return nb_clusters;
|
|
|
+}
|
|
|
+
|
|
|
+void _starpu_cluster_machine(hwloc_obj_type_t cluster_level,
|
|
|
+ struct starpu_cluster_machine* machine)
|
|
|
+{
|
|
|
+ struct _starpu_cluster_group* g;
|
|
|
+
|
|
|
+ _starpu_cluster_topology(cluster_level, machine);
|
|
|
+
|
|
|
+ if (machine->params->sched_policy_struct != NULL)
|
|
|
+ {
|
|
|
+ machine->id = starpu_sched_ctx_create(NULL, -1, "main sched ctx",
|
|
|
+ STARPU_SCHED_CTX_POLICY_STRUCT,
|
|
|
+ machine->params->sched_policy_struct,
|
|
|
+ 0);
|
|
|
+ }
|
|
|
+ else if (machine->params->sched_policy_name != NULL)
|
|
|
+ {
|
|
|
+ machine->id = starpu_sched_ctx_create(NULL, -1, "main sched ctx",
|
|
|
+ STARPU_SCHED_CTX_POLICY_NAME,
|
|
|
+ machine->params->sched_policy_name,
|
|
|
+ 0);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ struct starpu_sched_policy* sched_policy;
|
|
|
+ struct _starpu_sched_ctx* global_ctx =
|
|
|
+ _starpu_get_sched_ctx_struct(STARPU_GLOBAL_SCHED_CTX);
|
|
|
+ sched_policy = _starpu_get_sched_policy(global_ctx);
|
|
|
+ machine->id = starpu_sched_ctx_create(NULL, -1, "main sched ctx",
|
|
|
+ STARPU_SCHED_CTX_POLICY_STRUCT,
|
|
|
+ sched_policy, 0);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ for (g = _starpu_cluster_group_list_begin(machine->groups) ;
|
|
|
+ g != _starpu_cluster_group_list_end(machine->groups) ;
|
|
|
+ g = _starpu_cluster_group_list_next(g))
|
|
|
+ _starpu_cluster_group_create(g);
|
|
|
+
|
|
|
+ starpu_task_wait_for_all();
|
|
|
+ starpu_sched_ctx_set_context(&machine->id);
|
|
|
+
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+void _starpu_cluster_topology(hwloc_obj_type_t cluster_level,
|
|
|
+ struct starpu_cluster_machine* machine)
|
|
|
+{
|
|
|
+ int w;
|
|
|
+ hwloc_topology_t topology;
|
|
|
+ hwloc_cpuset_t avail_cpus;
|
|
|
+ char *buf;
|
|
|
+
|
|
|
+ struct _starpu_machine_config* config = _starpu_get_machine_config();
|
|
|
+ STARPU_ASSERT_MSG(config->topology.hwtopology != NULL, "STARPU_CLUSTER: You "
|
|
|
+ "need to call starpu_init() or make sure to activate hwloc.");
|
|
|
+ hwloc_topology_dup(&topology, config->topology.hwtopology);
|
|
|
+
|
|
|
+ avail_cpus = hwloc_bitmap_alloc();
|
|
|
+ hwloc_bitmap_zero(avail_cpus);
|
|
|
+
|
|
|
+ int nworkers = starpu_worker_get_count_by_type(STARPU_CPU_WORKER);
|
|
|
+ int *workers = (int*) malloc(sizeof(int) * nworkers);
|
|
|
+ starpu_worker_get_ids_by_type(STARPU_CPU_WORKER, workers, nworkers);
|
|
|
+
|
|
|
+ for (w = 0; w < nworkers ; w++)
|
|
|
+ {
|
|
|
+ struct _starpu_worker *worker_str = _starpu_get_worker_struct(workers[w]);
|
|
|
+ hwloc_bitmap_or(avail_cpus, avail_cpus, worker_str->hwloc_cpu_set);
|
|
|
+ }
|
|
|
+ hwloc_bitmap_list_asprintf(&buf, avail_cpus);
|
|
|
+
|
|
|
+ hwloc_topology_restrict(topology, avail_cpus, 0);
|
|
|
+ free(workers);
|
|
|
+
|
|
|
+ /* Use new topology to fill in the cluster list */
|
|
|
+ hwloc_topology_dup(&machine->topology, topology);
|
|
|
+ _starpu_cluster_group(cluster_level, machine);
|
|
|
+
|
|
|
+ hwloc_bitmap_free(avail_cpus);
|
|
|
+ hwloc_topology_destroy(topology);
|
|
|
+
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+void _starpu_cluster_group(hwloc_obj_type_t cluster_level,
|
|
|
+ struct starpu_cluster_machine* machine)
|
|
|
+{
|
|
|
+ unsigned nb_objects;
|
|
|
+ int i;
|
|
|
+ struct _starpu_cluster_group* group = NULL;
|
|
|
+
|
|
|
+ if (machine->groups == NULL)
|
|
|
+ machine->groups = _starpu_cluster_group_list_new();
|
|
|
+
|
|
|
+ nb_objects = hwloc_get_nbobjs_by_type(machine->topology, cluster_level);
|
|
|
+ if (nb_objects == 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ group = _starpu_cluster_group_list_begin(machine->groups);
|
|
|
+ for (i = 0 ; i < nb_objects ; i++)
|
|
|
+ {
|
|
|
+ hwloc_obj_t cluster_obj = hwloc_get_obj_by_type(machine->topology,
|
|
|
+ cluster_level, i);
|
|
|
+
|
|
|
+ if (group == NULL)
|
|
|
+ {
|
|
|
+ group = _starpu_cluster_group_new();
|
|
|
+ _starpu_cluster_group_init(group, machine);
|
|
|
+ _starpu_cluster_group_list_push_back(machine->groups, group);
|
|
|
+ }
|
|
|
+
|
|
|
+ group->group_obj = cluster_obj;
|
|
|
+
|
|
|
+ _starpu_cluster(group);
|
|
|
+ machine->ngroups++;
|
|
|
+ machine->nclusters += group->nclusters;
|
|
|
+ group = _starpu_cluster_group_list_next(group);
|
|
|
+ }
|
|
|
+
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+void _starpu_cluster(struct _starpu_cluster_group* group)
|
|
|
+{
|
|
|
+ int i, avail_pus, npus, npreset=0;
|
|
|
+ struct _starpu_cluster* cluster;
|
|
|
+ char* buf;
|
|
|
+ npus = hwloc_get_nbobjs_inside_cpuset_by_type(group->father->topology,
|
|
|
+ group->group_obj->cpuset,
|
|
|
+ HWLOC_OBJ_PU);
|
|
|
+
|
|
|
+ /* Preset clusters */
|
|
|
+ avail_pus = npus;
|
|
|
+ for (cluster=_starpu_cluster_list_begin(group->clusters);
|
|
|
+ cluster!=_starpu_cluster_list_end(group->clusters);
|
|
|
+ cluster=_starpu_cluster_list_next(cluster))
|
|
|
+ {
|
|
|
+ if (cluster->ncores > avail_pus)
|
|
|
+ cluster->ncores = avail_pus;
|
|
|
+ else if (avail_pus == 0)
|
|
|
+ cluster->ncores = 0;
|
|
|
+
|
|
|
+ if (cluster->ncores > 0)
|
|
|
+ {
|
|
|
+ cluster->cores = malloc(sizeof(int)*cluster->ncores);
|
|
|
+ cluster->workerids = malloc(sizeof(int)*cluster->ncores);
|
|
|
+ avail_pus -= cluster->ncores;
|
|
|
+ npreset++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Automatic clusters */
|
|
|
+ group->nclusters = _starpu_cluster_analyze_parameters(group->params, avail_pus);
|
|
|
+ for (i=0 ; i<group->nclusters && avail_pus>0 ; i++)
|
|
|
+ {
|
|
|
+ if (cluster == NULL)
|
|
|
+ {
|
|
|
+ cluster = _starpu_cluster_new();
|
|
|
+ _starpu_cluster_init(cluster, group);
|
|
|
+ _starpu_cluster_list_push_back(group->clusters, cluster);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (cluster->ncores != 0 && cluster->ncores > avail_pus)
|
|
|
+ {
|
|
|
+ cluster->ncores = avail_pus;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (cluster->params->keep_homogeneous)
|
|
|
+ cluster->ncores = avail_pus/(group->nclusters-i);
|
|
|
+ else
|
|
|
+ cluster->ncores = i==group->nclusters-1?
|
|
|
+ avail_pus:
|
|
|
+ avail_pus/(group->nclusters-i);
|
|
|
+ }
|
|
|
+ avail_pus -= cluster->ncores;
|
|
|
+ cluster->cores = malloc(sizeof(int)*cluster->ncores);
|
|
|
+ cluster->workerids = malloc(sizeof(int)*cluster->ncores);
|
|
|
+
|
|
|
+ cluster = _starpu_cluster_list_next(cluster);
|
|
|
+ }
|
|
|
+ group->nclusters += npreset;
|
|
|
+
|
|
|
+ cluster = _starpu_cluster_list_begin(group->clusters);
|
|
|
+ int count = 0;
|
|
|
+ static int starpu_cluster_warned = 0;
|
|
|
+ hwloc_bitmap_list_asprintf(&buf, group->group_obj->cpuset);
|
|
|
+
|
|
|
+ for (i=0 ; i<npus ; i++)
|
|
|
+ {
|
|
|
+ hwloc_obj_t pu = hwloc_get_obj_inside_cpuset_by_type(group->father->topology,
|
|
|
+ group->group_obj->cpuset,
|
|
|
+ HWLOC_OBJ_PU, i);
|
|
|
+
|
|
|
+ /* If we have more than one worker on this resource, let's add them too --
|
|
|
+ even if it's bad (they'll all be boud on the same PU) */
|
|
|
+ int size = 0, j;
|
|
|
+ struct _starpu_worker* worker_str = _starpu_worker_list_front(pu->userdata);
|
|
|
+ for (j = 0; j < _starpu_worker_list_size(pu->userdata) ; j++)
|
|
|
+ {
|
|
|
+ if (worker_str->arch == STARPU_CPU_WORKER)
|
|
|
+ size++;
|
|
|
+ worker_str = _starpu_worker_list_next(worker_str);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (size > 1)
|
|
|
+ {
|
|
|
+ if (!starpu_cluster_warned)
|
|
|
+ {
|
|
|
+ fprintf(stderr, "STARPU CLUSTERS: Caution! It seems that you have"
|
|
|
+ " multiple workers bound to the same PU. If you have"
|
|
|
+ " multithreading on your cores it is greatly adviced"
|
|
|
+ " to export STARPU_NTHREADS_PER_CORE=nb.");
|
|
|
+ starpu_cluster_warned = 1;
|
|
|
+ }
|
|
|
+ cluster->ncores += size-1;
|
|
|
+ cluster->cores = realloc(cluster->cores,
|
|
|
+ sizeof(int)*cluster->ncores);
|
|
|
+ cluster->workerids = realloc(cluster->workerids,
|
|
|
+ sizeof(int)*cluster->ncores);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* grab workerid list and return first cpu */
|
|
|
+ worker_str = _starpu_worker_list_front(pu->userdata);
|
|
|
+ if (worker_str)
|
|
|
+ hwloc_bitmap_or(cluster->cpuset, cluster->cpuset,
|
|
|
+ worker_str->hwloc_cpu_set);
|
|
|
+ j = 0;
|
|
|
+ while (worker_str)
|
|
|
+ {
|
|
|
+ if (worker_str->arch == STARPU_CPU_WORKER)
|
|
|
+ {
|
|
|
+ cluster->cores[count+j] = worker_str->bindid;
|
|
|
+ cluster->workerids[count+j] = worker_str->workerid;
|
|
|
+ j++;
|
|
|
+ }
|
|
|
+ worker_str = _starpu_worker_list_next(worker_str);
|
|
|
+ }
|
|
|
+
|
|
|
+ count+=size;
|
|
|
+ if (cluster->ncores == count)
|
|
|
+ {
|
|
|
+ count = 0;
|
|
|
+ cluster = _starpu_cluster_list_next(cluster);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return;
|
|
|
+}
|