当前位置: 首页 > news >正文

linux之调度管理(8)-SMP cpu 的 psci启动

一、psci介绍

   psci是arm提供的一套电源管理接口,当前一共包含0.1、0.2和1.0三个版本。它可被用于以下场景:
(1)cpu的idle管理

(2)cpu hotplug以及secondary cpu启动

(3)系统shutdown和reset

  但该接口不包含dvfs和设备电源管理(如像GPU之类的外设电源管理)功能。

  由于psci与虚拟化以及trust os有一定的关联,为了专注于电源管理相关的实现,故本系列的介绍都不涉及与它们相关的内容。

  下面我们将按照电源管理拓扑结构(power domain)、电源状态(power state)以及armv8安全扩展几个方面介绍psci的一些基础知识

1.1 power domain

        我们前面已经介绍过cpu的拓扑结构,如aarch64架构下每块soc可能会包含多个cluster,而每个cluster又包含多个core,它们共同组成了层次化的拓扑结构。如以下为一块包含2个cluster,每个cluster包含四个core的soc:

        由于其中每个core以及每个cluster的电源都可以独立地执行开关操作,因此若core0 – core3的电源都关闭了,则cluster 0的电源也可以被关闭以降低功耗。若core0 – core3中的任一个core需要上电,则显然cluster 0需要先上电。为了更好地进行层次化电源管理,psci在电源管理流程中将以上这些组件都抽象为power domain。如以下为上例的power domain层次结构:

 其中system level用于管理整个系统的电源,cluster level用于管理某个特定cluster的电源,而core level用于管理一个单独core的电源。

1.2 power state

         由于aarch64架构有多种不用的电源状态,不同电源状态的功耗和唤醒延迟不同。如standby状态会关闭power domain的clock,但并不关闭电源。因此它虽然消除了门电路翻转引起的动态功耗,但依然存在漏电流等引起的静态功耗。故其功耗相对较大,但相应地唤醒延迟就比较低。

  而对于power down状态,会断开对应power domain的电源,因此其不仅消除了动态功耗,还消除了静态功耗,相应地其唤醒延迟就比较高了。

 psci一共为power domain定义了四种power state:

(1)run:电源和时钟都打开,该domain正常工作

(2)standby:关闭时钟,但电源处于打开状态。其寄存器状态得到保存,打开时钟后就可继续运行。功耗相对较大,但唤醒延迟较低。arm执行wfi或wfe指令会进入该状态。

(3)retention:它将core的状态,包括调试设置都保存在低功耗结构中,并使其部分关闭。其状态在从低功耗变为运行时能自动恢复。从操作系统角度看,除了进入方法、延迟等有区别外,其它都与standby相同。它的功耗和唤醒延迟都介于standby和power down之间。

(4)power down:关闭时钟和电源。power domain掉电后,所有状态都丢失,上电以后软件必须重新恢复其状态。它的功耗最低,但唤醒延迟也相应地最高。

        显然,power state的睡眠程度从run到power down逐步加深。而高层级power domain的power state不应低于低层级power domain。如以上例子中core 0 – core 2都为power down状态,而core 3为standby状态,则cluster 0不能为retention或power down状态。同样若cluster 0为standby状态,而cluster 1为run状态,则整个系统必须为run状态。

        当然,若core 0 –core 3都为power down状态,则cluster 1保持其它状态除了增大功耗之外,并没有其它意义,因此也应该将其设置为power down状态。

为了达到上述约束,不同power domain之间的power state具有以下关系:

        psci实现了父leve与子level之间的电源关系协调,如cluster 0中最后一个core被设置为power down状态后,psci就会将该cluster也设置为power donw状态。若其某一个core被设置为run状态,则psci会先将其对应cluster的状态设置为run,然后再设置对应core的电源状态,这也是psci名字的由来(power state coordinate interface)

