Skip to content

Commit f9a5a52

Browse files
committed
Basic support for memory allocation on GPU using CUDA unified memory. Partially addressing #284. IOR support completed.
1 parent 310fd37 commit f9a5a52

8 files changed

+103
-54
lines changed

configure.ac

+20
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,26 @@ AS_IF([test "$ac_cv_header_gpfs_h" = "yes" -o "$ac_cv_header_gpfs_fcntl_h" = "ye
7373
])
7474
])
7575

76+
# Check for CUDA
77+
AC_ARG_WITH([cuda],
78+
[AS_HELP_STRING([--with-cuda],
79+
[support configurable CUDA @<:@default=check@:>@])],
80+
[], [with_cuda=check])
81+
82+
AS_IF([test "x$with_cuda" != xno], [
83+
AC_CHECK_HEADERS([cuda_runtime.h], [AC_DEFINE([HAVE_CUDA], [], [CUDA GPU API found])], [
84+
if test "x$with_cuda" != xcheck; then
85+
AC_MSG_FAILURE([--with-cuda was given, <cuda_runtime.h> not found])
86+
fi
87+
])
88+
AS_IF([test "$ac_cv_header_cuda_runtime_h" = "yes"], [
89+
AC_SEARCH_LIBS([cudaMalloc], [cudart], [],
90+
[AC_MSG_ERROR([Library containing cudaMalloc symbol not found])])
91+
])
92+
])
93+
AM_CONDITIONAL([USE_CUDA], [test x$with_cuda = xyes])
94+
95+
7696
# Check for system capabilities
7797
AC_SYS_LARGEFILE
7898

src/Makefile.am

+4
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ extraLDFLAGS += -L/opt/hadoop-2.2.0/lib/native
4141
extraLDADD += -lhdfs
4242
endif
4343

44+
if USE_CUDA
45+
extraLDADD += -lcudart
46+
endif
47+
4448
if USE_HDF5_AIORI
4549
extraSOURCES += aiori-HDF5.c
4650
extraLDADD += -lhdf5 -lz

src/ior.c

+4-42
Original file line numberDiff line numberDiff line change
@@ -472,44 +472,6 @@ static int CountErrors(IOR_param_t * test, int access, int errors)
472472
return (allErrors);
473473
}
474474

475-
/*
476-
* Allocate a page-aligned (required by O_DIRECT) buffer.
477-
*/
478-
static void *aligned_buffer_alloc(size_t size)
479-
{
480-
size_t pageMask;
481-
char *buf, *tmp;
482-
char *aligned;
483-
484-
#ifdef HAVE_SYSCONF
485-
long pageSize = sysconf(_SC_PAGESIZE);
486-
#else
487-
size_t pageSize = getpagesize();
488-
#endif
489-
490-
pageMask = pageSize - 1;
491-
buf = malloc(size + pageSize + sizeof(void *));
492-
if (buf == NULL)
493-
ERR("out of memory");
494-
/* find the alinged buffer */
495-
tmp = buf + sizeof(char *);
496-
aligned = tmp + pageSize - ((size_t) tmp & pageMask);
497-
/* write a pointer to the original malloc()ed buffer into the bytes
498-
preceding "aligned", so that the aligned buffer can later be free()ed */
499-
tmp = aligned - sizeof(void *);
500-
*(void **)tmp = buf;
501-
502-
return (void *)aligned;
503-
}
504-
505-
/*
506-
* Free a buffer allocated by aligned_buffer_alloc().
507-
*/
508-
static void aligned_buffer_free(void *buf)
509-
{
510-
free(*(void **)((char *)buf - sizeof(char *)));
511-
}
512-
513475
void AllocResults(IOR_test_t *test)
514476
{
515477
int reps;
@@ -1018,7 +980,7 @@ static void InitTests(IOR_test_t *tests)
1018980
static void XferBuffersSetup(IOR_io_buffers* ioBuffers, IOR_param_t* test,
1019981
int pretendRank)
1020982
{
1021-
ioBuffers->buffer = aligned_buffer_alloc(test->transferSize);
983+
ioBuffers->buffer = aligned_buffer_alloc(test->transferSize, test->gpuMemoryFlags);
1022984
}
1023985

1024986
/*
@@ -1027,7 +989,7 @@ static void XferBuffersSetup(IOR_io_buffers* ioBuffers, IOR_param_t* test,
1027989
static void XferBuffersFree(IOR_io_buffers* ioBuffers, IOR_param_t* test)
1028990

1029991
{
1030-
aligned_buffer_free(ioBuffers->buffer);
992+
aligned_buffer_free(ioBuffers->buffer, test->gpuMemoryFlags);
1031993
}
1032994

1033995

@@ -1829,7 +1791,7 @@ static IOR_offset_t WriteOrRead(IOR_param_t *test, IOR_results_t *results,
18291791

18301792
void * randomPrefillBuffer = NULL;
18311793
if(test->randomPrefillBlocksize && (access == WRITE || access == WRITECHECK)){
1832-
randomPrefillBuffer = aligned_buffer_alloc(test->randomPrefillBlocksize);
1794+
randomPrefillBuffer = aligned_buffer_alloc(test->randomPrefillBlocksize, test->gpuMemoryFlags);
18331795
// store invalid data into the buffer
18341796
memset(randomPrefillBuffer, -1, test->randomPrefillBlocksize);
18351797
}
@@ -1951,7 +1913,7 @@ static IOR_offset_t WriteOrRead(IOR_param_t *test, IOR_results_t *results,
19511913
backend->fsync(fd, test->backend_options); /*fsync after all accesses */
19521914
}
19531915
if(randomPrefillBuffer){
1954-
aligned_buffer_free(randomPrefillBuffer);
1916+
aligned_buffer_free(randomPrefillBuffer, test->gpuMemoryFlags);
19551917
}
19561918

