文章目录

  • 0. bpftrace
    • 0.1 bpftrace组件
    • 0.2 bpftrace 帮助信息
    • 0.3 bpftrace 工具速览表
    • 0.4 bpftrace 探针
      • 0.4.1 tracepoint
      • 0.4.2 usdt
      • 0.4.3 kprobe和kretprobe
      • 0.4.4 uprobe和uretprobe
      • 0.4.5 software和hardware
      • 0.4.6 profile和interval
  • 1. 安装bpftrace
  • 2. bpftrace 工具
    • 2.1 bpftrace 编程
      • 2.1.1 bpftrace 用法
      • 2.1.2 程序结构
      • 2.1.3 探针格式
      • 2.1.4 变量
      • 2.1.5 控制流
        • 2.1.5.1 filter
        • 2.1.5.2 if 语句
        • 2.1.5.3 unroll 循环语句
      • 2.1.5 函数
    • 2.2 bpftrace 示例
      • 2.2.1 单行程序示例

0. bpftrace

Alastair 与2016.12创建了bpftrace。bpftrace 是一款基于BPF和BCC的开源跟踪器。其自带了许多多性能工具和支持文档,同时提供了一个高级编程语言环境,可以用来创建强大的单行程序和小工具。

0.1 bpftrace组件

在安装bpftrace的时候,其会存在以下的目录树。其中提供了工具的文档、man帮助文档、示例文件等等。

├── docs     # 参考手册 单行小程序指引
├── libbpf      # 库文件
├── src         # 前端
│   └── ast     #中间代码生成
├── man
│   ├── adoc
│   └── man8    # 帮助文档
├── README
├── INSTALL
└── tools       # 工具和实例

0.2 bpftrace 帮助信息

使用-h参数以获取帮助信息

[root@bogon bpftrace]# bpftrace -h
USAGE:bpftrace [options] filenamebpftrace [options] - <stdin input>bpftrace [options] -e 'program'OPTIONS:-B MODE        output buffering mode ('full', 'none')-f FORMAT      output format ('text', 'json')-o file        redirect bpftrace output to file-d             debug info dry run-dd            verbose debug info dry run-e 'program'   execute this program-h, --help     show this help message-I DIR         add the directory to the include search path--include FILE add an #include file before preprocessing-l [search]    list probes-p PID         enable USDT probes on PID-c 'CMD'       run CMD and enable USDT probes on resulting process--usdt-file-activationactivate usdt semaphores based on file path--unsafe       allow unsafe builtin functions-q             keep messages quiet-v             verbose messages--info         Print information about kernel BPF support-k             emit a warning when a bpf helper returns an error (except read functions)-kk            check all bpf helper functions-V, --version  bpftrace version--no-warnings  disable all warning messagesENVIRONMENT:BPFTRACE_STRLEN             [default: 64] bytes on BPF stack per str()BPFTRACE_NO_CPP_DEMANGLE    [default: 0] disable C++ symbol demanglingBPFTRACE_MAP_KEYS_MAX       [default: 4096] max keys in a mapBPFTRACE_CAT_BYTES_MAX      [default: 10k] maximum bytes read by cat builtinBPFTRACE_MAX_PROBES         [default: 512] max number of probesBPFTRACE_LOG_SIZE           [default: 1000000] log size in bytesBPFTRACE_PERF_RB_PAGES      [default: 64] pages per CPU to allocate for ring bufferBPFTRACE_NO_USER_SYMBOLS    [default: 0] disable user symbol resolutionBPFTRACE_CACHE_USER_SYMBOLS [default: auto] enable user symbol cacheBPFTRACE_VMLINUX            [default: none] vmlinux path used for kernel symbol resolutionBPFTRACE_BTF                [default: none] BTF fileEXAMPLES:
bpftrace -l '*sleep*'list probes containing "sleep"
bpftrace -e 'kprobe:do_nanosleep { printf("PID %d sleeping...\n", pid); }'trace processes calling sleep
bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }'count syscalls by process name

