Skip to content

Commit 1f3c9bd

Browse files
mat-hekvarsill
andauthored
Dashboard (#571)
* add observability for dashboard * fix tests * observer metric id -> pad * observer: cleanup metrics on unlink/death * add observer tests * Update lib/membrane/core/observer.ex Co-authored-by: Łukasz Kita <lukasz.kita0@gmail.com> * WIP metric functions * atomic demand metric * demand metric, input queue size metric * fix tests * changes for CR * rename observer to stalker * refactor observability setup * remove kino from deps * fix stalker time rounding * fixes for CR * pad_data.metrics -> stalker_metrics --------- Co-authored-by: Łukasz Kita <lukasz.kita0@gmail.com>
1 parent b1cd21f commit 1f3c9bd

30 files changed

Lines changed: 964 additions & 312 deletions

lib/membrane/core/bin.ex

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ defmodule Membrane.Core.Bin do
9292
log_metadata: options.log_metadata
9393
}
9494

95-
Membrane.Core.Observability.setup(observability_config)
95+
Membrane.Core.Stalker.register_component(options.stalker, observability_config)
9696
SubprocessSupervisor.set_parent_component(options.subprocess_supervisor, observability_config)
9797

9898
clock_proxy = Membrane.Clock.start_link(proxy: true) ~> ({:ok, pid} -> pid)
@@ -122,7 +122,8 @@ defmodule Membrane.Core.Bin do
122122
},
123123
children_log_metadata: options.log_metadata,
124124
subprocess_supervisor: options.subprocess_supervisor,
125-
resource_guard: resource_guard
125+
resource_guard: resource_guard,
126+
stalker: options.stalker
126127
}
127128
|> Child.PadSpecHandler.init_pads()
128129

lib/membrane/core/bin/state.ex

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,11 @@ defmodule Membrane.Core.Bin.State do
4545
terminating?: boolean(),
4646
resource_guard: Membrane.ResourceGuard.t(),
4747
setup_incomplete?: boolean(),
48-
handling_action?: boolean()
48+
handling_action?: boolean(),
49+
stalker: Membrane.Core.Stalker.t()
4950
}
5051

51-
@enforce_keys [:module, :synchronization, :subprocess_supervisor, :resource_guard]
52+
@enforce_keys [:module, :synchronization, :subprocess_supervisor, :resource_guard, :stalker]
5253
defstruct @enforce_keys ++
5354
[
5455
internal_state: nil,

lib/membrane/core/child/pad_model.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ defmodule Membrane.Core.Child.PadModel do
4343
options: %{optional(atom) => any},
4444
auto_demand_size: pos_integer() | nil,
4545
associated_pads: [Pad.ref()] | nil,
46-
sticky_events: [Membrane.Event.t()]
46+
sticky_events: [Membrane.Event.t()],
47+
stalker_metrics: %{atom => :atomics.atomics_ref()}
4748
}
4849

4950
@type pad_data :: bin_pad_data | element_pad_data

lib/membrane/core/element.ex

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,13 @@ defmodule Membrane.Core.Element do
1818
use Bunch
1919
use GenServer
2020

21-
alias Membrane.Core.Element.DemandHandler
2221
alias Membrane.{Clock, Core, ResourceGuard, Sync}
23-
24-
alias Membrane.Core.{SubprocessSupervisor, TimerController}
22+
alias Membrane.Core.Child.PadSpecHandler
2523

2624
alias Membrane.Core.Element.{
2725
BufferController,
2826
DemandController,
27+
DemandHandler,
2928
EffectiveFlowController,
3029
EventController,
3130
LifecycleController,
@@ -34,7 +33,10 @@ defmodule Membrane.Core.Element do
3433
StreamFormatController
3534
}
3635

36+
alias Membrane.Core.{SubprocessSupervisor, TimerController}
37+
3738
require Membrane.Core.Message, as: Message
39+
require Membrane.Core.Stalker, as: Stalker
3840
require Membrane.Core.Telemetry, as: Telemetry
3941
require Membrane.Logger
4042

@@ -98,13 +100,13 @@ defmodule Membrane.Core.Element do
98100

99101
observability_config = %{
100102
name: options.name,
101-
component_type: :bin,
103+
component_type: :element,
102104
pid: self(),
103105
parent_path: options.parent_path,
104106
log_metadata: options.log_metadata
105107
}
106108