19571919
return (dataMoved);

src/ior.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ typedef struct
101101
MPI_Comm testComm; /* Current MPI communicator */
102102
MPI_Comm mpi_comm_world; /* The global MPI communicator */
103103
int dryRun; /* do not perform any I/Os just run evtl. inputs print dummy output */
104-
int dualMount; /* dual mount points */
104+
int dualMount; /* dual mount points */
105+
int gpuMemoryFlags; /* use the GPU to store the data */
105106
int numTasks; /* number of tasks for test */
106107
int numNodes; /* number of nodes for test */
107108
int numTasksOnNode0; /* number of tasks on node 0 (usually all the same, but don't have to be, use with caution) */

src/mdtest.c

+4-10
Original file line numberDiff line numberDiff line change
@@ -666,10 +666,7 @@ void mdtest_read(int random, int dirs, const long dir_iter, char *path) {
666666

667667
/* allocate read buffer */
668668
if (o.read_bytes > 0) {
669-
int alloc_res = posix_memalign((void**)&read_buffer, sysconf(_SC_PAGESIZE), o.read_bytes);
670-
if (alloc_res) {
671-
FAIL("out of memory");
672-
}
669+
read_buffer = aligned_buffer_alloc(o.read_bytes, 0);
673670
memset(read_buffer, -1, o.read_bytes);
674671
}
675672

@@ -764,7 +761,7 @@ void mdtest_read(int random, int dirs, const long dir_iter, char *path) {
764761
o.backend->close (aiori_fh, o.backend_options);
765762
}
766763
if(o.read_bytes){
767-
free(read_buffer);
764+
aligned_buffer_free(read_buffer, 0);
768765
}
769766
}
770767

@@ -2301,10 +2298,7 @@ mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE *
23012298

23022299
/* allocate and initialize write buffer with # */
23032300
if (o.write_bytes > 0) {
2304-
int alloc_res = posix_memalign((void**)& o.write_buffer, sysconf(_SC_PAGESIZE), o.write_bytes);
2305-
if (alloc_res) {
2306-
FAIL("out of memory");
2307-
}
2301+
o.write_buffer = aligned_buffer_alloc(o.write_bytes, 0);
23082302
generate_memory_pattern(o.write_buffer, o.write_bytes);
23092303
}
23102304

@@ -2445,7 +2439,7 @@ mdtest_results_t * mdtest_run(int argc, char **argv, MPI_Comm world_com, FILE *
24452439
}
24462440

24472441
if (o.write_bytes > 0) {
2448-
free(o.write_buffer);
2442+
aligned_buffer_free(o.write_buffer, 0);
24492443
}
24502444

24512445
return o.summary_table;

src/parse_options.c

