Linux perf probe 的使用(三)

news2024/11/27 8:22:00

文章目录

  • 前言
  • 一、Dynamic Tracing
  • 二、kprobes
    • 2.1 perf kprobe 的使用
    • 2.2 kprobe Arguments
    • 3.3 tcp_sendmsg()
      • 3.3.1 Kernel: tcp_sendmsg()
      • 3.3.2 Kernel: tcp_sendmsg() with size
      • 3.3.2 Kernel: tcp_sendmsg() line number and local variable
  • 三、uprobes的使用
    • 3.1 perf uprobe 的使用
    • 3.2 uprobe Arguments
  • 参考资料

前言

perf使用术语探测事件来指kprobes、uprobes和USDT探测。这些是“动态”的,必须先初始化,然后才能跟踪它们:默认情况下,它们不在perf列表的输出中(某些USDT探针可能存在,因为它们已自动初始化)。一旦初始化,它们将被列为“Tracepoint event”。

一、Dynamic Tracing

跟踪点和动态跟踪之间的区别如下图所示,该图说明了常见跟踪点库的覆盖范围:
在这里插入图片描述
图片来自于:https://www.brendangregg.com/perf.html

tracepoint和kprobe之间的比较如下表所示:
在这里插入图片描述

虽然动态跟踪可以看到所有内容,但它也是一个不稳定的接口,因为它检测原始代码。这意味着您开发的任何动态跟踪工具都可能在内核补丁或更新后崩溃。首先尝试使用静态跟踪点,因为它们的接口应该更稳定。它们也可以更容易使用和理解,因为它们的设计考虑到了跟踪最终用户。

动态跟踪的一个好处是,它可以在实时系统上启用,而无需重新启动任何东西。您可以使用已经运行的内核或应用程序,然后开始动态检测,它(安全地)修补内存中的指令以添加检测。这意味着在您开始使用该功能之前,该功能的开销为零。前一刻,您的二进制文件未经修改且全速运行,下一刻,它将运行您动态添加的一些额外的检测指令。一旦您使用完动态跟踪会话,这些指令最终应该被删除。

使用动态跟踪和执行额外指令时的开销与检测事件的频率乘以每个检测所做的工作有关。

对于内核分析,使用CONFIG_KPROBES=y和CONFIG_KPROBE_EVENTS=y来启用内核动态跟踪,而CONFIG_FRAME_POINTER=y用于基于帧指针的内核堆栈。对于用户级分析,CONFIG_UPROBES=y和CONFIG_UROBE_EVENTS=y用于用户级动态跟踪。

使用 perf-probe 命令动态跟踪函数:

NAME
       perf-probe - Define new dynamic tracepoints

DESCRIPTION
       This command defines dynamic tracepoint events, by symbol and registers without debuginfo, or by C expressions (C line numbers, C function names, and C local variables) with debuginfo.

常用的一些参数选项:

	   -a, --add=
           Define a probe event (see PROBE SYNTAX for detail).

       -d, --del=
           Delete probe events. This accepts glob wildcards(*, ?) and character classes(e.g. [a-z], [!A-Z]).

       -l, --list[=[GROUP:]EVENT]
           List up current probe events. This can also accept filtering patterns of event names. When this is used with --cache, perf shows all cached probes instead of the live probes.

二、kprobes

2.1 perf kprobe 的使用

以下是创建和使用kprobe的典型工作流,在本例中,用于检测do_nanosleep()内核函数。

动态跟踪的函数要在内核符号文件/proc/kallsyms中:

[root@localhost ~]# cat /proc/kallsyms | grep do_nanosleep
ffffffffb0f66b40 t do_nanosleep

在没有动态跟踪do_nanosleep之前:

[root@localhost ~]# perf list probe:do_nanosleep

List of pre-defined events (to be used in -e):


Metric Groups:

使用perf list查询不到do_nanosleep事件。

接下来动态跟踪do_nanosleep函数:

perf probe --add do_nanosleep
perf record -e probe:do_nanosleep -a sleep 5
perf script
perf probe --del do_nanosleep

kprobe是使用probe子命令和–add(–add是可选的)创建的,当不再需要它时,将使用probe和–del删除它。以下是该序列的输出,包括列出探测事件:
(1)添加动态事件:

[root@localhost ~]# perf probe --add do_nanosleep
Added new event:
  probe:do_nanosleep   (on do_nanosleep)

You can now use it in all perf tools, such as:

        perf record -e probe:do_nanosleep -aR sleep 1

(2)查看动态事件(do_nanosleep初始化后,将被列为“Tracepoint event”):

[root@localhost ~]# perf list probe:do_nanosleep

List of pre-defined events (to be used in -e):

  probe:do_nanosleep                                 [Tracepoint event]


Metric Groups:

(3)record/script 动态事件

[root@localhost ~]# perf record -e probe:do_nanosleep -aR sleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.618 MB perf.data (3 samples) ]
[root@localhost ~]# perf script
           sleep 30562 [001] 63910.281197: probe:do_nanosleep: (ffffffffb0f66b40)
           sleep 30568 [000] 63910.340391: probe:do_nanosleep: (ffffffffb0f66b40)
            pool  6556 [002] 63910.844546: probe:do_nanosleep: (ffffffffb0f66b40)
[root@localhost ~]# cat /proc/kallsyms | grep do_nanosleep
ffffffffb0f66b40 t do_nanosleep

(4)删除动态事件

[root@localhost ~]# perf probe --del probe:do_nanosleep
Removed event: probe:do_nanosleep

(5)kretprobe
可以通过添加%return来检测函数的返回:

[root@localhost ~]# perf probe --add do_nanosleep%return
Added new event:
  probe:do_nanosleep   (on do_nanosleep%return)

You can now use it in all perf tools, such as:

        perf record -e probe:do_nanosleep -aR sleep 1

这使用kretprobe:

[root@localhost ~]# perf probe --add do_nanosleep%return
Added new event:
  probe:do_nanosleep   (on do_nanosleep%return)

You can now use it in all perf tools, such as:

        perf record -e probe:do_nanosleep -aR sleep 1

[root@localhost ~]#
[root@localhost ~]# perf record -e probe:do_nanosleep -aR sleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.611 MB perf.data (2 samples) ]
[root@localhost ~]# perf script
            pool  6556 [000] 64259.662728: probe:do_nanosleep: (ffffffffb0f66b40 <- ffffffffb08c6a6b)
           sleep   518 [001] 64260.171569: probe:do_nanosleep: (ffffffffb0f66b40 <- ffffffffb08c6a6b)
[root@localhost ~]# perf probe --del probe:do_nanosleep
Removed event: probe:do_nanosleep

2.2 kprobe Arguments

至少有四种不同的方式将参数插入内核函数。

(1)
首先,如果内核debuginfo可用,那么perf可以获得函数变量(包括参数)的信息。使用–vars选项列出do_nanosleep()kprobe的变量:

-V, --vars=
           Show available local variables at given probe point. The argument syntax is same as PROBE SYNTAX, but NO ARGs.
[root@localhost ~]# perf probe --vars do_nanosleep
Available variables at do_nanosleep
        @<do_nanosleep+0>
                enum hrtimer_mode       mode
                struct hrtimer_sleeper* t

此输出显示名为mode和t的变量,它们是do_nanosleep()的入口参数。可以在创建探头时添加这些内容,以便在记录时包含这些内容。例如,添加模式:

[root@localhost ~]#  perf probe 'do_nanosleep mode'
Added new event:
  probe:do_nanosleep   (on do_nanosleep with mode)

You can now use it in all perf tools, such as:

        perf record -e probe:do_nanosleep -aR sleep 1

[root@localhost ~]# perf record -e probe:do_nanosleep -a
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.605 MB perf.data (3 samples) ]

[root@localhost ~]# perf script
            pool  6556 [000] 64979.664437: probe:do_nanosleep: (ffffffffb0f66b40) mode=0x1
           sleep  5962 [002] 64980.279301: probe:do_nanosleep: (ffffffffb0f66b40) mode=0x1
            pool  6556 [000] 64980.316230: probe:do_nanosleep: (ffffffffb0f66b40) mode=0x1

输出显示 mode 变量等于1。

(2)
第二,如果内核debuginfo不可用(正如我在生产中经常发现的那样),那么可以通过它们的寄存器位置读取参数。一个技巧是使用相同的系统(相同的硬件和内核)并在其上安装内核调试信息以供参考。然后,可以使用-n(dry run)和-v(verbose)选项查询此参考系统以查找寄存器位置,以执行探测:

[root@localhost ~]# perf probe -nv 'do_nanosleep mode'
......
Found 1 probe_trace_events.
Opening /sys/kernel/debug/tracing//kprobe_events write=1
Writing event: p:probe/do_nanosleep _text+7760704 mode=%si:u32
Added new event:
  probe:do_nanosleep   (on do_nanosleep with mode)
......

由于它是一个 dry run,因此不会创建事件。但是输出显示了模式变量的位置:它位于寄存器%si中,并打印为32位十六进制数(u32)。现在可以通过复制和粘贴模式声明字符串(mode=%si:x32)在无debuginfo系统上使用此语法:

[root@localhost ~]# perf probe 'do_nanosleep mode=%si:u32'
Added new event:
  probe:do_nanosleep   (on do_nanosleep with mode=%si:u32)

You can now use it in all perf tools, such as:

        perf record -e probe:do_nanosleep -aR sleep 1

[root@localhost ~]# perf record -e probe:do_nanosleep -a
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.606 MB perf.data (3 samples) ]

[root@localhost ~]# perf script
            pool  6556 [000] 65807.996795: probe:do_nanosleep: (ffffffffb0f66b40) mode=0x1
           sleep 11789 [002] 65808.370905: probe:do_nanosleep: (ffffffffb0f66b40) mode=0x1
            pool  6556 [000] 65808.648566: probe:do_nanosleep: (ffffffffb0f66b40) mode=0x1

只有当系统具有相同的处理器ABI和内核版本时,这才有效,否则可能会检测到错误的寄存器位置。

(3)
第三,如果您知道处理器ABI,可以自己确定寄存器位置。下一节中给出了一个 uprobes 的示例。

(4)
第四,有一个新的内核调试信息源:BPF类型格式(BTF)。默认情况下,这更可能是可用的,将来的perf版本应该支持它作为备用的debuginfo源。

(5)
对于使用kretprobe检测的do_nanosleep的返回,可以使用特殊的$retval变量读取返回值:

perf probe 'do_nanosleep%return $retval'

查看内核源代码以确定返回值包含的内容。

3.3 tcp_sendmsg()

3.3.1 Kernel: tcp_sendmsg()

此示例显示在Linux 3.10.0内核上检测内核tcp_sendmsg()函数:

[root@localhost perf]# cat /proc/kallsyms | grep tcp_sendmsg
ffffffffb0e93fc0 T tcp_sendmsg
[root@localhost perf]# perf probe --add tcp_sendmsg
Added new event:
  probe:tcp_sendmsg    (on tcp_sendmsg)

You can now use it in all perf tools, such as:

        perf record -e probe:tcp_sendmsg -aR sleep 1

[root@localhost perf]# perf record -e probe:tcp_sendmsg -a -g -- sleep 5
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.632 MB perf.data (42 samples) ]
[root@localhost perf]# perf report --stdio
# To display the perf.data header info, please use --header/--header-only options.
#
#
# Total Lost Samples: 0
#
# Samples: 42  of event 'probe:tcp_sendmsg'
# Event count (approx.): 42
#
# Children      Self  Trace output
# ........  ........  ..................
#
   100.00%   100.00%  (ffffffffb0e93fc0)
            |
            ---__GI___libc_write
               system_call
               sys_write
               vfs_write
               do_sync_write
               sock_aio_write
               tcp_sendmsg



#
# (Tip: For memory address profiling, try: perf mem record / perf mem report)

这显示了write()系统调用到tcp_sendmsg()的路径。

[root@localhost perf]# perf probe --del tcp_sendmsg
Removed event: probe:tcp_sendmsg

3.3.2 Kernel: tcp_sendmsg() with size

如果内核具有debuginfo(CONFIG_DEBUG_INFO=y),则可以从函数中找出内核变量。这是检查size_ t(整数)的简单示例:
列出tcp_sendmsg()可用的变量:

-V, --vars=
           Show available local variables at given probe point. The argument syntax is same as PROBE SYNTAX, but NO ARGs.
[root@localhost perf]# perf probe -V tcp_sendmsg
Available variables at tcp_sendmsg
        @<tcp_sendmsg+0>
                int     size_goal
                long int        timeo
                size_t  size
                struct kiocb*   iocb
                struct msghdr*  msg
                struct sock*    sk