1.3 armv8的安全扩展

        为了增强arm架构的安全性,aarch64一共实现了secure和non-secure两种安全状态。通过一系列硬件扩展,在cpu执行状态、总线、内存、外设、中断、tlb、cache等方面都实现了两种状态之间的隔离。

        在这种机制下,secure空间的程序可以访问所有secure和non-secure的资源,而non-secure空间的程序只能访问non-secure资源,却不能访问secure资源。从而可以将一些安全关键的资源放到secure空间,以增强其安全性。

  为此aarch64实现了4个异常等级,其中EL3工作在secure空间,而EL0 – EL2既可以工作于secure空间,又可以工作于non-secure空间。不同异常等级及不同secure状态的模式下可运行不同类型软件。

  如secure EL1和El0用于运行trust os内核及其用户态程序,non-secure EL1和El0用于运行普通操作系统内核(如linux)及其用户态程序,EL2用于运行虚拟机的hypervisor。而EL3运行secure monitor程序(通常为bl31),其功能为执行secure和non secure状态切换、消息转发以及提供类似psci等secure空间服务。以下为其示意图:

        psci是工作于non secure EL1(linux内核)和EL3(bl31)之间的一组电源管理接口,其目的是让linux实现具体的电源管理策略,而由bl31管理底层硬件相关的操作。从而将cpu电源控制这种影响系统安全的控制权限放到安全等级更高的层级中,从而提升系统的整体安全性。

  那么psci如何从EL1调用EL3的服务呢?其实它和系统调用是类似的,只是系统调用是用户态程序陷入操作系统内核,而psci是从操作系统内核陷入secure monitor。armv8提供了一条smc异常指令,内核只需要提供合适的参数后,触发该指令即可通过异常的方式进入secure monitor。

二、psci软件架构

由于psci是由linux内核调用bl31中的安全服务,实现cpu电源管理功能的。因此其软件架构包含三个部分:
(1)内核与bl31之间的调用接口规范

(2)内核中的架构

(3)bl31中的架构

2.1 psci接口规范

psci规定了linux内核调用bl31中电源管理相关服务的接口规范,它包含实现以下功能所需的接口:
(1)cpu idle管理

(2)向系统动态添加或从系统动态移除cpu,通常称为hotplug

(3)secondary cpu启动

(4)系统的shutdown和reset

  psci接口规定了命令对应的function_id、接口的输入参数以及返回值。 其中输入参数可通过x0 – x7寄存器传递,而返回值通过x0 – x4寄存器传递。

  如secondary cpu启动或cpu hotplug时可调用cpu_on接口,为一个cpu执行上电操作。该接口的格式如下:
(1)function_id:0xc400 0003

(2)输入参数:使用mpidr值表示的target cpu id

       cpu启动入口的物理地址

       context id,该值用于表示本次调用上下文相关的信息

(3)返回值:可以为success、invalid_parameter、invalid_address、already_on、on_pending或internal_failure

  有了以下这些接口的详细定义,内核和bl31就只需按照该接口的规定,独立开发psci相关功能。从而避免了它们之间的耦合,简化了开发复杂度。

2.2 内核中的psci架构

        内核psci软件架构包含psci驱动和每个cpu的cpu_ops回调函数实现两部分。其中psci驱动实现了驱动初始化和psci相关接口实现功能,而cpu_ops回调函数最终也会调用psci驱动的接口。

2.2.1 psci驱动

首先我们看一下devicetree中的配置:

psci {compatible = "arm,psci-0.2";  (1)method = "smc";               (2)}

(1)用于指定psci版本

(2)根据该psci由bl31处理还是hypervisor处理,可以指定其对应的陷入方式。若由bl31处理为smc,若由hypervisor处理则为hvc

目前我开发的英伟达板子上的设备树信息:

驱动流程主要是与bl31通信,以确认其是否支持给定的psci版本,以及相关psci操作函数的实现,其流程如下:

其主要工作即为psci设置相关的回调函数,该函数定义如下:

