Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • benchmark/io/batch-readv.c

    r1c49dc5 rc33ed65  
    11// Program to test the optimial batchsize in a single threaded process
    22extern "C" {
     3        #ifndef _GNU_SOURCE         /* See feature_test_macros(7) */
     4        #define _GNU_SOURCE         /* See feature_test_macros(7) */
     5        #endif
     6        #include <errno.h>
     7        #include <stdio.h>
     8        #include <stdint.h>
     9        #include <stdlib.h>
     10        #include <string.h>
     11        #include <locale.h>
    312        #include <getopt.h>
    4         #include <locale.h>
     13        #include <unistd.h>
     14        #include <sys/mman.h>
     15        #include <sys/syscall.h>
     16        #include <sys/uio.h>
     17        #include <fcntl.h>
    518        #include <time.h>                                                                               // timespec
    619        #include <sys/time.h>                                                                   // timeval
     20
     21        #include <linux/io_uring.h>
    722}
    823
     24
    925enum { TIMEGRAN = 1000000000LL };                                       // nanosecond granularity, except for timeval
    1026
    1127#include <omp.h>
    1228
    13 #include "io_uring.h"
    14 
    15 
     29# ifndef __NR_io_uring_setup
     30#  define __NR_io_uring_setup           425
     31# endif
     32# ifndef __NR_io_uring_enter
     33#  define __NR_io_uring_enter           426
     34# endif
     35# ifndef __NR_io_uring_register
     36#  define __NR_io_uring_register        427
     37# endif
     38
     39struct io_uring_sq {
     40        // Head and tail of the ring (associated with array)
     41        volatile uint32_t * head;
     42        volatile uint32_t * tail;
     43
     44        // The actual kernel ring which uses head/tail
     45        // indexes into the sqes arrays
     46        uint32_t * array;
     47
     48        // number of entries and mask to go with it
     49        const uint32_t * num;
     50        const uint32_t * mask;
     51
     52        // Submission flags (Not sure what for)
     53        uint32_t * flags;
     54
     55        // number of sqes not submitted (whatever that means)
     56        uint32_t * dropped;
     57
     58        // Like head/tail but not seen by the kernel
     59        volatile uint32_t alloc;
     60
     61        // A buffer of sqes (not the actual ring)
     62        struct io_uring_sqe * sqes;
     63
     64        // The location and size of the mmaped area
     65        void * ring_ptr;
     66        size_t ring_sz;
     67};
     68
     69struct io_uring_cq {
     70        // Head and tail of the ring
     71        volatile uint32_t * head;
     72        volatile uint32_t * tail;
     73
     74        // number of entries and mask to go with it
     75        const uint32_t * mask;
     76        const uint32_t * num;
     77
     78        // number of cqes not submitted (whatever that means)
     79        uint32_t * overflow;
     80
     81        // the kernel ring
     82        struct io_uring_cqe * cqes;
     83
     84        // The location and size of the mmaped area
     85        void * ring_ptr;
     86        size_t ring_sz;
     87};
     88
     89struct io_ring {
     90        struct io_uring_sq submit_q;
     91        struct io_uring_cq completion_q;
     92        uint32_t flags;
     93        int fd;
     94};
     95
     96struct fred {
     97        io_ring io;
     98};
     99
     100fred self;
    16101int myfd;
    17102
     
    132217        myfd = open(__FILE__, 0);
    133218
    134         init_uring(2048);
     219        // Step 1 : call to setup
     220        struct io_uring_params params;
     221        memset(&params, 0, sizeof(params));
     222
     223        uint32_t nentries = 2048;
     224
     225        int fd = syscall(__NR_io_uring_setup, nentries, &params );
     226        if(fd < 0) {
     227                fprintf(stderr, "KERNEL ERROR: IO_URING SETUP - %s\n", strerror(errno));
     228                abort();
     229        }
     230
     231        // Step 2 : mmap result
     232        memset(&self.io, 0, sizeof(struct io_ring));
     233        struct io_uring_sq & sq = self.io.submit_q;
     234        struct io_uring_cq & cq = self.io.completion_q;
     235
     236        // calculate the right ring size
     237        sq.ring_sz = params.sq_off.array + (params.sq_entries * sizeof(unsigned)           );
     238        cq.ring_sz = params.cq_off.cqes  + (params.cq_entries * sizeof(struct io_uring_cqe));
     239
     240        // Requires features
     241        // // adjust the size according to the parameters
     242        // if ((params.features & IORING_FEAT_SINGLE_MMAP) != 0) {
     243        //      cq->ring_sz = sq->ring_sz = max(cq->ring_sz, sq->ring_sz);
     244        // }
     245
     246        // mmap the Submit Queue into existence
     247        sq.ring_ptr = mmap(0, sq.ring_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, fd, IORING_OFF_SQ_RING);
     248        if (sq.ring_ptr == (void*)MAP_FAILED) {
     249                fprintf(stderr, "KERNEL ERROR: IO_URING MMAP1 - %s\n", strerror(errno));
     250                abort();
     251        }
     252
     253        // mmap the Completion Queue into existence (may or may not be needed)
     254        // Requires features
     255        // if ((params.features & IORING_FEAT_SINGLE_MMAP) != 0) {
     256        //      cq->ring_ptr = sq->ring_ptr;
     257        // }
     258        // else {
     259                // We need multiple call to MMAP
     260                cq.ring_ptr = mmap(0, cq.ring_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, fd, IORING_OFF_CQ_RING);
     261                if (cq.ring_ptr == (void*)MAP_FAILED) {
     262                        munmap(sq.ring_ptr, sq.ring_sz);
     263                        fprintf(stderr, "KERNEL ERROR: IO_URING MMAP2 - %s\n", strerror(errno));
     264                        abort();
     265                }
     266        // }
     267
     268        // mmap the submit queue entries
     269        size_t size = params.sq_entries * sizeof(struct io_uring_sqe);
     270        sq.sqes = (struct io_uring_sqe *)mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, fd, IORING_OFF_SQES);
     271        if (sq.sqes == (struct io_uring_sqe *)MAP_FAILED) {
     272                munmap(sq.ring_ptr, sq.ring_sz);
     273                if (cq.ring_ptr != sq.ring_ptr) munmap(cq.ring_ptr, cq.ring_sz);
     274                fprintf(stderr, "KERNEL ERROR: IO_URING MMAP3 - %s\n", strerror(errno));
     275                abort();
     276        }
     277
     278        // Get the pointers from the kernel to fill the structure
     279        // submit queue
     280        sq.head    = (volatile uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.head);
     281        sq.tail    = (volatile uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.tail);
     282        sq.mask    = (   const uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_mask);
     283        sq.num     = (   const uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_entries);
     284        sq.flags   = (         uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.flags);
     285        sq.dropped = (         uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.dropped);
     286        sq.array   = (         uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.array);
     287        sq.alloc = *sq.tail;
     288
     289        // completion queue
     290        cq.head     = (volatile uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.head);
     291        cq.tail     = (volatile uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.tail);
     292        cq.mask     = (   const uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.ring_mask);
     293        cq.num      = (   const uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.ring_entries);
     294        cq.overflow = (         uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.overflow);
     295        cq.cqes   = (struct io_uring_cqe *)(((intptr_t)cq.ring_ptr) + params.cq_off.cqes);
     296
     297        self.io.fd = fd;
    135298
    136299        // Allocate the sqe
     
    181344
    182345        printf("Took %'ld ms\n", to_miliseconds(end - start));
    183         printf("Submitted        %'llu\n", submits);
    184         printf("Completed        %'llu\n", completes);
    185         printf("Submitted / sec  %'.f\n", submits   / to_fseconds(end - start));
    186         printf("Completed / sec  %'.f\n", completes / to_fseconds(end - start));
    187         printf("ns per Submitted %'.f\n", 1000000000.0 * to_fseconds(end - start) / (submits   / batch) );
    188         printf("ns per Completed %'.f\n", 1000000000.0 * to_fseconds(end - start) / (completes / batch) );
     346        printf("Submitted       %'llu\n", submits);
     347        printf("Completed       %'llu\n", completes);
     348        printf("Submitted / sec %'.f\n", submits   / to_fseconds(end - start));
     349        printf("Completed / sec %'.f\n", completes / to_fseconds(end - start));
    189350}
Note: See TracChangeset for help on using the changeset viewer.