NewMadeleine

Documentation

« back to PM2 home.
nm_data.h
Go to the documentation of this file.
1/*
2 * NewMadeleine
3 * Copyright (C) 2015-2026 (see AUTHORS file)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at
8 * your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULA R PURPOSE. See the GNU
13 * General Public License for more details.
14 */
15
21#ifndef NM_DATA_H
22#define NM_DATA_H
23
24#include <assert.h>
25#include <string.h>
26
27#include <Padico/Puk.h>
28
29#include <nm_config.h>
30#include <nm_public.h>
31
32#ifdef NMAD_CUDA
33#include <cuda.h>
34#include <cuda_runtime.h>
35#include <cuda_runtime_api.h>
36#endif /* NMAD_CUDA */
37
38#ifdef NMAD_HIP
39#include <hip/hip_runtime.h>
40#include <hip/hip_runtime_api.h>
41#endif /* NMAD_HIP */
42
79/* ** Data descriptor ************************************** */
80
82#define _NM_DATA_CONTENT_SIZE 64
83
84/* forward declaration so that operators declared inside struct nm_data_s may
85 * take struct nm_data_s* as parameters
86 */
87struct nm_data_s;
88
90typedef void (*nm_data_apply_t)(void*ptr, nm_len_t len, void*_context);
91
94{
98#ifdef NMAD_CUDA
99 int is_cuda;
100#endif /* NMAD_CUDA */
101#ifdef NMAD_HIP
102 int is_hip;
103#endif /* NMAD_HIP */
104};
105
118
120{
121 /* empty */
122};
123
125{
126 void*__restrict__ p_dest_ptr;
127 const struct nm_data_s*p_data;
128};
129
131{
132 const void*__restrict__ p_src_ptr;
133 const struct nm_data_s*p_data;
134};
135
141
147
155
160
175
181typedef void (*nm_data_traversal_t)(const void*_data_content, struct nm_data_op_s*p_op);
182
185
193
197
205
207static inline void nm_data_propertie_gpu_preinit(struct nm_data_properties_s*p_props);
208
211static inline void nm_data_propertie_gpu_postinit(const struct nm_data_properties_s*p_props);
212
214EXTERN_C void nm_data_properties_gpu_fill(struct nm_data_properties_s*p_props, const void*p_ptr);
215
223#define NM_DATA_TYPE(ENAME, CONTENT_TYPE, OPS) \
224 __attribute__((unused)) \
225 static inline void nm_data_##ENAME##_set(struct nm_data_s*p_data, CONTENT_TYPE value) \
226 { \
227 p_data->ops = *(OPS); \
228 assert(p_data->ops.p_traversal != NULL); \
229 if(p_data->ops.p_properties_compute == NULL) \
230 { \
231 p_data->ops.p_properties_compute = nm_data_default_properties_compute; \
232 } \
233 assert(sizeof(CONTENT_TYPE) <= _NM_DATA_CONTENT_SIZE); \
234 CONTENT_TYPE*p_content = (CONTENT_TYPE*)&p_data->_content[0]; \
235 *p_content = value; \
236 p_data->props.blocks = -1; \
237 nm_data_propertie_gpu_preinit(&p_data->props); \
238 (*p_data->ops.p_properties_compute)(p_data); \
239 nm_data_propertie_gpu_postinit(&p_data->props); \
240 } \
241 __attribute__((unused)) \
242 static inline CONTENT_TYPE*nm_data_##ENAME##_content(const struct nm_data_s*p_data) \
243 { \
244 return (CONTENT_TYPE*)p_data->_content; \
245 }
246
247/* ** datav data (dynamic vector of nm_data)
248 */
249
251#define NM_DATAV_INIT_SIZE 4
252
262
264static inline void nm_datav_init(struct nm_datav_s*p_datav);
265
267static inline void nm_datav_destroy(struct nm_datav_s*p_datav);
268
270static inline void nm_datav_add_chunk_data(struct nm_datav_s*p_datav, const struct nm_data_s*p_data);
271
273static inline void nm_datav_add_chunk(struct nm_datav_s*p_datav, const void*ptr, nm_len_t len);
274
277
279static inline nm_len_t nm_datav_size(struct nm_datav_s*p_datav);
280
283static inline void nm_datav_uncommit(struct nm_datav_s*p_datav);
284
287/* ** Built-in data ops ************************************ */
288
289static inline void nm_data_op_apply(void*__restrict__ p_ptr, nm_len_t len, struct nm_data_op_s*__restrict__ p_op);
290static inline void nm_data_op_apply_nop(void*__restrict__ p_ptr, nm_len_t len, struct nm_data_op_context_nop_s*__restrict__ p_nop);
291static inline void nm_data_op_apply_copy_from(void*__restrict__ p_ptr, nm_len_t len, struct nm_data_op_context_copy_from_s*__restrict__ p_copy_from);
292static inline void nm_data_op_apply_copy_to(void*__restrict__ p_ptr, nm_len_t len, struct nm_data_op_context_copy_to_s*__restrict__ p_copy_to);
293static inline void nm_data_op_apply_dynamic(void*__restrict__ p_ptr, nm_len_t len, struct nm_data_op_context_dynamic_s*__restrict__ p_dynamic);
294static inline void nm_data_op_apply_getprops(void*__restrict__ p_ptr, nm_len_t len, struct nm_data_op_context_getprops_s*__restrict__ p_getprops);
295static inline void nm_data_op_apply_chunk(void*__restrict__ p_ptr, nm_len_t len, struct nm_data_op_context_chunk_s*__restrict__ p_chunk);
296static inline void nm_data_op_apply_slicer_coroutine(void*__restrict__ p_ptr, nm_len_t len, struct nm_data_op_context_slicer_coroutine_s*__restrict__ p_slicer_coroutine);
297
305#define NM_DATA_OP_APPLY_LOOP_REF(I, COUNT, PTR, LEN, P_OP) \
306 { \
307 nm_len_t I; \
308 for(I = 0; I < (COUNT); I++) \
309 { \
310 nm_data_op_apply((PTR), (LEN), (P_OP)); \
311 } \
312 }
313
317#define NM_DATA_OP_APPLY_KIND_LEN(I, OP_KIND, START, COUNT, PTR, LEN, P_OP) \
318 { \
319 nm_len_t I; \
320 for(I = START; I < (START) + (COUNT); I++) \
321 { \
322 nm_data_op_apply_##OP_KIND((PTR), (LEN), &(P_OP)->context.OP_KIND); \
323 } \
324 }
325
330#define NM_DATA_OP_APPLY_KIND_VECT(I, OP_KIND, START, COUNT, PTR, LEN, P_OP) \
331 { \
332 if((LEN) == 1) \
333 { \
334 NM_DATA_OP_APPLY_KIND_LEN(I, OP_KIND, START, COUNT, PTR, 1, P_OP); \
335 } \
336 else if((LEN) == 2) \
337 { \
338 NM_DATA_OP_APPLY_KIND_LEN(I, OP_KIND, START, COUNT, PTR, 2, P_OP); \
339 } \
340 else if((LEN) == 4) \
341 { \
342 NM_DATA_OP_APPLY_KIND_LEN(I, OP_KIND, START, COUNT, PTR, 4, P_OP); \
343 } \
344 else if((LEN) == 8) \
345 { \
346 NM_DATA_OP_APPLY_KIND_LEN(I, OP_KIND, START, COUNT, PTR, 8, P_OP); \
347 } \
348 else if((LEN) == 16) \
349 { \
350 NM_DATA_OP_APPLY_KIND_LEN(I, OP_KIND, START, COUNT, PTR, 16, P_OP); \
351 } \
352 else \
353 { \
354 NM_DATA_OP_APPLY_KIND_LEN(I, OP_KIND, START, COUNT, PTR, (LEN), P_OP); \
355 } \
356 }
357
361#define NM_DATA_OP_APPLY_LOOP_OPT(I, COUNT, PTR, LEN, P_OP) \
362 { \
363 switch((P_OP)->kind) \
364 { \
365 case NM_DATA_OP_NOP: \
366 NM_DATA_OP_APPLY_KIND_LEN(I, nop, 0, (COUNT), (PTR), (LEN), (P_OP)); \
367 break; \
368 case NM_DATA_OP_COPY_FROM: \
369 NM_DATA_OP_APPLY_KIND_VECT(I, copy_from, 0, (COUNT), (PTR), (LEN), (P_OP)); \
370 break; \
371 case NM_DATA_OP_COPY_TO: \
372 NM_DATA_OP_APPLY_KIND_VECT(I, copy_to, 0, (COUNT), (PTR), (LEN), (P_OP)); \
373 break; \
374 case NM_DATA_OP_GETPROPS: \
375 NM_DATA_OP_APPLY_KIND_LEN(I, getprops, 0, (COUNT), (PTR), (LEN), (P_OP)); \
376 break; \
377 case NM_DATA_OP_DYNAMIC: \
378 NM_DATA_OP_APPLY_KIND_LEN(I, dynamic, 0, (COUNT), (PTR), (LEN), (P_OP)); \
379 break; \
380 case NM_DATA_OP_CHUNK: \
381 { \
382 struct nm_data_op_context_chunk_s*__restrict__ p_chunk = &(P_OP)->context.chunk; \
383 nm_len_t blocks_done = 0; \
384 if(p_chunk->done < p_chunk->chunk_offset) \
385 { \
386 nm_len_t skip_blocks = (p_chunk->chunk_offset - p_chunk->done) / (LEN); \
387 if(skip_blocks > (COUNT)) skip_blocks = (COUNT); \
388 p_chunk->done += skip_blocks * (LEN); \
389 blocks_done += skip_blocks; \
390 if( (p_chunk->done < p_chunk->chunk_offset) && \
391 (blocks_done < (COUNT)) ) \
392 { \
393 assert(p_chunk->chunk_offset - p_chunk->done < (LEN)); \
394 const nm_len_t I = blocks_done; \
395 nm_data_op_apply_chunk((PTR), (LEN), p_chunk); \
396 blocks_done++; \
397 p_chunk->done += (LEN); \
398 } \
399 } \
400 const nm_len_t chunk_end = p_chunk->chunk_offset + p_chunk->chunk_len; \
401 if( (p_chunk->done < chunk_end) && \
402 (blocks_done < (COUNT)) ) \
403 { \
404 nm_len_t op_blocks = (chunk_end - p_chunk->done) / (LEN); \
405 if(blocks_done + op_blocks > (COUNT)) \
406 op_blocks = (COUNT) - blocks_done; \
407 switch(p_chunk->p_op->kind) \
408 { \
409 case NM_DATA_OP_NOP: \
410 break; \
411 case NM_DATA_OP_COPY_FROM: \
412 NM_DATA_OP_APPLY_KIND_VECT(I, copy_from, blocks_done, op_blocks, (PTR), (LEN), p_chunk->p_op); \
413 break; \
414 case NM_DATA_OP_COPY_TO: \
415 NM_DATA_OP_APPLY_KIND_VECT(I, copy_to, blocks_done, op_blocks, (PTR), (LEN), p_chunk->p_op); \
416 break; \
417 case NM_DATA_OP_GETPROPS: \
418 NM_DATA_OP_APPLY_KIND_LEN(I, getprops, blocks_done, op_blocks, (PTR), (LEN), p_chunk->p_op); \
419 break; \
420 default: \
421 { \
422 nm_len_t I; \
423 for(I = blocks_done; I < blocks_done + op_blocks; I++) \
424 { \
425 nm_data_op_apply((PTR), (LEN), p_chunk->p_op); \
426 } \
427 } \
428 break; \
429 } \
430 blocks_done += op_blocks; \
431 p_chunk->done += op_blocks * (LEN); \
432 if((p_chunk->done < chunk_end) && (blocks_done < (COUNT))) \
433 { \
434 assert(chunk_end - p_chunk->done < (LEN)); \
435 const nm_len_t I = blocks_done; \
436 nm_data_op_apply_chunk((PTR), (LEN), p_chunk); \
437 blocks_done++; \
438 p_chunk->done += (LEN); \
439 } \
440 } \
441 assert(blocks_done <= (COUNT)); \
442 } \
443 break; \
444 case NM_DATA_OP_SLICER_COROUTINE: \
445 { \
446 struct nm_data_slicer_s*__restrict__ p_slicer = (P_OP)->context.slicer_coroutine.p_slicer; \
447 nm_len_t blocks_done = 0; \
448 while(blocks_done < (COUNT)) \
449 { \
450 const nm_len_t slice_len = p_slicer->coroutine.slice_len; \
451 nm_len_t slice_blocks = slice_len / (LEN); \
452 if(blocks_done + slice_blocks > (COUNT)) \
453 slice_blocks = (COUNT) - blocks_done; \
454 if(slice_blocks > 0) \
455 { \
456 switch(p_slicer->coroutine.op.kind) \
457 { \
458 case NM_DATA_OP_NOP: \
459 NM_DATA_OP_APPLY_KIND_LEN(I, nop, blocks_done, slice_blocks, (PTR), (LEN), &p_slicer->coroutine.op); \
460 break; \
461 case NM_DATA_OP_COPY_FROM: \
462 NM_DATA_OP_APPLY_KIND_VECT(I, copy_from, blocks_done, slice_blocks, (PTR), (LEN), &p_slicer->coroutine.op); \
463 break; \
464 case NM_DATA_OP_COPY_TO: \
465 NM_DATA_OP_APPLY_KIND_VECT(I, copy_to, blocks_done, slice_blocks, (PTR), (LEN), &p_slicer->coroutine.op); \
466 break; \
467 default: \
468 { \
469 nm_len_t I; \
470 for(I = blocks_done; I < blocks_done + slice_blocks; I++) \
471 { \
472 nm_data_op_apply((PTR), (LEN), &p_slicer->coroutine.op); \
473 } \
474 } \
475 break; \
476 } \
477 p_slicer->coroutine.slice_len = slice_len - slice_blocks * (LEN); \
478 blocks_done += slice_blocks; \
479 if(slice_len == slice_blocks * (LEN)) \
480 { \
481 nm_data_coroutine_yield_to_caller(&p_slicer->coroutine.coroutine); \
482 } \
483 else if(blocks_done < (COUNT)) \
484 { \
485 const nm_len_t I = blocks_done; \
486 nm_data_op_apply_slicer_coroutine((PTR), (LEN), &(P_OP)->context.slicer_coroutine); \
487 blocks_done++; \
488 } \
489 } \
490 else if(blocks_done < (COUNT)) \
491 { \
492 const nm_len_t I = blocks_done; \
493 nm_data_op_apply_slicer_coroutine((PTR), (LEN), &(P_OP)->context.slicer_coroutine); \
494 blocks_done++; \
495 } \
496 } \
497 assert(blocks_done <= (COUNT)); \
498 } \
499 break; \
500 default: \
501 { \
502 nm_len_t I; \
503 for(I = 0; I < (COUNT); I++) \
504 { \
505 nm_data_op_apply((PTR), (LEN), (P_OP)); \
506 } \
507 } \
508 break; \
509 } \
510 }
511
513#define NM_DATA_OP_APPLY_LOOP NM_DATA_OP_APPLY_LOOP_OPT
514
515
516/* ** Built-in data types ********************************** */
517
535{
536 int dummy;
537};
538extern const struct nm_data_ops_s nm_data_ops_null;
540static inline void nm_data_null_build(struct nm_data_s*p_data)
541{
542 struct nm_data_null_s n = { 0 };
543 nm_data_null_set(p_data, n);
544}
545static inline int nm_data_isnull(struct nm_data_s*p_data)
546{
547 return (p_data->ops.p_traversal == nm_data_ops_null.p_traversal);
548}
549
558extern const struct nm_data_ops_s nm_data_ops_contiguous;
560
561static inline void nm_data_contiguous_build(struct nm_data_s*p_data, void*ptr, nm_len_t len)
562{
563 struct nm_data_contiguous_s dc;
564 dc.ptr = ptr;
565 dc.len = len;
566 nm_data_contiguous_set(p_data, dc);
567}
568
573{
574 const struct iovec*v;
575 int n;
576};
577extern const struct nm_data_ops_s nm_data_ops_iov;
579
580static inline void nm_data_iov_build(struct nm_data_s*p_data, const struct iovec*v, int n)
581{
582 struct nm_data_iov_s di;
583 di.v = v;
584 di.n = n;
585 nm_data_iov_set(p_data, di);
586}
587
592{
594};
595extern const struct nm_data_ops_s nm_data_ops_datav;
597
599static inline void nm_data_datav_build(struct nm_data_s*p_datav_data, struct nm_datav_s*p_datav)
600{
601 p_datav->commited = 1;
602 struct nm_data_datav_s dv;
603 dv.p_datav = p_datav;
604 nm_data_datav_set(p_datav_data, dv);
605}
606
616extern const struct nm_data_ops_s nm_data_ops_excerpt;
618
621static inline void nm_data_excerpt_build(struct nm_data_s*p_data, struct nm_data_s*p_inner_data,
623{
624 struct nm_data_excerpt_s de;
626 de.chunk_len = chunk_len;
627 de.p_data = p_inner_data;
628 nm_data_excerpt_set(p_data, de);
629}
630
631
632/* ** Helper functions ************************************* */
633
644static inline void nm_data_traversal_op_apply(const struct nm_data_s*p_data, struct nm_data_op_s*p_op)
645{
646 assert(p_data->ops.p_traversal != NULL);
647 (*p_data->ops.p_traversal)((void*)p_data->_content, p_op);
648}
649
652static inline void nm_data_traversal_apply(const struct nm_data_s*p_data, nm_data_apply_t p_apply, void*_context)
653{
654 struct nm_data_op_s op;
656 op.context.dynamic.p_apply = p_apply;
657 op.context.dynamic.p_apply_context = _context;
659}
660
662 struct nm_data_op_s*p_op);
663
665 nm_data_apply_t p_apply, void*p_apply_context);
666
668static inline const struct nm_data_properties_s*nm_data_properties_get(const struct nm_data_s*p_data)
669{
670 return &p_data->props;
671}
672
674static inline nm_len_t nm_data_size(const struct nm_data_s*p_data)
675{
676 const struct nm_data_properties_s*p_props = nm_data_properties_get((struct nm_data_s*)p_data);
677 return p_props->size;
678}
679
682
685
688 struct nm_data_properties_s*p_props);
689
692
694uint32_t nm_data_checksum(const struct nm_data_s*p_data);
695
697void nm_data_copy_from(const struct nm_data_s*p_data, nm_len_t offset, nm_len_t len, void*destbuf);
698
700void nm_data_copy_to(const struct nm_data_s*p_data, nm_len_t offset, nm_len_t len, const void*srcbuf);
701
703void nm_data_copy(struct nm_data_s*p_dest, struct nm_data_s*p_from);
704
706void nm_data_dump(struct nm_data_s*p_data, const char*label);
707
710/* ** Data slicer ****************************************** */
711
731/* ** coroutine */
732
734
735typedef void (*nm_data_coroutine_worker_t)(struct nm_data_coroutine_s*p_coroutine, void*_user_data);
736
744
746{
748 union
749 {
750 struct nm_data_coroutine_ucontext_s*p_ucontext;
751 struct nm_data_coroutine_longjmp_s*p_longjmp;
755};
756
759
760/* ** slicer */
761
769
771typedef struct nm_data_slicer_s
772{
774 const struct nm_data_s*p_data;
776 union
777 {
778 struct
779 {
784 struct
785 {
788 };
790
792#define NM_DATA_SLICER_NULL ((struct nm_data_slicer_s){ .kind = NM_DATA_SLICER_NONE })
793
795static inline int nm_data_slicer_isnull(const nm_data_slicer_t*p_slicer)
796{
797 return (p_slicer->kind == NM_DATA_SLICER_NONE);
798}
799
801void nm_data_slicer_copy_from(nm_data_slicer_t*p_slicer, void*dest_ptr, nm_len_t slice_len);
802void nm_data_slicer_copy_to(nm_data_slicer_t*p_slicer, const void*src_ptr, nm_len_t slice_len);
805
809/* ********************************************************* */
810/* ** inline functions */
811
812
813/* ** datav */
814
815static inline void nm_datav_init(struct nm_datav_s*p_datav)
816{
817 p_datav->p_data = &p_datav->data[0];
818 p_datav->n_data = 0;
819 p_datav->allocated = 0;
820 p_datav->commited = 0;
821}
822
823static inline void nm_datav_destroy(struct nm_datav_s*p_datav)
824{
825 assert(p_datav->p_data != NULL);
826 if(p_datav->p_data != &p_datav->data[0])
827 {
828 padico_free(p_datav->p_data);
829 p_datav->p_data = NULL;
830 }
831 }
832
833static inline void nm_datav_add_chunk_data(struct nm_datav_s*p_datav, const struct nm_data_s*p_data)
834{
835 assert(!p_datav->commited); /* cannot modify datav once it is used as a nm_data */
836 if(p_datav->n_data == NM_DATAV_INIT_SIZE)
837 {
838 assert(p_datav->p_data == &p_datav->data[0]);
839 p_datav->allocated = NM_DATAV_INIT_SIZE * 2;
840 p_datav->p_data = (struct nm_data_s*)padico_malloc(p_datav->allocated * sizeof(struct nm_data_s));
841 memcpy(p_datav->p_data, &p_datav->data[0], p_datav->n_data * sizeof(struct nm_data_s));
842 }
843 else if((p_datav->n_data > NM_DATAV_INIT_SIZE) &&
844 (p_datav->n_data > p_datav->allocated - 1))
845 {
846 assert(p_datav->p_data != &p_datav->data[0]);
847 p_datav->allocated *= 2;
848 p_datav->p_data = (struct nm_data_s*)padico_realloc(p_datav->p_data, p_datav->allocated * sizeof(struct nm_data_s));
849 }
850 p_datav->p_data[p_datav->n_data] = *p_data;
851 p_datav->n_data++;
852}
853
854static inline void nm_datav_add_chunk(struct nm_datav_s*p_datav, const void*ptr, nm_len_t len)
855{
856 struct nm_data_s data;
857 nm_data_contiguous_build(&data, (void*)ptr, len);
858 nm_datav_add_chunk_data(p_datav, &data);
859}
860
862{
863 struct nm_data_s data;
865 nm_datav_add_chunk_data(p_datav, &data);
866}
867
868static inline nm_len_t nm_datav_size(struct nm_datav_s*p_datav)
869{
870 nm_len_t size = 0;
871 int i;
872 for(i = 0; i < p_datav->n_data; i++)
873 {
874 size += nm_data_size(&p_datav->p_data[i]);
875 }
876 return size;
877}
878
879static inline void nm_datav_uncommit(struct nm_datav_s*p_datav)
880{
881 assert(p_datav->commited);
882 p_datav->commited = 0;
883}
884
885/* ** GPU */
886
887static inline void nm_data_propertie_gpu_preinit(struct nm_data_properties_s*p_props __attribute__((unused)))
888{
889#ifdef NMAD_CUDA
890 p_props->is_cuda = -1;
891#endif /* NMAD_CUDA */
892#ifdef NMAD_HIP
893 p_props->is_hip = -1;
894#endif /* NMAD_HIP */
895}
896
897static inline void nm_data_propertie_gpu_postinit(const struct nm_data_properties_s*p_props __attribute__((unused)))
898{
899#ifdef NMAD_CUDA
900 if(p_props->is_cuda == -1)
901 {
902 NM_FATAL("incorrect data properties: is_cuda = %d (should be either 0 or 1)\n", p_props->is_cuda);
903 }
904#endif /* NMAD_CUDA */
905#ifdef NMAD_HIP
906 if(p_props->is_hip == -1)
907 {
908 NM_FATAL("incorrect data properties: is_hip = %d (should be either 0 or 1)\n", p_props->is_hip);
909 }
910#endif /* NMAD_HIP */
911}
912
913
918static inline void nm_data_memcpy_from(void*p_dest, const void*p_src, nm_len_t len, const struct nm_data_properties_s*p_props)
919{
920#if defined(NMAD_CUDA)
921 if(p_props->is_cuda)
922 {
923 cudaError_t rc = cudaMemcpy(p_dest /* host */, p_src /* gpu */, len, cudaMemcpyDeviceToHost);
924 if(rc != cudaSuccess)
925 {
926 NM_FATAL("CUDA cannot copy %ld bytes from GPU; error %s\n", len, cudaGetErrorString(rc));
927 }
928 return;
929 }
930#endif /* NMAD_CUDA */
931
932#if defined(NMAD_HIP)
933 if(p_props->is_hip)
934 {
935 hipError_t rc = hipMemcpy(p_dest /* host */, p_src /* gpu */, len, hipMemcpyDeviceToHost);
936 if(rc != hipSuccess)
937 {
938 NM_FATAL("HIP cannot copy %ld bytes from GPU; error %s\n", len, hipGetErrorString(rc));
939 }
940 return;
941 }
942#endif /* NMAD_HIP */
943
944 /* default case: host memory */
945 memcpy(p_dest, p_src, len);
946}
947
952static inline void nm_data_memcpy_to(void*p_dest, const void*p_src, nm_len_t len, const struct nm_data_properties_s*p_props)
953{
954#if defined(NMAD_CUDA)
955 if(p_props->is_cuda)
956 {
957 cudaError_t rc = cudaMemcpy(p_dest /* gpu */, p_src /* src */, len, cudaMemcpyHostToDevice);
958 if(rc != cudaSuccess)
959 {
960 NM_FATAL("CUDA cannot copy %ld bytes from GPU; error %s\n", len, cudaGetErrorString(rc));
961 }
962 return;
963 }
964#endif /* NMAD_CUDA */
965
966#if defined(NMAD_HIP)
967 if(p_props->is_hip)
968 {
969 hipError_t rc = hipMemcpy(p_dest /* gpu */, p_src /* host */, len, hipMemcpyHostToDevice);
970 if(rc != hipSuccess)
971 {
972 NM_FATAL("HIP cannot copy %ld bytes from GPU; error %s\n", len, hipGetErrorString(rc));
973 }
974 return;
975 }
976#endif /* NMAD_HIP */
977
978 /* default case: host memory */
979 memcpy(p_dest, p_src, len);
980}
981
982/* ** data op inline */
983
984static inline void nm_data_op_apply_nop(void*__restrict__ p_ptr, nm_len_t len, struct nm_data_op_context_nop_s*__restrict__ p_nop)
985{
986 /* empty */
987}
988
989static inline void nm_data_op_apply_copy_from(void*__restrict__ p_ptr, nm_len_t len, struct nm_data_op_context_copy_from_s*__restrict__ p_copy_from)
990{
991 nm_data_memcpy_from(p_copy_from->p_dest_ptr, p_ptr, len, &p_copy_from->p_data->props);
992 p_copy_from->p_dest_ptr = (char*)p_copy_from->p_dest_ptr + len;
993}
994
995static inline void nm_data_op_apply_copy_to(void*__restrict__ p_ptr, nm_len_t len, struct nm_data_op_context_copy_to_s*__restrict__ p_copy_to)
996{
997 nm_data_memcpy_to(p_ptr, p_copy_to->p_src_ptr, len, &p_copy_to->p_data->props);
998 p_copy_to->p_src_ptr = (char*)p_copy_to->p_src_ptr + len;
999}
1000
1001static inline void nm_data_op_apply_dynamic(void*__restrict__ p_ptr, nm_len_t len, struct nm_data_op_context_dynamic_s*__restrict__ p_dynamic)
1002{
1003 (*p_dynamic->p_apply)(p_ptr, len, p_dynamic->p_apply_context);
1004}
1005
1006static inline void nm_data_op_apply_getprops(void*__restrict__ p_ptr, nm_len_t len, struct nm_data_op_context_getprops_s*__restrict__ p_getprops)
1007{
1008 p_getprops->props.size += len;
1009 p_getprops->props.blocks += 1;
1010 if(p_getprops->props.is_contig)
1011 {
1012 if((p_getprops->p_blockend != NULL) && (p_ptr != p_getprops->p_blockend))
1013 p_getprops->props.is_contig = 0;
1014 p_getprops->p_blockend = (char*)p_ptr + len;
1015#if defined(NMAD_CUDA) || defined(NMAD_HIP)
1016 if(p_getprops->p_blockend == NULL) /* test only first chunk */
1017 {
1018 nm_data_properties_gpu_fill(&p_getprops->props, p_ptr);
1019 }
1020#endif /* CUDA || HIP */
1021 }
1022}
1023
1024static inline void nm_data_op_apply_chunk(void*__restrict__ p_ptr, nm_len_t len, struct nm_data_op_context_chunk_s*__restrict__ p_chunk)
1025{
1026 const nm_len_t chunk_offset = p_chunk->chunk_offset;
1027 const nm_len_t chunk_len = p_chunk->chunk_len;
1028 if( (!(p_chunk->done + len <= p_chunk->chunk_offset)) /* data before chunk- do nothing */
1029 &&
1030 (!(p_chunk->done >= p_chunk->chunk_offset + p_chunk->chunk_len))) /* data after chunk- do nothing */
1031 {
1032 /* data in chunk */
1033 const nm_len_t block_offset = (p_chunk->done < chunk_offset) ? (chunk_offset - p_chunk->done) : 0;
1034 const nm_len_t block_len = (chunk_offset + chunk_len > p_chunk->done + len) ?
1035 (len - block_offset) : (chunk_offset + chunk_len - p_chunk->done - block_offset);
1036 nm_data_op_apply((char*)p_ptr + block_offset, block_len, p_chunk->p_op);
1037 }
1038 p_chunk->done += len;
1039}
1040
1041static inline void nm_data_op_apply_slicer_coroutine(void*__restrict__ p_ptr, nm_len_t len, struct nm_data_op_context_slicer_coroutine_s*__restrict__ p_slicer_coroutine)
1042{
1043 struct nm_data_slicer_s*__restrict__ p_slicer = p_slicer_coroutine->p_slicer;
1044 restart:
1045 ;
1046 const nm_len_t slice_len = p_slicer->coroutine.slice_len; /* take a snapshot of volatile var */
1047 const nm_len_t chunk_len = (len > slice_len) ? slice_len : len;
1048 nm_data_op_apply(p_ptr, chunk_len, &p_slicer->coroutine.op);
1049 if(slice_len == chunk_len)
1050 {
1051 /* slice is done- give hand back to caller context */
1052 nm_data_coroutine_yield_to_caller(&p_slicer->coroutine.coroutine);
1053 /* back from caller context */
1054 if(len != chunk_len)
1055 {
1056 /* crop block and process remainder */
1057 p_ptr = (char*)p_ptr + chunk_len;
1058 len -= chunk_len;
1059 goto restart;
1060 }
1061 }
1062 else
1063 {
1064 p_slicer->coroutine.slice_len = slice_len - chunk_len;
1065 }
1066}
1067
1069static inline void nm_data_op_apply(void*__restrict__ p_ptr, nm_len_t len, struct nm_data_op_s*__restrict__ p_op)
1070{
1071 switch(p_op->kind)
1072 {
1073 case NM_DATA_OP_NOP:
1074 nm_data_op_apply_nop(p_ptr, len, &p_op->context.nop);
1075 break;
1077 nm_data_op_apply_copy_from(p_ptr, len, &p_op->context.copy_from);
1078 break;
1079 case NM_DATA_OP_COPY_TO:
1080 nm_data_op_apply_copy_to(p_ptr, len, &p_op->context.copy_to);
1081 break;
1082 case NM_DATA_OP_DYNAMIC:
1083 nm_data_op_apply_dynamic(p_ptr, len, &p_op->context.dynamic);
1084 break;
1086 nm_data_op_apply_getprops(p_ptr, len, &p_op->context.getprops);
1087 break;
1088 case NM_DATA_OP_CHUNK:
1089 nm_data_op_apply_chunk(p_ptr, len, &p_op->context.chunk);
1090 break;
1092 nm_data_op_apply_slicer_coroutine(p_ptr, len, &p_op->context.slicer_coroutine);
1093 break;
1094 case NM_DATA_OP_NONE:
1095 NM_FATAL("cannot apply NM_DATA_OP_NONE.\n");
1096 break;
1097 default:
1098 NM_FATAL("op = %d not managed in apply.\n", p_op->kind);
1099 break;
1100 }
1101}
1102
1103
1104#endif /* NM_DATA_H */
struct nm_data_contiguous_s __attribute__
#define _NM_DATA_CONTENT_SIZE
maximum size of content descriptor for nm_data
Definition nm_data.h:82
nm_data_op_kind_e
operation to apply to data in traversal & slicer
Definition nm_data.h:108
void(* nm_data_traversal_t)(const void *_data_content, struct nm_data_op_s *p_op)
funtion to traverse data with app layout, i.e.
Definition nm_data.h:181
static void nm_datav_add_chunk_excerpt(struct nm_datav_s *p_datav, struct nm_data_s *p_data, nm_len_t chunk_offset, nm_len_t chunk_len)
add an excerpt of data to datav; given p_data content is not copied.
Definition nm_data.h:861
static void nm_datav_uncommit(struct nm_datav_s *p_datav)
'uncommit' a datav: explicitely declare that nm_data pointing to this datav has been destroyed.
Definition nm_data.h:879
#define NM_DATAV_INIT_SIZE
initial size of an nm_datav
Definition nm_data.h:251
static void nm_data_propertie_gpu_preinit(struct nm_data_properties_s *p_props)
pre-init GPU part of data properties
static nm_len_t nm_datav_size(struct nm_datav_s *p_datav)
get the size (number of bytes) of data contained in the datav
Definition nm_data.h:868
static void nm_datav_add_chunk(struct nm_datav_s *p_datav, const void *ptr, nm_len_t len)
add a chunk of contiguous data to a datav
Definition nm_data.h:854
EXTERN_C void nm_data_properties_gpu_fill(struct nm_data_properties_s *p_props, const void *p_ptr)
fill in the GPU part of data properties, following pointer 'p_ptr'
enum nm_data_op_kind_e nm_data_op_t
operation to apply to data in traversal & slicer
void(* nm_data_apply_t)(void *ptr, nm_len_t len, void *_context)
function to apply to each data chunk upon traversal
Definition nm_data.h:90
void(* nm_data_properties_compute_t)(struct nm_data_s *p_data)
function to compute data properties
Definition nm_data.h:184
#define NM_DATA_TYPE(ENAME, CONTENT_TYPE, OPS)
macro to generate typed functions to init/access data fields.
Definition nm_data.h:223
static void nm_datav_init(struct nm_datav_s *p_datav)
initialize a datav
Definition nm_data.h:815
static void nm_data_propertie_gpu_postinit(const struct nm_data_properties_s *p_props)
post-init GPU part of data properties: check that p_properties_compute function actually filled the G...
static void nm_datav_destroy(struct nm_datav_s *p_datav)
destroys a datav
Definition nm_data.h:823
static void nm_datav_add_chunk_data(struct nm_datav_s *p_datav, const struct nm_data_s *p_data)
add a chunk of data to datav; given p_data content is copied.
Definition nm_data.h:833
EXTERN_C void nm_data_default_properties_compute(struct nm_data_s *p_data)
@ NM_DATA_OP_CHUNK
apply op on chunk
Definition nm_data.h:115
@ NM_DATA_OP_NONE
no operation selected
Definition nm_data.h:109
@ NM_DATA_OP_COPY_TO
copy to iterator, from user buffer
Definition nm_data.h:112
@ NM_DATA_OP_COPY_FROM
copy from iterator to user buffer
Definition nm_data.h:111
@ NM_DATA_OP_SLICER_COROUTINE
coroutine-based slicer
Definition nm_data.h:116
@ NM_DATA_OP_DYNAMIC
dynamic function call
Definition nm_data.h:113
@ NM_DATA_OP_GETPROPS
compute data properties
Definition nm_data.h:114
@ NM_DATA_OP_NOP
perform no operation on data (fast forward)
Definition nm_data.h:110
void nm_data_chunk_extractor_op_traversal(const struct nm_data_s *p_data, nm_len_t chunk_offset, nm_len_t chunk_len, struct nm_data_op_s *p_op)
static nm_len_t nm_data_size(const struct nm_data_s *p_data)
returns the amount of data contained in the descriptor
Definition nm_data.h:674
void nm_data_copy(struct nm_data_s *p_dest, struct nm_data_s *p_from)
copy from nm_data to another nm_data
void nm_data_chunk_properties_compute(const struct nm_data_s *p_data, nm_len_t chunk_offset, nm_len_t chunk_len, struct nm_data_properties_s *p_props)
compute properties of the given chunk inside the data
void nm_data_dump(struct nm_data_s *p_data, const char *label)
dump data content for debug
static void nm_data_traversal_op_apply(const struct nm_data_s *p_data, struct nm_data_op_s *p_op)
Definition nm_data.h:644
static void nm_data_traversal_apply(const struct nm_data_s *p_data, nm_data_apply_t p_apply, void *_context)
helper function to apply iterator to data
Definition nm_data.h:652
void nm_data_copy_to(const struct nm_data_s *p_data, nm_len_t offset, nm_len_t len, const void *srcbuf)
copy chunk of data from contiguous buffer to user layout
void * nm_data_baseptr_get(const struct nm_data_s *p_data)
find base pointer for a data known to be contiguous
void nm_data_copy_from(const struct nm_data_s *p_data, nm_len_t offset, nm_len_t len, void *destbuf)
copy chunk of data from user layout to contiguous buffer
void nm_data_chunk_extractor_traversal(const struct nm_data_s *p_data, nm_len_t chunk_offset, nm_len_t chunk_len, nm_data_apply_t p_apply, void *p_apply_context)
nm_len_t nm_data_chunk_first_get(const struct nm_data_s *p_data, nm_len_t chunk_offset, nm_len_t chunk_len, int n)
get length of first n blocks in given chunk
static const struct nm_data_properties_s * nm_data_properties_get(const struct nm_data_s *p_data)
returns the properties block for the data
Definition nm_data.h:668
uint32_t nm_data_checksum(const struct nm_data_s *p_data)
checksum data
void * nm_data_chunk_baseptr_get(const struct nm_data_s *p_data, nm_len_t chunk_offset, nm_len_t chunk_len)
find base pointer for a data chunk known to be contiguous
static int nm_data_slicer_isnull(const nm_data_slicer_t *p_slicer)
tests whether a slicer is null
Definition nm_data.h:795
struct nm_data_slicer_s nm_data_slicer_t
internal state of a data slicer.
void nm_data_slicer_forward(nm_data_slicer_t *p_slicer, nm_len_t offset)
nm_data_slicer_kind_t
various kinds of slicer implementations
Definition nm_data.h:764
nm_data_coroutine_kind_e
Definition nm_data.h:738
void nm_data_coroutine_yield_to_data(struct nm_data_coroutine_s *p_coroutine)
void nm_data_slicer_copy_to(nm_data_slicer_t *p_slicer, const void *src_ptr, nm_len_t slice_len)
void(* nm_data_coroutine_worker_t)(struct nm_data_coroutine_s *p_coroutine, void *_user_data)
Definition nm_data.h:735
void nm_data_slicer_destroy(nm_data_slicer_t *p_slicer)
void nm_data_coroutine_yield_to_caller(struct nm_data_coroutine_s *p_coroutine)
void nm_data_slicer_copy_from(nm_data_slicer_t *p_slicer, void *dest_ptr, nm_len_t slice_len)
enum nm_data_coroutine_kind_e nm_data_coroutine_kind_t
Definition nm_data.h:743
void nm_data_slicer_init(nm_data_slicer_t *p_slicer, const struct nm_data_s *p_data)
@ NM_DATA_SLICER_NONE
Definition nm_data.h:765
@ NM_DATA_SLICER_COROUTINE
coroutine-based slicer, using generic data traversal
Definition nm_data.h:766
@ NM_DATA_SLICER_CONTIG
slicer specialized for contig data
Definition nm_data.h:767
@ NM_DATA_COROUTINE_LONGJMP
longjmp-based coroutine, when stack jumping is possible with longjmp
Definition nm_data.h:741
@ NM_DATA_COROUTINE_UCONTEXT
ucontext-based coroutines, when stack jumping is not available through longjmp
Definition nm_data.h:740
@ NM_DATA_COROUTINE_NONE
Definition nm_data.h:739
assert(p_data->ops.p_traversal !=NULL)
static void nm_data_op_apply_copy_from(void *__restrict__ p_ptr, nm_len_t len, struct nm_data_op_context_copy_from_s *__restrict__ p_copy_from)
Definition nm_data.h:989
const struct nm_data_ops_s nm_data_ops_excerpt
static void nm_data_contiguous_build(struct nm_data_s *p_data, void *ptr, nm_len_t len)
Definition nm_data.h:561
static void nm_data_iov_build(struct nm_data_s *p_data, const struct iovec *v, int n)
Definition nm_data.h:580
static void nm_data_op_apply_copy_to(void *__restrict__ p_ptr, nm_len_t len, struct nm_data_op_context_copy_to_s *__restrict__ p_copy_to)
Definition nm_data.h:995
static void nm_data_datav_build(struct nm_data_s *p_datav_data, struct nm_datav_s *p_datav)
frontend to build a nm_data from a datav
Definition nm_data.h:599
static void nm_data_op_apply_dynamic(void *__restrict__ p_ptr, nm_len_t len, struct nm_data_op_context_dynamic_s *__restrict__ p_dynamic)
Definition nm_data.h:1001
const struct nm_data_ops_s nm_data_ops_null
static void nm_data_op_apply_nop(void *__restrict__ p_ptr, nm_len_t len, struct nm_data_op_context_nop_s *__restrict__ p_nop)
Definition nm_data.h:984
static void nm_data_op_apply_slicer_coroutine(void *__restrict__ p_ptr, nm_len_t len, struct nm_data_op_context_slicer_coroutine_s *__restrict__ p_slicer_coroutine)
Definition nm_data.h:1041
const struct nm_data_ops_s nm_data_ops_iov
static void nm_data_memcpy_to(void *p_dest, const void *p_src, nm_len_t len, const struct nm_data_properties_s *p_props)
copy chunks of data.
Definition nm_data.h:952
static void nm_data_excerpt_build(struct nm_data_s *p_data, struct nm_data_s *p_inner_data, nm_len_t chunk_offset, nm_len_t chunk_len)
build a data descriptor as an excerpt of another data.
Definition nm_data.h:621
static void nm_data_memcpy_from(void *p_dest, const void *p_src, nm_len_t len, const struct nm_data_properties_s *p_props)
copy chunks of data.
Definition nm_data.h:918
static void nm_data_op_apply(void *__restrict__ p_ptr, nm_len_t len, struct nm_data_op_s *__restrict__ p_op)
apply op on block (p_ptr, len)
Definition nm_data.h:1069
static int nm_data_isnull(struct nm_data_s *p_data)
Definition nm_data.h:545
static void nm_data_op_apply_chunk(void *__restrict__ p_ptr, nm_len_t len, struct nm_data_op_context_chunk_s *__restrict__ p_chunk)
Definition nm_data.h:1024
static void nm_data_op_apply_getprops(void *__restrict__ p_ptr, nm_len_t len, struct nm_data_op_context_getprops_s *__restrict__ p_getprops)
Definition nm_data.h:1006
static void nm_data_null_build(struct nm_data_s *p_data)
Definition nm_data.h:540
const struct nm_data_ops_s nm_data_ops_contiguous
nm_data_propertie_gpu_preinit & p_data
Definition nm_data.h:539
const struct nm_data_ops_s nm_data_ops_datav
uint16_t len
chunk len
Definition nm_headers.h:0
nm_len_t chunk_len
length of this chunk
Definition nm_headers.h:4
nm_len_t chunk_offset
offset of the enclosed chunk
Definition nm_headers.h:4
struct nm_mpi_operator_s * p_op
nm_len_t size
size of the onsided data (not incuding target-side completion)
This is the common public header for NewMad.
#define NM_FATAL(format,...)
Definition nm_public.h:67
uint64_t nm_len_t
data length used by nmad
Definition nm_types.h:68
data descriptor for contiguous data
Definition nm_data.h:554
nm_len_t len
data length
Definition nm_data.h:556
void * ptr
base pointer for block
Definition nm_data.h:555
struct nm_data_coroutine_ucontext_s * p_ucontext
Definition nm_data.h:750
nm_data_coroutine_worker_t p_worker
Definition nm_data.h:753
nm_data_coroutine_kind_t kind
Definition nm_data.h:747
struct nm_data_coroutine_longjmp_s * p_longjmp
Definition nm_data.h:751
union nm_data_coroutine_s::@21 impl
data descriptor for datav in a nm_data (embedd a vector of nm_data in nm_data)
Definition nm_data.h:592
struct nm_datav_s * p_datav
Definition nm_data.h:593
data as an excerpt of another data.
Definition nm_data.h:611
nm_len_t chunk_offset
Definition nm_data.h:612
nm_len_t chunk_len
Definition nm_data.h:613
struct nm_data_s * p_data
Definition nm_data.h:614
data descriptor for iov data (embedd iovec in nm_data)
Definition nm_data.h:573
const struct iovec * v
Definition nm_data.h:574
data descriptor for 'null' data
Definition nm_data.h:535
int dummy
unused, to avoid non-portable empty structure
Definition nm_data.h:536
nm_len_t chunk_offset
offset for begin of copy at destination
Definition nm_data.h:150
nm_len_t done
offset done so far at destination
Definition nm_data.h:152
struct nm_data_op_s * p_op
operation to apply on chunk
Definition nm_data.h:153
nm_len_t chunk_len
length to copy
Definition nm_data.h:151
const struct nm_data_s * p_data
Definition nm_data.h:127
void *__restrict__ p_dest_ptr
Definition nm_data.h:126
const void *__restrict__ p_src_ptr
Definition nm_data.h:132
const struct nm_data_s * p_data
Definition nm_data.h:133
nm_data_apply_t p_apply
Definition nm_data.h:138
struct nm_data_properties_s props
Definition nm_data.h:145
void * p_blockend
end of previous block
Definition nm_data.h:144
struct nm_data_slicer_s * p_slicer
Definition nm_data.h:158
union nm_data_op_s::@20 context
struct nm_data_op_context_nop_s nop
Definition nm_data.h:166
struct nm_data_op_context_copy_to_s copy_to
Definition nm_data.h:168
struct nm_data_op_context_getprops_s getprops
Definition nm_data.h:170
struct nm_data_op_context_copy_from_s copy_from
Definition nm_data.h:167
struct nm_data_op_context_chunk_s chunk
Definition nm_data.h:171
enum nm_data_op_kind_e kind
Definition nm_data.h:163
struct nm_data_op_context_slicer_coroutine_s slicer_coroutine
Definition nm_data.h:172
struct nm_data_op_context_dynamic_s dynamic
Definition nm_data.h:169
set of operations available on data type.
Definition nm_data.h:189
nm_data_properties_compute_t p_properties_compute
optimized function to compute data properties (optionnal)
Definition nm_data.h:191
nm_data_traversal_t p_traversal
operation to apply a given function to all chunks of data (required)
Definition nm_data.h:190
block of static properties for a given data descriptor
Definition nm_data.h:94
nm_len_t size
total size in bytes (accumulator)
Definition nm_data.h:96
int is_contig
data is contiguous; data may be contiguous even with blocks > 1, if blocks are next to each other
Definition nm_data.h:97
nm_len_t blocks
number of blocks; -1 if properties are not initialized
Definition nm_data.h:95
a data descriptor, used to pack/unpack data from app layout to/from contiguous buffers
Definition nm_data.h:200
struct nm_data_ops_s ops
collection of iterators
Definition nm_data.h:201
struct nm_data_properties_s props
cache for properties
Definition nm_data.h:202
char _content[64]
placeholder for type-dependant content
Definition nm_data.h:203
internal state of a data slicer.
Definition nm_data.h:772
struct nm_data_op_s op
op to apply on the current slice
Definition nm_data.h:780
struct nm_data_slicer_s::@22::@25 contig
slicer for contiguous data; no context switch
void * p_baseptr
base pointer of the data
Definition nm_data.h:786
volatile nm_len_t slice_len
length of the current slice
Definition nm_data.h:781
struct nm_data_coroutine_s coroutine
Definition nm_data.h:782
nm_len_t done
length of data processed so far
Definition nm_data.h:775
nm_data_slicer_kind_t kind
Definition nm_data.h:773
const struct nm_data_s * p_data
Definition nm_data.h:774
encapsulate a dynamic vector of nm_data
Definition nm_data.h:255
int commited
Definition nm_data.h:260
struct nm_data_s data[4]
vector of data
Definition nm_data.h:257
int n_data
number of entries actually used in the above array
Definition nm_data.h:258
struct nm_data_s * p_data
vector of nm_data; either dynamically allocated, or points to data[0]
Definition nm_data.h:256
int allocated
allocated number of entries in p_data
Definition nm_data.h:259