194 lines
5.1 KiB
C++
194 lines
5.1 KiB
C++
#include <pthread.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <stddef.h>
|
|
#include <getopt.h>
|
|
#include <pthread.h>
|
|
#include <gtest/gtest.h>
|
|
#include "stellar/monitor.h"
|
|
#include "monitor_ringbuf.h"
|
|
|
|
#define TOTAL_TEST_NUM 100000
|
|
#define BATCH_NUM 10
|
|
#define MAX_PAYLOAD_LEN 2048
|
|
#define MAGIC_NUM 0x1234ABCD
|
|
static struct monitor_ringbuf_wrap *rbf_ctop;
|
|
static struct monitor_ringbuf_wrap *rbf_ptoc;
|
|
static const size_t ringbuf_size = MAX_PAYLOAD_LEN * 1024;
|
|
|
|
static unsigned long long ctop_producer_len = 0, ctop_consumer_len = 0;
|
|
static unsigned long long ptoc_producer_len = 0, ptoc_consumer_len = 0;
|
|
|
|
struct test_ringbuf_data
|
|
{
|
|
long long magic;
|
|
long long block_len; /* total length, include this header and paylaod */
|
|
char payload[MAX_PAYLOAD_LEN];
|
|
};
|
|
|
|
static int test_ringbuf_push_mode = 0; /* 0: easy push, 1: push by offset */
|
|
|
|
static int ringbuf_push(int tid, struct monitor_ringbuf_wrap *rbf, struct test_ringbuf_data *payload)
|
|
{
|
|
int ret = 0;
|
|
if (0 == test_ringbuf_push_mode)
|
|
{
|
|
ret = stm_ringbuf_easy_push(tid, rbf, payload, payload->block_len);
|
|
}
|
|
else
|
|
{
|
|
ssize_t offset = stm_ringbuf_stream_start(tid, rbf, payload->block_len);
|
|
if (offset < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
stm_ringbuf_stream_append(tid, rbf, offset++, payload++, 1);
|
|
usleep(1);
|
|
stm_ringbuf_stream_append(tid, rbf, offset++, payload++, 1);
|
|
usleep(10);
|
|
stm_ringbuf_stream_append(tid, rbf, offset++, payload++, 1);
|
|
usleep(100);
|
|
stm_ringbuf_stream_append(tid, rbf, offset, payload, payload->block_len - 3);
|
|
stm_ringbuf_stream_finish(tid, rbf);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int ringbuf_producer(int tid, struct monitor_ringbuf_wrap *rbf, int batch)
|
|
{
|
|
struct test_ringbuf_data t;
|
|
for (int i = 0; i < batch; i++)
|
|
{
|
|
t.magic = MAGIC_NUM;
|
|
t.block_len = rand() % (MAX_PAYLOAD_LEN - sizeof(long long) * 2) + sizeof(long long) * 2; /* variable-length */
|
|
while (ringbuf_push(tid, rbf, &t) < 0)
|
|
{
|
|
usleep(1);
|
|
}
|
|
if (rbf == rbf_ctop)
|
|
{
|
|
ctop_producer_len += t.block_len;
|
|
}
|
|
else
|
|
{
|
|
ptoc_producer_len += t.block_len;
|
|
}
|
|
}
|
|
return batch;
|
|
}
|
|
|
|
static int ringbuf_customer(int tid, struct monitor_ringbuf_wrap *rbf, int batch)
|
|
{
|
|
(void)tid;
|
|
void *data;
|
|
size_t pop_len;
|
|
for (int i = 0; i < batch; i++)
|
|
{
|
|
while ((data = stm_ringbuf_pop(rbf, &pop_len)) == NULL)
|
|
{
|
|
;
|
|
}
|
|
|
|
struct test_ringbuf_data *td = (struct test_ringbuf_data *)data;
|
|
if (td->magic != MAGIC_NUM)
|
|
{
|
|
stm_ringbuf_release(rbf, pop_len); /* maybe lost many messages */
|
|
return 0;
|
|
}
|
|
td->magic = random();
|
|
size_t rel_len = td->block_len;
|
|
if (rbf == rbf_ctop)
|
|
{
|
|
ctop_consumer_len += td->block_len;
|
|
}
|
|
else
|
|
{
|
|
ptoc_consumer_len += td->block_len;
|
|
}
|
|
td->block_len = 0;
|
|
stm_ringbuf_release(rbf, rel_len);
|
|
}
|
|
return batch;
|
|
}
|
|
|
|
static void *producer_thread(void *arg)
|
|
{
|
|
(void)arg;
|
|
int ctop_num = 0;
|
|
int ptoc_num = 0;
|
|
for (int i = 0; i < TOTAL_TEST_NUM; i++)
|
|
{
|
|
/* only two threads, use fake fix thread id */
|
|
ctop_num += ringbuf_producer(0, rbf_ctop, BATCH_NUM);
|
|
ptoc_num += ringbuf_customer(0, rbf_ptoc, BATCH_NUM);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void *consumer_thread(void *arg)
|
|
{
|
|
(void)arg;
|
|
int ctop_num = 0;
|
|
int ptoc_num = 0;
|
|
for (int i = 0; i < TOTAL_TEST_NUM; i++)
|
|
{
|
|
/* only two threads, use fake fix thread id */
|
|
ptoc_num += ringbuf_producer(1, rbf_ptoc, BATCH_NUM);
|
|
ctop_num += ringbuf_customer(1, rbf_ctop, BATCH_NUM);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static int gtest_ringbuf(int mode)
|
|
{
|
|
pthread_t pid[2];
|
|
test_ringbuf_push_mode = mode;
|
|
rbf_ctop = stm_ringbuf_wrap_new(2, ringbuf_size);
|
|
rbf_ptoc = stm_ringbuf_wrap_new(2, ringbuf_size);
|
|
|
|
pthread_create(&pid[0], NULL, producer_thread, NULL);
|
|
pthread_create(&pid[1], NULL, consumer_thread, NULL);
|
|
|
|
pthread_join(pid[0], NULL);
|
|
pthread_join(pid[1], NULL);
|
|
|
|
stm_ringbuf_get_statistics(rbf_ctop, NULL, &ctop_producer_len, NULL, &ctop_consumer_len);
|
|
stm_ringbuf_get_statistics(rbf_ptoc, NULL, &ptoc_producer_len, NULL, &ptoc_consumer_len);
|
|
|
|
printf("ctop push len:%llu, ctop pop len:%llu\n", ctop_producer_len, ctop_consumer_len);
|
|
printf("ptoc push len:%llu, ctop pop len:%llu\n", ptoc_producer_len, ptoc_consumer_len);
|
|
if (ctop_producer_len != ctop_consumer_len)
|
|
{
|
|
return -1;
|
|
}
|
|
if (ptoc_producer_len != ptoc_consumer_len)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
stm_ringbuf_wrap_free(rbf_ptoc);
|
|
stm_ringbuf_wrap_free(rbf_ctop);
|
|
pthread_cancel(pid[0]);
|
|
pthread_cancel(pid[1]);
|
|
|
|
return 0;
|
|
}
|
|
|
|
TEST(MONITOR_RINGBUF, easy)
|
|
{
|
|
ASSERT_EQ(0, gtest_ringbuf(0));
|
|
}
|
|
|
|
TEST(MONITOR_RINGBUF, stream)
|
|
{
|
|
ASSERT_EQ(0, gtest_ringbuf(0));
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
srand(time(NULL));
|
|
|
|
testing::InitGoogleTest(&argc, argv);
|
|
int ret = RUN_ALL_TESTS();
|
|
return ret;
|
|
} |