Skip to content

Commit

Permalink
add option to use weights instead of probabilities for sessions (TSUN…
Browse files Browse the repository at this point in the history
…-231)
  • Loading branch information
nniclausse committed Aug 20, 2012
1 parent 12cdf33 commit 2c7ba46
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 20 deletions.
23 changes: 21 additions & 2 deletions doc/user_manual.html
Expand Up @@ -96,7 +96,7 @@
<!--CUT DEF section 1 --><H1 ALIGN=center>Tsung User’s manual</H1><DIV CLASS="center">

<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=1><TR><TD ALIGN=left NOWRAP bgcolor="#F2F2F2"> Version:</TD><TD ALIGN=left NOWRAP>1.4.2</TD></TR>
<TR><TD ALIGN=left NOWRAP bgcolor="#F2F2F2"> Date :</TD><TD ALIGN=left NOWRAP>August 17, 2012</TD></TR>
<TR><TD ALIGN=left NOWRAP bgcolor="#F2F2F2"> Date :</TD><TD ALIGN=left NOWRAP>August 20, 2012</TD></TR>
</TABLE>
</DIV><!--TOC section Contents-->
<H2 CLASS="section"><!--SEC ANCHOR -->Contents</H2><!--SEC END --><UL CLASS="toc"><LI CLASS="li-toc">
Expand Down Expand Up @@ -1452,7 +1452,26 @@ <H3 CLASS="subsection"><!--SEC ANCHOR --><A NAME="htoc55">6.6</A>  Sessions</H
<A NAME="sec:sessions"></A></P><P>Sessions define the content of the scenario itself. They describe
the requests to execute.</P><P>Each session has a given probability. This is used to decide which
session a new user will execute. The sum of all session<CODE>'</CODE>s
probabilities must be 100.</P><P>A transaction is just a way to have customized statistics. Say if you
probabilities must be 100.</P><P><B>Since Tsung 1.4.3</B>, you can use weights instead of
probabilities. In the following example, there will be twice as many
sessions of type s1 than s2.
</P><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0><TR><TD><TABLE BORDER=0 CELLPADDING=0
CELLSPACING=0><TR><TD BGCOLOR=black COLSPAN="3"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
</TD></TR>
</TABLE></TD></TR>
<TR><TD BGCOLOR=black COLSPAN="1"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
</TD></TR>
</TABLE></TD><TD><TABLE BORDER=0 CELLPADDING="1" CELLSPACING=0><TR><TD><PRE CLASS="verbatim"> &lt;session name="s1" weight="2" type="ts_http"&gt;
&lt;session name="s2" weight="1" type="ts_http"&gt;
</PRE></TD></TR>
</TABLE></TD><TD BGCOLOR=black COLSPAN="1"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
</TD></TR>
</TABLE></TD></TR>
<TR><TD BGCOLOR=black COLSPAN="3"><TABLE CELLSPACING="1" CELLPADDING=0 BORDER=0><TR><TD>
</TD></TR>
</TABLE></TD></TR>
</TABLE></TD></TR>
</TABLE><P>A transaction is just a way to have customized statistics. Say if you
want to know the response time of the login page of your website, you
just have to put all the requests of this page (HTML + embedded
pictures) within a transaction. In the example above, the transaction
Expand Down
8 changes: 7 additions & 1 deletion doc/user_manual.tex
Expand Up @@ -1183,11 +1183,17 @@ \subsection{Sessions}
Sessions define the content of the scenario itself. They describe
the requests to execute.
Each session has a given probability. This is used to decide which
session a new user will execute. The sum of all session\verb|'|s
probabilities must be 100.
\strong{Since Tsung 1.4.3}, you can use weights instead of
probabilities. In the following example, there will be twice as many
sessions of type s1 than s2.
\begin{Verbatim}
<session name="s1" weight="2" type="ts_http">
<session name="s2" weight="1" type="ts_http">
\end{Verbatim}
A transaction is just a way to have customized statistics. Say if you
Expand Down
2 changes: 2 additions & 0 deletions include/ts_config.hrl
Expand Up @@ -70,6 +70,8 @@
user_server_maxuid = none, % user_id max
oids=[],
rate_limit,
total_popularity = 0, % should be 100 if we use probabilites; sum of all weights if we use weights
use_weights , % true if we use weights instead of probabilities
job_notify_port
}).

