summaryrefslogtreecommitdiffstats
path: root/sources/fabrice/simulator/simulTrace.ml
blob: b58bf414124ced7c91c9d972d8cd1353c4b46320 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
open SimulTypes
open SimulGraphes  
  
type trace_event =
  Peers of int
| Days of int * int
| Peer of int * float * string
| Round of int
| On of int 
| Off of int
| Dead of int
| End 
| Exponential
  
let trace_output oc trace_event =
  output_string oc (match trace_event with
      Peers npeers -> Printf.sprintf "Peers %d\n" npeers
    | Days (ndays, day) -> Printf.sprintf "Days %d %d\n" ndays day
    | Peer (i,avail,s) ->        
        Printf.sprintf "Peer %d %.3f %s\n" i avail s
    | Round  round -> Printf.sprintf "Round %d\n" round 
    | On i -> Printf.sprintf "On %d\n" i
    | Off i -> Printf.sprintf "Off %d\n" i
    | Dead i -> Printf.sprintf "Dead %d\n" i
    | End -> "End\n"
    | Exponential -> "Exponential\n"
  )
  
let trace_input ic =
  let line = input_line ic in
  match String2.split line ' ' with
    ["Peers"; npeers] -> Peers (int_of_string npeers)
  | ["Days"; ndays] -> Days (int_of_string ndays, 24 * 60)
  | ["Days"; ndays; day] -> Days (int_of_string ndays, int_of_string day)
  | "Peer" :: i :: avail :: tail ->
      Peer (int_of_string i, float_of_string avail, String2.unsplit tail ' ')
  | ["End"] -> End
  | ["Exponential"] -> Exponential
  | ["Round"; round] -> Round (int_of_string round)
  | ["On"; i] -> On (int_of_string i)
  | ["Dead"; i] -> Dead (int_of_string i)
  | ["Off"; i] -> Off (int_of_string i)
        
  | _ -> failwith (Printf.sprintf "Bad line [%s]" (String.escaped line))

let print_distribution = ref false
(*      gnuplot> plot exp(1-log(2+65*x)), 1.0/12  *)

let exponential = ref false
let distribution = ref []
let availability = ref []
  
let trace_read filename =
  let ic = open_in filename in
  let npeers = match trace_input ic with
      Peers npeers -> npeers
    | _ -> assert false
  in
  let (ndays, day) = match trace_input ic with
      Days (ndays, day) -> ndays, day
    | _ -> assert false
  in
  
  let rec read_peer ii =
    match trace_input ic with          
      Exponential -> exponential := true;
        read_peer ii
    | Peer (i, avail, s) ->
        assert (i=ii);
(*
            let x = float_of_int avail /. 900000. in                
            
        let avail = (if !exponential then
              max 0.02 (min 1. (exp(1. -. log(2. +. 65. *. x))))
              else
                  0.02 +. 0.98 *. x
              )
            in
            if !print_distribution then begin
                distribution := x :: !distribution;
                availability := avail :: !availability;                
                end;
            let lambda = float_of_int decs /. (60. *. 24.) in
           let mu = avail *. lambda /. (1. -. avail) in
  *)
        let p = {
            i = i;
            avail = avail;            
            descr = s;
            session = 0;
            day = true;
            state = OFF;
            real_avail = 0;
            real_decs = 0;
          } in
        p            
    | _ -> assert false
  in    
  let peers = Array.init npeers read_peer in
  let event = ref None in
  let get_event () =
    let ev = trace_input ic in    
    event := Some ev
  in
  
  let next_day = ref 0 in
  let begin_time = (Int64.of_float (Unix.gettimeofday ())) in
  let rec iter_round round =
    match !event with
      None -> 
        next_event round
    | Some ev ->
        match ev with
          Round rr -> 
            if rr = round then begin
                if !next_day = round then begin
                    let time = Unix.gettimeofday () in
                    let time = Int64.of_float time in
                    Printf.printf "Day %d (%Ld)\n%!" (round / day) 
                    (Int64.sub time begin_time);
                    next_day := !next_day + day
                  end;
                next_event round
              end else
              assert (rr > round)
        | On i ->
            event := None;
            let p = peers.(i) in
            p.state <- ON;
            next_event round
        | Off i ->
            event := None;
            let p = peers.(i) in
            p.state <- OFF;
            p.real_decs <- p.real_decs + 1;
            next_event round
        | Dead i ->
            event := None;
            let p = peers.(i) in
            p.state <- DEAD;
            peers.(i) <- {
              p with state = OFF; 
            };
            next_event round
        | End -> ()
        | _ -> assert false
            
  and next_event round =
    get_event (); 
    iter_round round    
  in
  if !print_distribution then begin
      cdf_of_list string_of_float "dist_random" !distribution
        "set yrange [0:1]" "CDF of peers" "Distribution" 
        " title 'random'";
      cdf_of_list string_of_float "dist_availability" !availability
        "set yrange [0:1]" "CDF of peers" "Distribution" 
        " title 'avail'";
      distribution := [];
      availability := [];
    end;          
  peers, ndays * day, iter_round