cpufreq子系统

cpufreq是linux上负责实现动态调频的关键,这篇笔记总结了linux内核cpufreq子系统的关键实现(Linux 3.18.140)。

概述

借用一张网络上的图片来看cpufreq子系统的整体结构:

  • 用户态接口:cpufreq通过sysfs向用户态暴露接口,这些节点部分是为了展示内核的配置,部分节点是可以配置的,通过这些节点可以控制cpufreq的一些行为。
  • core层:cpufreq子系统的核心层,负责管理子系统中的policy、governor和driver组件,是三者的纽带,通过core层,实现了调频策略和调频机制的分离。
  • policy:调频策略,每个CPU都有一个调频策略,规定了该CPU的最大、最小可运行频率等信息。
  • governor:可以独立于core层实现,通过规定的接口和core层交互。policy必须和某个governor关联,由governor实现具体的调频策略。可以认为policy负责管理调频参数,governor基于调频参数实现调频策略。
  • driver:平台相关的调频驱动,core层使用driver中的接口完成具体的调频操作。
  • notifier:cpufreq基于通知链机制对外发布的通知事件,外部模块可以通过监听这些事件在CPU的调频策略或者频率发生变化时做出一些处理。
  • stats:一些频率调整的统计信息,我们不关注。

这篇笔记我们重点关注core层的实现,其它部分模块仅作简要介绍。

core层关键实现

core层是cpufreq子系统的关键,它主要包含下面内容:

  1. driver的管理。
  2. policy的管理。
  3. governor的管理。
  4. 事件通知。
  5. 用户态接口。
  6. 为了方便driver、governor实现而提供的一些公共的API。

core层初始化

开机过程中,core层最开始的初始化非常简单,仅仅是创建一个kobject对象,该对象在sysfs中对应到目录/sys/devices/system/cpu/cpufreq

struct kobject *cpufreq_global_kobject;static int __init cpufreq_core_init(void)
{if (cpufreq_disabled()) // cpu动态调频功能未使能return -ENODEV;// 创建kobject代表cpufreqcpufreq_global_kobject = kobject_create();return 0;
}
core_initcall(cpufreq_core_init);

driver的管理

cpufreq驱动的实现需要实例化一个struct cpufreq_dirver对象,然后通过cpufreq_register_driver()函数向core层注册自己。系统只需要一个cpufreq驱动来实现具体的CPU频率调整功能,所以core层只允许注册一个驱动。

struct cpufreq_driver

下面是cpufreq_driver的一些核心字段:

  • init():该回调必须实现,core层在为CPU设置policy时会用分配的policy为参数调用驱动的该回调,驱动需要在实现中设置policy的部分字段。
  • verify():该回调必须实现,core层会通过该回调让驱动校验policy中的参数设置是否正确。
  • setpolicy()、target()、target_index():这几个回调必须实现一个。当实现setpolicy()时,驱动表示软件只需要设置一个策略参数(如功耗优先or性能优先)即可,硬件来决定具体的CPU工作频率。当实现后两个回调时,表示需要由governor来决定CPU的具体工作频率,然后通过这两个接口将CPU工作频率设定为指定值。
struct cpufreq_driver {char name[CPUFREQ_NAME_LEN]; // 驱动名称会在sysfs中体现u8 flags; // 表明一些驱动的featurevoid *driver_data; // cpufreq驱动自己的指针,core层不关注int    (*init)    (struct cpufreq_policy *policy);int    (*verify)    (struct cpufreq_policy *policy);int    (*setpolicy)    (struct cpufreq_policy *policy);int    (*target)    (struct cpufreq_policy *policy,    /* Deprecated */unsigned int target_freq,unsigned int relation);int    (*target_index)    (struct cpufreq_policy *policy,
unsigned int index);// 可选的,但一般都会实现。获取指定CPU的当前工作频率unsigned int    (*get)    (unsigned int cpu);struct freq_attr    **attr; // 驱动可以定义一些自己需要在sysfs中体现的参数
...    
};

