[EBPF] 实时捕获DM数据库是否存在SQL阻塞

1. 介绍

eBPF(extened Berkeley Packet Filter)是一种内核技术,它允许开发人员在不修改内核代码的情况下运行特定的功能。eBPF 的概念源自于 Berkeley Packet Filter(BPF),后者是由贝尔实验室开发的一种网络过滤器,可以捕获和过滤网络数据包。

eBPF 可以在不侵入任何业务代码的基础上实现应用的可观测性。但是 eBPF 对 Linux 内核版本是有一定要求的(4.14 以上)。

2. 工作原理

eBPF 的工作原理主要分为三个步骤:加载、编译和执行。

eBPF 需要在内核中运行。这通常是由用户态的应用程序完成的,它会通过系统调用来加载 eBPF 程序。在加载过程中,内核会将 eBPF 程序的代码复制到内核空间。

eBPF 程序需要经过编译和执行。这通常是由Clang/LLVM的编译器完成,然后形成字节码后,将用户态的字节码装载进内核,并通过一个JIT编译步骤将程序的通用字节码转换为机器特定指令集,以优化程序的执行速度。

在内核中运行时,eBPF 程序通常会挂载到一个内核钩子(hook)上,以便在特定的事件发生时被执行。例如,可以将 eBPF 程序挂载到网络协议栈的某个位置,以便在收到网络数据包时被执行。

最后,eBPF 程序还需要经过内核安全机制的检查。这是为了确保 eBPF 程序不会破坏内核的稳定性和安全性。在检查过程中,内核会对 eBPF 程序的代码进行分析,以确保它不会进行恶意操作,如系统调用、内存访问等。如果 eBPF 程序通过了内核安全机制的检查,它就可以在内核中正常运行了。在运行过程中,eBPF 程序可以访问内核的数据结构,并通过内核接口与其他组件进行交互。例如,eBPF 程序可以捕获网络数据包,并通过内核接口将它们转发给用户态的应用程序。总之,eBPF 的工作原理是通过动态加载、执行和检查无损编译过的代码来实现的。

3.环境介绍

名称版本
linux版本(centos8.5)4.18.0-348.el8.x86_64
DM88.1.4.27
pythonPython 3.6.8

4.安装环境

4.1检查环境

CONFIG_DEBUG_INFO_BTF=y必须项,否则就是操作系统不支持

[root@localhost opt]# uname -r
4.18.0-348.el8.x86_64
[root@localhost opt]# cat /boot/config-`uname -r` | grep CONFIG_DEBUG_INFO_BTF
CONFIG_DEBUG_INFO_BTF=y

4.2安装依赖包

[root@localhost opt]# dnf install -y bison cmake ethtool flex git iperf3 libstdc++-devel python3-netaddr python3-pip gcc gcc-c++ make zlib-devel elfutils-libelf-devel
[root@localhost opt]# dnf install -y clang clang-devel llvm llvm-devel llvm-static ncurses-devel
[root@localhost opt]# dnf -y install netperf
[root@localhost opt]# pip3 install pyroute2
[root@localhost opt]# ln -s /usr/bin/python3 /usr/bin/python

4.3安装并编译bcc

[root@localhost opt]# git clone https://github.com/iovisor/bcc.git
[root@localhost opt]# mkdir bcc-build
[root@localhost opt]# cd bcc-build/
[root@localhost opt]# cmake ../bcc -DCMAKE_INSTALL_PREFIX=/usr -DENABLE_LLVM_SHARED=1
[root@localhost opt]# make -j10
[root@localhost opt]# make install 

4.4添加环境变量

安装后,可以将 bcc 目录添加到$PATH,可以将其添加到 ~/.bashrc

[root@localhost opt]# vim ~/.bashrc
bcctools=/usr/share/bcc/tools
export PATH=$bcctools:$PATH
[root@localhost opt]# source ~/.bashrc

4.5安装DM并初始化实例

此步骤忽略

5.思路

5.1模拟阻塞场景

建表sql

