/** ******************************************************************************** ** \brief main ** \details ** process input parms \n ** open device \n ** alloc memory \n ** loop running IO until secs expire \n ** print IO stats \n ** cleanup *******************************************************************************/ int main(int argc, char **argv) { struct timeval start, delta; long int mil = 1000000; float esecs = 0; uint8_t *rbuf = NULL; uint8_t *wbuf = NULL; OP_t *op = NULL; char *dev = NULL; char FF = 0xFF; char c = '\0'; chunk_ext_arg_t ext = 0; int flags = 0; int i, rc = 0; int id = 0; char *_secs = NULL; char *_QD = NULL; char *_RD = NULL; char *_nblocks = NULL; uint32_t plun = 0; uint32_t nsecs = 4; uint32_t QD = 256; uint32_t nRD = 100; uint32_t RD = 0; uint32_t WR = 0; uint32_t intrp_thds = 0; int rtag = 0; int htag = 0; uint32_t lba = 0; size_t nblks = 0; uint32_t nblocks = 1; uint32_t cnt = 0; uint32_t tmiss = 0; uint64_t status = 0; uint32_t TI = TIME_INTERVAL; uint32_t N = 0; uint32_t TIME = 1; uint32_t COMP = 0; uint32_t miss = 0; uint64_t tlat = 0; double ns_per_tick = 0; /*-------------------------------------------------------------------------- * process and verify input parms *------------------------------------------------------------------------*/ while (FF != (c=getopt(argc, argv, "d:r:q:n:s:phi"))) { switch (c) { case 'd': dev = optarg; break; case 'r': _RD = optarg; break; case 'q': _QD = optarg; break; case 'n': _nblocks = optarg; break; case 's': _secs = optarg; break; case 'p': plun = 1; break; case 'i': intrp_thds = 1; break; case 'h': case '?': usage(); break; } } if (_secs) nsecs = atoi(_secs); if (_QD) QD = atoi(_QD); if (_nblocks) nblocks = atoi(_nblocks); if (_RD) nRD = atoi(_RD); if (QD > _8K) QD = _8K; if (nRD > 100) nRD = 100; if (!plun && nblocks > 1) { printf("error: <-n %d> can only be used with a physical lun\n",nblocks); usage(); } if (dev == NULL) usage(); srand48(time(0)); ns_per_tick = time_per_tick(1000, 100); N = QD; COMP = QD < 8 ? 1 : QD/8; /*-------------------------------------------------------------------------- * open device and set lun size *------------------------------------------------------------------------*/ rc = cblk_init(NULL,0); if (rc) { fprintf(stderr,"cblk_init failed with rc = %d and errno = %d\n", rc,errno); exit(1); } if (!plun) flags = CBLK_OPN_VIRT_LUN; if (!intrp_thds) flags |= CBLK_OPN_NO_INTRP_THREADS; id = cblk_open(dev, QD, O_RDWR, ext, flags); if (id == NULL_CHUNK_ID) { if (ENOSPC == errno) fprintf(stderr,"cblk_open: ENOSPC\n"); else if (ENODEV == errno) fprintf(stderr,"cblk_open: ENODEV\n"); else fprintf(stderr,"cblk_open: errno:%d\n",errno); cblk_term(NULL,0); exit(errno); } rc = cblk_get_lun_size(id, &nblks, 0); if (rc) { fprintf(stderr, "cblk_get_lun_size failed: errno: %d\n", errno); exit(errno); } if (!plun) { nblks = nblks > SET_NBLKS ? SET_NBLKS : nblks; rc = cblk_set_size(id, nblks, 0); if (rc) { fprintf(stderr, "cblk_set_size failed, errno: %d\n", errno); exit(errno); } } lba = lrand48() % nblks; /*-------------------------------------------------------------------------- * alloc data for IO *------------------------------------------------------------------------*/ op = malloc(QD*sizeof(OP_t)); if ((rc=posix_memalign((void**)&rbuf, _4K, _4K*nblocks))) { fprintf(stderr,"posix_memalign failed, size=%d, rc=%d\n", _4K*nblocks, rc); cblk_close(id,0); cblk_term(NULL,0); exit(0); } if ((rc=posix_memalign((void**)&wbuf, _4K, _4K*nblocks))) { fprintf(stderr,"posix_memalign failed, size=%d, rc=%d\n", _4K*nblocks, rc); cblk_close(id,0); cblk_term(NULL,0); exit(0); } memset(wbuf,0x79,_4K*nblocks); memset(op, 0, QD*sizeof(OP_t)); /*-------------------------------------------------------------------------- * loop running IO until secs expire *------------------------------------------------------------------------*/ gettimeofday(&start, NULL); do { /* setup #read ops and #write ops to send before completing ops */ if (!RD && !WR) {RD=nRD; WR=100-RD;} /*---------------------------------------------------------------------- * send up to RD reads, as long as the queuedepth N is not max *--------------------------------------------------------------------*/ while (TIME && RD && N) { rc = cblk_aread(id, rbuf, lba, nblocks, &rtag, NULL, CBLK_ARW_WAIT_CMD_FLAGS); if (0 == rc) {OP_BEG(rtag); --RD; --N; BMP_LBA();} else if (EBUSY == errno) {break;} else {io_error(id,errno);} } /*---------------------------------------------------------------------- * send up to WR writes, as long as the queuedepth N is not max *--------------------------------------------------------------------*/ while (TIME && WR && N) { rc = cblk_awrite(id, wbuf, lba, nblocks, &rtag, NULL, CBLK_ARW_WAIT_CMD_FLAGS); if (0 == rc) {OP_BEG(rtag); --WR; --N; BMP_LBA();} else if (EBUSY == errno) {break;} else {io_error(id,errno);} } /*---------------------------------------------------------------------- * complete cmds *--------------------------------------------------------------------*/ for (i=0; i<QD && N<COMP; i++, htag++) { if (intrp_thds) { rc = cblk_aresult(id, &htag, &status, CBLK_ARESULT_BLOCKING | CBLK_ARESULT_NEXT_TAG); if (rc != nblocks) {io_error(id,errno);} OP_END(htag); ++cnt; ++N; continue; } if (htag>=QD) htag=0; if (!op[htag].iss) {continue;} rc = cblk_aresult(id, &htag, &status, 0); if (rc == 0) { if (QD==1 && ++miss==1) {usleep(80);} ++tmiss; continue; } else if (rc < 0) {io_error(id,errno);} OP_END(htag); ++cnt; ++N; miss=0; } /*---------------------------------------------------------------------- * at an interval which does not impact performance, check if secs * have expired, and randomize lba *--------------------------------------------------------------------*/ if (cnt > TI) { TI += TIME_INTERVAL; gettimeofday(&delta, NULL); if (delta.tv_sec - start.tv_sec >= nsecs) {TIME=0; COMP=QD;} lba = lrand48() % nblks; } } while (TIME || QD-N); /*-------------------------------------------------------------------------- * print IO stats *------------------------------------------------------------------------*/ gettimeofday(&delta, NULL); esecs = ((float)((delta.tv_sec*mil + delta.tv_usec) - (start.tv_sec*mil + start.tv_usec))) / (float)mil; printf("d:%s r:%d q:%d s:%d p:%d n:%d i:%d miss:%d lat:%d mbps:%d iops:%d", dev, nRD, QD, nsecs, plun, nblocks, intrp_thds, tmiss, (uint32_t)((tlat*ns_per_tick)/cnt/1000), (uint32_t)((float)((cnt*nblocks*4)/1024)/esecs), (uint32_t)((float)(cnt/esecs))); if (plun && nblocks > 1) printf(" 4k-iops:%d", (uint32_t)((float)(cnt*nblocks)/esecs)); printf("\n"); /*-------------------------------------------------------------------------- * cleanup *------------------------------------------------------------------------*/ free(op); free(rbuf); free(wbuf); cblk_close(id,0); cblk_term(NULL,0); return 0; }
/** ******************************************************************************** ** \brief main ** \details ** process input parms \n ** open device \n ** alloc memory \n ** loop running IO until secs expire \n ** print IO stats \n ** cleanup *******************************************************************************/ int main(int argc, char **argv) { struct timeval start, delta; long int mil = 1000000; float esecs = 0; uint8_t **rbuf = NULL; uint8_t **wbuf = NULL; int *tags = NULL; char *dev = NULL; char FF = 0xFF; char c = '\0'; chunk_ext_arg_t ext = 0; int flags = 0; int rc = 0; int id = 0; char *_secs = NULL; char *_QD = NULL; char *_RD = NULL; char *_nblocks = NULL; uint32_t plun = 0; uint32_t nsecs = 4; uint32_t QD = 500; uint32_t nRD = 100; uint32_t RD = 0; uint32_t WR = 0; uint32_t intrp_thds = 0; int tag = 0; int rtag = 0; uint32_t lba = 0; size_t nblks = 0; uint32_t nblocks = 1; uint32_t cnt = 0; uint32_t pollN = 0; uint64_t status = 0; uint32_t TI = TIME_INTERVAL; uint32_t N = 0; uint32_t TIME = 1; uint32_t COMP = 0; /*-------------------------------------------------------------------------- * process and verify input parms *------------------------------------------------------------------------*/ while (FF != (c=getopt(argc, argv, "d:r:q:n:s:phi"))) { switch (c) { case 'd': dev = optarg; break; case 'r': _RD = optarg; break; case 'q': _QD = optarg; break; case 'n': _nblocks = optarg; break; case 's': _secs = optarg; break; case 'p': plun = 1; break; case 'i': intrp_thds = 1; break; case 'h': case '?': usage(); break; } } if (_secs) nsecs = atoi(_secs); if (_QD) QD = atoi(_QD); if (_nblocks) nblocks = atoi(_nblocks); if (_RD) nRD = atoi(_RD); if (QD > _8K) QD = _8K; if (nRD > 100) nRD = 100; if (!plun) nblocks = 1; if (dev == NULL) usage(); srand48(time(0)); N = QD; COMP = QD < 5 ? 1 : QD/5; /*-------------------------------------------------------------------------- * open device and set lun size *------------------------------------------------------------------------*/ rc = cblk_init(NULL,0); if (rc) { fprintf(stderr,"cblk_init failed with rc = %d and errno = %d\n", rc,errno); exit(1); } if (!plun) flags = CBLK_OPN_VIRT_LUN; if (!intrp_thds) flags |= CBLK_OPN_NO_INTRP_THREADS; id = cblk_open(dev, QD, O_RDWR, ext, flags); if (id == NULL_CHUNK_ID) { if (ENOSPC == errno) fprintf(stderr,"cblk_open: ENOSPC\n"); else if (ENODEV == errno) fprintf(stderr,"cblk_open: ENODEV\n"); else fprintf(stderr,"cblk_open: errno:%d\n",errno); cblk_term(NULL,0); exit(errno); } rc = cblk_get_lun_size(id, &nblks, 0); if (rc) { fprintf(stderr, "cblk_get_lun_size failed: errno: %d\n", errno); exit(errno); } if (!plun) { nblks = nblks > SET_NBLKS ? SET_NBLKS : nblks; rc = cblk_set_size(id, nblks, 0); if (rc) { fprintf(stderr, "cblk_set_size failed, errno: %d\n", errno); exit(errno); } } /*-------------------------------------------------------------------------- * alloc data for IO *------------------------------------------------------------------------*/ tags = malloc(QD*sizeof(int)); rbuf = malloc(QD*sizeof(uint8_t*)); wbuf = malloc(QD*sizeof(uint8_t*)); for (tag=0; tag<QD; tag++) { if ((rc=posix_memalign((void**)&(rbuf[tag]), _4K, _4K*nblocks))) { fprintf(stderr,"posix_memalign failed, size=%d, rc=%d\n", _4K*nblocks, rc); cblk_close(id,0); cblk_term(NULL,0); exit(0); } if ((rc=posix_memalign((void**)&(wbuf[tag]), _4K, _4K*nblocks))) { fprintf(stderr,"posix_memalign failed, size=%d, rc=%d\n", _4K*nblocks, rc); cblk_close(id,0); cblk_term(NULL,0); exit(0); } memset(wbuf[tag],0x79,_4K*nblocks); tags[tag] = tag; } /*-------------------------------------------------------------------------- * loop running IO until secs expire *------------------------------------------------------------------------*/ gettimeofday(&start, NULL); do { /* setup #read ops and #write ops to send before completing ops */ if (!RD && !WR) {RD=nRD; WR=100-RD;} /*---------------------------------------------------------------------- * send up to RD reads, as long as the queuedepth N is not max *--------------------------------------------------------------------*/ while (TIME && RD && N) { tag = tags[--N]; rc = cblk_aread(id, rbuf[tag], lba, nblocks, &tag, NULL, CBLK_ARW_WAIT_CMD_FLAGS | CBLK_ARW_USER_TAG_FLAG); if (0 == rc) {--RD; lba+=2; if (lba >= nblks) lba=cnt%2;} else if (EBUSY == errno) {++N; usleep(USLEEP); continue;} else {io_error(id,errno);} } /*---------------------------------------------------------------------- * send up to WR writes, as long as the queuedepth N is not max *--------------------------------------------------------------------*/ while (TIME && WR && N) { tag = tags[--N]; rc = cblk_awrite(id, wbuf[tag], lba, nblocks, &tag, NULL, CBLK_ARW_WAIT_CMD_FLAGS | CBLK_ARW_USER_TAG_FLAG); if (0 == rc) {--WR; lba+=2; if (lba >= nblks) lba=cnt%2;} else if (EBUSY == errno) {++N; usleep(USLEEP); continue;} else {io_error(id,errno);} } /* if the queuedepth is 1, don't immediately pound aresult */ if (QD==1) usleep(USLEEP); /*---------------------------------------------------------------------- * complete cmds until queue depth is QD-COMP *--------------------------------------------------------------------*/ while (N < COMP) { rtag=0; rc = cblk_aresult(id, &rtag, &status, CBLK_ARESULT_BLOCKING| CBLK_ARESULT_NEXT_TAG); if (rc == 0) {++pollN; usleep(USLEEP); continue;} else if (rc < 0) {io_error(id,errno);} ++cnt; tags[N++] = rtag; } /*---------------------------------------------------------------------- * at an interval which does not impact performance, check if secs * have expired, and randomize lba *--------------------------------------------------------------------*/ if (cnt > TI) { TI += TIME_INTERVAL; gettimeofday(&delta, NULL); if (delta.tv_sec - start.tv_sec >= nsecs) {TIME=0; COMP = QD;} lba = lrand48() % TIME_INTERVAL; } } while (TIME || QD-N); /*-------------------------------------------------------------------------- * print IO stats *------------------------------------------------------------------------*/ gettimeofday(&delta, NULL); esecs = ((float)((delta.tv_sec*mil + delta.tv_usec) - (start.tv_sec*mil + start.tv_usec))) / (float)mil; printf("d:%s r:%d q:%d s:%d p:%d n:%d i:%d pollN:%d mbps:%d iops:%d", dev, nRD, QD, nsecs, plun, nblocks, intrp_thds, pollN, (uint32_t)((float)((cnt*nblocks*4)/1024)/esecs), (uint32_t)((float)(cnt/esecs))); if (plun && nblocks > 1) printf(" 4k-iops:%d", (uint32_t)((float)(cnt*nblocks)/esecs)); printf("\n"); /*-------------------------------------------------------------------------- * cleanup *------------------------------------------------------------------------*/ for (cnt=0; cnt<QD; cnt++) { free(rbuf[cnt]); free(wbuf[cnt]); } free(rbuf); free(wbuf); cblk_close(id,0); cblk_term(NULL,0); return 0; }