注册cpufreq驱动

core层为驱动提供了cpufreq_register_driver()函数来注册cpufreq驱动,cpufreq_unregister_driver()是去注册接口,不再展开。注册过程包含三个关键逻辑:

  1. 检查drver实例中的参数设置是否正确。
  2. 保存driver实例到全局变量cpufreq_driver中,相当于完成注册。
  3. 触发为系统中的CPU设置policy的流程,该流程见下文分析。
static struct subsys_interface cpufreq_interface = {.name = "cpufreq",.subsys = &cpu_subsys, // cpu子系统.add_dev = cpufreq_add_dev, // 向cpufreq子系统添加和移除cpu的回调.remove_dev    = cpufreq_remove_dev,
};int cpufreq_register_driver(struct cpufreq_driver *driver_data)
{unsigned long flags;// 检查驱动的回调实现是否正确if (!driver_data || !driver_data->verify || !driver_data->init ||!(driver_data->setpolicy || driver_data->target_index ||driver_data->target) ||(driver_data->setpolicy && (driver_data->target_index ||driver_data->target)) ||(!!driver_data->get_intermediate != !!driver_data->target_intermediate))return -EINVAL;if (driver_data->setpolicy)driver_data->flags |= CPUFREQ_CONST_LOOPS;// cpufreq驱动只能注册一个,保存到全局变量cpufreq_driver中write_lock_irqsave(&cpufreq_driver_lock, flags);if (cpufreq_driver) {write_unlock_irqrestore(&cpufreq_driver_lock, flags);return -EEXIST;}cpufreq_driver = driver_data;write_unlock_irqrestore(&cpufreq_driver_lock, flags);// 这一步会为系统的所有CPU设置policyret = subsys_interface_register(&cpufreq_interface);// 监听CPU热插拔事件register_hotcpu_notifier(&cpufreq_cpu_notifier);
}

policy的管理

调频策略用struct cpufreq_policy来描述。系统中每个CPU都必须有一个调频策略,由于可能存在多个CPU共用一个调频策略的情况(如手机上常见的一个cluster中的CPU频率必须保持一致),所以系统中实际的cpufreq_policy对象数量可能少于CPU个数。core层用Per-CPU变量为每个CPU保存对应的cpufreq_policy对象指针。

static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
// 系统中所有的cpufreq_policy对象组织到全局链表中
static LIST_HEAD(cpufreq_policy_list);

struct cpufreq_policy

cpufreq_policy代表一个CPU调频策略,其关键字段如下:

struct cpufreq_policy {// 共享该policy的CPU掩码,cpus为online状态的CPU集合,related_cpus为所有共享该plocy的CPU集合cpumask_var_t cpus;cpumask_var_t related_cpus;unsigned int cpu; // 每个policy都有一个管理cpuunsigned int last_cpu; // 由于CPU可以热插拔,保存前一个管理该policy的CPU// CPU支持的最大、最小等频率信息,由驱动设置struct cpufreq_cpuinfo cpuinfo;/* see above */unsigned int min;    /* in kHz */unsigned int max;    /* in kHz */unsigned int cur;    /* in kHz, only needed if cpufreqgovernors are used */unsigned int policy; // 硬件自己控制具体的CPU频率时才使用该字段struct cpufreq_governor    *governor; // 软件控制频率时,具体的governor实现void *governor_data;bool governor_enabled; /* governor start/stop flag */// CPU的工作频率并非是可以调节为任意值的,驱动提供了可调节的频率挡位struct cpufreq_frequency_table    *freq_table;struct list_head policy_list; // 将该policy组织到全局链表中
};// 所有的policy对象保存到全局链表中
DEFINE_MUTEX(cpufreq_governor_lock);
static LIST_HEAD(cpufreq_policy_list);

设置CPU的policy

在驱动注册的最后,会调用subsys_interface_register()函数遍历系统中所有CPU,将每个CPU以设备的方式通过cpufreq_add_dev()函数添加到core层,这时会为CPU设置调频策略。

