a91aef9061e76bfa878b47782c5ef94f478ada0a
[yaz-moved-to-github.git] / zoom / zoom-benchmark.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2008 Index Data
3  * See the file LICENSE for details.
4  */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <ctype.h>
10 #include <sys/time.h>
11
12 #include <yaz/xmalloc.h>
13 #include <yaz/options.h>
14 #include <yaz/zoom.h>
15
16
17 /* naming events */
18 static char* zoom_events[ZOOM_EVENT_MAX+1];
19
20 /* re-sorting event numbers to progress numbers */
21 static int zoom_progress[ZOOM_EVENT_MAX+1];
22
23 /* commando line parameters */
24 static struct parameters_t { 
25     char host[1024];
26     char query[1024];
27     int progress[4096];
28     int concurrent;
29     int repeat;
30     int timeout;
31     char proxy[1024];
32     int piggypack;
33     int gnuplot;
34 } parameters;
35
36 struct  event_line_t 
37 {
38     int connection;
39     long time_sec;
40     long time_usec;
41     int progress;
42     int event;
43     char zoom_event[128];
44     int error;
45     char errmsg[128];
46 };
47
48
49 void print_event_line(struct event_line_t *pel)
50 {
51     printf ("%d\t%ld.%06ld\t%d\t%d\t%s\t%d\t%s\n",
52             pel->connection, pel->time_sec, pel->time_usec, 
53             pel->progress,
54             pel->event, pel->zoom_event, 
55             pel->error, pel->errmsg);
56 }
57
58 void  update_events(int *elc, struct event_line_t *els,
59                     int repeat,
60                     int conn,
61                     long sec,
62                     long usec,
63                     int prog,
64                     int event,
65                     const char * eventmsg,
66                     int error,
67                     const char * errmsg){
68
69     int ielc = repeat*parameters.concurrent + conn;
70     int iels = repeat*parameters.concurrent*10 + conn*10 + elc[ielc];
71
72     els[iels].connection = conn;
73     els[iels].time_sec = sec;
74     els[iels].time_usec = usec;
75     els[iels].progress = prog;
76     els[iels].event = event;
77
78     if (eventmsg)
79         strcpy(els[iels].zoom_event, eventmsg);
80     else
81         strcpy(els[iels].zoom_event, "---");
82
83     els[iels].error = error;
84     strcpy(els[iels].errmsg, errmsg);
85     /* print_event_line(&els[iels]); */
86     elc[ielc] += 1;
87 }
88
89 void  print_events(int *elc,  struct event_line_t *els, 
90                    int connections){
91     int i;
92     int j;
93     int k;
94     int ielc;
95     int iels;
96
97     for (k=0; k < parameters.repeat; k++){
98         for (i=0; i < connections; i++){
99             ielc = k * parameters.concurrent + i;
100             for (j=0; j < elc[ielc]; j++){
101                 iels = k * parameters.concurrent * 10 + i * 10 + j;
102                 print_event_line(&els[iels]);
103             }
104             printf("\n");
105         }
106         printf("\n");
107     }
108 }
109
110
111
112 void init_statics(void)
113 {
114     int i;
115     char nullstring[1] = "";
116
117     /* naming events */
118     zoom_events[ZOOM_EVENT_NONE] = "ZOOM_EVENT_NONE";
119     zoom_events[ZOOM_EVENT_CONNECT] = "ZOOM_EVENT_CONNECT";
120     zoom_events[ZOOM_EVENT_SEND_DATA] = "ZOOM_EVENT_SEND_DATA";
121     zoom_events[ZOOM_EVENT_RECV_DATA] = "ZOOM_EVENT_RECV_DATA";
122     zoom_events[ZOOM_EVENT_TIMEOUT] = "ZOOM_EVENT_TIMEOUT";
123     zoom_events[ZOOM_EVENT_UNKNOWN] = "ZOOM_EVENT_UNKNOWN";
124     zoom_events[ZOOM_EVENT_SEND_APDU] = "ZOOM_EVENT_SEND_APDU";
125     zoom_events[ZOOM_EVENT_RECV_APDU] = "ZOOM_EVENT_RECV_APDU";
126     zoom_events[ZOOM_EVENT_RECV_RECORD] = "ZOOM_EVENT_RECV_RECORD";
127     zoom_events[ZOOM_EVENT_RECV_SEARCH] = "ZOOM_EVENT_RECV_SEARCH";
128     zoom_events[ZOOM_EVENT_END] = "ZOOM_EVENT_END";
129
130     /* re-sorting event numbers to progress numbers */
131     zoom_progress[ZOOM_EVENT_NONE] = 0;
132     zoom_progress[ZOOM_EVENT_CONNECT] = 1;
133     zoom_progress[ZOOM_EVENT_SEND_DATA] = 3;
134     zoom_progress[ZOOM_EVENT_RECV_DATA] = 4;
135     zoom_progress[ZOOM_EVENT_TIMEOUT] = 9;
136     zoom_progress[ZOOM_EVENT_UNKNOWN] = 10;
137     zoom_progress[ZOOM_EVENT_SEND_APDU] = 2;
138     zoom_progress[ZOOM_EVENT_RECV_APDU] = 5;
139     zoom_progress[ZOOM_EVENT_RECV_RECORD] = 7;
140     zoom_progress[ZOOM_EVENT_RECV_SEARCH] = 6;
141     zoom_progress[ZOOM_EVENT_END] = 8;
142
143     /* parameters */
144     parameters.concurrent = 1;
145     parameters.timeout = 0;
146     parameters.repeat = 1;
147     strcpy(parameters.proxy, nullstring);
148     parameters.gnuplot = 0;
149     parameters.piggypack = 0;
150
151     /* progress initializing */
152     for (i = 0; i < 4096; i++){
153         parameters.progress[i] = 0;
154     }
155     
156 }
157  
158 struct time_type 
159 {
160     struct timeval now;
161     struct timeval then;
162     long sec;
163     long usec;
164 };
165
166 void time_init(struct time_type *ptime)
167 {
168     gettimeofday(&(ptime->now), 0);
169     gettimeofday(&(ptime->then), 0);
170     ptime->sec = 0;
171     ptime->usec = 0;
172 }
173
174 void time_stamp(struct time_type *ptime)
175 {
176     gettimeofday(&(ptime->now), 0);
177     ptime->sec = ptime->now.tv_sec - ptime->then.tv_sec;
178     ptime->usec = ptime->now.tv_usec - ptime->then.tv_usec;
179     if (ptime->usec < 0){
180         ptime->sec--;
181         ptime->usec += 1000000;
182     }
183 }
184
185 long time_sec(struct time_type *ptime)
186 {
187     return ptime->sec;
188 }
189
190 long time_usec(struct time_type *ptime)
191 {
192     return ptime->usec;
193 }
194
195 void print_option_error(void)
196 {
197     fprintf(stderr, "zoom-benchmark:  Call error\n");
198     fprintf(stderr, "zoom-benchmark -h host:port -q pqf-query "
199             "[-c no_concurrent (max 4096)] "
200             "[-n no_repeat] "
201             "[-b (piggypack)] "
202             "[-g (gnuplot outfile)] "
203             "[-p proxy] \n");
204     /* "[-t timeout] \n"); */
205     exit(1);
206 }
207
208
209 void read_params(int argc, char **argv, struct parameters_t *p_parameters){    
210     char *arg;
211     int ret;
212     while ((ret = options("h:q:c:t:p:bgn:", argv, argc, &arg)) != -2)
213     {
214         switch (ret)
215         {
216         case 'h':
217             strcpy(p_parameters->host, arg);
218             break;
219         case 'q':
220             strcpy(p_parameters->query, arg);
221             break;
222         case 'p':
223             strcpy(p_parameters->proxy, arg);
224             break;
225         case 'c':
226             p_parameters->concurrent = atoi(arg);
227             break;
228 #if 0
229             case 't':
230             p_parameters->timeout = atoi(arg);
231             break;
232 #endif
233         case 'b':
234             p_parameters->piggypack = 1;
235                     break;
236         case 'g':
237             p_parameters->gnuplot = 1;
238                     break;
239         case 'n':
240             p_parameters->repeat = atoi(arg);
241                     break;
242         case 0:
243             print_option_error();
244             break;
245         default:
246             print_option_error();
247         }
248     }
249     
250     if(0){
251         printf("zoom-benchmark\n");
252         printf("   host:       %s \n", p_parameters->host);
253         printf("   query:      %s \n", p_parameters->query);
254         printf("   concurrent: %d \n", p_parameters->concurrent);
255         printf("   repeat:     %d \n", p_parameters->repeat);
256 #if 0
257         printf("   timeout:    %d \n", p_parameters->timeout);
258 #endif
259         printf("   proxy:      %s \n", p_parameters->proxy);
260         printf("   piggypack:  %d \n\n", p_parameters->piggypack);
261         printf("   gnuplot:    %d \n\n", p_parameters->gnuplot);
262     }
263
264     if (! strlen(p_parameters->host))
265         print_option_error();
266     if (! strlen(p_parameters->query))
267         print_option_error();
268     if (! (p_parameters->concurrent > 0))
269         print_option_error();
270     if (! (p_parameters->repeat > 0))
271         print_option_error();
272     if (! (p_parameters->timeout >= 0))
273         print_option_error();
274     if (! ( p_parameters->concurrent <= 4096))
275         print_option_error();
276 }
277
278 void print_table_header(void)
279 {
280     if (parameters.gnuplot)
281         printf("#");
282     printf ("target\tsecond.usec\tprogress\tevent\teventname\t");
283     printf("error\terrorname\n");
284 }
285
286
287 int main(int argc, char **argv)
288 {
289     struct time_type time;
290     ZOOM_connection *z;
291     ZOOM_resultset *r;
292     int *elc;
293     struct event_line_t *els;
294     ZOOM_options o;
295     int i;
296     int k;
297
298     init_statics();
299
300     read_params(argc, argv, &parameters);
301
302     z = (ZOOM_connection *) xmalloc(sizeof(*z) * parameters.concurrent);
303     r = (ZOOM_resultset *) xmalloc(sizeof(*r) * parameters.concurrent);
304     elc = (int *) xmalloc(sizeof(*elc) * parameters.concurrent * parameters.repeat);
305     els = (struct event_line_t *) xmalloc(
306         sizeof(*els) * parameters.concurrent * parameters.repeat * 10);
307     o = ZOOM_options_create();
308
309     /* async mode */
310     ZOOM_options_set (o, "async", "1");
311
312     /* get first record of result set (using piggypack) */
313     if (parameters.piggypack)
314         ZOOM_options_set (o, "count", "1");
315
316     /* set proxy */
317     if (strlen(parameters.proxy))
318         ZOOM_options_set (o, "proxy", parameters.proxy);
319
320
321     /* preferred record syntax */
322     if (0){
323         ZOOM_options_set (o, "preferredRecordSyntax", "usmarc");
324         ZOOM_options_set (o, "elementSetName", "F");
325     }
326     
327     time_init(&time);
328     /* repeat loop */
329     for (k = 0; k < parameters.repeat; k++){
330
331         /* progress zeroing */
332         for (i = 0; i < 4096; i++){
333             parameters.progress[i] = k * 5 -1;
334         }
335
336         /* connect to all concurrent connections*/
337         for ( i = 0; i < parameters.concurrent; i++){
338             /* set event count to zero */
339             elc[k * parameters.concurrent + i] = 0;
340
341             /* create connection - pass options (they are the same for all) */
342             z[i] = ZOOM_connection_create(o);
343             
344             /* connect and init */
345             ZOOM_connection_connect(z[i], parameters.host, 0);
346         }
347         /* search all */
348         for (i = 0; i < parameters.concurrent; i++)
349             r[i] = ZOOM_connection_search_pqf (z[i], parameters.query);
350
351         /* network I/O. pass number of connections and array of connections */
352         while ((i = ZOOM_event (parameters.concurrent, z))){ 
353             int event = ZOOM_connection_last_event(z[i-1]);
354             const char *errmsg;
355             const char *addinfo;
356             int error = 0;
357             //int progress = zoom_progress[event];
358             
359             if (event == ZOOM_EVENT_SEND_DATA || event == ZOOM_EVENT_RECV_DATA)
360                 continue;
361
362             time_stamp(&time);
363
364             /* updating events and event list */
365             error = ZOOM_connection_error(z[i-1] , &errmsg, &addinfo);
366             if (error)
367                 parameters.progress[i] = zoom_progress[ZOOM_EVENT_UNKNOWN];
368             //parameters.progress[i] = zoom_progress[ZOOM_EVENT_NONE];
369             else if (event == ZOOM_EVENT_CONNECT)
370                 parameters.progress[i] = zoom_progress[event];
371             else
372                 //parameters.progress[i] = zoom_progress[event];
373                 parameters.progress[i] += 1;
374             
375             update_events(elc, els,
376                           k, i-1, 
377                           time_sec(&time), time_usec(&time), 
378                           parameters.progress[i],
379                           event, zoom_events[event], 
380                           error, errmsg);
381         }
382
383         /* destroy connections */
384         for (i = 0; i<parameters.concurrent; i++)
385             {
386                 ZOOM_resultset_destroy (r[i]);
387                 ZOOM_connection_destroy (z[i]);
388             }
389
390
391
392     } /* for (k = 0; k < parameters.repeat; k++) repeat loop */
393
394     /* output */
395
396     if (parameters.gnuplot){
397         printf("# gnuplot data and instruction file \n");
398         printf("# gnuplot thisfile \n");
399         printf("\n");
400         printf("set title \"Z39.50 connection plot\"\n");
401         printf("set xlabel \"Connection\"\n");
402         printf("set ylabel \"Time Seconds\"\n");
403         printf("set zlabel \"Progress\"\n");
404         printf("set ticslevel 0\n");
405         printf("set grid\n");
406         printf("set pm3d\n");
407         printf("splot '-' using ($1):($2):($3) t '' with points\n");
408         printf("\n");
409         printf("\n");
410     }
411     
412     print_table_header();    
413     print_events(elc,  els, parameters.concurrent);
414     
415     if (parameters.gnuplot){
416         printf("end\n");
417         printf("pause -1 \"Hit ENTER to return\"\n");
418     }
419
420     /* destroy data structures and exit */
421     xfree(z);
422     xfree(r);
423     xfree(elc);
424     xfree(els);
425     ZOOM_options_destroy(o);
426     exit (0);
427 }
428 /*
429  * Local variables:
430  * c-basic-offset: 4
431  * indent-tabs-mode: nil
432  * End:
433  * vim: shiftwidth=4 tabstop=8 expandtab
434  */
435