QNX时钟调研
SYSPAGE_ENTRY()的使用,SYSPAGE_ENTRY
测试QNX下printf(“poo\n”);的耗时
#include <sys/neutrino.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/syspage.h>
int main( void )
{
uint64_t cps, cycle1, cycle2, ncycles;
float sec;
/* snap the time */
cycle1=ClockCycles( );
/* do something */
printf("poo\n");
/* snap the time again */
cycle2=ClockCycles( );
ncycles=cycle2-cycle1;
printf("%lld cycles elapsed \n", ncycles);
/* find out how many cycles per second */
cps = SYSPAGE_ENTRY(qtime)->cycles_per_sec;
printf( "This system has %lld cycles/sec.\n",cps );
sec=(float)ncycles/cps;
printf("The cycles in seconds is %f \n",sec);
return EXIT_SUCCESS;
}
输出
ClockCycles() 和TIMESTAMP的使用
测试代码
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <inttypes.h>
#include <time.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#ifdef __QNX__
#include <sys/neutrino.h>
#include <sys/syspage.h>
#endif
#define log(fmt, ...) printf(fmt "\n", ##__VA_ARGS__);
int create_server_socket() {
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
log("cannot create socket");
return -1;
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(8080);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
if (ret < 0) {
log("cannot bind socket");
return -1;
}
int optval = 1;
ret = setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &optval, sizeof(optval));
if (ret < 0) {
log("cannot setsockopt SO_TIMESTAMP");
return -1;
}
return sock;
}
int destroy_socket(int sock) {
if (sock < 0) {
log("invalid socket");
return -1;
}
int ret = close(sock);
if (ret < 0) {
log("cannot close socket");
return -1;
}
return 0;
}
int64_t get_so_timestampns(int sock) {
struct msghdr msg;
struct iovec iov;
char cmsgbuf[4096];
char buf[1024];
struct cmsghdr *cmsg;
struct timeval *tv;
int ret;
memset(buf, 0, sizeof(buf));
memset(&msg, 0, sizeof(msg));
memset(&iov, 0, sizeof(iov));
memset(cmsgbuf, 0, sizeof(cmsgbuf));
iov.iov_base = buf;
iov.iov_len = sizeof(buf);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
ret = recvmsg(sock, &msg, 0);
if (ret < 0) {
log("cannot recvmsg %s", strerror(errno));
return -1;
}
write(sock, buf, strlen(buf));
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
#ifdef _QNX_
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMP) {
#else
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMP) {
#endif
tv = (struct timeval *)CMSG_DATA(cmsg);
return tv->tv_sec * 1000000000 + tv->tv_usec * 1000;
}
}
log("cannot find SO_TIMESTAMP");
return -1;
}
int send_to_sock(int sock, const char* buf, int len) {
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(8080);
// localhost
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
int ret = sendto(sock, buf, len, 0, (struct sockaddr *)&addr, sizeof(addr));
if (ret < 0) {
log("cannot sendto");
return -1;
}
return 0;
}
int main() {
#ifdef __QNX__
uint64_t cntpclk = SYSPAGE_ENTRY(qtime)->cycles_per_sec;
#endif
int sock = create_server_socket();
if (sock < 0) {
return -1;
}
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(sock, &rfds);
const char* buf = "hello world";
int64_t sec, msec, usec, nsec;
int64_t ns = -1;
int ret = -1;
for (;;) {
struct timespec start, end;
#ifdef __QNX__
if (clock_gettime(CLOCK_REALTIME, &start) == -1) {
#else
if (clock_gettime(CLOCK_MONOTONIC, &start) == -1) {
#endif
log("cannot get start time");
return -1;
}
ret = send_to_sock(sock, buf, strlen(buf));
if (ret < 0) {
return -1;
}
ret = select(sock + 1, &rfds, NULL, NULL, NULL);
if (ret < 0) {
log("cannot select");
return -1;
}
ns = get_so_timestampns(sock);
if (ns < 0) {
return -1;
}
#ifdef __QNX__
uint64_t cycles = ClockCycles();
sec = cycles / cntpclk;
nsec = ((cycles % cntpclk) * 1000000000) / cntpclk;
#else
sec = ns / 1000000000;
nsec = ns % 1000000000;
#endif
msec = (ns % 1000000000) / 1000000;
usec = (ns % 1000000) / 1000;
log("ts: %ld.%03ld.%03ld.%03ld", sec, msec, usec, nsec);
#ifdef __QNX__
if (clock_gettime(CLOCK_REALTIME, &end) == -1) {
#else
if (clock_gettime(CLOCK_MONOTONIC, &end) == -1) {
#endif
log("cannot get end time");
return -1;
}
#ifdef __QNX__
uint64_t elapsed = (end.tv_sec - start.tv_sec) * cntpclk + (end.tv_nsec - start.tv_nsec) * cntpclk / 1000000000;
#else
uint64_t elapsed = (end.tv_sec - start.tv_sec) * 1000000000 + (end.tv_nsec - start.tv_nsec);
#endif
log("Elapsed time: %lu ns", elapsed);
}
destroy_socket(sock);
}
输出
QNX编译server, client在x86
./so_times_client2server
-1688469126.732655764,-1688469126.728909969,-1688469126.732655764,9223372036.854776382,-1688469126.728909969,9223372036.854776382
-1688469126.732184887,-1688469126.728912115,-1688469126.732184887,9223372036.854776382,-1688469126.728909969,-1688469126.728912115
-1688469126.732127190,-1688469126.728909254,-1688469126.732127190,9223372036.854776382,-1688469126.728909254,-1688469126.728912115
-1688469126.731760502,-1688469126.728905678,-1688469126.731760502,9223372036.854776382,-1688469126.728905678,-1688469126.728912115
-1688469126.731424093,-1688469126.728862762,-1688469126.731424093,9223372036.854776382,-1688469126.728862762,-1688469126.728912115
-1688469126.731297493,-1688469126.728890896,-1688469126.731297493,9223372036.854776382,-1688469126.728862762,-1688469126.728912115
-1688469126.731182575,-1688469126.728879690,-1688469126.731182575,9223372036.854776382,-1688469126.728862762,-1688469126.728912115
-1688469126.731026411,-1688469126.728876829,-1688469126.731026411,9223372036.854776382,-1688469126.728862762,-1688469126.728912115
-1688469126.730824709,-1688469126.728859663,-1688469126.730824709,9223372036.854776382,-1688469126.728859663,-1688469126.728912115
-1688469126.730739594,-1688469126.728857994,-1688469126.730739594,9223372036.854776382,-1688469126.728857994,-1688469126.728912115
-1688469126.730360746,-1688469126.728832722,-1688469126.730360746,9223372036.854776382,-1688469126.728832722,-1688469126.728912115
-1688469126.730060339,-1688469126.728815556,-1688469126.730060339,9223372036.854776382,-1688469126.728815556,-1688469126.728912115
x86 编译server, client在x86
./so_times_client2server_x86
0.000026974,0.000043670,0.000026974,9223372036.854776382,0.000043670,9223372036.854776382
0.000017392,0.000033999,0.000026974,0.000017392,0.000043670,0.000033999
0.000016327,0.000031998,0.000026974,0.000016327,0.000043670,0.000031998
0.000023419,0.000041275,0.000026974,0.000016327,0.000043670,0.000031998
0.000022748,0.000040941,0.000026974,0.000016327,0.000043670,0.000031998
0.000023593,0.000042021,0.000026974,0.000016327,0.000043670,0.000031998
0.000041016,0.000059082,0.000041016,0.000016327,0.000059082,0.000031998
0.000022167,0.000040225,0.000041016,0.000016327,0.000059082,0.000031998
0.000029824,0.000047739,0.000041016,0.000016327,0.000059082,0.000031998
0.000021904,0.000039896,0.000041016,0.000016327,0.000059082,0.000031998
0.000024818,0.000043094,0.000041016,0.000016327,0.000059082,0.000031998
0.000022284,0.000040727,0.000041016,0.000016327,0.000059082,0.000031998
0.000024739,0.000064953,0.000041016,0.000016327,0.000064953,0.000031998
0.000021680,0.000038507,0.000041016,0.000016327,0.000064953,0.000031998
0.000039627,0.000069057,0.000041016,0.000016327,0.000069057,0.000031998
so_times_client2server.c
#include <arpa/inet.h>
#include <errno.h>
#include <inttypes.h>
#include <netinet/if_ether.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#ifdef _QNX_
#include <sys/neutrino.h>
#include <sys/siginfo.h>
#else
#include <pthread.h>
#endif
#define PORT 23333
#define log(fmt, ...) printf(fmt "\n", ##__VA_ARGS__);
int create_server_socket() {
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
log("cannot create socket");
return -1;
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = PORT;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
if (ret < 0) {
log("cannot bind socket");
return -1;
}
int optval = 1;
ret = setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &optval, sizeof(optval));
if (ret < 0) {
log("cannot setsockopt SO_TIMESTAMP");
return -1;
}
return sock;
}
int create_client_socket(const char *ip) {
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
log("cannot create socket");
return -1;
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = PORT;
if (ip == NULL) {
addr.sin_addr.s_addr = inet_addr("224.0.1.129");
} else {
addr.sin_addr.s_addr = inet_addr(ip);
}
int ret = connect(sock, (struct sockaddr *)&addr, sizeof(addr));
if (ret < 0) {
log("cannot connect socket");
return -1;
}
int optval = 1;
ret = setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &optval, sizeof(optval));
if (ret < 0) {
log("cannot setsockopt SO_TIMESTAMP");
return -1;
}
return sock;
}
int destroy_socket(int sock) {
if (sock < 0) {
log("invalid socket");
return -1;
}
int ret = close(sock);
if (ret < 0) {
log("cannot close socket");
return -1;
}
return 0;
}
void show_so_timestamp(int sock, int use_cmsg) {
struct timespec inner_ts;
clock_gettime(CLOCK_REALTIME, &inner_ts);
struct msghdr msg;
struct iovec iov;
char cmsgbuf[4096];
char buf[1024];
struct cmsghdr *cmsg;
struct timeval *tv;
int ret;
memset(buf, 0, sizeof(buf));
memset(&msg, 0, sizeof(msg));
memset(&iov, 0, sizeof(iov));
memset(cmsgbuf, 0, sizeof(cmsgbuf));
iov.iov_base = buf;
iov.iov_len = sizeof(buf);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
ret = recvmsg(sock, &msg, 0);
if (ret < 0) {
return;
}
int64_t inner_ns = inner_ts.tv_sec * 1000000000 + inner_ts.tv_nsec;
int64_t recv_ns = -1;
int64_t tag_ns = -1;
struct timespec *ts = (struct timespec *)buf;
tag_ns = ts->tv_sec * 1000000000 + ts->tv_nsec;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
#ifdef _QNX_
if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_TIMESTAMP) {
#else
if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SO_TIMESTAMP) {
#endif
tv = (struct timeval *)CMSG_DATA(cmsg);
recv_ns = tv->tv_sec * 1000000000 + tv->tv_usec * 1000;
}
}
if (recv_ns < 0 || tag_ns < 0) {
log("recv_ns %ld, tag_ns %ld", recv_ns, tag_ns);
return;
}
int64_t diff_ns = recv_ns - tag_ns;
int64_t diff_inner_ns = inner_ns - tag_ns;
static int64_t diff_ns_max = INT64_MIN;
static int64_t diff_ns_min = INT64_MAX;
if (diff_ns > diff_ns_max) {
diff_ns_max = diff_ns;
} else if (diff_ns < diff_ns_min) {
diff_ns_min = diff_ns;
}
static int64_t diff_inner_ns_max = INT64_MIN;
static int64_t diff_inner_ns_min = INT64_MAX;
if (diff_inner_ns > diff_inner_ns_max) {
diff_inner_ns_max = diff_inner_ns;
} else if (diff_inner_ns < diff_inner_ns_min) {
diff_inner_ns_min = diff_inner_ns;
}
log("%.9lf,%.9lf,%.9lf,%.9lf,%.9lf,%.9lf",
diff_ns / 1000000000.0, diff_inner_ns / 1000000000.0,
diff_ns_max / 1000000000.0, diff_ns_min / 1000000000.0,
diff_inner_ns_max / 1000000000.0, diff_inner_ns_min / 1000000000.0);
}
int64_t send_to_sock(int sock) {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
int ret = sendto(sock, &ts, sizeof(ts), 0, NULL, 0);
if (ret < 0) {
return -1;
}
return ts.tv_sec * 1000000000 + ts.tv_nsec;
}
void wait_recv(int sock, int use_cmsg) {
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(sock, &rfds);
struct timeval timeOut = {0, 0};
int ret = -1;
for (;;) {
ret = select(sock + 1, &rfds, NULL, NULL, NULL);
if (ret < 0) {
log("cannot select");
return;
}
show_so_timestamp(sock, use_cmsg);
}
}
void server_loop() {
int sock = create_server_socket();
if (sock < 0) {
return;
}
wait_recv(sock, 1);
destroy_socket(sock);
}
static const int64_t interval_us = 100 * 1000;
static int client_sock = -1;
#ifdef _QNX_
void client_notify_function() {
send_to_sock(client_sock);
#else
void *client_notify_function(void *arg) {
for (;;) {
send_to_sock(client_sock);
usleep(interval_us);
}
return NULL;
#endif
}
void client_loop(const char *ip) {
client_sock = create_client_socket(ip);
if (client_sock < 0) {
return;
}
#ifdef _QNX_
timer_t timer_id;
struct sigevent event;
memset(&event, 0, sizeof(event));
event.sigev_value.sival_ptr = &timer_id;
event.sigev_notify = SIGEV_THREAD;
event.sigev_notify_function = client_notify_function;
timer_create(CLOCK_REALTIME, &event, &timer_id);
struct itimerspec itime;
memset(&itime, 0, sizeof(itime));
itime.it_value.tv_nsec = interval_us * 1000;
itime.it_interval.tv_nsec = interval_us * 1000;
timer_settime(timer_id, 0, &itime, NULL);
#else
pthread_t thread;
pthread_create(&thread, NULL, client_notify_function, NULL);
#endif
wait_recv(client_sock, 0);
destroy_socket(client_sock);
}
int main(int argc, char *argv[]) {
#ifdef _QNX_
struct _clockperiod period;
period.nsec = 10000;
period.fract = 0;
ClockPeriod(CLOCK_REALTIME, &period, NULL, 0);
#endif
if (argc < 2) {
server_loop();
} else {
client_loop(argv[1]);
}
}