I.MX RT1170双核学习(3):多核管理之MCMGR源码分析详解

本文通过SDK中最简单的hello_world例程来说明一下双核程序如何运行。在CM7和CM4的工程中都有一个MCMGR(Multicore Manager)文件夹,它是用来管理多核之间的操作的,当然也包括我们前面提到的那些寄存器的设置。

在这里插入图片描述

文章目录

  • 1 MCMGR_EarlyInit
    • 1.1 MCMGR_TriggerEvent
  • 2 MCMGR_Init函数
    • 2.1 MCMGR_RegisterEvent函数
    • 2.2 事件回调函数
    • 2.3 mcmgr_late_init_internal
  • 3 MCMGR_StartCore函数
  • 4 MCMGR_GetStartupData函数
  • 5 MU中断接收函数
  • 6 双核状态机交互过程详解
  • 7 总结

我们现在就以CM7核激活CM4核为例,先分析一下CM7核的代码。实际上在CM7的例程中就调用了 MCMGR_EarlyInitMCMGR_InitMCMGR_StartCore三个函数就能启动M4核了。下面就来分析一下这三个函数:

1 MCMGR_EarlyInit

无论是CM7还是CM4,都需要调用这个函数,它是用来初始化底层的多核管理库(MCMGR)的,这个函数应该尽可能在reset_handler附近调用,表示某个核已经启动并准备好执行任务。在这里,这个函数在ResetISR->SystemInit中就调用了。这个函数最终调用的是mcmgr_early_init_internal

mcmgr_status_t mcmgr_early_init_internal(mcmgr_core_t coreNum) 
{MU_Init(MUA);  //实际上就是使能MU的时钟(M7核初始化MUA,M4核这里的参数为MUB)return MCMGR_TriggerEvent(kMCMGR_RemoteCoreUpEvent, 0);
}

1.1 MCMGR_TriggerEvent

MCMGR_TriggerEvent函数实际上调用的是MCMGR_TriggerEventCommon

mcmgr_status_t MCMGR_TriggerEvent(mcmgr_event_type_t type, uint16_t eventData)
{return MCMGR_TriggerEventCommon(type, eventData, false);
}

所以来看一下MCMGR_TriggerEventCommon函数:

/*! @brief Type definition of event types. */
typedef enum _mcmgr_event_type_t
{kMCMGR_RemoteCoreUpEvent = 1,kMCMGR_RemoteCoreDownEvent,kMCMGR_RemoteExceptionEvent,kMCMGR_StartupDataEvent,kMCMGR_FeedStartupDataEvent,kMCMGR_RemoteRPMsgEvent,kMCMGR_RemoteApplicationEvent,kMCMGR_FreeRtosMessageBuffersEvent,kMCMGR_EventTableLength
} mcmgr_event_type_t;static mcmgr_status_t MCMGR_TriggerEventCommon(mcmgr_event_type_t type, uint16_t eventData, bool forcedWrite)
{uint32_t remoteData;remoteData = (((uint32_t)type) << 16) | eventData;return mcmgr_trigger_event_internal(remoteData, forcedWrite);
}

接着看一下mcmgr_trigger_event_internal函数:

