Modified IO Load Generator (sio_ntap.c)
May 28, 2014 § 1 Comment
Below is the text of a diff output between the NetApp sio_ntap.c file, downloadable from here:
https://communities.netapp.com/blogs/zurich/2011/01/24/sio–performance-load-testing-simplified
and my updated version. To merge them, “patch ./sio_ntap ./sio_ntap.c.diff” should be sufficient.
The ammended version attempts to produce a specified number of IOPS by throttling a sleep. Once the required rate has been successfully held, the sleep time is fixed for the duration of the measured run.
An extension to this would be to alter the distribution of the sleep time to approximate a Poisson process. This should give more realistic performance figures under load.
44,45c44
< #include <unistd.h> // need for usleep
< #include <time.h> // need for nanosecond timer
—
>
115,116c114
< #define IOPS_POS 7
< #define DEVICES_POS 8
—
> #define DEVICES_POS 7
135,137d132
< pthread_mutex_t mutx = PTHREAD_MUTEX_INITIALIZER;
< pthread_cond_t condx = PTHREAD_COND_INITIALIZER;
< typedef enum { false, true } bool;
153c148
< struct timeb begin_time, end_time, cur_time, tmp_time;
—
> struct timeb begin_time, end_time;
169,187d163
< struct timespec timer_start() {
< struct timespec start_time_ns;
< clock_gettime(CLOCK_REALTIME, &start_time_ns);
< return start_time_ns;
< }
<
< long timer_end(struct timespec start_time_ns) {
< struct timespec end_time_ns;
< clock_gettime(CLOCK_REALTIME, &end_time_ns);
< long diffInNs = end_time_ns.tv_nsec – start_time_ns.tv_nsec;
< if ( start_time_ns.tv_nsec > end_time_ns.tv_nsec ) {
< diffInNs += 1000000000; //adjust for having times from different seconds.
< }
< return diffInNs;
< }
<
<
<
<
241d216
< int iops_target = atoi (argv[IOPS_POS]);
266,267d240
<
< int sleep_us = 1000 * 1000 / iops_target;
269c242
< while (!io_completes[i]) {
—
> while (!io_completes[i])
271d243
< }
279,340c251
< ftime (&cur_time);
< int iops_counter = 0;
<
< long time_elapsed_ns = 0;
<
< struct timespec run_start_time = timer_start();
< bool in_warmup = true;
< bool in_speedtest = false;
< int iops_scale_pct = 100;
< int hold_count = 0;
<
< printf(“Beginning warmup phase. Attempting to hold requested mean IO rate.\n”);
< while(cur_time.time – begin_time.time < run_time ) {
<
< //Need to spend the first second working out what the scale factor needs to be….
< if (in_warmup == true && timer_end(run_start_time) > 900000000L ) {
< //Done warmup
< in_warmup = false;
< in_speedtest = true;
< iops_counter = 0;
< run_start_time = timer_start();
< }
< if (in_speedtest == true && timer_end( run_start_time) > 900000000L ) {
< int tmp_iops_scale_pct = 90 * iops_target / iops_counter;
< if (tmp_iops_scale_pct <= 100) {
< //No more scaling needed.
< ++hold_count;
< if (hold_count == 10) {
< in_speedtest = false;
< for (i = 0; i < num_threads; i++) io_completes[i] = 0;
< in_speedtest = false;
< in_warmup = false;
< }
< else {
< in_speedtest = false;
< in_warmup = true;
< }
< } else {
< in_warmup = true;
< in_speedtest = false;
< }
<
< //Only change scale factor if > 100.
< //if (tmp_iops_scale_pct > 100)
< iops_scale_pct = iops_scale_pct * tmp_iops_scale_pct / 100;
< printf(“.”);
< run_start_time = timer_start();
< iops_counter = 0;
<
< //reset timers so this doesn’t count to run length, or to iops.
< ftime (&begin_time);
< }
<
< struct timespec loop_start_time = timer_start();
< usleep (sleep_us * 100 / iops_scale_pct);
< pthread_cond_signal(&condx);
< ++iops_counter;
< ftime (&cur_time);
< time_elapsed_ns = timer_end( loop_start_time );
< }
< printf(“\n”);
<
—
> sleep (run_time);
484a396
>
519,523d430
<
< //Setup threading to wait for io.
< pthread_mutex_lock (&mutx);
< pthread_cond_wait(&condx, &mutx);
< pthread_mutex_unlock(&mutx);
Note: This patch has only been tested on Linux.