使用“size”变量为tcp_sendmsg()创建探测:

[root@localhost perf]# perf probe --add 'tcp_sendmsg size'
Added new event:
  probe:tcp_sendmsg    (on tcp_sendmsg with size)

You can now use it in all perf tools, such as:

        perf record -e probe:tcp_sendmsg -aR sleep 1

Tracing this probe:

[root@localhost perf]# perf record -e probe:tcp_sendmsg -a
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.628 MB perf.data (49 samples) ]

[root@localhost perf]# perf script
            sshd 29204 [001] 82790.664230: probe:tcp_sendmsg: (ffffffffb0e93fc0) size=0x50
            sshd 29204 [001] 82790.664939: probe:tcp_sendmsg: (ffffffffb0e93fc0) size=0x60
            sshd 29204 [001] 82790.665627: probe:tcp_sendmsg: (ffffffffb0e93fc0) size=0x50
            sshd 29204 [001] 82790.665712: probe:tcp_sendmsg: (ffffffffb0e93fc0) size=0x30
            sshd 29204 [001] 82790.667466: probe:tcp_sendmsg: (ffffffffb0e93fc0) size=0x40
            sshd 29204 [001] 82790.667566: probe:tcp_sendmsg: (ffffffffb0e93fc0) size=0x30
            sshd 29204 [001] 82790.668484: probe:tcp_sendmsg: (ffffffffb0e93fc0) size=0x30
            sshd 29204 [001] 82790.668582: probe:tcp_sendmsg: (ffffffffb0e93fc0) size=0x30
            sshd 29204 [001] 82791.672211: probe:tcp_sendmsg: (ffffffffb0e93fc0) size=0x40
            sshd 29204 [001] 82791.674832: probe:tcp_sendmsg: (ffffffffb0e93fc0) size=0x60
            sshd 29204 [001] 82791.677249: probe:tcp_sendmsg: (ffffffffb0e93fc0) size=0x50
            sshd 29204 [001] 82791.677519: probe:tcp_sendmsg: (ffffffffb0e93fc0) size=0x30
            sshd 29204 [001] 82791.681480: probe:tcp_sendmsg: (ffffffffb0e93fc0) size=0x40
            sshd 29204 [001] 82791.681772: probe:tcp_sendmsg: (ffffffffb0e93fc0) size=0x30
            sshd 29204 [001] 82791.684988: probe:tcp_sendmsg: (ffffffffb0e93fc0) size=0x30
            sshd 29204 [001] 82791.685259: probe:tcp_sendmsg: (ffffffffb0e93fc0) size=0x30
            sshd 29204 [001] 82792.689914: probe:tcp_sendmsg: (ffffffffb0e93fc0) size=0x40
            sshd 29204 [001] 82792.692504: probe:tcp_sendmsg: (ffffffffb0e93fc0) size=0x60
            sshd 29204 [001] 82792.694701: probe:tcp_sendmsg: (ffffffffb0e93fc0) size=0x50
            sshd 29204 [001] 82792.694949: probe:tcp_sendmsg: (ffffffffb0e93fc0) size=0x30
			......

3.3.2 Kernel: tcp_sendmsg() line number and local variable

使用debuginfo,perf_events可以为内核函数内的行创建跟踪点。列出tcp_sendmsg()的可用行探测:

-L, --line=
           Show source code lines which can be probed. This needs an argument which specifies a range of the source code. (see LINE SYNTAX for detail)
[root@localhost perf]# perf probe -L tcp_sendmsg
<tcp_sendmsg@/usr/src/debug/kernel-3.10.0-957.el7/linux-3.10.0-957.el7.x86_64/net/ipv4/tcp.c:0>
      0  int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                        size_t size)
      2  {
                struct iovec *iov;
                struct tcp_sock *tp = tcp_sk(sk);
                struct sk_buff *skb;
      6         int iovlen, flags, err, copied = 0;
      7         int mss_now = 0, size_goal, copied_syn = 0, offset = 0;
                bool sg;
                long timeo;

     11         lock_sock(sk);

     13         flags = msg->msg_flags;
     14         if (flags & MSG_FASTOPEN) {
     15                 err = tcp_sendmsg_fastopen(sk, msg, &copied_syn, size);
     16                 if (err == -EINPROGRESS && copied_syn > 0)
                                goto out;
     18                 else if (err)
                                goto out_err;
                        offset = copied_syn;
                }
          ......
          }

