From 5d9dbb028d77f9e56e37c38ee853e7d8072bd2cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=AF=85?= Date: Mon, 9 Jul 2018 17:36:48 +0800 Subject: [PATCH] Refactor mace-nnlib --- mace/core/mace.cc | 3 -- .../hexagon/hexagon_control_wrapper.cc | 9 +---- .../runtime/hexagon/hexagon_control_wrapper.h | 3 +- .../core/runtime/hexagon/hexagon_controller.h | 36 ------------------ third_party/nnlib/hexagon_nn.h | 8 ++-- third_party/nnlib/libhexagon_controller.so | Bin 16508 -> 15564 bytes 6 files changed, 8 insertions(+), 51 deletions(-) delete mode 100644 mace/core/runtime/hexagon/hexagon_controller.h diff --git a/mace/core/mace.cc b/mace/core/mace.cc index 2150e83a..db04fcc6 100644 --- a/mace/core/mace.cc +++ b/mace/core/mace.cc @@ -204,9 +204,6 @@ MaceStatus MaceEngine::Impl::Init( MACE_CHECK(hexagon_controller_->Init(), "hexagon init error"); hexagon_controller_->SetDebugLevel( static_cast(mace::logging::LogMessage::MinVLogLevel())); - int dsp_mode = - ProtoArgHelper::GetOptionalArg(*net_def, "dsp_mode", 0); - hexagon_controller_->SetGraphMode(dsp_mode); MACE_CHECK(hexagon_controller_->SetupGraph(*net_def, model_data), "hexagon setup graph error"); if (VLOG_IS_ON(2)) { diff --git a/mace/core/runtime/hexagon/hexagon_control_wrapper.cc b/mace/core/runtime/hexagon/hexagon_control_wrapper.cc index 0dac0c32..62312744 100644 --- a/mace/core/runtime/hexagon/hexagon_control_wrapper.cc +++ b/mace/core/runtime/hexagon/hexagon_control_wrapper.cc @@ -51,7 +51,7 @@ int HexagonControlWrapper::GetVersion() { bool HexagonControlWrapper::Config() { LOG(INFO) << "Hexagon config"; - if (hexagon_controller_InitHexagonWithMaxAttributes(0, 100) != 0) { + if (hexagon_nn_set_powersave_level(0) != 0) { return false; } return hexagon_nn_config() == 0; @@ -66,7 +66,7 @@ bool HexagonControlWrapper::Init() { bool HexagonControlWrapper::Finalize() { LOG(INFO) << "Hexagon finalize"; - return hexagon_controller_DeInitHexagon() == 0; + return hexagon_nn_set_powersave_level(1) == 0; } bool HexagonControlWrapper::SetupGraph(const NetDef &net_def, @@ -271,11 +271,6 @@ void HexagonControlWrapper::SetDebugLevel(int level) { "set debug level error"); } -void HexagonControlWrapper::SetGraphMode(int mode) { - LOG(INFO) << "Set dsp mode: " << mode; - MACE_CHECK(hexagon_nn_set_graph_mode(nn_id_, mode) == 0, "set mode error"); -} - void HexagonControlWrapper::GetPerfInfo() { LOG(INFO) << "Get perf info"; std::vector perf_info(MACE_MAX_NODE); diff --git a/mace/core/runtime/hexagon/hexagon_control_wrapper.h b/mace/core/runtime/hexagon/hexagon_control_wrapper.h index 4e4d8499..adcd5224 100644 --- a/mace/core/runtime/hexagon/hexagon_control_wrapper.h +++ b/mace/core/runtime/hexagon/hexagon_control_wrapper.h @@ -17,10 +17,10 @@ #include -#include "mace/core/runtime/hexagon/hexagon_controller.h" #include "mace/core/runtime/hexagon/quantize.h" #include "mace/core/tensor.h" #include "mace/public/mace.h" +#include "third_party/nnlib/hexagon_nn.h" namespace mace { @@ -44,7 +44,6 @@ class HexagonControlWrapper { void GetPerfInfo(); void ResetPerfInfo(); void SetDebugLevel(int level); - void SetGraphMode(int mode); private: static constexpr int NODE_ID_OFFSET = 10000; diff --git a/mace/core/runtime/hexagon/hexagon_controller.h b/mace/core/runtime/hexagon/hexagon_controller.h deleted file mode 100644 index afe4b727..00000000 --- a/mace/core/runtime/hexagon/hexagon_controller.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2018 Xiaomi, Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef MACE_CORE_RUNTIME_HEXAGON_HEXAGON_CONTROLLER_H_ -#define MACE_CORE_RUNTIME_HEXAGON_HEXAGON_CONTROLLER_H_ - -#include "third_party/nnlib/hexagon_nn.h" - -#ifdef __cplusplus -extern "C" { -#else -#include -#endif // __cplusplus - -int hexagon_controller_InitHexagonWithMaxAttributes(int enable_dcvs, - int bus_usage); - -int hexagon_controller_DeInitHexagon(); - -#ifdef __cplusplus -} -#endif // __cplusplus - -#endif // MACE_CORE_RUNTIME_HEXAGON_HEXAGON_CONTROLLER_H_ - diff --git a/third_party/nnlib/hexagon_nn.h b/third_party/nnlib/hexagon_nn.h index b8dbad35..b7485c93 100644 --- a/third_party/nnlib/hexagon_nn.h +++ b/third_party/nnlib/hexagon_nn.h @@ -37,7 +37,7 @@ #define THIRD_PARTY_NNLIB_HEXAGON_NN_H_ #ifndef __QAIC_HEADER #define __QAIC_HEADER(ff) ff -#endif // __QAIC_HEADER +#endif //__QAIC_HEADER #ifndef __QAIC_HEADER_EXPORT #define __QAIC_HEADER_EXPORT @@ -49,7 +49,7 @@ #ifndef __QAIC_IMPL #define __QAIC_IMPL(ff) ff -#endif // __QAIC_IMPL +#endif //__QAIC_IMPL #ifndef __QAIC_IMPL_EXPORT #define __QAIC_IMPL_EXPORT @@ -131,7 +131,7 @@ struct hexagon_nn_const_node { }; __QAIC_HEADER_EXPORT int __QAIC_HEADER(hexagon_nn_config)(void) __QAIC_HEADER_ATTRIBUTE; -__QAIC_HEADER_EXPORT int __QAIC_HEADER(hexagon_nn_init)(hexagon_nn_nn_id* g) +__QAIC_HEADER_EXPORT int __QAIC_HEADER(hexagon_nn_init)(hexagon_nn_nn_id *g) __QAIC_HEADER_ATTRIBUTE; __QAIC_HEADER_EXPORT int __QAIC_HEADER(hexagon_nn_set_debug_level)( hexagon_nn_nn_id id, int level) __QAIC_HEADER_ATTRIBUTE; @@ -221,6 +221,8 @@ __QAIC_HEADER_EXPORT int __QAIC_HEADER(hexagon_nn_execute_new)( int inputsLen, hexagon_nn_tensordef *outputs, int outputsLen) __QAIC_HEADER_ATTRIBUTE; +__QAIC_HEADER_EXPORT unsigned int __QAIC_HEADER(hexagon_nn_get_dsp_offset)(void) + __QAIC_HEADER_ATTRIBUTE; #ifdef __cplusplus } #endif diff --git a/third_party/nnlib/libhexagon_controller.so b/third_party/nnlib/libhexagon_controller.so index 7daedd621b12686032f952a0da6564a13b63981a..05c8f3d8d71401ff117ce9b75f21cebc5e44dc66 100755 GIT binary patch literal 15564 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 literal 16508 zcmeHO4RloHnf~sbo5|!4B1QCJr0VYDt6v5f&z4yJzO@f}D z)1Ezh&iWwqaN5K~{pA2pol2Tkm&_z`#&hhGbR0^I1|a`4IMyxTeaZg9g;eHMdz5pI;f8GIkOk-iiB zui!<9OZD3Uo{vHHeUyXvufborVt70p0jK$dAtEjjS>h!4n+P|?$2d%!3*d`bULN?} zh>R+0@`}Nmz^QB`|2FV_;APCe0)F@l!}5jG>v2ci0KZ2#olC-DXE@>xMMQ(Q#l0-x zch(2|kx-zq(HnBk@%th*y7!lTk%oEhmdZ#Z-5w=1on2JfVUBKeJJq2XqoJ3Dj?c=sc)G%HPyn*!`_I~ z<6Y9c%-QID$lEwNXj#Y|Y;ZOOJR^(X4{EJvj=jtqX$*|W${j=3q#3pZNqc0p0 zP433VK)qNR@{Y)a_9odgeZw04wSnF}_V@eF%9W#OxIa zI{oe@uQL*G`aB{W2{mH8n35pe=b=!FWe%9_HKtUR&+iVcxM!^F`84w9j_fRM8>ip9 z+$@bMi;?LJEM1D)nM1;jz9vCon0cQv5A+B;1$1H_z`74lEuA1s%wqIxeRC+}_1CX3 zPiB@td1E!efa7(ci7_1U)L(x+k*lyi-2`hkw1(0CjO9+)VGCf%(AwzGT>1~TYn*nl zufyI5OM5GwQLxmB8(^oxmcY{9ekCle{f41+nf4YkpVLA6orYgp!>L>sGuYlf(WHMu zNT$gj%Rg3U{k&y(Uj|1S>^RuVVX^dU2HUr0XpJXB=O1h-BA*D%6j&U?aPAv6*TYGB z#JoWL(GiEaP6r9>(L0{fu$Ovy2JG^Ne&@q;e~aHpWcG zY{neMT*f>`J7WQ3A!8AvgRzvcjIo@tg0Y&hhH)0ix?L(x)?o-4UCP9LBn1qYZ=!uu4jxgb~0{e+`_n@F~MlNO>fs+#zMw2#zl+`jGc_nGVWyD&-f1G zS;owAU48*$IpadcM#fggHH>Q+*DPKZVJ zEa7A!5`>ovah?#HqSAB2`%2Fb-XGWVWRETWtM}*AM)KN|@5yhhdvAX7rS}bYjmceM za+jIh4wJjkWtr8+sd|Fmst?b)w|Q`^6LJX55>eJ(6-u(YL5 zt@^O1UfGb+mNCuRR`h&>s^p9KFD|6T950LbD<6r%zaElQOAX1`ar*Qzv1cMS-w(0j zDmAuU8nl^`F|BD?YBu2pGj?#x8-i? z`oQ8on6SrkuQ`|~*kWz7Z9kYOYR&9W+NEe#6m@?(IT$-NF81>A_;(?9_L|s4RY9GS zgPBQD+^VJ@SuW(yC$KPNyq&wp=1{uj?G{(^&$)K_n&e>Tsa0y>3$^j&Ee=&78Q-z? zeLG!DwdKpM+TO>~t6UpqW%WsxS6r)Ia@5ixb=>{-qVBFl_7+8*uZrT=6FFPb25jlK z97!9@a)Bv2^+$44_tbpKv*C(rEgYBI?9xC**w?px|2VvQ14P_D3$RZcXH5i z%Bo(~U`L&AIaQ>J8xq|{ZRV;}xA?L20W2LGl7seBii)v)NNlt@_9n#o*Av-diEAU~ z7TT`niP(7b$)wFwRO*q&k8?JO{Iqs?Ti#V&AIefj+hv;$Ch}sor!(6oZc6WvqDos< zUy3CQ;{*NBo*e8ysrAF!k^NBfu_#`pW*o5&$hO+v{pg8IttV23dZIQi+meI7KbbnJ zFT~W^UiI<~vufiuNp?{`RG}YUG4+I^E>NjAMDc&3CsGG&nWaZk1_~^x1KGk}BCe`S z6s(kP-c=<~e+&Gj0lQS0s90H-s9sr_CSOBF zo1aqc&rpxGU6`_|_N;iYHlCL`Zd>}(8Expdk}EgK&r!eSUs(q++uiSn)q9hYK0*-l#2;0un1{EgWzOXpPlDxK5to6=c;Uu)+z_{~)( z(tLTsDDU0o@>UL)_q~3-yhglAbG!w^@qWwkP_If_m8|Mo^-9#~+6z=8tPCmEZDSm{>lfEWWgG!>`|E=a+TOZLZF|JDE1oZ^7Soi3RBl5}Xy5XkuZ?e6 zAg1a&ZQd`9y4^prZVU9f_4bXfn*(*z_pa*mG@>P{f!h*IMVngNl>((L1-{a%gryHm~iL2~fA^P*T*E6${^64SAMq*a``WL4^bl%Cd?E+j`6){?Zh`pz9pAk$eBe7H zSq5?~8WRoYl|Oicgt z9-N-iv45o5?T-w8{2aMX{e}Ea{-rA+y6}1hX)0aYU29Z%EE{CZ zp$@GyqVN}oXy>L>T?wTJc@Egd$(!y-SbHoRmG8~M+D!A|-E+0^uA%u5-Tluxb5`|^ zJ#&7s_u^;HkMUw_5#FO50AB3OIcN9SGv}As??s$9TOTy$bLsBk`S~2qi!?uR`pdWI zv$O4}P^Mv}Kr4NGLOYk^Ec!Ul=ML@E_uoRs2@yLLr7N)&q_(ADUr{X9c3ZnXw|h=x zU~ad}?ovh958fXiU)QtaOfpHY`|bR4)lT{Ydy~7xKCDA1#tS&r?Q8UU?2&+-wFq{+ zyth}+yr=F~`&BLJ+ABI0Z(JLFU-KHW@DyNrWh!)40{m8sM?_FGiLZ)f7!(trODY!+ zQ}U^Aq5#X5P8{0;f1@{i@8%iDxcUNDM3Al?

m+O?p(?58rO_2hk1O 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 SZg6wFKVd-j7?FTRy#E2&9Hv14 -- GitLab