Linux驱动开发笔记(六)中断子系统及实验

文章目录

  • 前言
  • 一、中断子系统框架
    • 1. 中断硬件简单描述
    • 2. 中断的软件描述
  • 二、GIC v3中断控制器
    • 1. GIC v3基本结构
      • 1.1 Distributor
      • 1.2 Redistributor
      • 1.3 ITS
      • 1.4 CPU interface
    • 2. 中断类型与特点
    • 3. 中断号
  • 三、函数编写
    • 3.1 相关API函数
    • 3.2 驱动初始化函数
    • 3.3 operations函数
      • 3.3.1 open函数
      • 3.3.2 .read
      • 3.3.3 .release
    • 3.4 中断函数
  • 四、设备树的编辑
    • 1. 设备树插件格式
    • 2. 设备树插件的编写


前言

  本章我们将讲解下和中断相关的知识,了解内核中断的框架和中断的概念,对于arm的中断控制器(GIC v3)相关内容,主要是借鉴参考手册简单解释下。


一、中断子系统框架

  Linux中的中断相似于之前STM32的中断,是硬件在需要时向CPU发出的一种信号,导致CPU暂时停止当前正在执行的程序,转而处理这个硬件请求的一种机制。
  中断发生在CPU正常运行期间,由于内外部事件或由程序预先安排的事件引起的CPU暂时停止正在运行的程序,转而去为该内部或外部事件或预先安排的事件服务,服务完毕后再返回继续执行原来的程序。

1. 中断硬件简单描述

  中断硬件主要有三种器件参与,各个外设、中断控制器和CPU。之间的关系可以简单看下下面图片:
在这里插入图片描述

2. 中断的软件描述

  一个完整的中断子系统框架可以分为四个层次,由上到下分别为用户层、通用层、硬件相关层和硬件层,每个层相关的介绍如下所示:

  • 用户层:用户层是中断的使用者,主要包括各类设备驱动。这些驱动程序通过中断相关的接口进行中断的申请和注册。当外设触发中断时,用户层驱动程序会进行相应的回调处理,执行特定的操作。
  • 通用层:通用层也可称为框架层,它是硬件无关的层次。通用层的代码在所有硬件平台上都是通用的,不依赖于具体的硬件架构或中断控制器。通用层提供了统一的接口和功能,用于管理和处理中断,使得驱动程序能够在不同的硬件平台上复用。
  • 硬件相关层:硬件相关层包含两部分代码。一部分是与特定处理器架构相关的代码,比如ARM64处理器的中断处理相关代码。这些代码负责处理特定架构的中断机制,包括中断向量表、中断处理程序等。另一部分是中断控制器的驱动代码,用于与中断控制器进行通信和配置。这些代码与具体的中断控制器硬件相关。
  • 硬件层:硬件层位于最底层,与具体的硬件连接相关。它包括外设与SoC(系统片上芯片)的物理连接部分。中断信号从外设传递到中断控制器,由中断控制器统一管理和路由到处理器。硬件层的设计和实现决定了中断信号的传递方式和硬件的中断处理能力。

二、GIC v3中断控制器

  ARM多核处理器里最常用的中断控制器是GIC, GIC是Generic Interrupt Controller的缩写,提供了灵活的和可扩展的中断管理方法,支持单核系统到数百个大型多芯片设计的核心。 主要作用就是接受硬件中断信号,通过一定的设置策略,然后分发给对应的CPU进行处理。
  GIC v3中断控制器是ARM公司推出的一款与cortex-A和cortex-R处理器配合使用的中断控制器,广泛应用于基于armv8的SOC设计中。GIC v3为CPU处理所有连接到其上的中断,包括管理所有的中断源、中断行为、中断分组以及中断路由方式等。同时,它还提供相应的寄存器接口用于软件对这些行为的控制。

1. GIC v3基本结构

  GIC v3包含了SPI(Shared Peripheral Interrupt)、PPI(Private Peripheral Interrupt)、SGI(Software Generated Interrupt)和LPI(Locality-Specific Peripheral Interrupt)四种中断类型,以及distributor、redistributor、ITS(Interrupt Translation Service)和CPU interface四大组件。
