diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a2c444..4003d70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,7 +60,8 @@ target_link_libraries(ex9 m MPI::MPI_C paraconf::paraconf PDI::pdi) add_executable(ex10 ex10.c) target_link_libraries(ex10 m MPI::MPI_C paraconf::paraconf PDI::pdi) -add_executable(ex12 ex12.c) -target_link_libraries(ex12 m MPI::MPI_C paraconf::paraconf PDI::pdi) +add_executable(ex11 ex11.c) +set_target_properties(ex11 PROPERTIES ENABLE_EXPORTS TRUE) +target_link_libraries(ex11 m MPI::MPI_C paraconf::paraconf PDI::pdi) -add_subdirectory(ex11/) +add_subdirectory(ex_deisa/) diff --git a/README.md b/README.md index f905580..49d3501 100644 --- a/README.md +++ b/README.md @@ -612,6 +612,74 @@ To see your `h5` file in readable file format, you can check the section [Comparison with the `h5dump` command](#h5comparison). +## Call a user C function + +### Ex11. user_code plugin + +In this exercise, you will learn how to call a user C function in %PDI with the +\ref user_code_plugin "user_code plugin". +Moreover, to reduce the standard output log, +we run sequentially and we reduce the number of iterations. + +\attention +You need to read the section \ref important_notes_node "Important notes" +before using \ref user_code_plugin "user_code plugin". +To compile the program `ex11` with Wl,`--export-dynamic` or `-rdynamic`, +we have added the following line: +```cmake +set_target_properties(ex11 PROPERTIES ENABLE_EXPORTS TRUE) +``` +in the CMakeList.txt provided. + +The objective is to write the integral of `main_field` on the file +`integral.dat`. +This integral is computed in the C function `compute_integral` +defined in `ex11.c`. + +* Examine the C file, the YAML file and compile the code. + +\remark In the `compute_integral` function, the %PDI function `::PDI_access` +and `::PDI_release` are called (see \ref annotation "Code annotation"). +For example, +```c +int *iter; +PDI_access("ii", (void **)&iter, PDI_IN); +PDI_release("ii"); +``` +`::PDI_access` sets our pointer (`iter`) to the data location of `ii`. +We need to pass `PDI_IN` because data flows from PDI to our application. +We also want to use `::PDI_release`, because `::PDI_reclaim` would end +the sharing status of this descriptor and we reclaim this data later in +the main function. + +The keyword `on_event` allows to call a C function inside `::PDI_event`. +You can call a user C function inside `::PDI_share` +using the keyword `on_data` in the \ref user_code_plugin "user_code plugin". + +In this exercise, we only modify `ex11.yml`. + +* Open the file `integral.dat` at event “initialization” for recording +the integral of the `main_field` in calling `open_file` function. + +* Close the file `integral.dat` at event “finalization” in calling `close_file` +function. + +* Compute the integral of `main_field` and write this to the file `integral.dat` +(using `compute_integral` function) when `main_field` is shared to %PDI. + +You should be able to match the expected output described +in `integral_solution.dat`. +You can easily check if the files are the same by running: +```bash + diff integral_solution.dat integral.dat +``` + +* Check that the call of C functions defined by `on_event` and `on_data` are +indeed done in the expected order in the log. + +\remark The keywords `on_event` and `on_data` are also used in other plugins +to execute instructions in `::PDI_event` and `::PDI_share` respectively. + ## What next ? In this tutorial, you used the C API of %PDI and from YAML, you used the diff --git a/ex11.c b/ex11.c new file mode 100644 index 0000000..757f1f3 --- /dev/null +++ b/ex11.c @@ -0,0 +1,322 @@ +/******************************************************************************* + * Copyright (C) 2015-2019 Commissariat a l'energie atomique et aux energies alternatives (CEA) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ******************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +// load the PDI header +#include + +// size of the local data as [HEIGHT, WIDTH] including the number of ghost layers +// for communications or boundary conditions +int dsize[2]; + +// 2D size of the process grid as [HEIGHT, WIDTH] +int psize[2]; + +// 2D rank of the local process in the process grid as [YY, XX] +int pcoord[2]; + +// the alpha coefficient used in the computation +double alpha; + +double L=1.0; +// definition of the source +// the source corresponds to a disk of an uniform value +// source1: center=(0.4,0.4), radius=0.2 and value=100 +double source1[4]={0.4, 0.4, 0.2, 100}; +// source2: center=(0.8,0.7), radius=0.1 and value=200 +double source2[4]={0.7, 0.8, 0.1, 200}; +// the order of the coordinates of the center (XX,YY) is inverted in the vector + +FILE *pFile2=NULL; + +void open_file(void) +{ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + if(rank>0) return; + printf("\n Call open_file.\n"); + pFile2 = fopen("integral.dat", "w"); +} + +void close_file(void) +{ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + if(rank>0) return; + printf("\n Call close_file.\n"); + + if(pFile2 == NULL){ + fprintf(stderr,"\n error: The file integral.dat is not open. You must call open_file before.\n \n"); + exit(1); + } + fclose(pFile2); +} + +void compute_integral(void) +{ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + if(rank==0) printf("\n Call compute_integral.\n"); + + int *iter; + PDI_access("ii", (void **)&iter, PDI_IN); + PDI_release("ii"); + + int *local_size; + PDI_access("dsize", (void **)&local_size, PDI_IN); + PDI_release("dsize"); + + int *para_size; + PDI_access("psize", (void **)¶_size, PDI_IN); + PDI_release("psize"); + + double dy = L / ((local_size[0]-2) *para_size[0]); + double dx = L / ((local_size[1]-2) *para_size[1]); + + double *field; + double integral_of_main_field=0.0; + PDI_access("input", (void **)&field, PDI_IN); + for (int i=1; i0) return; + + if(pFile2 == NULL){ + fprintf(stderr,"\n error: The file integral.dat is not open. You must call open_file before.\n \n"); + exit(1); + } + fprintf(pFile2, "%d\t%.6f\n", *iter, integral_of_main_field); +} + + +/** Initialize all the data to 0, with the exception of a given cell + * whose center (cpos_x,cpos_y) is inside of the disks + * defined by source1 or source2 + * \param[out] dat the local data to initialize + */ +void init(double dat[dsize[0]][dsize[1]]) +{ + for (int yy=0; yy0 & $ii<4' + memory_selection: + size: ['$dsize[0]-2', '$dsize[1]-2'] + start: [1, 1] + dataset_selection: + size: [1, '$dsize[0]-2', '$dsize[1]-2'] + start: ['$ii-1', '$pcoord[0]*($dsize[0]-2)', '$pcoord[1]*($dsize[1]-2)'] + + user_code: + on_event: + #*** open file on initialization + #... + #*** close file on finalization + #... + on_data: + main_field: + #*** compute the total mass and write to file + #... \ No newline at end of file diff --git a/ex11/CMakeLists.txt b/ex_deisa/CMakeLists.txt similarity index 100% rename from ex11/CMakeLists.txt rename to ex_deisa/CMakeLists.txt diff --git a/ex11/README.md b/ex_deisa/README.md similarity index 100% rename from ex11/README.md rename to ex_deisa/README.md diff --git a/ex11/client.py b/ex_deisa/client.py similarity index 100% rename from ex11/client.py rename to ex_deisa/client.py diff --git a/ex11/dask_interface.py b/ex_deisa/dask_interface.py similarity index 100% rename from ex11/dask_interface.py rename to ex_deisa/dask_interface.py diff --git a/ex11/launch.sh b/ex_deisa/launch.sh similarity index 100% rename from ex11/launch.sh rename to ex_deisa/launch.sh diff --git a/ex11/simulation.c b/ex_deisa/simulation.c similarity index 100% rename from ex11/simulation.c rename to ex_deisa/simulation.c diff --git a/ex11/simulation.yml b/ex_deisa/simulation.yml similarity index 100% rename from ex11/simulation.yml rename to ex_deisa/simulation.yml diff --git a/integral_solution.dat b/integral_solution.dat new file mode 100644 index 0000000..761d5a6 --- /dev/null +++ b/integral_solution.dat @@ -0,0 +1,5 @@ +0 18.888889 +1 18.888889 +2 18.888889 +3 18.888889 +4 18.888889 diff --git a/solutions/ex11.yml b/solutions/ex11.yml new file mode 100644 index 0000000..b04127c --- /dev/null +++ b/solutions/ex11.yml @@ -0,0 +1,46 @@ +# the alpha parameter +alpha: 0.125 +# global data-size (excluding the number of ghost layers for boundary conditions) +global_size: { height: 60, width: 12 } +# degree of parallelism (number of blocks in each dimension) +parallelism: { height: 1, width: 1 } +# PDI configuration +pdi: + metadata: # small values for which PDI keeps a copy + ii: int + dsize: { type: array, subtype: int, size: 2 } + psize: { type: array, subtype: int, size: 2 } + pcoord: { type: array, subtype: int, size: 2 } + data: # values for which PDI does not keep a copy + main_field: { type: array, subtype: double, size: [ '$dsize[0]', '$dsize[1]' ] } + + plugins: + mpi: + trace: + decl_hdf5: + file: ex11.h5 + communicator: $MPI_COMM_WORLD + datasets: + main_field: { type: array, subtype: double, size: [ 3, '$psize[0]*($dsize[0]-2)', '$psize[1]*($dsize[1]-2)' ] } + write: + main_field: + when: '$ii>0 & $ii<4' + memory_selection: + size: ['$dsize[0]-2', '$dsize[1]-2'] + start: [1, 1] + dataset_selection: + size: [1, '$dsize[0]-2', '$dsize[1]-2'] + start: ['$ii-1', '$pcoord[0]*($dsize[0]-2)', '$pcoord[1]*($dsize[1]-2)'] + + user_code: + on_event: + #*** open file on initialization + initialization: + open_file: {} # no input parameters in this function, therefore we have a curly empty bracket + #*** close file on finalization + finalization: + close_file: {} # no input parameters in this function, therefore we have a curly empty bracket + on_data: + main_field: + #*** compute the total mass and write to file + compute_integral: { input: $main_field } \ No newline at end of file