【昇腾】【玩转Atlas200DK系列】应用开发之HelloWorld
【昇腾】【玩转Atlas200DK系列】应用开发之HelloWorld
【昇腾】万事皆有开头,从本篇起,开始学习如何开发运行在Atlas200DK上的应用!
不免俗,咱也从hello world用例开始!在本例中,我们不新增引擎,只是利用默认的引擎打印一句“Hello World”,并在结束时打印“App run finished”,来了解和学习Matrix框架和引擎的概念以及数据的流动。
通过Mind Studio工具提供的UI界面进行应用开发前,需要完成Mind Studio的安装(包括DDK安装)和编译环境的配置(包括Lib包安装),如果还没有准备好环境,请参见请参见Mind Studio安装以及配置编译环境。
创建工程
创建工程时注意选择Ascend App,并选择Custom工程,便可以创建一个最基本的拥有Matrix编程框架的自定义工程,你可以在该基本框架下添枝加叶,开发出你自己的应用。
点击Finish之后,创建的工程目录结构如下:
其中,工程结构及Matrix/Engine等的概念请参考官方指导中快速入门中体验首个AI应用进行了解,官方指导中的例子会详细告诉你这些概念,在此不再赘述。在本例中,我们开始最简单的实战编程。
编译并运行
我们先编译运行一下看看,发现该工程已经能够运行,只是运行后没有任何输出(在开发板侧直接运行也是),没有任何感觉。
HelloWorld实现
接下来我们实现我们预定的目标:
在本例中,我们不新增引擎,只是利用默认的引擎打印一句“Hello World”,并在结束时打印“App run finished”,来了解和学习Matrix框架和引擎的概念以及数据的流动。
第一步:
在main.cpp中将原来发送的空串赋值为”Hello World”
第二步:
在Custom.cpp中,接收传入的字符串并打印到屏幕上,然后发送字符串,该字符串会在引擎的回调函数中接收并输出到屏幕;
第三步:
在main.cpp中定义的回调函数中将接收到的内容输出到屏幕
第四步:
编译运行;
然后ssh登陆到开发板上直接运行可执行程序:
发现预定目标已经实现。
是不是非常简单,那当然了,要不然干嘛叫HelloWorld呢。
知其所以然
(注:如果有任何不明白的可以查看应用开发教程:https://ascend.huawei.com/doc/Atlas%20200%20DK/1.31.0.0(beta)/zh/zh-cn_topic_0197853888.html)
接下来解析工程,尝试理解下这个这个工程框架;
1. 查看graph.config, 发现只有一个引擎(Custom),该引擎ID为611,引擎名称为“Custom”,该引擎后面编译后会生成libHost.so,该so会在运行时被同步到Atlas200DK。
2. 解析main.cpp,只干了两件事情;
2.1 创建图并注册回调函数,创建图好理解,在Matrix流程编排中,依据graph.config创建图,图中定义了各个引擎以及各个引擎之间的链接关系;注册回调函数,则一般是为最后一个引擎注册一个回调函数,当最后一个引擎发送数据时,该回调函数会被调用,具体实现方法请参考(https://ascend.huawei.com/doc/Atlas%20200%20DK/1.31.0.0(beta)/zh/zh-cn_topic_0188098559.html)
2.2 发送一个数据至引擎,这时候调的是Graph::SendData, 是从外部向Matrix发送一个数据启动引擎,该数据可以是一个空串,也可以是任意一个数据类型,强转为void类型,该数据会被发送至Graph.confg中定义的一个引擎,这时数据就流动起来了。
ret = graph->SendData(engineId, "string", std::static_pointer_cast<void>(data));
在本案例中,我们就是用的这个string向引擎Custom发送一个字符串:HelloWorld
3. 解析Custom.cpp, 也是干了两件事:
首先接收传进来的数据arg0,后面我们会了解到如果有多个数据,则为arg1,arg2....
然后在发出一个数据,该数据被从0端口发出,框架保证了发送的数据会被main.cpp中定义的注册函数接收到,所以我们在这里发了一个字符串: "App run finished!"
HIAI_IMPL_ENGINE_PROCESS("Custom", Custom, INPUT_SIZE)
{
//TODO:
//user code here
auto a = std::static_pointer_cast<string>(arg0);
printf("%s\n", (*a).c_str());
//send data
std::shared_ptr<std::string> resultData(new std::string);
*resultData = "App run finished!";
HIAI_StatusT ret = SendData(0, "string", std::static_pointer_cast<void>(resultData));
return ret;
}
4. 接下来再来看main.cpp, 看注册的回到函数做了是啥?
首先是咱加的一句打屏;
然后可以看到就是将flag--, 那么该flag--什么用呢?
HIAI_StatusT CustomDataRecvInterface::RecvData(const std::shared_ptr<void>& message) {
std::shared_ptr<std::string> data = std::static_pointer_cast<std::string>(message);
std::cout << *data << std::endl;
mt.lock();
flag--;
mt.unlock();
return HIAI_OK;
}
继续查看flag发现,flag在程序启动时初始化为1,在主函数中,每隔100毫秒便会查看一次flag,如果flag小于等于0则停止运行。
那么可以理解了,在回调函数中做的事情就是为了告诉主函数该结束了。(如果你想玩一下,可以试一下将flag初始化为2(而不是1),那么一旦你开始运行,你发现你的程序结束不了了。)
for (;;) {
if(flag <= 0) {
break;
} else {
usleep(100000);
}
}
总结
通过该案例并结合应用开发教程,你应该已经大致了解了Matrix开发的基本流程,回调函数在Matrix开发中的应用,Graph::SendData以及Engine::SendData, arg0的解析,graph.config的结构和使用等等知识点。
- 点赞
- 收藏
- 关注作者
评论(0)