在这里插入图片描述
   GIC v3中,将cpu interface从GIC中抽离,放入到了cpu中,cpu interface通过AXI Stream,与gic进行通信。 当GIC要发送中断,GIC通过AXI stream接口,给cpu interface发送中断命令,cpu interface收到中断命令后,根据中断线映射配置,决定是通过IRQ还是FIQ管脚,向cpu发送中断。

1.1 Distributor

  Distributor是GIC v3中用于管理共享外设中断(SPI)的关键组件。它负责接收来自外设的SPI中断请求,并根据配置决定中断的优先级以及将中断路由到哪个Redistributor。

  • 关键特性:
    • 中断分发:Distributor根据中断的优先级、亲和性(affinity)等配置,将SPI中断路由到适当的Redistributor。
    • 优先级管理:Distributor为每个SPI中断设置优先级,确保高优先级的中断能够优先得到处理。
    • 中断状态管理:Distributor维护中断的状态信息,如中断是否激活、是否挂起等。
  • 寄存器接口:
    • GICD_系列寄存器(如GICD_ISENABLER、GICD_ICENABLER、GICD_IPRIORITYR等)用于配置Distributor的行为,包括启用/禁用中断、设置中断优先级等。

1.2 Redistributor

  Redistributor与CPU接口连接,负责将来自Distributor的中断路由到正确的CPU。在多核系统中,Redistributor确保中断被正确地分发到目标CPU或CPU组。

  • 关键特性:

    • 中断路由:Redistributor根据配置将中断路由到相应的CPU接口。
    • 亲和性管理:Redistributor支持中断的亲和性配置,允许中断被路由到特定的CPU或CPU组。
  • 寄存器接口:

    • GICR_系列寄存器(如GICR_ISENABLER、GICR_ICENABLER等)用于配置Redistributor的行为,包括启用/禁用中断、设置中断路由等。

1.3 ITS

  ITS是GIC v3中用于处理基于消息的中断(LPI)的组件。它提供LPI中断的转换服务,将来自虚拟中断源的LPI中断转换为物理中断源,并将其路由到适当的Redistributor。

  • 关键特性:
    • 中断转换:ITS将LPI中断转换为物理中断,以便在物理世界中进行处理。
    • 中断路由:ITS负责将LPI中断路由到正确的Redistributor。

1.4 CPU interface

  CPU interface是GIC v3与CPU之间的接口,负责将中断传递到它所连接到的处理器元素(PE,即CPU)。当Redistributor将中断路由到某个CPU接口时,该接口会将中断信号发送到相应的CPU。

  • 关键特性:
    • 中断传递:CPU interface将来自Redistributor的中断信号传递给CPU。
    • 中断状态管理:CPU interface可能还负责维护中断的状态信息,如中断是否已被CPU接收、是否正在处理等。

2. 中断类型与特点

  • SPI:共享外设中断,不与特定的CPU绑定,可以根据affinity配置被路由到任意CPU或一组特定的CPU上。
  • PPI:私有外设中断,每个处理器私有的中断类型,即一个特定的中断只会被路由到特定的处理器上。
  • SGI:软件生成中断,没有实际的物理连线,而是由软件通过写寄存器方式触发,只支持边沿触发。
  • LPI:基于消息的中断,LPI相关的配置保存在内存中而非寄存器。
NTID范围中断类型备注
0 - 15SGI(软件生成中断) 文本居右每个核心分别存储
16 - 31PPI(私有外设中断)每个核心分别存储
32 - 1019SPI(共享外设中断)
1020 - 1023特殊中断号用于表示特殊情况
1024 - 8191保留
8192及更大LPI(特定局部外设中断)上限由实现定义

在这里插入图片描述

  • Inactive(非活动状态):中断源当前未被触发。
  • Pending(等待状态):中断源已被触发,但尚未被处理器核心确认。
  • Active(活动状态):中断源已被触发,并且已被处理器核心确认。
  • Active and Pending(活动且等待状态):已确认一个中断实例,同时另一个中断实例正在等待处理。