/* MCMGR MU channel index - used for passing startupData */
#define MCMGR_MU_CHANNEL 3mcmgr_status_t mcmgr_trigger_event_internal(uint32_t remoteData, bool forcedWrite)
{/* When forcedWrite is false, execute the blocking call, i.e. wait until previouslysent data is processed. Otherwise, run the non-blocking version of the MU send function. */if (false == forcedWrite){MU_SendMsg(MUA, MCMGR_MU_CHANNEL, remoteData);// M7执行这条,M4的第一个参数MUA换为MUB}else{MU_SendMsgNonBlocking(MUA, MCMGR_MU_CHANNEL, remoteData);// M7执行这条,M4的第一个参数MUA换为MUB}return kStatus_MCMGR_Success;
}

这里的forcedWrite参数为false的时候,执行阻塞写函数,等待上一次发送的数据处理完了才发送;forcedWrite参数为true时,直接往寄存器中写数据,这个函数最好搭配中断使用。

从上面我们知道,mcmgr_early_init_internal实际上就是通过自己核对应的MU的通道3发送一个组合的32位数(高16位为type,低16位为eventData,这里typekMCMGR_RemoteCoreUpEventeventData为0)给对方核对应的MU的通道3。

  • 如果不知道MU的,建议看一下我之前介绍MU的文章:双核通信之MU消息单元详解

2 MCMGR_Init函数

接着就是调用MCMGR_Init函数:

mcmgr_status_t MCMGR_Init(void)
{// 通过OCOTP熔丝相应位可以判断当前是CM4(返回0)还是CM7核(返回1)mcmgr_core_t coreNum = MCMGR_GetCurrentCore();// 两个回调函数MCMGR_RegisterEvent(kMCMGR_StartupDataEvent, MCMGR_StartupDataEventHandler, (void *)&s_mcmgrCoresContext[coreNum]);MCMGR_RegisterEvent(kMCMGR_FeedStartupDataEvent, MCMGR_FeedStartupDataEventHandler, (void *)&s_mcmgrCoresContext[(coreNum == 0) ? 1 : 0]);return mcmgr_late_init_internal(coreNum);
}

MCMGR_RegisterEvent用来注册某个事件(参数一)的回调函数(参数二),其中参数三s_mcmgrCoresContext会传给回调函数作为其参数供其使用,它的定义如下:

typedef struct _mcmgr_core_context
{/*! @brief Current state of the core. */mcmgr_core_state_t state;/*! @brief Startup data, if state >= kMCMGR_RunningCoreState */uint32_t startupData;
} mcmgr_core_context_t;/*! @brief Type definition of possible core states. */
typedef enum _mcmgr_core_state
{kMCMGR_ResetCoreState = 0,kMCMGR_StartupGettingLowCoreState,kMCMGR_StartupGettingHighCoreState,kMCMGR_RunningCoreState,
} mcmgr_core_state_t;volatile mcmgr_core_context_t s_mcmgrCoresContext[2] = {{.state = kMCMGR_ResetCoreState, .startupData = 0}, {.state = kMCMGR_ResetCoreState, .startupData = 0}};

看样子似乎是一个状态机,其中:

  • s_mcmgrCoresContext[0]用于kMCMGR_StartupDataEvent事件的MCMGR_StartupDataEventHandler回调

  • s_mcmgrCoresContext[1]用于kMCMGR_FeedStartupDataEvent事件的MCMGR_FeedStartupDataEventHandler回调

具体完成了什么我们后面用到了再分析。

2.1 MCMGR_RegisterEvent函数

顾名思义就是用来注册回调函数的,实现也非常简单,就是定义了一个结构体数组,然后填充即可:

/*! @brief Type definition of structure with event handler and data. */
typedef struct _mcmgr_event
{/*! @brief Pointer to callback function. */mcmgr_event_callback_t callback;/*! @brief Context data for callback. */void *callbackData;
} mcmgr_event_t;mcmgr_event_t MCMGR_eventTable[kMCMGR_EventTableLength] = {0};mcmgr_status_t MCMGR_RegisterEvent(mcmgr_event_type_t type, mcmgr_event_callback_t callback, void *callbackData)
{if (type >= kMCMGR_EventTableLength){return kStatus_MCMGR_Error;}MCMGR_eventTable[type].callback = ((void *)0);MCMGR_eventTable[type].callbackData = callbackData;MCMGR_eventTable[type].callback = callback;return kStatus_MCMGR_Success;
}

mcmgr_event_type_t有8种事件,每个事件占据MCMGR_eventTable数组的一个索引。

接下来看一下两个回调函数完成了什么:

2.2 事件回调函数

下面来看一下MCMGR_StartupDataEventHandlerMCMGR_FeedStartupDataEventHandler

static void MCMGR_StartupDataEventHandler(uint16_t startupDataChunk, void *context)
{mcmgr_core_context_t *coreContext = (mcmgr_core_context_t *)context;switch (coreContext->state){case kMCMGR_StartupGettingLowCoreState:coreContext->startupData = startupDataChunk; /* Receive the low part */coreContext->state       = kMCMGR_StartupGettingHighCoreState;(void)MCMGR_TriggerEvent(kMCMGR_FeedStartupDataEvent, (uint16_t)kMCMGR_StartupGettingHighCoreState);break;case kMCMGR_StartupGettingHighCoreState:coreContext->startupData |= ((uint32_t)startupDataChunk) << 16;coreContext->state = kMCMGR_RunningCoreState;(void)MCMGR_TriggerEvent(kMCMGR_FeedStartupDataEvent, (uint16_t)kMCMGR_RunningCoreState);break;default:break;}
}static void MCMGR_FeedStartupDataEventHandler(uint16_t startupDataChunk, void *context)
{mcmgr_core_context_t *coreContext = (mcmgr_core_context_t *)context;switch ((mcmgr_core_state_t)startupDataChunk){case kMCMGR_StartupGettingLowCoreState:(void)MCMGR_TriggerEvent(kMCMGR_StartupDataEvent, (uint16_t)(coreContext->startupData & 0xFFFFU));coreContext->state = (mcmgr_core_state_t)startupDataChunk;break;case kMCMGR_StartupGettingHighCoreState:(void)MCMGR_TriggerEvent(kMCMGR_StartupDataEvent, (uint16_t)((coreContext->startupData) >> 16));coreContext->state = (mcmgr_core_state_t)startupDataChunk;break;case kMCMGR_RunningCoreState:coreContext->state = (mcmgr_core_state_t)startupDataChunk;break;default:break;}
}

这里的context就是前面注册回调函数时的第三个参数s_mcmgrCoresContext[0/1],前面我们看到默认的statekMCMGR_ResetCoreState,所以不会进入任何分支中,具体初始状态在何时改变的,我们后续分析。

我们看到这里两个Handler最后都是调用MCMGR_TriggerEvent函数,即通过MU发送一个32位数给对方核。

2.3 mcmgr_late_init_internal

MCMGR_Init最后调用mcmgr_late_init_internal打开MU的通道3的接收中断:
(下面代码为CM7核的,CM4核打开的是MUB)

mcmgr_status_t mcmgr_late_init_internal(mcmgr_core_t coreNum)
{MU_EnableInterrupts(MUA, (uint32_t)kMU_Rx3FullInterruptEnable);NVIC_SetPriority(MUA_IRQn, 2);NVIC_EnableIRQ(MUA_IRQn);return kStatus_MCMGR_Success;
}

在前面的MCMGR_TriggerEvent中,最后也是使用通道3发送的消息,所以在SDK中使用MU的通道3来完成双核执行的同步。

3 MCMGR_StartCore函数

对于CM7来说,注册完回调函数之后,还需要调用MCMGR_StartCore来启动CM4核。

MCMGR_StartCore(kMCMGR_Core1, (void *)(char *)CORE1_BOOT_ADDRESS, 2, kMCMGR_Start_Synchronous);

具体实现如下:

#define CORE1_BOOT_ADDRESS (void *)0x20200000
MCMGR_StartCore(kMCMGR_Core1, (void *)(char *)CORE1_BOOT_ADDRESS, 2, kMCMGR_Start_Synchronous); //kMCMGR_Core1=1mcmgr_status_t MCMGR_StartCore(mcmgr_core_t coreNum, void *bootAddress, uint32_t startupData, mcmgr_start_mode_t mode)
{mcmgr_status_t ret;/* 填充startupData */s_mcmgrCoresContext[coreNum].startupData = startupData;/* 设置相关寄存器 */ret = mcmgr_start_core_internal(coreNum, bootAddress);if (mode == kMCMGR_Start_Synchronous){/* 等待M4核读取和确认我们刚刚填充的startupData */while (s_mcmgrCoresContext[coreNum].state != kMCMGR_RunningCoreState){}}return kStatus_MCMGR_Success;
}

这里假设我们将CM4的程序通过CM7的映射地址0x20200000拷贝到CM4的TCM中了,如果CM4的程序在NOR Flash中,填写对应的地址即可。

mcmgr_start_core_internal就是我们上一篇文章双核相互激活和启动流程提到的CM7激活CM4相关寄存器的修改:

mcmgr_status_t mcmgr_start_core_internal(mcmgr_core_t coreNum, void *bootAddress)
{IOMUXC_LPSR_GPR->GPR0 = IOMUXC_LPSR_GPR_GPR0_CM4_INIT_VTOR_LOW(((uint32_t)(char *)bootAddress) >> 3u);IOMUXC_LPSR_GPR->GPR1 = IOMUXC_LPSR_GPR_GPR1_CM4_INIT_VTOR_HIGH(((uint32_t)(char *)bootAddress) >> 16u);SRC->CTRL_M4CORE = SRC_CTRL_M4CORE_SW_RESET_MASK;SRC->SCR |= SRC_SCR_BT_RELEASE_M4_MASK;return kStatus_MCMGR_Success;
}

4 MCMGR_GetStartupData函数

在CM4核启动后会调用MCMGR_GetStartupData函数,直到这个函数返回kStatus_MCMGR_Success

do{status = MCMGR_GetStartupData(&startupData);} while (status != kStatus_MCMGR_Success);

现在来看一下这个函数:

mcmgr_status_t MCMGR_GetStartupData(uint32_t *startupData)
{if (s_mcmgrCoresContext[1].state == kMCMGR_ResetCoreState){s_mcmgrCoresContext[1].state = kMCMGR_StartupGettingLowCoreState;if (kStatus_MCMGR_Success !=MCMGR_TriggerEvent(kMCMGR_FeedStartupDataEvent, (uint16_t)kMCMGR_StartupGettingLowCoreState)){return kStatus_MCMGR_Error;}}return mcmgr_get_startup_data_internal(1, startupData);
}mcmgr_status_t mcmgr_get_startup_data_internal(mcmgr_core_t coreNum, uint32_t *startupData)
{if (s_mcmgrCoresContext[1].state >= kMCMGR_RunningCoreState){*startupData = s_mcmgrCoresContext[1].startupData;return kStatus_MCMGR_Success;}return kStatus_MCMGR_NotReady;
}

实际上也是和刚刚的状态机相关。

5 MU中断接收函数

现在我们对CM7和CM4的交互过程还是一头雾水,前面注册的回调函数什么时刻被调用,CM7启动CM4后等待s_mcmgrCoresContext[coreNum].state变为kMCMGR_RunningCoreState,还有CM4启动后,CM4也要等待状态变化再往下执行程序,那么这些状态是在哪里被修改的呢?下面就来分析一下这个过程。

前面我们打开了中断,所以我们首先看一下中断处理回调函数,在通道三收到数据后将调用此回调函数:(下面为CM7核MUA的回调,MUB的类似)

void MU_Rx3FullFlagISR(void)
{uint32_t data;uint16_t eventType;uint16_t eventData;#if defined(FSL_FEATURE_MU_SIDE_A)data = MU_ReceiveMsgNonBlocking(MUA, 3);
#elif defined(FSL_FEATURE_MU_SIDE_B)data = MU_ReceiveMsgNonBlocking(MUB, 3);
#endif/* To be MISRA compliant, return value needs to be checked even it could not never be 0 */if (0U != data){eventType = (uint16_t)(data >> 16u);eventData = (uint16_t)(data & 0x0000FFFFu);if (((mcmgr_event_type_t)eventType >= kMCMGR_RemoteCoreUpEvent) &&((mcmgr_event_type_t)eventType < kMCMGR_EventTableLength)){if (MCMGR_eventTable[(mcmgr_event_type_t)eventType].callback != ((void *)0)){MCMGR_eventTable[(mcmgr_event_type_t)eventType].callback(eventData, MCMGR_eventTable[(mcmgr_event_type_t)eventType].callbackData);}}}
}
  • 在理论上我们的程序中没有发送数据内容为0的代码,但是为了符合MISRA规范,这里还是检查了0U != data

前面在MCMGR_TriggerEvent中,我们将typeevent组合成一个32位的数发送给对方,这里同样的,我们收到数据后取出高16位的type和低16位的event。然后调用我们使用MCMGR_RegisterEvent注册的回调函数,第一个参数为eventData,第二个参数为我们注册的时候提供的callbackData(这里为s_mcmgrCoresContext)。

6 双核状态机交互过程详解

看完了中断函数后,感觉两个核有一些联系了,我们先来看一下两个核的执行流程:
在这里插入图片描述
这些函数前面都分析过了,但是里面状态机的状态改变似乎有些复杂,而状态的改变是通过双核之间的通道3进行交互的,这里我们就来捋清里面的流程:

  • 这里通道间发送数据为32位,高16位为type,低16位为eventData,下面都表示为(type, eventData)

1、MCMGR_EarlyInit
发送32位数据,(kMCMGR_RemoteCoreUpEvent,0)。由于后面我们在MCMGR_Init函数中并没有注册kMCMGR_RemoteCoreUpEvent的回调函数,实际上这个消息会被忽略。

2、MCMGR_Init
这里没有发送任何数据,但是注册了两个回调函数,在回调函数中会发送数据:
在这里插入图片描述

3、启动CM4:MCMGR_StartCore

s_mcmgrCoresContext[1].startupData = 2;
while (s_mcmgrCoresContext[1].state != kMCMGR_RunningCoreState);

这里CM7将s_mcmgrCoresContext[1]startupData设置为了2,然后等待s_mcmgrCoresContext[1]state变为kMCMGR_RunningCoreState

4、CM4和CM7消息同步
(1)CM4在MCMGR_GetStartupData中将s_mcmgrCoresContext[1]state设置为了kMCMGR_StartupGettingLowCoreState,然后向CM7发送(kMCMGR_FeedStartupDataEvent, kMCMGR_StartupGettingLowCoreState)

(2)在CM7接收到这个32位消息后,将进入MCMGR_FeedStartupDataEventHandler中,向CM4发送(kMCMGR_StartupDataEvent, 2),然后将state设置为kMCMGR_StartupGettingLowCoreState

case kMCMGR_StartupGettingLowCoreState:(void)MCMGR_TriggerEvent(kMCMGR_StartupDataEvent, (uint16_t)(coreContext->startupData & 0xFFFFU));coreContext->state = (mcmgr_core_state_t)startupDataChunk;break;

此时双核的状态如下:
在这里插入图片描述

(3)CM4收到(kMCMGR_StartupDataEvent, 0),进入MCMGR_StartupDataEventHandler的下面分支:

case kMCMGR_StartupGettingLowCoreState:coreContext->startupData = startupDataChunk; /* Receive the low part */coreContext->state       = kMCMGR_StartupGettingHighCoreState;(void)MCMGR_TriggerEvent(kMCMGR_FeedStartupDataEvent, (uint16_t)kMCMGR_StartupGettingHighCoreState);break;

startupData设置为2,state设置为kMCMGR_StartupGettingHighCoreState,然后发送(kMCMGR_FeedStartupDataEvent, kMCMGR_StartupGettingHighCoreState)给CM7。

(4)CM7收到(kMCMGR_FeedStartupDataEvent, kMCMGR_StartupGettingHighCoreState),进入MCMGR_FeedStartupDataEventHandler的下面分支:

case kMCMGR_StartupGettingHighCoreState:(void)MCMGR_TriggerEvent(kMCMGR_StartupDataEvent, (uint16_t)((coreContext->startupData) >> 16));coreContext->state = (mcmgr_core_state_t)startupDataChunk;break;

这里发送(kMCMGR_StartupDataEvent, (uint16_t)(2>> 16))给CM4,然后设置自身的statekMCMGR_StartupGettingHighCoreState

此时双核的状态如下:
在这里插入图片描述

(5)CM4收到(kMCMGR_StartupDataEvent, 0)后,进入MCMGR_StartupDataEventHandler的下面分支:

case kMCMGR_StartupGettingHighCoreState:coreContext->startupData |= ((uint32_t)startupDataChunk) << 16;coreContext->state = kMCMGR_RunningCoreState;(void)MCMGR_TriggerEvent(kMCMGR_FeedStartupDataEvent, (uint16_t)kMCMGR_RunningCoreState);break;

startupData与之前收到的低16位进行组合,然后赋到startupData中,即CM7在MCMGR_StartCore函数中的第三个参数传给了CM4。然后将state设置为kMCMGR_RunningCoreState,并向CM7发送(kMCMGR_FeedStartupDataEvent, kMCMGR_RunningCoreState)

(6)CM7收到(kMCMGR_FeedStartupDataEvent, kMCMGR_RunningCoreState)后进入MCMGR_FeedStartupDataEventHandler中的kMCMGR_RunningCoreState分支:

case kMCMGR_RunningCoreState:coreContext->state = (mcmgr_core_state_t)startupDataChunk;break;

最终就将state设置为了kMCMGR_RunningCoreState。此时在MCMGR_StartCore中等待s_mcmgrCoresContext[1]state变为kMCMGR_RunningCoreState则成立,此时CM7知道CM4已经成功启动。

最终的状态如下:
在这里插入图片描述

7 总结

从上面状态机分析可知,CM7仅用了kMCMGR_FeedStartupDataEvent,而CM4仅用了kMCMGR_StartupDataEvent。在CM4启动后,先发送一个消息给CM7,然后CM7开始传startupData给CM4,最终CM7的状态都变为kMCMGR_RunningCoreState,表示CM7知道CM4已经启动了,就可以执行其它操作了。

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

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

相关文章

数据库交付运维高级工程师-腾讯云TDSQL

数据库交付运维高级工程师-腾讯云TDSQL上机指导&#xff0c;付费指导&#xff0c;暂定99

设计模式—装饰模式

与其明天开始&#xff0c;不如现在行动&#xff01; 文章目录 装饰模式—穿衣服&#x1f48e;总结 装饰模式—穿衣服 装饰模式&#xff08;Decorator&#xff09;可以动态的给对象添加一些额外的职责。 Component是定义一个对象接口&#xff0c;可以给这些对象动态地添加职责。…

关于mysql存储过程中N/A和null的使用注意事项

oracle和mysql的存储过程大同小异&#xff0c;但是一些细节还是需要留意的。最近发现mysql的N/A和null在存储过程中容易忽略的一点&#xff0c;这会导致我们的存储过程提前结束。今天突然想起来了就记录一下。   mysql的N/A和null区别网上也说得很详细了&#xff0c;我就不赘…

RabbitMq交换机详解

目录 1.交换机类型2.Fanout交换机2.1.声明队列和交换机2.2.消息发送2.3.消息接收2.4.总结 3.Direct交换机3.1.声明队列和交换机3.2.消息接收3.3.消息发送3.4.总结 4.Topic交换机4.1.说明4.2.消息发送4.3.消息接收4.4.总结 5.Headers交换机5.1.说明5.2.消息发送5.3.消息接收5.4.…

开源 LLM 微调训练指南:如何打造属于自己的 LLM 模型

一、介绍 今天我们来聊一聊关于LLM的微调训练&#xff0c;LLM应该算是目前当之无愧的最有影响力的AI技术。尽管它只是一个语言模型&#xff0c;但它具备理解和生成人类语言的能力&#xff0c;非常厉害&#xff01;它可以革新各个行业&#xff0c;包括自然语言处理、机器翻译、…

【POI的如何做大文件的写入】

&#x1f513;POI如何做大文件的写入 &#x1f3c6;文件和POI之间的区别是什么&#xff1f;&#x1f3c6;POI对于当今的社会发展有何重要性&#xff1f;&#x1f3c6;POI大文件的写入&#x1f396;️使用XSSF写入文件&#x1f396;️使用SXSSFWorkbook写入文件&#x1f396;️对…

webpack详细教程

1&#xff0c;什么是webpackwebpack | webpack中文文档 | webpack中文网 Webpack 不仅是一个模块打包器(bundler)&#xff0c;更完整的讲是一个前端自动化构建工具。在 Webpack 看来前端的所有资源文件(s/json/css/img/less/...)都会作为横块处理它将根据模块的依赖关系进行静…

Matlab示例-Examine 16-QAM Using MATLAB学习笔记

​工作之余学习16-QAM 写在前面 网上看到许多示例&#xff0c;但一般都比较难以跑通。所以&#xff0c;还是老方法&#xff0c;先将matlab自带的例子研究下。 Examine 16-QAM Using MATLAB Examine 16-QAM Using MATLAB 或者&#xff0c;在matlab中&#xff0c;键入&#x…

Windows11环境下配置深度学习环境(Pytorch)

目录 1. 下载安装Miniconda2. 新建Python3.9虚拟环境3. 下载英伟达驱动4. 安装CUDA版Pytorch5. CPU版本pytorch安装 1. 下载安装Miniconda 下载安装包&#xff1a;镜像文件地址 将Miniconda相关路径添加至系统变量的路径中。 打开Anaconda Powershell Prompt&#xff0c;输入…

如何将数据库导入MySQL的办法

在电脑cmd终端进行导入 首先找到MySQL中bin的位置 第一步&#xff1a;找到MySQL 第二步&#xff1a;进入MySQL 第三步&#xff1a;打开bin 第四步&#xff1a;输入cmd进入终端 第五步&#xff1a; 输入mysql -uroot -p 然后会弹出enter password&#xff1a; 输入你的密码…

Eclipse 自动生成注解,如果是IDEA可以参考编译器自带模版进行修改

IDEA添加自动注解 左上角选择 File -> Settings -> Editor -> File and Code Templates&#xff1b; 1、添加class文件自动注解&#xff1a; ​/*** <b>Function: </b> todo* program: ${NAME}* Package: ${PACKAGE_NAME}* author: Jerry* date: ${YEA…

08-工厂方法

意图 定义一个用于创建对象的接口&#xff0c;让子类决定实例化哪一个类 类图 适用性 在下列情况可以使用工厂方法模式&#xff1a; 当一个类不知道它所必须创建的对象的类的时候。当一个类希望由它的子类来指定它所创建的对象的时候。当类将创建对象的职责委托给多个帮助子…

电容C 和电感 V-I 特性

1.电容器 QCU 电压等于电流的积分乘以C分之一如下公式&#xff1a; 电容元件是一种储能元件&#xff0c;是一种无源器件。 2.电感元件 UNΔΦ/Δt UL为 在整个电感线圈的里面产生的感生电动势 N为线圈的匝数 ΔΦ 为一个线圈产生的磁通 Δt 为磁通变化的时间的长短 Li…

87 GB 模型种子,GPT-4 缩小版,超越ChatGPT3.5,多平台在线体验

瞬间爆火的Mixtral 8x7B 大家好&#xff0c;我是老章 最近风头最盛的大模型当属Mistral AI 发布的Mixtral 8x7B了&#xff0c;火爆程度压过Google的Gemini。 缘起是MistralAI二话不说&#xff0c;直接在其推特账号上甩出了一个87GB的种子 随后Mixtral公布了模型的一些细节&am…

如何提高RAG增强的准确性

在一个典型的RAG应用开发中&#xff0c;必要的步骤为文档加载&#xff0c;文档拆分&#xff0c;向量化&#xff0c;向量存储。然后基于向量存储进行相似性查询&#xff0c;或基于向量距离的查询。这类查询就叫检索&#xff0c;LangChain所提供的对应组件就是检索器。 但这种方…

Flink系列之:监控Checkpoint

Flink系列之&#xff1a;监控Checkpoint 一、概览二、概览&#xff08;Overview&#xff09;选项卡三、历史记录&#xff08;History&#xff09;选项卡四、历史记录数量配置五、摘要信息&#xff08;Summary&#xff09;选项卡六、配置信息&#xff08;Configuration&#xff…

✺ch3——数学基础

目录 3D坐标系和点矩阵单位矩阵转置矩阵逆矩阵逆转置矩阵矩阵的运算矩阵加法()矩阵乘法() 常用的变换矩阵平移矩阵缩放矩阵旋转矩阵透视矩阵正射投影矩阵LookAt矩阵 向量加法和减法点积叉积 局部空间和世界空间——模型矩阵M视觉空间和合成相机——模型-视图矩阵MV用GLSL函数构…

VR虚拟现实的七大应用领域

一、工业领域 园区利用虚拟现实技术优化生产管理与节能减排&#xff0c;实现提质增效降本。发展支持多人协作和模拟仿真的虚拟现实开放式服务平台&#xff0c;打通产品设计与制造环节&#xff0c;构建虚实融合的远程运维新型解决方案&#xff0c;适配各类先进制造技术的员工技…

电影小镇智慧旅游项目技术方案:PPT全文111页,附下载

关键词&#xff1a;智慧旅游项目平台&#xff0c;智慧文旅建设&#xff0c;智慧城市建设&#xff0c;智慧文旅解决方案&#xff0c;智慧旅游技术应用&#xff0c;智慧旅游典型方案&#xff0c;智慧旅游景区方案&#xff0c;智慧旅游发展规划 一、智慧旅游的起源 智慧地球是IB…

功能测试转向自动化测试 。10 年 心路历程——愿测试人不再迷茫

十年测试心路历程&#xff1a; 由于历史原因&#xff0c;大部分测试人员&#xff0c;最开始接触都是纯功能界面测试&#xff0c;随着工作年限&#xff0c;会接触到一些常用测试工具&#xff0c;比如抓包&#xff0c;数据库&#xff0c;linux 等。 我大学学的计算机专业&#…