create table lock_test01(id int primary key, name varchar(20));
create table lock_test02(id int primary key, name varchar(20));insert into lock_test01(id, name) values(1, '1cheng');
insert into lock_test01(id, name) values(2, '1gao');insert into lock_test02(id, name) values(1, '2cheng');
insert into lock_test02(id, name) values(2, '2gao');

阻塞场景

-- Session A 执行insert 不提交
insert into "SYSDBA"."LOCK_TEST01"("ID", "NAME")  VALUES(3, '3zzzz');
-- Session B 执行insert  会发生阻塞
insert into "SYSDBA"."LOCK_TEST01"("ID", "NAME")  VALUES(3, '4zzzz');

5.2判断堆栈中的核心函数

下面的堆栈是阻塞SQL的线程堆栈

Thread 127 (Thread 0x7fb29dfeb700 (LWP 19089)):
#0  0x00007fb64d8a77e8 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
#1  0x0000000000752f72 in os_event2_wait_timeout (event=event@entry=0x7fb6315e1fb0, s_time=s_time@entry=30) at /home/dmops/build/svns/1725521374498/os/osevent2.c:303
#2  0x0000000001e571cb in uevent_wait_timeout (env=env@entry=0x7fb29dfe6020, event=event@entry=0x7fb6315e1fa8, s_time=s_time@entry=30) at /home/dmops/build/svns/1725521374498/knl/uevent.c:111
#3  0x0000000000ccc186 in trx4_waiting_timeout (env=env@entry=0x7fb29dfe6020, trx=trx@entry=0x7fb6315e0898, w_time=w_time@entry=3) at /home/dmops/build/svns/1725521374498/trx/trx4.c:14642
#4  0x0000000000ccc32a in trx4_waiting_interval (env=env@entry=0x7fb29dfe6020, trx=trx@entry=0x7fb6315e0898, s_time=s_time@entry=0) at /home/dmops/build/svns/1725521374498/trx/trx4.c:14217
#5  0x0000000000cd69e4 in trx4_waiting (env=env@entry=0x7fb29dfe6020, trx=trx@entry=0x7fb6315e0898, s_time=s_time@entry=0) at /home/dmops/build/svns/1725521374498/trx/trx4.c:14383
#6  0x00000000018446f0 in nins2_check_second_unique (memobj=memobj@entry=0x7fb2e000d3b8, trx=trx@entry=0x7fb6315e0898, ptx=ptx@entry=0x7fb29dfdd2c0, pbc=pbc@entry=0x7fb29dfdcf30, bcur=bcur@entry=0x7fb29dfdce90, key=key@entry=0x7fb34c417a60, desc=desc@entry=0x7fb2ee14c098, tableid=tableid@entry=1017, search_mode=search_mode@entry=2, need_lock_row=need_lock_row@entry=1, cflt_rowid=cflt_rowid@entry=0x0, need_modify=need_modify@entry=0x7fb29dfdfb6c, pll_index_fill=pll_index_fill@entry=0) at /home/dmops/build/svns/1725521374498/op/nins2.c:8616
#7  0x0000000001847789 in nins2_second_unique_search_and_check (memobj=memobj@entry=0x7fb2e000d3b8, trx=trx@entry=0x7fb6315e0898, ptx=ptx@entry=0x7fb29dfdd2c0, pbc=pbc@entry=0x7fb29dfdcf30, index=index@entry=0x7fb2ee14bd70, table=table@entry=0x7fb2ee14aae8, key=key@entry=0x7fb34c417a60, need_lock_row=need_lock_row@entry=1, search_mode=search_mode@entry=2, desc=desc@entry=0x7fb2ee14c098, rec_len=19, rowid=rowid@entry=4, ign_cflt=ign_cflt@entry=0, cflt_rowid=cflt_rowid@entry=0x0, need_modify=need_modify@entry=0x7fb29dfdfb6c, bcur=bcur@entry=0x7fb29dfdce90, pll_index_fill=pll_index_fill@entry=0) at /home/dmops/build/svns/1725521374498/op/nins2.c:10126
#8  0x0000000001848fd9 in nins2_second_unique_insert_low (memobj=memobj@entry=0x7fb2e000d3b8, trx=0x7fb6315e0898, ptx=0x7fb29dfdd2c0, pbc=0x7fb29dfdcf30, index=index@entry=0x7fb2ee14bd70, table=0x7fb2ee14aae8, tuple=tuple@entry=0x7fb34c417998, key=key@entry=0x7fb34c417a60, need_lock_row=need_lock_row@entry=1, search_mode=search_mode@entry=2, n_rol_len_fixed_part=n_rol_len_fixed_part@entry=45, rowid=rowid@entry=4, with_trxid=with_trxid@entry=0, ign_cflt=ign_cflt@entry=0, cflt_rowid=cflt_rowid@entry=0x0, need_modify=need_modify@entry=0x7fb29dfdfb6c, bcur=bcur@entry=0x7fb29dfdce90, pll_index_fill=pll_index_fill@entry=0, org_trx_id_out=org_trx_id_out@entry=0x0) at /home/dmops/build/svns/1725521374498/op/nins2.c:10222
#9  0x00000000018492c5 in nins2_second_unique_insert (memobj=memobj@entry=0x7fb2e000d3b8, trx=<optimized out>, ptx=<optimized out>, pbc=<optimized out>, index=index@entry=0x7fb2ee14bd70, table=<optimized out>, tuple=0x7fb34c417998, key=0x7fb34c417a60, need_lock_row=1, search_mode=2, n_rol_len_fixed_part=45, rowid=4, ign_cflt=0, cflt_rowid=0x0, need_modify=0x7fb29dfdfb6c, bcur=0x7fb29dfdce90, pll_index_fill=0) at /home/dmops/build/svns/1725521374498/op/nins2.c:10267
#10 0x0000000001849a39 in nins2_index_insert_entry_low (memobj=memobj@entry=0x7fb2e000d3b8, trx=<optimized out>, ptx=ptx@entry=0x7fb29dfdd2c0, pbc=pbc@entry=0x7fb29dfdcf30, index=index@entry=0x7fb2ee14bd70, tuple=tuple@entry=0x7fb34c417998, key=0x7fb34c417998, key@entry=0x7fb34c417a60, need_lock_row=1279359584, need_lock_row@entry=1, search_mode=1, search_mode@entry=2, n_rol_len_fixed_part=2, n_rol_len_fixed_part@entry=45, rowid=0x7fb20000002d, rowid@entry=0x7fb29dfdff50, ign_cflt=4, ign_cflt@entry=0, cflt_rowid=cflt_rowid@entry=0x0, need_modify=0x0, need_modify@entry=0x7fb29dfdfb6c, table=0x7fb29dfdfb6c, table@entry=0x7fb2ee14aae8, with_rowid=2650656400, with_rowid@entry=0, vm_node=0x7fb300000000, vm_node@entry=0x7fb34c416fd0, bcur=bcur@entry=0x7fb29dfdce90, pll_index_fill=0) at /home/dmops/build/svns/1725521374498/op/nins2.c:10508
#11 0x000000000185c1f8 in nins2_index_insert_entry (env=0x7fb29dfe6020, memobj=0x7fb2e000d3b8, vm=vm@entry=0x7fb2e000d350, index=index@entry=0x7fb2ee14bd70, tuple=0x7fb34c417998, key=key@entry=0x7fb34c417a60, need_lock_low=1, n_rol_len_fixed_part=45, rowid=rowid@entry=0x7fb29dfdff50, ign_cflt=ign_cflt@entry=0, cflt_rowid=cflt_rowid@entry=0x0, need_modify=need_modify@entry=0x7fb29dfdfb6c, table=0x7fb2ee14aae8, with_rowid=0, vm_node=vm_node@entry=0x7fb34c416fd0) at /home/dmops/build/svns/1725521374498/op/nins2.c:11889
#12 0x000000000185ceea in nins2_exec_insert_low (nins2_vm=nins2_vm@entry=0x7fb34c416fd0) at /home/dmops/build/svns/1725521374498/op/nins2.c:12796
#13 0x000000000185da5f in nins2_exec_insert (nins2_vm=nins2_vm@entry=0x7fb34c416fd0) at /home/dmops/build/svns/1725521374498/op/nins2.c:13492
#14 0x000000000186077f in nins2_exec (nins2_vm=0x7fb34c416fd0) at /home/dmops/build/svns/1725521374498/op/nins2.c:18904
#15 0x000000000195eab8 in vm_run_low (vm=vm@entry=0x7fb2e000d350) at /home/dmops/build/svns/1725521374498/op/vm.c:6115
#16 0x000000000195ef30 in vm_run (vm=vm@entry=0x7fb2e000d350) at /home/dmops/build/svns/1725521374498/op/vm.c:6196
#17 0x000000000195f080 in vm_run_pln_low (env=env@entry=0x7fb29dfe6020, stmt=stmt@entry=0x7fb2e000c8f0, pln=pln@entry=0x7fb2ee138ac8, ret_ident_flag=ret_ident_flag@entry=0 '\000', n_ret_col=n_ret_col@entry=0, ret_col_ident=ret_col_ident@entry=0x0, err_desc=err_desc@entry=0x0) at /home/dmops/build/svns/1725521374498/op/vm.c:11602
#18 0x0000000001fae1d0 in ntsk_process_exec_low (env=env@entry=0x7fb29dfe6020, stmt=0x7fb2e000c8f0, pln=pln@entry=0x7fb2ee138ac8, ret_ident_flag=ret_ident_flag@entry=0 '\000', n_ret_col=<optimized out>, ret_col_ident=0x0, dlck_reprepare=dlck_reprepare@entry=0x7fb29dfe46bc) at /home/dmops/build/svns/1725521374498/mgr/ntsk.c:12603
#19 0x0000000001fb2256 in ntsk_process_prepare_and_exec (env=env@entry=0x7fb29dfe6020, sess=sess@entry=0x7fb2e00110f0, msg_in=msg_in@entry=0x7fb2e00029a8 "", stmtsql_out=stmtsql_out@entry=0x7fb29dfe57c8) at /home/dmops/build/svns/1725521374498/mgr/ntsk.c:13063
#20 0x0000000001fde785 in ntsk_process_cop (env=0x7fb29dfe6020, task=<optimized out>) at /home/dmops/build/svns/1725521374498/mgr/ntsk.c:21389
#21 0x0000000001e5b755 in uthr_db_main_for_sess (sess2=0x7fb2e00110f0) at /home/dmops/build/svns/1725521374498/knl/uthr.c:1367
#22 0x00007fb64d8a117a in start_thread () from /lib64/libpthread.so.0
#23 0x00007fb64ccb5dc3 in clone () from /lib64/libc.so.6
  1. 头部 pthread_cond_timedwait 和 uevent_wait_timeout 都是自定义函数,而不是标准库提供的系统函数。