[root@localhost perf]# perf probe -V tcp_sendmsg:81
Available variables at tcp_sendmsg:81
        @<tcp_sendmsg+826>
                bool    sg
                int     copied
                int     flags
                int     iovlen
                int     mss_now
                int     offset
                int     size_goal
                long int        timeo
                size_t  seglen
                struct iovec*   iov
                struct sock*    sk
                unsigned char*  from

现在让我们跟踪第81行,并在循环中检查seglen变量:

[root@localhost perf]# perf probe --del tcp_sendmsg
Removed event: probe:tcp_sendmsg
[root@localhost perf]# perf probe --add 'tcp_sendmsg:81 seglen'
Added new event:
  probe:tcp_sendmsg    (on tcp_sendmsg:81 with seglen)

You can now use it in all perf tools, such as:

        perf record -e probe:tcp_sendmsg -aR sleep 1

[root@localhost perf]# perf record -e probe:tcp_sendmsg -a
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.619 MB perf.data (33 samples) ]

[root@localhost perf]# perf script
            sshd 29204 [001] 83979.203223: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x50
            sshd 29204 [001] 83979.205938: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x60
            sshd 29204 [001] 83979.208299: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x50
            sshd 29204 [001] 83979.208539: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x30
            sshd 29204 [001] 83979.214403: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x40
            sshd 29204 [001] 83979.214656: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x30
            sshd 29204 [001] 83979.218265: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x30
            sshd 29204 [001] 83979.218564: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x30
            sshd 29204 [001] 83980.223443: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x50
            sshd 29204 [001] 83980.226039: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x30
            sshd 29204 [001] 83980.226248: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x70
            sshd 29204 [002] 83980.229020: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x50
            sshd 29204 [002] 83980.229094: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x30
            sshd 29204 [002] 83980.232982: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x40
            sshd 29204 [002] 83980.233220: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x30
            sshd 29204 [002] 83980.236385: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x30
            sshd 29204 [002] 83980.236677: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x30
            sshd 29204 [002] 83981.241734: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x50
            sshd 29204 [002] 83981.244477: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x60
            sshd 29204 [002] 83981.246985: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x50
            sshd 29204 [002] 83981.247241: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x30
            sshd 29204 [002] 83981.251093: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x40
            sshd 29204 [002] 83981.251360: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x30
            sshd 29204 [002] 83981.254500: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x30
            sshd 29204 [002] 83981.254828: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x30
            sshd 29204 [002] 83982.259723: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x40
            sshd 29204 [002] 83982.262445: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x60
            sshd 29204 [002] 83982.264933: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x50
            sshd 29204 [002] 83982.265127: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x30
            sshd 29204 [002] 83982.268984: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x40
            sshd 29204 [002] 83982.269206: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x30
            sshd 29204 [002] 83982.272402: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x30
            sshd 29204 [002] 83982.272704: probe:tcp_sendmsg: (ffffffffb0e942fa) seglen=0x30

还可以在内核过滤中使用–filter,以仅匹配所需的数据。

三、uprobes的使用

uprobes(用户空间探测器)与kprobes类似,但适用于用户空间。它们可以动态地插入应用程序和库中的函数,并提供一个不稳定的API,用于深入其他工具范围之外的软件内部。uprobes在2012年发布的Linux3.5中提供。

3.1 perf uprobe 的使用

在使用 perf 时,uprobes的创建与kprobes类似。例如,要为libc文件打开函数创建uprobe,fopen:

# perf probe -x /lib/x86_64-linux-gnu/libc.so.6 --add fopen
Added new event:
 probe_libc:fopen (on fopen in /lib/x86_64-linux-gnu/libc-2.27.so)

二进制路径使用-x指定。uprobe名为probe_libc:fopen,现在可以与perf record一起使用来记录事件。

完成uprobe后,可以使用–del:

# perf probe --del probe_libc:fopen
Removed event: probe_libc:fopen

可以通过添加%return来检测函数的返回:

# perf probe -x /lib/x86_64-linux-gnu/libc.so.6 --add fopen%return

使用uretpobe。

3.2 uprobe Arguments

