1    	/*
2    	 * Copyright (c) 2009 Red Hat, Inc.
3    	 *
4    	 * All rights reserved.
5    	 *
6    	 * Author: Steven Dake (sdake@redhat.com)
7    	 *
8    	 * libqb is free software: you can redistribute it and/or modify
9    	 * it under the terms of the GNU Lesser General Public License as published by
10   	 * the Free Software Foundation, either version 2.1 of the License, or
11   	 * (at your option) any later version.
12   	 *
13   	 * libqb is distributed in the hope that it will be useful,
14   	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   	 * GNU Lesser General Public License for more details.
17   	 *
18   	 * You should have received a copy of the GNU Lesser General Public License
19   	 * along with libqb.  If not, see <http://www.gnu.org/licenses/>.
20   	 */
21   	#include <unistd.h>
22   	#include <sys/types.h>
23   	#include <sys/socket.h>
24   	#include <errno.h>
25   	#include <assert.h>
26   	#include <stdio.h>
27   	#include <stdint.h>
28   	#include <stdlib.h>
29   	#include <string.h>
30   	#include <sys/time.h>
31   	#include <time.h>
32   	#include <signal.h>
33   	
34   	#include <qb/qbdefs.h>
35   	#include <qb/qbutil.h>
36   	#include <qb/qbipcc.h>
37   	
38   	#define ITERATIONS 10000000
39   	#define THREADS 4
40   	
41   	struct bm_ctx {
42   		qb_ipcc_connection_t *conn;
43   		qb_util_stopwatch_t *sw;
44   		float mbs;
45   		float secs;
46   		int32_t multi;
47   		uint32_t counter;
48   	};
49   	
50   	static void bm_start(struct bm_ctx *ctx)
51   	{
52   		qb_util_stopwatch_start(ctx->sw);
53   	}
54   	
55   	static void bm_finish(struct bm_ctx *ctx, const char *operation, int32_t size)
56   	{
57   		qb_util_stopwatch_stop(ctx->sw);
(1) Event zero_return: Function call "qb_util_stopwatch_sec_elapsed_get(ctx->sw)" returns 0.0. [details]
(2) Event assign: Assigning: "ctx->secs" = "qb_util_stopwatch_sec_elapsed_get(ctx->sw)".
Also see events: [divide_by_zero]
58   		ctx->secs = qb_util_stopwatch_sec_elapsed_get(ctx->sw);
59   	
(3) Event divide_by_zero: In expression "(float)ctx->counter * size / ctx->secs", division by expression "ctx->secs" which may be zero results in either +infinity, -infinity, or NaN.
Also see events: [zero_return][assign]
60   		ctx->mbs =
61   		    ((((float)ctx->counter) * size) / ctx->secs) / (1024.0 *
62   								    1024.0);
63   	}
64   	
65   	static void bmc_connect(struct bm_ctx *ctx)
66   	{
67   		ctx->sw = qb_util_stopwatch_create();
68   		ctx->conn = qb_ipcc_connect("bm1", QB_MAX(1000 * (100 + THREADS),
69   							  1024*1024));
70   		if (ctx->conn == NULL) {
71   			perror("qb_ipcc_connect");
72   			exit(-1);
73   		}
74   	}
75   	
76   	static void bmc_disconnect(struct bm_ctx *ctx)
77   	{
78   		qb_ipcc_disconnect(ctx->conn);
79   		qb_util_stopwatch_free(ctx->sw);
80   	}
81   	
82   	struct my_req {
83   		struct qb_ipc_request_header hdr;
84   		char message[1024 * 1024];
85   	};
86   	
87   	static struct my_req request;
88   	
89   	static int32_t bmc_send_nozc(struct bm_ctx *ctx, uint32_t size)
90   	{
91   		struct qb_ipc_response_header res_header;
92   		int32_t res;
93   	
94   		request.hdr.id = QB_IPC_MSG_USER_START + 3;
95   		request.hdr.size = sizeof(struct qb_ipc_request_header) + size;
96   	
97   	repeat_send:
98   		res = qb_ipcc_send(ctx->conn, &request, request.hdr.size);
99   		if (res < 0) {
100  			if (res == -EAGAIN) {
101  				goto repeat_send;
102  			} else if (res == -EINVAL || res == -EINTR) {
103  				perror("qb_ipcc_send");
104  				return -1;
105  			} else {
106  				errno = -res;
107  				perror("qb_ipcc_send");
108  				goto repeat_send;
109  			}
110  		}
111  	
112  		res = qb_ipcc_recv(ctx->conn, &res_header,
113  				   sizeof(struct qb_ipc_response_header), -1);
114  		if (res == -EINTR) {
115  			return -1;
116  		}
117  		if (res < 0) {
118  			perror("qb_ipcc_recv");
119  		}
120  		assert(res == sizeof(struct qb_ipc_response_header));
121  		assert(res_header.id == 13);
122  		assert(res_header.size == sizeof(struct qb_ipc_response_header));
123  		return 0;
124  	}
125  	
126  	uint32_t alarm_notice = 0;
127  	static void sigalrm_handler(int32_t num)
128  	{
129  		alarm_notice = 1;
130  	}
131  	
132  	static void *benchmark(void *ctx)
133  	{
134  		struct bm_ctx *bm_ctx = (struct bm_ctx *)ctx;
135  		int32_t res;
136  	
137  		bmc_connect(bm_ctx);
138  	
139  		bm_start(bm_ctx);
140  		for (;;) {
141  			bm_ctx->counter++;
142  			res = bmc_send_nozc(bm_ctx, 1000 * bm_ctx->multi);
143  			if (alarm_notice || res == -1) {
144  				bm_finish(bm_ctx, "send_nozc", 1000 * bm_ctx->multi);
145  				bmc_disconnect(bm_ctx);
146  				return (NULL);
147  			}
148  		}
149  	}
150  	
151  	
152  	int32_t main(void)
153  	{
154  		struct bm_ctx bm_ctx[THREADS];
155  		pthread_t threads[THREADS];
156  		pthread_attr_t thread_attr[THREADS];
157  		int32_t i, j;
158  		float total_mbs;
159  		void *retval;
160  	
161  		for (i = 0; i < THREADS; i++) {
162  			bm_ctx[i].mbs = 0;
163  		}
164  		signal(SIGALRM, sigalrm_handler);
165  		for (j = 0; j < 500; j++) {
166  			alarm_notice = 0;
167  			alarm(3);
168  			for (i = 0; i < THREADS; i++) {
169  				bm_ctx[i].multi = j + 100;
170  				bm_ctx[i].counter = 0;
171  				pthread_attr_init(&thread_attr[i]);
172  	
173  				pthread_attr_setdetachstate(&thread_attr[i],
174  							    PTHREAD_CREATE_JOINABLE);
175  				pthread_create(&threads[i], &thread_attr[i], benchmark,
176  					       &bm_ctx[i]);
177  			}
178  			for (i = 0; i < THREADS; i++) {
179  				pthread_join(threads[i], &retval);
180  			}
181  			total_mbs = 0;
182  			for (i = 0; i < THREADS; i++) {
183  				total_mbs = total_mbs + bm_ctx[i].mbs;
184  			}
185  			printf("%d ", 1000 * bm_ctx[0].multi);
186  			printf("%9.3f\n", total_mbs);
187  		}
188  		return EXIT_SUCCESS;
189  	}
190