Skip to content

Commit 8c94949

Browse files
committed
Add caf_allocate and call to it from prif_allocate. For the
moment, `caf_allocate` has a trivial implementation in relation to memory allocation with just a simple `malloc` call. This will be replaced.
1 parent af0ef6d commit 8c94949

File tree

5 files changed

+124
-14
lines changed

5 files changed

+124
-14
lines changed

manifest/fpm.toml.template

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "caffeine"
22
version = "0.1.0"
33
license = "BSD"
4-
author = ["Damian Rouson", "Harris Snyder", "Brad Richardson"]
4+
author = ["Damian Rouson", "Harris Snyder", "Brad Richardson", "Katherine Rasmussen"]
55
maintainer = "rouson@lbl.gov"
66
copyright = "2021-2022 UC Regents"
77

src/caffeine/allocation_s.f90

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
contains
88

99
module procedure prif_allocate
10+
use caffeine_h_m, only: caf_allocate
11+
12+
allocated_memory = caf_allocate( &
13+
product(ubounds-lbounds+1)*element_length, size(ucobounds), lcobounds, ucobounds, final_func, coarray_handle%ptr)
1014
end procedure
1115

1216
end submodule allocation_s

src/caffeine/caffeine.c

Lines changed: 99 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
#include "caffeine.h"
55
#include <stdint.h>
66
#include <stdio.h>
7-
#include <stdbool.h>
7+
#include <stdbool.h>
8+
#include <assert.h>
89
#include "gasnet_safe.h"
910
#include <gasnet_tools.h>
1011

@@ -21,12 +22,32 @@ static gex_Rank_t rank, size;
2122
const int double_Complex_workaround =4100;
2223
#endif
2324

25+
26+
#define HANDLE_SIZE(corank) (sizeof(intmax_t) + (sizeof(intmax_t) * (corank) * 2) + sizeof(final_func_ptr) + sizeof(size_t) + sizeof(int64_t) + sizeof(char*))
27+
28+
// macros that access a field of the coarray handle (CAH), an internal coarray metadata object
29+
30+
// since the size of the handle is dependent on the value of corank, the first field in the handle, each accessor
31+
// dereferences corank and uses its value to correctly calculate the memory locations of the other fields
32+
#define CAH_CORANK(coarray_handle) *((intmax_t*)(coarray_handle))
33+
#define CAH_LCOBOUNDS(coarray_handle) (intmax_t*)((char*)(coarray_handle) + sizeof(intmax_t))
34+
#define CAH_UCOBOUNDS(coarray_handle) (intmax_t*)((char*)(coarray_handle) + sizeof(intmax_t) + (sizeof(intmax_t) * *(intmax_t*)(coarray_handle)))
35+
#define CAH_FINAL_FUNC(coarray_handle) *(final_func_ptr*)((char*)(coarray_handle) + sizeof(intmax_t) + (sizeof(intmax_t) * *(intmax_t*)(coarray_handle) * 2))
36+
#define CAH_OBJECT_SIZE(coarray_handle) *(size_t*)((char*)(coarray_handle) + sizeof(intmax_t) + (sizeof(intmax_t) * *(intmax_t*)(coarray_handle) * 2) + sizeof(final_func_ptr))
37+
#define CAH_ALLOCATOR(coarray_handle) *(int64_t*)((char*)(coarray_handle) + sizeof(intmax_t) + (sizeof(intmax_t) * *(intmax_t*)(coarray_handle) * 2) + sizeof(final_func_ptr) + sizeof(size_t))
38+
39+
#define CAH_OBJECT_BASE_ADDR(coarray_handle) *(char**)((char*)(coarray_handle) + sizeof(intmax_t) + (sizeof(intmax_t) * *(intmax_t*)(coarray_handle) * 2) + sizeof(final_func_ptr) + sizeof(size_t) + sizeof(int64_t))
40+
41+
#define PTR_DIFFERENCE_BYTES(first_element_addr, fortran_object_base_addr) ((char*)(first_element_addr) - (char*)(fortran_object_base_addr))
42+
43+
static void setupCoarrayHandle(void* handle_mem, int corank, intmax_t* lcobounds, intmax_t* ucobounds, final_func_ptr final_func, size_t sz, int64_t allocator, void* object_base_addr_ptr);
44+
2445
void caf_caffeinate(int argc, char *argv[])
2546
{
2647
GASNET_SAFE(gex_Client_Init(&myclient, &myep, &myteam, "caffeine", &argc, &argv, 0));
27-
28-
size_t segsz = GASNET_PAGESIZE;
29-
48+
49+
size_t segsz = GASNET_PAGESIZE;
50+
3051
int argi = 1;
3152
if (argi < argc) {
3253
if (!strcmp(argv[argi], "-m")) {
@@ -37,7 +58,7 @@ void caf_caffeinate(int argc, char *argv[])
3758
}
3859
++argi;
3960
}
40-
61+
4162
gex_Segment_t mysegment;
4263
GASNET_SAFE(gex_Segment_Attach(&mysegment, myteam, segsz));
4364
}
@@ -57,6 +78,72 @@ int caf_num_images()
5778
return gex_TM_QuerySize(myteam);
5879
}
5980