static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
{return __cpufreq_add_dev(dev, sif);
}static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
{unsigned int j, cpu = dev->id;int ret = -ENOMEM;struct cpufreq_policy *policy;unsigned long flags;bool recover_policy = cpufreq_suspended;if (cpu_is_offline(cpu)) // 只为online的CPU分配调频策略return 0;#ifdef CONFIG_SMP// 可能存在多个CPU共用一个策略的情况,所以如果该CPU已经设置了策略,则处理结束policy = cpufreq_cpu_get(cpu);if (unlikely(policy)) {cpufreq_cpu_put(policy);return 0;}
#endif// 分配一个policy对象policy = recover_policy ? cpufreq_policy_restore(cpu) : NULL;if (!policy) {recover_policy = false;policy = cpufreq_policy_alloc();}// 设置该CPU为policy的管理CPUif (recover_policy && cpu != policy->cpu)WARN_ON(update_policy_cpu(policy, cpu, dev));elsepolicy->cpu = cpu;cpumask_copy(policy->cpus, cpumask_of(cpu)); // 当前cpu属于该policy管理init_completion(&policy->kobj_unregister);INIT_WORK(&policy->update, handle_update);// 调用驱动的init回调。驱动会设置policy中的参数ret = cpufreq_driver->init(policy);// 驱动在init()回调中必须正确的设置哪些CPU会共享该policy,这样core层才能正确设置policy中的cpus字段cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus);cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);if (!recover_policy) {policy->user_policy.min = policy->min;policy->user_policy.max = policy->max;}// 为共用同一个policy的其它CPU设置Per-CPU指针,指向分配的policy对象write_lock_irqsave(&cpufreq_driver_lock, flags);for_each_cpu(j, policy->cpus)per_cpu(cpufreq_cpu_data, j) = policy;write_unlock_irqrestore(&cpufreq_driver_lock, flags);// 获取CPU的当前工作频率if (cpufreq_driver->get && !cpufreq_driver->setpolicy) {policy->cur = cpufreq_driver->get(policy->cpu);}// 对于那种开机时不以可调节频率表中频率运行的情况,这里将CPU的频率调整为一个已知的频率if ((cpufreq_driver->flags & CPUFREQ_NEED_INITIAL_FREQ_CHECK) && has_target()) {/* Are we running at unknown frequency ? */ret = cpufreq_frequency_table_get_index(policy, policy->cur);if (ret == -EINVAL) {ret = __cpufreq_driver_target(policy, policy->cur - 1, CPUFREQ_RELATION_L);}}// 发送CPUFREQ_START通知blocking_notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_START, policy);if (!recover_policy) {// 为policy在sysfs中创建属性文件,即/sys/devices/system/cpu/cpufreq/policyX/XXX文件ret = cpufreq_add_dev_interface(policy, dev);// 发送CPUFREQ_CREATE_POLICY通知blocking_notifier_call_chain(&cpufreq_policy_notifier_list,CPUFREQ_CREATE_POLICY, policy);}// 将policy对象加入到全局链表中write_lock_irqsave(&cpufreq_driver_lock, flags);list_add(&policy->policy_list, &cpufreq_policy_list);write_unlock_irqrestore(&cpufreq_driver_lock, flags);// 为policy关联governorcpufreq_init_policy(policy);if (!recover_policy) {policy->user_policy.policy = policy->policy;policy->user_policy.governor = policy->governor;}
}
  1. 只有online状态的cpu才会设置调频策略。
  2. cpufreq_cpu_get()函数根据Per-CPU变量cpufreq_cpu_data的设置,检查该CPU是否和其它CPU复用了一个policy对象,如果是则不需要进行后续的处理。
  3. 分配一个policy对象,将当前cpu设置为该policy的管理CPU。然后调用驱动的init()回调,驱动必须在该回调中对policy中的cpu、频率的信息进行正确的设置。
  4. 继续用驱动设置好的参数设置policy中的其它字段。特别重要的一步是将该共享的policy对象设置到其它CPU的cpufreq_cpu_data中。
  5. 对外发送通知,并在sysfs中为该policy创建属性节点。
  6. 将policy加入全局的cpufreq_policy_list链表中。
  7. 为该policy设置governor,该流程见下文介绍。

