1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
2 /*
3  * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
4  *                         University Research and Technology
5  *                         Corporation.  All rights reserved.
6  * Copyright (c) 2004-2013 The University of Tennessee and The University
7  *                         of Tennessee Research Foundation.  All rights
8  *                         reserved.
9  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
10  *                         University of Stuttgart.  All rights reserved.
11  * Copyright (c) 2004-2005 The Regents of the University of California.
12  *                         All rights reserved.
13  * Copyright (c) 2006-2009 Cisco Systems, Inc.  All rights reserved.
14  * Copyright (c) 2006      Voltaire. All rights reserved.
15  * Copyright (c) 2007      Mellanox Technologies. All rights reserved.
16  * Copyright (c) 2010      IBM Corporation.  All rights reserved.
17  * Copyright (c) 2012-2015 NVIDIA Corporation.  All rights reserved.
18  * Copyright (c) 2015      Los Alamos National Security, LLC.  All rights
19  *                         reserved.
20  *
21  * $COPYRIGHT$
22  *
23  * Additional copyrights may follow
24  *
25  * $HEADER$
26  */
27 
28 /**
29  * @file:
30  *
31  * This file implements a simple memory pool that is used by the GPU
32  * buffer on the sending side.  It just gets a memory handle and event
33  * handle that can be sent to the remote side which can then use the
34  * handles to get access to the memory and the event to determine when
35  * it can start accessing the memory.  There is no caching of the
36  * memory handles as getting new ones is fast.  The event handles are
37  * cached by the cuda_common code.
38  */
39 
40 #include "opal_config.h"
41 #include "opal/mca/rcache/base/base.h"
42 #include "opal/mca/rcache/gpusm/rcache_gpusm.h"
43 #include "opal/mca/common/cuda/common_cuda.h"
44 
45 /**
46  * Called when the registration free list is created.  An event is created
47  * for each entry.
48  */
mca_rcache_gpusm_registration_constructor(mca_rcache_gpusm_registration_t * item)49 static void mca_rcache_gpusm_registration_constructor( mca_rcache_gpusm_registration_t *item )
50 {
51     mca_common_cuda_construct_event_and_handle(&item->event,
52                                                (void *)&item->evtHandle);
53 }
54 
55 /**
56  * Called when the program is exiting.  This destroys the events.
57  */
mca_rcache_gpusm_registration_destructor(mca_rcache_gpusm_registration_t * item)58 static void mca_rcache_gpusm_registration_destructor( mca_rcache_gpusm_registration_t *item )
59 {
60     mca_common_cuda_destruct_event(item->event);
61 }
62 
63 OBJ_CLASS_INSTANCE(mca_rcache_gpusm_registration_t, mca_rcache_base_registration_t,
64                    mca_rcache_gpusm_registration_constructor,
65                    mca_rcache_gpusm_registration_destructor);
66 
67 /*
68  *  Initializes the rcache module.
69  */
mca_rcache_gpusm_module_init(mca_rcache_gpusm_module_t * rcache)70 void mca_rcache_gpusm_module_init(mca_rcache_gpusm_module_t* rcache)
71 {
72     rcache->super.rcache_component = &mca_rcache_gpusm_component.super;
73     rcache->super.rcache_register = mca_rcache_gpusm_register;
74     rcache->super.rcache_find = mca_rcache_gpusm_find;
75     rcache->super.rcache_deregister = mca_rcache_gpusm_deregister;
76     rcache->super.rcache_finalize = mca_rcache_gpusm_finalize;
77 
78     OBJ_CONSTRUCT(&rcache->reg_list, opal_free_list_t);
79 
80     /* Start with 0 entries in the free list since CUDA may not have
81      * been initialized when this free list is created and there is
82      * some CUDA specific activities that need to be done. */
83     opal_free_list_init (&rcache->reg_list, sizeof(struct mca_rcache_common_cuda_reg_t),
84             opal_cache_line_size,
85             OBJ_CLASS(mca_rcache_gpusm_registration_t),
86             0,opal_cache_line_size,
87             0, -1, 64, NULL, 0, NULL, NULL, NULL);
88 
89 }
90 
91 /**
92  * Just go ahead and get a new registration.  The find and register
93  * functions are the same thing for this memory pool.
94  */
mca_rcache_gpusm_find(mca_rcache_base_module_t * rcache,void * addr,size_t size,mca_rcache_base_registration_t ** reg)95 int mca_rcache_gpusm_find(mca_rcache_base_module_t *rcache, void *addr,
96                          size_t size,
97                          mca_rcache_base_registration_t **reg)
98 {
99     return mca_rcache_gpusm_register(rcache, addr, size, 0, 0, reg);
100 }
101 
102 /*
103  * This is the one function that does all the work.  It will call into
104  * the register function to get the memory handle for the sending
105  * buffer.  There is no need to deregister the memory handle so the
106  * deregister function is a no-op.
107  */
mca_rcache_gpusm_register(mca_rcache_base_module_t * rcache,void * addr,size_t size,uint32_t flags,int32_t access_flags,mca_rcache_base_registration_t ** reg)108 int mca_rcache_gpusm_register(mca_rcache_base_module_t *rcache, void *addr,
109                              size_t size, uint32_t flags, int32_t access_flags,
110                              mca_rcache_base_registration_t **reg)
111 {
112     mca_rcache_gpusm_module_t *rcache_gpusm = (mca_rcache_gpusm_module_t*)rcache;
113     mca_rcache_base_registration_t *gpusm_reg;
114     opal_free_list_item_t *item;
115     unsigned char *base, *bound;
116     int rc;
117 
118     /* In spite of the fact we return an error code, the existing code
119      * checks the registration for a NULL value rather than looking at
120      * the return code.  So, initialize the registration to NULL in
121      * case we run into a failure. */
122     *reg = NULL;
123 
124     base = addr;
125     bound = (unsigned char *)addr + size - 1;
126 
127     item = opal_free_list_get (&rcache_gpusm->reg_list);
128     if(NULL == item) {
129         return OPAL_ERR_OUT_OF_RESOURCE;
130     }
131     gpusm_reg = (mca_rcache_base_registration_t*)item;
132 
133     gpusm_reg->rcache = rcache;
134     gpusm_reg->base = base;
135     gpusm_reg->bound = bound;
136     gpusm_reg->flags = flags;
137     gpusm_reg->access_flags = access_flags;
138 
139     rc = cuda_getmemhandle (base, size, gpusm_reg, NULL);
140 
141     if(rc != OPAL_SUCCESS) {
142         opal_free_list_return (&rcache_gpusm->reg_list, item);
143         return rc;
144     }
145 
146     *reg = gpusm_reg;
147     (*reg)->ref_count++;
148     return OPAL_SUCCESS;
149 
150 }
151 
152 /*
153  * Return the registration to the free list.
154  */
mca_rcache_gpusm_deregister(struct mca_rcache_base_module_t * rcache,mca_rcache_base_registration_t * reg)155 int mca_rcache_gpusm_deregister(struct mca_rcache_base_module_t *rcache,
156                                mca_rcache_base_registration_t *reg)
157 {
158     int rc;
159     mca_rcache_gpusm_module_t *rcache_gpusm = (mca_rcache_gpusm_module_t *)rcache;
160 
161     rc = cuda_ungetmemhandle (NULL, reg);
162     opal_free_list_return (&rcache_gpusm->reg_list, (opal_free_list_item_t *) reg);
163     return OPAL_SUCCESS;
164 }
165 
166 /**
167  * Free up the resources.
168  */
mca_rcache_gpusm_finalize(struct mca_rcache_base_module_t * rcache)169 void mca_rcache_gpusm_finalize(struct mca_rcache_base_module_t *rcache)
170 {
171     opal_free_list_item_t *item;
172     mca_rcache_gpusm_module_t *rcache_gpusm = (mca_rcache_gpusm_module_t *)rcache;
173 
174     /* Need to run the destructor on each item in the free list explicitly.
175      * The destruction of the free list only runs the destructor on the
176      * main free list, not each item. */
177     while (NULL != (item = (opal_free_list_item_t *)opal_lifo_pop(&(rcache_gpusm->reg_list.super)))) {
178         OBJ_DESTRUCT(item);
179     }
180 
181     OBJ_DESTRUCT(&rcache_gpusm->reg_list);
182     return;
183 }
184