2) os_event2_wait_timeout:这是一个封装函数,它调用 pthread_cond_timedwait 并接受一个事件和超时时间(30秒)。

  1. uevent_wait_timeout:这个函数在内核中用于等待 uevent 事件,传入的参数包括环境指针和事件指针,以及超时时间。

  2. trx4_waiting_timeout:这个函数可能是一个事务相关的等待函数,传入了环境、事务和等待时间(3秒)

根据函数命名以及堆栈的含义,pthread_cond_timedwait 和 uevent_wait_timeout 肯定是代码底层的通用函数,所以初步判断SQL阻塞使用 trx4_waiting_timeout 函数就可以 我们此时进行测试。

6.编写代码

[root@localhost opt]# vim ebpf_trx.pyfrom bcc import BPF# 定义 eBPF 程序
bpf_text = """
#include <uapi/linux/ptrace.h>
#include <linux/sched.h>
#include <linux/timekeeping.h>BPF_HASH(start_time, u64);// 处理 uprobe 事件
int trace_ntsk_process_cop(struct pt_regs *ctx) {u64 pid_tgid = bpf_get_current_pid_tgid(); // 获取 PID 和 TGIDu64 thread_id = pid_tgid >> 32; // 获取线程号u64 timestamp = bpf_ktime_get_ns();// 记录开始时间start_time.update(&pid_tgid, &timestamp);bpf_trace_printk("ntsk_process_cop called: pid=%d, thread_id=%d, timestamp=%llu", pid_tgid & 0xFFFFFFFF, thread_id, timestamp);return 0;
}// 处理返回事件
int trace_ret_ntsk_process_cop(struct pt_regs *ctx) {u64 pid_tgid = bpf_get_current_pid_tgid(); // 获取 PID 和 TGIDu64 thread_id = pid_tgid >> 32; // 获取线程号u64 *start_ts = start_time.lookup(&pid_tgid);if (start_ts != 0) {u64 end_time = bpf_ktime_get_ns();u64 total_time = end_time - *start_ts;u64 total_time_ms = total_time / 1000000;bpf_trace_printk("ntsk_process_cop exited: pid=%d, thread_id=%d, total_time=%llu ms", pid_tgid & 0xFFFFFFFF, thread_id, total_time_ms);start_time.delete(&pid_tgid);}return 0;
}
"""# 加载 eBPF 程序
b = BPF(text=bpf_text)# 设置 uprobe
b.attach_uprobe(name="/opt/dmdbms/bin/dmserver", sym="trx4_waiting_timeout", fn_name="trace_ntsk_process_cop")
b.attach_uretprobe(name="/opt/dmdbms/bin/dmserver", sym="trx4_waiting_timeout", fn_name="trace_ret_ntsk_process_cop")# 输出跟踪信息
print("正在跟踪 uprobe... 按 Ctrl-C 结束。")# 输出追踪信息
b.trace_print()

