目录

一、AER内核处理整体流程梳理

二、AER代码重要部分梳理

1、AER初始化阶段

2、中断上半部 aer_irq

3、中断下半部 aer_isr

3.1、aer_isr_one_error

3.2、find_source_device

3.3、aer_process_err_devices

3.4、handle_error_source

3.5、pcie_do_recovery 整体逻辑

3.5.1、pcie_do_recovery 整体总结--AER处理的核心部分

3.5.2、附加: aer_root_reset的函数分析--辅助理解pcie_do_recovery

三、内核处理流程整体总结



一、AER内核处理整体流程梳理

可能有理解不到位写得不对的地方

二、AER代码重要部分梳理

AER驱动与pciehp、pcie-dpc类似,都是作为PCIe port的可选服务,这些服务模块挂载在PCIe port驱动上,由portdrv_core统一管理。服务的注册通过pcie_port_service_register函数完成:

1、AER初始化阶段

static struct pcie_port_service_driver aerdriver = {.name       = "aer",.port_type  = PCIE_ANY_PORT,.service    = PCIE_PORT_SERVICE_AER,
​.probe      = aer_probe,.remove     = aer_remove,
};
​
int __init pcie_aer_init(void)
{if (!pci_aer_available())return -ENXIO;return pcie_port_service_register(&aerdriver);
}

PCIe AER驱动属于PCIe port driver, 其绑定的是PCIe root port

同时,port_type = PCIE_ANY_PORT这个澄清内核增加了PCIE RCEC支持,针对RCEC设备也可以AER处理

static int aer_probe(struct pcie_device *dev)
{... .../* * AER 仅支持根端口(Root Port)或根复合体事件收集器(RCEC)* 检查PCIe设备类型,如果不是这两种类型则直接返回*/if ((pci_pcie_type(port) != PCI_EXP_TYPE_RC_EC) &&(pci_pcie_type(port) != PCI_EXP_TYPE_ROOT_PORT))return -ENODEV;  // 设备不支持
​/* 为根端口控制结构(aer_rpc)分配内核内存 */rpc = devm_kzalloc(device, sizeof(struct aer_rpc), GFP_KERNEL);if (!rpc)return -ENOMEM;  /* 内存分配失败 */
​/* 初始化aer_rpc结构体 */rpc->rpd = port;  /* 保存根端口设备 */INIT_KFIFO(rpc->aer_fifo);  /* 初始化用于AER事件的FIFO队列 */set_service_data(dev, rpc);  /* 将rpc与pcie_device关联 */
​status = devm_request_threaded_irq(device, dev->irq, aer_irq, aer_isr,IRQF_SHARED, "aerdrv", dev);... .../* 在根端口上启用AER功能 */aer_enable_rootport(rpc);... ...
}

主要做了下面两件事情:

(1)注册AER事件的线程化中断处理程序:aer_irq: 上半部(快速处理),aer_isr: 下半部(实际处理)

(2)在根端口上启用AER功能

2、中断上半部 aer_irq

​
static irqreturn_t aer_irq(int irq, void *context)
{... ...// 读取根错误状态寄存器pci_read_config_dword(rp, aer + PCI_ERR_ROOT_STATUS, &e_src.status);// 检查是否真的有错误发生(可纠正或不可纠正错误)if (!(e_src.status & (PCI_ERR_ROOT_UNCOR_RCV|PCI_ERR_ROOT_COR_RCV)))return IRQ_NONE;  // 如果没有错误,返回IRQ_NONE表示不是我们的中断
​// 读取错误源ID寄存器,获取详细错误信息pci_read_config_dword(rp, aer + PCI_ERR_ROOT_ERR_SRC, &e_src.id);// 清除根错误状态寄存器(写1清除)pci_write_config_dword(rp, aer + PCI_ERR_ROOT_STATUS, e_src.status);
​// 尝试将错误信息放入FIFO队列if (!kfifo_put(&rpc->aer_fifo, e_src))return IRQ_HANDLED;  // 如果队列已满,直接返回IRQ_HANDLED
​// 成功放入队列,返回IRQ_WAKE_THREAD唤醒下半部处理线程return IRQ_WAKE_THREAD;
}

