Comments 9
1. Через ioctl к сокету. struct timeval tv_rcv;
int res = ioctl(s, SIOCGSTAMP, &tv_rcv);
2. Через кольцевой буфер PACKET_SOCKET.
#include
typedef struct {
struct tpacket_hdr tp_h
__attribute__((aligned(TPACKET_ALIGNMENT)));
struct sockaddr_ll s_ll
__attribute__((aligned(TPACKET_ALIGNMENT)));
uint8_t data[0]
__attribute__((aligned(TPACKET_ALIGNMENT)));
} frame_map_hack_t;
/*
XXX volatile attr and invalidate cache ops may be needed in
many cases to access PACKET SOCKET ring buffers, also
keep in mind cache aliasing problems in some platforms
*/
typedef struct {
struct tpacket_hdr tp_h
__attribute__((aligned(TPACKET_ALIGNMENT)));
struct sockaddr_ll s_ll
__attribute__((aligned(TPACKET_ALIGNMENT)));
uint8_t data[CAP_SNAPLEN-sizeof(frame_map_hack_t)]
__attribute__((aligned(TPACKET_ALIGNMENT)));
} rx_ring_cell_t;
…
volatile rx_ring_cell_t *rc_cur = ps_rbuf;
…
tv_last.tv_sec = rc_cur->tp_h.tp_sec;
tv_last.tv_usec = rc_cur->tp_h.tp_usec;
Да, есть и такой способ. Можно после получения (recv
) пакета из сокета дернуть ioctl
SIOCGSTAMP
или SIOCGSTAMPNS
и получить время получения ядром этого пакета. Последний ioctl
возвращает struct timespec
допускающую точность до наносекунд, в отличие от первого, который возвращает struct timeval
с микросекундами.
Полученное таким образов время ничем не будет отличаться времени полученного через SO_TIMESTAMPING
с установленным флагом SOF_TIMESTAMPING_RX_SOFTWARE
.
Но есть еще один способ получить то же самое, сделав на один системный вызов меньше. Опция сокета SO_TIMESTAMP
(не путать с SO_TIMESTAMPING
) включает доставку временных меток в контрольном сообщении. Временные метки те же самые, что и в SIOCGSTAMP
.
Как минимум есть TCP_INFO, где есть некоторые тайминги.
Это возможно?
tcpi_last_data_recv даст что-то похоже на то, что хочется, только он отдаёт не таймштамп, а миллисекунды(1e-3!) с момента получения данных и разрешение у него в jiffies.
Я не уверен, укладывается ли такая точность в определение "тормозов" для конкретного случая.
Про использование обсуждаемых в статье таймштампов применительно TCP я не в курсе, надо исходники читать :-)
на типичном офисном x86-32 и x86-64 точность будет порядка 50us если нужно точнее тогда придется встраиваться в ядро и «дампить» куда-нибудь в «отмепленную» память результаты rdtsc и в user space сравнивать и не забыть привязать ваш event loop к конкретному ядру процессора. На ppc и mips аналогично а вот у arm плохо с таймерами и гранулярность порядка 100ns к сожалению обычно предел :(
Кстати не забывайте отключать алгоритм nagle, если вам важна скорость доставки сообщений через TCP (TCP_NODELAY и выключенный TCP_CORC вам в помощь)
Documentation/networking/timestamping.txt об этом говорит следующее:
1.4 Bytestream Timestamps
The SO_TIMESTAMPING interface supports timestamping of bytes in a
bytestream. Each request is interpreted as a request for when the
entire contents of the buffer has passed a timestamping point. That
is, for streams option SOF_TIMESTAMPING_TX_SOFTWARE will record
when all bytes have reached the device driver, regardless of how
many packets the data has been converted into.
Они обещают сообщить пользовательскому приложению момент, когда последний байт данных пройдет "timestamping point". Хотя они упоминают явно только отправку пакета, полагаю что это применимо и к приему.
Лучшая документация по ядру — его исходники. Если разберетесь, обязательно расскажите нам :).
SO_TIMESTAMPING в картинках. Прием пакета