每个外设中断可以是以下两种类型之一:

  • 边沿触发(Edge-triggered):
    这是一种在检测到中断信号上升沿时触发的中断,然后无论信号状态如何,都保持触发状态,直到满足本规范定义的条件来清除中断。
  • 电平触发(Level-sensitive):
    这是一种在中断信号电平处于活动状态时触发的中断,并且在电平不处于活动状态时取消触发。

3. 中断号

  在linux 内核中,我们使用IRQ number和HW interrupt ID两个ID来标识一个来自外设的中断:

  • IRQ number:CPU需要为每一个外设中断编号,我们称之IRQ Number。这个IRQ number是一个虚拟的interrupt ID,和硬件无关,仅仅是被CPU用来标识一个外设中断。
  • HW interrupt ID:对于GIC中断控制器而言,它收集了多个外设的interrupt request line并向上传递,因此,GIC中断控制器需要对外设中断进行编码。GIC中断控制器用HW interrupt ID来标识外设的中断。如果只有一个GIC中断控制器,那IRQ number和HW interrupt ID是可以一一对应的,如下图所示:
    在这里插入图片描述
      但如果是在GIC中断控制器级联的情况下,仅仅用HW interrupt ID就不能唯一标识一个外设中断,还需要知道该HW interrupt ID所属的GIC中断控制器(HW interrupt ID在不同的Interrupt controller上是会重复编码的)。

三、函数编写

3.1 相关API函数

函数名描述
irq_of_parse_and_map( )解析得到软中断号
request_irq( )注册中断
devm_request_irq( )注册中断,申请的是内核“managed”的资源
free_irq( )释放中断
*irq_handler_t( )指定一个中断处理函数
enable_irq( )中断的使能
disable_irq( )中断的屏蔽
gpio_to_irq( )将 GPIO 引脚映射到对应中断号的函数
//解析得到软中断号
unsigned int irq_of_parse_and_map(struct device_node *np, int index)
  • 参数:
    • np:节点指针
    • index:设备树节点中interrupts键对应值的下标
  • 返回值:成功返回软中断号,失败返回0
//注册中断
static inline int __must_check request_irq(unsigned int irq, irq_handler_t 
    handler,unsigned long flags, const char *name, void *dev);
  • 参数:
    • irq:软中断号(内核中用到的中断号全部都是软中断号)(设备树获取)
    • handler:中断处理函数指针
    • flags:中断触发方式
      • IRQF_TRIGGER_RISING //上升沿
      • IRQF_TRIGGER_FALLING //下降沿
      • IRQF_TRIGGER_HIGH //高电平
      • IRQF_TRIGGER_LOW //低电平
      • IRQF_SHARED //共享中断
    • name:中断的名字
      cat /proc/interrupts 命令查看(设备号的查看方式 cat /proc/device)
    • dev:给中断处理函数传递的参数
  • 返回值:成功返回0,失败返回错误码

  此函数与request_irq()的区别是devm_开头的API申请的是内核“managed”的资源,一般不需要在出错处理和 remove()接口里再显式的释放。

int devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t 
	handler,unsigned long irqflags, const char *devname, void *dev_id);
  • 参数:
    • dev:指向您的设备的 struct device 结构体指针。这个结构体包含了设备的各种信息,并且允许设备管理器跟踪与该设备相关的所有资源。
    • irq:要请求的中断号。
    • handler:当中断触发时要调用的处理函数。
    • irqflags:标志位,用于指定中断处理函数的行为,如 IRQF_SHARED 允许多个处理程序共享同一个中断。
    • devname:与中断关联的名称,通常用于调试和日志记录。
    • dev_id:传递给中断处理函数的参数,允许您在中断处理程序中区分不同的中断源或设备实例。
  • 返回值:
    • 如果成功请求了中断,则返回 0。
    • 如果失败(例如,由于中断号无效、中断已被占用且未标记为可共享等),则返回负的错误码。