这是中断处理的上半部,主要负责快速读取错误状态并暂存数据,实际处理会在下半部中进行,主要做了下面几件事:

(1)通过PCI_ERR_ROOT_STATUS寄存器检测错误类型

(2)读取PCI_ERR_ROOT_ERR_SRC获取错误源详细信息

(3)清除错误状态,唤醒中断下半部

3、中断下半部 aer_isr

3.1、aer_isr_one_error

上半部 aer_irq 将错误存入FIFO,下半部 aer_isr 是消费者,从FIFO取出错误处理

static irqreturn_t aer_isr(int irq, void *context)
{... ...// 循环处理FIFO中的所有错误信息while (kfifo_get(&rpc->aer_fifo, &e_src)) {// 对每个错误调用处理函数aer_isr_one_error(rpc, &e_src);}return IRQ_HANDLED;
}
​
static void aer_isr_one_error(struct aer_rpc *rpc, struct aer_err_source *e_src)
{... ...if (e_src->status & PCI_ERR_ROOT_COR_RCV) {// 设置可纠正错误信息e_info.id = ERR_COR_ID(e_src->id);       // 提取可纠正错误IDe_info.severity = AER_CORRECTABLE;       // 设置错误严重性为可纠正
​// 检查是否多个可纠正错误if (e_src->status & PCI_ERR_ROOT_MULTI_COR_RCV)e_info.multi_error_valid = 1;        // 标记为多个错误elsee_info.multi_error_valid = 0;
​// 打印端口错误信息aer_print_port_info(pdev, &e_info);
​// 查找错误源设备并处理错误if (find_source_device(pdev, &e_info))aer_process_err_devices(&e_info);}
​// 处理不可纠正错误if (e_src->status & PCI_ERR_ROOT_UNCOR_RCV) {// 设置不可纠正错误信息e_info.id = ERR_UNCOR_ID(e_src->id);     // 提取不可纠正错误ID
​// 判断是否为致命错误if (e_src->status & PCI_ERR_ROOT_FATAL_RCV)e_info.severity = AER_FATAL;         // 致命错误elsee_info.severity = AER_NONFATAL;      // 非致命错误
​// 检查是否多个不可纠正错误if (e_src->status & PCI_ERR_ROOT_MULTI_UNCOR_RCV)e_info.multi_error_valid = 1;        // 标记为多个错误elsee_info.multi_error_valid = 0;
​// 打印端口错误信息aer_print_port_info(pdev, &e_info);
​// 查找错误源设备并处理错误if (find_source_device(pdev, &e_info))aer_process_err_devices(&e_info);}
}

错误处理流程

(1)先更新错误统计(pci_rootport_aer_stats_incr)

(2)打印错误信息(aer_print_port_info)

(3)定位错误源设备(find_source_device)

(4)处理错误设备(aer_process_err_devices)

3.2、find_source_device
static bool find_source_device(struct pci_dev *parent,struct aer_err_info *e_info)
{... .../* 检查根端口本身是否是发送错误消息的代理 */result = find_device_iter(dev, e_info);if (result)return true;
​/* 根据父设备类型采用不同的搜索方式 */if (pci_pcie_type(parent) == PCI_EXP_TYPE_RC_EC)/* 如果是根复合体事件收集器(RCEC),则遍历RCEC */pcie_walk_rcec(parent, find_device_iter, e_info);else/* 否则遍历根端口的下属总线 */pci_walk_bus(parent->subordinate, find_device_iter, e_info);... ...
}

在PCIe设备树中定位触发AER(高级错误报告)的具体设备,支持从根端口(Root Port)或根复合体事件收集器(RCEC)开始搜索。

首先检查根端口自身是否是错误源,如果不是,则向下遍历设备树:

  • 对于RCEC类型设备使用pcie_walk_rcec()

  • 对于普通根端口使用pci_walk_bus()

3.3、aer_process_err_devices
static inline void aer_process_err_devices(struct aer_err_info *e_info)
{int i;
​/* 第一阶段:报告所有错误信息(在处理前先记录,避免因复位等操作丢失记录) */for (i = 0; i < e_info->error_dev_num && e_info->dev[i]; i++) {if (aer_get_device_error_info(e_info->dev[i], e_info))aer_print_error(e_info->dev[i], e_info);}
​/* 第二阶段:处理所有错误源 */for (i = 0; i < e_info->error_dev_num && e_info->dev[i]; i++) {if (aer_get_device_error_info(e_info->dev[i], e_info))handle_error_source(e_info->dev[i], e_info);}
}

该函数主要负责两个阶段处理错误设备:

(1)错误信息报告阶段:先收集并打印所有设备的错误信息

(2)错误处理阶段:然后对所有设备执行实际的错误处理

3.4、handle_error_source
static void handle_error_source(struct pci_dev *dev, struct aer_err_info *info)
{/* 获取设备的AER能力寄存器偏移量 */int aer = dev->aer_cap;
​/* 处理可纠正错误(AER_CORRECTABLE)*/if (info->severity == AER_CORRECTABLE) {// 可纠正错误不需要软件干预,无需走完整的错误恢复流程。if (aer)/* 清除可纠正错误状态寄存器(写1清除) */pci_write_config_dword(dev, aer + PCI_ERR_COR_STATUS,info->status);/* 如果设备支持原生AER处理,清除设备状态 */if (pcie_aer_is_native(dev))pcie_clear_device_status(dev);}/* 处理非致命错误(AER_NONFATAL)*/else if (info->severity == AER_NONFATAL)/* 执行标准恢复流程(I/O通道状态正常) */pcie_do_recovery(dev, pci_channel_io_normal, aer_root_reset);/* 处理致命错误(AER_FATAL)*/else if (info->severity == AER_FATAL)/* 执行强制恢复流程(I/O通道已冻结) */pcie_do_recovery(dev, pci_channel_io_frozen, aer_root_reset);/* 减少设备的引用计数(配对之前可能的pci_dev_get) */pci_dev_put(dev);
}

函数根据错误严重级别采取不同的处理措施:

可纠正错误:仅清除错误状态寄存器,额外调用pcie_clear_device_status确保状态清除

非致命和致命错误都调用pcie_do_recovery,但传入不同的I/O通道状态:

pci_channel_io_normal:链路仍可用

pci_channel_io_frozen:链路已冻结

非致命错误:触发普通恢复流程

致命错误:触发强制恢复流程

3.5、pcie_do_recovery 整体逻辑

下面这块逻辑比较隐晦:

pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,pci_channel_state_t state,pci_ers_result_t (*reset_subordinates)(struct pci_dev *pdev))
{/** - 如果是根端口/下游端口/RCEC/RCiEP,恢复该设备及其下级设备* - 其他设备类型,恢复该设备及同端口下的所有设备*/if (type == PCI_EXP_TYPE_ROOT_PORT ||type == PCI_EXP_TYPE_DOWNSTREAM ||type == PCI_EXP_TYPE_RC_EC ||type == PCI_EXP_TYPE_RC_END)bridge = dev;  // 端口类设备自身作为恢复起点elsebridge = pci_upstream_bridge(dev);  // 其他设备向上找到最近的端口... .../* 阶段1:错误检测处理 */if (state == pci_channel_io_frozen) {/* 冻结状态处理 */pci_walk_bridge(bridge, report_frozen_detected, &status);if (reset_subordinates(bridge) != PCI_ERS_RESULT_RECOVERED) {pci_warn(bridge, "下级设备重置失败\n");goto failed;}} else {/* 正常状态处理 */pci_walk_bridge(bridge, report_normal_detected, &status);}
​/* 阶段2:MMIO重新启用 */if (status == PCI_ERS_RESULT_CAN_RECOVER) {status = PCI_ERS_RESULT_RECOVERED;pci_walk_bridge(bridge, report_mmio_enabled, &status);}
​/* 阶段3:插槽重置处理 */if (status == PCI_ERS_RESULT_NEED_RESET) {// 插槽重置函数,然后再调用, 驱动的slot_reset回调status = PCI_ERS_RESULT_RECOVERED;pci_walk_bridge(bridge, report_slot_reset, &status);}
​.../* 阶段4:恢复完成处理 */pci_walk_bridge(bridge, report_resume, &status);
​// 如果OS原生控制AER,清除设备错误状态; 如果平台控制AER,由平台负责清除if (host->native_aer || pcie_ports_native) {pcie_clear_device_status(dev);pci_aer_clear_nonfatal_status(dev);}... ...
}

首先是 pci_walk_bridge(bridge, report_frozen_detected, &status) 这块比较绕,展开后可以发现:

static void pci_walk_bridge(struct pci_dev *bridge,int (*cb)(struct pci_dev *, void *),void *userdata)
{if (bridge->subordinate)pci_walk_bus(bridge->subordinate, cb, userdata);elsecb(bridge, userdata);
}
​
void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *),void *userdata)
{struct pci_dev *dev;struct pci_bus *bus;struct list_head *next;int retval;
​bus = top;down_read(&pci_bus_sem);next = top->devices.next;for (;;) {if (next == &bus->devices) {/* end of this bus, go up or finish */if (bus == top)break;next = bus->self->bus_list.next;bus = bus->self->bus;continue;}dev = list_entry(next, struct pci_dev, bus_list);if (dev->subordinate) {/* this is a pci-pci bridge, do its devices next */next = dev->subordinate->devices.next;bus = dev->subordinate;} elsenext = dev->bus_list.next;retval = cb(dev, userdata);if (retval)break;}up_read(&pci_bus_sem);
​
}

