基于飞腾派的YOLOv10n实时安全帽检测系统
基于飞腾派的YOLOv10n实时安全帽检测系统1. 项目背景建筑工地、矿山和隧道等作业环境存在坠物、碰撞等安全风险,安全帽是最基础的个体防护装备。传统人工巡检容易受到监控画面数量、光照条件和人员注意力的限制,因此本项目希望在资源受限的国产 ARM 开发板上实现视频安全帽检测,对连续出现的未佩戴安全帽行为进行告警。 系统需要同时解决以下问题: 飞腾派算力和内存有限,原始模型直接部署时延较高; 夜间或隧道内照度不足,安全帽与背景的特征对比度下降; 解码、增强、推理和绘制串行执行时,各阶段会相互等待; 单帧漏检、误检或短时遮挡可能导致告警抖动; OpenCV、业务线程和 ncnn 内部线程若同时过度并行,会在四核处理器上产生资源竞争。 2. 硬件与软件平台系统部署在飞腾派开发板上。处理器包含 2 个 FTC664 核和 2 个 FTC310 核,属于大小核异构 ARMv8 架构。FTC664 适合承担计算密集型的神经网络推理,FTC310 可承担视频解码、轻量预处理和后处理等任务。 软件栈主要包括: Ubuntu 20.04; C++17、CMake 和 GCC/G...
CXL 3.1:CXL.cache 与 CXL.mem
CXL 3.1:CXL.cache 与 CXL.mem3.2 CXL.cache3.2.1 概述CXL.cache 协议把设备与主机之间的交互定义为一系列请求。每个请求至少关联一条响应消息,有时还伴随数据传输。接口在两个方向上各包含三个通道:请求(Request)、响应(Response)和数据(Data)。从设备到主机的方向称为 D2H,从主机到设备的方向称为 H2D。独立通道使不同类型的消息能够使用专用线路,从而实现解耦,并提高每条线路的有效吞吐量。 D2H Request 承载设备发往主机的新请求,这些请求通常以存储器为目标。每个请求会收到零个、一个或两个响应,最多返回一条 64 字节缓存行数据。D2H Request 可以被反压。D2H Response 承载设备发往主机的全部响应,例如设备对侦听请求的响应;响应会说明设备缓存最终保留的行状态,也可能说明数据正被返回到主机指定的数据缓冲区。D2H Data 承载设备发往主机的全部数据与字节使能,数据可能来自隐式写回(侦听的结果),也可能来自显式写回(缓存容量驱逐的结果)。该通道总是传输完整的 64 字节缓存行,并且必须能够...
无标题
在 Linux 用户态程序中,malloc 和 mmap 都可以用来获得一段可访问的虚拟内存,但它们并不是同一层次的接口。 简单来说: malloc 是 C 标准库提供的动态内存分配接口; mmap 是操作系统提供的虚拟内存映射接口; malloc 在实现过程中,可能通过 brk 扩展堆,也可能通过匿名 mmap 向内核申请内存。 因此,二者既有区别,也存在实现上的联系。 一、malloc 是什么malloc 的函数原型如下: 123#include <stdlib.h>void *malloc(size_t size); 调用成功时,malloc 返回一块至少为 size 字节的内存;失败时返回 NULL。使用结束后,应当通过 free 释放: 123456789int *array = malloc(100 * sizeof(int));if (array == NULL) { perror("malloc"); return 1;}/* 使用 array */free(array); malloc 属于...
如何在 QEMU 中建模 CPU
本文是基于格维开源社区QEMU训练营-CPU建模而来,原文 QEMU CPU 建模流程:以 RISC-V 为例 - QEMU Camp Tutorial 在原文中,我们需要手动定义 CPUDef 结构体,手动编写 class_init 函数,再手动将其注册到类型数组中。但在较新的 QEMU 版本中,官方提供了极其强大的宏(Macro)。预处理器会在编译时自动帮我们展开这些结构体,这让 CPU 建模变得异常简单。 首先定义CPU名称,打开target/riscv/cpu-qom.h,添加: 1#define TYPE_RISCV_CPU_G233 RISCV_CPU_TYPE_NAME("g233-cpu") RISCV_CPU_TYPE_NAME 这个宏会在编译时将 "g233" 展开为 "g233-riscv-cpu",这是 QEMU 内部对象树识别该硬件的唯一字符串凭证。 然后使用宏注册CPU蓝图 在cpu.c里找到static const TypeInfo riscv_cpu_ty...
Linux 内核 rwsem 及读写机制的理解
**rwsem(Read/Write Semaphore,读写信号量)**专门为了解决读多写少的并发场景。 rwsem 的规则如下: 读锁(Read Lock):允许多个进程同时持有。只要没有人在写,大家都能读。 写锁(Write Lock):是排他性的。一旦有人要写,既不允许其他人读,也不允许其他人写。 使用需要包含<linux/rwsem.h> 初始化: 12struct rw_semaphore my_rwsem;init_rwsem(&my_rwsem); 读操作: 123down_read(&my_rwsem); // 申请读锁,如果有人在写或写排队则睡觉/* --- 临界区:只读操作 --- */up_read(&my_rwsem); // 释放读锁 写操作: 123down_write(&my_rwsem); // 申请写锁,如果有任何人在读或写则睡觉/* --- 临界区:写入/修改操作 --- */up_write(&my_rwsem); // 释放写锁 上面读操作提...
Unix 中 fork 函数的理解
fork是创建子进程的关键函数,常和exec系列函数一起使用。 对于代码 12345678910111213141516171819202122232425262728293031#include <stdio.h>#include <unistd.h>#include <sys/types.h>#include <sys/wait.h>#include <stdlib.h> // 提供 exit()int main() { pid_t pid = fork(); if (pid < 0) { perror("fork 失败"); return 1; } if (pid == 0) { // 子进程 printf("我是子进程 (PID: %d),准备运行 ls...\n", getpid()); execl("/bin/ls&quo...
xv6_实验8_file_system
Large files这个实验的核心目标是修改 xv6 的文件系统,引入 二级间接块 (Doubly-Indirect Block),从而打破文件最大只能有 268 个块(约 268KB)的限制,使其支持约 65803 个块(约 65MB)。 原始结构:12 个直接块 + 1 个一级间接块 = 13 个槽位。总计 12+256=268 个块 新结构:11 个直接块 + 1 个一级间接块 + 1 个二级间接块 = 13 个槽位。总共256*256+256+11 =65803 个块 我们需要修改三个主要部分:头文件定义、映射函数 bmap 和截断函数 itrunc。 修改fs.h 12345678#define NDIRECT 11 // 从 12 改为 11#define NINDIRECT (BSIZE / sizeof(uint))// 修改 MAXFILE 的计算公式,增加二级间接块的支持#define MAXFILE (NDIRECT + NINDIRECT + NINDIRECT * NINDIRECT...
xv6_2025_实验7_lock
Memory allocator实验目标:优化内存分配器的并行性能,通过将单全局锁+单空闲链表的设计改为每CPU锁+每CPU空闲链表,减少多核环境下的锁竞争。 当前的瓶颈: 1234struct { struct spinlock lock; struct run *freelist;} kmem; 所有CPU共享同一个空闲链表和一个锁, 任何kalloc/kfree操作都需要竞争这个全局锁 解决方案:每个CPU操作自己的链表和锁 打开kalloc.c,先修改数据结构 1234struct { struct spinlock lock; struct run *freelist;} kmem[NCPU]; 初始化每个CPU锁 123456789voidkinit(){ // 为每个CPU初始化锁 for(int i = 0; i < NCPU; i++) { initlock(&kmem[i].lock, "kmem"); } freeran...
xv6_2025_实验6_networking
实验一:NIC分层结构: 123应用层 (nettest.c) ←→ 网络协议栈 (net.c) ←→ 设备驱动 (e1000.c) 用户程序 协议处理 硬件控制 ←→ 硬件 (E1000网卡) 物理设备 主要是 e1000_transmit() 和e1000_recv() 要理解 DMA(直接内存访问)与 描述符环 (Descriptor Ring),理解ring中head和tail怎么移动的 理解 1234567891011// 描述符结构定义(位于e1000_dev.h)struct tx_desc { uint64 addr; // 数据缓冲区地址 uint16 length; // 数据长度 uint8 cso; // 校验和偏移 uint8 cmd; // 命令字段 uint8 status; // 状态字段(重点!) uint8 css; // ...
