From c50cceb0def3e0123e92cee41bd9b6dde8bf2a75 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Mon, 20 Jun 2016 18:32:47 +0200 Subject: erts: Optimize spawn driver for large(r) environments that need to be enqueued. --- erts/emulator/sys/unix/sys_drivers.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'erts') diff --git a/erts/emulator/sys/unix/sys_drivers.c b/erts/emulator/sys/unix/sys_drivers.c index 812112fb91..e08ef41817 100644 --- a/erts/emulator/sys/unix/sys_drivers.c +++ b/erts/emulator/sys/unix/sys_drivers.c @@ -765,9 +765,14 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name, if (res < (buffsz + sizeof(buffsz))) { /* we only wrote part of the command payload. Enqueue the rest. */ for (i = 0; i < iov_len; i++) { - driver_enq(port_num, io_vector[i].iov_base, io_vector[i].iov_len); + if (res >= io_vector[i].iov_len) + res -= io_vector[i].iov_len; + else { + driver_enq(port_num, io_vector[i].iov_base + res, + io_vector[i].iov_len - res); + res = 0; + } } - driver_deq(port_num, res); driver_select(port_num, ofd[1], ERL_DRV_WRITE|ERL_DRV_USE, 1); } -- cgit v1.2.3 From 4fb4d6c57a987f58915f21af5a6321c5228b45dc Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 21 Jun 2016 19:07:23 +0200 Subject: erts: Add test port_SUITE:pipe_limit_env for 9f779819f6bda734c595. --- erts/emulator/sys/unix/sys_drivers.c | 4 +++ erts/emulator/test/port_SUITE.erl | 51 ++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) (limited to 'erts') diff --git a/erts/emulator/sys/unix/sys_drivers.c b/erts/emulator/sys/unix/sys_drivers.c index e08ef41817..3d7be020e1 100644 --- a/erts/emulator/sys/unix/sys_drivers.c +++ b/erts/emulator/sys/unix/sys_drivers.c @@ -688,6 +688,10 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name, return ERL_DRV_ERROR_ERRNO; } + /* + * Whitebox test port_SUITE:pipe_limit_env + * assumes this command payload format. + */ io_vector[i].iov_base = (void*)&buffsz; io_vector[i++].iov_len = sizeof(buffsz); diff --git a/erts/emulator/test/port_SUITE.erl b/erts/emulator/test/port_SUITE.erl index ee07699884..c9901ba610 100644 --- a/erts/emulator/test/port_SUITE.erl +++ b/erts/emulator/test/port_SUITE.erl @@ -91,6 +91,7 @@ exit_status/1, exit_status_multi_scheduling_block/1, huge_env/1, + pipe_limit_env/1, input_only/1, iter_max_ports/1, line/1, @@ -158,6 +159,7 @@ all() -> {group, multiple_packets}, parallell, dying_port, port_program_with_path, open_input_file_port, open_output_file_port, name1, env, huge_env, bad_env, cd, + pipe_limit_env, bad_args, exit_status, iter_max_ports, count_fds, t_exit, {group, tps}, line, stderr_to_stdout, otp_3906, otp_4389, win_massive, @@ -1002,6 +1004,55 @@ huge_env(Config) when is_list(Config) -> ct:fail("Open port failed ~p:~p",[E,R]) end. +%% Test to spawn program with command payload buffer +%% just around pipe capacity (9f779819f6bda734c5953468f7798) +pipe_limit_env(Config) when is_list(Config) -> + Cmd = "true", + CmdSize = command_payload_size(Cmd), + Limits = [4096, 16384, 65536], % Try a couple of common pipe buffer sizes + + lists:foreach(fun(Lim) -> + lists:foreach(fun(L) -> pipe_limit_env_do(L, Cmd, CmdSize) + end, lists:seq(Lim-5, Lim+5)) + end, Limits), + ok. + +pipe_limit_env_do(Bytes, Cmd, CmdSize) -> + case env_of_bytes(Bytes-CmdSize) of + [] -> skip; + Env -> + try erlang:open_port({spawn,Cmd},[exit_status, {env, Env}]) of + P -> + receive + {P, {exit_status,N}} = M -> + %% Bug caused exit_status 150 (EINVAL+128) + 0 = N + end + catch E:R -> + %% Have to catch the error here, as printing the stackdump + %% in the ct log is way to heavy for some test machines. + ct:fail("Open port failed ~p:~p",[E,R]) + end + end. + +%% environ format: KEY=VALUE\0 +env_of_bytes(Bytes) when Bytes > 3 -> + Env = [{"X",lists:duplicate(Bytes-3, $x)}]; +env_of_bytes(_) -> []. + +%% White box assumption about payload written to pipe +%% for Cmd and current environment (see spawn_start in sys_driver.c) +command_payload_size(Cmd) -> + EnvSize = lists:foldl(fun(E,Acc) -> length(E) + 1 + Acc end, + 0, os:getenv()), + {ok, PWD} = file:get_cwd(), + (4 % buffsz + + 4 % flags + + 5 + length(Cmd) + 1 % "exec $Cmd" + + length(PWD) + 1 % $PWD + + 1 % nullbuff + + 4 % env_len + + EnvSize). %% Test bad 'args' options. bad_args(Config) when is_list(Config) -> -- cgit v1.2.3 From a9ad9336a33ffbe0979a8e8e34bd69d0d87ede84 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 22 Jun 2016 19:27:50 +0200 Subject: erts: Fix etp-carrier-blocks for non smp --- erts/etc/unix/etp-commands.in | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'erts') diff --git a/erts/etc/unix/etp-commands.in b/erts/etc/unix/etp-commands.in index 15fb718c47..e2bf302cca 100644 --- a/erts/etc/unix/etp-commands.in +++ b/erts/etc/unix/etp-commands.in @@ -3581,9 +3581,24 @@ document etp-block %--------------------------------------------------------------------------- end +define etp-smp-atomic + if (etp_smp_compiled) + set $arg1 = (($arg0).counter) + else + set $arg1 = ($arg0) + end +end + +document etp-smp-atomic +%--------------------------------------------------------------------------- +% Read an erts_smp_atomic_t value from $arg0 into $arg1 +%--------------------------------------------------------------------------- +end + define etp-carrier-blocks set $etp_crr = (Carrier_t*) $arg0 - set $etp_alc = (Allctr_t*)($etp_crr->allctr.counter & ~7) + etp-smp-atomic $etp_crr->allctr $etp_alc + set $etp_alc = (Allctr_t*)($etp_alc & ~7) set $etp_crr_end = ((char*)$etp_crr + ($etp_crr->chdr & ~7) - (sizeof(void*) & ~8)) set $etp_blk = (Block_t*) ((char*)$etp_crr + $etp_alc->mbc_header_size) set $etp_prev_blk = 0 -- cgit v1.2.3