0.3 bpftrace 工具速览表

应用场景 工具名称 使用场景及用法
CPU execsnoop.bt

0.4 bpftrace 探针

类型 缩写 描述
tracepoint t 内核静态插桩点
usdt U 用户静态插桩点
kprobe k 内核动态函数插桩点
kretprobe kr 内核动态函数返回值插桩点
uprobe u 用户动态函数插桩点
uretprobe ur 用户动态函数返回值插桩点
software s 内核软件事件
hardware h 硬件基于计数器的插桩
profile p 对全部cpu进行采样
interval i 一个cpu上周期性报告
BEGIN 启动
END 退出

0.4.1 tracepoint

tracepoint 探针类型会对内核跟踪点进行插桩,格式如下:

# tracepoint_name 是跟踪点全名,包括用来将跟踪点所在列和事件名字分割开的冒号
tracepoint:tracepoint_name

跟踪点通常是带有参数的:bpftrace 可以通过内置变量args来访问这些参数信息。假如说我们访问的跟踪点有一个代表数据包长度的参数,名称为len,我们可以用agrs->len来访问这个变量。而一个跟踪点具体具有哪些参数则是可以bpftrace的-lv参数来进行查看:

[root@bogon ik]# bpftrace -lv tracepoint:syscalls:sys_enter_read
tracepoint:syscalls:sys_enter_readint __syscall_nrunsigned int fdchar * bufsize_t count

我们可以看到这里跟man参数文档描述的其实是不一致的,这里会多一个系统调用号__syscall_nr

ssize_t read(int fd,void *buf,size_t count)

0.4.2 usdt

udst探针对用户态静态探针点进行插桩。格式如下:

usdt:binary_path:probe_name
usdt:libary_path:probe_name
usdt:binary_path:namespace:probe_name
usdt:libary_path:namespace:probe_name

比如说我们定义了如下的函数:

// 会编译成可执行文件test
namespace bpf_method{void bpf_test();
}

那么对这个函数来说,其探针可以表述usdt:./test:bpf_method:bpf_test。另外,如果是在不确定的话,我们可以使用-l参数列出当前二进制文件之中所有可用的usdt探针。

# 这里存疑,笔者并没有实验成功
bpftrace -l 'usdt:/usr/local/cpython/python'

除此之外,我们还可以使用 -p pid的方式列出正在运行的程序其支持usdt类型探针:

bpftrace -lp 2266 | grep usdtusdt:/proc/2266/root/usr/lib64/libc-2.28.so:libc:memory_sbrk_more
usdt:/proc/2266/root/usr/lib64/libc-2.28.so:libc:memory_tcache_double_free
usdt:/proc/2266/root/usr/lib64/libc-2.28.so:libc:memory_tunable_tcache_count
usdt:/proc/2266/root/usr/lib64/libc-2.28.so:libc:memory_tunable_tcache_max_bytes
usdt:/proc/2266/root/usr/lib64/libc-2.28.so:libc:memory_tunable_tcache_unsorted_limit
usdt:/proc/2266/root/usr/lib64/libc-2.28.so:libc:setjmp
[...]

0.4.3 kprobe和kretprobe

这种探针类型用于内核的动态插桩,格式如下:

kprobe:function_name
kretprobe:function_name

kprobe对函数的开始进行插桩,其参数arg0,arg1,arg2…是进入函数时的参数,类型均为64位无符号整数。如果其是指向C结构体的指针,可以进行强制转换; kretprobe对函数的结束进行插桩,其内置参数retval是函数的返回值,类型永远是64位无符号整型,如果和上述整型不一致,需要通过类型强制转换为对应的类型

0.4.4 uprobe和uretprobe

这种探针类型用于用户态的动态插桩,格式如下:

uprobe:binary_path:function_name
uprobe:libary_path:function_name
uretprobe:binary_path:function_name
uretprobe:libary_path:function_name