Expand Down
12 changes: 12 additions & 0 deletions src/test/ts_test_config.erl
Expand Up @@ -16,6 +16,18 @@

test()->
ok.

popularity_test() ->
?assertError({"can't mix probabilites and weights",10,10}, ts_config:get_popularity(10,10,undefined,100)),
?assertError({"can't use probability when using weight"}, ts_config:get_popularity(10,0,true,100)),
?assertError({"can't use weights when using probabilities"}, ts_config:get_popularity(0,10,false,100)),
?assertEqual({10,false,110}, ts_config:get_popularity(10,0,false,100)),
?assertEqual({10,true,110}, ts_config:get_popularity(0,10,true,100)),
?assertEqual({30,false,60}, ts_config:get_popularity(30,0,false,30)),
?assertEqual({0,false,100}, ts_config:get_popularity(0,0,undefined,100)),
?assertEqual({0,true,100}, ts_config:get_popularity(0,0,true,100)),
?assertEqual({0,false,100}, ts_config:get_popularity(0,0,false,100)).

read_config_http_test() ->
myset_env(),
?assertMatch({ok, Config}, ts_config:read("./examples/http_simple.xml",".")).
Expand Down
27 changes: 25 additions & 2 deletions src/tsung_controller/ts_config.erl
Expand Up @@ -358,7 +358,9 @@ parse(Element = #xmlElement{name=session, attributes=Attrs},
Name = getAttr(Attrs, name),
?LOGF("Session name for id ~p is ~p~n",[Id+1, Name],?NOTICE),
?LOGF("Session type: persistent=~p, bidi=~p~n",[Persistent,Bidi],?NOTICE),
Probability = getAttr(float_or_integer, Attrs, probability),
Probability = getAttr(float_or_integer, Attrs, probability, 0),
Weight = getAttr(float_or_integer, Attrs, weight, 0),
{Popularity, NewUseWeights, NewTotal} = get_popularity(Probability, Weight, Conf#config.use_weights,Conf#config.total_popularity),
NewSList = case SList of
[] -> []; % first session
[Previous|Tail] ->
Expand All @@ -367,7 +369,7 @@ parse(Element = #xmlElement{name=session, attributes=Attrs},
end,
lists:foldl(fun parse/2,
Conf#config{sessions = [#session{id = Id + 1,
popularity = Probability,
popularity = Popularity,
type = Type,
name = Name,
persistent = Persistent,
Expand All @@ -378,6 +380,8 @@ parse(Element = #xmlElement{name=session, attributes=Attrs},
}
|NewSList],
main_sess_type = Type,
use_weights=NewUseWeights,
total_popularity=NewTotal,
curid=0, cur_req_id=0},% re-initialize request id
Element#xmlElement.content);

Expand Down Expand Up @@ -1016,3 +1020,22 @@ get_dynvar_name(VarNameStr) ->
{match,[Name,Index]} -> {list_to_atom(Name),Index};
_ -> list_to_atom(VarNameStr)
end.


%% @spec get_popularity(Proba::number(),Weight::number(),UseWeight:true|false|undefined, Total::number()) ->
%% {Value::number(), UseWeight:boolean(), Total:: number()}
%% check if we are using popularity or weights; keep the total up to date.
get_popularity(Proba,Weight,_,_) when is_number(Proba), Proba > 0, is_number(Weight), Weight > 0 ->
erlang:error({"can't mix probabilites and weights", Proba, Weight} );
get_popularity(Proba, Weight, true,_) when is_number(Proba), Proba > 0->
erlang:error({"can't use probability when using weight"});
get_popularity(_, Weight, false,_) when is_number(Weight), Weight > 0->
erlang:error({"can't use weights when using probabilities"});
get_popularity(_, Weight, undefined,_) when is_number(Weight), Weight > 0 ->
{Weight, true, Weight};
get_popularity(Proba, _, undefined,Total) when is_number(Proba) ->
{Proba, false, Proba+Total};
get_popularity(Proba, _, false,Total) when is_number(Proba) ->
{Proba, false, Proba+Total};
get_popularity(_, Weight, true, Total) when is_number(Weight) ->
{Weight, true, Weight+Total}.
31 changes: 17 additions & 14 deletions src/tsung_controller/ts_config_server.erl
Expand Up @@ -54,7 +54,7 @@
get_client_config/2, get_user_param/1, get_jobs_state/0 ]).

