diff options
author | Rickard Green <rickard@erlang.org> | 2019-09-02 12:40:04 +0200 |
---|---|---|
committer | Rickard Green <rickard@erlang.org> | 2019-09-02 12:40:04 +0200 |
commit | 227e54b53b95795f8fdce709458efb3edc8281f4 (patch) | |
tree | e3b97a530d5a4625caebe6d5592cb4e3afdf0ad4 /erts | |
parent | 7ac1f050adfbd31cd7c3e2e31e50a6a3cae03936 (diff) | |
parent | aab2b66cf88933ad184146893060ba15f599822a (diff) | |
download | erlang-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.c | 100 |
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; } } |