uprobe对函数的开始进行插桩,其参数arg0,arg1,arg2…是进入函数时的参数,类型均为64位无符号整数。如果其是指向C结构体的指针,可以进行强制转换; uretprobe对函数的结束进行插桩,其内置参数retval是函数的返回值,类型永远是64位无符号整型,如果和上述整型不一致,需要通过类型强制转换为对应的类型

0.4.5 software和hardware

这些探针的类型是预先定义好的软件事件和硬件事件,类型如下:

software:event_name
software:event_name:count
hardware:event_name
hardware:event_name:count

这些事件跟跟踪点是类似的,不过更适合于基于计数器的指标和基于采样的探测。由于事件的频闭可能很高,所以这里存在一个count字段,当每发生count此事件之后,才会触发一次探针。如果没有指定count,则会采用默认的频率。

0.4.6 profile和interval

这些是基于定时器的事件,格式如下:

profile:hz:rate
profile:s:rate
profile:ms:rate
profile:us:rate
interval:s:rate
interval:ms:rate

profile类型会在全部cpu之上进行激活,可以用作对CPU的使用进行采样;interval类型只在单个CPU上激活,可以用于周期性的打印输出。比如说profile:hz:100就表示100hz周期会激活一次对CPU使用的采样。

1. 安装bpftrace

  • centos
curl https://repos.baslab.org/bpftools.repo --output /etc/yum.repos.d/bpftools.reposudo yum install bpftrace bpftrace-tools
  • ubuntu
sudo apt-get update
sudo apt-get install bpftrace

2. bpftrace 工具

2.1 bpftrace 编程

下面是个bpftrace编程的例子,其展示了bpftrace 编程的基本结构:

# 指定解释器
#!/usr/local/bin/bpftrace# 定义的探针1
kprobe:vfs_read
{# 将当前进程调用vfs_read 的时间放入一个名为start的map之中@start[tid] = nsecs;
}# 定义的探针2
kretprobe:vfs_read
# 过滤start 这个map,获取tid这一项
/@start[tid]/
{# 获取执行时间$duration_us = (nsecs - @start[tid]) / 1000;# 执行时间放入直方图的bucket之中@us = hist($duration_us);# 删除map中这个元素delete(@start[tid]);
}

下面是上面这个文件的输出展示,vfs_exec_time.bt是存放上面代码的文件,bt后缀只是为了辨别:

[root@bogon bpftrace]# bpftrace vfs_exec_time.bt
Attaching 2 probes...
^C
@start[6165]: 6928640480723
@us:
[0]                  185 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
[1]                   56 |@@@@@@@@@@@@@@@                                     |
[2, 4)                91 |@@@@@@@@@@@@@@@@@@@@@@@@@                           |
[4, 8)                44 |@@@@@@@@@@@@                                        |
[8, 16)                1 |                                                    |
[16, 32)               3 |                                                    |
[32, 64)               2 |                                                    |
[64, 128)              0 |                                                    |
[128, 256)             0 |                                                    |
[256, 512)             0 |                                                    |
[512, 1K)              0 |                                                    |
[1K, 2K)               1 |                                                    |

2.1.1 bpftrace 用法

bpftrace主要有单行程序和批处理两种用法:

# bpftrace 单行程序
bpftrace -e 'program'

-e 参数表示bpftrace会执行program,并开始跟踪其中定义的所有时间。程序会持续运行,直达Ctrl+C组合键被按下或者程序显示的调用exit()为止。

bpftrace file.bt

程序还可被保存到一个文件之中,然后使用bpftrace来执行。或者我们也可以使用chmod +x file.bt 来赋予文件可执行权限,这样就可以像其他任何程序一样运行。

2.1.2 程序结构

bpftrace程序的结构是一系列探针+对应的动作,当探针被激活后,相应的动作就会被执行。

probe { actions }

