TASK –
write a C program that tests HDDs internal and external and get the results of :-
sequential read speed, sequential write speed, random read speed, random write speed , IOPS score, all of that in relation to Blocksize. also outputs any delays
please use C to do so.
inputs:- the directory of the drive and the Blocksize to get the speed of read and write
/*
** Compile: gcc -o hddbench -O2 -march=x86-64 try2.c -pthread
** Run: hddbench <device> <timeout_seconds> [number_of_threads]
** Example: ./hddbench /dev/sda 30 4
*/
#define _LARGEFILE64_SOURCE
#ifndef _REENTRANT
#define _REENTRANT
#endif
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <signal.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#define BLOCKSIZE 512 //constant for block size
#define O_DIRECT 00040000
pthread_mutex_t muteks = PTHREAD_MUTEX_INITIALIZER; //Initilize the pthread mutex
//variable declarations
int count;
int TIMEOUT;
time_t start; //variable to keep a track of time
//offset values
off64_t maxoffset = 0;
off64_t minoffset = 249994674176000uLL;
int threads; //count of pthreads
//data structure to be used in the program
//variables are defined for id, filename, number of bytes, offset, buffer size and seeds.
typedef struct {
int id;
int fd;
int run;
char* filename;
unsigned int seed;
unsigned long long numbytes;
char* buffer;
int count;
off64_t maxoffset;
off64_t minoffset;
} parm;
parm *p;
//function to calculate the time taken
//here, the time_t is ended, and value is calculated and printed for pthreads
void done() {
int i;
time_t end;
time(&end);
if (end < start + TIMEOUT) {
printf(“.”);
alarm(1);
return;
}
for (i = 0; i < threads; i++) {
p[i].run = 0;
}
}
//here, the final report is generated and printed
void report() {
if (count) {
printf(“.\nResults IOPS Score: %d \n %.3f”
“Time:\n (%llu < offsets < %llu)\n”,
count / TIMEOUT, 1000.0 * TIMEOUT / count,
(unsigned long long)minoffset,
(unsigned long long)maxoffset);
}
exit(EXIT_SUCCESS); //for a clean exit
}
//function for error handling
void handle(const char *string, int error) {
if (error) {
perror(string);
exit(EXIT_FAILURE);//exit wwith error message
}
}
//function to seed the memory, set offsets, align the seeks according to block size
//pthread processes are unlocked for system process, and started
void* f(void *arg) {
int retval;
off64_t offset;
parm *p = (parm*)arg;
srand(p->seed);
/* wait for all processes */
pthread_mutex_lock(&muteks);
pthread_mutex_unlock(&muteks);
while (p->run) {
offset = (off64_t) ( (unsigned long long) (p->numbytes *
(rand_r(&(p->seed)) / (RAND_MAX + 1.0) )));
/* do blocksize aligned seeks */
offset = offset & (~((off64_t) 0) & (~(BLOCKSIZE-1))) ;
/* printf(“%d %x\n”, p->id, (unsigned long long )offset); */ //used for debugging
//read/write process done, handled using system header file
retval = lseek64(p->fd, offset, SEEK_SET);
handle(“lseek64”, retval == (off64_t) -1); //for error handling
retval = read(p->fd, p->buffer, BLOCKSIZE);
handle(“read”, retval < 0);//for error handling
p->count++;
//check offset
if (offset > p->maxoffset) {
p->maxoffset = offset;
} else if (offset < p->minoffset) {
p->minoffset = offset;
}
}
return NULL;
}
//main function
int main(int argc, char **argv) {
int fd, retval;
int physical_sector_size = 0;//physical sector size initialization
size_t logical_sector_size = 0ULL; //logical sector size initialization
unsigned long long numblocks, numbytes; //variables for number of blocks and bytes
unsigned long long ull;
unsigned long ul;
pthread_t *t_id; //pthread ID
pthread_attr_t pthread_custom_attr; //pthread attribute setup
int i;
setvbuf(stdout, NULL, _IONBF, 0);
//usage argument help prompt if input is incorrect
if (!(argc == 3 || argc == 4)) {
printf(“Usage: %s device seconds [threads]\n”, argv[0]);
exit(1);
}
TIMEOUT = atoi(argv[2]); //getting the timeut value from user input
//starting the thread
threads = 1;
if (argc == 4) {
threads = atoi(argv[3]); //starting thread according to user input
}
//open file for read only for operation
fd = open(argv[1], O_RDONLY | O_LARGEFILE | O_DIRECT);
handle(“open”, fd < 0);//for error handling
//ioctl operation of opened file using system header file, according to system procesor (32 bit or 64 bit)
#ifdef BLKGETSIZE64
retval = ioctl(fd, BLKGETSIZE64, &ull); //for 64 bit
numbytes = (unsigned long long)ull;
#else
retval = ioctl(fd, BLKGETSIZE, &ul); //for 32 bit
numbytes = (unsigned long long)ul;
#endif
//get the desired values from ioctl and store in specific variables
handle(“ioctl”, retval == -1);//for error handling
retval = ioctl(fd, BLKBSZGET, &logical_sector_size);
handle(“ioctl”, retval == -1 && logical_sector_size > 0);//for error handling
retval = ioctl(fd, BLKSSZGET, &physical_sector_size);
handle(“ioctl”, retval == -1 && physical_sector_size > 0);//for error handling
numblocks = ((unsigned long long) numbytes) /
(unsigned long long)BLOCKSIZE;
//print result of benchmarking
printf(“Benchmarking %s\n[%llu blocks, %llu bytes,\n In Format: Sequential Read and Write, Random Read and Write\n”
“%llu GBpers, %llu MBpers, %llu GiBpers, %llu MiBpers]\n”,
argv[1], numblocks, numbytes,
numbytes/(1024uLL*1024uLL*1024uLL*TIMEOUT),
numbytes / (1024uLL*1024uLL*TIMEOUT),
numbytes/(1000uLL*1000uLL*1000uLL*TIMEOUT),
numbytes / (1000uLL*1000uLL*TIMEOUT));
printf(“Delay %d seconds\n”, TIMEOUT);
//start pthread with memory allocation
t_id = (pthread_t *)malloc(threads*sizeof(pthread_t)); //memory allocation
handle(“malloc”, t_id == NULL);//for error handling
pthread_attr_init(&pthread_custom_attr); //attribute initialization
p = (parm *)malloc(sizeof(parm)*threads);
handle(“malloc”, p == NULL);//for error handling
//start timer for timed test
time(&start);
//pthread operation
pthread_mutex_lock(&muteks);
srand((unsigned int)start*(unsigned int)getpid());
//pthread creation loop for all threads (user input)
for (i = 0; i < threads; i++) {
p[i].id = i;
p[i].filename = argv[1]; //filename from user input
p[i].seed = rand()+i;
p[i].fd = dup(fd);
handle(“dup”, p[i].fd < 0);//for error handling
p[i].buffer = (char *) memalign(512*8, sizeof(char)*BLOCKSIZE);
/* printf(“%x\n”, (int)(&(p[i].buffer))); */ //used for debugging
p[i].numbytes = numbytes;
handle(“malloc”, p[i].buffer == NULL);//for error handling
p[i].run = 1;
p[i].count = 0;
p[i].minoffset = minoffset;
p[i].maxoffset = maxoffset;
retval = pthread_create(&(t_id[i]), NULL, f, (void*)(p+i));
handle(“pthread_create”, retval != 0);
}
//delay
sleep(1);
time(&start);
signal(SIGALRM, &done);
alarm(1);
pthread_mutex_unlock(&muteks);
//join threads
for (i = 0; i < threads; i++) {
pthread_join(t_id[i], NULL);
}
//get offset values (sorting)
for (i = 0; i < threads; i++) {
count += p[i].count;
if (p[i].maxoffset > maxoffset) {
maxoffset = p[i].maxoffset;
}
if (p[i].minoffset < minoffset) {
minoffset = p[i].minoffset;
}
}
//report result
report();
/* notreached */
return 0;
}