如果您的系统具有目标二进制文件的debuginfo,则变量信息(包括参数)可能可用。这可以使用–vars列出:

# perf probe -x /lib/x86_64-linux-gnu/libc.so.6 --vars fopen
Available variables at fopen
 	@<_IO_vfscanf+15344>
 		char* filename
 		char* mode

输出显示fopen具有 filename 和 mode 变量。创建探针时可以添加以下内容:

perf probe -x /lib/x86_64-linux-gnu/libc.so.6 --add 'fopen filename mode'

Debuginfo可以通过-dbg或-dbgsym包提供。如果这在目标系统上不可用,但在另一个系统上,则其他系统可以用作参考系统,如前一节kprobes中所示。

参考资料

https://www.brendangregg.com/perf.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/331867.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PTA L1-043 阅览室

前言&#xff1a;内容包括四大模块&#xff1a;题目&#xff0c;代码实现&#xff0c;大致思路&#xff0c;代码解读 题目&#xff1a; 天梯图书阅览室请你编写一个简单的图书借阅统计程序。当读者借书时&#xff0c;管理员输入书号并按下S键&#xff0c;程序开始计时&#xf…

Java NIO学习(一):Java NIO概述

一、 IO 概述IO 的操作方式通常分为几种&#xff1a;同步阻塞 BIO、同步非阻塞 NIO、异步非阻塞 AIO。&#xff08;1&#xff09;在 JDK1.4 之前&#xff0c;我们建立网络连接的时候采用的是 BIO 模式。&#xff08;2&#xff09;Java NIO&#xff08;New IO 或 Non Blocking I…

【C语言】速刷日记

这里总结10道C语言经典题型问题&#xff0c;有兴趣可以刷刷看。1.递归问题12.递归问题23.短路求值问题4.字符数组定义问题5.二维数组元素访问问题6.指针问题7.二维数组地址问题8.前置与后置问题9.求1的个数问题10.求1的个数移位操作符1.递归问题1 给定 fun 函数如下&#xff0…

Fluid-架构详细解析

前言Fluid 是云原生分布式数据集编排和加速引擎&#xff0c;主要服务于云原生场景下的数据密集型应用&#xff0c;例如大数据应用、AI 应用等。其目标是为AI与大数据云原生应用提供一层高效便捷的数据抽象&#xff0c;将数据从存储抽象出来&#xff0c;以便实现&#xff1a;通过…

服务调用分布式session

目录一、nginx动静分离二、服务调用1、创建配置zmall-cart购物车模块2、创建配置zmall-order订单模块3、服务调用三、spring session实战1、什么是Spring Session2、为什么要使用Spring Session3、错误案例展示4、配置spring-session四、二级域名问题五、用户登录一、nginx动静…

从某种程度上来看,产业互联网是一次对于互联网的弥补和修正

如果对当下我们正在经历的这样一个时代进行一次定义的话&#xff0c;我更加愿意将其划归到产业互联网的范畴里。可能有人会说&#xff0c;这与产业互联网并无联系&#xff0c;因为从本质上来看&#xff0c;当下我们所经历的这样一个时代&#xff0c;其实是与互联网并没有太多联…

(深度学习快速入门)第五章第一节2:GAN经典案例之MNIST手写数字生成

获取pdf&#xff1a;密码7281 文章目录一&#xff1a;数据集介绍二&#xff1a;GAN简介&#xff08;1&#xff09;简介&#xff08;2&#xff09;损失函数三&#xff1a;代码编写&#xff08;1&#xff09;参数及数据预处理&#xff08;2&#xff09;生成器与判别器模型&#x…

Acwing---112.雷达设备

雷达设备1.题目2.基本思想3.代码实现1.题目 假设海岸是一条无限长的直线&#xff0c;陆地位于海岸的一侧&#xff0c;海洋位于另外一侧。 每个小岛都位于海洋一侧的某个点上。 雷达装置均位于海岸线上&#xff0c;且雷达的监测范围为 d&#xff0c;当小岛与某雷达的距离不超…

2023-02-09 mysql/innodb存储

前言 大家都知道 MySQL 的数据都是保存在磁盘的,那具体是保存在哪个文件呢?MySQL 存储的行为是由存储引擎实现的,MySQL 支持多种存储引擎,不同的存储引擎保存的文件自然也不同。InnoDB 是我们常用的存储引擎,也是 MySQL 默认的存储引擎。本文主要以 InnoDB 存储引擎展开讨…

