1 /**************************************************************************
2  *
3  *  ior_test.c - the IORATE routines to do the test
4  *
5  *  Copyright by EMC Corporation, 1997-2011.
6  *  All rights reserved.
7  *
8  *  Written by Vince Westin (vince.westin@emc.com), with a lot of
9  *  assistance from the EMC Engineering Team.
10  *
11  *  This code is the property of EMC Corporation.  However, it may be used,
12  *  reproduced, and passed on to others as long as the contents, including
13  *  all copyright notices, remain intact.  Modifications to, or modified
14  *  versions of these files, may also be distributed, provided that they
15  *  are clearly labeled as having been modified from the original.  In the
16  *  event that modified files are created, the original files are to be
17  *  included with every distribution of those modified files.  Inclusion of
18  *  this code into a commercial product by any company other than EMC is
19  *  prohibited without prior written consent.
20  *
21  *  Having said the legal stuff, this code is designed to provide a good,
22  *  generic tool for testing I/O subsystems under various kinds of loads.
23  *  If you have suggestions for improvements in this tool, please send them
24  *  along to the above address.
25  *
26  *************************************************************************/
27 
28 static char rcsid[] = "$Header: /home/westiv/iorate/RCS/ior_test.c,v 3.23 2011/11/03 15:44:20 westiv Exp westiv $";
29 
30 #include <stdio.h>
31 #include <string.h>
32 
33 #include "iorate.h"
34 
35 /*
36  * ior_run_dev_test - run a test pass on a selected drive
37  */
ior_run_dev_test(ior_config * cfg)38 int	ior_run_dev_test( ior_config *cfg )
39 /* ior_config	*cfg;			our configuration */
40 {
41     int		result;			/* final return code */
42     int		done;			/* is timing done? */
43     ior_test	*cur_test;		/* test we are running */
44     ior_device	*cur_dev;		/* current active device */
45     ior_skew_list *cur_skew;		/* currrent skew group list */
46     ior_skew_area *cur_area;		/* current skew area */
47     ior_clock	cur_time;		/* current time */
48     ior_clock	elapsed_time;		/* time gone by */
49     HUGE	o_size;			/* old size */
50     HUGE	n_size;			/* new size */
51     HUGE	over_size;		/* size we go over a set for this device */
52     HUGE	tgt_size;		/* size needed for test */
53     int		area_copies;		/* base copes of all areas */
54     double	d_size;			/* percent sizing of values */
55     long	shuffle_count;		/* how many areas to shuffle */
56     int		group;			/* skew group we are adding to */
57     int		skew_count;		/* skews in group for stats */
58     int		skew_start;		/* starting skew for stats */
59     int		n_skew;			/* current skew ID being added */
60     HUGE	n_iops;			/* iops for this group */
61     double	n_resp_time;		/* response time for this group */
62     char	msg[ 200 ];		/* message buffer */
63     int		i;
64 
65     ior_debug_l( cfg, IOR_DEBUG_MAJOR, "ior_run_dev_test: Entering code -->>" );
66 
67     result = strlen( rcsid );		/* STOP unused complaints from compiler */
68     result = 0;				/* all OK so far */
69     done = 0;				/* time not up yet */
70 
71     cur_dev = &( cfg->c_devs[ cfg->c_cur_dev ]);
72     cur_test = &( cfg->c_tests[ cfg->c_cur_test ]);
73 
74     sprintf( msg_buf, "Test starting on device %d.%d '%s'",
75 	    cfg->c_cur_dev + 1, cfg->c_cur_adev + 1, cur_dev->d_name );
76     ior_debug( cfg, msg_buf );
77 
78 					/* fix sizing of this test */
79 	/** NOTE: all locations are aligned when the random	**/
80 	/**       positions for the next I/O are chosen later.	**/
81     if ( cur_test->t_start_pct >= 0 ) {
82 	d_size = cur_test->t_start_pct / 100.0;
83 	d_size *= cur_dev->d_capacity;
84 	cur_test->t_start = d_size;
85 	sprintf( msg_buf,
86 		"  --> Sizing dev %d.%d test start at %.3lf%% of %0.2fm (%0.2fm)",
87 		cfg->c_cur_dev + 1, cfg->c_cur_adev + 1, cur_test->t_start_pct,
88 		cur_dev->d_capacity / 1048576.0,
89 		cur_test->t_start / 1048576.0 );
90 	ior_debug( cfg, msg_buf );
91     };
92     if ( cur_test->t_start < cur_dev->d_offset ) {
93 	cur_test->t_start = cur_dev->d_offset;
94     };
95 
96     if ( cur_test->t_size_pct >= 0 ) {
97 	d_size = cur_test->t_size_pct / 100.0 ;
98 	d_size *= cur_dev->d_capacity;
99 	cur_test->t_size = d_size;
100 	sprintf( msg_buf,
101 		"  --> Sizing dev %d.%d test size to %.3lf%% of %0.2fm (%0.2fm)",
102 		cfg->c_cur_dev + 1, cfg->c_cur_adev + 1, cur_test->t_size_pct,
103 		cur_dev->d_capacity / 1048576.0,
104 		cur_test->t_size / 1048576.0 );
105 	ior_debug( cfg, msg_buf );
106     };
107 
108     if ( cur_test->t_size <= 0 ) {	/* no size set yet */
109 	cur_test->t_end = cur_dev->d_capacity - ( IOR_MAX_IO_SIZE * 2 );
110 	cur_test->t_size = cur_test->t_end - cur_test->t_start;
111     };
112 
113     cur_test->t_end = cur_test->t_start + cur_test->t_size;
114 
115 	    				/* wrapped, so limit the size (quiet) */
116     if ( cur_test->t_end < 0 ) {
117 	cur_test->t_end = IOR_MAX_SEEK - IOR_MAX_IO_SIZE;
118 	cur_test->t_size = cur_test->t_end - cur_test->t_start;
119 	sprintf( msg_buf,
120 		"  --> Dev %d.%d test size over limit (wrapped) - fixed",
121 		cfg->c_cur_dev + 1, cfg->c_cur_adev + 1 );
122 	ior_debug( cfg, msg_buf );
123     };
124     if ( cur_test->t_end > cur_dev->d_capacity ) {
125 	o_size = cur_test->t_end - cur_test->t_start;
126 
127 	cur_test->t_end = cur_dev->d_capacity;
128 
129 	n_size = cur_test->t_end - cur_test->t_start;
130 
131 	sprintf( msg_buf,
132 		"Test size in test %d '%s' is too large for device %d.%d:\n\t-- Reduced to %0.2fm (from %0.2fm)",
133 		cfg->c_cur_test + 1, cur_test->t_name,
134 		cfg->c_cur_dev + 1, cfg->c_cur_adev + 1,
135 		n_size / 1048576.0, o_size / 1048576.0 );
136 
137 					/* note change if > .1% */
138 	if (( o_size - n_size ) > ( o_size / 1000 )) {
139 	    ior_warn( cfg, msg_buf );
140 	} else {
141 	    ior_debug( cfg, msg_buf );
142 	};
143 
144 	cur_test->t_size = n_size;
145     };
146     if ( cur_test->t_end > ( IOR_MAX_SEEK - IOR_MAX_IO_SIZE )) {
147 	o_size = cur_test->t_end - cur_test->t_start;
148 
149 	cur_test->t_end = IOR_MAX_SEEK - IOR_MAX_IO_SIZE;
150 
151 	n_size = cur_test->t_end - cur_test->t_start;
152 
153 	sprintf( msg_buf,
154 		"Test size in test %d '%s' is too long for seek, reduced to %0.2fm",
155 		cfg->c_cur_test + 1, cur_test->t_name, n_size / 1048576.0 );
156 
157 					/* note change if > .1% */
158 	if (( o_size - n_size ) > ( o_size / 1000 )) {
159 	    ior_warn( cfg, msg_buf );
160 	} else {
161 	    ior_debug( cfg, msg_buf );
162 	};
163 
164 	cur_test->t_size = n_size;
165     };
166 
167 		/* checks for test if skew is on */
168     if ( cur_test->t_skew > 0 ) {
169 
170 		/* if skewed, check the size */
171 	if ( cur_test->t_size <
172 		    cur_test->t_area * IOR_AREA_MIN_PER_DRIVE ) {
173 	    strcpy( msg, ior_size_to_ascii( cfg, cur_test->t_area ));
174 	    sprintf( msg_buf, "device '%s' %d.%d: size (%s) less than %d * skew area (%s)",
175 		cur_dev->d_name,
176 		cfg->c_cur_dev + 1, cfg->c_cur_adev + 1,
177 		ior_size_to_ascii( cfg, cur_test->t_size ),
178 		(int)( IOR_AREA_MIN_PER_DRIVE ),
179 		msg );
180 	    ior_error( cfg, msg_buf );
181 
182 	    return( -10 );
183 	};
184 
185 		    /* note the overall sizes we are targeting */
186 					/* how large without wrapping */
187 	cfg->c_skew_set_size = cfg->c_num_areas * cur_test->t_area;
188 					/* number of additional copies we MAY need */
189 	area_copies = cur_test->t_size / cfg->c_skew_set_size;
190 					/* size we target ABOVE the copies */
191 	tgt_size = cur_test->t_size - area_copies * cfg->c_skew_set_size;
192 
193 	if ( cfg->c_cur_adev < 1 ) {	/* only note for one copy of a device */
194 	    sprintf( msg_buf, "ior_test: device %d: unique mapped space %ldk, copies %d, overflow size %ldk",
195 		cfg->c_cur_dev + 1,
196 		(long)( cfg->c_skew_set_size / 1024L ),
197 		(int)( area_copies ),
198 		(long)( tgt_size / 1024L ));
199 	    ior_debug_l( cfg, IOR_DEBUG_MINOR, msg_buf );
200 	};
201 
202 					/* no over capacity yet */
203 	over_size = 0;
204 			/* number of copies for this test */
205 	for ( i = 0; i < cfg->c_num_areas; i++  ) { /* walk the areas */
206 	    cur_area = &( cfg->c_areas[ i ]);
207 
208 			/* at least base copies, 1 more if in range */
209 	    cur_area->a_copies = area_copies;
210 	    if ( over_size <= tgt_size ) {
211 		cur_area->a_copies++;
212 
213 			/* note area added here */
214 		over_size += cur_test->t_area;
215 	    };
216 	};
217 
218 
219 	/* now randomize the areas in each group for more realistic simulation */
220 	/*    this is done here so the pattern is unique per device copy */
221 	/* --- note that a new random seed per test/device is set in iorate.c --- */
222 	for ( group = 0; group < IOR_SKEW_LISTS; group++ ) {
223 	    cur_skew = &( cfg->c_skewed[ group ]);
224 	    cur_area = cur_skew->s_areas;
225 
226 					/* shuffle 100-300% - mix it up */
227 	    shuffle_count = ( cur_skew->s_area_current *
228 			( 100 + ior_rand( cfg ) % 200 )) / 100;
229 
230 	    for ( ; shuffle_count > 0; shuffle_count-- ) {
231 					/* pick a random area */
232 		for ( i = ior_rand( cfg ) %
233 			    ( cur_skew->s_area_current - 2 );
234 			i > 0; i-- ) {
235 		    cur_area = cur_area->a_next;
236 		};
237 
238 		sprintf( msg_buf, "randomizing: area %ld to tail of group %d - %ld more to go, %ld in group",
239 		    cur_area->a_id, group,
240 		    (long)( shuffle_count - 1 ),
241 		    cur_skew->s_area_current );
242 		ior_debug_l( cfg, IOR_DEBUG_SMALL, msg_buf );
243 
244 					/* move it to the end */
245 		ior_area( cfg, IOR_AREA_TAIL, cur_area, cur_skew );
246 
247 		cur_area = cur_skew->s_areas;
248 	    };
249 	};
250 
251     };
252 
253     sprintf( msg_buf,
254 	    "    --> Ready to test dev %d.%d:\n\tStart %.2fm - Size %.2fm - End %.2fm",
255 	    cfg->c_cur_dev + 1, cfg->c_cur_adev + 1,
256 	    cur_test->t_start / 1048576.0,
257 	    cur_test->t_size / 1048576.0,
258 	    cur_test->t_end / 1048576.0 );
259     ior_debug( cfg, msg_buf );
260 
261     if ( cur_test->t_skew < IOR_SKEW_MIN ) {
262 	result = ior_test_prep_std( cfg );	/* prep for all our patterns to run */
263     } else {
264 	result = ior_test_prep_skew( cfg );
265     };
266 
267 					/* open the target device */
268     if ( result == 0 ) {
269 	result = ior_open_dev( cfg, cfg->c_cur_dev );
270     };
271 
272 
273     if ( cur_test->t_ignore < 1 ) {	/* no delay - start stats now */
274 	cur_test->t_running = 1;
275     };
276 
277     if ( cfg->c_target_resp > 0 ) {	/* using target I/O rate */
278 
279 	/* since we will be waiting, sleep for a random desired time */
280 	/* to avoid process contention on devices on startup */
281 
282 	ior_debug( cfg, "Using target iorate, so starting with random delay" );
283 
284 	ior_sleep_usec( cfg, ior_rand( cfg ) % cfg->c_target_resp );
285     };
286 
287     cur_time = ior_get_time( cfg );	/* start with time */
288 
289     while ( !done && !result ) {
290 
291 	if ( cur_test->t_skew > 0 ) {
292 	    result = ior_run_skew( cfg,
293 		    cur_test->t_patterns[ ior_rand( cfg ) % 100 ]);
294 	} else {
295 	    result = ior_run_pat( cfg,
296 		    cur_test->t_patterns[ ior_rand( cfg ) % 100 ]);
297 	};
298 
299 	cur_time = ior_get_time( cfg );	/* check for time done */
300 	elapsed_time = cur_time - cfg->c_start_time;
301 	cfg->c_io_time = elapsed_time;	/* current I/O time */
302 
303 	if ( !cur_test->t_running ) {
304 	    if ( elapsed_time >= cur_test->t_ignore ) {
305 		cur_test->t_running = 1;
306 		cfg->c_reads = 0;
307 		cfg->c_blocks_read = 0;
308 		cfg->c_writes = 0;
309 		cfg->c_blocks_written = 0;
310 		cfg->c_read_time_msecs = 0;
311 		cfg->c_write_time_msecs = 0;
312 
313 					/* and for each skew group */
314 		if ( cur_test->t_skew > 0 ) {
315 		    for ( i = 0; i < IOR_SKEW_LISTS; i++ ) {
316 			cur_skew = &( cfg->c_skewed[ i ]);
317 
318 			cur_skew->s_perf.sp_rand_reads = 0;
319 			cur_skew->s_perf.sp_rand_read_resp = 0;
320 			cur_skew->s_perf.sp_seq_reads = 0;
321 			cur_skew->s_perf.sp_seq_read_resp = 0;
322 			cur_skew->s_perf.sp_rand_writes = 0;
323 			cur_skew->s_perf.sp_rand_write_resp = 0;
324 			cur_skew->s_perf.sp_seq_writes = 0;
325 			cur_skew->s_perf.sp_seq_write_resp = 0;
326 		    };
327 		};
328 
329 #ifdef	IOR_ENGINEERIG
330 		ior_eng_reset_stats( cfg );
331 #endif
332 
333 	    };
334 	} else {
335 	    cfg->c_io_time -= cur_test->t_ignore; /* no record of ignored I/Os */
336 	};
337 
338 	if ( elapsed_time >= cur_test->t_duration ) {
339 	    done = 1;
340 	};
341     };
342 					/* close the target device */
343     if ( cfg->c_devs[ cfg->c_cur_dev ].d_is_active ) {
344 	i = ior_close_dev( cfg, cfg->c_cur_dev );
345     } else {
346 	i = 0;
347     };
348 
349     if ( result == 0 ) {
350 	result = i;			/* set result to close status */
351 
352 	cur_dev = &( cfg->c_devs[ cfg->c_cur_dev ]);
353 
354 	fprintf( cfg->c_perf_file, "%d\t%s\t%d\t%s\t%ld\t%ld",
355 		cfg->c_cur_test + 1,
356 		cfg->c_tests[ cfg->c_cur_test ].t_name,
357 		cfg->c_cur_dev + 1,
358 		cur_dev->d_name,
359 		cur_time - cfg->c_start_time,
360 		cfg->c_io_time );
361 
362 	fprintf( cfg->c_perf_file, "\t%ld\t%ld\t%.3lf",
363 		(long)( cfg->c_reads ),
364 		(long)( cfg->c_blocks_read ),
365 		cfg->c_reads == 0 ? (double) 0.0 : /* no div by zero */
366 		    cfg->c_read_time_msecs / cfg->c_reads );
367 
368 	fprintf( cfg->c_perf_file, "\t%ld\t%ld\t%.3lf",
369 		(long)( cfg->c_writes ), (long)( cfg->c_blocks_written ),
370 		cfg->c_writes == 0 ? (double) 0.0 : /* no div by zero */
371 		    cfg->c_write_time_msecs / cfg->c_writes );
372 
373 	fprintf( cfg->c_perf_file, "\t%ld\t%ld\t%.3lf",
374 		(long)( cfg->c_reads + cfg->c_writes ),
375 		(long)( cfg->c_blocks_read + cfg->c_blocks_written ),
376 		( cfg->c_reads + cfg->c_writes ) == 0 ? (double) 0.0 :
377 		    ( cfg->c_read_time_msecs + cfg->c_write_time_msecs ) /
378 			( cfg->c_reads + cfg->c_writes ));
379 
380 	fprintf( cfg->c_perf_file, "\t%ld\t%ld\t%ld",
381 		(long)(( cfg->c_reads + cfg->c_writes ) / cfg->c_io_time ),
382 		(long)(( cfg->c_blocks_read + cfg->c_blocks_written ) /
383 		    cfg->c_io_time ),
384 		(long)( cfg->c_cur_adev + 1 ));
385 
386 		/* add skew area performance data as well */
387 	if ( cur_test->t_skew > 0 ) {
388 
389 		/* for DEBUG, we give data for each skew group */
390 	    if ( cfg->c_debug_level >= IOR_DEBUG_MAJOR ) {
391 		for ( i = 0; i < IOR_SKEW_LISTS; i++ ) {
392 		    cur_skew = &( cfg->c_skewed[ i ]);
393 
394 		    fprintf( cfg->c_perf_file, "\t%ld\t%.2f\t%ld\t%.2f\t%ld\t%.2f\t%ld\t%.2f",
395 			    (long)( cur_skew->s_perf.sp_rand_reads  ),
396 			    (float)( cur_skew->s_perf.sp_rand_reads == 0 ? 0 :
397 				    cur_skew->s_perf.sp_rand_read_resp /
398 					cur_skew->s_perf.sp_rand_reads ),
399 			    (long)( cur_skew->s_perf.sp_seq_reads ),
400 			    (float)( cur_skew->s_perf.sp_seq_reads == 0 ? 0 :
401 				    cur_skew->s_perf.sp_seq_read_resp /
402 				    cur_skew->s_perf.sp_seq_reads ),
403 			    (long)( cur_skew->s_perf.sp_rand_writes ),
404 			    (float)( cur_skew->s_perf.sp_rand_writes == 0 ? 0 :
405 				    cur_skew->s_perf.sp_rand_write_resp /
406 				    cur_skew->s_perf.sp_rand_writes ),
407 			    (long)( cur_skew->s_perf.sp_seq_writes ),
408 			    (float)( cur_skew->s_perf.sp_seq_writes == 0 ? 0 :
409 				    cur_skew->s_perf.sp_seq_write_resp /
410 				    cur_skew->s_perf.sp_seq_writes ));
411 		};
412 		/* otherwise, we give data for the target regions */
413 	    } else {
414 
415 		skew_start = 0;	/* none totaled yet */
416 		for ( i = 0; i < 3; i++ ) {
417 		    skew_count = cfg->c_skew_group_count[ i ];
418 
419 		    n_iops = 0;
420 		    n_resp_time = 0;
421 		    for ( n_skew = skew_start + skew_count - 1;
422 			    n_skew >= skew_start; n_skew-- ) {
423 			cur_skew = &( cfg->c_skewed[ n_skew ]);
424 			n_iops += cur_skew->s_perf.sp_rand_reads;
425 			n_resp_time += cur_skew->s_perf.sp_rand_read_resp;
426 		    };
427 		    fprintf( cfg->c_perf_file, "\t%ld\t%.2f",
428 			    (long)( n_iops ),
429 			    (float)( n_iops == 0 ? 0 :
430 				( n_resp_time / n_iops )));
431 
432 		    n_iops = 0;
433 		    n_resp_time = 0;
434 		    for ( n_skew = skew_start + skew_count - 1;
435 			    n_skew >= skew_start; n_skew-- ) {
436 			cur_skew = &( cfg->c_skewed[ n_skew ]);
437 			n_iops += cur_skew->s_perf.sp_seq_reads;
438 			n_resp_time += cur_skew->s_perf.sp_seq_read_resp;
439 		    };
440 		    fprintf( cfg->c_perf_file, "\t%ld\t%.2f",
441 			    (long)( n_iops ),
442 			    (float)( n_iops == 0 ? 0 :
443 				( n_resp_time / n_iops )));
444 
445 		    n_iops = 0;
446 		    n_resp_time = 0;
447 		    for ( n_skew = skew_start + skew_count - 1;
448 			    n_skew >= skew_start; n_skew-- ) {
449 			cur_skew = &( cfg->c_skewed[ n_skew ]);
450 			n_iops += cur_skew->s_perf.sp_rand_writes;
451 			n_resp_time += cur_skew->s_perf.sp_rand_write_resp;
452 		    };
453 		    fprintf( cfg->c_perf_file, "\t%ld\t%.2f",
454 			    (long)( n_iops ),
455 			    (float)( n_iops == 0 ? 0 :
456 				( n_resp_time / n_iops )));
457 
458 		    n_iops = 0;
459 		    n_resp_time = 0;
460 		    for ( n_skew = skew_start + skew_count - 1;
461 			    n_skew >= skew_start; n_skew-- ) {
462 			cur_skew = &( cfg->c_skewed[ n_skew ]);
463 			n_iops += cur_skew->s_perf.sp_seq_writes;
464 			n_resp_time += cur_skew->s_perf.sp_seq_write_resp;
465 		    };
466 		    fprintf( cfg->c_perf_file, "\t%ld\t%.2f",
467 			    (long)( n_iops ),
468 			    (float)( n_iops == 0 ? 0 :
469 				( n_resp_time / n_iops )));
470 
471 		    skew_start += skew_count;
472 		};
473 	    };
474 	};
475 
476 #ifdef	IOR_ENGINEERING
477 	ior_eng_test_done( cfg );
478 #endif
479 
480 	fprintf( cfg->c_perf_file, "\n" );
481 	fflush( cfg->c_perf_file );
482     } else {
483 	fprintf( cfg->c_perf_file,
484 		"TEST%03d,%s,FAILED,device %d copy %d\n",
485 		cfg->c_cur_test + 1, cfg->c_devs[ cfg->c_cur_dev ].d_name,
486 		cfg->c_cur_dev + 1, cfg->c_cur_adev + 1 );
487 	fflush( cfg->c_perf_file );
488 
489 	ior_error( cfg, "BAILING out of test due to errors" );
490     };
491 
492     ior_debug_l( cfg, IOR_DEBUG_MAJOR, "ior_run_dev_test: <<-- Leaving code" );
493 
494     return( result );
495 }
496 
497 /*
498  * ior_test_prep_std - prepare for a non-skew test run
499  */
ior_test_prep_std(ior_config * cfg)500 int	ior_test_prep_std( ior_config *cfg )
501 /* ior_config	*cfg;			our configuration */
502 {
503     int		result;			/* final return code */
504     int		cur;			/* current item in loop */
505     ior_test	*cur_test;		/* test we are running */
506     ior_pattern	*cur_pat;		/* current active pattern */
507     ior_device	*cur_dev;		/* current active pattern */
508     HUGE	saved_start;		/* saved pattern start */
509     HUGE	saved_end;		/* saved pattern end */
510     HUGE	o_size;			/* old size */
511     HUGE	n_size;			/* new size */
512     HUGE	h_tmp;			/* huge temp value */
513     double	d_size;			/* percent sizing of values */
514     char	msg[ 200 ];		/* message buffer */
515     int		i;
516 
517     ior_debug_l( cfg, IOR_DEBUG_MINOR, "ior_test_prep_std: Entering code -->>" );
518 
519     result = 0;				/* all OK so far */
520 
521     cur_dev = &( cfg->c_devs[ cfg->c_cur_dev ]);
522     cur_test = &( cfg->c_tests[ cfg->c_cur_test ]);
523 
524 					/* start each pattern */
525     for ( cur = 0; cur < cfg->c_npat; cur++ ) {
526 
527 	cur_pat = &( cfg->c_pats[ cur ]);
528 
529 					/* only check on active patterns */
530 	if (( !cur_pat->p_valid ) || ( cur_test->t_pat_pct[ cur ] < 1 )) {
531 	    continue;
532 	};
533 
534 			/* fix sizing for this pattern */
535 	if ( cur_pat->p_start_pct == 0 ) {
536 	    cur_pat->p_start = 0;
537 	};
538 	if ( cur_pat->p_start_pct > 0 ) {
539 	    d_size = cur_pat->p_start_pct / 100.0 ;
540 	    d_size *= cur_test->t_size;
541 	    cur_pat->p_start = d_size;
542 	    sprintf( msg_buf,
543 		    "    --> Sizing dev %d.%d pat %d start to %.3lf%% of %0.2fm (%0.2fm)",
544 		    cfg->c_cur_dev + 1, cfg->c_cur_adev + 1,
545 		    cur + 1, cur_pat->p_start_pct,
546 		    cur_test->t_size / 1048576.0,
547 		    cur_pat->p_start / 1048576.0 );
548 	    ior_debug( cfg, msg_buf );
549 	};
550 	if ( cur_test->t_start > 0 ) {	/* include any offset from test */
551 	    cur_pat->p_start += cur_test->t_start;
552 	    sprintf( msg_buf,
553 		    "  --> Adding test start of %ldk to dev %d.%d pat %d start",
554 		    (long)( cur_test->t_start / 1024L ),
555 		    cfg->c_cur_dev + 1, cfg->c_cur_adev + 1, cur + 1 );
556 	    ior_debug( cfg, msg_buf );
557 	};
558 	if ( cur_pat->p_size_pct >= 0 ) {
559 	    d_size = cur_pat->p_size_pct / 100.0 ;
560 	    d_size *= cur_test->t_size;
561 	    cur_pat->p_size = d_size;
562 	    sprintf( msg_buf,
563 		    "    --> Sizing dev %d.%d pat %d size to %.3lf%% of %0.2fm (%0.2fm)",
564 		    cfg->c_cur_dev + 1, cfg->c_cur_adev + 1,
565 		    cur + 1, cur_pat->p_size_pct,
566 		    cur_test->t_size / 1048576.0,
567 		    cur_pat->p_size / 1048576.0 );
568 	    ior_debug( cfg, msg_buf );
569 	};
570 	cur_pat->p_end = cur_pat->p_start + cur_pat->p_size;
571 
572 					/* check for too large */
573 	if ( cur_pat->p_end > cur_test->t_end ) {
574 	    o_size = cur_pat->p_end - cur_pat->p_start;
575 
576 	    cur_pat->p_end = cur_test->t_end;
577 
578 	    n_size = cur_pat->p_end - cur_pat->p_start;
579 
580 	    sprintf( msg_buf,
581 		    "    -->> Pattern '%s' (%d) size too large for test:\n\t-- Reduced to %0.2fm",
582 		    cur_pat->p_name, cur + 1, n_size / 1048576.0 );
583 
584 					/* note change if > .1% */
585 	    if (( o_size - n_size ) > ( o_size / 1000 )) {
586 		ior_warn( cfg, msg_buf );
587 	    } else {
588 		ior_debug( cfg, msg_buf );
589 	    };
590 
591 	    cur_pat->p_size = n_size;
592 	};
593 					/* prep localities */
594 	if ( cur_pat->p_local_pct > 0 ) {
595 	    cur_pat->p_local_size = (HUGE)(cur_pat->p_size *
596 		    cur_pat->p_local_pct / 100);
597 	    sprintf( msg_buf, "Setting locality size to %.0f%% (%ldk)",
598 		    cur_pat->p_local_pct,
599 		    (long)( cur_pat->p_local_size / 1024L ));
600 	    ior_debug( cfg, msg_buf );
601 	};
602 	if ( cur_pat->p_local_size > 0 ) {
603 
604 	    if ( cur_pat->p_local_size < cur_pat->p_io_size * 5 ) {
605 		sprintf( msg_buf,
606 			"Locality size too small (%ldk) in pattern %d - increased to %ldk",
607 			(long)( cur_pat->p_local_size / 1024L ), cur + 1,
608 			(long)(( cur_pat->p_io_size * 5 ) / 1024L ));
609 		ior_warn( cfg, msg_buf );
610 		cur_pat->p_local_size = cur_pat->p_io_size * 5;
611 	    };
612 
613 	    cur_pat->p_local_avail = cur_pat->p_size /
614 			( cur_pat->p_local_size * 2 );
615 
616 	    if ( cur_pat->p_local_avail < 1 ) {
617 		sprintf( msg_buf,
618 			"Not enough space for even 1 locality buffer in pattern %d",
619 			cur + 1 );
620 		ior_error( cfg, msg_buf );
621 		cur_pat->p_local_avail = 1; /* get through the code here */
622 		result = -4;
623 	    };
624 
625 	    if ( cur_pat->p_local_avail < cur_pat->p_local_count ) {
626 		sprintf( msg_buf,
627 #ifdef	IOR_LARGE_FILES
628 			"Available localities (%llu) less than requested (%llu)",
629 			(long long unsigned)( cur_pat->p_local_avail ),
630 			(long long unsigned)( cur_pat->p_local_count ));
631 #else
632 			"Available localities (%lu) less than requested (%lu)",
633 			(long unsigned)( cur_pat->p_local_avail ),
634 			(long unsigned)( cur_pat->p_local_count ));
635 #endif
636 		ior_error( cfg, msg_buf );
637 		result = -3;
638 	    };
639 
640 	    sprintf( msg_buf,
641 		    " -->> Locality buffers: count %ld size %ldk avail %ld",
642 		    (long)( cur_pat->p_local_count ),
643 		    (long)( cur_pat->p_local_size / 1024L ),
644 		    (long)( cur_pat->p_local_avail ));
645 	    ior_debug( cfg, msg_buf );
646 
647 
648 	    saved_start = cur_pat->p_start;
649 	    saved_end = cur_pat->p_end;
650 
651 	    for ( i = 0; i < cur_pat->p_local_count; i++) {
652 
653 		sprintf( msg_buf, "Preparing locality %d", i + 1 );
654 		ior_verbose( cfg, msg_buf );
655 
656 		cur_pat->p_local_uses[ i ] = 0;
657 		cur_pat->p_local_seqs[ i ] = 0;
658 
659 		h_tmp = ior_rand( cfg ) % cur_pat->p_local_avail;
660 		h_tmp *= 2 * cur_pat->p_local_size;
661 		cur_pat->p_local_starts[ i ] = saved_start + h_tmp;
662 		cur_pat->p_local_ends[ i ] =
663 			cur_pat->p_local_starts[ i ] + cur_pat->p_local_size;
664 
665 		cur_pat->p_start = cur_pat->p_local_starts[ i ];
666 		cur_pat->p_end = cur_pat->p_local_ends[ i ];
667 		cur_pat->p_size = cur_pat->p_end - cur_pat->p_start;
668 
669 					/* and a random starting location */
670 		ior_set_rand_pos( cfg, cur );
671 		cur_pat->p_local_pos[ i ] = cur_pat->p_pos;
672 
673 		sprintf( msg_buf,
674 			" -->> Pattern %d locality %d -- from %ldk to %ldk pos %ldk",
675 			cur + 1, i + 1,
676 			(long)( cur_pat->p_local_starts[ i ] / 1024L ),
677 			(long)( cur_pat->p_local_ends[ i ] / 1024L ),
678 			(long)( cur_pat->p_local_pos[ i ] / 1024L ));
679 		ior_debug( cfg, msg_buf );
680 	    };
681 
682 	    cur_pat->p_start = saved_start;
683 	    cur_pat->p_end = saved_end;
684 	    cur_pat->p_size = cur_pat->p_end - cur_pat->p_start;
685 	};
686 
687 	cur_pat->p_hist_active = 0;	/* no active history records */
688 	cur_pat->p_hist_next = 0;	/* start with item 0 */
689 
690 					/* help wih code debug */
691 	sprintf( msg, "Pattern %d dev %d.%d: Test from %0.2fm to %0.2fm (size %0.2fm)",
692 		cur + 1, cfg->c_cur_dev + 1, cfg->c_cur_adev + 1,
693 		cur_pat->p_start / 1048576.0,
694 		cur_pat->p_end / 1048576.0,
695 		cur_pat->p_size / 1048576.0 );
696 	ior_debug( cfg, msg );
697 					/* check for bad pattern sizing */
698 	if ( cur_pat->p_size <= ( cur_pat->p_io_size * 2 )) {
699 	    sprintf( msg, "Device %d.%d: Pattern %d: Too small a size (%ldk)",
700 		cfg->c_cur_dev + 1, cfg->c_cur_adev + 1, cur + 1,
701 		(long) ( cur_pat->p_size / 1024L ));
702 	    ior_error( cfg, msg );
703 	    result = -5;		/* note we took an error */
704 	};
705 					/* with no sequential history */
706 	cur_pat->p_cur_seq = 0;
707 					/* and a random starting location */
708 	ior_set_rand_pos( cfg, cur );
709     };
710 
711     ior_debug_l( cfg, IOR_DEBUG_MINOR, "ior_test_prep_std: <<-- Leaving code" );
712 
713     return( result );
714 }
715 
716 /*
717  * ior_run_pat - run the pattern on the given device
718  */
ior_run_pat(ior_config * cfg,long pat)719 int	ior_run_pat( ior_config *cfg, long pat )
720 /* ior_config	*cfg;			our configuration */
721 /* long		pat;			pattern to use */
722 {
723     int		result;			/* final return code */
724     ior_pattern	*cur_pat;		/* current active pattern */
725     ior_pattern	saved_pat;		/* save area for local stuff */
726     long	hist;			/* which history record to use */
727     long	local;			/* local we are using */
728     HUGE	h_tmp;			/* huge temp value */
729 
730     ior_debug_l( cfg, IOR_DEBUG_SMALL, "ior_run_pat: Entering code -->>" );
731 
732     result = 0;				/* all OK so far */
733 
734     cfg->c_cur_pat = pat;		/* note which pattern we are using */
735 
736     cur_pat = &( cfg->c_pats[ pat ]);
737 					/* use history if appropriate */
738 					/* ONLY if history is FULL */
739     if ( cur_pat->p_history
740 	    && ( cur_pat->p_hist_active >= cur_pat->p_history )
741 	    && cur_pat->p_hist_use[ ior_rand( cfg ) % 100 ]) {
742 
743 	hist = ior_rand( cfg ) % cur_pat->p_hist_active;
744 
745 	sprintf( msg_buf, "-> Using history I/O %ld at %ldk",
746 		hist + 1, (long) ( cur_pat->p_hist_records[ hist ]/ 1024L ));
747 	ior_verbose( cfg, msg_buf );
748 
749 	result = ior_io( cfg, cur_pat->p_read_use[ ior_rand( cfg ) % 100 ],
750 		cur_pat->p_io_size, cur_pat->p_hist_records[ hist ], NULL );
751 
752     } else if ( cur_pat->p_local_size > 0 ) { /* do locality stuff */
753 
754 					/* choose which local to use */
755 	local = ior_rand( cfg ) % cur_pat->p_local_count;
756 	cur_pat->p_cur_local = local;
757 
758 	sprintf( msg_buf, "Using I/O locality %ld (%ldk -> %ldk) [%d.%d]",
759 		local + 1,
760 		(long) ( cur_pat->p_local_starts[ local ] / 1024L ),
761 		(long) ( cur_pat->p_local_ends[ local ] / 1024L ),
762 		cfg->c_cur_dev + 1, cfg->c_cur_adev + 1 );
763 	ior_verbose( cfg, msg_buf );
764 
765 	saved_pat.p_pos = cur_pat->p_pos; /* save current pattern info */
766 	saved_pat.p_cur_seq = cur_pat->p_cur_seq;
767 	saved_pat.p_start = cur_pat->p_start;
768 	saved_pat.p_end = cur_pat->p_end;
769 	cur_pat->p_pos = cur_pat->p_local_pos[ local ];
770 	cur_pat->p_cur_seq = cur_pat->p_local_seqs[ local ];
771 	cur_pat->p_start = cur_pat->p_local_starts[ local ];
772 	cur_pat->p_end = cur_pat->p_local_ends[ local ];
773 	cur_pat->p_size = cur_pat->p_end - cur_pat->p_start;
774 
775 	result = ior_run_sel_pat( cfg, pat );
776 
777 	cur_pat->p_local_uses[ local ]++;
778 
779 	if (( cur_pat->p_local_limit > 0 )
780 		&& ( cur_pat->p_local_uses[ local ]
781 			>= cur_pat->p_local_limit )) {
782 
783 	    cur_pat->p_local_uses[ local ] = 0;
784 	    cur_pat->p_local_seqs[ local ] = 0;
785 
786 
787 
788 	    h_tmp = ior_rand( cfg ) % cur_pat->p_local_avail;
789 	    h_tmp *= 2 * cur_pat->p_local_size;
790 	    cur_pat->p_local_starts[ local ] = saved_pat.p_start + h_tmp;
791 	    cur_pat->p_local_ends[ local ] =
792 		    cur_pat->p_local_starts[ local ]
793 		    + cur_pat->p_local_size;
794 
795 	    cur_pat->p_start = cur_pat->p_local_starts[ local ];
796 	    cur_pat->p_end = cur_pat->p_local_ends[ local ];
797 	    cur_pat->p_size = cur_pat->p_end - cur_pat->p_start;
798 				    /* and a random starting location */
799 	    ior_set_rand_pos( cfg, pat );
800 	    cur_pat->p_local_pos[ local ] = cur_pat->p_pos;
801 
802 	    sprintf( msg_buf,
803 		    " -->> Pattern %ld locality %ld NOW from %ldk to %ldk pos %ldk [%d.%d]",
804 		    pat + 1, local + 1,
805 		    (long)( cur_pat->p_local_starts[ local ] / 1024L ),
806 		    (long)( cur_pat->p_local_ends[ local ] / 1024L ),
807 		    (long)( cur_pat->p_local_pos[ local ] / 1024L ),
808 		    cfg->c_cur_dev + 1, cfg->c_cur_adev + 1 );
809 	    ior_debug( cfg, msg_buf );
810 	} else {
811 	    cur_pat->p_local_pos[ local ] = cur_pat->p_pos;
812 	    cur_pat->p_local_seqs[ local ] = cur_pat->p_cur_seq;
813 	};
814 
815 					/* restore saved pattern info */
816 	cur_pat->p_pos = saved_pat.p_pos;
817 	cur_pat->p_cur_seq = saved_pat.p_cur_seq;
818 	cur_pat->p_start = saved_pat.p_start;
819 	cur_pat->p_end = saved_pat.p_end;
820 	cur_pat->p_size = cur_pat->p_end - cur_pat->p_start;
821 
822     } else {
823 	result = ior_run_sel_pat( cfg, pat );
824     };
825 
826     ior_debug_l( cfg, IOR_DEBUG_SMALL, "ior_run_pat: <<-- Leaving code" );
827 
828     return( result );
829 }
830 
831 /*
832  * ior_run_sel_pat - run the selected pattern on the given device
833  */
ior_run_sel_pat(ior_config * cfg,long pat)834 int	ior_run_sel_pat( ior_config *cfg, long pat )
835 /* ior_config	*cfg;			our configuration */
836 /* long		pat;			pattern to use */
837 {
838     int		result;			/* final return code */
839     ior_pattern	*cur_pat;		/* current active pattern */
840 
841     result = 0;				/* all OK so far */
842 
843     cur_pat = &( cfg->c_pats[ pat ]);
844 
845     cfg->c_cur_pat = pat;		/* note which pattern we are using */
846 
847     result = ior_io( cfg, cur_pat->p_read_use[ ior_rand( cfg ) % 100 ],
848 	    cur_pat->p_io_size, cur_pat->p_pos, NULL );
849 
850     cur_pat->p_pos = cfg->c_pos;	/* note new position for pattern */
851 
852     if ( cur_pat->p_history > 0 ) {	/* record new history item */
853 
854 	sprintf( msg_buf, "-->> Recording pattern %ld I/O as history element %ld [%d.%d]",
855 		pat + 1, cur_pat->p_hist_next + 1,
856 		cfg->c_cur_dev + 1, cfg->c_cur_adev + 1 );
857 	ior_verbose( cfg, msg_buf );
858 					/* note position I/O STARTED at */
859 	cur_pat->p_hist_records[ cur_pat->p_hist_next++ ] =
860 		cur_pat->p_pos - cur_pat->p_io_size;
861 	if ( cur_pat->p_hist_active < cur_pat->p_hist_next ) {
862 	    cur_pat->p_hist_active = cur_pat->p_hist_next;
863 	};
864 	if ( cur_pat->p_hist_next >= cur_pat->p_history ) {
865 	    cur_pat->p_hist_next = 0;
866 	};
867     };
868 					/* if not random or seq. too long */
869     if ( !( cur_pat->p_is_seq ) ||
870 	    (( cur_pat->p_max_seq > 0 ) &&
871 		( ++( cur_pat->p_cur_seq ) >= cur_pat->p_max_seq ))) {
872 	ior_set_rand_pos( cfg, pat );
873 	cur_pat->p_cur_seq = 0;
874 	sprintf( msg_buf, "I/O pattern %ld new random location chosen (%ldk) [%d.%d]",
875 		pat + 1, (long) ( cur_pat->p_pos / 1024L ),
876 		cfg->c_cur_dev + 1, cfg->c_cur_adev + 1 );
877 	ior_verbose( cfg, msg_buf );
878     } else {
879 	if ( cur_pat->p_pos + cur_pat->p_io_size >= cur_pat->p_end ) {
880 	    sprintf( msg_buf, "I/O pattern %ld wrapped to %ldk (%ldk >= %ldk) [%d.%d]",
881 		    pat + 1, (long) ( cur_pat->p_start / 1024L ),
882 		    (long) (( cur_pat->p_pos + cur_pat->p_io_size ) / 1024L ),
883 		    (long) ( cur_pat->p_end / 1024L ),
884 		    cfg->c_cur_dev + 1, cfg->c_cur_adev + 1 );
885 	    ior_verbose( cfg, msg_buf );
886 	    cur_pat->p_pos = cur_pat->p_start;
887 	    cur_pat->p_cur_seq = 0;
888 	};
889     };
890 
891     return( result );
892 }
893 
894 /*
895  * ior_test_prep_skew - prepare for a skew test run
896  */
ior_test_prep_skew(ior_config * cfg)897 int	ior_test_prep_skew( ior_config *cfg )
898 /* ior_config	*cfg;			our configuration */
899 {
900     int		result;			/* final return code */
901     int		cur;			/* current item in loop */
902     ior_test	*cur_test;		/* test we are running */
903     ior_pattern	*cur_pat;		/* current active pattern */
904     ior_device	*cur_dev;		/* current active pattern */
905     char	msg[ 200 ];		/* message buffer */
906 
907     ior_debug_l( cfg, IOR_DEBUG_MINOR, "ior_test_prep_skew: Entering code -->>" );
908 
909     result = 0;				/* all OK so far */
910 
911     cur_dev = &( cfg->c_devs[ cfg->c_cur_dev ]);
912     cur_test = &( cfg->c_tests[ cfg->c_cur_test ]);
913 
914 					/* start each pattern */
915     for ( cur = 0; cur < cfg->c_npat; cur++ ) {
916 
917 	cur_pat = &( cfg->c_pats[ cur ]);
918 
919 					/* only check on active patterns */
920 	if (( !cur_pat->p_valid ) || ( cur_test->t_pat_pct[ cur ] < 1 )) {
921 	    continue;
922 	};
923 
924 					/* limit sequential */
925 	if ( cur_pat->p_max_seq > IOR_SKEW_MAX_SEQ ) {
926 	    sprintf( msg, "limiting sequential operations from %ld to %d due to skew testing",
927 		    (long) cur_pat->p_max_seq, IOR_SKEW_MAX_SEQ );
928 	    ior_verbose( cfg, msg );
929 
930 	    cur_pat->p_max_seq = IOR_SKEW_MAX_SEQ;
931 	};
932 
933 	cur_pat->p_hist_active = 0;	/* no active history records */
934 	cur_pat->p_hist_next = 0;	/* start with item 0 */
935 
936 					/* with no sequential history */
937 	cur_pat->p_cur_seq = 0;
938 
939 	/* NOTE: position chosen at I/O time with skew.... */
940     };
941 
942     ior_debug_l( cfg, IOR_DEBUG_MINOR, "ior_test_prep_skew: <<-- Leaving code" );
943 
944     return( result );
945 }
946 
947 /*
948  * ior_run_skew - run an I/O with the skew profile
949  */
ior_run_skew(ior_config * cfg,long pat)950 int	ior_run_skew( ior_config *cfg, long pat )
951 /* ior_config	*cfg;			our configuration */
952 /* long		pat;			pattern to use */
953 {
954     int		result;			/* final return code */
955     int		group;			/* group for I/O */
956     int		do_seq_next;		/* do next sequential I/O */
957     int		next;			/* ID of next history item */
958     ior_skew_list *cur_skew;		/* current target skew group */
959     ior_skew_pat *cur_pat;		/* current target group pattern */
960     ior_skew_area *cur_area;		/* current target group area */
961     int		align;			/* alignment size */
962     long	cur_copy;		/* which copy of area to use */
963     long	hist;			/* which history record to use */
964     HUGE	area_end;		/* end address of target area */
965     HUGE	block;			/* new position block offset */
966     HUGE	n_pos;			/* new position */
967 
968     result = 0;				/* all OK so far */
969 
970 	/* choose a skew group to process against */
971     group = ior_odds_pick( cfg, &( cfg->c_odds ));
972     cur_skew = &( cfg->c_skewed[ group ]);
973     cur_pat = &( cur_skew->s_pats[ pat ]);
974     cfg->c_cur_pat = pat;
975     cur_area = cur_skew->s_areas;	/* assume this target area */
976 
977     while ( cur_area->a_copies < 1 ) {	/* for empty areas, pick again */
978 
979 	sprintf( msg_buf, "ior_run_skew: (starting) - skipping empty area %ld",
980 		cur_area->a_id );
981 	ior_debug_l( cfg, IOR_DEBUG_ALL, msg_buf );
982 
983 	ior_area( cfg, IOR_AREA_TAIL, cur_area, cur_skew );
984 
985 	cur_area = cur_skew->s_areas;	/* pick the new head */
986     };
987 
988     sprintf( msg_buf, "ior_run_skew: Entering code -->>  pattern %d, skew group %d, area %d",
989 	    (int)( pat + 1 ), group, (int)( cur_area->a_id ));
990     ior_debug_l( cfg, IOR_DEBUG_SMALL, msg_buf );
991 
992 					/* use history if appropriate */
993 					/* ONLY if history is FULL */
994     if ( cur_pat->p_history
995 	    && ( cur_pat->p_hist_active >= cur_pat->p_history )
996 	    && cur_pat->p_hist_use[ ior_rand( cfg ) % 100 ]) {
997 
998 	hist = ior_rand( cfg ) % cur_pat->p_hist_active;
999 
1000 	cur_area = cur_pat->p_hist_areas[ hist ];
1001 		/* NOT setting pattern position to save next sequential */
1002 
1003 	sprintf( msg_buf, "-> Using history I/O %ld at %ldk in area %ld",
1004 		hist + 1, (long) ( cur_pat->p_hist_records[ hist ]/ 1024L ),
1005 		cur_area->a_id );
1006 	ior_verbose( cfg, msg_buf );
1007 
1008 	result = ior_io( cfg, cur_pat->p_read_use[ ior_rand( cfg ) % 100 ],
1009 		cur_pat->p_io_size, cur_pat->p_hist_records[ hist ],
1010 		cur_skew );
1011 
1012     } else {		/* not history - a new, unique I/O */
1013 
1014 	do_seq_next = FALSE;			/* assume not sequential */
1015 
1016 	if (( cur_pat->p_is_seq ) &&
1017 		cur_pat->p_seq_area != NULL ) {	/* if a chance of sequential */
1018 
1019 					/* HOPEFULL for sequential */
1020 	    cur_copy = cur_pat->p_seq_copy;	/* remember the copy */
1021 	    cur_area = cur_pat->p_seq_area;	/* remember the area */
1022 
1023 	    area_end = cur_area->a_end +
1024 		    cur_copy * cfg->c_skew_set_size;
1025 
1026 				/* if seq. too long, do random */
1027 	    if (( cur_pat->p_max_seq > 0 ) &&
1028 		    ( ++( cur_pat->p_cur_seq ) >= cur_pat->p_max_seq )) {
1029 
1030 		/* nope, not sequential */
1031 
1032 	    } else if ( cur_pat->p_pos + cur_pat->p_io_size >= area_end ) {
1033 		sprintf( msg_buf, "ior_run_skew: seq I/O pattern %ld went over end of area %ld (%ldk), sequence interrupted",
1034 			pat + 1, cur_area->a_id,
1035 			(long) ( area_end / 1024L ));
1036 		ior_verbose( cfg, msg_buf );
1037 
1038 		/* and not sequential */
1039 
1040 	    } else {
1041 		do_seq_next = TRUE;		/* finally a good one! */
1042 	    };
1043 	};
1044 
1045 	if ( do_seq_next ) {
1046 
1047 	    /* the position stays where it was from the last I/O */
1048 
1049 	} else {		/* random new location */
1050 
1051 	    ior_debug_l( cfg, IOR_DEBUG_SMALL, "ior_run_skew: -- start new random" );
1052 
1053 	    cur_area = cur_skew->s_areas;	/* pick target area */
1054 
1055 	    cur_copy = ior_rand( cfg ) % cur_area->a_copies;
1056 	    n_pos = ior_rand( cfg ) % cur_area->a_size +
1057 		    cur_area->a_start +
1058 		    cur_copy * cfg->c_skew_set_size;
1059 
1060 					/* now fix the alignment */
1061 					/* -- first is by I/O size */
1062 	    align = cur_pat->p_io_size / (HUGE) IOR_BLOCK_SIZE;
1063 					/* -- or larger if align needed */
1064 	    if ( align < cfg->c_align ) {
1065 		align = cfg->c_align;
1066 	    };
1067 
1068 	    block = n_pos / (HUGE)( IOR_BLOCK_SIZE );
1069 	    block = ( block / align ) * align; /* aligned! */
1070 	    if ( block < 1 ) {		/* we want to align by starting at 1 */
1071 		block = align;
1072 	    };
1073 	    cur_pat->p_pos = block * (HUGE) IOR_BLOCK_SIZE;
1074 
1075 			/* save these, even if the pattern is not sequential */
1076 	    cur_pat->p_cur_seq = 0;
1077 	    cur_pat->p_seq_area = cur_area;
1078 
1079 	    sprintf( msg_buf, "ior_run_skew: I/O pattern %ld new random location chosen (%ldk) [%d.%d], copy %ld of area %ld (start %.2fm)",
1080 		    pat + 1, (long) ( cur_pat->p_pos / 1024L ),
1081 		    cfg->c_cur_dev + 1, cfg->c_cur_adev + 1,
1082 		    cur_copy, cur_area->a_id,
1083 		    (float)(( cur_area->a_start + cur_copy * cfg->c_skew_set_size ) / ( 1024.0 * 1024.0 )));
1084 	    ior_verbose( cfg, msg_buf );
1085 	    if ( !( cfg->c_verbose )) {
1086 		ior_debug_l( cfg, IOR_DEBUG_MINOR, msg_buf );
1087 	    };
1088 	};
1089 
1090 	if ( cur_pat->p_history > 0 ) {	/* record new history item */
1091 
1092 	    sprintf( msg_buf, "-->> Recording pattern %ld I/O as history element %ld [%d.%d]",
1093 		    pat + 1, cur_pat->p_hist_next + 1,
1094 		    cfg->c_cur_dev + 1, cfg->c_cur_adev + 1 );
1095 	    ior_verbose( cfg, msg_buf );
1096 
1097 	    next = cur_pat->p_hist_next++;
1098 
1099 	    cur_pat->p_hist_records[ next ] = cur_pat->p_pos;
1100 	    cur_pat->p_hist_areas[ next ] = cur_area;
1101 
1102 	    if ( cur_pat->p_hist_active < cur_pat->p_hist_next ) {
1103 		cur_pat->p_hist_active = cur_pat->p_hist_next;
1104 	    };
1105 	    if ( cur_pat->p_hist_next >= cur_pat->p_history ) {
1106 		cur_pat->p_hist_next = 0;
1107 	    };
1108 	};
1109 
1110 	result = ior_io( cfg, cur_pat->p_read_use[ ior_rand( cfg ) % 100 ],
1111 		cur_pat->p_io_size, cur_pat->p_pos, cur_skew );
1112 
1113 	cur_pat->p_pos = cfg->c_pos;	/* note new position for pattern */
1114     };
1115 
1116 				/* avoid selecting this area next */
1117     ior_area( cfg, IOR_AREA_TAIL, cur_area, cur_skew );
1118 
1119     ior_debug_l( cfg, IOR_DEBUG_SMALL, "ior_run_skew: <<-- Leaving code" );
1120 
1121     return( result );
1122 }
1123 
1124 
1125 /*
1126  * ior_io - perform an I/O against the target device
1127  */
ior_io(ior_config * cfg,long io,long io_size,HUGE pos,ior_skew_list * skew)1128 int	ior_io( ior_config *cfg, long io, long io_size, HUGE pos, ior_skew_list *skew )
1129 /* ior_config	*cfg;			our configuration */
1130 /* long		io;			type of I/O to do */
1131 /* long		io_size;		size of this I/O */
1132 /* HUGE		pos;			position for I/O */
1133 /* double	*io_resp;		RETURN response time */
1134 {
1135     int		result;			/* final return code */
1136     double	target_time;		/* how long should we have taken? */
1137     ior_device	*cur_dev;		/* our current device */
1138     ior_skew_pat *cur_pat;		/* our current pattern */
1139     double	cur_resp;		/* response time on the I/O */
1140 
1141     result = 0;				/* all OK so far */
1142 
1143     cur_dev = &( cfg->c_devs[ cfg->c_cur_dev ]);
1144 
1145     sprintf( msg_buf, "ior_io: Entering code: %s position %ldk size %ldk [%d.%d]",
1146 	    ( io == IOR_READ ? "Read from" : "Write to" ),
1147 	    (long) ( pos / 1024L ),
1148 	    (long) ( io_size / 1024L ),
1149 	    cfg->c_cur_dev + 1, cfg->c_cur_adev + 1 );
1150     ior_debug_l( cfg, IOR_DEBUG_SMALL, msg_buf );
1151 
1152 					/* valid position? */
1153     if (( pos < 0 ) ||
1154 	    ( pos + io_size > cur_dev->d_capacity )) {
1155 	if ( cfg->c_debug_level < IOR_DEBUG_ALL ) {
1156 	    ior_debug( cfg, msg_buf );
1157 	};
1158 
1159 	sprintf( msg_buf,
1160 		"internal: bad position in 'ior_io', file %d.%d, pattern %d",
1161 		cfg->c_cur_dev + 1, cfg->c_cur_adev + 1,
1162 		cfg->c_cur_pat + 1 );
1163 	ior_error( cfg, msg_buf );
1164 
1165 	if ( pos < 0 ) {
1166 	    sprintf( msg_buf, "starting position (%ldk) too small (0k) [%d.%d]",
1167 		    (long) ( pos / 1024L ),
1168 		    cfg->c_cur_dev + 1, cfg->c_cur_adev + 1 );
1169 	    ior_error( cfg, msg_buf );
1170 	} else {
1171 	    sprintf( msg_buf, "ending position (%ldk) too large (%ldk) [%d.%d]",
1172 		    (long) (( pos + io_size )/ 1024L ),
1173 		    (long) ( cur_dev->d_capacity / 1024L ),
1174 		    cfg->c_cur_dev + 1, cfg->c_cur_adev + 1 );
1175 	    ior_error( cfg, msg_buf );
1176 	};
1177 
1178 	ior_debug( cfg, "ior_io: <<-- Leaving code ** DUE TO ERRORS **" );
1179 	return( -1 );
1180     };
1181 
1182     if ( pos != cfg->c_pos ) {		/* seek if needed */
1183 	if ( ior_seek( cfg, pos ) != 0 ) {
1184 	    ior_debug( cfg, "ior_io: <<-- Leaving code ** DUE TO ERRORS ** SEEK Failed" );
1185 	    return( -2 );
1186 	};
1187     };
1188 
1189     if ( io == IOR_READ ) {		/* perform a read? */
1190 	result = ior_read( cfg, io_size, &cur_resp );
1191 	if ( result != 0 ) {
1192 	    sprintf( msg_buf, "ior_io: <<-- Leaving code ** READ Failed position %ldk, size %ldk [%d.%d], code %d",
1193 		    (long) ( pos / 1024L ),
1194 		    (long) ( io_size / 1024L ),
1195 		    cfg->c_cur_dev + 1,
1196 		    cfg->c_cur_adev + 1,
1197 		    result );
1198 	    ior_debug( cfg, msg_buf );
1199 
1200 	    return( -3 );
1201 	};
1202 
1203 	cfg->c_reads++;
1204 	cfg->c_blocks_read += io_size / 1024L;
1205 
1206 	if ( skew != NULL ) {
1207 	    cur_pat = &( skew->s_pats[ cfg->c_cur_pat ]);
1208 
1209 	    if ( cur_pat->p_is_seq ) {
1210 		skew->s_perf.sp_seq_reads++;
1211 		skew->s_perf.sp_seq_read_resp += cur_resp;
1212 	    } else {
1213 		skew->s_perf.sp_rand_reads++;
1214 		skew->s_perf.sp_rand_read_resp += cur_resp;
1215 	    };
1216 	};
1217     } else {
1218 	result = ior_write( cfg, io_size, &cur_resp );
1219 	if ( result != 0 ) {
1220 	    sprintf( msg_buf, "ior_io: <<-- Leaving code ** WRITE Failed position %ldk, size %ldk [%d.%d], code %d",
1221 		    (long) ( pos / 1024L ),
1222 		    (long) ( io_size / 1024L ),
1223 		    cfg->c_cur_dev + 1,
1224 		    cfg->c_cur_adev + 1,
1225 		    result );
1226 	    ior_debug( cfg, msg_buf );
1227 
1228 	    return( -4 );
1229 	};
1230 
1231 	cfg->c_writes++;
1232 	cfg->c_blocks_written += io_size / 1024L;
1233 
1234 	if ( skew != NULL ) {
1235 	    cur_pat = &( skew->s_pats[ cfg->c_cur_pat ]);
1236 
1237 	    if ( cur_pat->p_is_seq ) {
1238 		skew->s_perf.sp_seq_writes++;
1239 		skew->s_perf.sp_seq_write_resp += cur_resp;
1240 	    } else {
1241 		skew->s_perf.sp_rand_writes++;
1242 		skew->s_perf.sp_rand_write_resp += cur_resp;
1243 	    };
1244 	};
1245     };
1246 
1247     if ( cfg->c_target_resp > 0 ) {	/* slow down if desired */
1248 
1249 	/* Using the target time for the number of I/Os per second,	*/
1250 	/* decide if we need to go faster (no delay), slower (delay	*/
1251 	/* of a full target response time), or we are about on target	*/
1252 	/* (and sleep for a random average of half a target response	*/
1253 	/* time.							*/
1254 
1255 	target_time = cfg->c_target_sec * ( cfg->c_reads + cfg->c_writes );
1256 
1257 	if ( target_time > cfg->c_io_time ) { /* too fast - slow it down */
1258 	    ior_sleep_usec( cfg, cfg->c_target_resp );
1259 	} else if ( target_time >= cfg->c_io_time ) { /* about right */
1260 	    ior_sleep_usec( cfg, ior_rand( cfg ) % cfg->c_target_resp );
1261 	} else {
1262 		/* if neither, then too slow, so go flat out */
1263 	};
1264     };
1265 
1266     ior_debug_l( cfg, IOR_DEBUG_SMALL, "ior_io: <<-- Leaving code" );
1267     return( result );
1268 }
1269 
1270 /*
1271  * ior_set_rand_pos - set a new, random position for next I/O
1272  */
ior_set_rand_pos(ior_config * cfg,long pat)1273 int	ior_set_rand_pos( ior_config *cfg, long pat )
1274 /* ior_config	*cfg;			our configuration */
1275 /* long		pat;			pattern being worked on */
1276 {
1277     HUGE	block;			/* chosen block to perform I/O at */
1278     HUGE	pat_blocks;		/* blocks in the pattern */
1279     HUGE	h_tmp;			/* huge temp value */
1280     int		result;			/* final return code */
1281     int		align;			/* alignment size */
1282     ior_pattern	*cur_pat;		/* current active pattern */
1283 
1284     result = 0;				/* all OK so far */
1285 
1286 					/* find current pattern */
1287     cur_pat = &( cfg->c_pats[ pat ]);
1288 
1289     pat_blocks = cur_pat->p_size / (HUGE) IOR_BLOCK_SIZE;
1290     if ( pat_blocks < 1 ) {
1291 	sprintf( msg_buf, "Pattern size invalid (%ldk) for pattern %ld [%d.%d]",
1292 		(long)( cur_pat->p_size / 1024L ), pat + 1,
1293 		cfg->c_cur_dev + 1, cfg->c_cur_adev + 1 );
1294 	ior_error( cfg, msg_buf );
1295 	cur_pat->p_pos = cur_pat->p_start;
1296 	return( -1 );
1297     };
1298 					/* pick a block to start with */
1299     h_tmp = ior_rand( cfg ) % pat_blocks;
1300     block = cur_pat->p_start / (HUGE) IOR_BLOCK_SIZE + h_tmp;
1301 
1302 					/* now fix the alignment */
1303 					/* -- first is by I/O size */
1304     align = cur_pat->p_io_size / (HUGE) IOR_BLOCK_SIZE;
1305 					/* -- or larger if align needed */
1306     if ( align < cfg->c_align ) {
1307 	align = cfg->c_align;
1308     };
1309     block = ( block / align ) * align; /* aligned! */
1310     if ( block < 1 ) {			/* we want to align by starting at 1 */
1311 	block = align;
1312     };
1313 
1314     cur_pat->p_pos = block * (HUGE) IOR_BLOCK_SIZE;
1315 
1316 					/* just in case we go outside -- */
1317     if (( cur_pat->p_pos < cur_pat->p_start ) ||
1318 	    ( cur_pat->p_pos + cur_pat->p_io_size > cur_pat->p_end )) {
1319 	sprintf( msg_buf, "Pattern position invalid (%ldk) for pattern %ld [%d.%d]",
1320 		(long)( cur_pat->p_pos / 1024L ), pat + 1,
1321 		cfg->c_cur_dev + 1, cfg->c_cur_adev + 1 );
1322 	ior_warn( cfg, msg_buf );
1323 	cur_pat->p_pos = cur_pat->p_start; /* default to start of device */
1324     };
1325 
1326     return( result );
1327 }
1328 
1329