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 */ 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 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