git @ Cat's Eye Technologies pibfi / master src / pibfi_statistics.erl
master

Tree @master (Download .tar.gz)

pibfi_statistics.erl @masterraw · history · blame

%%% BEGIN pibfi_statistics.erl %%%
%%%
%%% pibfi - Platonic Ideal Brainf*ck Interpreter
%%% Copyright (c)2003 Cat's Eye Technologies.  All rights reserved.
%%%
%%% Redistribution and use in source and binary forms, with or without
%%% modification, are permitted provided that the following conditions
%%% are met:
%%%
%%%   Redistributions of source code must retain the above copyright
%%%   notice, this list of conditions and the following disclaimer.
%%%
%%%   Redistributions in binary form must reproduce the above copyright
%%%   notice, this list of conditions and the following disclaimer in
%%%   the documentation and/or other materials provided with the
%%%   distribution.
%%%
%%%   Neither the name of Cat's Eye Technologies nor the names of its
%%%   contributors may be used to endorse or promote products derived
%%%   from this software without specific prior written permission.
%%%
%%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
%%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
%%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
%%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
%%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
%%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
%%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
%%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
%%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
%%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
%%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
%%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
%%% POSSIBILITY OF SUCH DAMAGE. 

%% @doc Statistics collector for <code>pibfi</code>.
%%
%% @end

-module(pibfi_statistics).
-vsn('2003.0505').
-copyright('Copyright (c)2003 Cat`s Eye Technologies. All rights reserved.').

-export([start/3, server/2, dump/0, dump/1]).
-export([update_program/3]).

start(Supervisor, TapePid, Options) ->
  pibfi_supervisor:spawn_link(Supervisor, "statistics collector",
    noncritical, ?MODULE, server, [TapePid, Options]).

server(TapePid, Options) ->
  register(?MODULE, self()),
  case pibfi_options:get_option(Options, statusevery, undefined) of
    I when is_integer(I) ->
      timer:apply_interval(I, ?MODULE, dump, []);
    _ ->
      ok
  end,   
  Start = calendar:local_time(),
  loop({TapePid, 1, 1, $?, Start, {0,0,0,0,0,0,0,0,0}}).