// kernel/drivers/firmware/psci/psci.cstatic void __init psci_0_2_set_functions(void)
{pr_info("Using standard PSCI v0.2 function IDs\n");psci_ops.get_version = psci_get_version;--------------------(1)psci_function_id[PSCI_FN_CPU_SUSPEND] =PSCI_FN_NATIVE(0_2, CPU_SUSPEND);psci_ops.cpu_suspend = psci_cpu_suspend;psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF;psci_ops.cpu_off = psci_cpu_off;psci_function_id[PSCI_FN_CPU_ON] = PSCI_FN_NATIVE(0_2, CPU_ON);psci_ops.cpu_on = psci_cpu_on;psci_function_id[PSCI_FN_MIGRATE] = PSCI_FN_NATIVE(0_2, MIGRATE);psci_ops.migrate = psci_migrate;psci_ops.affinity_info = psci_affinity_info;psci_ops.migrate_info_type = psci_migrate_info_type;pm_power_off = psci_sys_poweroff;---------------------(2)arm_pm_restart = psci_sys_reset;set_system_pmic_post_power_off_handler(psci_sys_poweroff);---(3)
}

(1)为psci_ops设置相应的回调函数

(2)为psci模块设置系统重启时的通知函数

(3)将系统的power_off函数指向相应的psci接口

这里补充一点:psci-1.0 也是先基于psci-0.2 初始化的。下面是内核源码。

static const struct of_device_id psci_of_match[] __initconst = {{ .compatible = "arm,psci",     .data = psci_0_1_init},{ .compatible = "arm,psci-0.2", .data = psci_0_2_init},{ .compatible = "arm,psci-1.0", .data = psci_1_0_init},{},
};static int __init psci_1_0_init(struct device_node *np)
{int err;err = psci_0_2_init(np);if (err)return err;if (psci_has_osi_support()) {pr_info("OSI mode supported.\n");/* Default to PC mode. */psci_set_osi_mode(false);}return 0;
}
2.2.2 cpu_ops接口

        驱动初始化完成后,cpu的cpu_ops就可以调用这些回调实现psci功能的调用。如下所示,当devicetree中cpu的enable-method设置为psci时,该cpu的cpu_ops将指向cpu_psci_ops。

cpu0: cpu@0 {...enable-method = "psci";…
}

其中cpu_psci_ops的定义如下:

//kernel/arch/arm64/kernel/psci.cconst struct cpu_operations cpu_psci_ops = {.name           = "psci",.cpu_init       = cpu_psci_cpu_init,.cpu_prepare    = cpu_psci_cpu_prepare,.cpu_boot       = cpu_psci_cpu_boot,
#ifdef CONFIG_HOTPLUG_CPU.cpu_can_disable = cpu_psci_cpu_can_disable,.cpu_disable    = cpu_psci_cpu_disable,.cpu_die        = cpu_psci_cpu_die,.cpu_kill       = cpu_psci_cpu_kill,
#endif
};

如启动cpu的接口为cpu_psci_cpu_boot,它会通过以下流程最终调用psci驱动中的psci_ops函数:

static int cpu_psci_cpu_boot(unsigned int cpu)
{phys_addr_t pa_secondary_entry = __pa_symbol(function_nocfi(secondary_entry));int err = psci_ops.cpu_on(cpu_logical_map(cpu), pa_secondary_entry);if (err)pr_err("failed to boot CPU%d (%d)\n", cpu, err);return err;
}

2.3 bl31中的psci架构(是安全系统optee-os 中的内核)

 bl31为内核提供了一系列运行时服务,psci作为其标准运行时服务的一部分,通过宏DECLARE_RT_SVC注册到系统中。其相应的定义如下:

DECLARE_RT_SVC(std_svc,OEN_STD_START,OEN_STD_END,SMC_TYPE_FAST,std_svc_setup,std_svc_smc_handler
)

        其中std_svc_setup会在bl31启动流程中被调用,以用于初始化该服务相关的配置。而std_svc_smc_handler为其smc异常处理函数,当内核通过psci接口调用相关服务时,最终将由该函数执行实际的处理流程。

上图为psci初始化相关的流程,它主要包含内容:

(1)前面我们已经介绍过power domain相关的背景,即psci需要协调不同层级的power domain状态,因此其必须要了解系统的power domain配置情况。以上流程中红色虚线框的部分主要就是用于初始化系统的power domain拓扑及其状态

