/* $Source: bitbucket.org:berkeleylab/gasnet.git/extended-ref/coll/gasnet_scratch.h $ * Description: Reference implemetation of GASNet Collectives team * Copyright 2009, Rajesh Nishtala , Paul H. Hargrove , Dan Bonachea * Terms of use are as specified in license.txt */ /* in all the functions below i assume that the scratch space is no bigger than 4GB*/ #ifndef __GASNET_SCRATCH_H__ #define __GASNET_SCRATCH_H__ 1 #define GASNETE_COLL_SCRATCH_TREE_OP 0 #define GASNETE_COLL_SCRATCH_DISSEM_OP 1 // How many elements (of appropriate types) to inline in order to avoid dynamic allocations #define GASNETE_COLL_NUM_INLINE_OUT_PEERS 8 #define GASNETE_COLL_NUM_INLINE_IN_PEERS 8 struct gasnete_coll_node_scratch_status_t_; typedef struct gasnete_coll_node_scratch_status_t_ gasnete_coll_node_scratch_status_t; /* down tree means we send to relative ranks that are higher than us*/ /* up tree means that we send to relative ranks that are lower than us*/ typedef enum {GASNETE_COLL_UP_TREE=0, GASNETE_COLL_DOWN_TREE} gasnete_coll_tree_dir_t; typedef enum {GASNETE_COLL_DISSEM_OP=0, GASNETE_COLL_TREE_OP} gasnete_coll_op_type_t; struct gasnete_coll_scratch_req_t_ { gasnete_coll_scratch_req_t *next; gasnete_coll_scratch_req_t **prev_p; gasnete_coll_op_t *op; gasnete_coll_tree_type_t tree_type; gex_Rank_t root; gasnete_coll_team_t team; /*notice that we don't need to keep track of the dissemination radix since we don't do anything withit */ /* whether this is a tree op where peers are fixed from phase to phase*/ gasnete_coll_op_type_t op_type; gasnete_coll_tree_dir_t tree_dir; /*this is the sum incoming space of all the peers sending to me*/ /*for now, for non treeops this is the amount of data that everyone is requesting*/ uintptr_t incoming_size; /*information for all the data for which i am the target*/ /*for non tree ops these values not used*/ int num_in_peers; gex_Rank_t *in_peers; /*information for all the data for which i am an initiator*/ /*for non tree ops this information is not used*/ int num_out_peers; gex_Rank_t *out_peers; uintptr_t *out_sizes; // A short array of uintptr_t for out_sizes and scratchpos (thus *2) // TODO: this could be a flexible array member sized according to team size? uintptr_t inline_uintptr[GASNETE_COLL_NUM_INLINE_OUT_PEERS*2]; }; // Allocate and free scratch_requests GASNETI_INLINE(gasnete_coll_scratch_alloc_req) GASNETI_MALLOC gasnete_coll_scratch_req_t *gasnete_coll_scratch_alloc_req(gasnete_coll_team_t team) { gasnete_coll_scratch_req_t *scratch_req = gasneti_lifo_pop(&team->scratch_free_list); if_pf (! scratch_req) { scratch_req = gasneti_calloc(1,sizeof(gasnete_coll_scratch_req_t)); scratch_req->team = team; } else { gasneti_assert(scratch_req->team == team); } return scratch_req; } GASNETI_INLINE(gasnete_coll_scratch_free_req) void gasnete_coll_scratch_free_req(gasnete_coll_scratch_req_t *scratch_req) { gasnete_coll_team_t team = scratch_req->team; gasneti_lifo_push(&team->scratch_free_list, scratch_req); } void gasnete_coll_scratch_req_purge(gasnete_coll_team_t team); // Allocate and free (consecutive) space used for out_sizes and scratchpos // For small sizes we use space within the scratch request itself // The allocation interfaces are such that one could split the two apart GASNETI_INLINE(gasnete_coll_scratch_alloc_out_sizes) void gasnete_coll_scratch_alloc_out_sizes(gasnete_coll_scratch_req_t *req, size_t n) { gasneti_assert(n == (req->op_type == GASNETE_COLL_DISSEM_OP ? 1 : req->num_out_peers)); size_t count = n + req->num_out_peers; if (count > 2 * GASNETE_COLL_NUM_INLINE_OUT_PEERS) { req->out_sizes = gasneti_malloc(count * sizeof(uintptr_t)); } else { req->out_sizes = req->inline_uintptr; } } GASNETI_INLINE(gasnete_coll_scratch_alloc_pos) void gasnete_coll_scratch_alloc_pos(gasnete_coll_scratch_req_t *req) { size_t num_out_sizes = (req->op_type == GASNETE_COLL_DISSEM_OP ? 1 : req->num_out_peers); gasnete_coll_op_t *op = req->op; op->scratchpos = req->out_sizes + num_out_sizes; } GASNETI_INLINE(gasnete_coll_scratch_free_inlines) void gasnete_coll_scratch_free_inlines(gasnete_coll_scratch_req_t *req) { size_t num_out_sizes = (req->op_type == GASNETE_COLL_DISSEM_OP ? 1 : req->num_out_peers); gasneti_assert(req->op->scratchpos == req->out_sizes + num_out_sizes); size_t n = req->num_out_peers + num_out_sizes; if (n > 2 * GASNETE_COLL_NUM_INLINE_OUT_PEERS) { gasneti_assert(req->out_sizes != req->inline_uintptr); gasneti_free(req->out_sizes); } } GASNETI_INLINE(gasnete_coll_scratch_base) uintptr_t gasnete_coll_scratch_base(gasnete_coll_team_t team, gex_Rank_t rank) { void *addr; if (team->scratch_addrs) { addr = team->scratch_addrs[rank]; } else { gex_Rank_t jobrank = team->rel2act_map ? team->rel2act_map[rank] : rank; addr = team->scratch_segs[jobrank].addr; } return (uintptr_t)addr + team->symmetric_scratch_offset; } GASNETI_INLINE(gasnete_coll_scratch_myaddr) void* gasnete_coll_scratch_myaddr(gasnete_coll_op_t *op, uintptr_t byte_offset) { const gasnete_coll_team_t team = op->team; return (void *)(byte_offset + op->myscratchpos + (uintptr_t)team->myscratch); } GASNETI_INLINE(gasnete_coll_scratch_addr) void* gasnete_coll_scratch_addr(gasnete_coll_op_t *op, gex_Rank_t rank, int index, uintptr_t byte_offset) { const gasnete_coll_team_t team = op->team; return (void *)(byte_offset + op->scratchpos[index] + gasnete_coll_scratch_base(team, rank)); } /* try to allocate scratch space*/ /* returns 1 on success or zero on failure*/ int8_t gasnete_coll_scratch_alloc_nb(gasnete_coll_op_t* op GASNETI_THREAD_FARG); /* release the associated scratch space with this op*/ void gasnete_coll_free_scratch(gasnete_coll_op_t *op); /* function calls for coll init*/ void gasnete_coll_alloc_new_scratch_status(gasnete_coll_team_t team); void gasnete_coll_free_scratch_status(gasnete_coll_team_t team); #endif