81+
// allocate memory for the Fortran object plus memory for a header which contains the coarray handle information
82+
void* caf_allocate(size_t sz, int corank, CFI_cdesc_t* desc_lcobounds, CFI_cdesc_t* desc_ucobounds, final_func_ptr final_func, void** coarray_handle)
83+
{
84+
// coarray handle contains
85+
// corank (scalar intmax_t)
86+
// lcobounds (intmax_t array with size corank)
87+
// ucobounds (intmax_t array with size corank)
88+
// final function pointer
89+
// object_sz (size_t) ! should only be used in the finalizer, in other cases where coarray_handle can be accessed, the object_sz may not reflect the size of the data that we are dealing with
90+
// allocator (int64_t)
91+
// object_base_addr_ptr (char*)
92+
// TODO: add pointer to beginning of next coarray handle's addr
93+
94+
// aliased coarray handle will have all of the elements of a coarray handle filled in
95+
// expect it will have no data in the Fortran object elements
96+
// the pointer to where the data begins will point back to the memory in the original
97+
// coarray handle where memory was allocated for the data
98+
99+
// every time one accesses a coarray, need to traverse an extra level of indirection to get to the elements
100+
//
101+
102+
// currently unused allocator field
103+
// which allocator it came from
104+
// 1 - symmetric allocator with initial team
105+
// 2 - stack of allocators for each child team
106+
// ...
107+
// maybe need more for each team
108+
109+
// TODO: Do we need to add alignment padding here for the elements? such as when dealing with c_long_double?
110+
// How do you ensure that memory given to c_f_pointer is aligned correctly for Fortran for the given datatype?
111+
// - will become global setting that is decided at runtime, or add arg to caf_allocate for minimum alignment
112+
113+
intmax_t* lcobounds = desc_lcobounds->base_addr;
114+
intmax_t* ucobounds = desc_ucobounds->base_addr;
115+
116+
assert(corank >= 1); // corank must be 1 or more (coarray)
117+
assert(desc_lcobounds->rank == 1 && desc_ucobounds->rank == 1); // the lcobounds and ucobounds arrays must be 1d
118+
assert(desc_lcobounds->dim[0].extent == desc_ucobounds->dim[0].extent); // size of each cobounds array must be the same
119+
assert(desc_lcobounds->dim[0].extent == corank); // size of cobounds arrays must be equal to corank
120+
for(int i = 0; i < corank; i++) {
121+
assert(lcobounds[i] <= ucobounds[i]); // lcobounds must not be greater than ucobounds
122+
}
123+
124+
size_t handle_sz = HANDLE_SIZE(corank);
125+
void* allocated_mem = malloc(sz + handle_sz);
126+
127+
setupCoarrayHandle(allocated_mem, corank, lcobounds, ucobounds, final_func, sz, -1, (char*)allocated_mem + handle_sz);
128+
129+
*coarray_handle = allocated_mem; // Return the address of the handle to the caller through the `coarray_handle` argument
130+
return (void*)((char*)allocated_mem + handle_sz); // Return the address of the Fortran object
131+
}
132+
133+
static void setupCoarrayHandle(void* handle_mem, int corank, intmax_t* lcobounds, intmax_t* ucobounds, final_func_ptr final_func, size_t sz, int64_t allocator, void* object_base_addr_ptr)
134+
{
135+
size_t cobounds_arr_sz = sizeof(intmax_t) * corank;
136+
137+
// fill in coarray handle
138+
CAH_CORANK(handle_mem) = (intmax_t)corank;
139+
memcpy(CAH_LCOBOUNDS(handle_mem), lcobounds, cobounds_arr_sz);
140+
memcpy(CAH_UCOBOUNDS(handle_mem), ucobounds, cobounds_arr_sz);
141+
CAH_FINAL_FUNC(handle_mem) = final_func;
142+
CAH_OBJECT_SIZE(handle_mem) = sz;
143+
CAH_ALLOCATOR(handle_mem) = allocator;
144+
CAH_OBJECT_BASE_ADDR(handle_mem)= object_base_addr_ptr;
145+
}
146+
60147
void caf_sync_all()
61148
{
62149
gasnet_barrier_notify(0,GASNET_BARRIERFLAG_ANONYMOUS);
@@ -80,7 +167,7 @@ void caf_co_reduce(
80167
myteam, a_address, a_address, GEX_DT_USER, c_sizeof_a, num_elements, GEX_OP_USER, user_op, &c_sizeof_a, 0
81168
);
82169
}
83-
gex_Event_Wait(ev);
170+
gex_Event_Wait(ev);
84171

