Last active
August 29, 2015 14:08
-
-
Save sora/0948d6dc131cc5c4e09f to your computer and use it in GitHub Desktop.
ring test
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <stdbool.h> | |
| #include <time.h> | |
| /* | |
| * memory management | |
| * | |
| * a b c d e | |
| * |---------+-------------+-----------|-------| | |
| * | |
| * a: ring.start (start address) | |
| * b: ring.read (read pointer) | |
| * c: ring:write (write pointer) | |
| * d: ring.end (end address) | |
| * e: (malloc size + MAX_PKT_SIZE) | |
| * | |
| * ring.size := d - a | |
| * ring.mask := ring.size - 1 | |
| */ | |
| /* | |
| * Packet format | |
| * 0 16 (bit) | |
| * +-----------------------+ | |
| * | Magic code (0x3776) | | |
| * +-----------------------+ | |
| * | Frame length | | |
| * +-----------------------+ | |
| * | | | |
| * | Ethernet frame | | |
| * | | | |
| * +-----------------------+ | |
| */ | |
| typedef unsigned char uint8_t; | |
| typedef unsigned short uint16_t; | |
| typedef unsigned int uint32_t; | |
| uint8_t *buf; | |
| struct ep_ring { | |
| volatile uint8_t *write; | |
| volatile uint8_t *read; | |
| uint8_t *end; | |
| uint8_t *start; | |
| uint32_t size; | |
| uint32_t mask; | |
| } static ring; | |
| #define EP_MAGIC 0x3776 | |
| #define EP_HDR_SIZE 4 | |
| #define BUF_SIZE (1*1024*1024) // 2^n | |
| #define MAX_PKT_SIZE 9000 | |
| #define MIN_PKT_SIZE 40 | |
| #define RING_ALMOST_FULL (MAX_PKT_SIZE*2) | |
| #define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1) | |
| #define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) | |
| #define DUMP \ | |
| printf("sz: %04X, st: %6p, ed: %6p, wr: %6p, rd: %6p, ", \ | |
| ring.size, ring.start, ring.end, ring.write, ring.read); \ | |
| printf("cnt: %08X, free_cnt: %08X, empty: %X, almost_full: %X\n", \ | |
| ring_count(&ring), ring_free_count(&ring), ring_empty(&ring), \ | |
| ring_almost_full(&ring)) | |
| static inline uint32_t ring_count(const struct ep_ring *r) | |
| { | |
| return ((r->write - r->read) & r->mask); | |
| } | |
| static inline uint32_t ring_free_count(const struct ep_ring *r) | |
| { | |
| return ((r->read - r->write - 1) & r->mask); | |
| } | |
| static inline bool ring_empty(const struct ep_ring *r) | |
| { | |
| return !!(r->read == r->write); | |
| } | |
| static inline bool ring_almost_full(const struct ep_ring *r) | |
| { | |
| return !!(ring_free_count(r) < RING_ALMOST_FULL); | |
| } | |
| static inline void ring_write_next(struct ep_ring *r, uint32_t size) | |
| { | |
| r->write += size; | |
| if (r->write > r->end) { | |
| r->write = r->start; | |
| } | |
| } | |
| static inline void ring_read_next(struct ep_ring *r, uint32_t size) | |
| { | |
| r->read += size; | |
| if (r->read > r->end) { | |
| r->read = r->start; | |
| } | |
| } | |
| static inline void ring_write_next_aligned(struct ep_ring *r, uint32_t size) | |
| { | |
| r->write += ALIGN(size, 4); | |
| if (r->write > r->end) { | |
| r->write = r->start; | |
| } | |
| } | |
| static inline void ring_read_next_aligned(struct ep_ring *r, uint32_t size) | |
| { | |
| r->read += ALIGN(size, 4); | |
| if (r->read > r->end) { | |
| r->read = r->start; | |
| } | |
| } | |
| static inline uint16_t get_frame_len(void) | |
| { | |
| return rand() % 0x3F + 40; // tekitou na size | |
| } | |
| static inline uint32_t set_data(struct ep_ring *r) | |
| { | |
| uint16_t len = get_frame_len(); | |
| int i; | |
| *(uint16_t *)&r->write[0] = 0x3776; // magic | |
| *(uint16_t *)&r->write[2] = len; // frame length | |
| for(i = 0; i < len; i++) { // dummy packet data | |
| r->write[EP_HDR_SIZE+i] = i; | |
| } | |
| return (EP_HDR_SIZE + len); | |
| } | |
| static inline uint32_t read_data(struct ep_ring *r) | |
| { | |
| uint16_t magic, len; | |
| uint8_t pkt[MAX_PKT_SIZE]; | |
| magic = *(uint16_t *)&r->read[0]; | |
| if (magic != EP_MAGIC) { | |
| printf("magic code error: %X\n", magic); | |
| return 0; | |
| } | |
| len = *(uint16_t *)&r->read[2]; | |
| if (len < MIN_PKT_SIZE || len > MAX_PKT_SIZE) { | |
| printf("packet size error: %X\n", len); | |
| return 0; | |
| } | |
| // dummy read (copy packet from ring to tmpbuf) | |
| memcpy(pkt, (uint8_t *)r->read, (EP_HDR_SIZE+len)); | |
| return (EP_HDR_SIZE + len); | |
| } | |
| static void init() | |
| { | |
| if (buf != NULL) | |
| free(buf); | |
| buf = malloc(BUF_SIZE+MAX_PKT_SIZE); | |
| ring.start = &buf[0]; | |
| ring.size = BUF_SIZE; | |
| ring.mask = ring.size - 1; | |
| ring.end = ring.start + ring.size - 1; | |
| ring.write = ring.start; | |
| ring.read = ring.start; | |
| } | |
| int main(void) | |
| { | |
| uint32_t size1, size2; | |
| int i; | |
| srand((unsigned)time(NULL)); | |
| init(); | |
| DUMP; | |
| /* test 1: overwriting (ring_write_next_aligned, ring_read_next_aligned) */ | |
| printf("\n-------------test 1\n"); | |
| init(); | |
| for (i = 0; i < 1000000; i++) { | |
| size1 = set_data(&ring); | |
| ring_write_next_aligned(&ring, size1); | |
| size2 = read_data(&ring); | |
| ring_read_next_aligned(&ring, size2); | |
| if (size1 != size2) { | |
| printf("size1 != size2\n"); | |
| exit(1); | |
| } | |
| } | |
| printf("---------------Done.\n"); | |
| /* test 2: overwriting (ring_write_next, ring_read_next) */ | |
| printf("\n-------------test 2\n"); | |
| init(); | |
| for (i = 0; i < 1000000; i++) { | |
| size1 = set_data(&ring); | |
| ring_write_next(&ring, size1); | |
| size2 = read_data(&ring); | |
| ring_read_next(&ring, size2); | |
| if (size1 != size2) { | |
| printf("size1 != size2\n"); | |
| exit(1); | |
| } | |
| } | |
| printf("---------------Done.\n"); | |
| /* test 3: ring_almost_full, ring_empty */ | |
| printf("\n-------------test 3\n"); | |
| init(); | |
| DUMP; | |
| for(i = 0; i <= 100000; i++) { | |
| if (!ring_almost_full(&ring)) { | |
| size1 = set_data(&ring); | |
| ring_write_next_aligned(&ring, size1); | |
| } else { | |
| break; | |
| } | |
| } | |
| DUMP; | |
| for(i = 0; i <= 100000; i++) { | |
| if (!ring_empty(&ring)) { | |
| size1 = read_data(&ring); | |
| ring_read_next_aligned(&ring, size1); | |
| } else { | |
| break; | |
| } | |
| } | |
| DUMP; | |
| printf("---------------Done.\n"); | |
| if (buf != NULL) | |
| free(buf); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment