Friday 7 September 2018

Program to demonstrate using O_DIRECT option in file operations and writev() call

Program

/* Below program showcases the use of O_DIRECT file option. Also, demonstrates writev() use */

#include <iostream>
#include <fcntl.h>    /* For O_RDWR */
#include <unistd.h>   /* For open(), creat() */
#include <string.h>   /* For strlen() */
#include <malloc.h>   /* For memalign() */
#include <sys/uio.h>  /* For struct iovec */
#include <stdint.h>   /* For datatypes */

#define O_DIRECT_ENABLE 1
using namespace std;

int main(int argc, char *argv[])
{
        if (argc != 3) {
            cout << "run: ./<prog_binary_name> <input_file_name> <outputFileName>"<<endl;
            return 0;
        }

        int fd_out, fd_in, ret;
#if O_DIRECT_ENABLE
        fd_out = open(argv[2], O_CREAT | O_WRONLY | O_TRUNC | O_APPEND | O_DIRECT, S_IRWXG | S_IRWXU);
        fd_in = open(argv[1], O_RDONLY | O_DIRECT);
#else
        fd_out = open(argv[2], O_CREAT | O_WRONLY | O_TRUNC | O_APPEND, S_IRWXG | S_IRWXU);
        fd_in = open(argv[1], O_RDONLY);
#endif
        if(!fd_out || !fd_in) {
            cout << "Unable to open one of the given files"<<endl;
            return 0;
        }
        char file_data1[4096];
        char *file_data2 = (char*)memalign(4096, 4096);

        /* Below vector declaration won't compile since aligned_allocator defined in xilinx lib.
        vector<uint8_t, aligned_allocator<uint8_t>>  file_data3(4096);
        read(fd_in, file_data3, 4096);
        int file_data3_len = strlen(file_data2);
        */

        read(fd_in, file_data1, 4096); /* not work with O_DIRECT option, it returns 0 bytes */
        int file_data1_len = strlen(file_data1);

        /* works with O_DIRECT since memalign is used for creating the buffer */
        read(fd_in, file_data2, 4096);
        int file_data2_len = strlen(file_data2);

        cout<<"read_4k_nonMemAlign, read_4k_memAlign: "<<file_data1_len<<", "<<file_data2_len<<endl;

        char *data = (char*)malloc(sizeof(char)* 4096);
        strcpy(data, "salkfalksfjslfnsdlfksdklfnsldkfslkdfskldfjskldngslkdgjsdngslkdgskldglksdglksdglsdglsdgklsdfgdfkg");
        int data_len =  strlen(data);

        char *data2 = (char*)memalign(4096, 4096);
        strcpy(data2, "12345678912345678912345678912345678912345678912345678912345678912345678912345678912345678912345");
        int data2_len =  strlen(data2);

        ret = write(fd_out, data, data_len); /* fails with -1 if O_DIRECT enabled */
        cout<<"data(malloc) write ret: "<<ret<<endl;

        ret = write(fd_out, data2, 4096); /* write() works with O_DIRECT since data buffer is memaligned and given size is 4096 also aligned */
        cout<<"data2(memalign) write ret: "<<ret<<endl;

        ret = lseek(fd_out, data_len, SEEK_SET);
        cout<<"seek ret1: "<<ret<<endl;
        ret = write(fd_out, file_data2, 4096); /* write() works with O_DIRECT since buf is memaligned */
        cout<<"write_ret2: "<<ret<<endl;

        ret = lseek(fd_out, 0, SEEK_CUR);
        cout<<"seek ret2: "<<ret<<endl;

        struct iovec    iov[4];
        iov[0].iov_base = (char *) file_data2;
        iov[0].iov_len  = 4096;
        iov[1].iov_base = (char *) data2;
        iov[1].iov_len  = 4096;//data2_len;
        iov[2].iov_base = (char *) file_data1;
        iov[2].iov_len  = file_data1_len;
        iov[3].iov_base = (char *) data;
        iov[3].iov_len  = data_len;

        int total_len = iov[0].iov_len + iov[1].iov_len + iov[2].iov_len + iov[3].iov_len;
        cout<<"total_len: "<<total_len<<" {"<<data_len<<", "<<data2_len<<", "<<file_data1_len<<", "<<file_data2_len<<"}"<<endl;

/*        ret = writev(fd_out, &iov[0], 4); */
        ret = writev(fd_out, &iov[0], 2);
        cout<<"writev ret: "<<ret<<endl; /*writev() works fine when O_DIRECT flag removed in file open option. */
        ret = lseek(fd_out, 4096+data2_len, SEEK_SET);
        cout<<"seek ret: "<<ret<<endl;
        ret = write(fd_out, data, 4096); /* write() works with O_DIRECT since buf is memaligned */
        cout<<"ret: "<<ret<<endl;
        close(fd_out);
        close(fd_in);
        return 0;
}

Program Output

$g++ odirect_writev_prog.cpp -o odirect_writev_prog
$ ./odirect_writev_prog input.txt output_fd.txt
read_4k_nonMemAlign, read_4k_memAlign: 0, 4096
data(malloc) write ret: -1
data2(memalign) write ret: 4096
seek ret1: 96
write_ret2: -1
seek ret2: 96
total_len: 8288 {96, 95, 0, 4096}
writev ret: -1
seek ret: 4191
ret: -1

No comments:

Post a Comment

You might also like

Related Posts Plugin for WordPress, Blogger...