企业没有网站怎样做推广方案/怎么制作网站教程步骤
CPU 拓扑用来表示 CPU 在硬件层面的组合方式,本文主要讲解 CPU 拓扑中的 SMP(Symmetric Multi-Processor,对称多处理器系统)架构,CPU 拓扑还包括其他信息,比如:cache 等,这些部分会在后面进行补充。CPU 拓扑除了描述 CPU 的组成关系外,还为内核的调度器提供服务,从而提供更好的性能。在 StratoVirt 中,支持 CPU 拓扑为后续的 CPU 热插拔开发打下一个基础。
常见的 CPU SMP 结构是:
Socket --> die --> cluster --> core --> thread
-
socket:对应主板上的 CPU 插槽
-
die:处理器在生产过程中,从晶圆上切割下来的一个个小方块,Die 之间的组件是通过片内总线互联的。
-
cluster:簇,大核或者小核的一种组合
-
core:表示独立的物理 CPU
-
thread:逻辑 CPU,英特尔超线程技术引入的新概念
CPU 拓扑的获取原理
因为 x86 和 ARM 的拓扑获取方式不同,下面将会分开进行介绍。
x86
在 x86 架构下面,操作系统会通过读取 CPUID 来获取 CPU 拓扑结构。在 x86 体系结构中,CPUID 指令(由 CPUID 操作码标识)是处理器补充指令(其名称源自 CPU 标识),允许软件发现处理器的细节。程序可以使用 CPUID 来确定处理器类型。
CPUID 隐式使用 EAX 寄存器来确定返回的信息的主要类别,这被称为 CPUID 叶。跟 CPU 拓扑相关的 CPUID 叶分别是:0BH 和 1FH。1FH 是 0BH 的扩展,可以用来表示更多的层级。Intel 建议先检查 1FH 是否存在,如果 1FH 存在会优先使用它。当 EAX 的值被初始化为 0BH 的时候,CPUID 会在 EAX,EBX,ECX 和 EDX 寄存器中返回 core/logical 处理器拓扑信息。这个函数(EAX=0BH)要求 ECX 同时被初始化为一个 index,这个 index 表示的是在 core 层级还是 logical processor 层级。OS 调用这个函数是按 ECX=0,1,2..n 这个顺序调用的。返回处理器拓扑级别的顺序是特定的,因为每个级别报告一些累积数据,因此一些信息依赖于从先前级别检索到的信息。在 0BH 下,ECX 可以表示的层级有:SMT 和 Core,在 1FH 下,可以表示的层级有:SMT,Core,Module,Tile 和 Die。
下表是一个更详细的一个解释:
Initial EAX Value | Information Provided about the Processor |
---|---|
0BH | EAX Bits 04 - 00: Number of bits to shift right on x2APIC ID to get a unique topology ID of the next level type*. All logical processors with the same next level ID share current level. Bits 31 - 05: Reserved. EBX Bits 15 - 00: Number of logical processors at this level type. The number reflects configuration as shipped by Intel. Bits 31- 16: Reserved. ECX Bits 07 - 00: Level number. Same value in ECX input. Bits 15 - 08: Level type. Bits 31 - 16: Reserved. EDX Bits 31- 00: x2APIC ID the current logical processor. |
1FH | EAX Bits 04 - 00: Number of bits to shift right on x2APIC ID to get a unique topology ID of the next level type*. All logical processors with the same next level ID share current level. Bits 31 - 05: Reserved. EBX Bits 15 - 00: Number of logical processors at this level type. The number reflects configuration as shipped by Intel. Bits 31- 16: Reserved. ECX Bits 07 - 00: Level number. Same value in ECX input. Bits 15 - 08: Level type. Bits 31 - 16: Reserved. EDX Bits 31- 00: x2APIC ID the current logical processor |
来源: Intel 64 and IA-32 Architectures Software Developer's Manual
ARM
在 ARM 架构下,如果操作系统是依靠 Device Tree 启动的,则会通过 Device Tree 去获取 CPU 拓扑。如果是以 ACPI 的方式启动的话,操作系统会通过解析 ACPI 的 PPTT 表去获取 CPU 拓扑结构。
ACPI——PPTT
ACPI 是 Advanced Configuration and Power Interface (高级配置和电源接口)的缩写,ACPI 是一种与体系结构无关的电源管理和配置框架。这个框架建立了一个硬件寄存器集合来定义电源状态。ACPI 是操作系统和固件之间的一个中间层,是他们两者之间的一个接口。ACPI 定义了两种数据结构:data tables 和 definition blocks。data tables 用于存储给设备驱动使用的 raw data。definition blocks 由一些字节码组成,这些码可以被解释器执行。
为了使硬件供应商在选择其实施时具有灵活性,ACPI 使用表格来描述系统信息、功能和控制这些功能的方法。这些表列出了系统主板上的设备或无法使用其他硬件标准检测或电源管理的设备,以及 ACPI 概念中所述的功能。它们还列出了系统功能,如支持的睡眠电源状态、系统中可用的电源平面和时钟源的说明、电池、系统指示灯等。这使 OSPM 能够控制系统设备,而不需要知道系统控制是如何实现的。
PPTT 表就是其中的一个表格,PPTT 表全称是 Processor Properties Topology Table,处理器属性拓扑表用于描述处理器的拓扑结构,该表还可以描述附加信息,例如处理器拓扑中的哪些节点构成物理包。
下表是 PPTT 表的结构,包含一个表头和主体,表头和其他的 ACPI 表差别不大。其中 Signature
用于表示这是 PPTT 表,Length
是整张表的大小,其他的信息可以查看下面的这张表。表的主体是一系列处理器拓扑结构。
下面的表表示处理器层级节点结构,表示处理器结构的话 Type
要设置为 0,Length
表示这个节点的字节数。Flags
用来描述跟处理器相关的信息,详细的看后面关于 Flags
的详细信息。Parent
用于指向这个节点的上一级节点,存放的是一个偏移量地址
下表是 Flags
的结构,Flags
占据 4 个字节的长度。Physical package
:如果处理器拓扑的此节点表示物理封装的边界,则设置 Physical package
为 1。如果处理器拓扑的此实例不表示物理软件包的边界,则设置为 0。Processor is a Thread
:对于叶条目:如果代表此处理器的处理元素与兄弟节点共享功能单元,则必须将其设置为 1。对于非叶条目:必须设置为 0。Node is a Leaf
:如果节点是处理器层次结构中的叶,则必须设置为 1。否则必须设置为 0。
参考:https://uefi.org/specs/ACPI/6.4/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#processor-properties-topology-table-pptt
Device Tree
Device Tree 是一种描述硬件的数据结构。内核的启动程序会将设备树加载入内存中,然后通过解析 Device Tree 来获取硬件细节。Device Tree 是树形结构,由一系列被命名的节点和属性组成,节点可以包含子节点,它们之间的关系构成一棵树。属性就是 name 和 value 的键值对。
一个典型的设备树如下图:
ARM 的 CPU 拓扑是定义在 cpu-map 节点内,cpu-map 是 cpu 节点的子节点。在 cpu-map 节点里可以包含三种子节点:cluster 节点,core 节点,thread 节点。整个 dts 的例子如下:
cpus {#size-cells = <0>;#address-cells = <2>;cpu-map {cluster0 {cluster0 {core0 {thread0 {cpu = <&CPU0>;};thread1 {cpu = <&CPU1>;};};core1 {thread0 {cpu = <&CPU2>;};thread1 {cpu = <&CPU3>;};};};cluster1 {core0 {thread0 {cpu = <&CPU4>;};thread1 {cpu = <&CPU5>;};};core1 {thread0 {cpu = <&CPU6>;};thread1 {cpu = <&CPU7>;};};};};};//...
};
参考:https://www.kernel.org/doc/Documentation/devicetree/bindings/arm/topology.txt
图来源:https://www.devicetree.org/specifications/
StratoVirt 具体实现
CPUID
首先我们需要计算每个拓扑结构唯一的 topology ID,然后获取或者自己建立相对应的 CPUID entry,当 entry 的 function 的值等于 0xB 和 0X1F 的时候,我们需要根据 CPUID 的规范去设置相对应的 EAX, EBX, ECX 的值。EAX 设置为拓扑 ID,EBX 用来表示那个层级的有几个逻辑处理器,ECX 表示层级号。0xB 需要配置 index 等于 0,1 对应的值,0x1F 需要配置 index 等于 0,1,2 对应的值。下面是相对应的代码:
// cpu/src/x86_64/mod.rs
const ECX_INVALID: u32 = 0u32 << 8;
const ECX_THREAD: u32 = 1u32 << 8;
const ECX_CORE: u32 = 2u32 << 8;
const ECX_DIE: u32 = 5u32 << 8;impl X86CPUState {fn setup_cpuid(&self, vcpu_fd: &Arc<VcpuFd>) -> Result<()> {// 计算 topology IDlet core_offset = 32u32 - (self.nr_threads - 1).leading_zeros();let die_offset = (32u32 - (self.nr_cores - 1).leading_zeros()) + core_offset;let pkg_offset = (32u32 - (self.nr_dies - 1).leading_zeros()) + die_offset;// 获取 KVM 的 fd 和 获取它支持的 CPUID entriesfor entry in entries.iter_mut() {match entry.function {// ...0xb => {// Extended Topology Enumeration Leafentry.edx = self.apic_id as u32;entry.ecx = entry.index & 0xff;match entry.index {0 => {entry.eax = core_offset;entry.ebx = self.nr_threads;entry.ecx |= ECX_THREAD;}1 => {entry.eax = pkg_offset;entry.ebx = self.nr_threads * self.nr_cores;entry.ecx |= ECX_CORE;}_ => {entry.eax = 0;entry.ebx = 0;entry.ecx |= ECX_INVALID;}}}// 0x1f 扩展,支持 die 层级0x1f => {if self.nr_dies < 2 {entry.eax = 0;entry.ebx = 0;entry.ecx = 0;entry.edx = 0;continue;}entry.edx = self.apic_id as u32;entry.ecx = entry.index & 0xff;match entry.index {0 => {entry.eax = core_offset;entry.ebx = self.nr_threads;entry.ecx |= ECX_THREAD;}1 => {entry.eax = die_offset;entry.ebx = self.nr_cores * self.nr_threads;entry.ecx |= ECX_CORE;}2 => {entry.eax = pkg_offset;entry.ebx = self.nr_dies * self.nr_cores * self.nr_threads;entry.ecx |= ECX_DIE;}_ => {entry.eax = 0;entry.ebx = 0;entry.ecx |= ECX_INVALID;}}}// ...}}
}
PPTT
根据 ACPI PPTT 表的标准来构建,我们需要计算每个节点的偏移值用于其子节点指向它。我们还需要计算每个节点的 uid,uid 初始化为 0,每增加一个节点 uid 的值加一。还需要根据 PPTT 表的标准计算 Flags 的值。最后需要计算整张表的大小然后修改原来的长度的值。
// machine/src/standard_vm/aarch64/mod.rs
impl AcpiBuilder for StdMachine {fn build_pptt_table(&self,acpi_data: &Arc<Mutex<Vec<u8>>>,loader: &mut TableLoader,) -> super::errors::Result<u64> {// ...// 配置 PPTT 表头// 添加 socket 节点for socket in 0..self.cpu_topo.sockets {// 计算到起始地址的偏移量let socket_offset = pptt.table_len() - pptt_start;let socket_hierarchy_node = ProcessorHierarchyNode::new(0, 0x2, 0, socket as u32);// ...for cluster in 0..self.cpu_topo.clusters {let cluster_offset = pptt.table_len() - pptt_start;let cluster_hierarchy_node =ProcessorHierarchyNode::new(0, 0x0, socket_offset as u32, cluster as u32);// ...for core in 0..self.cpu_topo.cores {let core_offset = pptt.table_len() - pptt_start;// 判断是否需要添加 thread 节点if self.cpu_topo.threads > 1 {let core_hierarchy_node =ProcessorHierarchyNode::new(0, 0x0, cluster_offset as u32, core as u32);// ...for _thread in 0..self.cpu_topo.threads {let thread_hierarchy_node =ProcessorHierarchyNode::new(0, 0xE, core_offset as u32, uid as u32);// ...uid += 1;}} else {let thread_hierarchy_node =ProcessorHierarchyNode::new(0, 0xA, cluster_offset as u32, uid as u32);// ...uid += 1;}}}}// 将 PPTT 表添加到 loader 中}
}
Device Tree
StratoVirt 的 microvm 使用 device tree 启动,所以我们需要配置 device tree 中的 cpus 节点下的 cpu-map 来使 microvm 支持解析 CPU 拓扑。在 StratoVirt 中,我们支持两层 cluster。我们使用了多层循环来创建这个 tree,第一层是创建第一层 cluster,第二层对应创建第二层的 cluster,第三层创建 core,第四层创建 thread。
impl CompileFDTHelper for LightMachine {fn generate_cpu_nodes(&self, fdt: &mut FdtBuilder) -> util::errors::Result<()> {// 创建 cpus 节点// ...// Generate CPU topology// 创建 cpu-map 节点let cpu_map_node_dep = fdt.begin_node("cpu-map")?;// 创建第一层 cluster 节点for socket in 0..self.cpu_topo.sockets {let sock_name = format!("cluster{}", socket);let sock_node_dep = fdt.begin_node(&sock_name)?;// 创建第二层 cluster 节点for cluster in 0..self.cpu_topo.clusters {let clster = format!("cluster{}", cluster);let cluster_node_dep = fdt.begin_node(&clster)?;// 创建 core 节点for core in 0..self.cpu_topo.cores {let core_name = format!("core{}", core);let core_node_dep = fdt.begin_node(&core_name)?;// 创建 thread 节点for thread in 0..self.cpu_topo.threads {let thread_name = format!("thread{}", thread);let thread_node_dep = fdt.begin_node(&thread_name)?;// 计算 cpu 的 id// let vcpuid = ...// 然后添加到节点中}fdt.end_node(core_node_dep)?;}fdt.end_node(cluster_node_dep)?;}fdt.end_node(sock_node_dep)?;}fdt.end_node(cpu_map_node_dep)?;Ok(())}
}
这个代码构建出来设备树的结构和前面原理中展示的结构基本一致
验证方法
我们可以通过下面的命令启动一个虚拟机,smp
参数用来配置 vCPU 拓扑
sudo ./target/release/stratovirt \-machine virt \-kernel /home/hwy/std-vmlinux.bin.1 \-append console=ttyAMA0 root=/dev/vda rw reboot=k panic=1 \-drive file=/usr/share/edk2/aarch64/QEMU_EFI-pflash.raw,if=pflash,unit=0,readonly=true \-drive file=/home/hwy/openEuler-22.03-LTS-stratovirt-aarch64.img,id=rootfs,readonly=false \-device virtio-blk-pci,drive=rootfs,bus=pcie.0,addr=0x1c.0x0,id=rootfs \-qmp unix:/var/tmp/hwy.socket,server,nowait \-serial stdio \-m 2048 \-smp 4,sockets=2,clusters=1,cores=2,threads=1
接着,我们可以通过观察 /sys/devices/system/cpu/cpu0/topology
下面的文件来查看配置的 topology。
[root@StratoVirt topology] ll
total 0
-r--r--r-- 1 root root 64K Jul 18 09:04 cluster_cpus
-r--r--r-- 1 root root 64K Jul 18 09:04 cluster_cpus_list
-r--r--r-- 1 root root 64K Jul 18 09:04 cluster_id
-r--r--r-- 1 root root 64K Jul 18 09:04 core_cpus
-r--r--r-- 1 root root 64K Jul 18 09:04 core_cpus_list
-r--r--r-- 1 root root 64K Jul 18 09:01 core_id
-r--r--r-- 1 root root 64K Jul 18 09:01 core_siblings
-r--r--r-- 1 root root 64K Jul 18 09:04 core_siblings_list
-r--r--r-- 1 root root 64K Jul 18 09:04 die_cpus
-r--r--r-- 1 root root 64K Jul 18 09:04 die_cpus_list
-r--r--r-- 1 root root 64K Jul 18 09:04 die_id
-r--r--r-- 1 root root 64K Jul 18 09:04 package_cpus
-r--r--r-- 1 root root 64K Jul 18 09:04 package_cpus_list
-r--r--r-- 1 root root 64K Jul 18 09:01 physical_package_id
-r--r--r-- 1 root root 64K Jul 18 09:01 thread_siblings
-r--r--r-- 1 root root 64K Jul 18 09:04 thread_siblings_list
比如:
cat core_cpus_list
结果是
0
表示和 cpu0 同一个 core 的 cpu 只有 cpu0。
cat package_cpus_list
会显示
0-1
表示和 cpu0 同一个 socket 的 cpu 有从 cpu0 到 cpu1。
下面这些工具也可以辅助进行验证。
比如:lscpu
lscpu
通过执行 lscpu
命令会出现下面结果
Architecture: aarch64CPU op-mode(s): 32-bit, 64-bitByte Order: Little Endian
CPU(s): 64On-line CPU(s) list: 0-63
Vendor ID: ARMModel name: Cortex-A72Model: 2Thread(s) per core: 1Core(s) per cluster: 16Socket(s): -Cluster(s): 4Stepping: r0p2BogoMIPS: 100.00Flags: fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
NUMA:NUMA node(s): 4NUMA node0 CPU(s): 0-15NUMA node1 CPU(s): 16-31NUMA node2 CPU(s): 32-47NUMA node3 CPU(s): 48-63
Vulnerabilities:Itlb multihit: Not affectedL1tf: Not affectedMds: Not affectedMeltdown: Not affectedSpec store bypass: VulnerableSpectre v1: Mitigation; __user pointer sanitizationSpectre v2: VulnerableSrbds: Not affectedTsx async abort: Not affected
相关文章:

StratoVirt 的 vCPU 拓扑(SMP)
CPU 拓扑用来表示 CPU 在硬件层面的组合方式,本文主要讲解 CPU 拓扑中的 SMP(Symmetric Multi-Processor,对称多处理器系统)架构,CPU 拓扑还包括其他信息,比如:cache 等,这些部分会在…...

现在直播大部分都是RTMP RTMP VS RTC
一 RTMP 抓了下抖音直播的包,windows端,走的TCP,加密了,估计还是RTMP。 我以为直播带货,都是RTC了。 快手直播也是TCP,地址用了IPV6。 淘宝直播也是。现在大部分直播都是RTMP。 只有视频会议走的RTC。…...

【Unity实战100例】Unity循环UI界面切换卡片功能
目录 编辑 一:制作UI界面 二:代码逻辑 1.定义基础变量...

Monorepo or 物料市场?结合工作实际情况对公司现有前端体系的思考
前言 去年年中基于若依vue前端框架进行了改造,加上后端的配合,我写了一套脚手架和项目中后台模板。中后台模板中包含了许多基础代码,比如登录/注册、路由、权限等等相关功能。这个中后台模板是基于我们实际开发定制的,所以跟通用…...

GEE学习笔记八十八:在自己的APP中使用绘制矢量(上)
在GEE中尤其是自己的APP中调用绘制的矢量图形方法之前没有合适的方法,但是现在可以通过ui.Map.DrawingTools(...)以及ui.Map.GeometryLayer(...)结合来做。具体的API如下图: 在这一篇中我先通过一个简单的例子来展示一下使用这些API后可以实现什么效果&a…...

“笨办法”学Python 3 ——练习 39. 字典,可爱的字典
练习39 源代码 # create a mapping of state to abbreviation #创建一个州与缩写的映射 states {Oregon:OR,Florida:FL,California: CA, New York: NY,Michigan:MI} #创建一个字典,key为州名,value为州缩写#Create a basic set of states and some cit…...

模糊的照片如何修复清晰?
相信有很多人用手机拍照时,觉得拍出来的照片一定是很漂亮的,结果拍了之后,拿出来一看模糊一片,根本看不清是什么。或者是只显示一半另一半模糊一片。而这些精彩瞬间很多时候是无法重拍的。虽然谁也不想拍出的照片出现模糊…...

如何理解session、cookie、token的区别与联系?
session、cookie、token。 相信学过接口的朋友都特别熟悉了。 但是对我一个刚接触接口测试的小白来说,属实有点分不清楚。 下文就是我通过查阅各种资料总结出来的一点理解,不准确的地方还请各位指正。 (文末送洗浴中心流程指南)…...

【MyBatis】| MyBatis分页插件PageHelper
目录 一:MyBatis使⽤PageHelper 1. limit分⻚ 2. PageHelper插件 一:MyBatis使⽤PageHelper 1. limit分⻚ (1)概念: ①页码:pageNum(用户会发送请求,携带页码pageNum给服务器&am…...

Java枚举类详解
一、定义格式 public enum s { 枚举项1,枚举项2,枚举项3; } // 定义一个枚举类,用来表示春,夏,秋,冬这四个固定值 public enum Season {SPRING,SUMMER,AUTUMN,WINTER; } 二、枚举的特点 1、所有枚举类都是Enum的子类 2、我们可以通…...

C语言数组
一.数组定义 数组由数据类型相同的一系列元素组成 如 int main(){ float candy[365]; char code[12]; int states[50]; … } cnady是包含了365个float元素的数组。code是包含了12个char类型的数组。states包含了50个int类型的数组。 二.数组初始化和取值 我们使用花括号包含值&…...

Scala 入门(第一章Scala 环境搭建、插件的安装)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 第 1 章 Scala 入门1.1 概述1.1.1 为什么学习 Scala1.1.2 Scala 发展历史1.1.3 Scala 和 Java 关系1.1.4 Scala 语言特点1.2 Scala 环境搭建1.3 Scala 插件安装1.4 HelloWorl…...

math@多项式@求和式乘法@代数学基本定理
文章目录多项式求和式乘法应用代数学基本定理相关证明高次方程其他关于多项式的参考多项式求和式乘法 S∏j1(∑k1ajk) j∏j1m(∑k1njajk) jS\prod_{j1}\left(\sum\limits_{k1}a_{jk}\right)_{\!\!\!j} \\\prod_{j1}^{m}\left(\sum\limits_{k1}^{n_j}a_{jk}\r…...

Kafka系列之:基于SCRAM和Ranger机制完成动态新增kafka读写账号、赋予账号对指定Topic的读写权限
Kafka系列之:基于SCRAM和Ranger机制完成动态新增kafka读写账号、赋予账号对指定Topic的读写权限 一、需求背景二、添加写用户三、查看用户是否添加到zookeeper中四、查看用户五、赋予用户topic写权限六、生产者配置文件七、ranger给用户权限八、往Topic写数据九、删除添加的用…...

第五十三章 DFS进阶(一)——剪枝优化
第五十四章 DFS进阶(一)——剪枝优化一、什么是剪枝?二、剪枝优化的策略1、优化搜索顺序2、排除等效冗余3、可行性剪枝4、最优性剪枝5、记忆化搜索三、例题1、AcWing 165. 小猫爬山(DFS 剪枝优化)2、AcWing 167. 木棒…...

Java字节码深度知多少?
文章目录1、字节码结构1.1、基本结构1.2、实际观测2、内存表示3、方法调用指令4、invokedynamicEND结语Java真的是长盛不衰,拥有顽强的生命力。其中,字节码机制功不可没。字节码,就像是 Linux 的 ELF。有了它,JVM直接摇身一变&…...

【C++】智能指针(万字详解)
🌈欢迎来到C专栏~~智能指针 (꒪ꇴ꒪(꒪ꇴ꒪ )🐣,我是Scort目前状态:大三非科班啃C中🌍博客主页:张小姐的猫~江湖背景快上车🚘,握好方向盘跟我有一起打天下嘞!送给自己的一句鸡汤&…...

使用docker配置mysql主从复制
1.新建主服务器容器实例: docker run -p 3307:3306 --name mysql \ -v /docker/mysql/data:/var/lib/mysql \ -v /docker/mysql/conf:/etc/mysql/conf \ -v /docker/mysql/log:/var/log/mysql \ -e MYSQL_ROOT_PASSWORDroot \ -d mysql:5.7 设置容器卷之后…...

v3 异步组件及分包使用
1 app.vue <template> <!-- vue3异步组件必须使用suspense --> <Suspense> <template #default> <!-- 异步组件 --> <SyncVue></SyncVue> </template> <template v-slot:fallback> <!-- 优先显示骨架屏 --> <…...

实用调试技巧【上篇】
🔴本文章是在 Visual Studio 2022(VS2022)编译环境下进行操作讲解 文章目录🥳1. 什么是bug?🥳2.调试有多重要?2.1. 我们是如何写代码的?2.2.调试是什么?2.3.调试的基本步…...

JavaScript 教程
手册简介JavaScript 是世界上最流行的脚本语言。 JavaScript 是属于 web 的语言,它适用于 PC、笔记本电脑、平板电脑和移动电话。 JavaScript 被设计为向 HTML 页面增加交互性。 许多 HTML 开发者都不是程序员,但是 JavaScript 却拥有非常简单的语法。几…...

在SpringBoot里面使用原生的Servlet
在SpringBoot里面使用Servlet 首先在主程序中添加注解主程序添加ServletComponentScan // 加上这个注解之后就可以使用原生的组件了 HttpServlet 继承HttpServlet 重写方法 添加WebServlet 第一种方式使用注解 WebServlet(value "/helsk") public class HelloSe…...

商标被驳回,先别慌!挽回商标有办法
商标注册是一个漫长的等待过程,提交了注册申请之后不代表就能得心应手。商标局在接收到申请后,便会开始各阶段审查,面对不符合条件的商标会予以商标驳回。商标局基于什么原因而驳回注册申请呢?驳回后还有必要进行商标驳回复审吗?今天心周企…...

VMware安装Linux虚拟机后忘记root密码处理方法
OS版本:Red Hat 7.7 问题说明: 之前用VMWare安装了一台Linux虚机,由于长期没使用,导致忘记了root密码。所以需要修改root密码。 Root密码修改 现将修改root密码的操作步骤记录如下。 1.启动虚拟机,出现启动倒计时…...

Centos安装OpenResty
文章目录一. OpenResty是什么二. OpenResty的安装1. 安装开发库2. 安装OpenResty仓库3. 安装OpenResty4. 安装opm工具5. 目录结构6. 配置nginx的环境变量7. 启动和运行8. 配置文件修改三. 小案例1. 案例说明2. OpenResty监听请求3. 编写业务代码4. 获取请求参数一. OpenResty是…...

阿里云部署SpringBoot项目
目录 步骤1:购买服务器(新用户免费试用一个月) 步骤2:查看服务器相关信息 编辑 步骤3:设置安全组 步骤4:远程连接 步骤5:使用FinalShell连接阿里云服务器 步骤6:阿里云服务器上安装JDK 编辑 步骤7…...

EdgeCOM嵌入式边缘计算机的参数配置
EdgeCOM嵌入式边缘计算机的参数配置: 下面以 eth0 为例进行命令说明。 在 Linux 系统下,使用 ifconfig 命令可以显示或配置网络设备,使用 ethtool 查询及 设置网卡参数。 设置 IP 地址,查看当前网卡详情: rootfl-imx6u…...

字节软件测试岗:惨不忍睹的三面,幸好做足了准备,月薪15k,拿到offer
我今年25岁,专业是电子信息工程本科,19年年末的时候去面试,统一投了测试的岗位,软件硬件都有,那时候面试的两家公司都是做培训的,当初没啥钱,他们以面试为谎言再推荐去培训这点让我特别难受。 …...

【编程基础之Python】5、安装Python第三方模块
【编程基础之Python】5、安装Python第三方模块安装Python第三方模块为什么需要安装第三方模块Python包管理器介绍pippip installpython -m pip installcondaconda install在Windows环境中安装Python模块安装numpy安装pandas安装matplotlib在Linux环境中安装Python模块在PyCharm…...

JavaScript 教程导读
JavaScript 是 Web 的编程语言。所有现代的 HTML 页面都使用 JavaScript,可以用于改进设计、验证表单、检测浏览器、创建cookies等。JavaScript 非常容易学。本教程将教你学习从初级到高级JavaScript知识。JavaScript 在线实例本教程包含了大量的 JavaScript 实例&a…...