MOD amélioration de la vitesse de euphorik_bd:messages (mais toujours en O(n)). Cette...
[euphorik.git] / modules / erl / euphorik_test.erl
1 % coding: utf-8
2 % Copyright 2008 Grégory Burri
3 %
4 % This file is part of Euphorik.
5 %
6 % Euphorik is free software: you can redistribute it and/or modify
7 % it under the terms of the GNU General Public License as published by
8 % the Free Software Foundation, either version 3 of the License, or
9 % (at your option) any later version.
10 %
11 % Euphorik is distributed in the hope that it will be useful,
12 % but WITHOUT ANY WARRANTY; without even the implied warranty of
13 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 % GNU General Public License for more details.
15 %
16 % You should have received a copy of the GNU General Public License
17 % along with Euphorik. If not, see <http://www.gnu.org/licenses/>.
18 %
19 % Module de test de euphorik.
20 % Crée un certain nombre d'utilisateur et post des messages aléatoire.
21
22
23 -module(euphorik_test).
24 -export([
25 bench_write_minichat/1,
26 start/2,
27 stop/1,
28 bench_get_messages/0,
29 bench_get_messages_avec_2_conversations/0
30 ]).
31 -include("../include/euphorik_bd.hrl").
32
33 % les intervalles en seconde min en max entre deux postes de message d'un utilisateur
34 % le temps d'attente est choisi au hasard entre ces deux valeurs
35 -define(INTERVALLE_MIN, 2).
36 -define(INTERVALLE_MAX, 5).
37
38
39 % N est le nombre d'utilisateur
40 % M est le nombre de message que chaque utilisateur va poster
41 start(N, M) ->
42 Ids = creer_users(N),
43 lists:map(
44 fun(Id) ->
45 timer:sleep(100),
46 spawn(
47 fun() ->
48 {A1, A2, A3} = now(),
49 random:seed(A1, A2, A3),
50 loop(Id, M)
51 end
52 )
53 end,
54 Ids
55 ).
56
57 stop(Pids) ->
58 lists:foreach(fun(Pid) -> exit(Pid, kill) end, Pids).
59
60 % des trucs qui trainent
61 bench_get_messages() ->
62 T = [
63 {page,"chat"},
64 {cookie,"5G84A5CJXMCPEHNI8T5A9"},
65 {message_count,40},
66 {last_message_id,0},
67 {main_page,1},
68 {troll_id,0},
69 {conversations,{array,[]}}
70 ],
71 moyenne_temps(euphorik_protocole, wait_event, [T], 20).
72 bench_get_messages_avec_2_conversations() ->
73 T = [
74 {page,"chat"},
75 {cookie,"5G84A5CJXMCPEHNI8T5A9"},
76 {message_count,40},
77 {last_message_id,0},
78 {main_page,1},
79 {troll_id,0},
80 {conversations,{array, [
81 {struct, [
82 {root, 921},
83 {page,1},
84 {last_message_id,0}
85 ]},
86 {struct, [
87 {root, 772},
88 {page, 1},
89 {last_message_id, 0}
90 ]}
91 ]}}
92 ],
93 moyenne_temps(euphorik_protocole, wait_event, [T], 20).
94 moyenne_temps(Module, Fun, Args, N) ->
95 moyenne_temps(Module, Fun, Args, N, N, 0).
96 moyenne_temps(_, _, _, 0, Total, Temps_acc) ->
97 Temps_acc / Total;
98 moyenne_temps(Module, Fun, Args, N, Total, Temps_acc) ->
99 {Temps, _} = timer:tc(Module, Fun, Args),
100 moyenne_temps(Module, Fun, Args, N - 1, Total, Temps_acc + Temps).
101
102
103 % Crée N user avec des noms aléatoires et renvoie la liste des id.
104 creer_users(N) ->
105 creer_users(N, []).
106 creer_users(0, Ids) -> lists:map(fun(#user{id = Id}) -> Id end, Ids);
107 creer_users(N, Ids) ->
108 creer_users(N - 1, [euphorik_bd:nouveau_user(mot_rand(random:uniform(4) + 4), "", "", #profile{}) | Ids ]).
109
110
111 % crée un message aléatoire et le renvoie
112 message_rand() ->
113 lists:flatten(message_rand(random:uniform(10), [])).
114 message_rand(0, Mots) -> Mots;
115 message_rand(N, Mots) ->
116 message_rand(N - 1, [mot_rand(random:uniform(2) + 5), $ | Mots]).
117
118
119 % Renvoie une succession de lettre aléatoire
120 mot_rand(L) ->
121 mot_rand(L, []).
122 mot_rand(0, Mot) -> Mot;
123 mot_rand(L, Mot) ->
124 mot_rand(L - 1, [random:uniform($z - $a + 1) + $a - 1 | Mot]).
125
126
127 % Tire au hasard de 0 à 3 messages sur les 10 derniers postés, renvoie une liste de int()
128 % répartition :
129 % 0 : 0.1
130 % 1 : 0.95
131 % 2 : 0.04
132 % 3 : 0.01
133 messages_id_rand() ->
134 R = random:uniform(),
135 if R =< 0.1 ->
136 [];
137 true ->
138 Messages = lists:map(fun(#minichat{id = Id}) -> Id end, euphorik_bd:messages(8)),
139 if
140 R > 0.1 andalso R =< 0.95 ->
141 tire_element_rand(1, Messages);
142 R > 0.95 andalso R =< 0.99 ->
143 tire_element_rand(2, Messages);
144 true ->
145 tire_element_rand(3, Messages)
146 end
147 end.
148
149
150 % tire N element distinct parmis la liste L proposée
151 tire_element_rand(N, L) when N =< length(L) ->
152 tire_element_rand(N, L, []);
153 tire_element_rand(_, _) ->
154 [].
155 tire_element_rand(0, _, Elements) -> Elements;
156 tire_element_rand(N, L, Elements) ->
157 E = lists:nth(random:uniform(length(L)), L),
158 E_se_trouve_dans_Elements = lists:any(fun(E2) -> E2 =:= E end, Elements),
159 if E_se_trouve_dans_Elements -> % si E a déjà été tiré on recommence sans rien changer
160 tire_element_rand(N, L, Elements);
161 true ->
162 tire_element_rand(N-1, L, [E | Elements])
163 end.
164
165 loop(User_id, 0) ->
166 io:format("~p a fini~n", [User_id]);
167 loop(User_id, M) ->
168 % attend un temp aléatoire compris entre INTERVALLE_MIN sec et INTERVALLE_MAX sec
169 timer:sleep(1000 * (random:uniform(?INTERVALLE_MAX - ?INTERVALLE_MIN + 1) + ?INTERVALLE_MIN - 1)),
170 % poste un message aléatoire par une personne aléatoire répondant à des messages aléatoires
171 {Message, Repond_a} = {message_rand(), messages_id_rand()},
172 % io:format("~p poste ~p et repond a ~w~n", [User_id, Message, Repond_a]),
173 case euphorik_bd:nouveau_message(Message, User_id, Repond_a) of
174 {erreur, E} ->
175 io:format("~p : erreur : ~p~n", [User_id, E]),
176 loop(User_id, M);
177 _ ->
178 loop(User_id, M - 1)
179 end.
180
181
182 % Permet de tester la vitesse d'écriture en fonction de la
183 % taille de la BD
184 % voir : http://erlang.org/pipermail/erlang-questions/2008-October/038697.html
185 bench_write_minichat(Filename) ->
186 Times = bench_write_minichat(1, []),
187 {ok, File} = file:open(Filename, [write]),
188 lists:foreach(
189 fun({Id, Time}) ->
190 io:format(File, "~w ~w~n", [Id, Time])
191 end,
192 Times
193 ),
194 file:close(File).
195 bench_write_minichat(100000, Temps) -> Temps;
196 bench_write_minichat(N, Temps) ->
197 {T, _} = timer:tc(mnesia, transaction, [fun() ->
198 Id = mnesia:dirty_update_counter(counter, minichat, 1),
199 mnesia:write(#minichat{
200 id = Id,
201 auteur_id = random:uniform(10000),
202 date = now(),
203 pseudo = "Test",
204 contenu = "Blabla blabla bla.",
205 racine_id = random:uniform(10000)
206 })
207 end]),
208 bench_write_minichat(N + 1, if N rem 500 =:= 0 -> [{N, T} | Temps]; true -> Temps end).
209
210
211
212