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_log.h>
22#include <nm_core_interface.h>
23
60
73
74
75/* ** generic trees **************************************** */
76
77void nm_coll_tree_init(struct nm_coll_tree_info_s*p_tree, nm_coll_tree_kind_t kind, int n, int self,
78 const struct nm_coll_topology_s*p_topology, int root);
79
84void nm_coll_tree_step(const struct nm_coll_tree_info_s*p_tree, int step, int*p_parent, int*p_children, int*n_children);
85
87
88int nm_coll_tree_weight(const struct nm_coll_tree_info_s*p_tree, int step, int self);
89
91
93
95
97void nm_coll_tree_descendants(const struct nm_coll_tree_info_s*p_tree, int step, int self, int*p_descendants);
98
101
103nm_coll_tree_kind_t nm_coll_tree_heuristic(int comm_size, nm_len_t data_size, const struct nm_coll_topology_s*p_topology);
104
106nm_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);
107
110
112static inline int nm_coll_tree_max_weight(const struct nm_coll_tree_info_s*p_tree)
113{
114 int max_weight = 0;
115 int s;
116 for(s = 0; s < p_tree->height; s++)
117 {
118 int p = -1, n = -1;
119 int c[p_tree->max_arity];
120 nm_coll_tree_step(p_tree, s, &p, c, &n);
121 if(p != -1)
122 {
123 max_weight = nm_coll_tree_weight(p_tree, s, p_tree->self);
124 break;
125 }
126 }
127 return max_weight;
128}
129
130/* ** toolbox ********************************************** */
131
132static inline int nm_coll_ispow2(int x)
133{
134 return (x != 0) && ((x & (x - 1)) == 0);
135}
136
138static inline int nm_coll_log2_floor(int x)
139{
140 assert(x > 0);
141 return ((unsigned) (8*sizeof (unsigned long long) - __builtin_clzll((x)) - 1));
142}
143
145static inline int nm_coll_log2_ceil(int x)
146{
147 assert(x > 0);
148 return nm_coll_log2_floor(x) + (!!(x & (x - 1)));
149}
150
152static inline int nm_coll_log4_floor(int x)
153{
154 return nm_coll_log2_floor(x) / 2;
155}
156
158static inline int nm_coll_ipow(int base, int exp)
159{
160 assert(base >= 0);
161 assert(exp >= 0);
162 /* cascade of tests should be elided by the compiler when base is a compile-time constant */
163 if(base == 2)
164 return 1 << exp;
165 else if(base == 4)
166 return 1 << (2 * exp);
167 else if(base == 8)
168 return 1 << (3 * exp);
169 else if(base == 16)
170 return 1 << (4 * exp);
171 int result = 1;
172 for(;;)
173 {
174 if(exp & 1)
175 result *= base;
176 exp >>= 1;
177 if(!exp)
178 break;
179 base *= base;
180 }
181 return result;
182}
183
185static inline int nm_coll_log_n_ceil(int x, const int n)
186{
187 assert(x > 0);
188 assert(n >= 2);
189 int l = 0;
190 int exp = n - 1;
191 x--;
192 while(x > 0)
193 {
194 x -= exp;
195 exp *= n;
196 l++;
197 }
198 return l;
199}
200
202static inline int nm_coll_log_n_floor(int x, const int n)
203{
204 assert(x >= 1);
205 assert(n >= 2);
206 int l = 0;
207 while(x >= n)
208 {
209 l++;
210 x = x / n;
211 }
212 return l;
213}
214
216static inline int nm_coll_r2v(int i, const struct nm_coll_tree_info_s*p_tree)
217{
218 return ((p_tree->n + i - p_tree->root) % p_tree->n);
219}
220
222static inline int nm_coll_v2r(int i, const struct nm_coll_tree_info_s*p_tree)
223{
224 return ((p_tree->root + i) % p_tree->n);
225}
226
227/* ********************************************************* */
228
243
247 nm_coll_tree_kind_t kind, nm_group_t p_group, int root, int self,
249{
250 p_status->p_session = p_session;
251 p_status->p_group = p_group;
252 p_status->tag = tag;
253 nm_coll_tree_init(&p_status->tree, kind, nm_group_size(p_group), self, nm_group_get_topology(p_group), root);
254 p_status->n_children = -1;
255 p_status->children_requests = padico_malloc((1 + p_status->tree.max_arity) * sizeof(nm_sr_request_t));
256 p_status->children = padico_malloc((1 + p_status->tree.max_arity) * sizeof(int));
257 p_status->pending_reqs = 0;
258}
259
260static inline void nm_coll_tree_status_destroy(struct nm_coll_tree_status_s*p_status)
261{
262 assert(p_status->p_session != NULL);
263 p_status->p_session = NULL;
264 assert(p_status->p_group != NULL);
265 p_status->p_group = NULL;
266 assert(p_status->pending_reqs == 0);
267 padico_free(p_status->children_requests);
268 p_status->children_requests = NULL;
269 padico_free(p_status->children);
270 p_status->children = NULL;
271 nm_coll_tree_destroy(&p_status->tree);
272}
273
274static inline void nm_coll_tree_send(struct nm_coll_tree_status_s*p_coll_tree, int dest,
275 struct nm_data_s*p_data, nm_sr_request_t*p_req)
276{
277 assert(dest != -1);
278 nm_gate_t p_gate = nm_group_get_gate(p_coll_tree->p_group, dest);
279 nm_atomic_inc(&p_coll_tree->pending_reqs);
280 nm_sr_isend_data(p_coll_tree->p_session, p_gate, p_coll_tree->tag, p_data, p_req);
281}
282
283static inline void nm_coll_tree_issend(struct nm_coll_tree_status_s*p_coll_tree, int dest,
284 struct nm_data_s*p_data, nm_sr_request_t*p_req)
285{
286 assert(dest != -1);
287 nm_gate_t p_gate = nm_group_get_gate(p_coll_tree->p_group, dest);
288 nm_atomic_inc(&p_coll_tree->pending_reqs);
289 nm_sr_send_init(p_coll_tree->p_session, p_req);
290 nm_sr_send_pack_data(p_coll_tree->p_session, p_req, p_data);
291 nm_sr_send_issend(p_coll_tree->p_session, p_req, p_gate, p_coll_tree->tag);
292}
293
294static inline void nm_coll_tree_recv(struct nm_coll_tree_status_s*p_coll_tree, int from,
295 struct nm_data_s*p_data, nm_sr_request_t*p_req)
296{
297 assert(from != -1);
298 nm_gate_t p_gate = nm_group_get_gate(p_coll_tree->p_group, from);
299 nm_atomic_inc(&p_coll_tree->pending_reqs);
300 nm_sr_irecv_data(p_coll_tree->p_session, p_gate, p_coll_tree->tag, p_data, p_req);
301}
302
303static inline void nm_coll_tree_set_notifier(struct nm_coll_tree_status_s*p_coll_tree, nm_sr_request_t*p_req,
304 void(*p_notifier)(nm_sr_event_t, const nm_sr_event_info_t*, void*))
305{
306 nm_sr_request_set_ref(p_req, p_coll_tree);
307 nm_sr_request_monitor(p_coll_tree->p_session, p_req, NM_SR_EVENT_FINALIZED, p_notifier);
308}
309
310static inline int nm_coll_tree_req_index(struct nm_coll_tree_status_s*p_coll_tree, nm_sr_request_t*p_request)
311{
312 if( (p_request < &p_coll_tree->children_requests[0]) ||
313 (p_request > &p_coll_tree->children_requests[p_coll_tree->tree.max_arity - 1]) )
314 {
315 NM_FATAL("given p_request = %p is not in coll_tree", p_request);
316 }
317 const int i = p_request - p_coll_tree->children_requests;
318 assert(i >= 0);
319 assert(i < p_coll_tree->tree.max_arity);
320 return i;
321}
322
323
int nm_group_size(nm_group_t group)
const struct nm_coll_topology_s * nm_group_get_topology(nm_group_t p_group)
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)
static int nm_coll_log_n_floor(int x, const int n)
floor(log_n(x)
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
void nm_coll_tree_init(struct nm_coll_tree_info_s *p_tree, nm_coll_tree_kind_t kind, int n, int self, const struct nm_coll_topology_s *p_topology, int root)
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 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)
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, int self, nm_tag_t tag)
initialize a common status for non-blocking collective
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
int nm_sr_request_monitor(nm_session_t p_session, nm_sr_request_t *p_request, nm_sr_event_t mask, nm_sr_event_notifier_t notifier)
Set a notification function called upon request completion.
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
nm_sr_event_t
events for nm_sr_monitor()
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.
static int nm_sr_request_set_ref(nm_sr_request_t *p_request, void *ref)
Add a user reference to a 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:538
static nm_session_t p_session
static nm_gate_t p_gate
Basic primitives to display info & warnings.
#define NM_FATAL(format,...)
Definition nm_log.h:36
int root
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_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)
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; both vects are empty when no topology is available
Definition nm_group.h:55
description of an instanciated tree
struct nm_coll_topology_s * p_topology
topology information of the nodes we will run the collective on; may be NULL
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)
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:199
Connection to another process.
Definition nm_gate.h:104
internal defintion of the sendrecv request
information field for sendrecv events