注:这里简单介绍一下中断处理函数指针

//typedef irqreturn_t (*irq_handler_t)(int, void *);
irqreturn_t key_irq_handle(int irqno,void *dev)
{
   //中断的处理---中断处理函数中不能加延时耗时的操作
    return IRQ_NONE;    //失败
    return IRQ_HANDLED; //成功
}
//释放中断
const void *free_irq(unsigned int irq, void *dev_id);
  • 参数:
    • irq:软中断号
    • dev_id:给中断处理函数传递的参数
  • 返回值:返回设备的名字
//在中断申请时需要指定一个中断处理函数
irqreturn_t (*irq_handler_t)(int irq, void * dev);
  • 参数:
    • int irq:表示触发中断的中断号(IRQ number)
    • void *dev:一个指向任何类型数据的指针,通常由 request_irq 或 devm_request_irq 函数的调用者提供,并传递给中断处理函数。这个指针通常用于传递与中断相关的设备或驱动程序的上下文信息
  • 返回值:
    • irqreturn_t类型:枚举类型变量
      • IRQ_NONE(0 << 0): 中断没有被处理
      • IRQ_HANDLED (1 << 0):中断被成功处理
      • IRQ_WAKE_THREAD(1 << 1):在中断服务函数是使用“上半部分”和“下半部分”实现
//中断的屏蔽和使能
void enable_irq(unsigned int irq);
void disable_irq(unsigned int irq);
  • 参数:
    • irq:指定的“内核中断号”
  • 返回值:无
//将 GPIO 引脚映射到对应中断号的函数,它的作用是根据给定的 GPIO 引脚号,获取与之关联的中断号。
#include <linux/gpio.h>
unsigned int gpio_to_irq(unsigned int gpio);
  • 参数:
    • gpio:要映射的 GPIO 引脚号。
  • 返回值:
    • 成功:返回值为该 GPIO 引脚所对应的中断号。
    • 失败:返回值为负数,表示映射失败或无效的 GPIO 引脚号。

3.2 驱动初始化函数

static int __init button_driver_init(void)
{
	int error = -1;

	//采用动态分配的方式,获取设备编号,次设备号为0,
	error = alloc_chrdev_region(&button_devno, 0, DEV_CNT, DEV_NAME);
	if (error < 0)
	{
		printk("fail to alloc button_devno\n");
		goto alloc_err;
	}

	//关联字符设备结构体cdev与文件操作结构体file_operations
	button_chr_dev.owner = THIS_MODULE;
	cdev_init(&button_chr_dev, &button_chr_dev_fops);

	//添加设备至cdev_map散列表中
	error = cdev_add(&button_chr_dev, button_devno, DEV_CNT);
	if (error < 0) 
	{
		printk("fail to add cdev\n");
		goto add_err;
	}

	class_button = class_create(THIS_MODULE, DEV_NAME); //创建类
	//创建设备 DEV_NAME 指定设备名
	device_button = device_create(class_button, NULL, button_devno, NULL, DEV_NAME);

	return 0;

add_err:
	// 添加设备失败时,需要注销设备号
	unregister_chrdev_region(button_devno, DEV_CNT);    
	printk("\n error! \n");
	
alloc_err:
	return -1;
}

3.3 operations函数

3.3.1 open函数

static int button_open(struct inode *inode, struct file *filp)
{
    int res = -1;

    //获取按键 设备树节点
    button_device_node = of_find_node_by_path("/button_interrupt");
    if(NULL == button_device_node)
    {
            printk("of_find_node_by_path error!");
            return -1;
    }

    //获取按键使用的GPIO
    button_GPIO_number = of_get_named_gpio(button_device_node ,"button-gpios", 0);
    if(0 == button_GPIO_number)
    {
            printk("of_get_named_gpio error");
            return -1;
    }

    //申请GPIO,记得释放
    res = gpio_request(button_GPIO_number, "button_gpio");
    if(error < 0)
    {
            printk("gpio_request error");
            gpio_free(button_GPIO_number);
            return -1;
    }
    
	//设置为输入模式
    res = gpio_direction_input(button_GPIO_number);

    //获取中断号
    interrupt_number = irq_of_parse_and_map(button_device_node, 0);
    printk("\n interrupt_number =  %d \n",interrupt_number);

    //申请中断, 记得释放
    res = request_irq(interrupt_number,button_irq_hander,IRQF_TRIGGER_RISING,"button_interrupt",NULL);
    if(error != 0)
    {
            printk("request_irq error");
            free_irq(interrupt_number, NULL);
            return -1;
    }
    return 0;
}