107-
Membrane.Core.Observability.setup(observability_config)
109+
Membrane.Core.Stalker.register_component(options.stalker, observability_config)
108110
SubprocessSupervisor.set_parent_component(options.subprocess_supervisor, observability_config)
109111

110112
{:ok, resource_guard} =
@@ -114,10 +116,46 @@ defmodule Membrane.Core.Element do
114116

115117
ResourceGuard.register(resource_guard, fn -> Telemetry.report_terminate(:element) end)
116118

119+
self_pid = self()
120+
121+
Stalker.register_metric_function(:message_queue_length, fn ->
122+
:erlang.process_info(self_pid, :message_queue_len) |> elem(1)
123+
end)
124+
125+
Stalker.register_metric_function(:total_reductions, fn ->
126+
:erlang.process_info(self_pid, :reductions) |> elem(1)
127+
end)
128+
117129
state =
118-
Map.take(options, [:module, :name, :parent_clock, :sync, :parent, :subprocess_supervisor])
119-
|> Map.put(:resource_guard, resource_guard)
120-
|> State.new()
130+
%State{
131+
module: options.module,
132+
type: options.module.membrane_element_type(),
133+
name: options.name,
134+
internal_state: nil,
135+
parent_pid: options.parent,
136+
supplying_demand?: false,
137+
delayed_demands: MapSet.new(),
138+
handle_demand_loop_counter: 0,
139+
synchronization: %{
140+
parent_clock: options.parent_clock,
141+
timers: %{},
142+
clock: nil,
143+
stream_sync: options.sync,
144+
latency: 0
145+
},
146+
initialized?: false,
147+
playback: :stopped,
148+
playback_queue: [],
149+
resource_guard: resource_guard,
150+
subprocess_supervisor: options.subprocess_supervisor,
151+
terminating?: false,
152+
setup_incomplete?: false,
153+
effective_flow_control: :push,
154+
handling_action?: false,
155+
pads_to_snapshot: MapSet.new(),
156+
stalker: options.stalker
157+
}
158+
|> PadSpecHandler.init_pads()
121159

122160
state = LifecycleController.handle_init(options.user_options, state)
123161
{:ok, state, {:continue, :setup}}

lib/membrane/core/element/action_handler.ex

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ defmodule Membrane.Core.Element.ActionHandler do
88

99
import Membrane.Pad, only: [is_pad_ref: 1]
1010

11+
alias Membrane.Telemetry
12+
1113
alias Membrane.{
1214
ActionError,
1315
Buffer,
@@ -19,8 +21,6 @@ defmodule Membrane.Core.Element.ActionHandler do
1921
StreamFormat
2022
}
2123

22-
alias Membrane.Core.Child.PadModel
23-
2424
alias Membrane.Core.Element.{
2525
DemandController,
2626
DemandHandler,
@@ -29,12 +29,12 @@ defmodule Membrane.Core.Element.ActionHandler do
2929
StreamFormatController
3030
}
3131

32-
alias Membrane.Core.{Events, Message, Telemetry, TimerController}
32+
alias Membrane.Core.{Events, TimerController}
3333
alias Membrane.Element.Action
3434

35-
require Membrane.Core.Child.PadModel
36-
require Membrane.Core.Message
37-
require Membrane.Core.Telemetry
35+
require Membrane.Core.Child.PadModel, as: PadModel
36+
require Membrane.Core.Message, as: Message
37+
require Membrane.Core.Telemetry, as: Telemetry
3838
require Membrane.Logger
3939

4040
@impl CallbackHandler
@@ -320,10 +320,12 @@ defmodule Membrane.Core.Element.ActionHandler do
320320
end_of_stream?: false,
321321
stream_format: stream_format,
322322
pid: pid,
323-
other_ref: other_ref
323+
other_ref: other_ref,
324+
stalker_metrics: stalker_metrics
324325
}
325326
when stream_format != nil <- pad_data do
326327
state = DemandController.decrease_demand_by_outgoing_buffers(pad_ref, buffers, state)
328+
:atomics.add(stalker_metrics.total_buffers, 1, length(buffers))
327329
Message.send(pid, :buffer, buffers, for_pad: other_ref)
328330

329331
PadModel.set_data!(state, pad_ref, :start_of_stream?, true)

