#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "epthread.h"
#define MAX_LOOPS 10
#define BIDX 0
#define SIDX 15
#define rdtsc(u64) { \
uint32_t hi, lo; \
__asm__ __volatile__ ("RDTSC\n\t" : "=a" (lo), "=d" (hi)); \
u64 = ((uint64_t )hi << 32) | lo; \
}
#define LFENCE __asm__ __volatile__ ("lfence")
#define ACCESS_ONCE(var) (*((volatile typeof(var) *)&(var)))
#define READ_ONCE(var) ({ typeof(var) _v; _v = ACCESS_ONCE(var); _v; })
#define WRITE_ONCE(var, val) (*((volatile typeof(val) *)(&(var))) = (val))
static volatile int start_flag = 0;
static int shd_data[16];
unsigned long tb_start , tb_end, ts_start, ts_end;
unsigned long gap[12];
unsigned long tsc_start[MAX_LOOPS];
unsigned long tsc_end[MAX_LOOPS];
void* ping(void *args)
{
int loop=0;
int old = 0;
int cur = 0;
memset(tsc_start, 0, MAX_LOOPS*sizeof(unsigned long));
memset(shd_data, 0, 64); // preheat
while (start_flag == 0) ; // sync. start
rdtsc(tb_start);
while (++loop < MAX_LOOPS) {
//rdtsc(tsc_start[loop]);
WRITE_ONCE(shd_data[BIDX], shd_data[BIDX]+1);
do {
cur = READ_ONCE(shd_data[SIDX]);
} while (cur <= old);
old = cur;
}
WRITE_ONCE(shd_data[BIDX], shd_data[BIDX]+1);
rdtsc(tb_end);
return NULL;
}
void* pong(void *args)
{
int loop=0;
int old = 0;
int cur = 0;
memset(tsc_end, 0, MAX_LOOPS*sizeof(unsigned long));
memset(shd_data, 0, 64); //preheat
while (start_flag == 0) ; // sync. start
rdtsc(ts_start);
while (++loop < MAX_LOOPS) {
do {
cur = READ_ONCE(shd_data[BIDX]);
//rdtsc(tsc_end[loop]);
} while (cur <= old);
old = cur;
WRITE_ONCE(shd_data[SIDX], shd_data[SIDX]+1);
}
WRITE_ONCE(shd_data[SIDX], shd_data[SIDX]+1);
rdtsc(ts_end);
return NULL;
}
int main (void)
{
epthread_t ep_ping, ep_pong;
ep_ping.pri = 99;
ep_ping.cpu = 1;
ep_ping.f = &ping;
ep_ping.args = NULL;
ep_pong.pri = 99;
ep_pong.cpu = 2;
ep_pong.f = &pong;
ep_pong.args = NULL;
EPTHREAD_CREATE(&ep_ping);
EPTHREAD_CREATE(&ep_pong);
sleep(1);
start_flag = 1;
EPTHREAD_JOIN(&ep_pong);
EPTHREAD_JOIN(&ep_ping);
unsigned long tdiff_ping = tb_end - tb_start;
unsigned long tdiff_pong = ts_end - ts_start;
unsigned long tdiff = (tdiff_ping > tdiff_pong)?tdiff_pong:tdiff_ping;
printf("Total ticks : %lu\n", tdiff);
printf("Per core-to-core latency : %lf (ticks)\n", tdiff*1.0/MAX_LOOPS);
for (int ii=0; ii<10; ++ii) {
printf("%lu\t", tsc_end[ii]-tsc_start[ii]);
}
printf("\n");
return 1;
}
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <pthread.h>
#include <sched.h>
#include <stdio.h>
#include <unistd.h>
#define EP_STATUS_UNKNOWN 0
#define EP_STATUS_CREATED 1
#define EP_STATUS_JOINED 2
typedef struct epthread_data_tag {
struct sched_param sp;
pthread_attr_t attr;
int pri;
int policy; //SCHED_FIFO, SCHED_OTHER
int cpu;
pthread_t id;
void * (*f) (void *);
void * args;
int status; // 0: unknown; 1: created;
} epthread_t;
void * epthread_function (void *args)
{
epthread_t *ep = (epthread_t *) args;
return (ep->f)(ep->args);
}
/**
* @brief create a thread
*/
void EPTHREAD_CREATE(epthread_t *ep)
{
pthread_attr_init(&(ep->attr));
pthread_attr_setschedpolicy(&(ep->attr), SCHED_FIFO);
pthread_attr_setinheritsched(&(ep->attr), PTHREAD_EXPLICIT_SCHED);
(ep->sp).sched_priority = ep->pri;
pthread_attr_setschedparam(&(ep->attr), &(ep->sp));
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(ep->cpu, &cpuset);
pthread_attr_setaffinity_np(&(ep->attr), sizeof(cpu_set_t), &cpuset);
pthread_create(&(ep->id), &(ep->attr), epthread_function, ep);
ep->status = EP_STATUS_CREATED;
}
/**
* @brief wait a thread to join
*/
void EPTHREAD_JOIN(epthread_t *ep)
{
pthread_join(ep->id, NULL);
ep->status = EP_STATUS_JOINED;
}