1 /*
2 * Copyright (c) International Business Machines Corp., 2001-2004
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
12 * the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 #include <pthread.h>
19 #include <sys/time.h>
20 #include <sys/times.h>
21 #include <sys/types.h>
22 #include <sys/wait.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <pthread.h>
28
29 #include <assert.h>
30
31 #include "config.h"
32
33 #include "ffsb.h"
34 #include "util.h"
35 #include "parser.h"
36
37 /* State information for the polling function below */
38 struct ffsb_time_poll {
39 struct timeval starttime;
40 int wait_time;
41 };
42
43 /* This is the polling function used by the threadgroups to check
44 * elapsed time, when it returns 1 they know it is time to stop
45 */
ffsb_poll_fn(void * ptr)46 static int ffsb_poll_fn(void *ptr)
47 {
48 struct ffsb_time_poll *data = (struct ffsb_time_poll *)ptr;
49 struct timeval curtime, difftime;
50 gettimeofday(&curtime, NULL);
51
52 timersub(&curtime, &data->starttime, &difftime);
53 if (difftime.tv_sec >= data->wait_time)
54 return 1;
55 return 0;
56 }
57
main(int argc,char * argv[])58 int main(int argc, char *argv[])
59 {
60 int i;
61 ffsb_config_t fc;
62 ffsb_barrier_t thread_barrier, tg_barrier;
63 tg_run_params_t *params;
64 struct ffsb_time_poll pdata;
65 struct timeval starttime, endtime, difftime;
66 pthread_attr_t attr;
67 ffsb_op_results_t total_results;
68 double totaltime = 0.0f, usertime = 0.0f, systime = 0.0f;
69 struct rusage before_self, before_children, after_self, after_children;
70 pthread_t *fs_pts; /* threads to do filesystem creates in parallel */
71 char *callout = NULL;
72
73 char ctime_start_buf[32];
74 char ctime_end_buf[32];
75
76 memset(&before_self, 0, sizeof(before_self));
77 memset(&before_children, 0, sizeof(before_children));
78 memset(&after_self, 0, sizeof(after_self));
79 memset(&after_children, 0, sizeof(after_children));
80
81 ffsb_unbuffer_stdout();
82
83 if (argc < 2) {
84 fprintf(stderr, "usage: %s <config file>\n", argv[0]);
85 exit(1);
86 }
87
88 /* VERSION comes from config.h (which is autogenerated by autoconf) */
89 printf("FFSB version %s started\n\n", VERSION);
90
91 ffsb_parse_newconfig(&fc, argv[1]);
92 pdata.wait_time = fc.time;
93
94 if (fc.time)
95 printf("benchmark time = %u\n", fc.time);
96 else
97 printf("Only creating the fileset, not running benchmark.\n");
98
99 pthread_attr_init(&attr);
100 pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
101
102 for (i = 0; i < fc.num_threadgroups; i++)
103 tg_print_config(&fc.groups[i]);
104
105 fs_pts = ffsb_malloc(sizeof(pthread_t) * fc.num_filesys);
106
107 gettimeofday(&starttime, NULL);
108 for (i = 0; i < fc.num_filesys; i++) {
109 fs_print_config(&fc.filesystems[i]);
110 pthread_create(fs_pts + i, &attr, construct_ffsb_fs,
111 &fc.filesystems[i]);
112 }
113
114 fflush(stdout);
115 for (i = 0; i < fc.num_filesys; i++)
116 pthread_join(fs_pts[i], NULL);
117
118 gettimeofday(&endtime, NULL);
119 timersub(&endtime, &starttime, &difftime);
120 printf("fs setup took %ld secs\n", difftime.tv_sec);
121 free(fs_pts);
122
123 if (fc.time == 0) {
124 printf("Setup complete, exiting\n");
125 return 0;
126 }
127
128 params = ffsb_malloc(sizeof(tg_run_params_t) * fc.num_threadgroups);
129
130 init_ffsb_op_results(&total_results);
131 ffsb_barrier_init(&thread_barrier, fc.num_totalthreads);
132 ffsb_barrier_init(&tg_barrier, fc.num_threadgroups + 1);
133
134 ffsb_sync();
135
136 /* Execute the callout if any and wait for it to return */
137 callout = fc_get_callout(&fc);
138 if (callout) {
139 printf("executing callout: \n %s\n", callout);
140 if (ffsb_system(callout) < 0) {
141 perror("system");
142 exit(1);
143 }
144 }
145
146 /* Spawn all of the threadgroup master threads */
147 for (i = 0; i < fc.num_threadgroups; i++) {
148 params[i].tg = &fc.groups[i];
149 params[i].fc = &fc;
150 params[i].poll_fn = ffsb_poll_fn;
151 params[i].poll_data = &pdata;
152 params[i].wait_time = FFSB_TG_WAIT_TIME;
153 params[i].tg_barrier = &tg_barrier;
154 params[i].thread_barrier = &thread_barrier;
155
156 pthread_create(¶ms[i].pt, &attr, tg_run, ¶ms[i]);
157 }
158
159 ffsb_getrusage(&before_self, &before_children);
160 gettimeofday(&pdata.starttime, NULL);
161
162 ffsb_barrier_wait(&tg_barrier); /* sync with tg's to start */
163 printf("Starting Actual Benchmark At: %s\n",
164 ctime_r(&pdata.starttime.tv_sec, ctime_start_buf));
165 fflush(stdout);
166
167 /* Wait for all of the threadgroup master threads to finish */
168 for (i = 0; i < fc.num_threadgroups; i++)
169 pthread_join(params[i].pt, NULL);
170
171 ffsb_sync();
172 gettimeofday(&endtime, NULL);
173 ffsb_getrusage(&after_self, &after_children);
174
175 printf("FFSB benchmark finished at: %s\n",
176 ctime_r(&endtime.tv_sec, ctime_end_buf));
177 printf("Results:\n");
178 fflush(stdout);
179
180 timersub(&endtime, &pdata.starttime, &difftime);
181
182 totaltime = tvtodouble(&difftime);
183
184 printf("Benchmark took %.2lf sec\n", totaltime);
185 printf("\n");
186
187 for (i = 0; i < fc.num_threadgroups; i++) {
188 struct ffsb_op_results tg_results;
189 ffsb_tg_t *tg = fc.groups + i;
190
191 init_ffsb_op_results(&tg_results);
192
193 /* Grab the individual tg results */
194 tg_collect_results(tg, &tg_results);
195
196 if (fc.num_threadgroups == 1)
197 printf("Total Results\n");
198 else
199 printf("ThreadGroup %d\n", i);
200
201 printf("===============\n");
202 print_results(&tg_results, totaltime);
203
204 if (tg_needs_stats(tg)) {
205 ffsb_statsd_t fsd;
206 tg_collect_stats(tg, &fsd);
207 ffsb_statsd_print(&fsd);
208 }
209 printf("\n");
210
211 /* Add the tg results to the total */
212 tg_collect_results(&fc.groups[i], &total_results);
213 }
214
215 if (fc.num_threadgroups > 1) {
216 printf("Total Results\n");
217 printf("===============\n");
218 print_results(&total_results, totaltime);
219 }
220 #define USEC_PER_SEC ((double)(1000000.0f))
221
222 /* sum up self and children after */
223 usertime = (after_self.ru_utime.tv_sec +
224 ((after_self.ru_utime.tv_usec) / USEC_PER_SEC)) +
225 ((after_children.ru_utime.tv_sec +
226 ((after_children.ru_utime.tv_usec) / USEC_PER_SEC)));
227
228 /* subtract away the before */
229 usertime -= (before_self.ru_utime.tv_sec +
230 ((before_self.ru_utime.tv_usec) / USEC_PER_SEC)) +
231 ((before_children.ru_utime.tv_sec +
232 ((before_children.ru_utime.tv_usec) / USEC_PER_SEC)));
233
234 /* sum up self and children after */
235 systime = (after_self.ru_stime.tv_sec +
236 ((after_self.ru_stime.tv_usec) / USEC_PER_SEC)) +
237 ((after_children.ru_stime.tv_sec +
238 ((after_children.ru_stime.tv_usec) / USEC_PER_SEC)));
239
240 /* subtract away the before */
241 systime -= (before_self.ru_stime.tv_sec +
242 ((before_self.ru_stime.tv_usec) / USEC_PER_SEC)) +
243 ((before_children.ru_stime.tv_sec +
244 ((before_children.ru_stime.tv_usec) / USEC_PER_SEC)));
245
246 printf("\n\n");
247 printf("%.1lf%% User Time\n", 100 * usertime / totaltime);
248 printf("%.1lf%% System Time\n", 100 * systime / totaltime);
249 printf("%.1f%% CPU Utilization\n", 100 * (usertime + systime) /
250 totaltime);
251 free(params);
252 destroy_ffsb_config(&fc);
253
254 return 0;
255 }
256