lib/membrane/core/element/buffer_controller.ex

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,13 @@ defmodule Membrane.Core.Element.BufferController do
3434
def handle_buffer(pad_ref, buffers, state) do
3535
withl pad: {:ok, data} <- PadModel.get_data(state, pad_ref),
3636
playback: %State{playback: :playing} <- state do
37-
%{direction: :input, start_of_stream?: start_of_stream?} = data
37+
%{
38+
direction: :input,
39+
start_of_stream?: start_of_stream?,
40+
stalker_metrics: stalker_metrics
41+
} = data
42+
43+
:atomics.add(stalker_metrics.total_buffers, 1, length(buffers))
3844

3945
state =
4046
if start_of_stream? do
@@ -57,10 +63,11 @@ defmodule Membrane.Core.Element.BufferController do
5763
@spec do_handle_buffer(Pad.ref(), PadModel.pad_data(), [Buffer.t()] | Buffer.t(), State.t()) ::
5864
State.t()
5965
defp do_handle_buffer(pad_ref, %{flow_control: :auto} = data, buffers, state) do
60-
%{demand: demand, demand_unit: demand_unit} = data
66+
%{demand: demand, demand_unit: demand_unit, stalker_metrics: stalker_metrics} = data
6167
buf_size = Buffer.Metric.from_unit(demand_unit).buffers_size(buffers)
6268

6369
state = PadModel.set_data!(state, pad_ref, :demand, demand - buf_size)
70+
:atomics.put(stalker_metrics.demand, 1, demand - buf_size)
6471

6572
state = AutoFlowUtils.auto_adjust_atomic_demand(pad_ref, state)
6673
exec_buffer_callback(pad_ref, buffers, state)

lib/membrane/core/element/demand_controller.ex

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ defmodule Membrane.Core.Element.DemandController do
88
alias __MODULE__.AutoFlowUtils
99

1010
alias Membrane.Buffer
11-
alias Membrane.Core.Child.PadModel
1211

1312
alias Membrane.Core.Element.{
1413
AtomicDemand,
@@ -19,7 +18,7 @@ defmodule Membrane.Core.Element.DemandController do
1918

2019
alias Membrane.Pad
2120

22-
require Membrane.Core.Child.PadModel
21+
require Membrane.Core.Child.PadModel, as: PadModel
2322
require Membrane.Logger
2423

2524
@spec snapshot_atomic_demand(Pad.ref(), State.t()) :: State.t()

lib/membrane/core/element/demand_controller/auto_flow_utils.ex

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,19 @@ defmodule Membrane.Core.Element.DemandController.AutoFlowUtils do
2626

2727
defp do_auto_adjust_atomic_demand(pad_data, state) when is_input_auto_pad_data(pad_data) do
2828
if increase_atomic_demand?(pad_data, state) do
29-
diff = pad_data.auto_demand_size - pad_data.demand
30-
:ok = AtomicDemand.increase(pad_data.atomic_demand, diff)
31-
32-
PadModel.set_data!(
33-
state,
34-
pad_data.ref,
35-
:demand,
36-
pad_data.auto_demand_size
37-
)
29+
%{
30+
ref: ref,
31+
auto_demand_size: auto_demand_size,
32+
demand: demand,
33+
atomic_demand: atomic_demand,
34+
stalker_metrics: stalker_metrics
35+
} = pad_data
36+
37+
diff = auto_demand_size - demand
38+
:ok = AtomicDemand.increase(atomic_demand, diff)
39+
40+
:atomics.put(stalker_metrics.demand, 1, auto_demand_size)
41+
PadModel.set_data!(state, ref, :demand, auto_demand_size)
3842
else
3943
state
4044
end

lib/membrane/core/element/input_queue.ex

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ defmodule Membrane.Core.Element.InputQueue do
1414
alias Membrane.Pad
1515
alias Membrane.StreamFormat
1616

17+
require Membrane.Core.Stalker, as: Stalker
1718
require Membrane.Core.Telemetry, as: Telemetry
1819
require Membrane.Logger
1920

@@ -35,8 +36,9 @@ defmodule Membrane.Core.Element.InputQueue do
3536
demand: non_neg_integer(),
3637
inbound_metric: module(),
3738
outbound_metric: module(),
38-
linked_output_ref: Pad.ref(),
39-
atomic_demand: AtomicDemand.t()
39+
pad_ref: Pad.ref(),
40+
atomic_demand: AtomicDemand.t(),
41+
stalker_metrics: %{atom() => any()}
4042
}
4143

