static int bindup_node(context_t *c) { /* choose any node rank here. i use node rank 0 (quid 0) because it's easy. * */ if (0 == c->noderank) { printf("### [rank %d on %s] expanding my cpuset for threading!\n", c->rank, c->hostname); /* QUO_BIND_PUSH_OBJ, so the last argument doesn't matter */ int rc = QUO_bind_push(c->quo, QUO_BIND_PUSH_OBJ, QUO_OBJ_MACHINE, -1); if (QUO_SUCCESS != rc) { fprintf(stderr, "%s fails with rc: %d\n", "QUO_bind_push", rc); return 1; } /* i pushed a policy */ c->pushed_policy = true; demo_emit_sync(c); } else { printf("--- [rank %d on %s] going to sleep...\n", c->rank, c->hostname); demo_emit_sync(c); } return 0; }
static int push_bind(const p1_context_t *c) { if (QUO_SUCCESS != QUO_bind_push(c->quo, QUO_BIND_PUSH_OBJ, QUO_OBJ_SOCKET, -1)) { return 1; } return 0; }
/** * elects some node ranks and distributes them onto all the sockets on the node */ static int bindup_sockets(const context_t *c) { /* if you are going to change bindings often, then cache this */ if (c->noderank + 1 <= c->nsockets) { if (QUO_SUCCESS != QUO_bind_push(c->quo, QUO_BIND_PUSH_PROVIDED, QUO_OBJ_SOCKET, c->noderank)) { return 1; } } return 0; }
int main() { int number, i; if (MPI_SUCCESS != MPI_Init(NULL, NULL)) return 1; if (MPI_SUCCESS != MPI_Comm_rank(MPI_COMM_WORLD, &rank)) goto err; if (MPI_SUCCESS != MPI_Comm_size(MPI_COMM_WORLD, &size)) goto err; if (QUO_SUCCESS != QUO_create(&context)) goto err; if (QUO_SUCCESS != QUO_bind_push(context, QUO_BIND_PUSH_PROVIDED, QUO_OBJ_SOCKET, rank%2)) { printf("QUO_bind failed\n"); goto err; } omp_set_nested(1); #pragma omp parallel num_threads(4) { if (QUO_SUCCESS != QUO_bind_threads(context, QUO_OBJ_SOCKET, rank%2)) printf("QUO_bind_threads failed\n"); toString("First configuration"); #pragma omp parallel num_threads(2) { if (QUO_SUCCESS != QUO_bind_threads(context, QUO_OBJ_SOCKET, rank%2)) printf("QUO_bind_threads failed\n"); toString("Second configuration"); } } err: if(context) QUO_free(context); MPI_Finalize(); return 0; }
* bind to what is provided. the assumption is that the binding policy for all * procs that are calling this are "binding up." this demo binds all ranks on a * node to the provided "this" that encloses the current policy. for example, if * i'm bound to a core and "bind up" to a socket, then i'll be bound to my * enclosing socket. */ static int bindup_to_this(context_t *c, QUO_obj_type_t this) { demo_emit_sync(c); printf("### [rank %d on %s] expanding my cpuset for threading!\n", c->rank, c->hostname); /* QUO_BIND_PUSH_OBJ, so the last argument doesn't matter. QUO will do smart * things here (ish). This is where how the things were launched matters. */ int rc = QUO_bind_push(c->quo, QUO_BIND_PUSH_OBJ, this, -1); if (QUO_SUCCESS != rc) { fprintf(stderr, "%s fails with rc: %d\n", "QUO_bind_push", rc); return 1; } c->pushed_policy = true; /* i pushed a policy */ demo_emit_sync(c); return 0; } /** * we can only safely pop bindings that were pushed, so those who were elected * to be the socket master can now revert their binding by calling pop. */
int main(void) { int qrc = QUO_SUCCESS, erc = EXIT_SUCCESS; int qv = 0, qsv = 0, nnodes = 0, nnoderanks = 0; int nsockets = 0, ncores = 0, npus = 0; char *bad_func = NULL; char *cbindstr = NULL, *cbindstr2 = NULL, *cbindstr3 = NULL; int bound = 0, bound2 = 0, bound3 = 0; QUO_context quo = NULL; inf_t info; if (init(&info)) { bad_func = "info"; goto out; } if (QUO_SUCCESS != (qrc = QUO_version(&qv, &qsv))) { bad_func = "QUO_version"; goto out; } /* cheap call */ if (QUO_SUCCESS != (qrc = QUO_create(&quo))) { bad_func = "QUO_create"; goto out; } if (QUO_SUCCESS != (qrc = QUO_nsockets(quo, &nsockets))) { bad_func = "QUO_nsockets"; goto out; } if (QUO_SUCCESS != (qrc = QUO_ncores(quo, &ncores))) { bad_func = "QUO_ncores"; goto out; } if (QUO_SUCCESS != (qrc = QUO_npus(quo, &npus))) { bad_func = "QUO_npus"; goto out; } if (QUO_SUCCESS != (qrc = QUO_bound(quo, &bound))) { bad_func = "QUO_bound"; goto out; } if (QUO_SUCCESS != (qrc = QUO_stringify_cbind(quo, &cbindstr))) { bad_func = "QUO_stringify_cbind"; goto out; } if (QUO_SUCCESS != (qrc = QUO_nnodes(quo, &nnodes))) { bad_func = "QUO_nnodes"; goto out; } if (QUO_SUCCESS != (qrc = QUO_nqids(quo, &nnoderanks))) { bad_func = "QUO_nnodes"; goto out; } /* last argument ignored with QUO_BIND_PUSH_OBJ option */ if (QUO_SUCCESS != (qrc = QUO_bind_push(quo, QUO_BIND_PUSH_OBJ, QUO_OBJ_CORE, 0))) { bad_func = "QUO_bind_push"; goto out; } if (QUO_SUCCESS != (qrc = QUO_stringify_cbind(quo, &cbindstr2))) { bad_func = "QUO_stringify_cbind"; goto out; } if (QUO_SUCCESS != (qrc = QUO_bound(quo, &bound2))) { bad_func = "QUO_bound"; goto out; } if (QUO_SUCCESS != (qrc = QUO_bind_pop(quo))) { bad_func = "QUO_bind_pop"; goto out; } if (QUO_SUCCESS != (qrc = QUO_stringify_cbind(quo, &cbindstr3))) { bad_func = "QUO_stringify_cbind"; goto out; } if (QUO_SUCCESS != (qrc = QUO_bound(quo, &bound3))) { bad_func = "QUO_bound"; goto out; } if (QUO_SUCCESS != (qrc = QUO_free(quo))) { bad_func = "QUO_free"; goto out; } printf("### quo version: %d.%d ###\n", qv, qsv); printf("### nnodes: %d\n", nnodes); printf("### nnoderanks: %d\n", nnoderanks); printf("### nsockets: %d\n", nsockets); printf("### ncores: %d\n", ncores); printf("### npus: %d\n", npus); printf("### process %d [%s] bound: %s\n", (int)getpid(), cbindstr, bound ? "true" : "false"); printf("### process %d [%s] bound: %s\n", (int)getpid(), cbindstr2, bound2 ? "true" : "false"); printf("### process %d [%s] bound: %s\n", (int)getpid(), cbindstr3, bound3 ? "true" : "false"); /* the string returned by QUO_machine_topo_stringify MUST be free'd by us */ free(cbindstr); free(cbindstr2); out: if (NULL != bad_func) { fprintf(stderr, "xxx %s failure in: %s\n", __FILE__, bad_func); erc = EXIT_FAILURE; } (void)fini(&info); return erc; }