Skip to content

Commit ecdf684

Browse files
committed
Reduce footprint of tasks
Tasks were launched with proc_lib, which added additional processing on boot. We removed the proc_lib layer, which has the benefit of removing the double logging (which only happened on tasks but not any other behaviour).
1 parent 536dcb3 commit ecdf684

File tree

3 files changed

+35
-136
lines changed

3 files changed

+35
-136
lines changed

lib/elixir/lib/task.ex

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ defmodule Task do
1717
They are implemented by spawning a process that sends a message
1818
to the caller once the given computation is performed.
1919
20+
Compared to plain processes, started with `spawn/1`, tasks
21+
include monitoring metadata and logging in case of errors.
22+
2023
Besides `async/1` and `await/2`, tasks can also be
2124
started as part of a supervision tree and dynamically spawned
2225
on remote nodes. We will explore these scenarios next.

lib/elixir/lib/task/supervised.ex

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,20 @@ defmodule Task.Supervised do
33
@ref_timeout 5000
44

55
def start(owner, callers, fun) do
6-
{:ok, :proc_lib.spawn(__MODULE__, :noreply, [owner, callers, fun])}
6+
{:ok, spawn(__MODULE__, :noreply, [owner, get_ancestors(), callers, fun])}
77
end
88

99
def start_link(owner, callers, fun) do
10-
{:ok, :proc_lib.spawn_link(__MODULE__, :noreply, [owner, callers, fun])}
10+
{:ok, spawn_link(__MODULE__, :noreply, [owner, get_ancestors(), callers, fun])}
1111
end
1212

1313
def start_link(owner, monitor) do
14-
{:ok, :proc_lib.spawn_link(__MODULE__, :reply, [owner, monitor])}
14+
{:ok, spawn_link(__MODULE__, :reply, [owner, get_ancestors(), monitor])}
1515
end
1616

17-
def reply({_, _, owner_pid} = owner, monitor) do
17+
def reply({_, _, owner_pid} = owner, ancestors, monitor) do
18+
put_ancestors(ancestors)
19+
1820
case monitor do
1921
:monitor ->
2022
mref = Process.monitor(owner_pid)
@@ -28,7 +30,7 @@ defmodule Task.Supervised do
2830
defp reply(owner, owner_pid, mref, timeout) do
2931
receive do
3032
{^owner_pid, ref, reply_to, callers, mfa} ->
31-
initial_call(mfa)
33+
put_initial_call(mfa)
3234
put_callers(callers)
3335
_ = is_reference(mref) && Process.demonitor(mref, [:flush])
3436
send(reply_to, {ref, invoke_mfa(owner, mfa)})
@@ -60,24 +62,36 @@ defmodule Task.Supervised do
6062
end
6163
end
6264

63-
def noreply(owner, callers, mfa) do
64-
initial_call(mfa)
65+
def noreply(owner, ancestors, callers, mfa) do
66+
put_initial_call(mfa)
67+
put_ancestors(ancestors)
6568
put_callers(callers)
6669
invoke_mfa(owner, mfa)
6770
end
6871

72+
defp get_ancestors() do
73+
with {:dictionary, dictionary} <- Process.info(self(), :dictionary),
74+
{:"$ancestors", ancestors} <- :lists.keyfind(:"$ancestors", 1, dictionary) do
75+
[self() | ancestors]
76+
else
77+
_ -> [self()]
78+
end
79+
end
80+
81+
defp put_ancestors(ancestors) do
82+
Process.put(:"$ancestors", ancestors)
83+
end
84+
6985
defp put_callers(callers) do
7086
Process.put(:"$callers", callers)
7187
end
7288

73-
defp initial_call(mfa) do
89+
defp put_initial_call(mfa) do
7490
Process.put(:"$initial_call", get_initial_call(mfa))
7591
end
7692

7793
defp get_initial_call({:erlang, :apply, [fun, []]}) when is_function(fun, 0) do
78-
{:module, module} = Function.info(fun, :module)
79-
{:name, name} = Function.info(fun, :name)
80-
{module, name, 0}
94+
:erlang.fun_info_mfa(fun)
8195
end
8296

8397
defp get_initial_call({mod, fun, args}) do
@@ -116,10 +130,14 @@ defmodule Task.Supervised do
116130
}
117131
)
118132

119-
:erlang.raise(kind, value, __STACKTRACE__)
133+
:erlang.raise(:exit, exit_reason(kind, value, __STACKTRACE__), __STACKTRACE__)
120134
end
121135
end
122136

