summaryrefslogtreecommitdiff
path: root/erts
diff options
context:
space:
mode:
authorRickard Green <rickard@erlang.org>2019-09-02 12:40:04 +0200
committerRickard Green <rickard@erlang.org>2019-09-02 12:40:04 +0200
commit227e54b53b95795f8fdce709458efb3edc8281f4 (patch)
treee3b97a530d5a4625caebe6d5592cb4e3afdf0ad4 /erts
parent7ac1f050adfbd31cd7c3e2e31e50a6a3cae03936 (diff)
parentaab2b66cf88933ad184146893060ba15f599822a (diff)
downloaderlang-227e54b53b95795f8fdce709458efb3edc8281f4.tar.gz
Merge branch 'rickard/port-bin-output/OTP-16001' into maint
* rickard/port-bin-output/OTP-16001: Output heap binaries from ports when data is small
Diffstat (limited to 'erts')
-rw-r--r--erts/emulator/beam/io.c100
1 files changed, 68 insertions, 32 deletions
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index 45fef0c0e5..1622330aab 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -3243,7 +3243,10 @@ static void deliver_read_message(Port* prt, erts_aint32_t state, Eterm to,
need += 3;
}
if ((state & ERTS_PORT_SFLG_BINARY_IO) && buf != NULL) {
- need += PROC_BIN_SIZE;
+ if (len <= ERL_ONHEAP_BIN_LIMIT)
+ need += heap_bin_size(len);
+ else
+ need += PROC_BIN_SIZE;
} else {
need += 2*len;
}
@@ -3261,11 +3264,21 @@ static void deliver_read_message(Port* prt, erts_aint32_t state, Eterm to,
if ((state & ERTS_PORT_SFLG_BINARY_IO) == 0) {
listp = buf_to_intlist(&hp, buf, len, listp);
} else if (buf != NULL) {
- Binary* bptr = erts_bin_nrml_alloc(len);
- sys_memcpy(bptr->orig_bytes, buf, len);
+ if (len <= ERL_ONHEAP_BIN_LIMIT) {
+ ErlHeapBin *hbin = (ErlHeapBin *) hp;
+ hbin->thing_word = header_heap_bin(len);
+ hbin->size = (Uint) len;
+ sys_memcpy(hbin->data, buf, len);
+ listp = make_binary(hp);
+ hp += heap_bin_size(len);
+ }
+ else {
+ Binary* bptr = erts_bin_nrml_alloc(len);
+ sys_memcpy(bptr->orig_bytes, buf, len);
- listp = erts_build_proc_bin(ohp, hp, bptr);
- hp += PROC_BIN_SIZE;
+ listp = erts_build_proc_bin(ohp, hp, bptr);
+ hp += PROC_BIN_SIZE;
+ }
}
/* Prepend the header */
@@ -3388,7 +3401,14 @@ deliver_vec_message(Port* prt, /* Port */
need = 3 + 3; /* Heap space for two tuples */
if (state & ERTS_PORT_SFLG_BINARY_IO) {
- need += (2+PROC_BIN_SIZE)*vsize - 2 + hlen*2;
+ Sint i;
+ for (i = 0; i < vsize; i++) {
+ if (iov[i].iov_len <= ERL_ONHEAP_BIN_LIMIT)
+ need += heap_bin_size(iov[i].iov_len);
+ else
+ need += PROC_BIN_SIZE;
+ }
+ need += (vsize - 1)*2 + hlen*2;
} else {
need += (hlen+csize)*2;
}
@@ -3408,36 +3428,52 @@ deliver_vec_message(Port* prt, /* Port */
} else {
binv += vsize;
while (vsize--) {
- ErlDrvBinary* b;
- ProcBin* pb = (ProcBin*) hp;
- byte* base;
-
- iov--;
- binv--;
- if ((b = *binv) == NULL) {
- b = driver_alloc_binary(iov->iov_len);
- sys_memcpy(b->orig_bytes, iov->iov_base, iov->iov_len);
- base = (byte*) b->orig_bytes;
- } else {
- /* Must increment reference count, caller calls free */
- driver_binary_inc_refc(b);
- base = iov->iov_base;
- }
- pb->thing_word = HEADER_PROC_BIN;
- pb->size = iov->iov_len;
- pb->next = ohp->first;
- ohp->first = (struct erl_off_heap_header*)pb;
- pb->val = ErlDrvBinary2Binary(b);
- pb->bytes = base;
- pb->flags = 0;
- hp += PROC_BIN_SIZE;
+ Eterm bin;
+ Uint bin_size;
+ iov--;
+ binv--;
+ bin_size = (Uint) iov->iov_len;
+
+ if (bin_size <= ERL_ONHEAP_BIN_LIMIT) {
+ ErlHeapBin *hbin = (ErlHeapBin *) hp;
+ hbin->thing_word = header_heap_bin(bin_size);
+ hbin->size = bin_size;
+ sys_memcpy(hbin->data, iov->iov_base, bin_size);
+ bin = make_binary(hp);
+ hp += heap_bin_size(bin_size);
+ }
+ else {
+ ErlDrvBinary* b;
+ ProcBin* pb = (ProcBin*) hp;
+ byte* base;
+
+ if ((b = *binv) == NULL) {
+ b = driver_alloc_binary(bin_size);
+ sys_memcpy(b->orig_bytes, iov->iov_base, bin_size);
+ base = (byte*) b->orig_bytes;
+ } else {
+ /* Must increment reference count, caller calls free */
+ driver_binary_inc_refc(b);
+ base = iov->iov_base;
+ }
+ pb->thing_word = HEADER_PROC_BIN;
+ pb->size = bin_size;
+ pb->next = ohp->first;
+ ohp->first = (struct erl_off_heap_header*)pb;
+ pb->val = ErlDrvBinary2Binary(b);
+ pb->bytes = base;
+ pb->flags = 0;
+ hp += PROC_BIN_SIZE;
- OH_OVERHEAD(ohp, iov->iov_len / sizeof(Eterm));
+ OH_OVERHEAD(ohp, bin_size / sizeof(Eterm));
+
+ bin = make_binary(pb);
+ }
if (listp == NIL) { /* compatible with deliver_bin_message */
- listp = make_binary(pb);
+ listp = bin;
} else {
- listp = CONS(hp, make_binary(pb), listp);
+ listp = CONS(hp, bin, listp);
hp += 2;
}
}