governor的管理

policy的调频策略实际由governor实现的,系统可以有多个governor,这些governor注册到core层后,用户态可以通过sysfs节点来为CPU指定具体使用哪个governor。系统用链表保存所有支持的governor。

static LIST_HEAD(cpufreq_governor_list);

core层提供了governor的注册函数cpufreq_register_governor(),实现很简单,不再展开。

struct governor

每个governor都需要实例化一个该对象,然后将其注册到core层。

struct cpufreq_policy {
...struct cpufreq_governor    *governor;void *governor_data;
}struct cpufreq_governor {char name[CPUFREQ_NAME_LEN]; // 每个governor都有一个唯一的名字int    initialized;// 处理governor的启动和停止事件int    (*governor)    (struct cpufreq_policy *policy,unsigned int event);ssize_t    (*show_setspeed)    (struct cpufreq_policy *policy,char *buf);int    (*store_setspeed)    (struct cpufreq_policy *policy,unsigned int freq);// governor实现对驱动的约束,要求驱动切换频率的最大时延必须小于该值unsigned int max_transition_latency;struct list_head governor_list; // 将governor组织到全局链表中};

为policy设置governor

policy的调频策略需要由governor来实现,如前面“设置CPU的policy”中分析,CPU设置了policy后,需要为policy关联一个governor。这是通过cpufreq_init_policy()函数完成的。用户态可以通过sysfs修改policy的governor,此时也会触发类似的流程。

// 记录每个CPU的governor,如果不配置则为其选择默认的governor
static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);static void cpufreq_init_policy(struct cpufreq_policy *policy)
{struct cpufreq_governor *gov = NULL;struct cpufreq_policy new_policy; // 借助一个临时变量完成设置过程int ret = 0;memcpy(&new_policy, policy, sizeof(*policy));// 根据名字从全局链表中选择governor,开机时可能尚未配置,选择一个默认的配置,默认配置来自系统configgov = __find_governor(per_cpu(cpufreq_cpu_governor, policy->cpu));if (gov)pr_debug("Restoring governor %s for cpu %d\n", policy->governor->name, policy->cpu);elsegov = CPUFREQ_DEFAULT_GOVERNOR;new_policy.governor = gov;if (cpufreq_driver->setpolicy)cpufreq_parse_governor(gov->name, &new_policy.policy, NULL);// 用新的配置更新当前policyret = cpufreq_set_policy(policy, &new_policy);
}// policy : current policy.new_policy: policy to be set.
static int cpufreq_set_policy(struct cpufreq_policy *policy,struct cpufreq_policy *new_policy)
{struct cpufreq_governor *old_gov;int ret;memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo));// 让驱动校验policy的参数设置是否正确ret = cpufreq_driver->verify(new_policy);// 发送CPUFREQ_ADJUST通知blocking_notifier_call_chain(&cpufreq_policy_notifier_list,CPUFREQ_ADJUST, new_policy);blocking_notifier_call_chain(&cpufreq_policy_notifier_list,CPUFREQ_INCOMPATIBLE, new_policy);// 上述的通知过程中可以调整policy,重新校验policy参数设置ret = cpufreq_driver->verify(new_policy);/* notification of the new policy */blocking_notifier_call_chain(&cpufreq_policy_notifier_list,CPUFREQ_NOTIFY, new_policy);policy->min = new_policy->min;policy->max = new_policy->max;if (cpufreq_driver->setpolicy) { // 驱动只需要设置策略的情形policy->policy = new_policy->policy;return cpufreq_driver->setpolicy(new_policy);}if (new_policy->governor == policy->governor)goto out;// 更新governor,对旧的governor执行STOP和EXIT,对新的governor执行INIT和STARTold_gov = policy->governor;if (old_gov) {__cpufreq_governor(policy, CPUFREQ_GOV_STOP);up_write(&policy->rwsem);__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);down_write(&policy->rwsem);}policy->governor = new_policy->governor;if (!__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT)) {if (!__cpufreq_governor(policy, CPUFREQ_GOV_START))goto out;}
}