137+
defp exit_reason(:error, reason, stacktrace), do: {reason, stacktrace}
138+
defp exit_reason(:exit, reason, _stacktrace), do: reason
139+
defp exit_reason(:throw, reason, stacktrace), do: {{:nocatch, reason}, stacktrace}
140+
123141
defp log_value(:throw, value), do: {:nocatch, value}
124142
defp log_value(_, value), do: value
125143

lib/logger/test/logger/translator_test.exs

Lines changed: 2 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -315,37 +315,9 @@ defmodule Logger.TranslatorTest do
315315
"""s
316316

317317
assert_receive {:event, {:string, ["Task " <> _ | _]}, task_metadata}
318-
assert_receive {:event, {:string, ["Process " | _]}, process_metadata}
319-
320318
assert {%RuntimeError{message: "oops"}, [_ | _]} = task_metadata[:crash_reason]
321-
assert {%RuntimeError{message: "oops"}, [_ | _]} = process_metadata[:crash_reason]
322319
assert [parent] == task_metadata[:callers]
323-
324320
refute Map.has_key?(task_metadata, :initial_call)
325-
assert process_metadata[:initial_call] == {Logger.TranslatorTest, :task, 1}
326-
end
327-
328-
test "translates Task async_stream crashes with neighbour" do
329-
fun = fn -> Task.async_stream([:oops], :erlang, :error, []) |> Enum.to_list() end
330-
{:ok, pid} = Task.start(__MODULE__, :task, [self(), fun])
331-
parent = self()
332-
333-
assert capture_log(:debug, fn ->
334-
ref = Process.monitor(pid)
335-
send(pid, :go)
336-
receive do: ({:DOWN, ^ref, _, _, _} -> :ok)
337-
end) =~ ~r"""
338-
Neighbours:
339-
#{inspect(pid)}
340-
Initial Call: Logger\.TranslatorTest\.task/2
341-
"""
342-
343-
assert_receive {:event, {:string, ["Task " <> _ | _]}, task_metadata}
344-
assert_receive {:event, {:string, ["Process " | _]}, process_metadata}
345-
assert [pid, parent] == task_metadata[:callers]
346-
347-
assert {:oops, [_ | _]} = task_metadata[:crash_reason]
348-
assert {%ErlangError{original: :oops}, [_ | _]} = process_metadata[:crash_reason]
349321
end
350322

351323
test "translates Task undef module crash" do
@@ -364,11 +336,8 @@ defmodule Logger.TranslatorTest do
364336
"""s
365337

366338
assert_receive {:event, {:string, ["Task " <> _ | _]}, task_metadata}
367-
assert_receive {:event, {:string, ["Process " | _]}, process_metadata}
368339
assert [parent] == task_metadata[:callers]
369-
370340
assert {%UndefinedFunctionError{function: :undef}, [_ | _]} = task_metadata[:crash_reason]
371-
assert {%UndefinedFunctionError{function: :undef}, [_ | _]} = process_metadata[:crash_reason]
372341
end
373342

374343
test "translates Task undef function crash" do
@@ -387,11 +356,8 @@ defmodule Logger.TranslatorTest do
387356
"""s
388357

389358
assert_receive {:event, {:string, ["Task " <> _ | _]}, task_metadata}
390-
assert_receive {:event, {:string, ["Process " | _]}, process_metadata}
391359
assert [parent] == task_metadata[:callers]
392-
393360
assert {%UndefinedFunctionError{function: :undef}, [_ | _]} = task_metadata[:crash_reason]
394-
assert {%UndefinedFunctionError{function: :undef}, [_ | _]} = process_metadata[:crash_reason]
395361
end
396362

397363
test "translates Task raising ErlangError" do
@@ -418,11 +384,8 @@ defmodule Logger.TranslatorTest do
418384
"""s
419385

420386
assert_receive {:event, {:string, ["Task " <> _ | _]}, task_metadata}
421-
assert_receive {:event, {:string, ["Process " | _]}, process_metadata}
422387
assert [parent] == task_metadata[:callers]
423-
424388
assert {%ErlangError{original: :foo}, [_ | _]} = task_metadata[:crash_reason]
425-
assert {%ErlangError{original: :foo}, [_ | _]} = process_metadata[:crash_reason]
426389
end
427390

428391
test "translates Task raising Erlang badarg error" do
@@ -441,11 +404,8 @@ defmodule Logger.TranslatorTest do
441404
"""s
442405

443406
assert_receive {:event, {:string, ["Task " <> _ | _]}, task_metadata}
444-
assert_receive {:event, {:string, ["Process " | _]}, process_metadata}
445407
assert [parent] == task_metadata[:callers]
446-
447408
assert {%ArgumentError{message: "argument error"}, [_ | _]} = task_metadata[:crash_reason]
448-
assert {%ArgumentError{message: "argument error"}, [_ | _]} = process_metadata[:crash_reason]
449409
end
450410

451411
test "translates Task exiting abnormally" do
@@ -464,11 +424,8 @@ defmodule Logger.TranslatorTest do
464424
"""s
465425

