High-level data manipulation through iterators. More...
#include <assert.h>#include <string.h>#include <Padico/Puk.h>#include <nm_config.h>

Go to the source code of this file.
Data Structures | |
| struct | nm_data_properties_s |
| block of static properties for a given data descriptor More... | |
| struct | nm_data_op_context_nop_s |
| struct | nm_data_op_context_copy_from_s |
| struct | nm_data_op_context_copy_to_s |
| struct | nm_data_op_context_dynamic_s |
| struct | nm_data_op_context_getprops_s |
| struct | nm_data_op_context_chunk_s |
| struct | nm_data_op_context_slicer_coroutine_s |
| struct | nm_data_op_s |
| struct | nm_data_ops_s |
| set of operations available on data type. More... | |
| struct | nm_data_s |
| a data descriptor, used to pack/unpack data from app layout to/from contiguous buffers More... | |
| struct | nm_datav_s |
| encapsulate a dynamic vector of nm_data More... | |
| struct | nm_data_null_s |
| data descriptor for 'null' data More... | |
| struct | value |
| struct | nm_data_contiguous_s |
| data descriptor for contiguous data More... | |
| struct | nm_data_iov_s |
| data descriptor for iov data (embedd iovec in nm_data) More... | |
| struct | nm_data_datav_s |
| data descriptor for datav in a nm_data (embedd a vector of nm_data in nm_data) More... | |
| struct | nm_data_excerpt_s |
| data as an excerpt of another data. More... | |
| struct | nm_data_coroutine_s |
| struct | nm_data_slicer_s |
| internal state of a data slicer. More... | |
Macros | |
| #define | _NM_DATA_CONTENT_SIZE 64 |
| maximum size of content descriptor for nm_data | |
| #define | NM_DATA_TYPE(ENAME, CONTENT_TYPE, OPS) |
| macro to generate typed functions to init/access data fields. | |
| #define | NM_DATAV_INIT_SIZE 4 |
| initial size of an nm_datav | |
| #define | NM_DATA_OP_APPLY_LOOP_REF(I, COUNT, PTR, LEN, P_OP) |
| apply an op in a loop, reference implementation I is a loop counter COUNT is the total number of iterations PTR is a pointer to a block, expressed using index I LEN is the length of the block P_OP is the data operation to apply to each block | |
| #define | NM_DATA_OP_APPLY_KIND_LEN(I, OP_KIND, START, COUNT, PTR, LEN, P_OP) |
| generate a loop specialized for the given op kind and given LEN. | |
| #define | NM_DATA_OP_APPLY_KIND_VECT(I, OP_KIND, START, COUNT, PTR, LEN, P_OP) |
| generate a loop specialized for the given op kind. | |
| #define | NM_DATA_OP_APPLY_LOOP_OPT(I, COUNT, PTR, LEN, P_OP) |
| apply an op in a loop, optimized implementation: generate specialized (per op) inlined code likely to be vectorized by compiler | |
| #define | NM_DATA_OP_APPLY_LOOP NM_DATA_OP_APPLY_LOOP_OPT |
| selector to switch easily between implementations | |
| #define | NM_DATA_SLICER_NULL ((struct nm_data_slicer_s){ .kind = NM_DATA_SLICER_NONE }) |
| a slicer attached to no data | |
Typedefs | |
| typedef void(* | nm_data_apply_t) (void *ptr, nm_len_t len, void *_context) |
| function to apply to each data chunk upon traversal | |
| typedef enum nm_data_op_kind_e | nm_data_op_t |
| operation to apply to data in traversal & slicer | |
| typedef 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. | |
| typedef void(* | nm_data_properties_compute_t) (struct nm_data_s *p_data) |
| function to compute data properties | |
| typedef void(* | nm_data_coroutine_worker_t) (struct nm_data_coroutine_s *p_coroutine, void *_user_data) |
| typedef enum nm_data_coroutine_kind_e | nm_data_coroutine_kind_t |
| typedef struct nm_data_slicer_s | nm_data_slicer_t |
| internal state of a data slicer. | |
Enumerations | |
| enum | nm_data_op_kind_e { NM_DATA_OP_NONE = 0 , NM_DATA_OP_NOP , NM_DATA_OP_COPY_FROM , NM_DATA_OP_COPY_TO , NM_DATA_OP_DYNAMIC , NM_DATA_OP_GETPROPS , NM_DATA_OP_CHUNK , NM_DATA_OP_SLICER_COROUTINE } |
| operation to apply to data in traversal & slicer More... | |
| enum | nm_data_coroutine_kind_e { NM_DATA_COROUTINE_NONE , NM_DATA_COROUTINE_UCONTEXT , NM_DATA_COROUTINE_LONGJMP } |
| enum | nm_data_slicer_kind_t { NM_DATA_SLICER_NONE = 0 , NM_DATA_SLICER_COROUTINE , NM_DATA_SLICER_CONTIG } |
| various kinds of slicer implementations More... | |
Functions | |
| void | nm_data_default_properties_compute (struct nm_data_s *p_data) |
| static void | nm_data_propertie_gpu_preinit (struct nm_data_properties_s *p_props) |
| pre-init GPU part of data properties | |
| 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 GPU part. | |
| 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' | |
| static void | nm_datav_init (struct nm_datav_s *p_datav) |
| initialize a datav | |
| static void | nm_datav_destroy (struct nm_datav_s *p_datav) |
| destroys a datav | |
| 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. | |
| 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 | |
| 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. | |
| 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 | |
| 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. | |
| 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) | |
| 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) |
| 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) |
| 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) |
| 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) |
| 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) |
| 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) |
| 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) |
| __attribute__ ((unused)) static inline void nm_data_null_set(struct nm_data_s *p_data | |
| assert (p_data->ops.p_traversal !=NULL) | |
| if (p_data->ops.p_properties_compute==NULL) | |
| assert (sizeof(struct nm_data_null_s)<=64) | |
| static void | nm_data_null_build (struct nm_data_s *p_data) |
| static int | nm_data_isnull (struct nm_data_s *p_data) |
| assert (sizeof(struct nm_data_contiguous_s)<=64) | |
| static void | nm_data_contiguous_build (struct nm_data_s *p_data, void *ptr, nm_len_t len) |
| assert (sizeof(struct nm_data_iov_s)<=64) | |
| static void | nm_data_iov_build (struct nm_data_s *p_data, const struct iovec *v, int n) |
| assert (sizeof(struct nm_data_datav_s)<=64) | |
| 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 | |
| assert (sizeof(struct nm_data_excerpt_s)<=64) | |
| 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. | |
| static void | nm_data_traversal_op_apply (const struct nm_data_s *p_data, struct nm_data_op_s *p_op) |
| 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 | |
| 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) |
| 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) |
| 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 | |
| static nm_len_t | nm_data_size (const struct nm_data_s *p_data) |
| returns the amount of data contained in the descriptor | |
| 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_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 | |
| 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 | |
| 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 | |
| uint32_t | nm_data_checksum (const struct nm_data_s *p_data) |
| checksum data | |
| 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_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_copy (struct nm_data_s *p_dest, struct nm_data_s *p_from) |
| copy from nm_data to another nm_data | |
| void | nm_data_coroutine_yield_to_caller (struct nm_data_coroutine_s *p_coroutine) |
| void | nm_data_coroutine_yield_to_data (struct nm_data_coroutine_s *p_coroutine) |
| static int | nm_data_slicer_isnull (const nm_data_slicer_t *p_slicer) |
| tests whether a slicer is null | |
| void | nm_data_slicer_init (nm_data_slicer_t *p_slicer, const struct nm_data_s *p_data) |
| void | nm_data_slicer_copy_from (nm_data_slicer_t *p_slicer, void *dest_ptr, nm_len_t slice_len) |
| void | nm_data_slicer_copy_to (nm_data_slicer_t *p_slicer, const void *src_ptr, nm_len_t slice_len) |
| void | nm_data_slicer_forward (nm_data_slicer_t *p_slicer, nm_len_t offset) |
| void | nm_data_slicer_destroy (nm_data_slicer_t *p_slicer) |
| static void | nm_data_propertie_gpu_preinit (struct nm_data_properties_s *p_props __attribute__((unused))) |
| static void | nm_data_propertie_gpu_postinit (const struct nm_data_properties_s *p_props __attribute__((unused))) |
| 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. | |
| 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. | |
Variables | |
| const struct nm_data_ops_s | nm_data_ops_null |
| p_data | ops = *( &nm_data_ops_null ) |
| struct nm_data_null_s * | p_content = ( struct nm_data_null_s *)&p_data->_content[0] |
| p_data props | blocks = -1 |
| nm_data_propertie_gpu_preinit & | p_data |
| struct nm_data_contiguous_s | __attribute__ |
| const struct nm_data_ops_s | nm_data_ops_contiguous |
| const struct nm_data_ops_s | nm_data_ops_iov |
| const struct nm_data_ops_s | nm_data_ops_datav |
| const struct nm_data_ops_s | nm_data_ops_excerpt |
Detailed Description
High-level data manipulation through iterators.
Definition in file nm_data.h.
Macro Definition Documentation
◆ NM_DATA_OP_APPLY_KIND_LEN
| #define NM_DATA_OP_APPLY_KIND_LEN | ( | I, | |
| OP_KIND, | |||
| START, | |||
| COUNT, | |||
| PTR, | |||
| LEN, | |||
| P_OP | |||
| ) |
generate a loop specialized for the given op kind and given LEN.
Not to be used by end-user.
◆ NM_DATA_OP_APPLY_KIND_VECT
| #define NM_DATA_OP_APPLY_KIND_VECT | ( | I, | |
| OP_KIND, | |||
| START, | |||
| COUNT, | |||
| PTR, | |||
| LEN, | |||
| P_OP | |||
| ) |
generate a loop specialized for the given op kind.
Distinguish cases for fixed len likely to be vectorized by compiler. Not to be used by end-user.
◆ NM_DATA_OP_APPLY_LOOP
| #define NM_DATA_OP_APPLY_LOOP NM_DATA_OP_APPLY_LOOP_OPT |
◆ NM_DATA_OP_APPLY_LOOP_OPT
| #define NM_DATA_OP_APPLY_LOOP_OPT | ( | I, | |
| COUNT, | |||
| PTR, | |||
| LEN, | |||
| P_OP | |||
| ) |
◆ NM_DATA_OP_APPLY_LOOP_REF
| #define NM_DATA_OP_APPLY_LOOP_REF | ( | I, | |
| COUNT, | |||
| PTR, | |||
| LEN, | |||
| P_OP | |||
| ) |
apply an op in a loop, reference implementation I is a loop counter COUNT is the total number of iterations PTR is a pointer to a block, expressed using index I LEN is the length of the block P_OP is the data operation to apply to each block
Function Documentation
◆ __attribute__()
◆ assert() [1/6]
| assert | ( | p_data->ops.p_traversal ! | = NULL | ) |
- Examples
- nm_sr_peek.c.
Referenced by nm_coll_datav_descendants(), nm_coll_ipow(), nm_coll_log2_ceil(), nm_coll_log2_floor(), nm_coll_log_n_ceil(), nm_coll_log_n_floor(), nm_coll_tree_issend(), nm_coll_tree_recv(), nm_coll_tree_req_index(), nm_coll_tree_send(), nm_coll_tree_status_destroy(), nm_core_polling_level(), nm_core_tag_match(), nm_core_task_enqueue(), nm_data_traversal_op_apply(), nm_datav_add_chunk_data(), nm_datav_destroy(), nm_datav_uncommit(), nm_gate_set_active(), nm_gate_trk_get(), nm_gtag_dtor(), nm_header_global_finalize(), nm_header_global_v0len(), nm_header_init_data(), nm_header_init_pkt_data(), nm_header_init_rdv(), nm_ibverbs_cnx_lazy_get_oob(), nm_minidriver_connect(), nm_minidriver_properties_normalize(), nm_minidriver_rpoll(), nm_minidriver_send_pkt_build(), nm_mpi_communicator_get_dest(), nm_mpi_communicator_get_gate(), nm_mpi_request_add_datatype2(), nm_mpi_win_valid_assert(), nm_ofi_common_init(), nm_ofi_display_all(), nm_pw_assign(), nm_pw_completed_enqueue(), nm_pw_ref_dec(), nm_pw_ref_dec_free(), nm_pw_remaining_buf(), nm_refcount_dec(), nm_refcount_inc_internal(), nm_req_chunk_init(), nm_req_chunk_submit(), nm_req_chunk_update(), nm_rpc_recv_header_data(), nm_rpc_req_wait_all(), nm_seq_compare(), nm_seq_next(), nm_spin_assert_locked(), nm_spin_assert_notlocked(), nm_spin_check_nothread(), nm_spin_clear_nothread(), nm_spin_destroy(), nm_spin_trylock(), nm_spin_unlock(), nm_sr_recv_data_size_wait(), nm_sr_recv_data_test(), nm_sr_recv_data_wait(), nm_sr_request_get_expected_size(), nm_sr_request_wait_all(), nm_status_assert(), nm_status_wait(), nm_tactic_req_short_size(), nm_trk_can_recv(), nm_trk_can_send(), and nm_trk_get_by_index().
◆ assert() [2/6]
| __attribute__::assert | ( | sizeof(struct nm_data_contiguous_s)<= | 64 | ) |
◆ assert() [3/6]
| __attribute__::assert | ( | sizeof(struct nm_data_datav_s)<= | 64 | ) |
◆ assert() [4/6]
| __attribute__::assert | ( | sizeof(struct nm_data_excerpt_s)<= | 64 | ) |
◆ assert() [5/6]
| __attribute__::assert | ( | sizeof(struct nm_data_iov_s)<= | 64 | ) |
◆ assert() [6/6]
| __attribute__::assert | ( | sizeof(struct nm_data_null_s)<= | 64 | ) |
◆ if()
◆ nm_data_contiguous_build()
|
inlinestatic |
- Examples
- nm_mcast_basic.c, nm_onesided_simple.c, and nm_sr_peek.c.
Definition at line 560 of file nm_data.h.
References nm_data_contiguous_s::len, len, p_data, and nm_data_contiguous_s::ptr.
Referenced by nm_datav_add_chunk(), nm_minidriver_recv_pkt_build(), nm_minidriver_send_pkt_build(), nm_rpc_irecv_body(), nm_rpc_recv_header(), nm_sr_recv_unpack_contiguous(), and nm_sr_send_pack_contiguous().
◆ nm_data_datav_build()
|
inlinestatic |
frontend to build a nm_data from a datav
Definition at line 598 of file nm_data.h.
References nm_datav_s::commited, and nm_data_datav_s::p_datav.
Referenced by nm_rpc_recv_header_data().
◆ nm_data_excerpt_build()
|
inlinestatic |
build a data descriptor as an excerpt of another data.
- Note
- p_inner_data is not copied; it must stay allocated as long as the excerpt
Definition at line 620 of file nm_data.h.
References nm_data_excerpt_s::chunk_len, chunk_len, nm_data_excerpt_s::chunk_offset, chunk_offset, p_data, and nm_data_excerpt_s::p_data.
Referenced by nm_datav_add_chunk_excerpt().
◆ nm_data_iov_build()
|
inlinestatic |
Definition at line 579 of file nm_data.h.
References nm_data_iov_s::n, p_data, and nm_data_iov_s::v.
Referenced by nm_sr_recv_unpack_iov(), and nm_sr_send_pack_iov().
◆ nm_data_isnull()
|
inlinestatic |
Definition at line 544 of file nm_data.h.
References nm_data_ops_null, p_data, and nm_data_ops_s::p_traversal.
◆ nm_data_memcpy_from()
|
inlinestatic |
copy chunks of data.
p_src is in a nm_data, maybe in GPU memory p_dest is in host memory
Definition at line 914 of file nm_data.h.
Referenced by nm_data_op_apply_copy_from().
◆ nm_data_memcpy_to()
|
inlinestatic |
copy chunks of data.
p_dest is in a nm_data, maybe in GPU memory p_src is in host memory
Definition at line 948 of file nm_data.h.
Referenced by nm_data_op_apply_copy_to().
◆ nm_data_null_build()
|
inlinestatic |
◆ nm_data_op_apply()
|
inlinestatic |
apply op on block (p_ptr, len)
- Examples
- nm_sr_custom_data.c.
Definition at line 1066 of file nm_data.h.
References len, nm_data_op_apply_chunk(), nm_data_op_apply_copy_from(), nm_data_op_apply_copy_to(), nm_data_op_apply_dynamic(), nm_data_op_apply_getprops(), nm_data_op_apply_nop(), nm_data_op_apply_slicer_coroutine(), NM_DATA_OP_CHUNK, NM_DATA_OP_COPY_FROM, NM_DATA_OP_COPY_TO, NM_DATA_OP_DYNAMIC, NM_DATA_OP_GETPROPS, NM_DATA_OP_NONE, NM_DATA_OP_NOP, NM_DATA_OP_SLICER_COROUTINE, NM_FATAL, and p_op.
Referenced by flypack_traversal(), nm_data_op_apply_chunk(), and nm_data_op_apply_slicer_coroutine().

