diff --git a/doc/Makefile b/doc/Makefile index 1c03ab892e15b2b998621be2bf04039d01e86d48..051b840576cc2ca1fd1434ca82570524f107d03d 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -101,7 +101,7 @@ MANPAGES_3_MD_PMEM2 = libpmem2/pmem2_errormsg.3.md libpmem2/pmem2_config_new.3.m libpmem2/pmem2_config_set_length.3.md libpmem2/pmem2_config_set_offset.3.md \ libpmem2/pmem2_map_get_store_granularity.3.md libpmem2/pmem2_get_flush_fn.3.md \ libpmem2/pmem2_get_drain_fn.3.md libpmem2/pmem2_get_persist_fn.3.md \ - libpmem2/pmem2_perror.3.md libpmem2/pmem2_get_memmove_fn.3.md libpmem2/pmem2_memcpy_async.3.md\ + libpmem2/pmem2_perror.3.md libpmem2/pmem2_get_memmove_fn.3.md libpmem2/pmem2_async.3.md\ libpmem2/pmem2_config_set_sharing.3.md libpmem2/pmem2_config_set_vm_reservation.3.md libpmem2/pmem2_vm_reservation_new.3.md \ libpmem2/pmem2_vm_reservation_get_address.3.md libpmem2/pmem2_vm_reservation_get_size.3.md \ libpmem2/pmem2_badblock_context_new.3.md libpmem2/pmem2_badblock_next.3.md \ @@ -114,7 +114,8 @@ MANPAGES_3_MD_PMEM2 = libpmem2/pmem2_errormsg.3.md libpmem2/pmem2_config_new.3.m MANPAGES_1_MD_PMEM2 = MANPAGES_3_DUMMY += libpmem2/pmem2_config_delete.3 libpmem2/pmem2_config_set_vdm.3 libpmem2/pmem2_source_from_handle.3 libpmem2/pmem2_source_delete.3 \ - libpmem2/pmem2_get_memset_fn.3 libpmem2/pmem2_get_memcpy_fn.3 libpmem2/pmem2_vm_reservation_delete.3 \ + libpmem2/pmem2_get_memset_fn.3 libpmem2/pmem2_get_memcpy_fn.3 libpmem2/pmem2_memcpy_async.3 libpmem2/pmem2_memmove_async.3 \ + libpmem2/pmem2_memset_async.3 libpmem2/pmem2_vm_reservation_delete.3 \ libpmem2/pmem2_badblock_context_delete.3 libpmem2/pmem2_vm_reservation_shrink.3 \ libpmem2/pmem2_vm_reservation_map_find_first.3 libpmem2/pmem2_vm_reservation_map_find_last.3 \ libpmem2/pmem2_vm_reservation_map_find_next.3 libpmem2/pmem2_vm_reservation_map_find_prev.3 \ diff --git a/doc/libpmem2/.gitignore b/doc/libpmem2/.gitignore index a1b3a358cfaeb4aed5e47516d620811a27b0cd1c..55ed800f212fabcef23dcfc85ae21dfe854437f3 100644 --- a/doc/libpmem2/.gitignore +++ b/doc/libpmem2/.gitignore @@ -22,7 +22,7 @@ pmem2_map_new.3 pmem2_map_get_address.3 pmem2_map_get_size.3 pmem2_map_get_store_granularity.3 -pmem2_memcpy_async.3 +pmem2_async.3 pmem2_source_alignment.3 pmem2_source_from_fd.3 pmem2_source_from_anon.3 diff --git a/doc/libpmem2/pmem2_memcpy_async.3.md b/doc/libpmem2/pmem2_async.3.md similarity index 50% rename from doc/libpmem2/pmem2_memcpy_async.3.md rename to doc/libpmem2/pmem2_async.3.md index 050813bca51f761574a5118f1f5618faaab14b65..d7f1e654fbd4bb9718d19b0d1f933015650c5dda 100644 --- a/doc/libpmem2/pmem2_memcpy_async.3.md +++ b/doc/libpmem2/pmem2_async.3.md @@ -1,7 +1,7 @@ --- layout: manual Content-Style: 'text/css' -title: _MP(PMEM2_MEMCPY_ASYNC, 3) +title: _MP(PMEM2_ASYNC, 3) collection: libpmem2 header: PMDK date: pmem2 API version 1.0 @@ -10,7 +10,7 @@ date: pmem2 API version 1.0 [comment]: <> (SPDX-License-Identifier: BSD-3-Clause [comment]: <> (Copyright 2022, Intel Corporation) -[comment]: <> (pmem2_memcpy_async.3 -- man page for pmem2_memcpy_async) +[comment]: <> (pmem2_async.3 -- man page for pmem2_async operations) [NAME](#name)<br /> [SYNOPSIS](#synopsis)<br /> @@ -19,7 +19,7 @@ date: pmem2 API version 1.0 [SEE ALSO](#see-also)<br /> # NAME # -**pmem2_config_set_vdm**(), **pmem2_memcpy_async**() - asynchronous data movement operations +**pmem2_config_set_vdm**(), **pmem2_memcpy_async**(), **pmem2_memmove_async**(), **pmem2_memset_async**() - asynchronous data movement operations # SYNOPSIS # @@ -30,6 +30,13 @@ int pmem2_config_set_vdm(struct pmem2_config *cfg, struct vdm *vdm); struct vdm_operation_future pmem2_memcpy_async(struct pmem2_map *map, void *pmemdest, const void *src, size_t len, unsigned flags); + +pmem2_memmove_async(struct pmem2_map *map, void *pmemdest, const void *src, + size_t len, unsigned flags) + +struct vdm_operation_future pmem2_memset_async(struct pmem2_map *map, + void *pmemstr, int c, size_t n, unsigned flags) +{ ``` # DESCRIPTION # @@ -37,19 +44,29 @@ To use those functions, you must have *libminiasync* installed. Those functions and vdm (virtual data mover) concepts from this library. Please check **miniasync**(7) for more details. The **pmem2_config_set_vdm** sets a vdm structure in the *pmem2_config*. -This structure will be used by pmem2_memcpy_async function, to create a *vdm_operation_future*. +This structure will be used by pmem2_*_async functions, to create a *vdm_operation_future*. If vdm is not set in the config, pmem2_map_new will use a default one which uses a pmem2 memory movement functions to perform memory operations. (**pmem2_get_memcpy_fn**(3), **pmem2_get_memmove_fn**(3), **pmem2_get_memsety_fn**(3)). -The **pmem2_memcpy_async** uses *vdm* structure held inside of the *pmem2_map* structure to initialise and return **vdm_operation_future**. -This future will perform memcpy operation from *vdm* to copy *len* bytes from *src* to *pmemdest*. In the current implementation *flags* are ignored. +The **pmem2_memcpy_async** uses *vdm* structure held inside the *pmem2_map* structure to initialise and returns **vdm_operation_future**. +This future will perform memcpy operation defined in *vdm* to copy *len* bytes from *src* to *pmemdest*. In the current implementation *flags* are ignored. -# RETURN VALUE # +The **pmem2_memmove_async** returns **vdm_operation_future** which +will perform memmove operation defined in *vdm* to copy *len* bytes from *src* to *pmemdest*. In the current implementation *flags* are ignored. + +The **pmem2_memmset_async** returns **vdm_operation_future** which +will perform memset operation defined in *vdm* to fill *n* bytes from *pmemstr* with value of int *c* interpreted as unsigned char. +In the current implementation *flags* are ignored. +# RETURN VALUE # The **pmem2_config_set_vdm** always return 0. -The **pmem2_memcpy_async** returns a new instance of **vdm_operation_future** which will copy *len* bytes from *src* to *pmemdest*. -You can execute returned structure using methods from the **libminiasync**() library. +The **pmem2_memcpy_async** returns a new instance of **vdm_operation_future** performing memcpy operation. +You can execute returned structure using methods from the **libminiasync**() library such as **FUTURE_BUSY_POLL**(3). + +The **pmem2_memmove_async** returns a new instance of **vdm_operation_future** performing memmove operation. + +The **pmem2_memset_async** returns a new instance of **vdm_operation_future** performing memset operation. # SEE ALSO # diff --git a/doc/libpmem2/pmem2_config_set_vdm.3 b/doc/libpmem2/pmem2_config_set_vdm.3 index 8e81274f85cd1576b8bc70188ae53d6c0d5fa9cd..3fd41779c0b6e0dd305488e88ca6c164074c920e 100644 --- a/doc/libpmem2/pmem2_config_set_vdm.3 +++ b/doc/libpmem2/pmem2_config_set_vdm.3 @@ -1 +1 @@ -.so pmem2_memcpy_async.3 +.so pmem2_async.3 diff --git a/doc/libpmem2/pmem2_memcpy_async.3 b/doc/libpmem2/pmem2_memcpy_async.3 new file mode 100644 index 0000000000000000000000000000000000000000..3fd41779c0b6e0dd305488e88ca6c164074c920e --- /dev/null +++ b/doc/libpmem2/pmem2_memcpy_async.3 @@ -0,0 +1 @@ +.so pmem2_async.3 diff --git a/doc/libpmem2/pmem2_memmove_async.3 b/doc/libpmem2/pmem2_memmove_async.3 new file mode 100644 index 0000000000000000000000000000000000000000..3fd41779c0b6e0dd305488e88ca6c164074c920e --- /dev/null +++ b/doc/libpmem2/pmem2_memmove_async.3 @@ -0,0 +1 @@ +.so pmem2_async.3 diff --git a/doc/libpmem2/pmem2_memset_async.3 b/doc/libpmem2/pmem2_memset_async.3 new file mode 100644 index 0000000000000000000000000000000000000000..3fd41779c0b6e0dd305488e88ca6c164074c920e --- /dev/null +++ b/doc/libpmem2/pmem2_memset_async.3 @@ -0,0 +1 @@ +.so pmem2_async.3 diff --git a/src/include/libpmem2.h b/src/include/libpmem2.h index 162c336dfed5dcefd311fcf70dc3d25b27f1b41d..c880ce64b4f6418273ef124e005a154c84f959d1 100644 --- a/src/include/libpmem2.h +++ b/src/include/libpmem2.h @@ -282,6 +282,12 @@ int pmem2_config_set_vdm(struct pmem2_config *cfg, struct vdm *vdm); struct vdm_operation_future pmem2_memcpy_async(struct pmem2_map *map, void *pmemdest, const void *src, size_t len, unsigned flags); + +struct vdm_operation_future pmem2_memmove_async(struct pmem2_map *map, + void *pmemdest, const void *src, size_t len, unsigned flags); + +struct vdm_operation_future pmem2_memset_async(struct pmem2_map *map, + void *str, int c, size_t n, unsigned flags); #endif /* error handling */ diff --git a/src/libpmem2/libpmem2.def b/src/libpmem2/libpmem2.def index 47692d2bfbcc43bbcbc69fef299fa5f08d11fd9a..ab809738e58a61e2d5ae986fbc8413fc95b3ea11 100644 --- a/src/libpmem2/libpmem2.def +++ b/src/libpmem2/libpmem2.def @@ -37,6 +37,8 @@ EXPORTS pmem2_map_from_existing pmem2_map_new pmem2_memcpy_async + pmem2_memmove_async + pmem2_memset_async pmem2_perrorU pmem2_perrorW pmem2_source_alignment diff --git a/src/libpmem2/libpmem2.link.in b/src/libpmem2/libpmem2.link.in index 1e59becc84223b50920a19ec83baec67969b19c1..5c0be977b3ba0166ba34c2c2bde4613f60b405e0 100644 --- a/src/libpmem2/libpmem2.link.in +++ b/src/libpmem2/libpmem2.link.in @@ -34,6 +34,8 @@ LIBPMEM2_1.0 { pmem2_map_new; pmem2_map_from_existing; pmem2_memcpy_async; + pmem2_memmove_async; + pmem2_memset_async; pmem2_perror; pmem2_source_alignment; pmem2_source_delete; diff --git a/src/libpmem2/mover.c b/src/libpmem2/mover.c index f57549d2c88ae85726ccc6da99bebe4423b9daf4..5a7157d0582abcde3e07aa667cff313e1e5e9025 100644 --- a/src/libpmem2/mover.c +++ b/src/libpmem2/mover.c @@ -41,7 +41,7 @@ sync_operation_check(void *data, const struct vdm_operation *operation) int complete; util_atomic_load_explicit32(&sync_op->complete, &complete, - memory_order_acquire); + memory_order_acquire); return complete ? FUTURE_STATE_COMPLETE : FUTURE_STATE_IDLE; } @@ -57,8 +57,8 @@ sync_operation_new(struct vdm *vdm, const enum vdm_operation_type type) SUPPRESS_UNUSED(type); struct data_mover *vdm_sync = (struct data_mover *)vdm; - struct data_mover_op *sync_op = membuf_alloc(vdm_sync->membuf, - sizeof(struct data_mover_op)); + struct data_mover_op *sync_op = + membuf_alloc(vdm_sync->membuf, sizeof(struct data_mover_op)); if (sync_op == NULL) return NULL; @@ -73,24 +73,27 @@ sync_operation_new(struct vdm *vdm, const enum vdm_operation_type type) */ static void sync_operation_delete(void *data, const struct vdm_operation *operation, - struct vdm_operation_output *output) + struct vdm_operation_output *output) { output->result = VDM_SUCCESS; switch (operation->type) { - case VDM_OPERATION_MEMCPY: - output->type = VDM_OPERATION_MEMCPY; - output->output.memcpy.dest = - operation->data.memcpy.dest; - break; - case VDM_OPERATION_MEMMOVE: - output->type = VDM_OPERATION_MEMMOVE; - output->output.memmove.dest = - operation->data.memcpy.dest; - break; - default: - FATAL("unsupported operation type"); - + case VDM_OPERATION_MEMCPY: + output->type = VDM_OPERATION_MEMCPY; + output->output.memcpy.dest = + operation->data.memcpy.dest; + break; + case VDM_OPERATION_MEMMOVE: + output->type = VDM_OPERATION_MEMMOVE; + output->output.memmove.dest = + operation->data.memcpy.dest; + break; + case VDM_OPERATION_MEMSET: + output->type = VDM_OPERATION_MEMSET; + output->output.memset.str = operation->data.memset.str; + break; + default: + FATAL("unsupported operation type"); } membuf_free(data); } @@ -100,11 +103,10 @@ sync_operation_delete(void *data, const struct vdm_operation *operation, */ static int sync_operation_start(void *data, const struct vdm_operation *operation, - struct future_notifier *n) + struct future_notifier *n) { LOG(3, "data %p op %p, notifier %p", data, operation, n); - struct data_mover_op *sync_data = - (struct data_mover_op *)data; + struct data_mover_op *sync_data = (struct data_mover_op *)data; struct data_mover *mover = membuf_ptr_user_data(data); if (n) n->notifier_used = FUTURE_NOTIFIER_NONE; @@ -130,11 +132,21 @@ sync_operation_start(void *data, const struct vdm_operation *operation, PMEM2_F_MEM_NONTEMPORAL); break; } + case VDM_OPERATION_MEMSET: { + pmem2_memset_fn memset_fn; + memset_fn = pmem2_get_memset_fn(mover->map); + + memset_fn(operation->data.memset.str, + operation->data.memset.c, + operation->data.memset.n, + PMEM2_F_MEM_NONTEMPORAL); + break; + } default: FATAL("unsupported operation type"); } - util_atomic_store_explicit32(&sync_data->complete, - 1, memory_order_release); + util_atomic_store_explicit32(&sync_data->complete, 1, + memory_order_release); return 0; } @@ -189,11 +201,37 @@ mover_delete(struct vdm *dms) * pmem2_memcpy_async -- returns a memcpy future */ struct vdm_operation_future -pmem2_memcpy_async(struct pmem2_map *map, - void *pmemdest, const void *src, size_t len, unsigned flags) +pmem2_memcpy_async(struct pmem2_map *map, void *pmemdest, const void *src, + size_t len, unsigned flags) { - LOG(3, "map %p, pmemdest %p, src %p, len %" PRIu64 ", flags %u", - map, pmemdest, src, len, flags); + LOG(3, "map %p, pmemdest %p, src %p, len %" PRIu64 ", flags %u", map, + pmemdest, src, len, flags); SUPPRESS_UNUSED(flags); return vdm_memcpy(map->vdm, pmemdest, (void *)src, len, 0); } + +/* + * pmem2_memove_async -- returns a memmove future + */ +struct vdm_operation_future +pmem2_memmove_async(struct pmem2_map *map, void *pmemdest, const void *src, + size_t len, unsigned flags) +{ + LOG(3, "map %p, pmemdest %p, src %p, len %" PRIu64 ", flags %u", map, + pmemdest, src, len, flags); + SUPPRESS_UNUSED(flags); + return vdm_memmove(map->vdm, pmemdest, (void *)src, len, 0); +} + +/* + * pmem2_memset_async -- returns a memset future + */ +struct vdm_operation_future +pmem2_memset_async(struct pmem2_map *map, void *pmemstr, int c, size_t n, + unsigned flags) +{ + LOG(3, "map %p, pmemstr %p, c %d, len %" PRIu64 ", flags %u", map, + pmemstr, c, n, flags); + SUPPRESS_UNUSED(flags); + return vdm_memset(map->vdm, pmemstr, c, n, 0); +} diff --git a/src/test/pmem2_mover/TESTS.py b/src/test/pmem2_mover/TESTS.py index e0243780a6779904d0bac1ba549a466f881897bf..90c358453e05149f842caaf6465ebfd71719d7a1 100644 --- a/src/test/pmem2_mover/TESTS.py +++ b/src/test/pmem2_mover/TESTS.py @@ -40,22 +40,56 @@ class PMEM2_MOVER_MT(PMEM2_MOVER): class TEST0(PMEM2_MOVER): - """verify pmem2 mover functionality""" - test_case = "test_mover_basic" + """verify pmem2 mover memcpy functionality""" + test_case = "test_mover_memcpy_basic" + + +class TEST1(PMEM2_MOVER): + """verify pmem2 mover memmove functionality""" + test_case = "test_mover_memmove_basic" + + +class TEST2(PMEM2_MOVER): + """verify pmem2 mover memset functionality""" + test_case = "test_mover_memset_basic" + + +class TEST3(PMEM2_MOVER_MT): + """verify pmem2 mover multi-threaded memcpy functionality""" + test_case = "test_mover_memcpy_multithreaded" + + +class TEST4(PMEM2_MOVER_MT): + """verify pmem2 mover multi-threaded memmove functionality""" + test_case = "test_mover_memmove_multithreaded" -class TEST1(PMEM2_MOVER_MT): - """verify pmem2 mover multi-threaded functionality""" - test_case = "test_mover_multithreaded" +class TEST5(PMEM2_MOVER_MT): + """verify pmem2 mover multi-threaded memset functionality""" + test_case = "test_mover_memset_multithreaded" + + +class TEST6(PMEM2_MOVER_MT): + test_type = t.Long + thread_num = 16 + """verify pmem2 mover multi-threaded memcpy functionality (Long)""" + test_case = "test_mover_memcpy_multithreaded" + + +class TEST7(PMEM2_MOVER_MT): + test_type = t.Long + thread_num = 16 + """verify pmem2 mover multi-threaded memmove functionality (Long)""" + test_case = "test_mover_memmove_multithreaded" -class TEST2(PMEM2_MOVER_MT): +class TEST8(PMEM2_MOVER_MT): test_type = t.Long thread_num = 16 - """verify pmem2 mover multi-threaded functionality (Long)""" - test_case = "test_mover_multithreaded" + """verify pmem2 mover multi-threaded memset functionality (Long)""" + test_case = "test_mover_memset_multithreaded" -class TEST3(PMEM2_MOVER): +class TEST9(PMEM2_MOVER): """verify pmem2 mover functionality""" test_case = "test_miniasync_mover" diff --git a/src/test/pmem2_mover/pmem2_mover.c b/src/test/pmem2_mover/pmem2_mover.c index 99db7807b692bee29100acd8fd5240565e52f7d5..7602ab2c7db58c08aa6c34693ddbd8e88e53f35d 100644 --- a/src/test/pmem2_mover/pmem2_mover.c +++ b/src/test/pmem2_mover/pmem2_mover.c @@ -6,12 +6,14 @@ */ #define PMEM2_USE_MINIASYNC 1 + #include "libpmem2.h" #include "unittest.h" #include "ut_pmem2.h" #include "ut_pmem2_setup_integration.h" #include <libminiasync.h> + /* * map_valid -- return valid mapped pmem2_map */ @@ -27,13 +29,13 @@ map_valid(struct pmem2_config *cfg, struct pmem2_source *src) } /* - * test_mover_basic -- test basic functionality of pmem2 default mover + * test_mover_memcpy_basic -- test basic functionality of pmem2 default mover */ static int -test_mover_basic(const struct test_case *tc, int argc, char *argv[]) +test_mover_memcpy_basic(const struct test_case *tc, int argc, char *argv[]) { if (argc < 1) - UT_FATAL("usage: test_mover_basic <file>"); + UT_FATAL("usage: test_mover_memcpy_basic <file>"); char *file = argv[0]; int fd = OPEN(file, O_RDWR); @@ -63,20 +65,124 @@ test_mover_basic(const struct test_case *tc, int argc, char *argv[]) return 1; } +/* + * test_mover_memmove_basic -- test memmove functionality of the default mover + * using two overlapping buffers: [1,2,3,4,0,0] -> [1,2,1,2,3,4] + * A B A B + */ +static int +test_mover_memmove_basic(const struct test_case *tc, int argc, char *argv[]) +{ + if (argc < 1) + UT_FATAL("usage: test_mover_memmove_basic <file>"); + + char *file = argv[0]; + int fd = OPEN(file, O_RDWR); + unsigned string_size = 255; + + struct pmem2_source *src; + struct pmem2_config *cfg; + PMEM2_PREPARE_CONFIG_INTEGRATION(&cfg, &src, fd, + PMEM2_GRANULARITY_PAGE); + + struct pmem2_map *map = map_valid(cfg, src); + char *data = pmem2_map_get_address(map); + pmem2_memcpy_fn pmem2_memcpy = pmem2_get_memcpy_fn(map); + + /* + * Create data for first buffer + */ + char *buffer_data = malloc(string_size); + for (unsigned i = 0; i < string_size; i++) { + buffer_data[i] = (char)i; + } + /* + * Fill first buffer with numbers from 0 to 255 + */ + pmem2_memcpy(data, buffer_data, string_size, 0); + + /* + * Create future to copy contents of first buffer into second buffer + * which starts in the half of first buffer. + */ + struct vdm_operation_future move = pmem2_memmove_async( + map, data + string_size / 2, data, string_size, 0); + + FUTURE_BUSY_POLL(&move); + + if (memcmp(data + string_size / 2, buffer_data, string_size)) + UT_FATAL("data should be equal"); + + pmem2_map_delete(&map); + pmem2_config_delete(&cfg); + pmem2_source_delete(&src); + CLOSE(fd); + return 1; +} + +/* + * test_mover_memmove_basic -- test memmove functionality of the default mover + * by filling a buffer with some data and then using memset to overwrite it + */ +static int +test_mover_memset_basic(const struct test_case *tc, int argc, char *argv[]) +{ + if (argc < 1) + UT_FATAL("usage: test_mover_memset_basic <file>"); + + char *file = argv[0]; + int fd = OPEN(file, O_RDWR); + unsigned array_size = 4096; + + struct pmem2_source *src; + struct pmem2_config *cfg; + PMEM2_PREPARE_CONFIG_INTEGRATION(&cfg, &src, fd, + PMEM2_GRANULARITY_PAGE); + + struct pmem2_map *map = map_valid(cfg, src); + char *data = pmem2_map_get_address(map); + char *memset_result = malloc(array_size); + memset(memset_result, 5, array_size); + + /* + * Fill buffer with some data different from a result of memset + */ + for (unsigned i = 0; i < array_size; i++) { + data[i] = (char)i; + } + + /* + * Create future to set every byte of the buffer to 5 + */ + struct vdm_operation_future move = + pmem2_memset_async(map, data, 5, array_size, 0); + + FUTURE_BUSY_POLL(&move); + + if (memcmp(data, memset_result, array_size)) + UT_FATAL("data should be equal"); + + pmem2_map_delete(&map); + pmem2_config_delete(&cfg); + pmem2_source_delete(&src); + CLOSE(fd); + return 1; +} + #define WORKER_RUNS 20000 #define TEST_SIZE 4096 struct thread_arg { - struct pmem2_map *map; - void *addr; - unsigned threads; - unsigned thread_id; + struct pmem2_map *map; + void *addr; + unsigned threads; + unsigned thread_id; }; /* - * thread_worker -- thread worker for test_mover_multithread + * thread_memcpy_worker -- thread worker for test_mover_memcpy_multithread */ static void * -thread_worker(void *arg) +thread_memcpy_worker(void *arg) { struct thread_arg *targ = arg; unsigned *pattern1, *pattern2; @@ -94,9 +200,8 @@ thread_worker(void *arg) for (int i = 0; i < WORKER_RUNS; i++) { unsigned *pattern = i % 2 ? pattern1 : pattern2; - struct vdm_operation_future cpy = - pmem2_memcpy_async(targ->map, targ->addr, pattern, - TEST_SIZE, 0); + struct vdm_operation_future cpy = pmem2_memcpy_async( + targ->map, targ->addr, pattern, TEST_SIZE, 0); FUTURE_BUSY_POLL(&cpy); @@ -109,13 +214,103 @@ thread_worker(void *arg) } /* - * test_mover_multithreaded -- multi-threaded test for the memcpy + * test_mover_memcpy_multithreaded -- multi-threaded test for the mover's memcpy + */ +static int +test_mover_memcpy_multithreaded(const struct test_case *tc, int argc, + char *argv[]) +{ + if (argc < 2) + UT_FATAL( + "usage: test_mover_memcpy_multithreaded <file> <threads>"); + + char *file = argv[0]; + int fd = OPEN(file, O_RDWR); + unsigned long num_threads = STRTOUL(argv[1], NULL, 10); + + struct pmem2_source *src; + struct pmem2_config *cfg; + PMEM2_PREPARE_CONFIG_INTEGRATION(&cfg, &src, fd, + PMEM2_GRANULARITY_PAGE); + + struct pmem2_map *map = map_valid(cfg, src); + + UT_ASSERT(pmem2_map_get_size(map) >= TEST_SIZE * num_threads); + + os_thread_t *threads = MALLOC(num_threads * sizeof(*threads)); + struct thread_arg *args = MALLOC(num_threads * sizeof(*args)); + + char *data = pmem2_map_get_address(map); + for (unsigned i = 0; i < num_threads; i++) { + args[i].map = map; + args[i].addr = data + i * TEST_SIZE; + args[i].threads = num_threads; + args[i].thread_id = i; + + THREAD_CREATE(&threads[i], NULL, thread_memcpy_worker, + &args[i]); + } + + for (unsigned i = 0; i < num_threads; i++) { + THREAD_JOIN(&threads[i], NULL); + } + + FREE(threads); + FREE(args); + + pmem2_map_delete(&map); + pmem2_config_delete(&cfg); + pmem2_source_delete(&src); + CLOSE(fd); + return 2; +} + +/* + * thread_memmove_worker -- thread worker for test_mover_memmove_multithread + */ +static void * +thread_memove_worker(void *arg) +{ + struct thread_arg *targ = arg; + unsigned *pattern1, *pattern2; + + UT_COMPILE_ERROR_ON(TEST_SIZE % sizeof(*pattern1) != 0); + unsigned array_size = TEST_SIZE / sizeof(*pattern1); + + pattern1 = MALLOC(array_size * sizeof(*pattern1)); + pattern2 = MALLOC(array_size * sizeof(*pattern2)); + + for (unsigned j = 0; j < array_size; j++) { + pattern1[j] = targ->thread_id + 1 * targ->threads; + pattern2[j] = targ->thread_id + 2 * targ->threads; + } + + for (int i = 0; i < WORKER_RUNS; i++) { + unsigned *pattern = i % 2 ? pattern1 : pattern2; + struct vdm_operation_future move = pmem2_memmove_async( + targ->map, targ->addr, pattern, TEST_SIZE, 0); + + FUTURE_BUSY_POLL(&move); + + if (memcmp(pattern, targ->addr, TEST_SIZE)) + UT_FATAL("data should be equal"); + } + FREE(pattern1); + FREE(pattern2); + return NULL; +} + +/* + * test_mover_memmove_multithreaded -- multi-threaded test for the mover's + * memmove */ static int -test_mover_multithreaded(const struct test_case *tc, int argc, char *argv[]) +test_mover_memmove_multithreaded(const struct test_case *tc, int argc, + char *argv[]) { if (argc < 2) - UT_FATAL("usage: test_mover_basic <file> <threads>"); + UT_FATAL( + "usage: test_mover_memmove_multithreaded <file> <threads>"); char *file = argv[0]; int fd = OPEN(file, O_RDWR); @@ -130,8 +325,7 @@ test_mover_multithreaded(const struct test_case *tc, int argc, char *argv[]) UT_ASSERT(pmem2_map_get_size(map) >= TEST_SIZE * num_threads); - os_thread_t *threads - = MALLOC(num_threads * sizeof(*threads)); + os_thread_t *threads = MALLOC(num_threads * sizeof(*threads)); struct thread_arg *args = MALLOC(num_threads * sizeof(*args)); char *data = pmem2_map_get_address(map); @@ -141,7 +335,96 @@ test_mover_multithreaded(const struct test_case *tc, int argc, char *argv[]) args[i].threads = num_threads; args[i].thread_id = i; - THREAD_CREATE(&threads[i], NULL, thread_worker, + THREAD_CREATE(&threads[i], NULL, thread_memove_worker, + &args[i]); + } + + for (unsigned i = 0; i < num_threads; i++) { + THREAD_JOIN(&threads[i], NULL); + } + + FREE(threads); + FREE(args); + + pmem2_map_delete(&map); + pmem2_config_delete(&cfg); + pmem2_source_delete(&src); + CLOSE(fd); + return 2; +} + +/* + * thread_memset_worker -- thread worker for test_mover_memset_multithread + */ +static void * +thread_memset_worker(void *arg) +{ + struct thread_arg *targ = arg; + char *expected_result1, *expected_result2; + + UT_COMPILE_ERROR_ON(TEST_SIZE % sizeof(*expected_result1) != 0); + unsigned array_size = TEST_SIZE / sizeof(*expected_result1); + + expected_result1 = MALLOC(array_size * sizeof(*expected_result1)); + expected_result2 = MALLOC(array_size * sizeof(*expected_result2)); + + memset(expected_result1, (int)targ->thread_id, TEST_SIZE); + memset(expected_result2, (int)(targ->thread_id + targ->threads), + TEST_SIZE); + + for (int i = 0; i < WORKER_RUNS; i++) { + int number = i % 2 ? (int)targ->thread_id + : (int)(targ->thread_id + targ->threads); + char *expected_result = + i % 2 ? expected_result1 : expected_result2; + struct vdm_operation_future set = pmem2_memset_async( + targ->map, targ->addr, number, array_size, 0); + + FUTURE_BUSY_POLL(&set); + + if (memcmp(expected_result, targ->addr, TEST_SIZE)) + UT_FATAL("data should be equal"); + } + FREE(expected_result1); + FREE(expected_result2); + return NULL; +} + +/* + * test_mover_memset_multithreaded -- multi-threaded test for the mover's memset + */ +static int +test_mover_memset_multithreaded(const struct test_case *tc, int argc, + char *argv[]) +{ + if (argc < 2) + UT_FATAL( + "usage: test_mover_memset_multithreaded <file> <threads>"); + + char *file = argv[0]; + int fd = OPEN(file, O_RDWR); + unsigned long num_threads = STRTOUL(argv[1], NULL, 10); + + struct pmem2_source *src; + struct pmem2_config *cfg; + PMEM2_PREPARE_CONFIG_INTEGRATION(&cfg, &src, fd, + PMEM2_GRANULARITY_PAGE); + + struct pmem2_map *map = map_valid(cfg, src); + + UT_ASSERT(pmem2_map_get_size(map) >= TEST_SIZE * num_threads); + + os_thread_t *threads = MALLOC(num_threads * sizeof(*threads)); + struct thread_arg *args = MALLOC(num_threads * sizeof(*args)); + + char *data = pmem2_map_get_address(map); + for (unsigned i = 0; i < num_threads; i++) { + args[i].map = map; + args[i].addr = data + i * TEST_SIZE; + args[i].threads = num_threads; + args[i].thread_id = i; + + THREAD_CREATE(&threads[i], NULL, thread_memset_worker, &args[i]); } @@ -206,10 +489,13 @@ test_miniasync_mover(const struct test_case *tc, int argc, char *argv[]) * test_cases -- available test cases */ static struct test_case test_cases[] = { - TEST_CASE(test_mover_basic), - TEST_CASE(test_mover_multithreaded), - TEST_CASE(test_miniasync_mover) -}; + TEST_CASE(test_mover_memcpy_basic), + TEST_CASE(test_mover_memmove_basic), + TEST_CASE(test_mover_memset_basic), + TEST_CASE(test_mover_memcpy_multithreaded), + TEST_CASE(test_mover_memmove_multithreaded), + TEST_CASE(test_mover_memset_multithreaded), + TEST_CASE(test_miniasync_mover)}; #define NTESTS (sizeof(test_cases) / sizeof(test_cases[0])) diff --git a/src/test/scope/out13.log.match b/src/test/scope/out13.log.match index 0cd04d146f37ec950b02696c3bbb98ba2135fd1c..bf6639cb2ef2baaada9f8fb10e0b380631a5531a 100644 --- a/src/test/scope/out13.log.match +++ b/src/test/scope/out13.log.match @@ -26,6 +26,8 @@ pmem2_map_get_size$(nW) pmem2_map_get_store_granularity$(nW) pmem2_map_new$(nW) pmem2_memcpy_async$(nW) +pmem2_memmove_async$(nW) +pmem2_memset_async$(nW) pmem2_perror$(nW) pmem2_source_alignment$(nW) pmem2_source_delete$(nW) diff --git a/src/test/scope/out14.log.match b/src/test/scope/out14.log.match index e64fd58b04d723535c18e607bbd1f613e6878adb..63f642cd626bc759104c59accd4a8dca86544b41 100644 --- a/src/test/scope/out14.log.match +++ b/src/test/scope/out14.log.match @@ -28,6 +28,8 @@ pmem2_map_get_size pmem2_map_get_store_granularity pmem2_map_new pmem2_memcpy_async +pmem2_memmove_async +pmem2_memset_async pmem2_perrorU pmem2_perrorW pmem2_source_alignment diff --git a/utils/docker/images/Dockerfile.fedora-31 b/utils/docker/images/Dockerfile.fedora-31 index ff95935999d0cedf3e7dddca9f156cd683febf16..95389b9ecea4fc09f6a7bc833434b06e43d713e7 100644 --- a/utils/docker/images/Dockerfile.fedora-31 +++ b/utils/docker/images/Dockerfile.fedora-31 @@ -1,5 +1,5 @@ # SPDX-License-Identifier: BSD-3-Clause -# Copyright 2016-2020, Intel Corporation +# Copyright 2016-2022, Intel Corporation # # Dockerfile - a 'recipe' for Docker to build an image of fedora-based diff --git a/utils/docker/images/Dockerfile.fedora-35 b/utils/docker/images/Dockerfile.fedora-35 index 4a89989ecc1dcda45f56521c42de5a16804b7c76..5d07c11f26b55dd9c79f1501946349c22ce49b33 100644 --- a/utils/docker/images/Dockerfile.fedora-35 +++ b/utils/docker/images/Dockerfile.fedora-35 @@ -1,5 +1,5 @@ # SPDX-License-Identifier: BSD-3-Clause -# Copyright 2016-2020, Intel Corporation +# Copyright 2016-2022, Intel Corporation # # Dockerfile - a 'recipe' for Docker to build an image of fedora-based diff --git a/utils/docker/images/Dockerfile.ubuntu-20.04 b/utils/docker/images/Dockerfile.ubuntu-20.04 index 8b201a85a0de1a626671363996ac7b20b8ab6212..7d0d4acc1dfc754d0fe1451a99427255e83d8909 100644 --- a/utils/docker/images/Dockerfile.ubuntu-20.04 +++ b/utils/docker/images/Dockerfile.ubuntu-20.04 @@ -1,5 +1,5 @@ # SPDX-License-Identifier: BSD-3-Clause -# Copyright 2016-2020, Intel Corporation +# Copyright 2016-2022, Intel Corporation # # Dockerfile - a 'recipe' for Docker to build an image of ubuntu-based