1 /*
2  * This file is part of the Sofia-SIP package
3  *
4  * Copyright (C) 2005 Nokia Corporation.
5  *
6  * Contact: Pekka Pessi <pekka.pessi@nokia.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24 
25 /**@ingroup su_root_ex
26  * @CFILE su_perf.c
27  *
28  * Performance test for su message passing
29  *
30  * @internal
31  *
32  * @author Pekka Pessi <Pekka.Pessi@nokia.com>
33  *
34  * @date Created: Thu Mar 18 19:40:51 1999 pessi
35  */
36 
37 #include "config.h"
38 
39 #include <stdlib.h>
40 #include <assert.h>
41 #include <stdio.h>
42 #include <string.h>
43 
44 struct perf;
45 #define SU_ROOT_MAGIC_T struct perf
46 #define SU_MSG_ARG_T    struct message
47 
48 #include "sofia-sip/su.h"
49 #include "sofia-sip/su_wait.h"
50 
51 struct perf {
52   enum { PINGER = 1, PONGER = 2 } const sort;
53   char const *const name;
54   unsigned          running : 1;
55   unsigned          target;
56   unsigned          n;
57   su_root_t        *root;
58   struct sockaddr_in sin;
59 };
60 
61 struct message {
62   su_time_t started;
63 };
64 
65 void
do_exit(struct perf * x,su_msg_r msg,struct message * m)66 do_exit(struct perf *x, su_msg_r msg, struct message *m)
67 {
68   su_root_break(su_task_root(su_msg_to(msg)));
69 }
70 
71 int
do_init(su_root_t * root,struct perf * p)72 do_init(su_root_t *root, struct perf *p)
73 {
74   p->root = root;
75   return 0;
76 }
77 
78 void
do_print(struct perf * p,su_msg_r msg,struct message * m)79 do_print(struct perf *p, su_msg_r msg, struct message *m)
80 {
81   su_time_t now = su_now();
82   double dur = su_time_diff(now, m->started);
83 
84   printf("su_perf: %g message exchanges per second"
85 	 " (%d message exchanges in %g seconds)\n",
86 	 (double)p->n / dur, p->n, dur);
87   su_msg_create(msg, su_root_parent(p->root), su_root_task(p->root),
88 		do_exit, sizeof(*m));
89   *su_msg_data(msg) = *m;
90   su_msg_send(msg);
91 }
92 
93 void
do_ping(struct perf * p,su_msg_r msg,struct message * m)94 do_ping(struct perf *p, su_msg_r msg, struct message *m)
95 {
96   if (p->sort == PINGER) {
97     p->n++;
98 
99     if (p->n % 100 == 0) {
100       if (su_duration(su_now(), m->started) > p->target) {
101 	do_print(p, msg, m);
102 	return;
103       }
104     }
105   }
106 
107   su_msg_reply(msg, msg, do_ping, sizeof(*m));
108   *su_msg_data(msg) = *m;
109   su_msg_send(msg);
110 }
111 
112 void
do_destroy(su_root_t * t,struct perf * p)113 do_destroy(su_root_t *t, struct perf *p)
114 {
115   p->running = 0;
116 }
117 
usage(char * name)118 void usage(char *name)
119 {
120   fprintf(stderr, "usage: %s [-1] [n]\n", name);
121   exit(2);
122 }
123 
124 /*
125  * Measure how many message passes can be done in a second.
126  *
127  * Create a ponger and pinger, responding to incoming message do_ping
128  *
129  * After "target" rounds, print out elapsed time and number of messages
130  * passed.
131  *
132  */
main(int argc,char * argv[])133 int main(int argc, char *argv[])
134 {
135   su_root_t *root;
136   su_clone_r ping = SU_CLONE_R_INIT, pong = SU_CLONE_R_INIT;
137   su_msg_r start_msg = SU_MSG_R_INIT;
138 
139   struct perf
140     pinger = { PINGER, "ping", 1, 0 },
141     ponger = { PONGER, "pong", 1, 0x7fffffff};
142 
143   int have_threads = 1;
144   char *argv0 = argv[0];
145   char *argv1 = argv[1];
146 
147   if (argv1 && strcmp(argv1, "-1") == 0)
148     have_threads = 0, argv1 = argv[2];
149 
150   if (!argv1)
151     argv1 = "10000";
152 
153   if (strlen(argv1) != strspn(argv1, "0123456789"))
154     usage(argv0);
155 
156   pinger.target = strtoul(argv1, NULL, 0);
157 
158   su_init(); atexit(su_deinit);
159 
160   root = su_root_create(NULL);
161 
162   su_root_threading(root, have_threads);
163 
164   if (su_clone_start(root, ping, &pinger, do_init, do_destroy) != 0)
165     perror("su_clone_start"), exit(1);
166   if (su_clone_start(root, pong, &ponger, do_init, do_destroy) != 0)
167     perror("su_clone_start"), exit(1);
168 
169   if (su_msg_create(start_msg, su_clone_task(pong), su_clone_task(ping),
170 		    do_ping, sizeof(struct message)) == 0) {
171     su_msg_data(start_msg)->started = su_now();
172     su_msg_send(start_msg);
173 
174     su_root_run(root);
175   }
176 
177 #if 0
178   su_clone_wait(root, ping);
179   su_clone_wait(root, pong);
180 
181   while (pinger.running || ponger.running)
182     su_root_step(root, 100L);
183 #endif
184 
185   su_root_destroy(root);
186 
187   return 0;
188 }
189