loop({TapePid, ProgramRow, ProgramColumn, Instruction, Start,
      {PlusT, MinusT, LeftT, RightT,
       InT, OutT, WhileT, WendT, WhileLevel}}) ->
  receive
    {program, Row, Col, {Ins, N}} ->
      PlusT1 = case Ins of $+ -> PlusT + N; _ -> PlusT end,
      MinusT1 = case Ins of $- -> MinusT + N; _ -> MinusT end,
      LeftT1 = case Ins of $< -> LeftT + N; _ -> LeftT end,
      RightT1 = case Ins of $> -> RightT + N; _ -> RightT end,
      InT1 = case Ins of $, -> InT + N; _ -> InT end,
      OutT1 = case Ins of $. -> OutT + N; _ -> OutT end,
      WhileT1 = case Ins of $[ -> WhileT + N; _ -> WhileT end,
      WendT1 = case Ins of $] -> WendT + N; _ -> WendT end,
      WhileLevel1 = case Ins of
        $[ ->
	  WhileLevel + 1;
	$] ->
	  WhileLevel - 1;
	_ ->
	  WhileLevel
      end,
      % ce_log:write("~c -> ~c ~p", [Instruction, Ins, N]),
      loop({TapePid, Row, Col, Ins, Start,
        {PlusT1, MinusT1, LeftT1, RightT1,
	 InT1, OutT1, WhileT1, WendT1, WhileLevel1}});
    {program, Row, Col, Ins} ->
      PlusT1 = case Ins of $+ -> PlusT + 1; _ -> PlusT end,
      MinusT1 = case Ins of $- -> MinusT + 1; _ -> MinusT end,
      LeftT1 = case Ins of $< -> LeftT + 1; _ -> LeftT end,
      RightT1 = case Ins of $> -> RightT + 1; _ -> RightT end,
      InT1 = case Ins of $, -> InT + 1; _ -> InT end,
      OutT1 = case Ins of $. -> OutT + 1; _ -> OutT end,
      WhileT1 = case Ins of $[ -> WhileT + 1; _ -> WhileT end,
      WendT1 = case Ins of $] -> WendT + 1; _ -> WendT end,
      WhileLevel1 = case Ins of
        $[ ->
	  WhileLevel + 1;
	$] ->
	  WhileLevel - 1;
	_ ->
	  WhileLevel
      end,
      % ce_log:write("~c -> ~c", [Instruction, Ins]),
      loop({TapePid, Row, Col, Ins, Start,
        {PlusT1, MinusT1, LeftT1, RightT1,
	 InT1, OutT1, WhileT1, WendT1, WhileLevel1}});
    {Pid, dump, Type} ->
      % flush mailbox here (?)
      Stop = calendar:local_time(),
      StartGD = calendar:datetime_to_gregorian_seconds(Start),
      StopGD = calendar:datetime_to_gregorian_seconds(Stop),
      Dur = StopGD - StartGD,
      DurString = case Dur of
        D when D < 60 ->
	  io_lib:format("~p sec", [D]);
        D when D < 3600 ->
	  io_lib:format("~p min ~p sec", [D div 60, D rem 60]);
        D ->
	  M = D rem 3600,
	  io_lib:format("~p hr ~p min ~p sec",
	   [D div 3600, M div 60, M rem 60])
      end,
      TotalT = PlusT + MinusT + LeftT + RightT + InT + OutT + WhileT + WendT,
      KIPS = round((TotalT / Dur) / 1000),
      io:fwrite("===== STATUS REPORT ===== ~s =====~n", [format_datetime(Stop)]),
      io:fwrite("= Run began ~s duration ~s at mean kips ~p~n",
        [format_datetime(Start), DurString, KIPS]),
      State = case Type of
        autopsy -> "Stopped";
        normal -> "Currently"
      end,
      io:fwrite("= ~s at line ~p, col ~p, instruction '~c', whilelevel ~p~n",
        [State, ProgramRow, ProgramColumn, Instruction, WhileLevel]),
      io:fwrite("= Exec tally:~12wx(+)~12wx(-)~12wx(<)~12wx(>)~n",
        [PlusT, MinusT, LeftT, RightT]),
      io:fwrite("= Exec tally:~12wx(,)~12wx(.)~12wx([)~12wx(])~n",
        [InT, OutT, WhileT, WendT]),
      pibfi_tape:examine(TapePid),
      Pid ! {?MODULE, dump, ok},
      loop({TapePid, ProgramRow, ProgramColumn, Instruction, Start,
            {PlusT, MinusT, LeftT, RightT,
	     InT, OutT, WhileT, WendT,
	     WhileLevel}})
  end.

format_datetime({{Y, M, D}, {H, I, S}}) ->
  DoW = element(calendar:day_of_the_week({Y,M,D}),
    {"Mon","Tue","Wed","Thu","Fri","Sat","Sun"}),
  MoY = element(M,
    {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}),
  T = io_lib:format("~s ~s ~w ~w, ~2.2.0w:~2.2.0w:~2.2.0w",
    [DoW, MoY, D, Y, H, I, S]),
  lists:flatten(T).

dump() ->
  dump(normal).
  
dump(Type) ->
  case catch ?MODULE ! {self(), dump, Type} of
    {'EXIT', Reason} ->
      {error, Reason};
    _ ->
      receive
        {?MODULE, dump, ok} ->
	  ok
	after 1000 ->
	  {error, timeout}
      end
  end.

update_program(Row, Col, Ins) ->
  catch ?MODULE ! {program, Row, Col, Ins}.

%%% END of pibfi_statistics.erl %%%