3.3.2 .read

static int button_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
    int error = -1;
    int button_countervc = 0;

    //读取按键状态值
    button_countervc = atomic_read(&button_status);

    //结果拷贝到用户空间
    error = copy_to_user(buf, &button_countervc, sizeof(button_countervc));
    if(error < 0)
    {
            printk_red("copy_to_user error");
            return -1;
    }
    //清零按键状态值
    atomic_set(&button_status,0);
    return 0;
}

3.3.3 .release

static int button_release(struct inode *inode, struct file *filp)
{
	
    //释放申请的引脚,和中断
    gpio_free(button_GPIO_number);
    free_irq(interrupt_number, device_button);
    printk("release over!");
    return 0;
}

3.4 中断函数

//定义整型原子变量,保存按键状态 ,设置初始值为0
atomic_t   button_status = ATOMIC_INIT(0);  

static irqreturn_t button_irq_hander(int irq, void *dev_id)
{
	printk("hander has entered!");
    //按键状态加一
    atomic_inc(&button_status);
    return IRQ_HANDLED;
}

四、设备树的编辑

1. 设备树插件格式

  设备树插件(Device Tree Overlay)是一种用于设备树(Device Tree)的扩展机制,它在Linux内核的嵌入式系统中发挥着重要作用。设备树插件允许在运行时动态修改设备树的内容,以便添加、修改或删除设备节点和属性。它提供了一种灵活的方式来配置和管理硬件设备,而无需重新编译整个设备树。通过使用设备树插件,开发人员可以在不重新启动系统的情况下对硬件进行配置更改。

#用于指定dts的版本
 /dts-v1/;
 
#表示允许使用未定义的引用并记录它们,设备树插件中可以引用主设备树中的节点
#这些“引用的节点”对于设备树插件来说就是未定义的,所以设备树插件应该加上“/plugin/”
/plugin/;

&{/} {
    /*此处在根节点"/"下,添加要插入的节点或者属性*/
};

&XXXXX {
    /*此处在节点"XXXXX"下,添加要插入的节点或者属性*/
};
    .......

2. 设备树插件的编写

#触发方式
#define IRQ_TYPE_NONE           0
#define IRQ_TYPE_EDGE_RISING    1
#define IRQ_TYPE_EDGE_FALLING   2
#define IRQ_TYPE_EDGE_BOTH      (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
#define IRQ_TYPE_LEVEL_HIGH     4
#define IRQ_TYPE_LEVEL_LOW      8

&{/} {
        #新增的button_interrupt节点
        button_interrupt: button_interrupt {
            status = "okay";
            compatible = "button_interrupt";
            #配置按键引脚
            button-gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_LOW>;
            #插件按键引脚的复用信息
            pinctrl-names = "default";
            pinctrl-0 = <&button_interrupt_pin>;
            #表示父中断控制节点是gpio0
            interrupt-parent = <&gpio0>;
            #表示中断引脚,触发方式
            interrupts = <RK_PB0 IRQ_TYPE_LEVEL_LOW>;
        };
    };

&{/pinctrl} {
    pinctrl_button {
        button_interrupt_pin: button_interrupt_pin {
            rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
        };
    };
};

免责声明:本文参考了野火的部分资料,仅供学习参考使用,若有侵权或勘误请联系笔者。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于Gdb快速上手调试Redis