代码解释

  • BPF_HASH(start_time, u64); 创建一个哈希表 start_time,键类型为 u64,用于存储每个进程的开始时间。它通过 PID(进程标识符)来索引
  • bpf_get_current_pid_tgid(): 获取当前进程的 PID 和线程 ID
  • attach_uprobe ()表示将钩子附加到dmserver的trx4_waiting_timeout函数的头部位置
  • attach_uretprobe()表示将钩子附加到dmserver的trx4_waiting_timeout函数的结尾位置
  • 在函数开始的时候存储开始时间在函数结尾时相减就是执行该函数的耗时,并输出PID 以及 threadID即可。

7.验证代码

[root@localhost opt]# python ebpf_trx.py 

验证结果说明

  • 运行程序以后,会发现只有当SQL阻塞的时候才会输出信息(进程号、线程号、函数的执行耗时) 说明对trx4_waiting_timeout函数添加钩子是没有问题
  • 运行时会发现每隔3S输出一次,添加符号文件的堆栈可以看到trx4_waiting_timeout函数的w_time=3,这块可以一一对应。
  • 有了这些信息就能够做很多事情,比如说将信息推送到监控平台等。

8.总结与思考

  1. 利用ebpf技术在不登录数据库的情况下,通过对数据库的函数添加钩子,实时的对数据库是否存在阻塞判断
  2. 现有的监控逻辑都是新建数据库用户执行SQL语句来判断阻塞情况,告警的实时性取决于监控的周期频率,而使用ebpf技术能够解决这个痛点
  3. ebpf有多种实现方式,这里便于理解测试的话 使用python语言内置c语言的形式进行了说明。涉及到生产环境应该是使用go语言或者c语言去做能够有效避免源码泄露等问题
  4. 如给sql线程添加钩子,有代sql变量的偏移量的话,就能够不登录数据库的情况下捕获到慢SQL,就能够有效的解决很多问题了,有待探究

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

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