: 动作
动作既可以是单条语句,也可以是使用分号分割的多条语句{ action1,action2、action3... }

probe /filter_pattern/ { actions }

: 过滤器
filter_pattern是个布尔表达式,其会决定一个动作是否被执行,比如说pid==123表示只有进程123触碰探针才会执行动作。同时,在布尔表达式中也可以运用 &&||等布尔运算符

如果我们希望对多个探针实行同一动作处理,可以在探针之间加上,来分割,如下:

probe1,probe2,... { actions }

同时,探针也支持通配符,如下:

# 匹配probe1、probeabc等等...
probe* { actions }

2.1.3 探针格式

探针以类型名字开始,然后是一系列以:为分隔的标识符:

# ...表示可选
type:identifier1[:identifier2[...]]

一般来说,内核探针kprobe探针类型对内核态函数进行插桩,只需要一个标识符:内核函数名。uprobe探针类型对用户态函数进行插桩,需要两个标识符: 二进制文件的路径和函数名

2.1.4 变量

在bpftrace之中有三种类型的变量:

  • 内置变量:由bpftrace定义,通常是个只读的信息源,主要有以下几种:
变量 作用
pid 进程id
comm 进程名称
nsecs 时间戳(纳秒)
curtask 当前线程的 task_struct 结构体
  • 临时变量:可以用于临时的计算,以$作为前缀
# 定义变量x并赋值1
$x = 1
  • 映射表变量:使用BPF映射表来存储对象,名字带有@前缀,可以用于全局存储,在不同动作之间传递数据。
# 定义全局变量a 并赋值1
probe1 { @a = 1;}# 定义array这个映射表,其为数组,给数组中对应的元素赋值
probe2 { @array[tid] = nsecs}# 复合数组映射表
probe2 { @muti_array[pid,tid] = nsecs}

2.1.5 控制流

bpftrace支持三种控制流:filter、ternarg和if语句,这些都依靠布尔表达式来有条件的改变对程序执行的流向。

2.1.5.1 filter

probe /filter_pattern/ { actions }

: 过滤器
filter_pattern是个布尔表达式,其会决定一个动作是否被执行,比如说pid==123表示只有进程123触碰探针才会执行动作。同时,在布尔表达式中也可以运用 &&||等布尔运算符

2.1.5.2 if 语句

bpftrace的 if 语法如下:

if (test) { actions
}if (test) { actions
} else {other_actions
}

2.1.5.3 unroll 循环语句

由于bpftrace运行在受限的环境中,所以这里使用了unroll语句来保证循环时有限的。

2.1.5 函数

bpftrace 的内置函数主要如下:

函数 类型 作用
exit() 普通函数 退出bpftrace
str(char*) 普通函数 输出一个指针,返回字符串
system(format[,arguments …]) 普通函数 在shell之中运行命令
count() 映射表函数 累计统计
sum($var) 映射表函数 求和
hist($var) 映射表函数 直方图展示
delete($var) 映射表函数 删除映射表元素

2.2 bpftrace 示例

2.2.1 单行程序示例

  • hello world:
bpftrace -e 'BEGIN { printf("hello world!\n"); }'
[root@bogon bpftrace]# bpftrace -e 'BEGIN { printf("hello world!\n"); }'
Attaching 1 probe...
hello world!
  • 展示系统谁在执行什么命令:
bpftrace -e 'tracepoint:syscalls:sys_enter_execve { printf("%s -> %s\n", comm, str(args->filename)); }'
# 在这里,笔者打开了另外一个中断,执行了ls 命令,也就是这里最后一行。
[root@bogon bpftrace]# bpftrace -e 'tracepoint:syscalls:sys_enter_execve { printf("%s -> %s\n", comm, str(args->filename)); }'
Attaching 1 probe...
ksmtuned -> /usr/bin/awk
ksmtuned -> /usr/bin/pgrep
ksmtuned -> /usr/bin/awk
ksmtuned -> /usr/bin/sleep
bash -> /usr/bin/ls

