gem5 RubyPort: mem_request_port作用与连接 simple-MI_example.py
简介
回答这个问题:RubyPort的口下,一共定义了六个口,分别是mem_request_port,mem_response_port,pio_request_port,pio_response_port,in_ports, interrupt_out_ports,他们分别有什么用,应该怎么接
overview是下面这个图。

以一个简单的l1 cache为例子
https://www.gem5.org/documentation/learning_gem5/part3/simple-MI_example/
首先是l1cache对子函数的连接
class L1Cache(L1Cache_Controller):。。。def connectQueues(self, ruby_system):。。。self.mandatoryQueue = MessageBuffer()self.requestFromCache = MessageBuffer(ordered = True)self.requestFromCache.master = ruby_system.network.slaveself.responseFromCache = MessageBuffer(ordered = True)self.responseFromCache.master = ruby_system.network.slaveself.forwardToCache = MessageBuffer(ordered = True)self.forwardToCache.slave = ruby_system.network.masterself.responseToCache = MessageBuffer(ordered = True)self.responseToCache.slave = ruby_system.network.master
然后是system对子函数的连接操作
step 1对一个RubySystem延伸的类,他的controller是python自己定义的。
step 2 这里它简化了一下,只有一个dir controller,也就是只有一个memory ctrl,但是 l1cache还是每个cpu都有一个的。
step3 创建了self.controller之后,并没有互联! 这个rubysystem调用了自己的子类的子函数连接了网络和controllers。
step4 显式的连接cpu 与ruby system的 sequencer。
#step 1
class MyCacheSystem(RubySystem):#step 2 self.controllers = [L1Cache(system, self, cpu) for cpu in cpus] + [ DirController(self, system.mem_ranges, mem_ctrls) ]#step 3self.network.connectControllers(self.controllers)#step 4# Connect the cpu's cache, interrupt, and TLB ports to Rubyfor i,cpu in enumerate(cpus):cpu.icache_port = self.sequencers[i].slavecpu.dcache_port = self.sequencers[i].slaveisa = buildEnv['TARGET_ISA']if isa == 'x86':cpu.interrupts[0].pio = self.sequencers[i].mastercpu.interrupts[0].int_master = self.sequencers[i].slavecpu.interrupts[0].int_slave = self.sequencers[i].masterif isa == 'x86' or isa == 'arm':cpu.itb.walker.port = self.sequencers[i].slavecpu.dtb.walker.port = self.sequencers[i].slave
然后我们看看每一步怎么连接的细节:
step3 network.connectControllers(self.controllers)
先看看前置的一些条件
这里的self.controllers 创建了64个L1缓存控制器,每个控制器对应一个CPU,加上一个目录控制器。因此,controllers 列表总共包含65个控制器。
这里有一个不是很常规的情况:每个router连接了一个controller,也就是有65个router。正常应该是64个router对应64个cpu的,这里为了简便,直接每个controller分配一个router。同时,router间的互连也简化为crossbar,每个router连接了剩下所有的64个 router
# Create one router/switch per controller in the systemself.routers = [Switch(router_id = i) for i in range(len(controllers))]#outer间的互连也简化为crossbar,每个router连接了剩下所有的router,例如64个routerfor ri in self.routers:for rj in self.routers:if ri == rj: continue # Don't connect a router to itself!link_count += 1self.int_links.append(SimpleIntLink(link_id = link_count,src_node = ri,dst_node = rj))
这些前置条件过后,看怎么连接controller和router的:
def connectControllers(self, controllers):"""Connect all of the controllers to routers and connect the routerstogether in a point-to-point network."""# Create one router/switch per controller in the systemself.routers = [Switch(router_id = i) for i in range(len(controllers))]# Make a link from each controller to the router. The link goes# externally to the network.self.ext_links = [SimpleExtLink(link_id=i, ext_node=c,int_node=self.routers[i])for i, c in enumerate(controllers)]# Make an "internal" link (internal to the network) between every pair# of routers.link_count = 0self.int_links = []for ri in self.routers:for rj in self.routers:if ri == rj: continue # Don't connect a router to itself!link_count += 1self.int_links.append(SimpleIntLink(link_id = link_count,src_node = ri,dst_node = rj))
把这些代码画成图如下:
+----------------+| CPU 0 || icache_port || dcache_port |+----------------+|v+----------------+| RubySequencer |+----------------+|v+---------------+| L1 Cache | | L1 Cache.sub | |viaSimpleExtLin| |responseFromCache.master| |forwardToCache.slave| |responseToCache.slave|+---------------+ +---------------+ +---------------+ +---------------+ | | | |v v v v+----------------+ +----------------+ |rubysystem.network.Router 0| |rubysystem.network.slave| |rubysystem.network.slave| |ruby_system.network.master | +----------------+ +----------------+
... (多个类似的组件重复上述连接关系) ...+----------------+| CPU 63 || icache_port || dcache_port |+----------------+|v+----------------+| RubySequencer |+----------------+|v+---------------+| L1 Cache |+---------------+|v+----------------+| Router 63 |+----------------+第65个router比较特殊,在这个简化的实例里没有连接l1而是连接了dircontroller.同时每个router之间都是连接的。+----------------+| Router 64 |+----------------+^ || v+----------------+| DirController|+----------------+
代码和图联合 分析
按照https://www.gem5.org/documentation/learning_gem5/part3/simple-MI_example/ 的顺序,
连接l1 cache与router
rubysystem 创建了一堆controller,随后创建了sequencer但是还没连,然后调用network。connectController连接了controlle和router,
# Create the network and connect the controllers.# NOTE: This is quite different if using Garnet!self.network.connectControllers(self.controllers)self.network.setup_buffers()
也就是
l1cache和network.router通过simpleextlink相连的。
连接cpu 与sequencer
随后,rybysystem 显式的连接了之前创建的sequence和 cpu的interrupt 和itb.walker.port.
# Connect the cpu's cache, interrupt, and TLB ports to Rubyfor i,cpu in enumerate(cpus):cpu.icache_port = self.sequencers[i].slavecpu.dcache_port = self.sequencers[i].slaveisa = buildEnv['TARGET_ISA']if isa == 'x86':cpu.interrupts[0].pio = self.sequencers[i].mastercpu.interrupts[0].int_master = self.sequencers[i].slavecpu.interrupts[0].int_slave = self.sequencers[i].masterif isa == 'x86' or isa == 'arm':cpu.itb.walker.port = self.sequencers[i].slavecpu.dtb.walker.port = self.sequencers[i].slave
图里也就是连接这一部分:

连接l1cache 和rubysystem.networ
这里是隐藏在l1初始化的时候,创建l1cache需要初始化,(对这个python文件)初始化的时候l1cache就传递进来了rubysystem这个对象。
self.connectQueues(ruby_system)
然后l1cache连接了rubyssytem的master和slaveport.现在叫out_port 和in_port 。
def connectQueues(self, ruby_system):"""Connect all of the queues for this controller."""self.mandatoryQueue = MessageBuffer()self.requestFromCache = MessageBuffer(ordered = True)self.requestFromCache.master = ruby_system.network.slaveself.responseFromCache = MessageBuffer(ordered = True)self.responseFromCache.master = ruby_system.network.slaveself.forwardToCache = MessageBuffer(ordered = True)self.forwardToCache.slave = ruby_system.network.masterself.responseToCache = MessageBuffer(ordered = True)self.responseToCache.slave = ruby_system.network.master#小插曲: master和slave的说法已经被弃用了 by src/mem/ruby/network/Network.py#in_port = VectorResponsePort("CPU input port")#slave = DeprecatedParam(in_port, "`slave` is now called `in_port`")#out_port = VectorRequestPort("CPU output port")#master = DeprecatedParam(out_port, "`master` is now called `out_port`")
图里是这一部分,描述的l1的cache的子成员直接和network相连。