(2)由于psci在执行电源相关接口时,最终需要操作实际的硬件。而它们是与架构相关的,因此其操作函数最终需要注册到平台相关的回调中。plat_setup_psci_ops即用于注册特定平台的psci_ops回调,其格式如下:

typedef struct plat_psci_ops {void (*cpu_standby)(plat_local_state_t cpu_state);int (*pwr_domain_on)(u_register_t mpidr);void (*pwr_domain_off)(const psci_power_state_t *target_state);void (*pwr_domain_suspend_pwrdown_early)(const psci_power_state_t *target_state);void (*pwr_domain_suspend)(const psci_power_state_t *target_state);void (*pwr_domain_on_finish)(const psci_power_state_t *target_state);void (*pwr_domain_on_finish_late)(const psci_power_state_t *target_state);void (*pwr_domain_suspend_finish)(const psci_power_state_t *target_state);void __dead2 (*pwr_domain_pwr_down_wfi)(const psci_power_state_t *target_state);void __dead2 (*system_off)(void);void __dead2 (*system_reset)(void);int (*validate_power_state)(unsigned int power_state,psci_power_state_t *req_state);int (*validate_ns_entrypoint)(uintptr_t ns_entrypoint);void (*get_sys_suspend_power_state)(psci_power_state_t *req_state);int (*get_pwr_lvl_state_idx)(plat_local_state_t pwr_domain_state,int pwrlvl);int (*translate_power_state_by_mpidr)(u_register_t mpidr,unsigned int power_state,psci_power_state_t *output_state);int (*get_node_hw_state)(u_register_t mpidr, unsigned int power_level);int (*mem_protect_chk)(uintptr_t base, u_register_t length);int (*read_mem_protect)(int *val);int (*write_mem_protect)(int val);int (*system_reset2)(int is_vendor,int reset_type, u_register_t cookie);
}

最后我们再看一下psci操作相应的异常处理流程:

        即其会根据function id的值,分别执行相应的电源管理服务,如启动cpu时会调用psci_cpu_on函数,重启系统时会调用psci_system_rest函数等。

三、secondary cpu启动

        由于psci方式启动secondary cpu的流程,除了其所执行的cpu_ops不同之外,其它流程与spin-table方式是相同的,因此我们这里只给出执行流程图,详细分析可以参考上篇博文。其中以下流程执行secondary cpu启动相关的一些初始化工作:

在初始化完成且hotplug线程创建完成后,就可通过以下流程唤醒cpu hotplug线程:

此后hotplug线程将调用psci回调函数,并最终触发smc异常进入bl31:

bl31接收到该异常后执行std_svc_smc_handler处理函数,并最终调用平台相关的电源管理接口,完成cpu的上电工作,以下为其执行流程:

平台相关回调函数pwr_domain_on将为secondary cpu设置入口函数,然后为其上电使该cpu跳转到内核入口secondary_entry处开始执行。以下为其内核启动流程:

相关文章:

linux之调度管理(8)-SMP cpu 的 psci启动

一、psci介绍 psci是arm提供的一套电源管理接口,当前一共包含0.1、0.2和1.0三个版本。它可被用于以下场景: (1)cpu的idle管理 (2)cpu hotplug以及secondary cpu启动 (3)系统shutdo…...

review-消息中间件MQ