事件通知

事件通知虽然也是在core层实现的,但是它是相对独立的内容,这里单独对其进行分析。

cpufreq子系统利用Linux标准的通知链机制,实现了两种通知:policy通知Transition通知。外部模块可以监听这两种通知事件,在事件发生时执行一些需要的逻辑。

// 通知监听接口
int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list);
int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);// list参数代表了要监听的通知类型
#define CPUFREQ_TRANSITION_NOTIFIER    (0)
#define CPUFREQ_POLICY_NOTIFIER        (1)static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list);
static struct srcu_notifier_head cpufreq_transition_notifier_list;

policy通知

cpufreq子系统在CPU的policy发生变化时,会依次发送三个policy通知事件:

  1. 首先发出CPUFREQ_ADJUST事件,给通知接收者一个机会来修改policy中的参数,比如温控模块可能会修改其最大频率。
  2. 然后发出CPUFREQ_INCOMPATIBLE事件,给通知接收者一个机会来检查policy的参数是否和硬件不兼容,如果不兼容可以修改。这两个事件时挨着依次发出的,除了事件含义不同外,效果完全相同,所以事件接收者完全可以在一个事件中将所有该处理的事情执行完毕。
  3. 最后发出CPUFREQ_NOTIFY事件告诉通知接收者,将以该policy作为最终配置。
/* Policy Notifiers  */
#define CPUFREQ_ADJUST            (0)
#define CPUFREQ_INCOMPATIBLE        (1)
#define CPUFREQ_NOTIFY            (2)// 另外几个事件用来通知policy对象的生命周期变化
#define CPUFREQ_START            (3)
#define CPUFREQ_UPDATE_POLICY_CPU    (4)
#define CPUFREQ_CREATE_POLICY        (5)
#define CPUFREQ_REMOVE_POLICY        (6)

Transition通知

cpufreq子系统在CPU的频率发生变化前后,会依次发送两个Transition通知事件,携带的参数表明了修改的CPU及其变化前后的频率。

/* Transition notifiers */
#define CPUFREQ_PRECHANGE        (0)
#define CPUFREQ_POSTCHANGE        (1)struct cpufreq_freqs {unsigned int cpu;    /* cpu nr */unsigned int old;unsigned int new;u8 flags;        /* flags of cpufreq_driver, see below. */
};

用户态接口

cpufreq子系统在sysfs中有如下接口,通过这些既可以展示一些配置信息,也给用户态提供了一些可调整的参数。

cpufreq子系统的总目录是/sys/devices/system/cpu/cpufreq,下面是系统中所有的policy实例,每个policy目录名中的数字是该policy的管理CPU ID。其中schedutil是一种基于调度器的governor,该目录保存了该governor在sysfs中的内容。

每个policyX目录下是该policy暴露的节点,这些节点大部分是只读的,其含义如下:

  • affected_cpusreleated_cpu分别对应内核中policy->cpus和policy->releated_cpus,是该policy管理的CPU掩码。
  • cpuinfo_xxx_freq字段表示该CPU可以支持CPU频率,单位为kHZ。
  • cpuinfo_transition_latency字段表示该CPU频率切换需要的时延,单位为ns。
  • scaling_available_frequencies表示该组CPU可以调整的频率挡位;scaling_available_governors表示该组CPU可以选择的governor;scaling_driver表示当前的驱动名称;scaling_governor表示当前的governor名称。
  • scaling_xxx_freq表示当前该CPU上配置的可调节频率信息。
  • 用户态可以通过向scaling_setspeed节点写入频率来调整CPU频率,当然内核可能会不支持该操作。