关键问题:这些port结构连上了,但是属于哪些类型的rubyport?
rubyport。hh里有六种类型,这些结构上相连的port各自属于哪些类型? 我们一个个搜索从结构上看过来
RubySequencer
代码用的self.sequencers[i].master/slave,其中 self.sequencers = [RubySequencer(version = i,。。。
RubySequencer 从哪里来的呢?
在src/mem/ruby/system/Sequencer.py找到了 RubySequencer的定义:
class RubySequencer(RubyPort):type = "RubySequencer"cxx_class = "gem5::ruby::Sequencer"cxx_header = "mem/ruby/system/Sequencer.hh"
RubySequencer 不是Sequencer: python与c++的关系。
细看会发现,我们用的是 RubySequencer 不是Sequencer ,RubySequencer是python的class,他的type是cpp里的"gem5::ruby::Sequencer"。还告诉我们用的头文件是 “mem/ruby/system/Sequencer.hh”。
cpp Sequencer.hh 没有
先看src/mem/ruby/system/Sequencer.hh 中,
class Sequencer : public RubyPort
所以Sequencer 其实是继承自RubyPort的。而RubyPort继承自clockedobject.
这俩都没有.slave 子成员。 那我们的python代码调用的slave来自于哪里?
RubyPort的python定义
对rubyport最关键的代码出现了:src/mem/ruby/system/Sequencer.py
没错,竟然没有一个单独的python文件 RubyPort.py 而是在 Sequencer.py里。
step1 这个代码把c++和python联系起来了。
step2 这个代码创建了新的python里的名字
- in_port同时也是弃用的slave
- interrupt_out_port同时也是弃用的master
- pio_request_port同时也是弃用的 pio_master_port
- mem_request_port 同时也是弃用的mem_master_port
- pio_response_port 同时也是弃用的pio_slave_port
class RubyPort(ClockedObject):type = "RubyPort"abstract = Truecxx_header = "mem/ruby/system/RubyPort.hh"cxx_class = "gem5::ruby::RubyPort"version = Param.Int(0, "")in_ports = VectorResponsePort("CPU side of this RubyPort/Sequencer. ""The CPU request ports should be connected to this. If a CPU ""has multiple ports (e.g., I/D ports) all of the ports for a ""single CPU can connect to one RubyPort.")slave = DeprecatedParam(in_ports, "`slave` is now called `in_ports`")interrupt_out_port = VectorRequestPort("Port to connect to x86 interrupt ""controller to send the CPU requests from outside.")master = DeprecatedParam(interrupt_out_port, "`master` is now called `interrupt_out_port`")pio_request_port = RequestPort("Ruby pio request port")pio_master_port = DeprecatedParam(pio_request_port, "`pio_master_port` is now called `pio_request_port`")mem_request_port = RequestPort("Ruby mem request port")mem_master_port = DeprecatedParam(mem_request_port, "`mem_master_port` is now called `mem_request_port`")pio_response_port = ResponsePort("Ruby pio response port")pio_slave_port = DeprecatedParam(pio_response_port, "`pio_slave_port` is now called `pio_response_port`")
这些python的port和 c++port的定义
是python提供字符串描述,然后调用python通过名字找port的函数,然后cpp响应这个函数,返回对应的cpp对象。由此,python定义的port和c++的port联系起来。
下面是细节,分别是根据名字字符串 找port 的函数, c++对port名字的回应, 和这些port的对应关系。
根据名字字符串 找port 的函数
在src/python/m5/params.py中
class RequestPort(Port):# RequestPort("description")def __init__(self, desc):super().__init__("GEM5 REQUESTOR", desc, is_source=True)
c++对port名字的回应
Port &
RubyPort::getPort(const std::string &if_name, PortID idx)
{if (if_name == "mem_request_port") {return memRequestPort;} else if (if_name == "pio_request_port") {return pioRequestPort;} else if (if_name == "mem_response_port") {return memResponsePort;} else if (if_name == "pio_response_port") {return pioResponsePort;} else if (if_name == "interrupt_out_port") {// used by the x86 CPUs to connect the interrupt PIO and interrupt// response portif (idx >= static_cast<PortID>(request_ports.size())) {panic("%s: unknown %s index (%d)\n", __func__, if_name, idx);}return *request_ports[idx];} else if (if_name == "in_ports") {// used by the CPUs to connect the caches to the interconnect, and// for the x86 case also the interrupt request portif (idx >= static_cast<PortID>(response_ports.size())) {panic("%s: unknown %s index (%d)\n", __func__, if_name, idx);}return *response_ports[idx];}// pass it along to our super classreturn ClockedObject::getPort(if_name, idx);
}
python port和 cpp port的对应关系:根据name返回
mem_request_port 和 memRequestPort
python 文件中,mem_request_port 是来自于 RequestPort(“Ruby mem request port”)
mem_request_port = RequestPort(“Ruby mem request port”)
查找返回的是 if (if_name == “mem_request_port”) { return memRequestPort;
pio_request_port和 pioRequestPort
python 文件中, pio_request_port = RequestPort(“Ruby pio request port”)
查找的cpp返回的是 else if (if_name == “pio_request_port”) { return pioRequestPort;
pio_response_port 和 pioResponsePort
python 文件中 pio_response_port = ResponsePort(“Ruby pio response port”)
查找的cpp返回的是 else if (if_name == “pio_response_port”) { return pioResponsePort;
interrupt_out_port 和*request_ports[idx]
python 文件中 pio_response_port = ResponsePort(“Ruby pio response port”)
查找的cpp返回的是 else if (if_name == “interrupt_out_port”) { // used by the x86 CPUs to connect the interrupt PIO and interrupt // response port if (idx >= static_cast(request_ports.size())) { panic(“%s: unknown %s index (%d)\n”, func, if_name, idx); }
in_ports 和 *response_ports[idx]
python 文件中 in_ports = VectorResponsePort( "CPU side of this RubyPort/Sequencer. " “The CPU request ports should be connected to this. If a CPU " “has multiple ports (e.g., I/D ports) all of the ports for a " “single CPU can connect to one RubyPort.” )
查找的cpp返回的是 else if (if_name == “in_ports”) { // used by the CPUs to connect the caches to the interconnect, and // for the x86 case also the interrupt request port if (idx >= static_cast(response_ports.size())) { panic(”%s: unknown %s index (%d)\n”, func, if_name, idx); } return *response_ports[idx];
这些python port(同时也代表c++port) 怎么连接的
核心是这些连接是由python文件定义,我们还是以 simple-MI_example.py为例子:
cpu和sequencer
# Connect the cpu's cache, interrupt, and TLB ports to Rubyfor i,cpu in enumerate(cpus):cpu.icache_port = self.sequencers[i].slavecpu.dcache_port = self.sequencers[i].slaveisa = buildEnv['TARGET_ISA']if isa == 'x86':cpu.interrupts[0].pio = self.sequencers[i].mastercpu.interrupts[0].int_master = self.sequencers[i].slavecpu.interrupts[0].int_slave = self.sequencers[i].masterif isa == 'x86' or isa == 'arm':cpu.itb.walker.port = self.sequencers[i].slavecpu.dtb.walker.port = self.sequencers[i].slave
cpu 与sequencer 的连接图
画成图就是

network 和 l1 dir
l1 连接l1的port和network
def connectQueues(self, ruby_system):"""Connect all of the queues for this controller."""self.mandatoryQueue = MessageBuffer()self.requestFromCache = MessageBuffer(ordered = True)self.requestFromCache.master = ruby_system.network.slaveself.responseFromCache = MessageBuffer(ordered = True)self.responseFromCache.master = ruby_system.network.slaveself.forwardToCache = MessageBuffer(ordered = True)self.forwardToCache.slave = ruby_system.network.masterself.responseToCache = MessageBuffer(ordered = True)self.responseToCache.slave = ruby_system.network.master
DirController 里,连接dir 的port和network
def connectQueues(self, ruby_system):self.requestToDir = MessageBuffer(ordered = True)self.requestToDir.slave = ruby_system.network.masterself.dmaRequestToDir = MessageBuffer(ordered = True)self.dmaRequestToDir.slave = ruby_system.network.masterself.responseFromDir = MessageBuffer()self.responseFromDir.master = ruby_system.network.slaveself.dmaResponseFromDir = MessageBuffer(ordered = True)self.dmaResponseFromDir.master = ruby_system.network.slaveself.forwardFromDir = MessageBuffer()self.forwardFromDir.master = ruby_system.network.slaveself.responseFromMemory = MessageBuffer()
## network 里,连接router和 l1以及dir
```pythonself.ext_links = [SimpleExtLink(link_id=i, ext_node=c,int_node=self.routers[i])for i, c in enumerate(controllers)]
network 里连接network.router 和conrollers
# Make a link from each controller to the router. The link goes# externally to the network.self.ext_links = [SimpleExtLink(link_id=i, ext_node=c,int_node=self.routers[i])for i, c in enumerate(controllers)]
network with routers 与l1, dir 的连接图
画成图就是

#小结
再把sequencer中的cacher和l1相连起来就全部串起来了
最后的总结图:

相关文章:
gem5 RubyPort: mem_request_port作用与连接 simple-MI_example.py
简介 回答这个问题:RubyPort的口下,一共定义了六个口,分别是mem_request_port,mem_response_port,pio_request_port,pio_response_port,in_ports, interrupt_out_ports,他们分别有什…...
无人机支持的空中无蜂窝大规模MIMO系统中上行链路分布式检测
无人机支持的空中无蜂窝大规模MIMO系统中上行链路分布式检测 无人机支持的空中无蜂窝大规模MIMO系统中上行链路分布式检测介绍题目一. 背景(解决的问题)二. 系统模型信道模型信道系数进行标准化 信道估计 和 数据传输信道估计上行数据传输 三. 具体的流程…...
文献速递:生成对抗网络医学影像中的应用—— CG-3DSRGAN:用于从低剂量PET图像恢复图像质量的分类指导的3D生成对抗网络
文献速递:生成对抗网络医学影像中的应用—— CG-3DSRGAN:用于从低剂量PET图像恢复图像质量的分类指导的3D生成对抗网络 本周给大家分享文献的主题是生成对抗网络(Generative adversarial networks, GANs)在医学影像中的应用。文献…...
前端验收测试驱动开发
我们听说过很多关于测试驱动开发(TDD)的内容。那么什么是ATDD? ATDD代表验收测试驱动开发,这是一种定义验收标准并创建自动化测试来验证是否满足这些标准的软件开发方法。ATDD是一种协作方法,涉及客户、开发人员和测试…...
图像卷积操作
目录 一、互相关运算 二、卷积层 三、图像中目标的边缘检测 四、学习卷积核 五、特征映射和感受野 一、互相关运算 严格来说,卷积层是个错误的叫法,因为它所表达的运算其实是互相关运算(cross-correlation),而不是…...
目标检测入门体验,技术选型,加载数据集、构建机器学习模型、训练并评估
Hi, I’m Shendi 1、目标检测入门体验,技术选型,加载数据集、构建机器学习模型、训练并评估 在最近有了个物体识别的需求,于是开始学习 在一番比较与询问后,最终选择 TensorFlow。 对于编程语言,我比较偏向Java或nod…...
【UE5插件推荐】运行时,通过HTTP / HTTPS下载文件(Runtime Files Downloader)
UE5 github Home gtreshchev/RuntimeFilesDownloader Wiki (github.com)...
信息论安全与概率论
目录 一. Markov不等式 二. 选择引理 三. Chebyshev不等式 四. Chernov上限 4.1 变量大于 4.2 变量小于 信息论安全中会用到很多概率论相关的上界,本文章将梳理几个论文中常用的定理,重点关注如何理解这些定理以及怎么用。 一. Markov不等式 假定…...
各种不同语言分别整理的拿来开箱即用的8个开源免费单点登录(SSO)系统
各种不同语言分别整理的拿来开箱即用的8个开源免费单点登录(SSO)系统。 单点登录(SSO)是一个登录服务层,通过一次登录访问多个应用。使用SSO服务可以提高多系统使用的用户体验和安全性,用户不必记忆多个密…...
Netty Review - 优化Netty通信:如何应对粘包和拆包挑战
文章目录 概述Pre概述场景复现解决办法概览方式一: 特殊分隔符分包 (演示Netty提供的众多方案中的一种)流程分析 方式二: 发送长度(推荐) DelimiterBasedFrameDecoder 源码分析 概述 Pre Netty Review - 借助SimpleTalkRoom初体验…...
vue介绍以及基本指令
目录 一、vue是什么 二、使用vue的准备工作 三、创建vue项目 四、vue插值表达式 五、vue基本指令 六、key的作用 七、v-model 九、指令修饰符 一、vue是什么 Vue是一种用于构建用户界面的JavaScript框架。它可以帮助开发人员构建单页应用程序和复杂的前端应用程序。Vue…...
重塑数字生产力体系,生成式AI将开启云计算未来新十年?
科技云报道原创。 今天我们正身处一个历史的洪流,一个巨变的十字路口。生成式AI让人工智能技术完全破圈,带来了机器学习被大规模采用的历史转折点。 它掀起的新一轮科技革命,远超出我们今天的想象,这意味着一个巨大的历史机遇正…...
JFreeChart 生成图表,并为图表标注特殊点、添加文本标识框
一、项目场景: Java使用JFreeChart库生成图片,主要场景为将具体的数据 可视化 生成曲线图等的图表。 本篇文章主要针对为数据集生成的图表添加特殊点及其标识框。具体包括两种场景:x轴为 时间戳 类型和普通 数值 类型。(y轴都为…...
vue整合axios 未完
一、简介 1、介绍 axios前端异步请求库类似jouery ajax技术,axios用来在前端页面发起一个异步请求,请求之后页面不动,响应回来刷新页面局部;Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中 2、特…...
java代码编写twitter授权登录
在上一篇内容已经介绍了怎么申请twitter开放的API接口。 下面介绍怎么通过twitter提供的API,进行授权登录功能。 开发者页面设置 首先在开发者页面开启“用户认证设置”,点击edit进行信息编辑。 我的授权登录是个网页,并且只需要进行简单的…...
SK Ecoplant借助亚马逊云科技,海外服务器为环保事业注入新活力
在当今全球面临着资源紧缺和环境挑战的大背景下,数字技术所依赖的海外服务器正成为加速循环经济转型的关键利器。然而,很多企业在整合数字技术到运营中仍然面临着一系列挑战,依然存在低效流程导致的不必要浪费。针对这一问题,SK E…...
RPC(5):AJAX跨域请求处理
接上一篇RPC(4):HttpClient实现RPC之POST请求进行修改。 1 修改客户端项目 1.1 修改maven文件 修改后配置文件如下: <dependencyManagement><dependencies><dependency><groupId>org.springframework.b…...
用大白话举例子讲明白区块链
什么是区块链?网上这么说: 区块链是一种分布式数据库技术,它以块的形式记录和存储交易数据,并使用密码学算法保证数据的安全性和不可篡改性。每个块都包含了前一个块的哈希值和自身的交易数据,形成了一个不断增长的链条…...
Java URL
URL:统一资源定位符,说白了,就是一个网络 通过URLConnection类可以连接到URL,然后通过URLConnection可以获取读数据的通道。非文本数据用字节流来读取。 读完之后写入本地即可。 public class test {public static void main(S…...
ETL-从1学到100(1/100):ETL涉及到的名词解释
本文章主要介绍ETL和大数据中涉及到名词,同时解释这些名词的含义。由于不是一次性收集这些名词,所以这篇文章将会持续更新,更新日志会存放在本段话下面: 12-19更新:OLTP、OLAP、BI、ETL。 12-20更新:ELT、…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...
有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)
一、OpenBCI_GUI 项目概述 (一)项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台,其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言,首次接触 OpenBCI 设备时,往…...