%%debug
-export([choose_client_ip/1, choose_session/1]).
-export([choose_client_ip/1, choose_session/2]).

%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
Expand Down Expand Up @@ -268,7 +268,7 @@ handle_call({get_next_session, HostName}, _From, State=#state{users=Users}) ->
Config = State#state.config,
{value, Client} = lists:keysearch(HostName, #client.host, Config#config.clients),
?DebugF("get new session for ~p~n",[_From]),
case choose_session(Config#config.sessions) of
case choose_session(Config#config.sessions, Config#config.total_popularity) of
{ok, Session=#session{id=Id}} ->
?LOGF("Session ~p choosen~n",[Id],?INFO),
ts_mon:newclient({Id,now()}),
Expand Down Expand Up @@ -327,7 +327,7 @@ handle_call({status}, _From, State) ->

handle_call({get_jobs_state}, _From, State) when State#state.config == undefined ->
{reply, not_configured, State};
handle_call({get_jobs_state}, {Pid,Tag}, State) ->
handle_call({get_jobs_state}, {Pid,_Tag}, State) ->
Config = State#state.config,
Reply = case Config#config.job_notify_port of
{Ets,Port} ->
Expand Down Expand Up @@ -514,15 +514,15 @@ choose_rr(List, Key, _) ->
{ok, lists:nth(I, List)}.

%%----------------------------------------------------------------------
%% Func: choose_session/1
%% Func: choose_session/2
%% Args: List of #session
%% Purpose: choose an session randomly
%% Returns: #session
%%----------------------------------------------------------------------
choose_session([Session]) -> %% only one Session
choose_session([Session], _Total) -> %% only one Session
{ok, Session};
choose_session(Sessions) ->
choose_session(Sessions, random:uniform() * 100,0).
choose_session(Sessions,Total) ->
choose_session(Sessions, random:uniform() * Total, 0).

choose_session([S=#session{popularity=P} | _],Rand,Cur) when Rand =< P+Cur->
{ok, S};
Expand Down Expand Up @@ -635,16 +635,17 @@ setup_user_servers(FileId,Val) when is_atom(FileId), is_integer(Val) ->
%% Func: check_config/1
%% Returns: ok | {error, ErrorList}
%%----------------------------------------------------------------------
check_config(Config)->
Pop= ts_utils:check_sum(Config#config.sessions, #session.popularity, ?SESSION_POP_ERROR_MSG),
check_config(Config=#config{use_weights=true})->
%% FIXME: we should not depend on a protocol specific feature here
Agents = ts_config_http:check_user_agent_sum(Config#config.session_tab),
case lists:filter(fun(X)-> X /= ok end, [Pop, Agents]) of
[] -> ok;
ErrorList -> {error, ErrorList}
ts_config_http:check_user_agent_sum(Config#config.session_tab);
check_config(Config)->
case abs(100-Config#config.total_popularity) < 0.05 of
false ->
{error, {bad_sum, Config#config.total_popularity ,?SESSION_POP_ERROR_MSG}};
true ->
ts_config_http:check_user_agent_sum(Config#config.session_tab)
end.


load_app(Name) when is_atom(Name) ->
FName = atom_to_list(Name) ++ ".app",
case code:where_is_file(FName) of
Expand Down Expand Up @@ -826,3 +827,5 @@ get_one_node_per_host([Node | Nodes], Dict) ->
NewDict = dict:store(Host, Node, Dict),
get_one_node_per_host(Nodes,NewDict)
end.


3 changes: 2 additions & 1 deletion tsung-1.0.dtd
Expand Up @@ -118,7 +118,8 @@ repeat | if | change_type | foreach | set_option)*>
name CDATA #REQUIRED
bidi CDATA #IMPLIED
persistent (true | false) #IMPLIED
probability NMTOKEN #REQUIRED
probability NMTOKEN #IMPLIED
weight NMTOKEN #IMPLIED
type (ts_jabber | ts_http | ts_raw | ts_pgsql | ts_ldap | ts_webdav |ts_mysql| ts_fs |ts_shell|ts_job) #REQUIRED>

<!ELEMENT change_type EMPTY>
Expand Down

0 comments on commit 2c7ba46

Please sign in to comment.