每个CPU都必须有一种policy,所以在cpu的目录下会有一个软链接指向对应的policy目录:

参考资料

  1. cpufreq schedutil原理剖析-CSDN博客;
  2. https://www.cnblogs.com/LoyenWang/p/11385811.html;
  3. 内核Doc:Documentation/cpu-freq/core.txt;

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

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

相关文章

Java知识点:泛型、类加载器、内部类、可变参数

文章目录 1、this关键字2、泛型2.1 泛型介绍2.2 泛型分类定义2.2.1 泛型类2.2.2 泛型方法2.2.3 泛型接口 2.3 泛型通配符 3、可变参数4、日志4.1 使用步骤4.2 日志级别4.3 配置文件 5、类加载器5.1 类加载器5.2 类加载的完整过程5.2.1 类加载时机5.2.2 类加载过程 5.3 类加载的…

【开源项目】超经典开源项目实景三维数字孪生智慧工厂

数字孪生工厂,以模型驱动的自动化,与数据驱动的人工智能技术紧密融合与协同,实现机器、工件与组件间全面的和点对点的数据通信。飞渡科技基于自研DTS平台,将物联网IOT、人工智能、大数据、云计算等技术应用于工厂,实现…

期货日数据维护与使用_日数据维护_模块运行演示

写在前面: 本文默认已经创建了项目,如果不知道如何创建一个空项目的,请参看以下两篇博文 PyQt5将项目搬到一个新的虚拟环境中 https://blog.csdn.net/m0_37967652/article/details/122625280 python_PyQt5开发工具结构基础 https://blog.cs…

TMC4671闭环调试步进、伺服、音圈、永磁、无刷电机

一、IDE 连接开发板 下 面 讲 解 IDE 和 开 发 板 连 接 的 详 细 操 作 。 这 里 我 们 选 择 用 主 控 板 TMC671-EVALTMC6200-EVAL 开发板做讲解。其它型号的开发板也是大同小异 的操作步骤。 1.首先我连接好开发板,并给开发板上电 连接好的开发板如下…

【激活函数】SELU 激活函数

1、介绍 SELU (Scaled Exponential Linear Unit) SELU是对ELU激活函数的改进,通过引入自动标准化机制,使得神经网络的隐藏层在训练过程中可以自动地保持输出的均值和方差接近于1。 # 定义 SELU 激活函数 def selu(x, alpha1.67326, lambda_1.0507):retu…

【Python百宝箱】数据清洗艺术:Python库助力打磨完美数据

数据清洗与预处理:Python库大揭秘 前言 在数据科学领域,数据清洗和预处理是构建可靠模型的关键步骤。本文深入探讨了一系列强大的Python库,它们在处理重复数据、字符串匹配、数据整理以及降维等方面发挥着重要作用。通过学习这些库&#xf…

单片机相关知识点

在STM32上运行FreeRTOS,十分简练的小文章FreeRTOS(STM32CubeMX)_cubemx freertos-CSDN博客 STM32CubeMX转Keil使用STM32CubeMX生成Keil工程并完成流水灯-CSDN博客

unity PDFRender Curved UI3.3

【PDF】PDFRender 链接:https://pan.baidu.com/s/1wSlmfiWTAHZKqEESxuMH6Q 提取码:csdn 【曲面ui】 Curved UI3.3 链接:https://pan.baidu.com/s/1uNZySJTW0-pPwi2FTE6fgA 提取码:csdn

【unity小技巧】FPS游戏实现相机的震动、后坐力和偏移

最终效果 文章目录 最终效果前言相机的震动实现后坐力和偏移相机震动相机震动脚本换弹节点震动 武器射击后退效果完结 前言 关于后坐力之前其实已经分享了一个:FPS游戏后坐力制作思路 但是实现起来比较复杂,如果你只是想要简单的实现,可以看…

Linux ssh 实现远程免密登录

