Mercurial > octave
changeset 30227:b00ff462e0f2
improve efficiency of mxArray -> octave_value conversion
* Array.h (Array<T>::ArrayRep, Array<T>::Array): New constructor that
accepts externally allocated data array.
* Sparse.h (Sparse<T>::SparseRep, Sparse<T>::Sparse): New constructor
that accepts externally allocated data and index arrays.
* mex.cc (maybe_disown_ptr): New function.
(mxArray_interleaved_full::fp_to_ov): Use new Array constructor to
pass allocated data from mxArray object to Array object without
copying data. Call maybe_disown_ptr on data pointer to give up
ownership.
(mxArray_interleaved_sparse::to_ov): Use new Array constructor to
pass allocated data from mxArray object to Array object without
copying data. Call maybe_disown_ptr on data pointer to give up
ownership.
(mxArray_separate_full::to_ov): New template.
(mxArray_separate_flll::as_octave_value): Use it.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Fri, 01 Oct 2021 15:25:51 -0400 |
parents | f3ffb4596bd8 |
children | 39a4ab124fd0 |
files | libinterp/corefcn/mex.cc liboctave/array/Array.h liboctave/array/Sparse.h |
diffstat | 3 files changed, 103 insertions(+), 80 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/corefcn/mex.cc Wed Sep 29 16:43:08 2021 -0400 +++ b/libinterp/corefcn/mex.cc Fri Oct 01 15:25:51 2021 -0400 @@ -352,6 +352,8 @@ static inline void * maybe_mark_foreign (void *ptr); +static inline void maybe_disown_ptr (void *ptr); + #define VOID_MUTATION_METHOD(FCN_NAME, ARG_LIST) \ void FCN_NAME ARG_LIST { request_mutation (); } @@ -1995,10 +1997,12 @@ switch (get_class_id ()) { case mxDOUBLE_CLASS: - return fp_to_ov<double> (dv); + return (is_complex () + ? fp_to_ov<Complex> (dv) : fp_to_ov<double> (dv)); case mxSINGLE_CLASS: - return fp_to_ov<float> (dv); + return (is_complex () + ? fp_to_ov<FloatComplex> (dv) : fp_to_ov<float> (dv)); case mxCHAR_CLASS: return int_to_ov<mxChar, charNDArray, char> (dv); @@ -2051,36 +2055,13 @@ octave_value fp_to_ov (const dim_vector& dv) const { - if (is_complex ()) - { - std::complex<ELT_T> *ppr = static_cast<std::complex<ELT_T> *> (m_pr); - - Array<std::complex<ELT_T>> val (dv); - - std::complex<ELT_T> *ptr = val.fortran_vec (); - - mwSize nel = get_number_of_elements (); - - for (mwIndex i = 0; i < nel; i++) - ptr[i] = ppr[i]; - - return octave_value (val); - } - else - { - ELT_T *ppr = static_cast<ELT_T *> (m_pr); - - Array<ELT_T> val (dv); - - ELT_T *ptr = val.fortran_vec (); - - mwSize nel = get_number_of_elements (); - - for (mwIndex i = 0; i < nel; i++) - ptr[i] = ppr[i]; - - return octave_value (val); - } + ELT_T *ppr = static_cast<ELT_T *> (m_pr); + + Array<ELT_T> val (ppr, dv); + + maybe_disown_ptr (m_pr); + + return octave_value (val); } template <typename ELT_T, typename ARRAY_T, typename ARRAY_ELT_T> @@ -2092,6 +2073,11 @@ ELT_T *ppr = static_cast<ELT_T *> (m_pr); +#if 0 + ARRAY_T val (ppr, dv); + + maybe_disown_ptr (m_pr); +#else ARRAY_T val (dv); ARRAY_ELT_T *ptr = val.fortran_vec (); @@ -2100,6 +2086,7 @@ for (mwIndex i = 0; i < nel; i++) ptr[i] = ppr[i]; +#endif return octave_value (val); } @@ -2307,42 +2294,10 @@ switch (get_class_id ()) { case mxDOUBLE_CLASS: - { - mwSize nel = get_number_of_elements (); - - double *ppr = static_cast<double *> (m_pr); - - ComplexNDArray val (dv); - - Complex *ptr = val.fortran_vec (); - - double *ppi = static_cast<double *> (m_pi); - - for (mwIndex i = 0; i < nel; i++) - ptr[i] = Complex (ppr[i], ppi[i]); - - retval = val; - } - break; + return to_ov<double> (dv); case mxSINGLE_CLASS: - { - mwSize nel = get_number_of_elements (); - - float *ppr = static_cast<float *> (m_pr); - - FloatComplexNDArray val (dv); - - FloatComplex *ptr = val.fortran_vec (); - - float *ppi = static_cast<float *> (m_pi); - - for (mwIndex i = 0; i < nel; i++) - ptr[i] = FloatComplex (ppr[i], ppi[i]); - - retval = val; - } - break; + return to_ov<float> (dv); case mxLOGICAL_CLASS: case mxINT8_CLASS: @@ -2376,6 +2331,26 @@ private: + template <typename T> + octave_value + to_ov (const dim_vector& dv) const + { + mwSize nel = get_number_of_elements (); + + T *ppr = static_cast<T *> (m_pr); + + Array<std::complex<T>> val (dv); + + std::complex<T> *ptr = val.fortran_vec (); + + T *ppi = static_cast<T *> (m_pi); + + for (mwIndex i = 0; i < nel; i++) + ptr[i] = std::complex<T> (ppr[i], ppi[i]); + + return octave_value (val); + } + // Pointer to the imaginary part of the data. void *m_pi; }; @@ -2481,16 +2456,18 @@ { octave_value retval; + dim_vector dv = dims_to_dim_vector (); + switch (get_class_id ()) { case mxDOUBLE_CLASS: - return is_complex () ? to_ov<Complex> (): to_ov<double> (); + return is_complex () ? to_ov<Complex> (dv): to_ov<double> (dv); case mxSINGLE_CLASS: error ("single precision sparse data type not supported"); case mxLOGICAL_CLASS: - return to_ov<bool> (); + return to_ov<bool> (dv); default: panic_impossible (); @@ -2503,21 +2480,16 @@ template <typename ELT_T> octave_value - to_ov (void) const + to_ov (const dim_vector& dv) const { ELT_T *ppr = static_cast<ELT_T *> (m_pr); - Sparse<ELT_T> val (get_m (), get_n (), - static_cast<octave_idx_type> (m_nzmax)); - - for (mwIndex i = 0; i < m_nzmax; i++) - { - val.xdata (i) = ppr[i]; - val.xridx (i) = m_ir[i]; - } - - for (mwIndex i = 0; i < get_n () + 1; i++) - val.xcidx (i) = m_jc[i]; + Sparse<ELT_T> val (dv, static_cast<octave_idx_type> (m_nzmax), + ppr, m_ir, m_jc); + + maybe_disown_ptr (m_pr); + maybe_disown_ptr (m_ir); + maybe_disown_ptr (m_jc); return octave_value (val); } @@ -2641,6 +2613,8 @@ octave_value retval; + dim_vector dv = dims_to_dim_vector (); + switch (get_class_id ()) { case mxDOUBLE_CLASS: @@ -3604,6 +3578,17 @@ return ptr; } +static inline void +maybe_disown_ptr (void *ptr) +{ + if (mex_context) + { + mex_context->unmark (ptr); + mex_context->global_unmark (ptr); + mex_context->mark_foreign (ptr); + } +} + static inline mxArray * maybe_unmark_array (mxArray *ptr) {
--- a/liboctave/array/Array.h Wed Sep 29 16:43:08 2021 -0400 +++ b/liboctave/array/Array.h Fri Oct 01 15:25:51 2021 -0400 @@ -167,6 +167,10 @@ std::fill_n (m_data, n, val); } + explicit ArrayRep (T *ptr, const dim_vector& dv) + : m_data (ptr), m_len (dv.safe_numel ()), m_count (1) + { } + ArrayRep (const ArrayRep& a) : m_data (new T [a.m_len]), m_len (a.m_len), m_count (1) { @@ -271,6 +275,20 @@ m_dimensions.chop_trailing_singletons (); } + // Construct an Array from a pointer to an externally allocated array + // of values. PTR must be allocated with operator new. The Array + // object takes ownership of PTR and will delete it when the Array + // object is deleted. The dimension vector DV must be consistent with + // the size of the allocated PTR array. + + explicit Array (T *ptr, const dim_vector& dv) + : m_dimensions (dv), + m_rep (new typename Array<T>::ArrayRep (ptr, dv)), + m_slice_data (m_rep->m_data), m_slice_len (m_rep->m_len) + { + m_dimensions.chop_trailing_singletons (); + } + //! Reshape constructor. OCTARRAY_API Array (const Array<T>& a, const dim_vector& dv);
--- a/liboctave/array/Sparse.h Wed Sep 29 16:43:08 2021 -0400 +++ b/liboctave/array/Sparse.h Fri Oct 01 15:25:51 2021 -0400 @@ -113,6 +113,13 @@ std::copy_n (c, nc + 1, m_cidx); } + template <typename U> + SparseRep (const dim_vector& dv, octave_idx_type nz, + U *d, octave_idx_type *r, octave_idx_type *c) + : m_data (d), m_ridx (r), m_cidx (c), + m_nzmax (nz), m_nrows (dv(0)), m_ncols (dv(1)), m_count (1) + { } + SparseRep (const SparseRep& a) : m_data (new T [a.m_nzmax]), m_ridx (new octave_idx_type [a.m_nzmax]), m_cidx (new octave_idx_type [a.m_ncols + 1]), @@ -218,6 +225,19 @@ : m_rep (new typename Sparse<T>::SparseRep (nr, nc, nz)), m_dimensions (dim_vector (nr, nc)) { } + // Construct a Sparse array from pointers to externally allocated + // arrays of values and indices. PTR, RIDX, and CIDX must be + // allocated with operator new. The Sparse object takes ownership of + // these arrays and will delete them when the Sparse object is + // deleted. The dimension vector DV must be consistent with the sizes + // of the allocated PTR, CIDX, and RIDX arrays. + + Sparse (const dim_vector& dv, octave_idx_type nz, + T *ptr, octave_idx_type *ridx, octave_idx_type *cidx) + : m_rep (new typename Sparse<T>::SparseRep (dv, nz, ptr, ridx, cidx)), + m_dimensions (dv) + { } + // Both SparseMatrix and SparseBoolMatrix need this ctor, and this // is their only common ancestor. explicit OCTAVE_API Sparse (const PermMatrix& a);