NewMadeleine

Documentation

« back to PM2 home.
nm_coll_trees.h
Go to the documentation of this file.
1/*
2 * NewMadeleine
3 * Copyright (C) 2014-2026 (see AUTHORS file)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at
8 * your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 */
15
21#include <nm_public.h>
22#include <nm_core_interface.h>
23
60
73
74
75/* ** generic trees **************************************** */
76
78void nm_coll_tree_init(struct nm_coll_tree_info_s*p_tree, nm_coll_tree_kind_t kind, int n, int self, int root);
79
82
87void nm_coll_tree_step(const struct nm_coll_tree_info_s*p_tree, int step, int*p_parent, int*p_children, int*n_children);
88
90
91int nm_coll_tree_weight(const struct nm_coll_tree_info_s*p_tree, int step, int self);
92
94
96
98
100void nm_coll_tree_descendants(const struct nm_coll_tree_info_s*p_tree, int step, int self, int*p_descendants);
101
104
106nm_coll_tree_kind_t nm_coll_tree_heuristic(int comm_size, nm_len_t data_size, const struct nm_coll_topology_s*p_topology);
107
109nm_coll_tree_kind_t nm_coll_tree_weight_heuristic(int comm_size, nm_len_t data_size, const struct nm_coll_topology_s*p_topology);
110
113
115static inline int nm_coll_tree_max_weight(const struct nm_coll_tree_info_s*p_tree)
116{
117 int max_weight = 0;
118 int s;
119 for(s = 0; s < p_tree->height; s++)
120 {
121 int p = -1, n = -1;
122 int c[p_tree->max_arity];
123 nm_coll_tree_step(p_tree, s, &p, c, &n);
124 if(p != -1)
125 {
126 max_weight = nm_coll_tree_weight(p_tree, s, p_tree->self);
127 break;
128 }
129 }
130 return max_weight;
131}
132
133/* ** toolbox ********************************************** */
134
135static inline int nm_coll_ispow2(int x)
136{
137 return (x != 0) && ((x & (x - 1)) == 0);
138}
139
141static inline int nm_coll_log2_floor(int x)
142{
143 assert(x > 0);
144 return ((unsigned) (8*sizeof (unsigned long long) - __builtin_clzll((x)) - 1));
145}
146
148static inline int nm_coll_log2_ceil(int x)
149{
150 assert(x > 0);
151 return nm_coll_log2_floor(x) + (!!(x & (x - 1)));
152}
153
155static inline int nm_coll_log4_floor(int x)
156{
157 return nm_coll_log2_floor(x) / 2;
158}
159
161static inline int nm_coll_ipow(int base, int exp)
162{
163 assert(base >= 0);
164 assert(exp >= 0);
165 /* cascade of tests should be elided by the compiler when base is a compile-time constant */
166 if(base == 2)
167 return 1 << exp;
168 else if(base == 4)
169 return 1 << (2 * exp);
170 else if(base == 8)
171 return 1 << (3 * exp);
172 else if(base == 16)
173 return 1 << (4 * exp);
174 int result = 1;
175 for(;;)
176 {
177 if(exp & 1)
178 result *= base;
179 exp >>= 1;
180 if(!exp)
181 break;
182 base *= base;
183 }
184 return result;
185}
186
188static inline int nm_coll_log_n_ceil(int x, const int n)
189{
190 assert(x > 0);
191 assert(n >= 2);
192 int l = 0;
193 int exp = n - 1;
194 x--;
195 while(x > 0)
196 {
197 x -= exp;
198 exp *= n;
199 l++;
200 }
201 return l;
202}
203
205static inline int nm_coll_log_n_floor(int x, const int n)
206{
207 assert(x >= 1);
208 assert(n >= 2);
209 int l = 0;
210 while(x >= n)
211 {
212 l++;
213 x = x / n;
214 }
215 return l;
216}
217
219static inline int nm_coll_r2v(int i, const struct nm_coll_tree_info_s*p_tree)
220{
221 return ((p_tree->n + i - p_tree->root) % p_tree->n);
222}
223
225static inline int nm_coll_v2r(int i, const struct nm_coll_tree_info_s*p_tree)
226{
227 return ((p_tree->root + i) % p_tree->n);
228}
229
230/* ********************************************************* */
231
246
251{
252 p_status->p_session = p_session;
253 p_status->p_group = p_group;
254 p_status->tag = tag;
256 p_status->n_children = -1;
257 p_status->children_requests = padico_malloc((1 + p_status->tree.max_arity) * sizeof(nm_sr_request_t));
258 p_status->children = padico_malloc((1 + p_status->tree.max_arity) * sizeof(int));
259 p_status->pending_reqs = 0;
260}
261
262static inline void nm_coll_tree_status_destroy(struct nm_coll_tree_status_s*p_status)
263{
264 assert(p_status->p_session != NULL);
265 p_status->p_session = NULL;
266 assert(p_status->p_group != NULL);
267 p_status->p_group = NULL;
268 assert(p_status->pending_reqs == 0);
269 padico_free(p_status->children_requests);
270 p_status->children_requests = NULL;
271 padico_free(p_status->children);
272 p_status->children = NULL;
273 nm_coll_tree_destroy(&p_status->tree);
274}
275
276static inline void nm_coll_tree_send(struct nm_coll_tree_status_s*p_coll_tree, int dest,
277 struct nm_data_s*p_data, nm_sr_request_t*p_req)
278{
279 assert(dest != -1);
280 nm_gate_t p_gate = nm_group_get_gate(p_coll_tree->p_group, dest);
281 nm_atomic_inc(&p_coll_tree->pending_reqs);
282 nm_sr_isend_data(p_coll_tree->p_session, p_gate, p_coll_tree->tag, p_data, p_req);
283}
284
285static inline void nm_coll_tree_issend(struct nm_coll_tree_status_s*p_coll_tree, int dest,
286 struct nm_data_s*p_data, nm_sr_request_t*p_req)
287{
288 assert(dest != -1);
289 nm_gate_t p_gate = nm_group_get_gate(p_coll_tree->p_group, dest);
290 nm_atomic_inc(&p_coll_tree->pending_reqs);
291 nm_sr_send_init(p_coll_tree->p_session, p_req);
292 nm_sr_send_pack_data(p_coll_tree->p_session, p_req, p_data);
293 nm_sr_send_issend(p_coll_tree->p_session, p_req, p_gate, p_coll_tree->tag);
294}
295
296static inline void nm_coll_tree_recv(struct nm_coll_tree_status_s*p_coll_tree, int from,
297 struct nm_data_s*p_data, nm_sr_request_t*p_req)
298{
299 assert(from != -1);
300 nm_gate_t p_gate = nm_group_get_gate(p_coll_tree->p_group, from);
301 nm_atomic_inc(&p_coll_tree->pending_reqs);
302 nm_sr_irecv_data(p_coll_tree->p_session, p_gate, p_coll_tree->tag, p_data, p_req);
303}
304
305static inline void nm_coll_tree_set_notifier(struct nm_coll_tree_status_s*p_coll_tree, nm_sr_request_t*p_req,
306 void(*p_notifier)(nm_sr_event_t, const nm_sr_event_info_t*, void*))
307{
308 nm_sr_request_monitor_with_ref(p_coll_tree->p_session, p_req, NM_SR_EVENT_FINALIZED, p_notifier, p_coll_tree);
309}
310
311static inline int nm_coll_tree_req_index(struct nm_coll_tree_status_s*p_coll_tree, nm_sr_request_t*p_request)
312{
313 if( (p_request < &p_coll_tree->children_requests[0]) ||
314 (p_request > &p_coll_tree->children_requests[p_coll_tree->tree.max_arity - 1]) )
315 {
316 NM_FATAL("given p_request = %p is not in coll_tree", p_request);
317 }
318 const int i = p_request - p_coll_tree->children_requests;
319 assert(i >= 0);
320 assert(i < p_coll_tree->tree.max_arity);
321 return i;
322}
323
324
nm_gate_t nm_group_get_gate(nm_group_t p_group, int rank)
struct nm_group_s * nm_group_t
type for groups
Definition nm_group.h:38
static int nm_coll_tree_max_weight(const struct nm_coll_tree_info_s *p_tree)
find the weight for the local process, without knowing at wich step we have a parent
nm_coll_tree_kind_t nm_coll_tree_kind_by_name(const char *s_kind)
enum nm_coll_tree_kind_e nm_coll_tree_kind_t
static void nm_coll_tree_recv(struct nm_coll_tree_status_s *p_coll_tree, int from, struct nm_data_s *p_data, nm_sr_request_t *p_req)
static int nm_coll_log2_ceil(int x)
ceil(log2(x))
static void nm_coll_tree_issend(struct nm_coll_tree_status_s *p_coll_tree, int dest, struct nm_data_s *p_data, nm_sr_request_t *p_req)
static void nm_coll_tree_set_notifier(struct nm_coll_tree_status_s *p_coll_tree, nm_sr_request_t *p_req, void(*p_notifier)(nm_sr_event_t, const nm_sr_event_info_t *, void *))
static int nm_coll_ispow2(int x)
void nm_coll_tree_init_group(struct nm_coll_tree_info_s *p_tree, nm_coll_tree_kind_t kind, nm_group_t p_group, int root)
init tree with a group as a support; the group holds additionnal topology information
static int nm_coll_log_n_floor(int x, const int n)
floor(log_n(x)
void nm_coll_tree_init(struct nm_coll_tree_info_s *p_tree, nm_coll_tree_kind_t kind, int n, int self, int root)
generic tree init
void nm_coll_tree_descendants(const struct nm_coll_tree_info_s *p_tree, int step, int self, int *p_descendants)
get all the leaves below the 'self' vertex, including self
static void nm_coll_tree_send(struct nm_coll_tree_status_s *p_coll_tree, int dest, struct nm_data_s *p_data, nm_sr_request_t *p_req)
static int nm_coll_r2v(int i, const struct nm_coll_tree_info_s *p_tree)
translate real ranks to virtual ranks (with root=0)
int nm_coll_binary_nb_nodes_in_left_subtree(const struct nm_coll_tree_info_s *const p_tree)
nm_coll_tree_kind_e
kind of tree
int nm_coll_tree_has_descendants(nm_coll_tree_kind_t k)
whether this coll_tree kind implements 'descendants' method for scatter/gather
static int nm_coll_log_n_ceil(int x, const int n)
ceil(log_n(x))
static int nm_coll_log2_floor(int x)
floor(log2(x))
static void nm_coll_tree_status_init(struct nm_coll_tree_status_s *p_status, nm_session_t p_session, nm_coll_tree_kind_t kind, nm_group_t p_group, int root, nm_tag_t tag)
initialize a common status for non-blocking collective
static int nm_coll_v2r(int i, const struct nm_coll_tree_info_s *p_tree)
translate virtual ranks (with root=0) to real ranks
void nm_coll_tree_destroy(struct nm_coll_tree_info_s *p_tree)
const char * nm_coll_tree_kind_name(nm_coll_tree_kind_t kind)
nm_coll_tree_kind_t nm_coll_tree_heuristic(int comm_size, nm_len_t data_size, const struct nm_coll_topology_s *p_topology)
heuristic to select a coll_tree kind for a generic tree-based collective
static int nm_coll_log4_floor(int x)
floor(log4(x))
void nm_coll_tree_step(const struct nm_coll_tree_info_s *p_tree, int step, int *p_parent, int *p_children, int *n_children)
get the parent & children for the local node at the given step.
int nm_coll_tree_has_weight(nm_coll_tree_kind_t k)
static int nm_coll_ipow(int base, int exp)
fast integer power() = base ^ exp
int nm_coll_tree_weight(const struct nm_coll_tree_info_s *p_tree, int step, int self)
static int nm_coll_tree_req_index(struct nm_coll_tree_status_s *p_coll_tree, nm_sr_request_t *p_request)
nm_coll_tree_kind_t nm_coll_tree_weight_heuristic(int comm_size, nm_len_t data_size, const struct nm_coll_topology_s *p_topology)
heuristic to select a coll_tree kind for a tree-based collective that needs weights (scatter/gather)
static void nm_coll_tree_status_destroy(struct nm_coll_tree_status_s *p_status)
@ NM_COLL_TREE_H4ARY
@ NM_COLL_TREE_FLAT
@ NM_COLL_TREE_8ARY
@ NM_COLL_TREE_3NOMIAL
@ NM_COLL_TREE_4NOMIAL
@ NM_COLL_TREE_2CHAINS_MODIFIED
HPL 2-rings modified.
@ NM_COLL_TREE_CHAIN_MODIFIED
HPL ring-modified algorithm.
@ NM_COLL_TREE_BINOMIAL
@ NM_COLL_TREE_HBINOMIAL
@ NM_COLL_TREE_8NOMIAL
@ NM_COLL_TREE_DEFAULT
for public interfaces, will fallback to one of the previous tree kinds
@ NM_COLL_TREE_16NOMIAL
@ NM_COLL_TREE_NONE
@ NM_COLL_TREE_3ARY
@ NM_COLL_TREE_H4NOMIAL
@ NM_COLL_TREE_HBINARY
@ NM_COLL_TREE_4ARY
@ NM_COLL_TREE_LADDER
@ _NM_COLL_TREE_MAX
@ NM_COLL_TREE_BINARY
@ NM_COLL_TREE_CHAIN
static int nm_atomic_inc(int *v)
increment int, atomic only when multithread
static int nm_sr_isend_data(nm_session_t p_session, nm_gate_t p_gate, nm_tag_t tag, struct nm_data_s *p_data, nm_sr_request_t *p_request)
static int nm_sr_request_monitor_with_ref(nm_session_t p_session, nm_sr_request_t *p_request, nm_sr_event_t mask, nm_sr_event_notifier_t notifier, void *ref)
static void nm_sr_send_init(nm_session_t p_session, nm_sr_request_t *p_request)
Init a send request.
static int nm_sr_send_issend(nm_session_t p_session, nm_sr_request_t *p_request, nm_gate_t p_gate, nm_tag_t tag)
send a built request in synchronous mode
static int nm_sr_irecv_data(nm_session_t p_session, nm_gate_t p_gate, nm_tag_t tag, struct nm_data_s *p_data, nm_sr_request_t *p_request)
nm_sr_event_t
events for monitors
static void nm_sr_send_pack_data(nm_session_t p_session, nm_sr_request_t *p_request, const struct nm_data_s *p_data)
Pack data described through an iterator into the given request.
@ NM_SR_EVENT_FINALIZED
request finalized, may be freed by user
nm_tag_t tag
the user-supplied tag
assert(p_data->ops.p_traversal !=NULL)
nm_data_propertie_gpu_preinit & p_data
Definition nm_data.h:539
static nm_session_t p_session
static nm_gate_t p_gate
int root
This is the common public header for NewMad.
#define NM_FATAL(format,...)
Definition nm_public.h:67
uint64_t nm_tag_t
user tags, 64 bits, contained in indirect hashtable
Definition nm_types.h:56
uint64_t nm_len_t
data length used by nmad
Definition nm_types.h:68
a description of hierarchy of processes; subgroup is empty when no topology is available and n_subgro...
Definition nm_group.h:55
description of an instanciated tree
int root
root node of the collective
void * _status
status of the underlying tree algorithm
int height
tree height: number of communications steps in the tree (0 for a single node)
nm_group_t p_group
group this collective will run on, if known, that holds topology information; may be NULL
int self
rank of local node
int n
number of nodes involved in collective
int max_arity
maximum number of children in tree
nm_coll_tree_kind_t kind
common status for a non-blocking operation that walks a tree
nm_sr_request_t parent_request
struct nm_coll_tree_info_s tree
int pending_reqs
number of pending send/recv operations
nm_sr_request_t * children_requests
a data descriptor, used to pack/unpack data from app layout to/from contiguous buffers
Definition nm_data.h:200
Connection to another process.
Definition nm_gate.h:109
internal defintion of the sendrecv request
information field for sendrecv events