+3
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ void DecodeDirective(char *line, IOR_param_t *params, options_all_t * module_opt
123123
params->testFileName = strdup(value);
124124
} else if (strcasecmp(option, "dualmount") == 0){
125125
params->dualMount = atoi(value);
126+
} else if (strcasecmp(option, "allocateBufferOnGPU") == 0) {
127+
params->gpuMemoryFlags = atoi(value);
126128
} else if (strcasecmp(option, "deadlineforstonewalling") == 0) {
127129
params->deadlineForStonewalling = atoi(value);
128130
} else if (strcasecmp(option, "stoneWallingWearOut") == 0) {
@@ -398,6 +400,7 @@ option_help * createGlobalOptions(IOR_param_t * params){
398400
{.help=" -O stoneWallingWearOut=1 -- once the stonewalling timeout is over, all process finish to access the amount of data", .arg = OPTION_OPTIONAL_ARGUMENT},
399401
{.help=" -O stoneWallingWearOutIterations=N -- stop after processing this number of iterations, needed for reading data back written with stoneWallingWearOut", .arg = OPTION_OPTIONAL_ARGUMENT},
400402
{.help=" -O stoneWallingStatusFile=FILE -- this file keeps the number of iterations from stonewalling during write and allows to use them for read", .arg = OPTION_OPTIONAL_ARGUMENT},
403+
{.help=" -O allocateBufferOnGPU=1 -- allocate I/O buffers on the GPU", .arg = OPTION_OPTIONAL_ARGUMENT},
401404
{'e', NULL, "fsync -- perform a fsync() operation at the end of each read/write phase", OPTION_FLAG, 'd', & params->fsync},
402405
{'E', NULL, "useExistingTestFile -- do not remove test file before write access", OPTION_FLAG, 'd', & params->useExistingTestFile},
403406
{'f', NULL, "scriptFile -- test script name", OPTION_OPTIONAL_ARGUMENT, 's', & params->testscripts},

src/utilities.c

+64
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@
3737
#include <sys/types.h>
3838
#include <time.h>
3939

40+
#ifdef HAVE_CUDA
41+
#include <cuda_runtime.h>
42+
#endif
43+
4044
#ifndef _WIN32
4145
# include <regex.h>
4246
# ifdef __sun /* SunOS does not support statfs(), instead uses statvfs() */
@@ -864,3 +868,63 @@ unsigned long GetProcessorAndCore(int *chip, int *core){
864868
return 1;
865869
}
866870
#endif
871+
872+
873+
874+
/*
875+
* Allocate a page-aligned (required by O_DIRECT) buffer.
876+
*/
877+
void *aligned_buffer_alloc(size_t size, int gpu)
878+
{
879+
size_t pageMask;
880+
char *buf, *tmp;
881+
char *aligned;
882+
883+
if(gpu){
884+
#ifdef HAVE_CUDA
885+
// use unified memory here to allow drop-in-replacement
886+
if (cudaMallocManaged((void**) & buf, size, cudaMemAttachGlobal) != cudaSuccess){
887+
ERR("Cannot allocate buffer on GPU");
888+
}
889+
return buf;
890+
#else
891+
ERR("No CUDA supported, cannot allocate on the GPU");
892+
#endif
893+
}
894+
895+
#ifdef HAVE_SYSCONF
896+
long pageSize = sysconf(_SC_PAGESIZE);
897+
#else
898+
size_t pageSize = getpagesize();
899+
#endif
900+
901+
pageMask = pageSize - 1;
902+
buf = safeMalloc(size + pageSize + sizeof(void *));
903+
/* find the alinged buffer */
904+
tmp = buf + sizeof(char *);
905+
aligned = tmp + pageSize - ((size_t) tmp & pageMask);
906+
/* write a pointer to the original malloc()ed buffer into the bytes
907+
preceding "aligned", so that the aligned buffer can later be free()ed */
908+
tmp = aligned - sizeof(void *);
909+
*(void **)tmp = buf;
910+
911+
return (void *)aligned;
912+
}
913+
914+
/*
915+
* Free a buffer allocated by aligned_buffer_alloc().
916+
*/
917+
void aligned_buffer_free(void *buf, int gpu)
918+
{
919+
if(gpu){
920+
#ifdef HAVE_CUDA
921+
if (cudaFree(buf) != cudaSuccess){
922+
WARN("Cannot free buffer on GPU");
923+
}
924+
return;
925+
#else
926+
ERR("No CUDA supported, cannot free on the GPU");
927+
#endif
928+
}
929+
free(*(void **)((char *)buf - sizeof(char *)));
930+
}

src/utilities.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -58,5 +58,6 @@ void init_clock(MPI_Comm com);
5858
double GetTimeStamp(void);
5959
char * PrintTimestamp(); // TODO remove this function
6060
unsigned long GetProcessorAndCore(int *chip, int *core);
61-
61+
void *aligned_buffer_alloc(size_t size, int gpu);
62+
void aligned_buffer_free(void *buf, int gpu);
6263
#endif /* !_UTILITIES_H */

0 commit comments

Comments
 (0)