首先分析 pci_walk_bus,该函数主要做了以下两件事:

(1)优先向下遍历桥接设备的子总线,确保处理完整个子树后再返回上级,如:

Bus 0 (top)
├─ Device A(桥接器)→ Bus 1
│   ├─ Device C
│   └─ Device D
└─ Device B

遍历顺序:Bus 0 → Device A → Bus 1 → Device C → Device D → Device B

(2)回调函数cb (即report_frozen_detected)返回非零值会立即终止遍历(例如在错误恢复中已找到目标设备时)。

下面再看 report_frozen_detected这块调用流程的逻辑:

static int report_frozen_detected(struct pci_dev *dev, void *data)
{return report_error_detected(dev, pci_channel_io_frozen, data);
}
​
static int report_error_detected(struct pci_dev *dev,pci_channel_state_t state,enum pci_ERS_result *result)
{const struct pci_error_handlers *err_handler;... ...if (!pci_dev_set_io_state(dev, state) ||!dev->driver ||!dev->driver->err_handler ||!dev->driver->err_handler->error_detected) {/* 如果整个设备subtree没有error_detected回调,PCI_ERS_RESULT_NO_AER_DRIVER将阻止后续任何设备的错误回调 */if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {/* 非桥设备没有回调则标记为无法恢复 */vote = PCI_ERS_RESULT_NO_AER_DRIVER;} else {vote = PCI_ERS_RESULT_NONE;}} else {/* 获取错误处理程序并调用error_detected回调 */err_handler = dev->driver->err_handler;vote = err_handler->error_detected(dev, state);}... ...
}
​
static pci_ers_result_t merge_result(enum pci_ers_result orig,enum pci_ers_result new)
{if (new == PCI_ERS_RESULT_NO_AER_DRIVER)return PCI_ERS_RESULT_NO_AER_DRIVER;
​if (new == PCI_ERS_RESULT_NONE)return orig;
​switch (orig) {case PCI_ERS_RESULT_CAN_RECOVER:case PCI_ERS_RESULT_RECOVERED:orig = new;break;case PCI_ERS_RESULT_DISCONNECT:if (new == PCI_ERS_RESULT_NEED_RESET)orig = PCI_ERS_RESULT_NEED_RESET;break;default:break;}
​return orig;
}