centos7.6 设置防火墙

1、查看系统版本 cat /etc/redhat-release2、查看防火墙运行状态 systemctl status firewalld这里可以看到当前是未运行状态(inactive)。 3、关闭开机自启动防火墙 systemctl disable firewalld.service4、启动防火墙并查看状态&#xff0c;系统默认 22 端口是开启的。 sy…

云原生微服务应用平台 EDAS 2022 年度报告

作者&#xff1a;孤戈 最近一年来&#xff0c;随着我们的客户对于云技术的诉求从资源快速交付的服务&#xff0c;转变为对资源精益运用的服务。EDAS 团队结合公共云上所服务的企业类客户的几万个应用&#xff0c;选取了 8 个最具代表性的指标&#xff0c;进行了一次系统性的分…

进度条实时显示request下载文件的解决方案

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,科大讯飞比赛第三名,CCF比赛第四名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

Linux -文件打包和解压缩

1、概念 在 Windows 上最常见的不外乎这两种 .zip&#xff0c;.7z 后缀的压缩文件。而在 Linux 上面常见的格式除了以上两种外&#xff0c;还有 .rar&#xff0c;.gz&#xff0c;.xz&#xff0c;.bz2&#xff0c;.tar&#xff0c;.tar.gz&#xff0c;.tar.xz&#xff0c;*.tar…

python--turtle

前言 就随便练练&#xff0c;学习一下turtle库的使用 正文 1.语法学习 import turtle #导入库 turtle.showturtle() #画笔显示箭头 turtle.write("我是大帅逼") #写下字符串 turtle.forward(300) …

拦截器interceptor总结

拦截器一. 概念拦截器和AOP的区别&#xff1a;拦截器和过滤器的区别&#xff1a;二. 入门案例2.1 定义拦截器bean2.2 定义配置类2.3 执行流程2.4 简化配置类到SpringMvcConfig中一. 概念 引入&#xff1a; 消息从浏览器发送到后端&#xff0c;请求会先到达Tocmat服务器&#x…

C语言一维数组篇【下】——每日刷题经验分享

一维数组篇——每日刷题经验分享~&#x1f60e;前言&#x1f64c;有序序列插入一个整数 &#x1f60a;序列中删除指定数字 &#x1f60a;序列中整数去重小乐乐查找数字筛选法求素数总结撒花&#x1f49e;&#x1f60e;博客昵称&#xff1a;博客小梦~ &#x1f60a;最喜欢的座右…

【FFMPEG源码分析】从ffplay源码摸清ffmpeg框架(一)

ffplay入口 ffmpeg\fftools\ffplay.c int main(int argc, char **argv) {/*******************start 动态库加载/网络初始化等**************/int flags;VideoState *is;init_dynload();av_log_set_flags(AV_LOG_SKIP_REPEATED);parse_loglevel(argc, argv, options);/* regis…

SSJ-21A AC220V静态【时间继电器】

系列型号&#xff1a; SSJ-11B静态时间继电器&#xff1b;SSJ-21B静态时间继电器 SSJ-21A静态时间继电器&#xff1b;SSJ-22A静态时间继电器 SSJ-22B静态时间继电器SSJ-42B静态时间继电器 SSJ-42A静态时间继电器SSJ-41A静态时间继电器 SSJ-41B静态时间继电器SSJ-32B静态时间继电…

dev-c++解决中文输出乱码问题

之前写c程序老是出现编译输出乱码的问题&#xff0c;就去博客&#xff0c;百度查阅了一番找了找了办法。废话不多说直接上操作。 首先打开dev-c-》工具-》编译选项 在第一行输入 -fexec-charsetgbk//生成gbk格式 -fexec-charsetUFT-8//生成UFT-8格式 也可以输入UFT-8格式&…

获取主机RDP连接凭据

为了避免每次连接服务器都进行身份验证&#xff0c;经常使用RDP的用户可能勾选保存连接凭据&#xff0c;以便进行快速的身份验证。这些凭据都使用数据保护API以加密形式存储在windows的凭据管理器中&#xff0c;路径为“%USERPROFILE%\AppData\Local\Microsoft\Credentials”执…