: 什么是ksmtuned?
KSM 是一种节省内存的重复数据删除功能,由 CONFIG_KSM=y 启用,在 2.6.32 中添加到 Linux 内核中。
KSM 最初是为与 KVM(在那里称为内核共享内存)一起使用而开发的,通过共享它们之间的公共数据,将更多虚拟机放入物理内存中。但它对于生成相同数据的许多实例的任何应用程序都非常有用。

  • 展示新进程的创建:
bpftrace -e 'tracepoint:syscalls:sys_enter_execve { join(args->argv); }'
# 下面代码中的第一行展示了笔者在另外的终端运行ls的过程,其余代码则是KSM机制所带来的
[root@bogon bpftrace]# bpftrace -e 'tracepoint:syscalls:sys_enter_execve { join(args->argv); }'
Attaching 1 probe...
ls --color=auto
awk /^(MemFree|Buffers|Cached):/ {free += $2}; END {print free} /proc/meminfo
pgrep -d   -- ^qemu(-(kvm|system-.+)|:.{1,11})$
awk { sum += $1 }; END { print 0+sum }
sleep 60
  • 按照进程统计文件的开启情况:
bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s %s\n", comm, str(args->filename)); }'
[root@bogon bpftrace]# bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s %s\n", comm, str(args->filename)); }'
Attaching 1 probe...
in:imjournal /run/log/journal/29545612d2ce4e319e6a9edaa0cff1d3/system.journa
systemd-journal /
systemd-journal sys
systemd-journal bus

: 什么是systemd-journal?
systemd-journald 是一个收集并存储各类日志数据的系统服务。 它创建并维护一个带有索引的、结构化的日志数据库, 并可以收集来自各种不同渠道的日志:

  1. 通过 kmsg 收集内核日志
  2. 通过 libc 的 syslog(3) 接口收集系统日志
  3. 通过 本地日志接口 sd_journal_print(3) 收集结构化的系统日志
  4. 捕获服务单元的标准输出(STDOUT)与标准错误(STDERR)
  5. 通过内核审计子系统收集审计记录
  • 按照程序统计系统调用次数:
bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }'
[root@bogon bpftrace]# bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }'
Attaching 1 probe...
^C
@[NetworkManager]: 19
@[tuned]: 24
@[sshd]: 24
@[irqbalance]: 40
@[bpftrace]: 67
@[gdbus]: 93
@[in:imjournal]: 673
@[systemd-journal]: 7752
...
  • 按照探针名字统计系统调用次数:
bpftrace -e 'tracepoint:syscalls:sys_enter_* { @[probe] = count(); }'
# 下面的代码会统计运行期间符合‘tracepoint:syscalls:sys_enter_*’ 正则匹配的所有探针的调用次数
[root@bogon bpftrace]# bpftrace -e 'tracepoint:syscalls:sys_enter_* { @[probe] = count(); }'
Attaching 341 probes...
^C
@[tracepoint:syscalls:sys_enter_waitid]: 1
@[tracepoint:syscalls:sys_enter_getpid]: 1
@[tracepoint:syscalls:sys_enter_timerfd_create]: 1
@[tracepoint:syscalls:sys_enter_socket]: 1
@[tracepoint:syscalls:sys_enter_rt_sigreturn]: 1
@[tracepoint:syscalls:sys_enter_munmap]: 2
@[tracepoint:syscalls:sys_enter_mmap]: 2
@[tracepoint:syscalls:sys_enter_sendmsg]: 5
@[tracepoint:syscalls:sys_enter_writev]: 5
@[tracepoint:syscalls:sys_enter_ftruncate]: 5
@[tracepoint:syscalls:sys_enter_inotify_add_watch]: 5
...
  • 按照进程统计系统调用数量:
bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[pid, comm] = count(); }'
[root@bogon bpftrace]# bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[pid, comm] = count(); }'
Attaching 1 probe...
^C
@[3126, gpg-agent]: 1
@[3171, gpg-agent]: 1
@[3139, gpg-agent]: 1
@[985, sssd]: 1
@[1084, tuned]: 2
@[2848, gmain]: 3
@[2751, gmain]: 4
@[698, systemd-journal]: 2178
...
  • 按照进程展示运行期间内总的读取字节数:
bpftrace -e 'tracepoint:syscalls:sys_exit_read /args->ret/ { @[comm] = sum(args->ret); }'
[root@bogon bpftrace]# bpftrace -e 'tracepoint:syscalls:sys_exit_read /args->ret/ { @[comm] = sum(args->ret); }'
Attaching 1 probe...
^C
@[sshd]: 54
@[in:imjournal]: 63
@[gmain]: 188
@[sedispatch]: 756
@[systemd-journal]: 18056
  • 按照进程展示read 返回结果大小的分布:
bpftrace -e 'tracepoint:syscalls:sys_exit_read { @[comm] = hist(args->ret); }'
[root@bogon ik]# bpftrace -e 'tracepoint:syscalls:sys_exit_read { @[comm] = hist(args->ret); }'
Attaching 1 probe...
^C
@[sshd]:
[2, 4)                 1 |@@@@@@@@@@@@@@@@@@@@@@@@@@                          |
[4, 8)                 0 |                                                    |
[8, 16)                0 |                                                    |
[16, 32)               1 |@@@@@@@@@@@@@@@@@@@@@@@@@@                          |
[32, 64)               2 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
...
  • 展示进程的磁盘IO尺寸:
bpftrace -e 'tracepoint:block:block_rq_issue { printf("%d %s %d\n", pid, comm, args->bytes); }'
[root@bogon ik]# bpftrace -e 'tracepoint:block:block_rq_issue { printf("%d %s %d\n", pid, comm, args->bytes); }'
Attaching 1 probe...
# pid name bytes
251 kworker/2:1H 4096
284 kworker/4:1H 0
251 kworker/2:1H 0
288 kworker/7:1H 14848
288 kworker/7:1H 0
3684 kworker/2:0 8
3684 kworker/2:0 8
  • 按照进程展示页换入数量:
bpftrace -e 'software:major-faults:1 { @[comm] = count(); }'
[root@bogon ik]# bpftrace -e 'software:major-faults:1 { @[comm] = count(); }'
Attaching 1 probe...
^C
@[sssd_nss]: 2
  • 按照进程展示缺页中断数量:
bpftrace -e 'software:faults:1 { @[comm] = count(); }'
[root@bogon ik]# bpftrace -e 'software:faults:1 { @[comm] = count(); }'
Attaching 1 probe...
^C
@[systemd-journal]: 5
@[in:imjournal]: 5
  • 对pid为xxx的进程以yyhz抓取其用户态的调用栈信息:
bpftrace -e 'profile:hz:yy /pid == xxx/ { @[ustack] = count(); }'