写在文章开头 近期很多读者有询问有没有什么简单的办法快速上手调试redis&#xff0c;对此&#xff0c;笔者用到了Linux系统中比较易上手的调试工具GDB&#xff0c;本文将基于一个C语言两数交换的例子演示一下这款工具的使用。 Hi&#xff0c;我是 sharkChili &#xff0c;是个…

【Python深度学习系列】网格搜索神经网络超参数:批量大小和迭代周期数(案例+源码)

这是我的第297篇原创文章。 一、引言 在深度学习中&#xff0c;超参数是指在训练模型时需要手动设置的参数&#xff0c;它们通常不能通过训练数据自动学习得到。超参数的选择对于模型的性能至关重要&#xff0c;因此在进行深度学习实验时&#xff0c;超参数调优通常是一个重要的…

在线Logo背景去除:pixian.ai

文章目录 简介特色 简介 pixian.ai是一款智能图片背景去除工具&#xff0c;进入网页后&#xff0c;会非常醒目地提示你准备【Free】还是【Paid】&#xff0c;这点就非常好&#xff0c;不向有一些网站&#xff0c;主打免费使用&#xff0c;但时不时弹出“免费注册”&#xff0c…

1782java英语陪学记词系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java英语陪学记词系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助采用了java设计&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统采用web模式&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&…

RabbitMQ-工作模式(简单模式工作队列)

文章目录 简单模式&#xff08;simple&#xff09;工作队列&#xff08;work&#xff09;准备工作轮询调度消息确认消息持久性公平分发代码示例 本篇总结 更多相关内容可查看 简单模式&#xff08;simple&#xff09; 通俗概括:生产者-队列-消费者 想详细了解Rabbit的基础或简…

ESD防护SP3232E真+3.0V至+5.5V RS-232收发器

特征 采用3.0V至5.5V电源&#xff0c;符合真正的EIA/TIA-232-F标准 满载时最低 120Kbps 数据速率 1μA 低功耗关断&#xff0c;接收器处于活动状态 &#xff08;SP3222E&#xff09; 可与低至 2.7V 电源的 RS-232 互操作 增强的ESD规格&#xff1a; 15kV人体模型 15kV IEC1000…

软件杯 题目:基于深度学习卷积神经网络的花卉识别 - 深度学习 机器视觉

文章目录 0 前言1 项目背景2 花卉识别的基本原理3 算法实现3.1 预处理3.2 特征提取和选择3.3 分类器设计和决策3.4 卷积神经网络基本原理 4 算法实现4.1 花卉图像数据4.2 模块组成 5 项目执行结果6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基…

计算机毕业设计Spark+Flink+Hive地铁客流量预测 交通大数据 地铁客流量大数据 交通可视化 大数据毕业设计 深度学习 机器学习

项目说明​ ​ 1该项目主要分析通刷卡数据&#xff0c;通过大数据技术来研究地铁客运能力及探索优化服务的方向​ 2主要讲解Flink流处理实时分析部分&#xff0c;离线部分较简单&#xff0c;暂时略过​ ​ 技术架构​ ​项目流程&#xff1a;​ 采用python请求深圳地铁数…

70 Realistic Mountain Environment Textures Cliff(70+张真实的山地环境纹理)

大量适合山区和其他岩石环境的纹理--悬崖、岩石、砾石等等 每个纹理都是可贴的/无缝的,并且完全兼容各种不同的场景--标准Unity地形、Unity标准着色器、URP、HDRP等等都兼容。 所有的纹理都是4096x4096,并包括一个HDRP掩码,以完全支持HDRP。 特点。 70种质地 70种材料 70个地…

基于springboot实现农产品直卖平台系统项目【项目源码+论文说明】

基于springboot实现农产品直卖平台系统的设计演示 摘要 计算机网络发展到现在已经好几十年了&#xff0c;在理论上面已经有了很丰富的基础&#xff0c;并且在现实生活中也到处都在使用&#xff0c;可以说&#xff0c;经过几十年的发展&#xff0c;互联网技术已经把地域信息的隔…

内网快速传输工具

