this repo has no description
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add SimLogger

garrison 646440fc ddfc0400

+100 -8
+6
lib/trinity/scheduler.ex
··· 15 15 file_paths: :ets.table, 16 16 file_data: :ets.table, 17 17 18 + log: :ets.table, 19 + log_atomic: :atomics.atomics_ref, 20 + 18 21 now: :atomics.atomics_ref, 19 22 supervisor_pid: pid, 20 23 } ··· 29 32 30 33 :file_paths, 31 34 :file_data, 35 + 36 + :log, 37 + :log_atomic, 32 38 33 39 :now, 34 40 :supervisor_pid,
+37 -3
lib/trinity/scheduler/simulation_supervisor.ex
··· 52 52 file_paths: :ets.new(__MODULE__, [:ordered_set, :public]), 53 53 file_data: :ets.new(__MODULE__, [:ordered_set, :public]), 54 54 55 + log: :ets.new(__MODULE__, [:ordered_set, :public]), 56 + log_atomic: :atomics.new(2, signed: false), 57 + 55 58 now: :atomics.new(1, signed: false), 56 59 supervisor_pid: self(), 57 60 } ··· 86 89 sim: sim, 87 90 root_pid: root_pid, 88 91 parent_pid: parent_pid, 89 - parent_ref: parent_ref, 90 92 } = state 91 93 92 94 case from do ··· 96 98 97 99 ^root_pid -> 98 100 # The root has died, end the simulation 99 - send parent_pid, {parent_ref, reason} 101 + end_simulation(state, reason) 100 102 {:noreply, state} 101 103 102 104 _ -> ··· 110 112 111 113 # If the root was killed, end the simulation 112 114 case pid == root_pid do 113 - true -> send parent_pid, {parent_ref, reason} 115 + true -> end_simulation(state, reason) 114 116 _ -> :noop 115 117 end 116 118 end) 117 119 118 120 {:noreply, state} 119 121 end 122 + end 123 + 124 + defp end_simulation(%State{} = state, reason) do 125 + %{sim: sim, parent_pid: parent_pid, parent_ref: parent_ref} = state 126 + 127 + %Simulation{log: log, log_atomic: log_atomic} = sim 128 + hash = :atomics.get(log_atomic, 1) 129 + 130 + require Logger 131 + Logger.info """ 132 + Simulation complete 133 + Hash: #{print_hash(hash)} 134 + Log: 135 + 136 + #{print_log(log)} 137 + """ 138 + 139 + send parent_pid, {parent_ref, reason} 140 + end 141 + 142 + defp print_hash(hash) do 143 + :crypto.hash(:sha256, <<hash::integer-32>>) 144 + |> Base.encode32() 145 + |> String.slice(0, 8) 146 + end 147 + 148 + defp print_log(log) do 149 + :ets.tab2list(log) 150 + |> Enum.reduce("", fn {i, msg}, acc -> 151 + i_pad = String.pad_leading(Integer.to_string(i), 2) 152 + acc <> i_pad <> ": " <> msg <> "\n" 153 + end) 120 154 end 121 155 122 156 defp spawn_sim_child(%Simulation{} = sim, fun) do
-1
lib/trinity/sim_file.ex
··· 231 231 232 232 defp put_path(file_paths, node, path, value) 233 233 when value == :directory or is_integer(value) do 234 - dbg {{node, path}, value} 235 234 :ets.insert(file_paths, {{node, path}, value}) 236 235 end 237 236 end
+50
lib/trinity/sim_logger.ex
··· 1 + defmodule Trinity.SimLogger do 2 + import Trinity.Scheduler, only: [simulation_key: 0] 3 + 4 + @spec get_sim :: Simulation.t | nil 5 + defp get_sim, do: Process.get(simulation_key()) 6 + 7 + defmacro debug(message) do 8 + key = simulation_key() 9 + 10 + {:<<>>, _, elements} = message 11 + values = 12 + Enum.reduce(elements, [], fn 13 + {:"::", _, [{{:., _, [Kernel, :to_string]}, _, [value]}, {:binary, _, _}]}, acc -> 14 + [value | acc] 15 + _, acc -> 16 + acc 17 + end) 18 + |> Enum.reverse() 19 + 20 + %{module: module, line: line} = __CALLER__ 21 + values_tuple = {:{}, [], [module, line | values]} 22 + 23 + quote do 24 + require Logger 25 + case Process.get(unquote(key)) do 26 + nil -> Logger.debug(unquote(message)) 27 + _sim -> Trinity.SimLogger.sim_hash_and_log(unquote(values_tuple), unquote(message)) 28 + end 29 + end 30 + end 31 + 32 + @doc false 33 + def sim_hash_and_log(values_tuple, message) do 34 + %{log: log, log_atomic: log_atomic} = get_sim() 35 + 36 + sim_hash_values(log_atomic, values_tuple) 37 + sim_log_message(log, log_atomic, message) 38 + end 39 + 40 + defp sim_hash_values(log_atomic, values_tuple) do 41 + prev_hash = :atomics.get(log_atomic, 1) 42 + new_hash = :erlang.phash2([prev_hash | values_tuple]) 43 + :atomics.put(log_atomic, 1, new_hash) 44 + end 45 + 46 + defp sim_log_message(log, log_atomic, message) do 47 + i = :atomics.add_get(log_atomic, 2, 1) 48 + :ets.insert(log, {i, message}) 49 + end 50 + end
+7 -4
test/trinity_test.exs
··· 1 1 defmodule TrinityTest do 2 2 use ExUnit.Case 3 3 4 - alias Trinity.{SimProcess, Scheduler} 4 + alias Trinity.{SimProcess, SimLogger, Scheduler} 5 5 import Trinity.Scheduler, only: [receive_yield: 1] 6 + require SimLogger 6 7 7 8 defmodule Counter do 8 9 use GenServer ··· 19 20 def init(%{id: id, initial_count: initial_count}) do 20 21 :ok = SimFile.mkdir_p("/counters/#{id}/") 21 22 {:ok, fd} = SimFile.open("/counters/#{id}/#{id}.count", [:read, :write]) 23 + 24 + SimLogger.debug "Init (id=#{fd}, fd=#{fd}, initial_count=#{initial_count})" 22 25 23 26 state = %{ 24 27 fd: fd, ··· 62 65 SimProcess.register(self(), name) 63 66 64 67 receive_yield do 65 - :begin -> dbg {"began", name} 68 + :begin -> :noop 66 69 end 67 70 68 71 pids = Enum.map(1..10, fn i -> ··· 81 84 end) 82 85 |> Enum.concat() 83 86 84 - dbg pids 87 + #dbg pids 85 88 86 89 Enum.each(pids, fn {pid, id} -> 87 90 result = Counter.add(pid, 10) ··· 90 93 91 94 SimProcess.send_after self(), :finish, 1000 92 95 receive_yield do 93 - :finish -> dbg "finished" 96 + :finish -> :noop 94 97 end 95 98 96 99 Scheduler.yield(1000)