PID: 0 TASK: ffff8d2b3775b0c0 CPU: 1 COMMAND: "swapper/1"#0 [ffff8d597f6489f0] machine_kexec at ffffffffa5a63b34#1 [ffff8d597f648a50] __crash_kexec at ffffffffa5b1e242#2 [ffff8d597f648b20] panic at ffffffffa615d85b#3 [ffff8d597f648ba0] nmi_panic at ffffffffa5a9859f#4 [ffff8d597f648bb0] watchdog_overflow_callback at ffffffffa5b4a881#5 [ffff8d597f648bc8] __perf_event_overflow at ffffffffa5ba26b7#6 [ffff8d597f648c00] perf_event_overflow at ffffffffa5babd24#7 [ffff8d597f648c10] intel_pmu_handle_irq at ffffffffa5a0a850#8 [ffff8d597f648e38] perf_event_nmi_handler at ffffffffa616d031#9 [ffff8d597f648e58] nmi_handle at ffffffffa616e91c#10 [ffff8d597f648eb0] do_nmi at ffffffffa616ebf8#11 [ffff8d597f648ef0] end_repeat_nmi at ffffffffa616dd89[exception RIP: __getnstimeofday64+144]RIP: ffffffffa5b03940 RSP: ffff8d597f643c78 RFLAGS: 00000212RAX: 15b5c8320b8602cd RBX: ffff8d597f643cb0 RCX: 000000005f89ee29RDX: 00000000ee4479fe RSI: 0000012b5478f3b2 RDI: 0009709c7629b240RBP: ffff8d597f643c90 R8: 00000000007001de R9: ffff8d596d5c0000R10: 000000000000007a R11: 000000000000000e R12: ffffffffa662ea80R13: 000000003ccbcfb6 R14: ffff8d895de08000 R15: 0000000000000081ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018--- <NMI exception stack> ---#12 [ffff8d597f643c78] __getnstimeofday64 at ffffffffa5b03940#13 [ffff8d597f643c98] getnstimeofday64 at ffffffffa5b0398e#14 [ffff8d597f643ca8] ktime_get_real at ffffffffa5b03a45#15 [ffff8d597f643cd0] netif_receive_skb_internal at ffffffffa603b936#16 [ffff8d597f643d00] napi_gro_receive at ffffffffa603c588#17 [ffff8d597f643d28] mlx5e_handle_rx_cqe_mpwrq at ffffffffc052ef1d [mlx5_core]#18 [ffff8d597f643db8] mlx5e_poll_rx_cq at ffffffffc052f4b8 [mlx5_core]#19 [ffff8d597f643e08] mlx5e_napi_poll at ffffffffc05304c6 [mlx5_core]#20 [ffff8d597f643e78] net_rx_action at ffffffffa603bf1f#21 [ffff8d597f643ef8] __do_softirq at ffffffffa5aa2155#22 [ffff8d597f643f68] call_softirq at ffffffffa617a32c#23 [ffff8d597f643f80] do_softirq at ffffffffa5a2e675
int __getnstimeofday64(struct timespec64 *ts){struct timekeeper *tk = &timekeeper;unsigned long seq;s64 nsecs = 0;do {seq = read_seqcount_begin(&timekeeper_seq);ts->tv_sec = tk->xtime_sec;//caq:秒值赋值nsecs = timekeeping_get_ns(&tk->tkr_mono);} while (read_seqcount_retry(&timekeeper_seq, seq));ts->tv_nsec = 0;timespec64_add_ns(ts, nsecs);//caq:这里面还有个循环呢,** Do not bail out early, in case there were callers still using* the value, even in the face of the WARN_ON.*/if (unlikely(timekeeping_suspended))return -EAGAIN;return 0;}
0xffffffffa5b0393b <__getnstimeofday64+139>: xor %edx,%edx----清零 u32 ret = 0;0xffffffffa5b0393d <__getnstimeofday64+141>: nopl (%rax)0xffffffffa5b03940 <__getnstimeofday64+144>: sub $0x3b9aca00,%rax---------------------1s就是1000000000 ns,循坏在这,而栈中的rax为 15b5c8320b8602cd0xffffffffa5b03946 <__getnstimeofday64+150>: add $0x1,%edx---------ret++;edx is the lower 32 bit of rdx,rdx为00000000ee4479fe,所以edx为 0xee4479fe,也就是39974650860xffffffffa5b03949 <__getnstimeofday64+153>: cmp $0x3b9ac9ff,%rax-------------------------------------剩余是否小于1ns0xffffffffa5b0394f <__getnstimeofday64+159>: ja 0xffffffffa5b03940 <__getnstimeofday64+144>include/linux/time.h: 215---对应 timespec_add_ns0xffffffffa5b03951 <__getnstimeofday64+161>: add %rcx,%rdx---delta算出的秒值+之前保存的秒值,就是最新的秒值0xffffffffa5b03954 <__getnstimeofday64+164>: mov %rax,0x8(%rbx)----剩余的ns,赋值给a->tv_nsec = ns;0xffffffffa5b03958 <__getnstimeofday64+168>: mov %rdx,(%rbx)---加完delta秒值的最新的秒值,赋值给a->tv_sec0xffffffffa5b0395b <__getnstimeofday64+171>: cmpl $0x1,0xc55702(%rip) # 0xffffffffa6759064----if(timekeeping_suspended)kernel/time/timekeeping.c: 5120xffffffffa5b03962 <__getnstimeofday64+178>: pop %rbx0xffffffffa5b03963 <__getnstimeofday64+179>: pop %r120xffffffffa5b03965 <__getnstimeofday64+181>: pop %r13
0xffffffffa5b03940 <__getnstimeofday64+144>: sub $0x3b9aca00,%rax---------------------1s就是1000000000 ns,循坏在这,而栈中的rax为 15b5c8320b8602cd
static __always_inline void timespec64_add_ns(struct timespec64 *a, u64 ns){a->tv_sec += __iter_div_u64_rem(a->tv_nsec + ns, NSEC_PER_SEC, &ns);a->tv_nsec = ns;}__iter_div_u64_rem展开如下:static __always_inline u32__iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder){u32 ret = 0;while (dividend >= divisor) {//这个循环* The following asm() prevents the compiler fromoptimising this loop into a modulo operation. */asm("" : "+rm"(dividend));dividend -= divisor;ret++;}*remainder = dividend;return ret;}
RAX: 15b5c8320b8602cdcrash> p 0x15b5c8320b8602cd/0x3b9aca00$7 = 1564376562
static inline s64 timekeeping_get_ns(struct tk_read_base *tkr){u64 delta;delta = timekeeping_get_delta(tkr);//caq:上次读取与本次读取之间的差值return timekeeping_delta_to_ns(tkr, delta);//caq:差值转换为ns}delta的来源是:static inline u64 timekeeping_get_delta(struct tk_read_base *tkr){u64 cycle_now, delta;struct clocksource *clock;* read clocksource: */clock = tkr->clock;cycle_now = tkr->clock->read(clock);//当前值是通过读取来的* calculate the delta since the last update_wall_time */delta = clocksource_delta(cycle_now, clock->cycle_last, clock->mask);//计算差值return delta;}
crash> timekeepertimekeeper = $1 = {tkr_mono = {------------------------------timekeeping_get_ns(&tk->tkr_mono)clock = 0xffffffffa662ea80, ------------这个就是 clocksource,这个值当前就是 clocksource_tsccycle_last = 16728674596502256,mult = 7340510,shift = 24,xtime_nsec = 2657092090049088, 这个值并不是ns,而是要 >>tkr->shiftbase = {tv64 = 2788453640047242}},tkr_raw = {clock = 0xffffffffa662ea80,cycle_last = 16728674596502256,mult = 8007931,shift = 24,xtime_nsec = 0,base = {tv64 = 2788490058099290}},xtime_sec = 1602874921, ------------------当前的秒数
crash> dis -l 0xffffffffa662ea800xffffffffa662ea80 <clocksource_tsc>: addb $0xa5,-0x5d(%rcx)--------------就是 clocksource_tsc ,tsc就是一个clock_sourcecrash> clocksource_tscclocksource_tsc = $2 = {read = 0xffffffffa5a34180, -----------read_tsccycle_last = 16728674596502256, ------上次更新墙上时间的时刻取的cycle值mask = 18446744073709551615,mult = 8007931,shift = 24, ----------------------注意位数max_idle_ns = 204347035648,maxadj = 880872,archdata = {vclock_mode = 1},name = 0xffffffffa647c1cd "tsc", ---名称list = {next = 0xffffffffa6633ff8,prev = 0xffffffffa665c9b0},rating = 300, --------------优先级,enable = 0x0,disable = 0x0,flags = 35, ---没有CLOCK_SOURCE_UNSTABLE标志suspend = 0x0,resume = 0x0,owner = 0x0}
static inline s64 timekeeping_delta_to_ns(struct tk_read_base *tkr,u64 delta){s64 nsec;//注意,这里是带符号数nsec = delta * tkr->mult + tkr->xtime_nsec;nsec >>= tkr->shift;//换算成ns/* If arch requires, add in get_arch_timeoffset() */return nsec + arch_gettimeoffset();}
-static inline s64 timekeeping_delta_to_ns(struct tk_read_base *tkr,+static inline u64 timekeeping_delta_to_ns(struct tk_read_base *tkr,cycle_t delta){- s64 nsec;+ u64 nsec;
作者简介
Anqing 高级后端工程师
目前主要负责linux内核及容器,虚拟机等虚拟化方面的工作。
文章转载自OPPO数智技术,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