相关文章

Linux系统进程控制

目录 一、进程创建 1.进程创建过程 2.写时拷贝 3.fork函数的两种常规用法 二、进程终止 1.进程终止的三种情况 2.进程退出信息 &#xff08;1&#xff09;退出码 &#xff08;2&#xff09;退出信号 3.进程终止的方式 三、进程等待 1.为什么要有进程等待&#xff1f…

5个最佳开源RPA框架之一UI.Vision介绍

博主介绍&#xff1a; 大家好&#xff0c;我是Yuperman&#xff0c;互联网宇宙厂经验&#xff0c;17年医疗健康行业的码拉松奔跑者&#xff0c;曾担任技术专家、架构师、研发总监负责和主导多个应用架构。技术范围&#xff1a; 目前专注java体系&#xff0c;以及golang、.Net、…

Golang优雅关闭gRPC实践

本文主要讨论了在 Go 语言中实现gRPC服务优雅关闭的技术和方法&#xff0c;从而确保所有连接都得到正确处理&#xff0c;防止数据丢失或损坏。原文: Go Concurrency — Graceful Shutdown 问题 我在上次做技术支持的时候&#xff0c;遇到了一个有趣的错误。我们的服务在 Kubern…

webshell-HTTP常见特征

一、总体特点 二、蚁剑 数据中可以看到一些明文字符串函数&#xff0c;响应中可以看到响应的明文数据。 ant特征以及对数据base64可以解码 chr类别的会出现大量的chr编码 大量的百分号字符 三、哥斯拉 第一个请求包很大 响应为0 密钥被拆分到数据前后 响应包cookie带&#xf…