常见的有LANDrop&#xff0c;支持多种设备&#xff0c;如电脑、pad、手机等等之间互传。但本文介绍的这款是很小的电脑间互传工具。 特点是非常的快速&#xff0c;文件很小&#xff0c;不用安装解压就可用。

transformers peft加载lora模型;TextStreamer流式输出,kv cache使用

1、transformers peft加载lora模型 https://github.com/hiyouga/LLaMA-Factory/blob/cae47379079ff811aa385c297481a27020a8da6b/scripts/loftq_init.py#L13 代码&#xff1a; from peft import AutoPeftModelForCausalLM, PeftModel from transformers import AutoTokenizer…

《手把手教你》系列练习篇之13-python+ selenium自动化测试 -压轴篇(详细教程)

1. 简介 “压轴”原本是戏曲名词&#xff0c;指一场折子戏演出的倒数第二个剧目。在现代社会中有很多应用&#xff0c;比如“压轴戏”&#xff0c;但压轴也是人们知识的一个盲区。“压轴”本意是指倒数第二个节目&#xff0c;而不是人们常说的倒数第一个&#xff0c;倒数第一个…

Incredibuild for Mac 来了!

Mac 开发者在寻找适合自己需求的工具时可能会遇到一些困难&#xff0c;因为 Mac 操作系统相对封闭&#xff0c;不像其他系统那样开放和灵活。尽管如此&#xff0c;Mac 开发者在开发应用程序时的需求&#xff08;比如功能、效率等&#xff09;和使用其他操作系统的开发者是类似的…

C++ - 查找算法 和 其他 算法

目录 一. 查找算法&#xff1a; 1.顺序查找&#xff1a; 2.二分查找&#xff1a; 二. 其他算法&#xff1a; 1.遍历算法&#xff1a; 2.求和、求平均值等聚合算法。 a.求和算法&#xff1a; b.求平均值算法&#xff1a; 一. 查找算法&#xff1a; 1.顺序查找&#xff1…

如何访问内网数据库?

现如今&#xff0c;随着信息化的不断发展&#xff0c;数据库已经成为了企业管理和数据存储的重要组成部分。由于安全等原因&#xff0c;很多公司和组织将自己的数据库部署在内网中&#xff0c;限制了外部的访问。有些情况下&#xff0c;我们仍然需要在外部网络环境中访问内网的…

C++开发基础之初探CUDA计算环境搭建

一、前言 项目中有使用到CUDA计算的相关内容。但是在早期CUDA计算环境搭建的过程中&#xff0c;并不是非常顺利&#xff0c;编写此篇文章记录下。对于刚刚开始研究的你可能会有一定的帮助。 二、环境搭建 搭建 CUDA 计算环境涉及到几个关键步骤&#xff0c;包括安装适当的 C…

:长亭雷池社区版动态防护体验测评

序 长亭雷池在最近发布了动态防护功能&#xff0c;据说可以动态加密保护网页前端代码和阻止爬虫行为、阻止漏洞扫描行为等。今天就来体验测试一下 WAF 是什么 WAF 是 Web Application Firewall 的缩写&#xff0c;也被称为 Web 应用防火墙。区别于传统防火墙&#xff0c;WAF …

Error:..\FreeRTOS\portable\RVDS\ARM_CM7\r0p1\port.c,265

移植完FreeRTOS后&#xff0c;使用Keil进行编译&#xff0c;编译未报错&#xff0c;串口打印助手打印了错误报告。 串口打印的错误报告&#xff1a; Error:..\FreeRTOS\portable\RVDS\ARM_CM7\r0p1\port.c,265看一下265行 该行所在函数为prvTaskExitError函数&#xff0c;功能…

阅读笔记:Multi-threaded Rasterization in the Chromium Compositor

Multi-threaded Rasterization in the Chromium Compositor PPT 原始链接&#xff1a; https://docs.google.com/presentation/d/1nPEC4YRz-V1m_TsGB0pK3mZMRMVvHD1JXsHGr8I3Hvc/edit?uspsharing PPT主要介绍了Chromium浏览器中使用多线程光栅化(Impl-side painting)的机制&a…