可以发现,这个函数的主要作用是遍历PCI总线上的多个设备时(例如通过 pci_walk_bus),综合所有设备的错误恢复状态,决定最终的恢复策略(如是否需要复位、是否断开设备等),根据代码看,整体的设备是否可恢复状态合并逻辑是这样的:

原始状态 (orig)新状态 (new)合并结果
CAN_RECOVERDISCONNECTDISCONNECT
RECOVEREDNEED_RESETNEED_RESET
DISCONNECTNEED_RESETNEED_RESET
DISCONNECTCAN_RECOVERDISCONNECT(不降级)
NO_AER_DRIVER任意NO_AER_DRIVER(最高优先级)

因此,pci_walk_bridge 这个函数的作用就是,如果设备是桥,根据桥和下面的子设备error_detected 回调函数,综合判断设备要不要恢复,是走DISCONNECTNEED_RESET还是CAN_RECOVER。如果设备是RCEP,直接判断因该置位自己设备为哪种预备状态

3.5.1、pcie_do_recovery 整体总结--AER处理的核心部分

接下来重新回到 pcie_do_recovery 函数来看,这个函数的逻辑就比较清晰了,即:

(1)如果错误为 FATAL 错误,即设备A已经被标记成 pci_channel_io_frozen 状态了,这个时候先用深度优先算法,遍历该设备A和其下子设备,去检查是否满足reset条件,然后综合该设备和设备下挂子设备能否reset,给A这条线路置一个 PCI_ERS_RESULT_NEED_RESET 还是 PCI_ERS_RESULT_CAN_RECOVER 等的标识