SUP-NeRF-ECCV2024: 单目3D对象重建的新突破

2024-09-25&#xff0c;由Bosch Research North America和Michigan State University联合发布的SUP-NeRF&#xff0c;是一个基于单目图像进行3D对象重建的新型方法。一个无缝集成姿态估计和物体重建的统一网格。 ECCV&#xff1a;欧洲计算机视觉会议的缩写&#xff0c;它是计算…

Rust 语言开发 ESP32C3 并在 Wokwi 电子模拟器上运行(esp-hal 非标准库、LCD1602、I2C)

文章目录 esp-rs 简介GithubRust 包仓库Wokwi 电子模拟器开发环境Rust 环境esp-rs 环境创建 ESP32C3 项目项目结构编译项目命令运行模拟器ESP32C3 烧录 esp-rs 简介 esp-rs 是一个专注于为 Espressif 系列芯片&#xff08;如 ESP32、ESP32-S2、ESP32-C3 等&#xff09;提供 Ru…

学日语必备神器!这4款翻译APP你用过吗?

小伙伴们&#xff0c;你们有没有在日常生活或工作中遇到过需要翻译日语的场景呢&#xff1f;无论是阅读日本原著、工作文档还是和日本小伙伴交流&#xff0c;一个好的翻译工具绝对能成为你的贴心小助手&#xff1b;今天&#xff0c;我就来跟大家分享几款我个人非常喜欢的日语翻…

2024年合肥市职业院校技能大赛(中职组)赛 网络安全 竞赛样题

2024年合肥市职业院校技能大赛(中职组)赛 网络安全 竞赛样题 (总分100分) 培训、环境、资料、考证 公众号&#xff1a;Geek极安云科 网络安全群&#xff1a;624032112 网络系统管理群&#xff1a;223627079 网络建设与运维群&#xff1a;870959784 极安云科专注于技能提升&am…

数据结构与算法——Java实现 19.队列

目录 一、概述 二、链表实现队列 接口定义 接口实现类 测试类 三、环形数组实现队列 优点 下标计算 判满和判空 判满 判空 辅助变量size判空和判满 方法1 接口定义 接口实现类 测试类 方式2 接口定义 接口实现类 测试类 方法3 接口定义 接口实现类 测试类 生活鲜少给人留下退…

Nginx配置及部署前端项目,安排!

哈喽小伙伴们大家好&#xff01;我是程序媛小李&#xff0c;一位正在往全栈方向发展的前端小姐姐&#xff0c;今天给大家分享一下在日常编码中我们是怎么使用nginx来部署前端项目的&#xff01; Nginx安装 浏览器输入nginx&#xff0c;来到官网 右边找到doewnload&#xff0c…

短剧向左,体育向右,快手前途未卜?

最近&#xff0c;辗转于多项业务的快手收到了来自于市场“寓褒于贬”的评价。 麦格理发表报告表示&#xff0c;短剧业务正成为快手近期新的增长动力&#xff0c;亦维持对快手的正面看法&#xff0c;给予“跑赢大市”评级&#xff0c;预期上市前投资者出售2%股份对基本面没有太…