4244
@enforce_keys [
@@ -46,7 +48,8 @@ defmodule Membrane.Core.Element.InputQueue do
4648
:atomic_demand,
4749
:inbound_metric,
4850
:outbound_metric,
49-
:linked_output_ref
51+
:pad_ref,
52+
:stalker_metrics
5053
]
5154

5255
defstruct @enforce_keys ++ [size: 0, demand: 0]
@@ -60,7 +63,7 @@ defmodule Membrane.Core.Element.InputQueue do
6063
inbound_demand_unit: Buffer.Metric.unit(),
6164
outbound_demand_unit: Buffer.Metric.unit(),
6265
atomic_demand: AtomicDemand.t(),
63-
linked_output_ref: Pad.ref(),
66+
pad_ref: Pad.ref(),
6467
log_tag: String.t(),
6568
target_size: pos_integer() | nil
6669
}) :: t()
@@ -69,7 +72,7 @@ defmodule Membrane.Core.Element.InputQueue do
6972
inbound_demand_unit: inbound_demand_unit,
7073
outbound_demand_unit: outbound_demand_unit,
7174
atomic_demand: atomic_demand,
72-
linked_output_ref: linked_output_ref,
75+
pad_ref: pad_ref,
7376
log_tag: log_tag,
7477
target_size: target_size
7578
} = config
@@ -81,14 +84,23 @@ defmodule Membrane.Core.Element.InputQueue do
8184

8285
target_size = target_size || default_target_size
8386

87+
size_metric = :atomics.new(1, [])
88+
89+
Stalker.register_metric_function(
90+
:input_queue_size,
91+
fn -> :atomics.get(size_metric, 1) end,
92+
pad: pad_ref
93+
)
94+
8495
%__MODULE__{
8596
q: @qe.new(),
8697
log_tag: log_tag,
8798
target_size: target_size,
8899
inbound_metric: inbound_metric,
89100
outbound_metric: outbound_metric,
90101
atomic_demand: atomic_demand,
91-
linked_output_ref: linked_output_ref
102+
pad_ref: pad_ref,
103+
stalker_metrics: %{size: size_metric}
92104
}
93105
|> maybe_increase_atomic_demand()
94106
end
@@ -97,7 +109,8 @@ defmodule Membrane.Core.Element.InputQueue do
97109
def store(input_queue, type \\ :buffers, v)
98110

99111
def store(input_queue, :buffers, v) when is_list(v) do
100-
%__MODULE__{size: size, target_size: target_size} = input_queue
112+
%__MODULE__{size: size, target_size: target_size, stalker_metrics: stalker_metrics} =
113+
input_queue
101114

102115
if size >= target_size do
103116
"""
@@ -111,6 +124,7 @@ defmodule Membrane.Core.Element.InputQueue do
111124
%__MODULE__{size: size} = input_queue = do_store_buffers(input_queue, v)
112125

113126
Telemetry.report_metric(:store, size, input_queue.log_tag)
127+
:atomics.put(stalker_metrics.size, 1, size)
114128

115129
input_queue
116130
end
@@ -160,7 +174,9 @@ defmodule Membrane.Core.Element.InputQueue do
160174
{out, input_queue} = do_take(input_queue, count)
161175
input_queue = maybe_increase_atomic_demand(input_queue)
162176

163-
Telemetry.report_metric(:take, input_queue.size, input_queue.log_tag)
177+
%{size: size, stalker_metrics: stalker_metrics} = input_queue
178+
Telemetry.report_metric(:take, size, input_queue.log_tag)
179+
:atomics.put(stalker_metrics.size, 1, size)
164180

165181
{out, input_queue}
166182
end
@@ -286,7 +302,7 @@ defmodule Membrane.Core.Element.InputQueue do
286302
diff = max(target_size - size - demand, div(target_size, 2))
287303

288304
"""
289-
Increasing AtomicDemand linked to #{inspect(input_queue.linked_output_ref)} by #{inspect(diff)}
305+
Increasing AtomicDemand for pad #{inspect(input_queue.pad_ref)} by #{inspect(diff)}
290306
"""
291307
|> mk_log(input_queue)
292308
|> Membrane.Logger.debug_verbose()

0 commit comments

Comments
 (0)