當資料包進入 Rx 緩沖區并被復制到應用程式記憶體時,我試圖測量延遲。我用這個代碼測量它:
struct timespec start, end;
clock_gettime(CLOCK_REALTIME, &start);
recvfrom(sock, msg, msg_len, 0, &client, &client_addrlen);
clock_gettime(CLOCK_REALTIME, &end);
我知道這無法精確測量延遲。但是,我可以通過接收許多資料包、測量每個資料包并計算它們來計算平均延遲。有什么方法可以更精確地測量延遲嗎?(例如,latency = (time when recvfrom() is done) - (time when NIC receives a packet from))
對于設備和設備驅動程式,我使用的是 Mellanox connectx-3 和 mlx4_en。
uj5u.com熱心網友回復:
我能夠得到一個幾乎精確的數字recvmsg()。
參考
- 最有用的鏈接(https://stackoverflow.com/a/47329376/5215330)
- 網路時間戳(https://www.kernel.org/doc/Documentation/networking/timestamping.txt)
- Linux 精確時間協議 ( http://linuxptp.sourceforge.net/ )
代碼
我正在從第一個鏈接復制代碼。此代碼不是可立即運行的,而只是作業代碼中的一個片段。
static struct timespec handle_time(struct msghdr *msg) {
struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
struct scm_timestamping *ts = (struct scm_timestamping *)CMSG_DATA(cmsg);
return ts->ts[0];
}
...
char ctrl[64];
char *msg = malloc(64);
int val = SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_RX_SOFTWARE
| SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_RAW_HARDWARE;
setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPING, &val, sizeof(val));
// user buffer
struct iovec iov = {
.iov_base = msg,
.iov_len = msg_len,
};
// ancillary message header
struct msghdr m = {
.msg_name = &client_addr, // struct sockaddr_in
.msg_namelen = client_addrlen, // socklen_t
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = &ctrl,
.msg_controllen = sizeof(ctrl),
};
while (1) {
memset(msg, 0, msg_len);
num_received = recvmsg(sock_fd, &m, 0);
start = handle_time(&m);
clock_gettime(CLOCK_REALTIME, &end);
if (verbose) {
double elapsed_time = time_diff(start, end) / 1000;
total_elapsed = elapsed_time;
count ;
printf("%f us %f us\n", elapsed_time, total_elapsed / count);
}
if (sendto(sock_fd, msg, msg_len, 0, (struct sockaddr *) &client_addr, client_addrlen) < 0) {
perror("\nMessage Send Failed\n");
fprintf(stderr, "Value of errno: %d\n", errno);
}
}
關鍵是使用setsockopt()和recvmsg()。關鍵機制是當您為某個套接字 FD 設定選項時,內核將根據時間戳標志設定時間戳。設定后,如果收到帶有 的訊息struct msghdr,內核會以 SW 或 HW 的方式審計時間戳。當您查看資料時,您將能夠獲得 3 個時間戳。這些資訊可以解釋如下:
The structure can return up to three timestamps. This is a legacy feature. At least one field is non-zero at any time. Most timestamps are passed in ts[0]. Hardware timestamps are passed in ts[2]. ts[1] used to hold hardware timestamps converted to system time. Instead, expose the hardware clock device on the NIC directly as a HW PTP clock source, to allow time conversion in userspace and optionally synchronize system time with a userspace PTP stack such as linuxptp. For the PTP clock API, see Documentation/driver-api/ptp.rst.
See 2.1 from Documentation/networking/timestamping.txt for detail.
If you want to see HW timestamp then you need to have a specific HW (refer this comment) and turn its feature with ioctl(). However, there is a convenient tool called linuxptp, which does this job.
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/360440.html