RabbitMQ RabbitMQ,作为当今流行的开源消息代理软件,以其卓越的可靠性、灵活性和易用性在微服务架构和分布式系统中扮演着至关重要的角色。它不仅能够确保消息在不同系统组件间的高效传递,还能通过其高级消息队列协议(AMQP&#x…...

leetcode400第N位数字

代码 class Solution {public int findNthDigit(int n) {int base 1;//位数int weight 9;//权重while(n>(long)base*weight){//300n-base*weight;base;weight*10;}//n111 base3 weight900;n--;int res (int)Math.pow(10,base-1)n/base;int index n%base;return String…...

前端网页开发学习(HTML+CSS+JS)有这一篇就够!

目录 HTML教程 ▐ 概述 ▐ 基础语法 ▐ 文本标签 ▐ 列表标签 ▐ 表格标签 ▐ 表单标签 CSS教程 ▐ 概述 ▐ 基础语法 ▐ 选择器 ▐ 修饰文本 ▐ 修饰背景 ▐ 透明度 ▐ 伪类 ▐ 盒子模型 ▐ 浮动 ▐ 定位 JavaScript教程 ▐ 概述 ▐ 基础语法 ▐ 函数 …...

CSS遮罩:mask

CSS属性 mask 允许使用者通过遮罩或者裁切特定区域的图片的方式来隐藏一个元素的部分或者全部可见区域。 // 一般用位图图片做遮罩 mask: url(~/assets/images/mask.png); mask-size: 100% 100%;// 使用 SVG 图形中的形状来做遮罩 mask: url(~/assets/images/mask.svg#star);…...

Swift闭包的本质

1 闭包的本质其实是一个引用类型:存储在堆空间上,由堆分配空间,且生命周期由ARC(自动引用计数机制)管理 2 捕获值:闭包会捕获上下文使用到的变量(引用类型会保持引用关系)&#xff…...

时代变迁对传统机器人等方向课程的巨大撕裂

2020年之后,全面转型新质课程规划,传统课程规划全部转为经验。 农耕-代表性生产关系-封建分配制度主要生产力-人力工业-代表性生产关系-资本分配制度工业分为机械时代,电气时代,信息时代;主要生产力-人力转为人脑&…...

【算法设计与分析实训】第1关:求序列的最大字段和

务描述 本关任务:编写用动态规划解决最大字段和问题。 相关知识 为了完成本关任务,你需要掌握:动态规划。 编程要求 给定由n个整数(可能为负数)组成的序列:a1,a2,……,an, 求该序列的最大子段和。当所有整…...

【澜舟科技-注册/登录安全分析报告】

前言 由于网站注册入口容易被机器执行自动化程序攻击,存在如下风险: 暴力破解密码,造成用户信息泄露,不符合国家等级保护的要求。短信盗刷带来的拒绝服务风险 ,造成用户无法登陆、注册,大量收到垃圾短信的…...

【读书笔记-《网络是怎样连接的》- 7】Chapter3_2 路由器

本篇继续介绍路由器及其转发过程。 1 路由器内部结构 路由器内部结构图如图所示。 即主要包含左侧的包转发模块和右侧的端口模块。转发模块负责查找包的发送目的地,端口模块完成包的发送。通过安装不同的硬件,转发模块不仅可以支持以太网,也…...

Android Activity 基础接口知识和常见问题

Activity 知识点及问题点 接口onMultiWindowModeChangedonConfigurationChanged 常见问题Android解决点击桌面图标,就重新启动应用程序问题 接口 onMultiWindowModeChanged 定义 onMultiWindowModeChanged是Android中Activity类的一个回调方法。它会在活动&#xf…...

利用python 检测当前目录下的所有PDF 并转化为png 格式

以下是一个完整的 Python 脚本,用于检测当前目录下的所有 PDF 文件并将每一页转换为 PNG 格式: import os from pdf2image import convert_from_path# 设置输出图像的 DPI(分辨率) DPI 300# 获取当前目录 current_directory os…...

解决 Spring Boot 中 `Ambiguous mapping. Cannot map ‘xxxController‘ method` 错误

前言 在使用 Spring Boot 开发 Web 应用时,经常会遇到各种各样的错误。其中一种常见的错误是 Ambiguous mapping. Cannot map ‘testController‘ method。本文将详细介绍这个错误的原因及解决方法,帮助开发者快速定位并解决问题。 错误解释 这个错误…...

C++ 函数返回值优化

本文中部分内容来自下面的文章,还有一部分来自智谱清言 C 返回值优化_c 局部变量返回优化-CSDN博客 elision:省略 copy elision:拷贝省略 RVO (Return Value Optimization):返回值优化 ------ 我最近也遇到了上面博文中说到的问题&…...

c++源码阅读__ThreadPool__正文阅读

一. 简介 本章我们开始阅读c git 高星开源项目ThreadPool, 这是一个纯c的线程池项目, 并且代码量极小, 非常适合新手阅读 git地址: progschj / ThreadPool 二. 前提知识 为了面对不同读者对c掌握情况不同的情况, 这里我会将基本上稍微值得一说的前提知识点, 全部专门写成一篇…...

关于ES的查询

查询结果那么多字段都是什么? 为什么会提到这个问题呢,因为默认ES查询的结果会有很多信息,我们可能并不希望要那么多数据,所以你需要了解这些字段都表示什么,并正确的返回和使用它们。 took– Elasticsearch 运行查询…...

数据结构初识

目录 1.初识 2.时间复杂度 常见时间复杂度举例: 3.空间复杂度 4.包装类&简单认识泛型 4.1装箱和拆箱 5.泛型 6.泛型的上界 7.泛型方法 8.List接口 1.初识 1.多画图 2.多思考 3.多写代码 4.多做题 牛客网-题库/在线编程/剑指offer 算法篇&#xff1a…...

保存数据到Oracle时报错ORA-17004: 列类型无效: 1111

1、问题描述: 关键信息:Mybatis;Oracle (1)保存信息到Oracle时报错: Caused by: org.apache.ibatis.type.TypeException: Error setting null for parameter #10 with JdbcType OTHER . Try setting a dif…...

Excel——宏教程(1)

Microsoft excel是一款功能非常强大的电子表格软件。它可以轻松地完成数据的各类数学运算,并用各种二维或三维图形形象地表示出来,从而大大简化了数据的处理工作。但若仅利用excel的常用功能来处理较复杂的数据,可能仍需进行大量的人工操作。…...

论文浅尝 | MindMap:知识图谱提示激发大型语言模型中的思维图(ACL2024)

笔记整理:和东顺,天津大学硕士,研究方向为软件缺陷分析 论文链接:https://aclanthology.org/2024.acl-long.558/ 发表会议:ACL 2024 1. 动机 虽然大语言模型(LLMs)已经在自然语言理解和生成任务…...

【Python】 -- 趣味代码 - 小恐龙游戏

文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

C++初阶-list的底层

目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

2.Vue编写一个app

1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

汇编常见指令

汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX&#xff08;不访问内存&#xff09;XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

算法岗面试经验分享-大模型篇

文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer &#xff08;1&#xff09;资源 论文&a…...

JavaScript 数据类型详解

JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型&#xff08;Primitive&#xff09; 和 对象类型&#xff08;Object&#xff09; 两大类&#xff0c;共 8 种&#xff08;ES11&#xff09;&#xff1a; 一、原始类型&#xff08;7种&#xff09; 1. undefined 定…...

MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用

文章目录 一、背景知识&#xff1a;什么是 B-Tree 和 BTree&#xff1f; B-Tree&#xff08;平衡多路查找树&#xff09; BTree&#xff08;B-Tree 的变种&#xff09; 二、结构对比&#xff1a;一张图看懂 三、为什么 MySQL InnoDB 选择 BTree&#xff1f; 1. 范围查询更快 2…...

如何做好一份技术文档?从规划到实践的完整指南

如何做好一份技术文档&#xff1f;从规划到实践的完整指南 &#x1f31f; 嗨&#xff0c;我是IRpickstars&#xff01; &#x1f30c; 总有一行代码&#xff0c;能点亮万千星辰。 &#x1f50d; 在技术的宇宙中&#xff0c;我愿做永不停歇的探索者。 ✨ 用代码丈量世界&…...

如何使用CodeRider插件在IDEA中生成代码

一、环境搭建与插件安装 1.1 环境准备 名称要求说明操作系统Windows 11JetBrains IDEIntelliJ IDEA 2025.1.1.1 (Community Edition)硬件配置推荐16GB内存50GB磁盘空间 1.2 插件安装流程 步骤1&#xff1a;市场安装 打开IDEA&#xff0c;进入File → Settings → Plugins搜…...