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 #ifndef _FFSB_TG_H_
19 #define _FFSB_TG_H_
20 #include <inttypes.h>
21 #include <stdlib.h>
22 #include <sys/types.h>
23 
24 #include <pthread.h>
25 
26 #include "ffsb.h"
27 #include "ffsb_op.h"
28 #include "ffsb_thread.h"
29 #include "ffsb_fs.h"
30 #include "ffsb_stats.h"
31 
32 #include "util.h" /* for barrier obj */
33 
34 /* "Thread Group" object defs.
35  *
36  *  A thread group contains configuration information and can run its
37  *  "gang" of threads performing a particular mix of operations.
38  *
39  * The thread group is responsible for creating the ffsb_thread
40  * objects which must ask the thread group object to select an
41  * operation and a filesystem to run that operation on.  The thread
42  * objects don't contain any of the configuration information.
43  *
44  * Thread groups are also abstracted so they can be "run" arbitrarily
45  * which is useful because we can reuse them for aging.  The running
46  * is a bit complex, the thread group has to have a callback function
47  * which is runs at a specified interval to determine when to
48  * terminate.
49  *
50  * To synchronize starting across many thread groups there are two
51  * barriers used, the first one "tg_barrier" in the run_params is to
52  * synchronize multiple thread-groups being ready to start, meaning
53  * that all their threads have been spawned The second one
54  * "thread_barrier" synchronizes all threads across multiple thread
55  * groups, so that they all start at once.
56 */
57 
58 struct ffsb_thread;
59 struct ffsb_config;
60 
61 typedef struct ffsb_tg {
62 	unsigned tg_num;
63 	unsigned num_threads;
64 	unsigned op_weights[FFSB_NUMOPS];
65 	struct ffsb_thread *threads;
66 
67 	/* A threadgroup can be bound to just one filesystem.
68 	 * A value * < 0 , means we aren't bound to any.
69 	*/
70 	int bindfs;
71 
72 	int read_random;	/* boolean */
73 	uint64_t read_size;
74 	uint32_t read_blocksize;
75 
76 	int read_skip;		/* boolean */
77 	uint32_t read_skipsize;
78 
79 	int write_random;	/* boolean */
80 	uint64_t write_size;
81 	uint32_t write_blocksize;
82 
83 	int fsync_file;		/* boolean */
84 
85 	/* Should be max(write_blocksize, read_blocksize) */
86 	uint32_t thread_bufsize;
87 
88 	/* these fields are calculated/set by tg_run() */
89 	unsigned sum_weights;
90 	struct ffsb_config *fc;
91 	ffsb_barrier_t *start_barrier;
92 
93 	/* Used for stopping the threads */
94 	int flagval;
95 	int stopval;
96 
97 	/* Delay between every operation, in milliseconds*/
98 	unsigned wait_time;
99 
100 	/* stats configuration */
101 	int need_stats;
102 	ffsb_statsc_t fsc;
103 } ffsb_tg_t;
104 
105 /* Init should be the very first thing called on the tg.  After that,
106  * the user can call the set methods and finally run.
107  */
108 void init_ffsb_tg(ffsb_tg_t *tg, unsigned num_threads, unsigned tg_num);
109 void destroy_ffsb_tg(ffsb_tg_t *tg);
110 
111 /* Parameters needed to fire off a thread group.  The main thread will
112  * evaluate poll_fn(poll_data) until it gets a nonzero return value.
113  * It will sleep for wait_time secs between calls The ffsb_config
114  * struct is needed for fs selection.  Barriers are to synchronize
115  * multiple tgs and all threads pt is for pthread_create()
116  */
117 typedef struct tg_run_params {
118 	ffsb_tg_t *tg;
119 	int (*poll_fn)(void *);
120 	void *poll_data;
121 	unsigned wait_time; /* in sec */
122 	struct ffsb_config *fc;
123 	ffsb_barrier_t *tg_barrier;
124 
125 	/* Should be initialized by caller to tg_run() */
126 	ffsb_barrier_t *thread_barrier;
127 	pthread_t  pt;
128 } tg_run_params_t;
129 
130 /* This function is meant to be called as a parameter to
131  * pthread_create()
132  */
133 void *tg_run(void *);
134 
135 void tg_print_config(ffsb_tg_t *tg);
136 void tg_print_config_aging(ffsb_tg_t *tg, char *fsname);
137 
138 /* Adds all of this tg's results to res */
139 void tg_collect_results(ffsb_tg_t *tg, ffsb_op_results_t *res);
140 
141 /* Adds up all this tg's stats to totals */
142 void tg_collect_stats(ffsb_tg_t *tg, ffsb_statsd_t *totals);
143 
144 /* getters/setters, setters should not be called after a run has begun */
145 
146 void tg_set_statsc(ffsb_tg_t *tg, ffsb_statsc_t *fsc);
147 
148 void tg_set_bindfs(ffsb_tg_t *tg, int fsnum);
149 int  tg_get_bindfs(ffsb_tg_t *tg);
150 
151 unsigned tg_get_numthreads(ffsb_tg_t *tg);
152 
153 void tg_set_op_weight(ffsb_tg_t *tg, char *opname, unsigned weight);
154 unsigned tg_get_op_weight(ffsb_tg_t *tg, char *opname);
155 
156 void tg_set_read_random(ffsb_tg_t *tg, int rr);
157 void tg_set_write_random(ffsb_tg_t *tg, int wr);
158 void tg_set_fsync_file(ffsb_tg_t *tg, int fsync);
159 
160 int tg_get_read_random(ffsb_tg_t *tg);
161 int tg_get_write_random(ffsb_tg_t *tg);
162 int tg_get_fsync_file(ffsb_tg_t *tg);
163 
164 void tg_set_read_size(ffsb_tg_t *tg, uint64_t rs);
165 void tg_set_read_blocksize(ffsb_tg_t *tg, uint32_t rs);
166 
167 void tg_set_read_skipsize(ffsb_tg_t *tg, uint32_t rs);
168 void tg_set_read_skip(ffsb_tg_t *tg, int rs);
169 
170 void tg_set_write_size(ffsb_tg_t *tg, uint64_t ws);
171 void tg_set_write_blocksize(ffsb_tg_t *tg, uint32_t ws);
172 
173 uint64_t tg_get_read_size(ffsb_tg_t *tg);
174 uint32_t tg_get_read_blocksize(ffsb_tg_t *tg);
175 
176 int tg_get_read_skip(ffsb_tg_t *tg);
177 uint32_t tg_get_read_skipsize(ffsb_tg_t *tg);
178 
179 uint64_t tg_get_write_size(ffsb_tg_t *tg);
180 uint32_t tg_get_write_blocksize(ffsb_tg_t *tg);
181 
182 void tg_set_waittime(ffsb_tg_t *tg, unsigned time);
183 unsigned tg_get_waittime(ffsb_tg_t *tg);
184 
185 /* The threads in the tg should be the only ones using these (below)
186  * funcs.
187  */
188 ffsb_barrier_t *tg_get_start_barrier(ffsb_tg_t *tg);
189 int tg_get_stopval(ffsb_tg_t *tg);
190 int tg_get_flagval(ffsb_tg_t *tg);
191 
192 /* The threads in this tg will use this function to get an op to run,
193  * so all configuration specific information is kept in this object.
194  */
195 typedef struct tg_op_params {
196 	struct ffsb_fs *fs;     /* out parameter */
197 	unsigned opnum;         /* out parameter */
198 } tg_op_params_t;
199 
200 /* tg and rd and in parameters, everything in params is out */
201 void  tg_get_op(ffsb_tg_t *tg, randdata_t *rd, tg_op_params_t *params);
202 
203 /* want stats for this tg ? */
204 int tg_needs_stats(ffsb_tg_t *tg);
205 
206 #endif /* _FFSB_TG_H_ */
207