掌握AI提示词的艺术:应用、防护与成为提示词专家的策略

掌握好提示词的编写&#xff0c;可以用来做的事情&#xff1a; 写简历、输出面试题、输出ppt、思维导图、提取摘要、翻译、总结会议纪要、总结审计报告、数据分析、写广告/营销/请假等跟文字相关的文案、爆款文章、小说、写周报/月报。 如何写提示词 4大原则 1、 指令要精简…

Python精选200Tips:176-180

针对图像的经典卷积网络结构进化史及可视化 P176--LeNet-5【1988】模型结构说明模型结构代码模型结构可视化 P177--AlexNet【2012】模型结构及创新性说明模型结构代码模型结构可视化 P178--VGGNet【2014】VGG19模型结构及创新性说明VGG19模型结构代码VGG19模型结构可视化 P179-…

广东自闭症寄宿学校:为大龄自闭症儿童提供全寄宿制教育

在广东这片温暖的土地上&#xff0c;有一类特殊的孩子&#xff0c;他们以自己独特的方式感知世界&#xff0c;却往往因为自闭症的障碍而在成长的道路上步履维艰。为了给予这些大龄自闭症儿童更加全面、专业的关怀与教育&#xff0c;广东地区涌现出了一批自闭症寄宿学校&#xf…

Java中的Junit、类加载时机与机制、反射、注解及枚举

目录 Java中的Junit、类加载时机与机制、反射、注解及枚举 Junit Junit介绍与使用 Junit注意事项 Junit其他注解 类加载时机与机制 类加载时机 类加载器介绍 获取类加载器对象 双亲委派机制和缓存机制 反射 获取类对象 获取类对象的构造方法 使用反射获取的构造方法创建对象 获…

从0-1搭建海外社媒矩阵,详细方案深度拆解

做买卖&#xff0c;好的产品质量固然是关键&#xff0c;但如何让更多的消费者知道&#xff1f;营销推广是必不可少的。在互联网时代&#xff0c;通过社交媒体推广已经成为跨境电商卖家常用的广告手段。 如何通过海外社交媒体矩阵扩大品牌影响力&#xff0c;实现营销目标&#…

【开源项目】数字孪生智慧停车场——开源工程及源码

飞渡科技数字孪生停车场管理平台&#xff0c;基于国产数字孪生3D渲染引擎&#xff0c;结合数字孪生、物联网IOT&#xff0c;以及车牌自动识别、视频停车诱导等技术&#xff0c;实现停车场的自动化、可视化和无人化值守管理。 以3D可视化技术为基础&#xff0c;通过三维场景完整…

240927-各种卷积最清晰易懂blender动画展示

240927-一些常用卷积清晰易懂的blender动画展示&#xff08;Conv、GConv、DWConv、1*1Conv、Shuffle&#xff09; 在几个月前&#xff0c;写过一篇关于卷积过程中输入图像维度变化的博客240627_关于CNN中图像维度变化问题_图像的尺寸为什么又四个维度-CSDN博客&#xff0c;但是…

猫鱼分干(模拟---拆分步骤)

算法分析&#xff1a; 注意&#xff1a;总是更新遍历方向上的元素&#xff08;eg. 左 i-1 和 i &#xff1a;更新i&#xff09;区分水平和分配量从左向右&#xff1a;只要右侧水平大于左侧&#xff0c;即右侧等于左侧值加一从右向左&#xff1a;若左侧水平大于右侧&#xf…

一次实践:给自己的手机摄像头进行相机标定

文章目录 1. 问题引入2. 准备工作2.1 标定场2.2 相机拍摄 3. 基本原理3.1 成像原理3.2 畸变校正 4. 标定解算4.1 代码实现4.2 详细解析4.2.1 解算实现4.2.2 提取点位 4.3 解算结果 5. 问题补充 1. 问题引入 不得不说&#xff0c;现在的计算机视觉技术已经发展到足够成熟的阶段…