Discussion:
how to return data from XS using minumum copy operations
(too old to reply)
Igor Sysoev
2006-04-05 20:02:50 UTC
Permalink
Hi,

is the effective way to return data from XS to perl without unnecessary
memory coping ? As I understand

1) if I return char*, then perl creates SV and copies the string to SV.

2) if I create SV using newSVpvn() and return it, then newSVpvn() copies
string to SV, then perl creates another SV (because my SV is mortal)
and again copies the string to its SV.

If I need to pass data with '\0's, then I have to use second way with
two copy operations. Is there way to set pointers only ?
And is there way to concatenate two memory blocks into one SV
using minumum copy operations ?


Igor Sysoev
http://sysoev.ru/en/
Igor Sysoev
2006-04-06 21:03:28 UTC
Permalink
Post by Igor Sysoev
is the effective way to return data from XS to perl without unnecessary
memory coping ? As I understand
1) if I return char*, then perl creates SV and copies the string to SV.
2) if I create SV using newSVpvn() and return it, then newSVpvn() copies
string to SV, then perl creates another SV (because my SV is mortal)
and again copies the string to its SV.
Sorry, I was mistaken. When perl creates another SV from my SV, it
copies the pointer only but not a whole data.


Igor Sysoev
http://sysoev.ru/en/
Sergey Skvortsov
2006-04-10 12:35:05 UTC
Permalink
This post might be inappropriate. Click to display it.
Igor Sysoev
2006-04-10 13:08:14 UTC
Permalink
Post by Sergey Skvortsov
Post by Igor Sysoev
is the effective way to return data from XS to perl without unnecessary
memory coping ? As I understand
1) if I return char*, then perl creates SV and copies the string to SV.
If you allocate *out with your own allocator (and *out must not be freed
char *my_c_func(const char *in, STLEN len_in, STLEN *len_out) {
char *out;
*len_out = len_in; // or other pre-calculated value
out = my_alloc(*len_out); // sic!
// process *in => *out
return out;
}
MODULE = XXX
PROTOTYPES: DISABLE
void
myfunc(in)
{
STRLEN len_in, len_out;
char *out;
char *in = SvPV(ST(0), len_in);
SV *res;
out = my_c_func(in, len, &len_out);
res = sv_newmortal();
sv_upgrade(sv, SVt_PV);
SvPOK_on(res);
SvPV_set(res, out);
SvLEN_set(res, len_out+1);
SvCUR_set(res, len_out);
SvFAKE_on(res); // trick!!!
SvREADONLY_on(res); // FAKE/READONLY will be reset
// on string change/normalization
// and PVX will be copied to new
// allocated string
ST(0) = res;
XSRETURN(1);
}
Thank you, Sergey. This is exactly what I need: I use own allocator
and my data should not be free()d by perl.
Post by Sergey Skvortsov
Fairly, there is even more speedup hacks. For example, you can use
TARG-macros, if you allocate string with Newx() call.
Could you explain in detail ?

By the way, is it possible to avoid creating my mortal SV and create just
perl SV ?


Igor Sysoev
http://sysoev.ru/en/
Sergey Skvortsov
2006-04-10 14:51:33 UTC
Permalink
This post might be inappropriate. Click to display it.
Marvin Humphrey
2006-04-09 18:31:47 UTC
Permalink
Post by Igor Sysoev
is the effective way to return data from XS to perl without
unnecessary
memory coping ?
Assuming that your C function can write to a passed in char* and that
you can know the length in advance, the best way is to create an SV
with a string buffer of sufficient length, write to the that buffer
directly, and put that SV on the stack.

SV*
efficient_read_from_c()
PREINIT:
SV *fresh_sv;
STRLEN len;
char *ptr;
CODE:
len = get_len();
SV* fresh_sv = newSV(len);
SvPOK_on(fresh_sv);
ptr = SvPVX(fresh_sv);
if (get_string(ptr))
SvCUR_set(fresh_sv, len);
*SvEND(fresh_sv) = '\0';
RETVAL = fresh_sv;
OUTPUT: RETVAL

This same subject was just discussed at some length on PerlMonks:
<http://www.perlmonks.org/index.pl?node_id=541706>.

Marvin Humphrey
Rectangular Research
http://www.rectangular.com/
Marvin Humphrey
2006-04-09 19:14:02 UTC
Permalink
On Apr 9, 2006, at 11:31 AM, Marvin Humphrey wrote:

I was a mite hasty. The code I provided would segfault if get_len()
ever returned 0. Here's one fix:

CODE:
len = get_len();
+ len = len ? len : 1;
SV* fresh_sv = newSV(len);
SvPOK_on(fresh_sv);

Marvin Humphrey
Rectangular Research
http://www.rectangular.com/
Loading...