Skip to content

Instantly share code, notes, and snippets.

@sora
Last active August 29, 2015 14:08
Show Gist options
  • Select an option

  • Save sora/0948d6dc131cc5c4e09f to your computer and use it in GitHub Desktop.

Select an option

Save sora/0948d6dc131cc5c4e09f to your computer and use it in GitHub Desktop.
ring test
#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