一、背景 我搭建了一个 zookeeper 集群,写了一个 shell 脚本来控制集群的启动和关闭,但是我发现每次我执行 shell 脚本的时候,都需要我输入各个服务器的密码才可以运行,感觉很麻烦。shell 脚本里面连接其他服务器用的就是 ssh 的方…

Linux安装JDK和Maven并配置环境变量

文章目录 一、安装JDK并配置环境变量二、安装maven并配置环境变量 一、安装JDK并配置环境变量 将JDK的安装包上传到Linux系统的usr/local目录 使用xftp上传文件 解压JDK的压缩包 xshell连接到云主机 [roottheo ~]# cd /usr/local[roottheo local]# ls aegis apache-tomcat-…

equals()方法和“==”运算符

equals()equals()方法和“”运算符比较 回到顶部 equals() 超类Object中有这个equals()方法,该方法主要用于比较两个对象是否相等。该方法的源码如下: public boolean equals(Object obj) {return (this obj);} 我们知道所有的对象都拥有标识(内存…

使用LVM分区方式安装Manjaro发行版

使用LVM分区方式安装Manjaro发行版 为什么单独介绍LVM方式呢? 主要是由于使用系统的图形安装工具创建卷组会出问题,会导致图形安装工具直接挂掉,唯一的方法是提前手动创建好卷组。 GPT分区表 分区表有: MBR(主引导记录分区表)…

【华为OD真题 Python】两数之和绝对值最小

文章目录 题目描述输入描述输出描述示例1输入输出说明代码实现题目描述 给定一个从小到大的有序整数序列(存在正整数和负整数)数组 nums ,请你在该数组中找出两个数,其和的绝对值(|nums[x]+nums[y]|)为最小值,并返回这个绝对值。 每种输入只会对应一个答案。但是,数组中…

性能优化-OpenMP概述(一)-宏观全面理解OpenMP

本文旨在从宏观角度来介绍OpenMP的原理、编程模型、以及在各个领域的应用、使用、希望读者能够从本文整体上了解OpenMP。 🎬个人简介:一个全栈工程师的升级之路! 📋个人专栏:高性能(HPC)开发基础…

【算法】链表-20240105

这里写目录标题 一、LCR 023. 相交链表二、142. 环形链表 II 一、LCR 023. 相交链表 给定两个单链表的头节点 headA 和 headB ,请找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。 提示: listA 中节点数目为 m list…

window 下载安装 Studio 3T

这里 我们先访问官网 https://studio3t.com/ 然后 他会弹出提示 如果您同意使用cookies和类似技术进行市场研究或广告目的,并希望获得额外功能,您可以点击“Accept all”按钮。 如果您不同意使用cookies和类似技术进行上述目的,您可以点击“…

大模型的实践应用16-一种针对大型预训练模型的微调技巧:Adapter-Tuning方法的实战应用,原理详细介绍

大家好,我是微学AI,今天给大家介绍一下大模型的实践应用16-一种针对大型预训练模型的微调技巧:Adapter-Tuning方法的实战应用,原理详细介绍。Adapter-Tuning 是一种针对大型预训练模型微调的技术,它可以在保持模型参数数量较小的情况下增加模型的表现。该技术将适配器插入…

ffmpeg 改变帧率,分辨率,时长等命令

ffmpeg -i elva.mp4 -ss 00:00:20 -t 00:00:30 -c:v copy -c:a copy output1.mp4 视频截取,开始时间和时长,-ss 00:00:20 -t 00:00:30 ffmpeg -i output1.mp4 -c:v libx265 output265.mp4 -c:v libx265,264转265 ffmpeg -i output1.mp4 -c:v libx264 output264.mp4 …

Java面试项目推荐,异构数据源数据流转服务DatalinkX

前言 作为一个年迈的夹娃练习生,每次到了春招秋招面试实习生时都能看到一批简历,十个简历里得有七八个是写商城或者外卖项目。 不由得想到了我大四那会,由于没有啥项目经验,又想借一个质量高点的项目通过简历初筛,就…