85172
if (stat != NULL) *stat = 0;
86173
}
@@ -90,12 +177,12 @@ void caf_co_broadcast(CFI_cdesc_t * a_desc, int source_image, int* stat, int num
90177
char* c_loc_a = (char*) a_desc->base_addr;
91178
size_t c_sizeof_a = a_desc->elem_len;
92179
int nbytes = num_elements * c_sizeof_a;
93-
180+
94181
int data_type = a_desc->type;
95182

96183
gex_Event_t ev
97184
= gex_Coll_BroadcastNB(myteam, source_image-1, c_loc_a, c_loc_a, nbytes, 0);
98-
gex_Event_Wait(ev);
185+
gex_Event_Wait(ev);
99186

100187
if (stat != NULL) *stat = 0;
101188
}
@@ -109,7 +196,7 @@ void set_stat_errmsg_or_abort(int* stat, char* errmsg, const int return_stat, co
109196
if (errmsg != NULL) {
110197
if (strlen(errmsg) >= strlen(return_message)) {
111198
// TODO: Figure out how/whether to handle repositioning of the null terminator.
112-
errmsg = return_message;
199+
errmsg = return_message;
113200
} else {
114201
// TODO: Figure out how to replace this with an assignment of a truncated error message.
115202
gasnett_fatalerror("%s", "caffeine.c: strlen(errmsg) too small");
@@ -142,7 +229,7 @@ void caf_co_max(CFI_cdesc_t* a_desc, int result_image, int* stat, char* errmsg,
142229
} else {
143230
ev = gex_Coll_ReduceToAllNB(myteam, a_address, a_address, a_type, c_sizeof_a, num_elements, GEX_OP_MAX, NULL, NULL, 0);
144231
}
145-
gex_Event_Wait(ev);
232+
gex_Event_Wait(ev);
146233

147234
if (stat != NULL) *stat = 0;
148235
}
@@ -172,7 +259,7 @@ void caf_co_min(CFI_cdesc_t* a_desc, int result_image, int* stat, char* errmsg,
172259
} else {
173260
ev = gex_Coll_ReduceToAllNB(myteam, a_address, a_address, a_type, c_sizeof_a, num_elements, GEX_OP_MIN, NULL, NULL, 0);
174261
}
175-
gex_Event_Wait(ev);
262+
gex_Event_Wait(ev);
176263

177264
if (stat != NULL) *stat = 0;
178265
}
@@ -204,7 +291,7 @@ void caf_co_sum(CFI_cdesc_t* a_desc, int result_image, int* stat, char* errmsg,
204291
} else {
205292
ev = gex_Coll_ReduceToAllNB(myteam, a_address, a_address, a_type, c_sizeof_a, num_elements, GEX_OP_ADD, NULL, NULL, 0);
206293
}
207-
gex_Event_Wait(ev);
294+
gex_Event_Wait(ev);
208295

209296
if (stat != NULL) *stat = 0;
210297
}

src/caffeine/caffeine.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ enum {
1414
ERRMSG_TOO_SHORT
1515
};
1616

17+
typedef void(*final_func_ptr)(void*, size_t) ;
18+
1719
// Program launch and finalization
1820

1921
void caf_caffeinate(int argc, char *argv[]);
@@ -24,6 +26,10 @@ void caf_decaffeinate(int exit_code);
2426
int caf_this_image();
2527
int caf_num_images();
2628

29+
// Memory allocation
30+
31+
void* caf_allocate(size_t sz, int corank, CFI_cdesc_t* desc_co_lbounds, CFI_cdesc_t* desc_co_ubounds, final_func_ptr final_func, void** coarray_handle);
32+
2733
// Synchronization
2834

2935
void caf_sync_all();

src/caffeine/caffeine_h_m.f90

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
! Terms of use are as specified in LICENSE.txt
33
module caffeine_h_m
44
! Fortran module shadowing the caffeine.h header file
5-
use iso_c_binding, only : c_int, c_ptr, c_size_t, c_funptr, c_bool
5+
use iso_c_binding, only : c_int, c_ptr, c_size_t, c_funptr, c_bool, c_size_t, c_intmax_t
66
implicit none
77

88
private
99
public :: caf_caffeinate, caf_decaffeinate
1010
public :: caf_num_images, caf_this_image
11+
public :: caf_allocate
1112
public :: caf_sync_all
1213
public :: caf_co_broadcast, caf_co_sum, caf_co_min, caf_co_max, caf_co_reduce
1314
public :: caf_same_cfi_type, caf_elem_len, caf_numeric_type, caf_is_f_string
@@ -47,6 +48,18 @@ pure function caf_num_images() bind(C)
4748
integer(c_int) caf_num_images
4849
end function
4950

51+
! _________________ Memory allocation ____________________
52+
53+
function caf_allocate(sz, corank, lcobounds, ucobounds, final_func, coarray_handle) result(ptr) bind(c)
54+
import c_int, c_size_t, c_intmax_t, c_funptr, c_ptr
55+
implicit none
56+
integer(kind=c_size_t), intent(in), value :: sz
57+
integer(kind=c_int), intent(in), value :: corank
58+
integer(kind=c_intmax_t), dimension(:), intent(in) :: lcobounds, ucobounds
59+
type(c_funptr), intent(in), value :: final_func
60+
type(c_ptr), intent(out) :: coarray_handle
61+
type(c_ptr) :: ptr
62+
end function
5063
! __________________ Synchronization _____________________
5164

5265
subroutine caf_sync_all() bind(C)

0 commit comments

Comments
 (0)