(2)同时,如果错误为 FATAL 错误,会调用 reset_subordinates(bridge) != PCI_ERS_RESULT_RECOVERED,进而调用 aer_root_reset去重置该 bridge,并期待返回 PCI_ERS_RESULT_RECOVERED标志,否则报异常

(3)如果错误为NON - FATAL错误,仅仅标记该端口的PCIe端口status状态为 PCI_ERS_RESULT_NONE 或者是 PCI_ERS_RESULT_NO_AER_DRIVER,不进行端口或者总线的重置操作

(4)然后,根据端口在上面被标记的status状态,遍历调用 report_mmio_enabled 去恢复特定端口的MMIO功能。同时,更新端口A的status位

(5)然后,对执行MMIO恢复后的,status被标记为PCI_ERS_RESULT_NEED_RESET的端口,遍历调用 report_slot_reset ,进行槽位级别的复位

(6)最后,根据设置的是固件优先还是OS优先,去清除Device Status寄存器和Uncorrectable Error Status 寄存器的响应错误bit位

3.5.2、附加: aer_root_reset的函数分析--辅助理解pcie_do_recovery
static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
{// * - RCiEP需要找到关联的RCEC,其他设备直接找到根端口if (type == PCI_EXP_TYPE_RC_END)root = dev->rcec;    // RCiEP使用关联的RCECelseroot = pcie_find_root_port(dev);  // 其他设备查找根端口
​// 如果平台保留AER控制权,RCiEP可能没有可见的RCEC,此时root可能为NULL,寄存器操作由固件负责aer = root ? root->aer_cap : 0;  // 获取AER能力位置
​/* 阶段1: 禁用根端口错误中断 */if ((host->native_aer || pcie_ports_native) && aer) {pci_read_config_dword(root, aer + PCI_ERR_ROOT_COMMAND, &reg32);reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;  // 清除中断使能位pci_write_config_dword(root, aer + PCI_ERR_ROOT_COMMAND, reg32);}
​/* 阶段2: 执行设备重置 */if (type == PCI_EXP_TYPE_RC_EC || type == PCI_EXP_TYPE_RC_END) {/* RCEC/RCiEP使用功能级重置(FLR) */rc = pcie_reset_flr(dev, PCI_RESET_DO_RESET);} else {/* 根端口/下游端口使用总线错误重置 */rc = pci_bus_error_reset(dev);pci_info(dev, "%s端口链路已重置(%d)\n",pci_is_root_bus(dev->bus) ? "根" : "下游", rc);}
​/* 阶段3: 清理并恢复中断 */if ((host->native_aer || pcie_ports_native) && aer) {/* 清除根错误状态寄存器 */pci_read_config_dword(root, aer + PCI_ERR_ROOT_STATUS, &reg32);pci_write_config_dword(root, aer + PCI_ERR_ROOT_STATUS, reg32);
​/* 重新启用根端口错误中断 */pci_read_config_dword(root, aer + PCI_ERR_ROOT_COMMAND, &reg32);reg32 |= ROOT_PORT_INTR_ON_MESG_MASK;  // 设置中断使能位pci_write_config_dword(root, aer + PCI_ERR_ROOT_COMMAND, reg32);}
​/* 返回结果: 成功恢复或需要断开 */return rc ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
}

主要做下面几件事情:

(1)禁用根端口错误中断

#define ROOT_PORT_INTR_ON_MESG_MASK (PCI_ERR_ROOT_CMD_COR_EN|   \PCI_ERR_ROOT_CMD_NONFATAL_EN|   \PCI_ERR_ROOT_CMD_FATAL_EN)

(2)执行设备重置(FLR或链路重置),如果是RCEC/RCiEP,通过pcie_reset_flr()执行功能级重置;如果是根端口或者下游端口,通过pci_bus_error_reset()执行总线级重置

(3)清除根错误状态

(4)重新启用根端口错误中断

接着向下看调用 pci_bus_error_reset()

int pci_bus_error_reset(struct pci_dev *bridge)
{/* 情况1:总线无槽位(如嵌入式设备),直接跳转总线复位 */if (list_empty(&bus->slots))goto bus_reset;
​/* 阶段1:检查所有槽位是否支持热复位 */list_for_each_entry(slot, &bus->slots, list)if (pci_probe_reset_slot(slot))  // 探测槽位复位能力goto bus_reset;  // 任一槽位不支持则改用总线复位
​/* 阶段2:执行实际槽位复位 */list_for_each_entry(slot, &bus->slots, list)if (pci_slot_reset(slot, PCI_RESET_DO_RESET))  // 实际复位操作goto bus_reset;  // 任一槽位复位失败则改用总线复位... ...
/* 降级处理路径:总线级复位 */
bus_reset:mutex_unlock(&pci_slot_mutex);return pci_bus_reset(bridge->subordinate, PCI_RESET_DO_RESET);
}

采用渐进式复位策略:先尝试最小影响的槽位复位(pci_slot_reset),失败时自动降级为总线复位(pci_bus_reset)

pci_slot_reset--> pci_reset_hotplug_slot(slot->hotplug, probe);--> hotplug->ops->reset_slot(hotplug, probe);--> pciehp_reset_slot--> pci_bridge_secondary_bus_reset(ctrl->pcie->port);

(1)置位桥控制寄存器的BUS_RESET位,保持复位状态至少2ms(符合PCI规范v3.0 7.6.4.2)

(2)清除BUS_RESET位,等待1秒确保下游设备完成初始化

pci_bus_reset(struct pci_bus *bus, bool probe)--> pci_bridge_secondary_bus_reset(bus->self);

三、内核处理流程整体总结

(1)EP设备发生AER错误,通过error msg上报到root port, root port上报中断给CPU处理

(2)Correctable Errors处理流程:获取出错的设备和清状态,读取设备详细错误信息

(3)NON-FATAL Errors处理流程:获取出错的设备和清状态,读取设备详细错误信息,错误恢复处理

(4)FATAL Errors处理流程:大体类似non-fatal,只是错误恢复的时候有差异,FATAL Errors影响pcie link链路,因此会做链路的恢复

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

​HAProxy负载均衡集群概述

前言&#xff1a; 在现代分布式系统中&#xff0c;负载均衡和高可用性是保障服务稳定性和性能的关键技术。HAProxy 作为一款高性能的 TCP/HTTP 负载均衡器&#xff0c;凭借其轻量级、高并发处理能力和灵活的配置机制&#xff0c;成为构建高可用架构的核心组件之一。通过智能的流…

ELN:生物医药科研的数字化引擎——衍因科技引领高效创新

在生物医药研究领域&#xff0c;实验数据的准确记录与管理是科研成败的关键。想象一个场景&#xff1a;某顶尖医学院实验室&#xff0c;研究员小张正为一项抗癌药物实验焦头烂额。纸质记录本中&#xff0c;数据混乱、协作困难&#xff0c;导致实验重复率高达20%。引入衍因科技的…

暑假---作业2

学习目标&#xff1a;xss-1abs 1-8关python美现自动化布尔自注的2、代码进行优化(二分查找)学习内容&#xff1a;1.xss-1abs 1-8关1<h2 align"center">欢迎用户test</h2>2 <script> alert (1)</script&gt<center> <form action&…

【Tensor数据转换】——深度学习.Torch框架

目录 1 Tensor与Numpy 1.1 张量转Numpy 1.2 Numpy转张量 1 Tensor与Numpy 1.1 张量转Numpy 调用numpy()方法可以把Tensor转换为Numpy&#xff0c;此时内存是共享的。 使用copy()方法可以避免内存共享 import torch import numpy as np# tensor转numpy:numpy() def test0…

基于Tranformer的NLP实战(5):BERT实战-基于Pytorch Lightning的文本分类模型

文本分类作为自然语言处理中的基础任务&#xff0c;能够帮助我们将海量医学摘要自动归类到具体疾病领域中。本文将基于NVIDIA NeMo框架&#xff0c;构建一个用于医学疾病摘要分类的深度学习应用&#xff0c;支持将摘要划分为三类&#xff1a;癌症类疾病、神经系统疾病及障碍、以…

14-链路聚合

链路聚合技术 一 链路聚合概述链路聚合定义链路聚合是把多条物理链路聚合在一起&#xff0c;形成一条逻辑链路。应用在交换机、路由器、服务器间链路。分为三层链路聚合和二层链路聚合。二 链路聚合的作用 1. 链路聚合模式静态聚合模式 端口不与对端设备交互信息。选择参考端口…

学习C++、QT---28(QT库中使用QShortcut类对快捷键创建和使用的讲解)

每日一言 所有的努力&#xff0c;都是为了让未来的自己感谢现在的你。 QShortcut 我们的记事本肯定要有通过快捷键对字体的放大和缩小进行控制的功能啊&#xff0c;那么我们这边就这个问题我们需要先学习一下QShortCut 我们这个类就是专门做快捷键的 老样子我们刚开始学习这个…

Web Worker:让前端飞起来的隐形引擎

目录 Web Worker&#xff1a;让前端飞起来的隐形引擎 一、什么是 Web Worker&#xff1f; 1、为什么需要 web worker 2、什么是 web worker 二、基本使用方法 1、创建一个 Worker 文件&#xff08;worker.js&#xff09; 2、主线程引入并使用 三、实战案例&#xff1a;…

关于在VScode中使用git的一些步骤常用命令及其常见问题:

输入 gitee用户 gitee绑定邮箱git config --global user.name "automated-piggy-senior" git config --global user.email "1323280131qq.com"克隆远程库到本地 git clone https://gitee.com/automated-piggy-senior/20250717-test.git常见问题1&#xff1…

LeafletJS 性能优化:处理大数据量地图

引言 LeafletJS 作为一个轻量、灵活的 JavaScript 地图库&#xff0c;以其高效的渲染能力和模块化设计深受开发者喜爱。然而&#xff0c;当处理大数据量&#xff08;如数千个标记、复杂的 GeoJSON 数据或高分辨率瓦片&#xff09;时&#xff0c;LeafletJS 的性能可能面临挑战&…

LLM(Large Language Model)大规模语言模型浅析

参考: https://zhuanlan.zhihu.com/p/7046080918 LLM(Large Language Model)大规模语言模型,是指具有大规模参数和复杂计算结构的机器学习模型。大模型里常说的多少B, B 是 Billion 的缩写&#xff0c;表示 十亿,如DeepSeek满血版 671B(6710亿参数); 大模型本质上是一个使用海量…

【后端】配置SqlSugar ORM框架并添加仓储

目录 1.添加包 2.配置连接字符串 3.配置SqlSugar 3.1.添加基础类 3.2.添加方法 3.2.1.读取配置方法 3.2.2.枚举扩展方法 3.3.添加管理类&#xff08;重要&#xff09; 4.配置仓储 4.1.仓储接口添加 5.注册 6.使用 该文档是配置SqlSugar多租户和加仓储教程。使用 S…

全国高等院校计算机基础教育研究会2025学术年会在西宁成功举办 ——高原论道启新程,数智融合育英才

7 月16日至18日&#xff0c;全国高等院校计算机基础教育研究会2025学术年会在青海西宁隆重召开。大会以“数智融合&#xff0c;创新计算机教育”为主题&#xff0c;汇聚人工智能领域顶尖专家学者、高校校长、产业翘楚及一线教师300 多人&#xff0c;共商人工智能时代计算机基础…

AppTrace:重新定义免填邀请码,解锁用户裂变新高度

​​在移动互联网时代&#xff0c;​用户裂变是App增长的核心引擎&#xff0c;而邀请机制则是裂变的关键驱动力。然而&#xff0c;传统的邀请码机制——依赖用户手动输入、记忆复杂字符——已经成为用户体验的绊脚石&#xff0c;导致转化率下降、运营成本上升。​AppTrace​ 作…

神经网络常见激活函数 13-Softplus函数

文章目录Softplus函数导函数函数和导函数图像优缺点PyTorch 中的 Softplus 函数TensorFlow 中的 Softplus 函数Softplus 函数导函数 Softplus函数 Softplus⁡(x)ln⁡(1ex)\begin{aligned} \operatorname{Softplus}(x) & \ln \bigl(1 e^{\,x}\bigr) \end{aligned} Softplu…

深度理解 KVM:Linux 内核系统学习的重要角度

&#x1f4d6; 推荐阅读&#xff1a;《Yocto项目实战教程:高效定制嵌入式Linux系统》 &#x1f3a5; 更多学习视频请关注 B 站&#xff1a;嵌入式Jerry 深度理解 KVM&#xff1a;Linux 内核系统学习的重要角度 作者&#xff1a;嵌入式 Jerry 一、为什么开发者需要学习 KVM&…

闭包的定义和应用场景

一、闭包是什么&#xff1f; 闭包是指函数可以“记住”并访问它定义时的词法作用域&#xff0c;即使这个函数在其作用域链之外执行。 简单说&#xff1a;函数 A 在函数 B 中被定义&#xff0c;并在函数 B 外部被调用&#xff0c;它依然能访问函数 B 中的变量&#xff0c;这就是…

北京-4年功能测试2年空窗-报培训班学测开-第五十四天

今天交付的成果是&#xff0c;初版简历虽然只写了项目部分&#xff0c;但用了一整天&#xff0c;期间联系了前司组长&#xff0c;拿到了性能测试报告。然后再看压测脚本&#xff0c;突然能看懂了&#xff0c;对服务端日志也能看懂些了&#xff0c;还找到了客户端日志怎么说呢&a…

算法训练营day24 回溯算法③ 93.复原IP地址 、78.子集、 90.子集II

今天继续回溯算法的专题&#xff0c;第三篇博客&#xff01; 93.复原IP地址 输入&#xff1a;s "25525511135" 输出&#xff1a;["255.255.11.135","255.255.111.35"] 切割字符串为4段&#xff0c;当进行到第四段的时候对第四段字符串进行判断…

jeccg-boot框架实现xls模板导出功能

文章目录一、后端部分二、前端部分三、模板制作一、后端部分 //1、在application-dev.yml文件增加模板路径path :#模板路径saxls: /data/opt/saxls/ //2、控制层写法 public class sabassalController extends JeecgController<sabassalVo, IsabassalService> {Autowired…