bpftrace 指南相关推荐

  1. Linux内核跟踪eBPF:bpftrace 参考指南

    bpftrace Reference Guide 推荐阅读:Linux内核跟踪eBPF:bpftrace一行教程 For a reference summary, see the README.md ...

  2. bpftrace参考指南

    目录 前言 一.名词解释 二.使用示范 1. help 2. Hello World 3. One-Liners程序 4. 列出可跟踪点 5. 调试输出-d 6. 输出详情 7. 预处理选项 8. 环 ...

  3. 深入浅出 eBPF: (Linux/Kernel/XDP/BCC/BPFTrace/Cillium)

    [BPF入门系列-1]eBPF 技术简介 | 深入浅出 eBPF[BPF入门系列-1]eBPF 技术简介https://www.ebpf.top/post/bpf_intro_blog/ 目录 eBP ...

  4. Linux 内核观测技术 eBPF 中文入门指南

    公众号关注 「奇妙的 Linux 世界」 设为「星标」,每天带你玩转 Linux ! 很早前就想写一篇关于 eBPF 的文章,但是迟迟没有动手,这两天有点时间,所以就来写一篇.这文章主要还是简单的介绍 ...

  5. 强劲的Linux Trace工具:bpftrace (DTrace 2.0) for Linux 2018

    Original:阿里 姜弋内核月谈 译者: 姜弋 译者注:原作者是大名鼎鼎的性能分析专家:Brendan Gregg,现在工作在Netflix,之前工作在Sun,在Sun公司的时候,他就做了大量的性 ...

  6. 神奇的BPF四 用bpftrace 开个后门

    一 前言 前面的文章聊到bpftrace,这是个强大简洁的编写bpf程序的利器,内部的语法看起来比较容易,功能一点也不弱,比如 我们想查看现在系统中谁在执行什么程序: [root@localhost ...

  7. io_uring 使用教程| io_uring 完全指南 | io_uring 实践指导 | io_uring 资料参考

    io_uring 完全指南地图 背景 io_uring 是 2019 年做的,与 kernel 5.1 发布.后续打了很多补丁,比较重要的在 2020年5月之后基本达到了一个很好的可用性(为什么这么说 ...

  8. 超详细中文预训练模型ERNIE使用指南-源码

    作者 | 高开远,上海交通大学,自然语言处理研究方向 最近在工作上处理的都是中文语料,也尝试了一些最近放出来的预训练模型(ERNIE,BERT-CHINESE,WWM-BERT-CHINESE),比对 ...

  9. 入门指南目录页 -PaddlePaddle 飞桨 入门指南 FAQ合集-深度学习问题

    入门指南目录页 -PaddlePaddle 飞桨 入门指南 FAQ合集 GT_Zhang关注 0.1012019.08.01 18:43:34字数 1,874阅读 795 Hi,欢迎各位来自Paddl ...

最新文章

  1. VS2010 编译 QT4.8.7 x64
  2. 逐步创建Data Guard
  3. 流量复制_详解Linux系统流量复制--gor、tcpcopy、nginx模块流量复制等
  4. 那个悲伤的朋友,去了一趟菜场竟然活过来了
  5. ssh: Could not resolve hostname gitcafe.com: nodename nor servname provided, or not known
  6. 2015workshop-age 的txt 生成过程
  7. 计算机网络学习socket--day3
  8. Determining IP information for eth0...failed
  9. 2018年阿里巴巴前端开源项目汇总
  10. etcd教程(二)—clientv3简单使用
  11. mac 桌面显示服务器,隐藏 Mac 桌面内容的三种方法 | 一日一技 · Mac
  12. 解决ubuntu18.04无法连接wifi问题
  13. android 11.0 12.0app应用卸载黑名单
  14. java-zxing扫描二维码和条形码(一维码)
  15. 用Python与Watson,将《魔戒》甘道夫的性格可视化!
  16. opencv 学习笔记3.1 高斯双边滤波(EPF) 常用于美颜
  17. Android Flurry使用说明
  18. 学习laravel5,Win7安装Composer-Setup.exe,出错ERR_CONNECTION:Unable to connect to getcomposer.org
  19. QT 读取扫描枪数据
  20. 我用 Python 处理3万多条数据,只要几秒钟……

热门文章

  1. 【云速建站】让你轻轻松松建立属于自己的网店
  2. 机器语言对不同型号的计算机来说一般是不同的
  3. 股指期货的基差为负值说明什么(股指期货的基差为负值说明什么问题)
  4. 我为什么相信以貌取人
  5. Android-0.IPC相关简介
  6. 华为联合教指委发布《物联网实践系列教材》
  7. 频繁跳槽是否能够快速升职呢?
  8. oracle存储过程和触发器结合database link的实例
  9. 实验一 信号、系统及系统响应
  10. 【MySQL】数据处理(数据的删除三种方法概念)