466426
assert_receive {:event, {:string, ["Task " <> _ | _]}, task_metadata}
467-
assert_receive {:event, {:string, ["Process " | _]}, process_metadata}
468427
assert [parent] == task_metadata[:callers]
469-
470428
assert {:abnormal, [_ | _]} = task_metadata[:crash_reason]
471-
assert {:abnormal, [_ | _]} = process_metadata[:crash_reason]
472429
end
473430

474431
test "translates application start" do
@@ -598,7 +555,7 @@ defmodule Logger.TranslatorTest do
598555
end
599556

600557
test "translates :proc_lib crashes with neighbour" do
601-
{:ok, pid} = Task.start_link(__MODULE__, :sub_task, [self()])
558+
pid = :proc_lib.spawn_link(__MODULE__, :sub_task, [self()])
602559

603560
assert capture_log(:info, fn ->
604561
ref = Process.monitor(pid)
@@ -621,7 +578,7 @@ defmodule Logger.TranslatorTest do
621578
raise "oops"
622579
end
623580

624-
{:ok, pid} = Task.start_link(__MODULE__, :sub_task, [self(), fun])
581+
pid = :proc_lib.spawn_link(__MODULE__, :sub_task, [self(), fun])
625582

626583
assert capture_log(:info, fn ->
627584
ref = Process.monitor(pid)
@@ -638,66 +595,6 @@ defmodule Logger.TranslatorTest do
638595
"""
639596
end
640597

641-
test "translates :proc_lib+Task crashes on debug" do
642-
{:ok, pid} = Task.start_link(__MODULE__, :task, [self()])
643-
parent = self()
644-
645-
assert capture_log(:debug, fn ->
646-
ref = Process.monitor(pid)
647-
send(pid, :message)
648-
send(pid, :go)
649-
receive do: ({:DOWN, ^ref, _, _, _} -> :ok)
650-
end) =~ ~r"""
651-
Ancestors: \[#PID<\d+\.\d+\.\d+>\]
652-
Message Queue Length: 1
653-
Messages: \[:message\]
654-
Links: \[\]
655-
Dictionary: \["\$callers": \[#PID<\d+\.\d+\.\d+>\]\]
656-
Trapping Exits: false
657-
Status: :running
658-
Heap Size: \d+
659-
Stack Size: \d+
660-
Reductions: \d+
661-
"""
662-
663-
assert_receive {:event, {:string, ["Task " <> _ | _]}, task_metadata}
664-
assert_receive {:event, {:string, ["Process " | _]}, process_metadata}
665-
666-
assert process_metadata[:pid] == task_metadata[:pid]
667-
assert is_list(process_metadata[:callers])
668-
assert is_list(process_metadata[:ancestors])
669-
assert [parent] == task_metadata[:callers]
670-
671-
assert {%RuntimeError{message: "oops"}, [_ | _]} = task_metadata[:crash_reason]
672-
assert {%RuntimeError{message: "oops"}, [_ | _]} = process_metadata[:crash_reason]
673-
end
674-
675-
test "translates :proc_lib+Task crashes with neighbour on debug" do
676-
{:ok, pid} = Task.start_link(__MODULE__, :sub_task, [self()])
677-
parent = self()
678-
679-
assert capture_log(:debug, fn ->
680-
ref = Process.monitor(pid)
681-
send(pid, :message)
682-
send(pid, :go)
683-
receive do: ({:DOWN, ^ref, _, _, _} -> :ok)
684-
end) =~ ~r"""
685-
Ancestors: \[#PID<\d+\.\d+\.\d+>, #PID<\d+\.\d+\.\d+>\]
686-
Message Queue Length: 0
687-
Links: \[#PID<\d+\.\d+\.\d+>\]
688-
Trapping Exits: false
689-
Status: :waiting
690-
Heap Size: \d+
691-
Stack Size: \d+
692-
Reductions: \d+
693-
Current Stacktrace:
694-
(lib/logger/)?test/logger/translator_test.exs:\d+: Logger.TranslatorTest.sleep/1
695-
"""
696-
697-
assert_receive {:event, {:string, ["Task " <> _ | _]}, task_metadata}
698-
assert [parent] == task_metadata[:callers]
699-
end
700-
701598
test "translates Supervisor progress" do
702599
{:ok, pid} = Supervisor.start_link([], strategy: :one_for_one)
703600

@@ -814,12 +711,9 @@ defmodule Logger.TranslatorTest do
814711
"""
815712

816713
assert_receive {:event, {:string, ["Task " <> _ | _]}, task_metadata}
817-
assert_receive {:event, {:string, ["Process " | _]}, process_metadata}
818714
assert_receive {:event, {:string, ["Child " | _]}, _child_metadata}
819715
assert_receive {:event, {:string, ["Child ", "Task" | _]}, _child_task_metadata}
820-
821716
assert {:stop, [_ | _]} = task_metadata[:crash_reason]
822-
assert {:stop, [_ | _]} = process_metadata[:crash_reason]
823717
end
824718

825719
test "translates Supervisor reports max restarts shutdown" do
@@ -836,12 +730,9 @@ defmodule Logger.TranslatorTest do
836730
"""
837731

838732
assert_receive {:event, {:string, ["Task " <> _ | _]}, task_metadata}
839-
assert_receive {:event, {:string, ["Process " | _]}, process_metadata}
840733
assert_receive {:event, {:string, ["Child " | _]}, _child_metadata}
841734
assert_receive {:event, {:string, ["Child ", "Task" | _]}, _child_task_metadata}
842-
843735
assert {:stop, [_ | _]} = task_metadata[:crash_reason]
844-
assert {:stop, [_ | _]} = process_metadata[:crash_reason]
845736
end
846737

847738
test "translates Supervisor reports abnormal shutdown" do
@@ -856,9 +747,7 @@ defmodule Logger.TranslatorTest do
856747
Start Call: Logger.TranslatorTest.abnormal\(\)
857748
"""
858749

859-
assert_receive {:event, {:string, ["Process " | _]}, process_metadata}
860750
assert_receive {:event, {:string, ["Child " | _]}, _child_metadata}
861-
assert {:stop, [_ | _]} = process_metadata[:crash_reason]
862751
end
863752

864753
test "translates Supervisor reports abnormal shutdown on debug" do
@@ -878,9 +767,7 @@ defmodule Logger.TranslatorTest do
878767
Type: :worker
879768
"""
880769

881-
assert_receive {:event, {:string, ["Process " | _]}, process_metadata}
882770
assert_receive {:event, {:string, ["Child " | _]}, _child_metadata}
883-
assert {:stop, [_ | _]} = process_metadata[:crash_reason]
884771
end
885772

886773
test "translates DynamicSupervisor reports abnormal shutdown" do
@@ -899,9 +786,7 @@ defmodule Logger.TranslatorTest do
899786
Start Call: Logger.TranslatorTest.abnormal\(\)
900787
"""
901788

902-
assert_receive {:event, {:string, ["Process " | _]}, process_metadata}
903789
assert_receive {:event, {:string, ["Child " | _]}, _child_metadata}
904-
assert {:stop, [_ | _]} = process_metadata[:crash_reason]
905790
end
906791

907792
test "translates DynamicSupervisor reports abnormal shutdown including extra_arguments" do
@@ -922,9 +807,7 @@ defmodule Logger.TranslatorTest do
922807
Start Call: Logger.TranslatorTest.abnormal\(:extra, :args\)
923808
"""
924809

925-
assert_receive {:event, {:string, ["Process " | _]}, process_metadata}
926810
assert_receive {:event, {:string, ["Child " | _]}, _child_metadata}
927-
assert {:stop, [_ | _]} = process_metadata[:crash_reason]
928811
end
929812

930813
test "translates named DynamicSupervisor reports abnormal shutdown" do
@@ -943,9 +826,7 @@ defmodule Logger.TranslatorTest do
943826
Start Call: Logger.TranslatorTest.abnormal\(\)
944827
"""
945828

946-
assert_receive {:event, {:string, ["Process " | _]}, process_metadata}
947829
assert_receive {:event, {:string, ["Child " | _]}, _child_metadata}
948-
assert {:stop, [_ | _]} = process_metadata[:crash_reason]
949830
end
950831

951832
test "translates :supervisor_bridge progress" do
@@ -975,11 +856,8 @@ defmodule Logger.TranslatorTest do
975856
"""
976857

977858
assert_receive {:event, {:string, ["Task " <> _ | _]}, task_metadata}
978-
assert_receive {:event, {:string, ["Process " | _]}, process_metadata}
979859
assert_receive {:event, {:string, ["Child of Supervisor " | _]}, _child_metadata}
980-
981860
assert {:stop, [_ | _]} = task_metadata[:crash_reason]
982-
assert {:stop, [_ | _]} = process_metadata[:crash_reason]
983861
end
984862

985863
test "translates process crash with ERTS" do

0 commit comments

Comments
 (0)