Observer logs stats for each run.
authorSiraaj Khandkar <siraaj@khandkar.net>
Sun, 29 Jul 2012 21:56:53 +0000 (17:56 -0400)
committerSiraaj Khandkar <siraaj@khandkar.net>
Sun, 29 Jul 2012 21:56:53 +0000 (17:56 -0400)
001/.gitignore
001/src/life_god.erl
001/src/life_observer.erl [new file with mode: 0644]
001/src/life_time.erl

index cfb2329..8c6a311 100644 (file)
@@ -1 +1,2 @@
 ebin
+data
index 8000eaa..ea3b236 100644 (file)
@@ -28,9 +28,13 @@ start_link(X, Y, CellData) ->
 init([X, Y, CellData]) ->
     CellNames = [Name || {_, Name, _} <- CellData],
     RestartStrategy = {one_for_one, 1000000, 1},
+
+    Observer = ?CHILD(worker, life_observer, [X, Y]),
     Cells = [spec_cell(Datum) || Datum <- CellData],
     Time = ?CHILD(worker, life_time, [X, Y, CellNames]),
-    Children = Cells ++ [Time],
+
+    Children = [Observer | Cells ++ [Time]],
+
     {ok, {RestartStrategy, Children}}.
 
 
diff --git a/001/src/life_observer.erl b/001/src/life_observer.erl
new file mode 100644 (file)
index 0000000..e16fcf7
--- /dev/null
@@ -0,0 +1,124 @@
+-module(life_observer).
+-behaviour(gen_event).
+
+
+%% API
+-export([start_link/2
+        ,register_with_logger/0
+        ,add_handler/2
+        ,delete_handler/0
+        ,log_generation/3
+        ]).
+
+%% Callbacks
+-export([init/1
+        ,terminate/2
+        ,code_change/3
+        ,handle_event/2
+        ,handle_call/2
+        ,handle_info/2
+        ]).
+
+
+-define(EVENT_MGR_REF, ?MODULE).
+-define(HANDLER, ?MODULE).
+
+-define(PATH_DIR__DATA, "data").
+-define(CSV_DELIMITER, ",").
+
+
+-record(state, {log_file :: file:io_device()}).
+
+
+%% ============================================================================
+%% API
+%% ============================================================================
+
+start_link(X, Y) ->
+    EventMgrName = {local, ?EVENT_MGR_REF},
+    {ok, PID} = gen_event:start_link(EventMgrName),
+    ok = add_handler(X, Y),
+    {ok, PID}.
+
+
+register_with_logger() ->
+    error_logger:add_report_handler(?HANDLER).
+
+
+add_handler(X, Y) ->
+    Args = [X, Y],
+    gen_event:add_handler(?EVENT_MGR_REF, ?HANDLER, Args).
+
+
+delete_handler() ->
+    Args = [],
+    gen_event:delete_handler(?EVENT_MGR_REF, ?HANDLER, Args).
+
+
+log_generation(GenID, Dead, Alive) ->
+    Event = {generation, GenID, Dead, Alive},
+    gen_event:notify(?EVENT_MGR_REF, Event).
+
+
+%% ============================================================================
+%% Callbacks (unused)
+%% ============================================================================
+
+code_change(_Old, State, _Other) -> {ok, State}.
+handle_call(_Request, State)     -> Reply = ok, {ok, Reply, State}.
+handle_info(_Info, State)        -> {ok, State}.
+
+
+%% ============================================================================
+%% Callbacks
+%% ============================================================================
+
+init([X, Y]) ->
+    N = X * Y,
+    {{Year, Month, Day}, {Hour, Min, Sec}} = calendar:local_time(),
+    DateTime = lists:flatten(io_lib:format(
+        "~4.10.0B-~2.10.0B-~2.10.0B--~2.10.0B:~2.10.0B:~2.10.0B",
+        [Year, Month, Day, Hour, Min, Sec]
+    )),
+
+    FileNameComponents = [DateTime | [integer_to_list(I) || I <- [N, X, Y]]],
+    FileName = string:join(FileNameComponents, "--") ++ ".csv",
+    FilePath = filename:join(?PATH_DIR__DATA, FileName),
+
+    ok = validate_makedir(file:make_dir(?PATH_DIR__DATA)),
+    {ok, LogFile} = file:open(FilePath, write),
+
+    CSVHeaders = ["Generation", "Dead", "Alive"],
+    ok = do_write(LogFile, list_to_csvline(CSVHeaders)),
+
+    {ok, #state{log_file=LogFile}}.
+
+
+terminate(_Reason, #state{log_file=LogFile}=State) ->
+    file:close(LogFile),
+    {ok, State}.
+
+
+handle_event({generation, GenID, Dead, Alive},
+    #state{log_file=LogFile}=State) ->
+
+    Values = [integer_to_list(I) || I <- [GenID, Dead, Alive]],
+    ok = do_write(LogFile, list_to_csvline(Values)),
+    {ok, State}.
+
+
+%% ============================================================================
+%% Internal
+%% ============================================================================
+
+validate_makedir(ok) -> ok;
+validate_makedir({error, eexist}) -> ok;
+validate_makedir(Other) -> Other.
+
+
+do_write(File, Line) ->
+    ok = io:format(File, "~s~n", [Line]).
+
+
+list_to_csvline(List) ->
+    string:join(List, ?CSV_DELIMITER).
index f009b11..089925f 100644 (file)
@@ -121,6 +121,8 @@ handle_cast({report_state, {CellID, GenID, CellState}},
             ),
             StateChars = [state_to_char(S) || {_, S} <- SortedStatePairs],
 
+            ok = life_observer:log_generation(GenID, NewNDead, NewNAlive),
+
             ok = io:format(
                 "X: ~b Y: ~b CELLS: ~b DEAD: ~b ALIVE: ~b GENERATION: ~b~n",
                 [X, Y, NumCells, NewNDead, NewNAlive, GenID]
This page took 0.025471 seconds and 4 git commands to generate.