source: benchmark/io/io_uring.h @ ece0e80

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since ece0e80 was 1c49dc5, checked in by Thierry Delisle <tdelisle@…>, 4 years ago

Updated batch benchmark to factor io_uring setup

  • Property mode set to 100644
File size: 5.2 KB
Line 
1extern "C" {
2        #ifndef _GNU_SOURCE         /* See feature_test_macros(7) */
3        #define _GNU_SOURCE         /* See feature_test_macros(7) */
4        #endif
5        #include <errno.h>
6        #include <stdio.h>
7        #include <stdint.h>
8        #include <stdlib.h>
9        #include <string.h>
10        #include <unistd.h>
11        #include <sys/mman.h>
12        #include <sys/syscall.h>
13        #include <sys/uio.h>
14        #include <fcntl.h>
15
16        #include <linux/io_uring.h>
17}
18
19# ifndef __NR_io_uring_setup
20#  define __NR_io_uring_setup           425
21# endif
22# ifndef __NR_io_uring_enter
23#  define __NR_io_uring_enter           426
24# endif
25# ifndef __NR_io_uring_register
26#  define __NR_io_uring_register        427
27# endif
28
29struct io_uring_sq {
30        // Head and tail of the ring (associated with array)
31        volatile uint32_t * head;
32        volatile uint32_t * tail;
33
34        // The actual kernel ring which uses head/tail
35        // indexes into the sqes arrays
36        uint32_t * array;
37
38        // number of entries and mask to go with it
39        const uint32_t * num;
40        const uint32_t * mask;
41
42        // Submission flags (Not sure what for)
43        uint32_t * flags;
44
45        // number of sqes not submitted (whatever that means)
46        uint32_t * dropped;
47
48        // Like head/tail but not seen by the kernel
49        volatile uint32_t alloc;
50
51        // A buffer of sqes (not the actual ring)
52        struct io_uring_sqe * sqes;
53
54        // The location and size of the mmaped area
55        void * ring_ptr;
56        size_t ring_sz;
57};
58
59struct io_uring_cq {
60        // Head and tail of the ring
61        volatile uint32_t * head;
62        volatile uint32_t * tail;
63
64        // number of entries and mask to go with it
65        const uint32_t * mask;
66        const uint32_t * num;
67
68        // number of cqes not submitted (whatever that means)
69        uint32_t * overflow;
70
71        // the kernel ring
72        struct io_uring_cqe * cqes;
73
74        // The location and size of the mmaped area
75        void * ring_ptr;
76        size_t ring_sz;
77};
78
79struct io_ring {
80        struct io_uring_sq submit_q;
81        struct io_uring_cq completion_q;
82        uint32_t flags;
83        int fd;
84};
85
86struct IO_singleton {
87        io_ring io;
88};
89
90IO_singleton self;
91
92void init_uring(uint32_t nentries) {
93      // Step 1 : call to setup
94        struct io_uring_params params;
95        memset(&params, 0, sizeof(params));
96        // params.flags = IORING_SETUP_SQPOLL;
97
98        int fd = syscall(__NR_io_uring_setup, nentries, &params );
99        if(fd < 0) {
100                fprintf(stderr, "KERNEL ERROR: IO_URING SETUP - %s\n", strerror(errno));
101                abort();
102        }
103
104        // Step 2 : mmap result
105        memset(&self.io, 0, sizeof(struct io_ring));
106        struct io_uring_sq & sq = self.io.submit_q;
107        struct io_uring_cq & cq = self.io.completion_q;
108
109        // calculate the right ring size
110        sq.ring_sz = params.sq_off.array + (params.sq_entries * sizeof(unsigned)           );
111        cq.ring_sz = params.cq_off.cqes  + (params.cq_entries * sizeof(struct io_uring_cqe));
112
113        // Requires features
114        // // adjust the size according to the parameters
115        // if ((params.features & IORING_FEAT_SINGLE_MMAP) != 0) {
116        //      cq->ring_sz = sq->ring_sz = max(cq->ring_sz, sq->ring_sz);
117        // }
118
119        // mmap the Submit Queue into existence
120        sq.ring_ptr = mmap(0, sq.ring_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, fd, IORING_OFF_SQ_RING);
121        if (sq.ring_ptr == (void*)MAP_FAILED) {
122                fprintf(stderr, "KERNEL ERROR: IO_URING MMAP1 - %s\n", strerror(errno));
123                abort();
124        }
125
126        // mmap the Completion Queue into existence (may or may not be needed)
127        // Requires features
128        // if ((params.features & IORING_FEAT_SINGLE_MMAP) != 0) {
129        //      cq->ring_ptr = sq->ring_ptr;
130        // }
131        // else {
132                // We need multiple call to MMAP
133                cq.ring_ptr = mmap(0, cq.ring_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, fd, IORING_OFF_CQ_RING);
134                if (cq.ring_ptr == (void*)MAP_FAILED) {
135                        munmap(sq.ring_ptr, sq.ring_sz);
136                        fprintf(stderr, "KERNEL ERROR: IO_URING MMAP2 - %s\n", strerror(errno));
137                        abort();
138                }
139        // }
140
141        // mmap the submit queue entries
142        size_t size = params.sq_entries * sizeof(struct io_uring_sqe);
143        sq.sqes = (struct io_uring_sqe *)mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, fd, IORING_OFF_SQES);
144        if (sq.sqes == (struct io_uring_sqe *)MAP_FAILED) {
145                munmap(sq.ring_ptr, sq.ring_sz);
146                if (cq.ring_ptr != sq.ring_ptr) munmap(cq.ring_ptr, cq.ring_sz);
147                fprintf(stderr, "KERNEL ERROR: IO_URING MMAP3 - %s\n", strerror(errno));
148                abort();
149        }
150
151        // Get the pointers from the kernel to fill the structure
152        // submit queue
153        sq.head    = (volatile uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.head);
154        sq.tail    = (volatile uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.tail);
155        sq.mask    = (   const uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_mask);
156        sq.num     = (   const uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_entries);
157        sq.flags   = (         uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.flags);
158        sq.dropped = (         uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.dropped);
159        sq.array   = (         uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.array);
160        sq.alloc = *sq.tail;
161
162        // completion queue
163        cq.head     = (volatile uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.head);
164        cq.tail     = (volatile uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.tail);
165        cq.mask     = (   const uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.ring_mask);
166        cq.num      = (   const uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.ring_entries);
167        cq.overflow = (         uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.overflow);
168        cq.cqes   = (struct io_uring_cqe *)(((intptr_t)cq.ring_ptr) + params.cq_off.cqes);
169
170        self.io.fd = fd;
171}
Note: See TracBrowser for help on using the repository browser.