aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2014-08-21 23:27:24 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2014-08-21 23:27:24 +0000
commitd9c9f89ba08fe11962a17df4d585641fc1b99f74 (patch)
treea03f761d51ba2ed73726555d232ffe42b1db878d /examples
parenta158633e318fd0ccb5358594152739714273f9ee (diff)
downloadsg3_utils-d9c9f89ba08fe11962a17df4d585641fc1b99f74.tar.gz
sg_vpd: fix '-I - -a -r' (it should not try to guess first VPD page); more examples/sg_tst_async work
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@601 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'examples')
-rw-r--r--examples/sg_tst_async.cpp158
1 files changed, 86 insertions, 72 deletions
diff --git a/examples/sg_tst_async.cpp b/examples/sg_tst_async.cpp
index 978eba28..058af985 100644
--- a/examples/sg_tst_async.cpp
+++ b/examples/sg_tst_async.cpp
@@ -56,7 +56,7 @@
#include "sg_lib.h"
#include "sg_io_linux.h"
-static const char * version_str = "1.05 20140819";
+static const char * version_str = "1.05 20140821";
static const char * util_name = "sg_tst_async";
/* This is a test program for checking the async usage of the Linux sg
@@ -134,8 +134,13 @@ static atomic<int> uniq_pack_id(1);
static int page_size = 4096; /* rough guess, will ask sysconf() */
enum command2execute {SCSI_TUR, SCSI_READ16, SCSI_WRITE16};
-enum blkQDiscipline {BQ_DEFAULT, BQ_AT_HEAD, BQ_AT_TAIL};
-enum myQDiscipline {MQD_LOW, MQD_MEDIUM, MQD_HIGH};
+/* Linux Block layer queue disciplines: */
+enum blkLQDiscipline {BLQ_DEFAULT, BLQ_AT_HEAD, BLQ_AT_TAIL};
+/* Queue disciplines of this utility. When both completions and
+ * queuing a new command are both possible: */
+enum myQDiscipline {MYQD_LOW, /* favour completions over new cmds */
+ MYQD_MEDIUM,
+ MYQD_HIGH}; /* favour new cmds over completions */
struct opts_t {
vector<const char *> dev_names;
@@ -151,8 +156,8 @@ struct opts_t {
int verbose;
int wait_ms;
command2execute c2e;
- blkQDiscipline bqd;
- myQDiscipline mqd;
+ blkLQDiscipline blqd;
+ myQDiscipline myqd;
};
#if 0
@@ -180,11 +185,16 @@ private:
};
#endif
+/* Use this class to wrap C++11 <random> features to produce uniform random
+ * unsigned ints in the range [lo, hi] (inclusive) given a_seed */
class Rand_uint {
public:
- Rand_uint(unsigned int lo, unsigned int hi, unsigned int my_seed)
- : uid(lo, hi), dre(my_seed) { }
+ Rand_uint(unsigned int lo, unsigned int hi, unsigned int a_seed)
+ : uid(lo, hi), dre(a_seed) { }
+ /* uid ctor takes inclusive range when integral type */
+
unsigned int get() { return uid(dre); }
+
private:
uniform_int_distribution<unsigned int> uid;
default_random_engine dre;
@@ -293,15 +303,16 @@ get_urandom_uint(void)
unsigned int res = 0;
int n;
unsigned char b[sizeof(unsigned int)];
- int fd = open(URANDOM_DEV, O_RDONLY);
+ rand_lba_mutex.lock();
+ int fd = open(URANDOM_DEV, O_RDONLY);
if (fd >= 0) {
- /* assume this read is atomic */
n = read(fd, b, sizeof(unsigned int));
if (sizeof(unsigned int) == n)
memcpy(&res, b, sizeof(unsigned int));
close(fd);
}
+ rand_lba_mutex.unlock();
return res;
}
@@ -469,13 +480,14 @@ get_aligned_heap(int bytes_at_least)
memset(wp, 0, n);
return (unsigned char *)wp;
#else
+ /* hack if posix_memalign() is not available */
if (n == page_size) {
wp = calloc(page_size, 1);
memset(wp, 0, n);
return (unsigned char *)wp;
} else {
pr2serr_lk("get_aligned_heap: too fiddly to align, choose smaller "
- "lb_sz\n");
+ "lb_sz\n");
return NULL;
}
#endif
@@ -488,7 +500,8 @@ work_thread(int id, struct opts_t * op)
int thr_async_finishes = 0;
unsigned int thr_eagain_count = 0;
unsigned int seed = 0;
- int k, n, res, sg_fd, num_outstanding, do_inc, num, pack_id, sg_flags;
+ unsigned int hi_lba;
+ int k, n, res, sg_fd, num_outstanding, do_inc, npt, pack_id, sg_flags;
int num_waiting_read, num_to_read;
int open_flags = O_RDWR;
bool is_rw = (SCSI_TUR != op->c2e);
@@ -499,19 +512,23 @@ work_thread(int id, struct opts_t * op)
const char * err = NULL;
Rand_uint * ruip = NULL;
struct pollfd pfd[1];
- list<unsigned char *> free_lst;
- map<int, unsigned char *> pi_2_buff;
- map<int, uint64_t> pi_2_lba;
+ list<unsigned char *> free_lst; /* of aligned lb buffers */
+ map<int, unsigned char *> pi_2_buff; /* pack_id -> lb buffer */
+ map<int, uint64_t> pi_2_lba; /* pack_id -> LBA */
+ /* device name and hi_lba may depend on id */
n = op->dev_names.size();
dev_name = op->dev_names[id % n];
+ if ((UINT_MAX == op->hi_lba) && (n == (int)op->hi_lbas.size()))
+ hi_lba = op->hi_lbas[id % n];
+ else
+ hi_lba = op->hi_lba;
+
if (op->verbose) {
- if ((op->verbose > 1) && op->hi_lba)
+ if ((op->verbose > 1) && hi_lba)
pr2serr_lk("Enter work_thread id=%d using %s\n"
" LBA range: 0x%x to 0x%x (inclusive)\n",
- id, dev_name, (unsigned int)op->lba,
- (UINT_MAX == op->hi_lba) ? op->hi_lbas[id % n]
- : op->hi_lba);
+ id, dev_name, (unsigned int)op->lba, hi_lba);
else
pr2serr_lk("Enter work_thread id=%d using %s\n", id, dev_name);
}
@@ -521,26 +538,22 @@ work_thread(int id, struct opts_t * op)
sg_fd = open(dev_name, open_flags);
if (sg_fd < 0) {
pr_errno_lk(errno, "%s: id=%d, error opening file: %s", __func__, id,
- dev_name);
+ dev_name);
return;
}
pfd[0].fd = sg_fd;
pfd[0].events = POLLIN;
- if (is_rw && op->hi_lba) {
+ if (is_rw && hi_lba) {
seed = get_urandom_uint();
if (op->verbose > 1)
pr2serr_lk(" id=%d, /dev/urandom seed=0x%x\n", id, seed);
- if (UINT_MAX == op->hi_lba)
- ruip = new Rand_uint((unsigned int)op->lba, op->hi_lbas[id % n],
- seed);
- else
- ruip = new Rand_uint((unsigned int)op->lba, op->hi_lba, seed);
+ ruip = new Rand_uint((unsigned int)op->lba, hi_lba, seed);
}
sg_flags = 0;
- if (BQ_AT_TAIL == op->bqd)
+ if (BLQ_AT_TAIL == op->blqd)
sg_flags |= SG_FLAG_Q_AT_TAIL;
- else if (BQ_AT_HEAD == op->bqd)
+ else if (BLQ_AT_HEAD == op->blqd)
sg_flags |= SG_FLAG_Q_AT_HEAD;
if (op->direct)
sg_flags |= SG_FLAG_DIRECT_IO;
@@ -551,14 +564,16 @@ work_thread(int id, struct opts_t * op)
((SCSI_TUR == op->c2e) ? "TUR":
((SCSI_READ16 == op->c2e) ? "READ" : "WRITE")));
- num = op->num_per_thread;
- for (k = 0, num_outstanding = 0; (k < num) || num_outstanding;
+ npt = op->num_per_thread;
+ /* main loop, continues until num_per_thread exhausted and there are
+ * no more outstanding responses */
+ for (k = 0, num_outstanding = 0; (k < npt) || num_outstanding;
k = do_inc ? k + 1 : k) {
do_inc = 0;
- if ((num_outstanding < op->maxq_per_thread) && (k < num)) {
+ if ((num_outstanding < op->maxq_per_thread) && (k < npt)) {
do_inc = 1;
pack_id = uniq_pack_id.fetch_add(1);
- if (is_rw) {
+ if (is_rw) { /* get new lb buffer or one from free list */
if (free_lst.empty()) {
lbp = get_aligned_heap(op->lb_sz);
if (NULL == lbp) {
@@ -573,7 +588,7 @@ work_thread(int id, struct opts_t * op)
lbp = NULL;
if (is_rw) {
if (ruip) {
- lba = ruip->get();
+ lba = ruip->get(); /* fetch a random LBA */
if (op->verbose > 3)
pr2serr_lk(" id=%d: start IO at lba=0x%" PRIx64 "\n",
id, lba);
@@ -593,7 +608,7 @@ work_thread(int id, struct opts_t * op)
pi_2_lba[pack_id] = lba;
}
num_to_read = 0;
- if ((num_outstanding >= op->maxq_per_thread) || (k >= num)) {
+ if ((num_outstanding >= op->maxq_per_thread) || (k >= npt)) {
/* full queue or finished injecting */
num_waiting_read = 0;
if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting_read) < 0) {
@@ -603,23 +618,23 @@ work_thread(int id, struct opts_t * op)
if (1 == num_waiting_read)
num_to_read = num_waiting_read;
else if (num_waiting_read > 0) {
- if (k >= num)
+ if (k >= npt)
num_to_read = num_waiting_read;
else {
- switch (op->mqd) {
- case MQD_LOW:
+ switch (op->myqd) {
+ case MYQD_LOW:
num_to_read = num_waiting_read;
break;
- case MQD_MEDIUM:
+ case MYQD_MEDIUM:
num_to_read = num_waiting_read / 2;
break;
- case MQD_HIGH:
+ case MYQD_HIGH:
default:
num_to_read = 1;
break;
}
}
- } else {
+ } else { /* nothing waiting to be read */
n = (op->wait_ms > 0) ? op->wait_ms : 0;
while (0 == (res = poll(pfd, 1, n))) {
if (res < 0) {
@@ -631,7 +646,7 @@ work_thread(int id, struct opts_t * op)
break;
}
} else { /* not full, not finished injecting */
- if (MQD_HIGH == op->mqd)
+ if (MYQD_HIGH == op->myqd)
num_to_read = 0;
else {
num_waiting_read = 0;
@@ -641,7 +656,7 @@ work_thread(int id, struct opts_t * op)
}
if (num_waiting_read > 0)
num_to_read = num_waiting_read /
- ((MQD_LOW == op->mqd) ? 1 : 2);
+ ((MYQD_LOW == op->myqd) ? 1 : 2);
else
num_to_read = 0;
}
@@ -697,18 +712,18 @@ work_thread(int id, struct opts_t * op)
if (ruip)
delete ruip;
- if (err || (k < num)) {
- if (k < num)
+ if (err || (k < npt)) {
+ if (k < npt)
pr2serr_lk("thread id=%d FAILed at iteration %d%s%s\n", id, k,
- (err ? ", Reason: " : ""), (err ? err : ""));
+ (err ? ", Reason: " : ""), (err ? err : ""));
else
pr2serr_lk("thread id=%d FAILed on last%s%s\n", id,
- (err ? ", Reason: " : ""), (err ? err : ""));
+ (err ? ", Reason: " : ""), (err ? err : ""));
}
n = pi_2_buff.size();
if (n > 0)
- pr2serr_lk("thread id=%d Still %d elements in pi_2_buff map on exit\n",
- id, n);
+ pr2serr_lk("thread id=%d Still %d elements in pi_2_buff map on "
+ "exit\n", id, n);
for (k = 0; ! free_lst.empty(); ++k) {
lbp = free_lst.back();
free_lst.pop_back();
@@ -717,7 +732,7 @@ work_thread(int id, struct opts_t * op)
}
if ((op->verbose > 2) && (k > 0))
pr2serr_lk("thread id=%d Maximum number of READ/WRITEs queued: %d\n",
- id, k);
+ id, k);
async_starts += thr_async_starts;
async_finishes += thr_async_finishes;
eagain_count += thr_eagain_count;
@@ -875,6 +890,7 @@ main(int argc, char * argv[])
struct opts_t opts;
struct opts_t * op;
const char * cp;
+ const char * dev_name;
op = &opts;
op->direct = !! DEF_DIRECT;
@@ -887,9 +903,9 @@ main(int argc, char * argv[])
op->verbose = 0;
op->wait_ms = DEF_WAIT_MS;
op->c2e = SCSI_TUR;
- op->bqd = BQ_DEFAULT;
+ op->blqd = BLQ_DEFAULT;
op->block = !! DEF_BLOCKING;
- op->mqd = MQD_HIGH;
+ op->myqd = MYQD_HIGH;
page_size = sysconf(_SC_PAGESIZE);
for (k = 1; k < argc; ++k) {
@@ -950,9 +966,9 @@ main(int argc, char * argv[])
if ((k < argc) && isdigit(*argv[k])) {
n = atoi(argv[k]);
if (0 == n)
- op->bqd = BQ_AT_HEAD;
+ op->blqd = BLQ_AT_HEAD;
else if (1 == n)
- op->bqd = BQ_AT_TAIL;
+ op->blqd = BLQ_AT_TAIL;
} else
break;
} else if (0 == memcmp("-Q", argv[k], 2)) {
@@ -960,11 +976,11 @@ main(int argc, char * argv[])
if ((k < argc) && isdigit(*argv[k])) {
n = atoi(argv[k]);
if (0 == n)
- op->mqd = MQD_LOW;
+ op->myqd = MYQD_LOW;
else if (1 == n)
- op->mqd = MQD_MEDIUM;
+ op->myqd = MYQD_MEDIUM;
else if (2 == n)
- op->mqd = MQD_HIGH;
+ op->myqd = MYQD_HIGH;
} else
break;
} else if (0 == memcmp("-R", argv[k], 2))
@@ -1028,24 +1044,23 @@ main(int argc, char * argv[])
struct stat a_stat;
for (k = 0; k < (int)op->dev_names.size(); ++k) {
- if (stat(op->dev_names[k], &a_stat) < 0) {
- snprintf(b, sizeof(b), "could not stat() %s",
- op->dev_names[k]);
+ dev_name = op->dev_names[k];
+ if (stat(dev_name, &a_stat) < 0) {
+ snprintf(b, sizeof(b), "could not stat() %s", dev_name);
perror(b);
return 1;
}
if (! S_ISCHR(a_stat.st_mode)) {
pr2serr_lk("%s should be a sg device which is a char "
- "device. %s\n", op->dev_names[k], op->dev_names[k]);
- pr2serr_lk("is not a char device and damage could be "
- "done if it is a BLOCK\ndevice, exiting ...\n");
+ "device. %s\n", dev_name, dev_name);
+ pr2serr_lk("is not a char device and damage could be done "
+ "if it is a BLOCK\ndevice, exiting ...\n");
return 1;
}
if (! force) {
- res = do_inquiry_prod_id(op->dev_names[k], op->block, b,
- sizeof(b));
+ res = do_inquiry_prod_id(dev_name, op->block, b, sizeof(b));
if (res) {
- pr2serr_lk("INQUIRY failed on %s\n", op->dev_names[k]);
+ pr2serr_lk("INQUIRY failed on %s\n", dev_name);
return 1;
}
// For safety, since <lba> written to, only permit scsi_debug
@@ -1062,21 +1077,20 @@ main(int argc, char * argv[])
unsigned int last_lba;
unsigned int blk_sz;
- res = do_read_capacity(op->dev_names[k], op->block,
- &last_lba, &blk_sz);
+ res = do_read_capacity(dev_name, op->block, &last_lba,
+ &blk_sz);
if (2 == res)
- res = do_read_capacity(op->dev_names[k], op->block,
- &last_lba, &blk_sz);
+ res = do_read_capacity(dev_name, op->block, &last_lba,
+ &blk_sz);
if (res) {
- pr2serr_lk("READ CAPACITY(10) failed on %s\n",
- op->dev_names[k]);
+ pr2serr_lk("READ CAPACITY(10) failed on %s\n", dev_name);
return 1;
}
op->hi_lbas.push_back(last_lba);
if (blk_sz != (unsigned int)op->lb_sz)
pr2serr_lk(">>> warning: Logical block size (%d) of %s\n"
" differs from command line option (or "
- "default)\n", blk_sz, op->dev_names[k]);
+ "default)\n", blk_sz, dev_name);
}
}
@@ -1118,7 +1132,7 @@ main(int argc, char * argv[])
if (a > 0.000001) {
printf("Time to complete %d commands was %d.%06d seconds\n",
n, (int)res_tm.tv_sec, (int)(res_tm.tv_nsec / 1000));
- cout << "Implies " << (b / a) << " IOPS" << endl;
+ printf("Implies %.0f IOPS\n", (b / a));
}
}