From c8c75648d8482482e111a668573962ce193283bf Mon Sep 17 00:00:00 2001 From: Siraaj Khandkar Date: Sun, 29 Jul 2012 17:56:53 -0400 Subject: [PATCH] Observer logs stats for each run. --- 001/.gitignore | 1 + 001/src/life_god.erl | 6 +- 001/src/life_observer.erl | 124 ++++++++++++++++++++++++++++++++++++++ 001/src/life_time.erl | 2 + 4 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 001/src/life_observer.erl diff --git a/001/.gitignore b/001/.gitignore index cfb2329..8c6a311 100644 --- a/001/.gitignore +++ b/001/.gitignore @@ -1 +1,2 @@ ebin +data diff --git a/001/src/life_god.erl b/001/src/life_god.erl index 8000eaa..ea3b236 100644 --- a/001/src/life_god.erl +++ b/001/src/life_god.erl @@ -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 index 0000000..e16fcf7 --- /dev/null +++ b/001/src/life_observer.erl @@ -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). diff --git a/001/src/life_time.erl b/001/src/life_time.erl index f009b11..089925f 100644 --- a/001/src/life_time.erl +++ b/001/src/life_time.erl @@ -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] -- 2.20.1