◆ nm_data_op_apply_chunk()
|
inlinestatic |
Definition at line 1021 of file nm_data.h.
References chunk_len, chunk_offset, len, and nm_data_op_apply().
Referenced by nm_data_op_apply().

◆ nm_data_op_apply_copy_from()
|
inlinestatic |
Definition at line 986 of file nm_data.h.
References len, and nm_data_memcpy_from().
Referenced by nm_data_op_apply().

◆ nm_data_op_apply_copy_to()
|
inlinestatic |
Definition at line 992 of file nm_data.h.
References len, and nm_data_memcpy_to().
Referenced by nm_data_op_apply().

◆ nm_data_op_apply_dynamic()
|
inlinestatic |
◆ nm_data_op_apply_getprops()
|
inlinestatic |
Definition at line 1003 of file nm_data.h.
References len, and nm_data_properties_gpu_fill().
Referenced by nm_data_op_apply().

◆ nm_data_op_apply_nop()
|
inlinestatic |
Definition at line 981 of file nm_data.h.
Referenced by nm_data_op_apply().
◆ nm_data_op_apply_slicer_coroutine()
|
inlinestatic |
Definition at line 1038 of file nm_data.h.
References chunk_len, nm_data_slicer_s::coroutine, len, nm_data_coroutine_yield_to_caller(), nm_data_op_apply(), and nm_data_slicer_s::slice_len.
Referenced by nm_data_op_apply().

◆ nm_data_propertie_gpu_postinit()
|
inlinestatic |
◆ nm_data_propertie_gpu_preinit()
|
inlinestatic |
Variable Documentation
◆ blocks
◆ nm_data_ops_contiguous
|
extern |
◆ nm_data_ops_datav
|
extern |
◆ nm_data_ops_excerpt
|
extern |
◆ nm_data_ops_iov
|
extern |
◆ nm_data_ops_null
|
extern |
Referenced by nm_data_isnull().
◆ ops
| p_data ops = *( &nm_data_ops_null ) |
◆ p_content
| * p_content = ( struct nm_data_null_s *)&p_data->_content[0] |
◆ p_data
| nm_data_propertie_gpu_postinit & p_data |
Definition at line 538 of file nm_data.h.
Referenced by nm_coll_datav_descendants(), nm_coll_tree_issend(), nm_coll_tree_recv(), nm_coll_tree_send(), nm_data_contiguous_build(), nm_data_excerpt_build(), nm_data_iov_build(), nm_data_isnull(), nm_data_null_build(), nm_data_properties_get(), nm_data_size(), nm_data_traversal_apply(), nm_data_traversal_op_apply(), nm_datav_add_chunk_data(), nm_datav_add_chunk_excerpt(), nm_mpi_data_build(), nm_sr_irecv_data(), nm_sr_isend_data(), nm_sr_recv_data(), nm_sr_recv_peek(), nm_sr_recv_peek_offset(), nm_sr_recv_unpack_data(), nm_sr_send_data(), nm_sr_send_pack_data(), nm_sync_clocks_bcast(), nm_sync_clocks_recv(), and nm_sync_clocks_send().