android關鍵點檢測演算法效能測試
markdown筆記-android關鍵點檢測演算法效能測試
1. 基本函式
-
intent基本用法
-
使用native關機字呼叫c/c++介面檔案
- 編寫java類
- 利用JAVA類生成.h標頭檔案
- 利用標頭檔案編寫c++程式碼
- 生成dll動態連結庫
- JAVA呼叫測試
-
JNI實現機制
-
對於JNI的詳細使用
-
生命週期中onResume和其他狀態
-
移位運算中的邏輯移位和算術移位區別:邏輯移位是整體移位,補0,算術移位符號位不一起移動,如果高位為1,則要補1
-
android實現動畫效果
-
android中匯入manifest包
import android.Manifest;
importandroid.support.v4.app.ActivityCompat;
-
android獲取外部儲存讀寫許可權
1.adb除錯工具
- 使用top命令檢視記憶體使用情況
\# 檢視PID adb shell top | grep app_name \# 檢視記憶體使用情況 adb shell dumpsys meminfo <package_name>
- 將可執行檔案傳到裝置執行
# 檢視裝置
Adb devices
# 使用某個裝置號開啟shell
adb -s 700S620070801 shell
Adb start-server
adb push HelloWorld /data/local/tmp
Adb shell
chmod 777 /data/local/tmp/HelloWorld
/data/local/tmp/HelloWorld
# 新增動態lib路徑,便於找到動態庫
export LD_LIBRARY_PATH=${PWD}:${LD_LIBRARY_PATH}
# 檢視CPU資訊
cat /proc/cpuinfo
-
windows下使用gdb除錯c++程式
3.android studio中profiler
-
程序排程中schedule()函式解析
-
幾種分析工具的比較
-
使用top命令結合android profiler命令進行效能分析
-
TOP命令中各個引數的含義
PID:程序
PR:在android N之前代表執行在哪個核上,在android N上代表優先順序,當然可能裝置廠商會進行自定義
CPU%:cpu佔用
S:執行狀態
#THR:執行緒數
VSS:Virtual Set Size 虛擬耗用記憶體(包含共享庫佔用的記憶體)
RSS:Resident Set Size 實際使用實體記憶體(包含共享庫佔用的記憶體)
PCY:排程策略優先順序,SP\_BACKGROUND/SP\_FOREGROUND
UID:程序所有者的使用者id
Thread:執行緒名稱
Name:程序名**cmake使用**
4.cmake使用
-
學習手冊
-
編譯和連結過程
- 預處理(預編譯):
- 將所有的#define刪除,並展開所有的巨集定義
- 處理所有的條件預編譯指令,如#ifdef\undef\enddef
- 處理#include,將包含的檔案插入到此處
- 刪除所有註釋,新增行號和標識,便於錯誤處理
- 保留#pargma編譯器指令
gcc -E hello.c -o hello.i
# 或
cpp hello.c > hello.i
- 編譯
- 將預處理完的.i檔案進行一系列的詞法分析、語法分析、語義分析及優化後生成響應的彙編程式碼檔案
gcc -S hello.i -o hello.s
- 彙編
- 彙編是將第二步生成的彙編程式碼程式設計機器可執行的指令,每一個彙編語句幾乎都對應一條機器指令
gcc -c hello.s -o hello.o或者 as hello.s -o hello.o
- 連結
- 連結動態庫和靜態庫
gcc hello.s -o hello.o
-
使用cmake編譯一個HelloWorld程式
-
cmake官方文件
-
使用NDK獨立工具鏈編譯android上執行的c++程式
-
cmake中新增openmp並行程式設計
FIND_PACKAGE( OpenMP REQUIRED)
if(OPENMP_FOUND)
message("OPENMP FOUND")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
endif()
原文連結:https://blog.csdn.net/sinat_33442459/article/details/71215120
4.2.cmake中函式
-
find_library
find_library(名稱1 [path1 path2 …])
作用:用於查詢庫。
VAR 建立名為的快取條目以儲存此命令的結果。
如果找到了庫,結果將儲存在變數中,除非清除變數,否則將不會重複搜尋。
如果什麼也沒找到,結果將是-NOTFOUND。
REQUIRED如果未找到任何內容,該選項將停止處理並顯示一條錯誤訊息,
否則,下次使用相同的變數調 用find_library時,將再次嘗試搜尋。
NAMES 為庫指定一個或多個可能的名稱。
HINTS, PATHS 除了預設位置,還指定要搜尋的目錄。該子選項讀取系統環境變數的路徑。
DOC 指定快取條目的文件字串。
REQUIRED 如果未找到任何內容,則停止處理並顯示錯誤訊息。
# 用法示例
尋找系統庫
find_library( log-lib log )
尋找指定路徑庫
find_library(my_lib libmylib.so ./)
-
從原始碼安裝cmake
-
add_library:將指定的檔案生成連結檔案,新增到專案工程中去
add_library(<name> [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
[source1] [source2] [...])
STATIC:目標檔案的歸檔檔案,在連結其他目標的時候使用
SHARED:動態連結庫,在執行時被載入
MODULE:不會被連結到其他目標中的外掛,但是可能在執行時使用dlopen-函式
-
add_library也可以用OBJECT物件的方式來進行新增庫,即不會將目標檔案歸檔到動態庫也不會歸檔到靜態庫,在呼叫的時候再選擇是動態庫呼叫還是靜態庫呼叫
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(recipe-03 LANGUAGES CXX)
add_library(message-objs
OBJECT
Message.hpp
Message.cpp
)
# this is only needed for older compilers
# but doesn't hurt either to have it
set_target_properties(message-objs
PROPERTIES
POSITION_INDEPENDENT_CODE 1
)
add_library(message-shared
SHARED
$<TARGET_OBJECTS:message-objs>
)
add_library(message-static
STATIC
$<TARGET_OBJECTS:message-objs>
)
add_executable(hello-world hello-world.cpp)
target_link_libraries(hello-world message-static)
# 通過add_library來匯入靜態庫
add_library(MYLIB STATIC IMPORTED)
set_target_properties(MYLIB PROPERTIES IMPORTED_LOCATION path/to/mylib.a)
- link_directories:該指令的作用主要是指定要連結的庫檔案的路徑,該指令有時候不一定需要。因為find_package和find_library指令可以得到庫檔案的絕對路徑。不過你自己寫的動態庫檔案放在自己新建的目錄下時,可以用該指令指定該目錄的路徑以便工程能夠找到(相當於export LD_LIBRARY_PATH)
- link_libraries:新增需要連結的庫檔案路徑,注意這裡是全路徑(可以是靜態檔案也可以是動態檔案)
LINK_LIBRARIES("/opt/MATLAB/R2012a/bin/glnxa64/libeng.so")
LINK_LIBRARIES("/opt/MATLAB/R2012a/bin/glnxa64/libmx.so")
LINK_LIBRARIES("/opt/MATLAB/R2012a/bin/glnxa64/libeng.so" "/opt/MATLAB/R2012a/bin/glnxa64/libmx.so")
- target_link_libraries:將目標檔案和庫檔案進行連結
target_link_libraries(<target> [item1] [item2] [...]
[[debug|optimized|general] <item>] ...)
上述指令中的
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
include_directories("/opt/MATLAB/R2012a/extern/include")
LINK_DIRECTORIES("/opt/MATLAB/R2012a/bin/glnxa64")
add_executable(myProject main.cpp)
target_link_libraries(myProject eng mx)
#equals to below
#target_link_libraries(myProject -leng -lmx)
#target_link_libraries(myProject libeng.so libmx.so)
\# 示例二:
project(CGALhellworld) //專案名稱,如果目標是vs,會是sln的名稱
cmake_minimum_required(VERSION 3.1) //版本申明
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
add_compile_options(-fPIC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fpic") //cmake.exe的環境變數。具體百度cmake配置
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpic")
include_directories(./3rdParty/windows/include)//include路徑
aux_source_directory(./AreaCaculate Allcpp )//新增AreaCaculate這個資料夾下的所有cpp,並命名為allcpp
link_directories(./3rdParty/android/lib/32) //新增靜態庫路徑
//add_library是生成庫的意思,生成exe是add_execute
add_library(
AreaCaculate //庫名/程式名
SHARED //共享庫
${Allcpp})//放入cpp,可以使用絕對路徑一個一個寫
set_property(TARGET AreaCaculate PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(AreaCaculate liblog.so)//新增所需靜態庫(目標名 庫名),這個是log庫。可以在c++裡直接寫loge列印日誌
-
Link_libraries和target_link_libraries的區別:target_link_libraries是在目的檔案已經編譯後才進行的,如果目的檔案沒有編譯,則不進行。link_libraries則是在他下面的所有add_executable,不管是否需要連結庫,都會進行,除非將其他不需要連結庫的add_executable放在其前面,那就沒有影響了,再者,由於某些你想要編譯的檔案根本不需要連結庫,link_libraries這一操作算是多此一舉了,另外一個區別就是,如果是多檔案在CMakeLists下,target_link_libraries可以指定給哪個exe檔案連線庫,其實link_libraries和target_link_libraries是不同的連線方式,link_directory是設定環境變數,使用target_link_libraries時也可以不使用它,直接按照link_libararies的方式一樣,給出路徑就行。二者唯一區別就是一個放在add_executable前面,一個要放在後面
-
include_directories:將指定目錄新增到編譯器的標頭檔案搜尋路徑之下,指定的目錄被解釋成當前原始碼路徑的相對路徑
# CMakeList.txt
cmake_minimum_required(VERSION 3.18.2)
project(include_directories_test)
include\_directories(sub) #與上個場景不同的地方在於此處,sub下存放test.h
add_executable(test main.cpp)
//main.cpp
#include "test.h"
#include <stdio.h>
int main(int argc, char **argv)
{
printf("hello, world!\n");
return 0;
}
- cmake中使用條件判斷(CMake菜譜)
if(USE_LIBRARY)
# add_library will create a static library
# since BUILD_SHARED_LIBS is OFF
add_library(message ${_sources})
add_executable(hello-world hello-world.cpp)
target_link_libraries(hello-world message)
else()
add_executable(hello-world hello-world.cpp ${_sources})
endif()
- option引數:可以使用-D選項來傳遞引數,有點像將-DANDROID連在一起表示傳參
# CMakeList.txt
option(USE_LIBRARY "Compile sources into a library" OFF)
# shell
Cd build
cmake -D USE_LIBRARY=ON ..
-
find_package:引入依賴包,分為兩種模式,module模式和config模式,module預設需要Find.cmake,此檔案負責查詢庫所在的路徑,此檔案在share/cmake-
/Modules目錄下,或指定的CMAKE_MODULE_PATH,如果失敗,則轉入config模式
4.3.編譯專案完成流程
- 此流程參考CMake菜譜,計算不同幾何影象的面積
# computer_area.cpp 這裡相當於main.cpp來對其他檔案進行呼叫
#include "geometry_circle.hpp"
#include "geometry_polygon.hpp"
#include "geometry_rhombus.hpp"
#include "geometry_square.hpp"
#include <cstdlib>
#include <iostream>
int main() {
using namespace geometry;
double radius = 2.5293;
double A_circle = area::circle(radius);
std::cout << "A circle of radius " << radius << " has an area of " << A_circle
<< std::endl;
int nSides = 19;
double side = 1.29312;
double A_polygon = area::polygon(nSides, side);
std::cout << "A regular polygon of " << nSides << " sides of length " << side
<< " has an area of " << A_polygon << std::endl;
double d1 = 5.0;
double d2 = 7.8912;
double A_rhombus = area::rhombus(d1, d2);
std::cout << "A rhombus of major diagonal " << d1 << " and minor diagonal " << d2
<< " has an area of " << A_rhombus << std::endl;
double l = 10.0;
double A_square = area::square(l);
std::cout << "A square of side " << l << " has an area of " << A_square
<< std::endl;
return EXIT_SUCCESS;
}
- 檔案目錄結構如下:
.
├─ CMakeLists.txt
├─ compute-areas.cpp
├─ geometry_circle.cpp
├─ geometry_circle.hpp
├─ geometry_polygon.cpp
├─ geometry_polygon.hpp
├─ geometry_rhombus.cpp
├─ geometry_rhombus.hpp
├─ geometry_square.cpp
└─ geometry_square.hpp
- CMakeList.txt的編寫
# 1.設定cmake的最低版本
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
# 2.宣告專案和語言CXX表示設定的編譯器,如cmake -D CMAKE_CXX_COMPILER=clang++ ..或env CXX=clang++ cmake .. 命令
project(recipe-08 LANGUAGES CXX)
# 3.列印當前編譯器標誌
message("C++ compiler flags: ${CMAKE_CXX_FLAGS}")
# 4.為目標檔案準備標誌列表,其中一些無法在windows上使用
list(APPEND flags "-fPIC" "-Wall")
if(NOT WIN32)
list(APPEND flags "-Wextra" "-Wpedantic")
endif()
# 5.將要呼叫的檔案打包成一個靜態庫
add_library(geometry
STATIC
geometry_circle.cpp
geometry_circle.hpp
geometry_polygon.cpp
geometry_polygon.hpp
geometry_rhombus.cpp
geometry_rhombus.hpp
geometry_square.cpp
geometry_square.hpp
)
# 6.為這個庫設定編譯選項
target_compile_options(geometry
PRIVATE
${flags}
)
# 7.將main函式新增成一個可執行目標檔案
add_executable(compute-areas compute-areas.cpp)
# 8.為可執行目標檔案設定編譯選項
target_compile_options(compute-areas
PRIVATE
"-fPIC"
)
# 9.將可執行檔案連結到庫檔案
target_link_libraries(compute-areas geometry)
4.4.使用cmake和NDK進行交叉編譯
- 示例使用cmake交叉編譯paddle lite的關鍵點檢測模型
1.編寫完cpp程式和CMakeLists.txt
# CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1)
project(pose-demo)
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread" )
set(PaddleLite_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../PaddleLite")
set(OpenCV_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../OpenCV/sdk/native/jni")
find_package(OpenCV REQUIRED)
message(STATUS "OpenCV libraries: ${OpenCV_LIBS}")
include_directories(${OpenCV_INCLUDE_DIRS})
include_directories(${PaddleLite_DIR}/cxx/include)
find_package( OpenMP REQUIRED)
if(OPENMP_FOUND)
message("OPENMP FOUND")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
endif()
set(SRCS postprocess.cc postprocess.h Detector.cc Detector.h Detector_Kpts.cc Detector_Kpts.h Pipeline.cc Pipeline.h Utils.cc Utils.h pose_action.cc pose_action.h)
add_executable(pose-demo main.cpp ${SRCS})
target_link_libraries(
# Specifies the target library.
pose-demo
${PaddleLite_DIR}/cxx/libs/${ANDROID_ABI}/libpaddle_light_api_shared.so
${OpenCV_LIBS}
GLESv2
EGL
${log-lib}
)
- 使用make.sh加編譯選項進行編譯
export BASE_PATH=/data/liyy/PoseDemoProject
export NDK_PATH=${BASE_PATH}/android-ndk-r15c
#export NDK_PATH=${SDK_PATH}
export cmake=${NDK_PATH}/build/cmake/cmake-3.22.1/bin/cmake
export LD_LIBRARY_PATH=${NDK_PATH}/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a:${LD_LIBRARY_PATH}
export LD_LIBRARY_PATH=/data/liyy/PoseDemoProject/pose_demo_android/app/src/main/cpp/build:${LD_LIBRARY_PATH}
mkdir build
cd build
${cmake} -DANDROID_NDK=${NDK_PATH}/build \
-DCMAKE_TOOLCHAIN_FILE=${NDK_PATH}/build/cmake/android.toolchain.cmake \
-DANDROID_PLATFORM=android-21 \
-DANDROID_TOOLCHAIN=clang \
-DANDROID_STL=c++_shared \
-DANDROID_ABI="arm64-v8a" ..
#-DANDROID_ABI="armeabi-v8a with NEON" ..
make -j4
5.NDK交叉編譯
-
ndk下載和使用
-
ubuntu下使用g++編譯HelloWorld
-
各版本NDK下載地址總結
-
NDK預設安裝工具鏈使用手冊
-
Cmake+NDK編譯可執行檔案
-
如何在androd中執行java程式?
4.Questions
-
為什麼android studio中profiler工具與top命令中不一樣?
android中顯示的CPU使用是總的CPU使用,而top中CPU顯示的是單個CPU使用,例如有8個CPU如果是top命令檢視則最大可以達到800%
-
eclispe中怎麼更改java版本?
-
cmd中執行javac可以,但是執行java命令報錯找不到類?
-
怎麼從eclipse中新建一個android專案?
-
怎麼從android studio專案中新增c++呼叫?
-
clang是什麼?與gcc一樣,是一個編譯器,但是是編譯器的前端,到編譯這一步都由clang完成,但是生成可執行檔案由LLVM(Low Level Virtual Machine)完成
-
armeabi-v7a是什麼意思?
一種CPU型別,一般為armeabi-v7a,可以通過命令檢視CPU型別
-
怎麼檢視CPU型別是armeabiv7還是v8?
# 檢視CPU型別
adb shell getprop ro.product.cpu.abi
# 檢視CPU架構
cat /proc/cpuinfo
-
靜態庫和共享庫的區別?
-
HelloWorld在android上交叉編譯不通過?
- 刪除build檔案和快取
- 動態庫.so改為靜態庫,可能沒有新增動態庫路徑到LD_LIBRARY_PATH中
pwd為當前資料夾,添加當前資料夾到LD_LIBRARY_PATH中
export LD_LIBRARY_PATH=${PWD}:${LD_LIBRARY_PATH}
-
編譯出錯:NEON support not enabled
-
.hpp.cc與.h.cpp的區別與聯絡
-
什麼是najia?najia是專注於快速的小型構建系統,在cmake中稱為生成器
-
怎麼在cmake中引入opencv庫?
-
使用find_package或者知道include目錄可以直接使用link_libraries指令
Ubuntu中使用cmake連結opencv庫的兩種方法(opencv3中 base+module動態庫的名字也在這裡寫好了)
-
可以在CMakeList.txt中設定OpenCV_DIR來找到OpenCV
set(OpenCV_DIR /home/User/opencv/build/)
find_package( OpenCV REQUIRED )
include_directories(${OpenCV_INCLUDE_DIRS})
-
找不到.so檔案怎麼辦?cmake查詢的是哪個目錄?查詢的是LD_LIBRARY_PATH
-
為什麼要再add_library中使用IMPORTED?有什麼作用?看不懂文件描述?
可以增加so或者靜態檔案路徑
-
ndk中gdb.exe除錯工具被移動?找不到gdb.exe?
D:\app\android-studio\sdk\ndk\21.4.7075529\prebuilt\windows-x86_64\bin>
-
編譯完之後出現了執行錯誤:/usr/local/google/buildbot/src/android/ndk-r15-release/external/libcxx/../../external/libcxxabi/src/abort_message.cpp:74: void abort_message(const char *, ...): assertion "terminating with uncaught exception of type std::bad_cast: std::bad_cast" failed
- 在編寫make.sh中,傳入的ANDROID_STL引數為libc++_static或者是libc++_shared要與使用的paddle_lite的static版本或者是shared版本一致
export BASE_PATH=/data/liyy/PoseDemoProject
export NDK_PATH=${BASE_PATH}/android-ndk-r15c
#export NDK_PATH=${SDK_PATH}
export cmake=${NDK_PATH}/build/cmake/cmake-3.22.1/bin/cmake
export LD_LIBRARY_PATH=${NDK_PATH}/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a:${LD_LIBRARY_PATH}
export LD_LIBRARY_PATH=/data/liyy/PoseDemoProject/pose_demo_android/app/src/main/cpp/build:${LD_LIBRARY_PATH}
mkdir build
cd build
${cmake} -DANDROID_NDK=${NDK_PATH}/build \
-DCMAKE_TOOLCHAIN_FILE=${NDK_PATH}/build/cmake/android.toolchain.cmake \
-DANDROID_PLATFORM=android-21 \
-DANDROID_TOOLCHAIN=clang \
// 這裡的ANDROID\_STL要與paddle\_lite版本一致
-DANDROID_STL=c++_shared \
-DANDROID_ABI="armeabi-v7a with NEON" ..
make -j4
-
出現make: *** No targets specified and no makefile found. Stop.錯誤
可能是快取問題,清除快取
-
增加模型推理併發能力的方法有哪些?
- 每隔一段時間如50ms做成batch來進行推理
- 使用多程序或者多執行緒來例項化物件,進行推理
-
在使用四個執行緒進行推理時,為什麼記憶體使用量沒有增加且推理耗時增加從100ms增加到了400ms?
請問paddle-lite android armv7的編譯庫 set_threads 沒有速度提升?(多核cpu的 使用率一直是100%)
- 列印檢視例項化的物件的記憶體地址,是否真的有例項化
- 列印檢視每個CPU的使用情況,檢視是否使用了多核CPU
- 檢視呼叫的CPU是否是執行緒安全
- 檢視是否限制了多核使用
-
手機CPU中什麼是大核什麼是小核?
-
怎麼通過關鍵點檢測模型得到第二種類別的關鍵點?
需要重新訓練模型(是在人的類別訓練好的情況下再進行訓練嗎?還是說同時訓練?),經過github提問,得到的答覆是需要另外訓練一個模型才行
-
shell指令碼執行發生錯誤:/bin/bash^M: bad interpreter: No such file or directory
shell指令碼執行報錯:/bin/bash^M: bad interpreter: No such file or directory
# 因為window上編輯的為dos格式,linux上為unix格式,通過檢視檔案是什麼格式
Vim filemain
:set ff
# 將dos格式轉為unix格式
:set ff=unix
-
Paddle lite怎麼進行量化?
參考文件:
-
為什麼在應用中訪問/proc/stat會顯示沒有許可權?cannot open /proc/stat: java.io.FileNotFoundException: /proc/stat: open failed: EACCES (Permission denied)
android O全稱為android Oreo,一般指android 8.0,即8.0之後不再被允許APP訪問/proc/stat,所以需要單獨寫c++程式來檢測每個核的使用,然後使用cmake和NDK交叉編譯到android執行即可
Android O: Permission denied on /proc entries for htop and top
c++監控CPU核的使用程式碼如下:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include "stdio.h"
#include <cstring>
#include <unistd.h>
#define CPU_NUMBER 8
long mLastIdle[CPU_NUMBER + 1];
long mUsage[CPU_NUMBER + 1];
long mLastTotal[CPU_NUMBER + 1];
int splitStringToVect(const std::string & srcStr, std::vector<std::string> & destVect, const std::string & strFlag)
{
// 從s下標為0開始查詢字串strFlag,返回起始位置,找不到返回-1
int pos = srcStr.find(strFlag, 0);
int startPos = 0;
int splitN = pos;
std::string lineText(strFlag);
while (pos > -1)
{
lineText = srcStr.substr(startPos, splitN);
startPos = pos + 1;
pos = srcStr.find(strFlag, pos + 1);
splitN = pos - startPos;
destVect.push_back(lineText);
}
lineText = srcStr.substr(startPos, srcStr.length() - startPos);
destVect.push_back(lineText);
return destVect.size();
}
void printCpuState()
{
// is為檔案流
std::ifstream is("/proc/stat");
// 使用stringstream來進行ifstream和string的轉化
std::stringstream buffer;
buffer << is.rdbuf();
std::string strbuff(buffer.str());
//std::cout << "start /proc/stat" << strbuff.c_str() << std::endl;
printf("********** start /proc/stat log\n* %s\n********** end /proc/stat log\n",strbuff.c_str());
//LOGV("********** start /proc/stat log\n* %s\n********** end /proc/stat log",strbuff.c_str());
std::vector<std::string> vec;
std::string flag = " ";
//vec = Tokenize(strbuff);
int size = splitStringToVect(strbuff,vec,flag);
//@ref http://stackoverflow.com/questions/11739444/how-to-get-usage-of-each-cpu-core-on-android
int cntcpu = 0;
for(int i = 0 ; i < vec.capacity(); i++){
std::string str = vec[i];
// string::npos表示不存在的位置
if( (str.find("cpu") != std::string::npos ) ) {//if contains str
// the columns are:
//
// 0 "cpu": the string "cpu" that identifies the line
// 1 user: normal processes executing in user mode
// 2 nice: niced processes executing in user mode
// 3 system: processes executing in kernel mode
// 4 idle: twiddling thumbs
// 5 iowait: waiting for I/O to complete
// 6 irq: servicing interrupts
// 7 softirq: servicing softirqs
//
// 這裡由於我的/proc/stat檔案中cpu行有兩個空格的情況,而vector都是按一個空格存的,所以cpu行會多出一個空格來,導致idle行後移了一位,需要單獨處理
if(str == "cpu"){
// cpu行有兩個空格導致錯誤
//std::cout << "CPU SP:" << idle << std::endl;
long idle = atol(vec[i+5].c_str());
long total = 0;
bool head = true;
for(int j = 0 ; j < 8; j++){
total += atol(vec[i+j+1].c_str());
}
long diffIdle = idle - mLastIdle[cntcpu];
long diffTotal = total - mLastTotal[cntcpu];
int usage = (int)((float)(diffTotal - diffIdle) / diffTotal * 100);
mUsage[cntcpu] = usage;
mLastTotal[cntcpu] = total;
mLastIdle[cntcpu] = idle;
printf("CPU difTot[%d] difIdle[%d]\n",diffTotal,diffIdle);
//LOGV("CPU difTot[%d] difIdle[%d]",diffTotal,diffIdle);
cntcpu++;
}else{
long idle = atol(vec[i+4].c_str());//Long.parseLong(parts[4], 10);
long total = 0;
bool head = true;
for(int j = 0 ; j < 7; j++){
total += atol(vec[i+j+1].c_str());
}
long diffIdle = idle - mLastIdle[cntcpu];
long diffTotal = total - mLastTotal[cntcpu];
int usage = (int)((float)(diffTotal - diffIdle) / diffTotal * 100);
mUsage[cntcpu] = usage;
mLastTotal[cntcpu] = total;
mLastIdle[cntcpu] = idle;
printf("CPU difTot[%d] difIdle[%d]\n",diffTotal,diffIdle);
//LOGV("CPU difTot[%d] difIdle[%d]",diffTotal,diffIdle);
cntcpu++;
}
}
}
for(int i = 0 ; i < CPU_NUMBER + 1; i++){
printf("CORE[%d] tot[%d] idl[%d] use[%d]\n",i,mLastTotal[i],mLastIdle[i],mUsage[i]);
//LOGV("CORE[%d] tot[%d] idl[%d] use[%d]",i,mLastTotal[i],mLastIdle[i],mUsage[i]);
}
printf("CPU Usage :Tot[%d\%] Core0[%d\%] Core1[%d\%] Core2[%d\%] Core3[%d\%] Core4[%d\%] Core5[%d\%] Core6[%d\%] Core7[%d\%]\n",
mUsage[0],
mUsage[1],
mUsage[2],
mUsage[3],
mUsage[4],
mUsage[5],
mUsage[6],
mUsage[7],
mUsage[8]
);
// LOGV("CPU Usage :Tot[%d\%] Core0[%d\%] Core1[%d\%] Core2[%d\%] Core3[%d\%]",
// mUsage[0],
// mUsage[1],
// mUsage[2],
// mUsage[3],
// mUsage[4]
// );
is.close();
}
int main(){
// 初始化時間為0
std::cout << "run main" << std::endl;
for(int i = 0 ; i < CPU_NUMBER + 1; i++){
mLastIdle[i] = 0;
mUsage[i] = 0;
mLastTotal[i] = 0;
}
int loop = 100;
while(loop){
printCpuState();
sleep(1);
std::cout << "delay 1" << std::endl;
loop--;
}
}
關鍵點檢測怎麼來做動作識別?
- 在關鍵點檢測後可以套動作識別模型
- 由於動作型別比較少,可以直接通過邏輯來判斷
關鍵點檢測怎麼得到運動資訊?
- 可以使用左右腳交替來判斷,得到跑步頻率
- 得到速度需要通過場地距離,來進行判斷
為什麼在app中打印出來的預測耗時在100ms左右,但是自己寫的c++程式跑出來的接近300ms,兩者為什麼會有這麼大的差距?
- 圖片大小要一致
- Paddle lite中有config檔案,裡面有優先順序和執行緒數,調節優先順序和執行緒數
- 可能有其他因素影響,在監控CPU之後,剛開始使用多執行緒依然會發現耗時增加問題,使用top檢視CPU使用情況時,發現Logd佔用CPU很高,以為是android studio問題,所以重新啟動android studio,重新連線平板後,偶然測試發現耗時恢復了正常,暫時不清楚是什麼情況
調節paddle lite執行緒數沒有效果,原因是什麼?
github上見回覆:issue
1)這個建議先在shell下驗證多執行緒是否生效,已排除APP殼的影響shell-demo:可以參考readme.md 文件完成模型和輸入預/後處理更新進行驗證
2)如果shell下多執行緒生效,然後可以參考paddle-lite-demo APP殼,完成你的模型和輸入/輸出處理更新,以驗證是否有問題
3)如果在這個APP 工程沒有問題,說明你參考的APP-demo 應該在多執行緒上處理有問題,執行緒數可能沒有生效
7.未解決問題
-
為什麼g++ -E引數會報錯?
-
使用cv::imread出現段錯誤sagment fault
單獨使用imread函式時在android中可以執行,但是加入到demo的main函式時不能執行
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
//using namespace cv;
int main(int argc,char **argv){
cv::Mat img;
std::cout << argv[1] << std::endl;
std::string imgPath = argv[1];
img = cv::imread(imgPath);
if(img.empty()){
std::cout << "read failed!" << std::endl;
return 1;
}
std::cout << "read success!" << std::endl;
return 0;
}
markdown筆記-c++
1.基本概念
-
std名稱空間:C++ 引入了名稱空間的概念,計劃重新編寫庫,將類、函式、巨集等都統一納入一個名稱空間,這個名稱空間的名字就是std。std 是 standard 的縮寫,意思是“標準名稱空間”
-
執行緒安全:
2.基本函式
-
reinterpret_cast:顧名思義,就是把記憶體裡的值重新解釋。本質上記憶體裡存的都是01位串,至於這些位串是什麼意思全看怎麼解釋。舉個例子,32位系統,int是32位,指標也是32位,我既可以把一個32位的值解釋成一個整數,也可以解釋成一個指標。至於究竟能不能這樣解釋,由程式設計師負責。而reinterpret_cast就是幹這個事的
-
std::shared_ptr:
-
作用:
a. 自動釋放沒有指標引用的資源
b. 使用引用計數記錄指向改資源的指標數
c. 執行緒安全 -
Set::reset用法:智慧指標指向新的物件
\# std::reset用法
#include <iostream>
#include <future>
#include <thread>
using namespace std;
class Person
{
public:
Person(int v) {
value = v;
std::cout << "Cons" <<value<< std::endl;
}
~Person() {
std::cout << "Des" <<value<< std::endl;
}
int value;
};
int main()
{
std::shared_ptr<Person> p1(new Person(1));// Person(1)的引用計數為1
std::shared_ptr<Person> p2 = std::make_shared<Person>(2);
p1.reset(new Person(3));// 首先生成新物件,然後引用計數減1,引用計數為0,故析構Person(1)
// 最後將新物件的指標交給智慧指標
std::shared_ptr<Person> p3 = p1;//現在p1和p3同時指向Person(3),Person(3)的引用計數為2
p1.reset();//Person(3)的引用計數為1
p3.reset();//Person(3)的引用計數為0,析構Person(3)
p3.reset();//再reset
return 0;
}
- c++讀寫檔案
#include <fstream> // ifstream, ifstream::in
using namespace std;
int main(){
// 1. 開啟圖片檔案
// 評論區的 @霍鑫網路 幫忙發現一個隱藏的bug,在此表示感謝,已經修正
// ifstream相關資料:https://blog.csdn.net/sinat_36219858/article/details/80369255
ifstream is("test.jpg", ifstream::in | ios::binary);
// 2. 計算圖片長度
is.seekg(0, is.end);
int length = is.tellg();
is.seekg(0, is.beg);
// 3. 建立記憶體快取區
char * buffer = new char[length];
// 4. 讀取圖片
is.read(buffer, length);
// 到此,圖片已經成功的被讀取到記憶體(buffer)中
delete [] buffer;
// 感謝評論區 @geocat 幫忙發現的bug,已經修正
is.close();
return 0;
}
- string和char之間的轉換
//這一段在cppreference裡面線上編譯執行的,
//用的VS2017的編譯器不支援strcpy,
//而且不支援strcpy_s裡面的引數型別為(char *,const char*)
//說沒有匹配的過載函式
string str = "hello";
char *p;
p = (char *)malloc((str.length()+1)*sizeof(char));
strcpy(p, str.c_str());
-
int與string的轉換
#include"stdafx.h"
#include<string>
#include<sstream>
usingnamespacestd;
voidmain()
{
//int轉string
stringstreamss;
intn=123;
stringstr;
ss<<n;
ss>>str;
//string轉int
str="456";
n=atoi(str.c_str());
}
-
c++中使用多執行緒
#include <iostream>
#include <vector>
#include <algorithm>
#include <thread>
using namespace std;
//執行緒要做的事情就寫在這個執行緒函式中
void GetSumT(vector<int>::iterator first,vector<int>::iterator last,int &result)
{
result = accumulate(first,last,0); //呼叫C++標準庫演算法
}
int main() //主執行緒
{
int result1,result2,result3,result4,result5;
vector<int> largeArrays;
for(int i=0;i<100000000;i++)
{
if(i%2==0)
largeArrays.push_back(i);
else
largeArrays.push_back(-1*i);
}
thread first(GetSumT,largeArrays.begin(),
largeArrays.begin()+20000000,std::ref(result1)); //子執行緒1
thread second(GetSumT,largeArrays.begin()+20000000,
largeArrays.begin()+40000000,std::ref(result2)); //子執行緒2
thread third(GetSumT,largeArrays.begin()+40000000,
largeArrays.begin()+60000000,std::ref(result3)); //子執行緒3
thread fouth(GetSumT,largeArrays.begin()+60000000,
largeArrays.begin()+80000000,std::ref(result4)); //子執行緒4
thread fifth(GetSumT,largeArrays.begin()+80000000,
largeArrays.end(),std::ref(result5)); //子執行緒5
first.join(); //主執行緒要等待子執行緒執行完畢
second.join();
third.join();
fouth.join();
fifth.join();
int resultSum = result1+result2+result3+result4+result5; //彙總各個子執行緒的結果
return 0;
}
-
c++中使用執行緒池
-
C++中實現延時
#include<iostream>
#include <cstring>
void delay_msec(int msec)
{
clock_t now = clock();
while(clock()-now < msec);
}
Void main(){
std::cout << "sleep:100" << std::endl;
delay_msec(200);
}
-
c++中std::stringstream使用
# nclude <iostream\>
# nclude <sstream\>
# nclude <string\>
using namespace std;
int main()
{
stringstream ostr("ccc");
ostr.put('d');
ostr.put('e');
ostr<<"fg";
string gstr = ostr.str();
cout<<gstr<<endl;
char a;
ostr>>a;
cout<<a
system("pause");
}
- Tokenize分割字串到vector容器
https://blog.csdn.net/weixin_33713503/article/details/93781262
#include <string>
#include <vector>
using std::string;
using std::vector;
int splitStringToVect(const string & srcStr, vector<string> & destVect, const string & strFlag);
int main()
{
string str = "asdasdas \n, sadasd\n, ssdddsrr\n \n \n ss\n";
vector<string> destVect;
splitStringToVect(str, destVect, "\n"); //以"\n"為標記,分割字串到vector中
return 1;
}
int splitStringToVect(const string & srcStr, vector<string> & destVect, const string & strFlag)
{
int pos = srcStr.find(strFlag, 0);
int startPos = 0;
int splitN = pos;
string lineText(strFlag);
while (pos > -1)
{
lineText = srcStr.substr(startPos, splitN);
startPos = pos + 1;
pos = srcStr.find(strFlag, pos + 1);
splitN = pos - startPos;
destVect.push_back(lineText);
}
lineText = srcStr.substr(startPos, srcStr.length() - startPos);
destVect.push_back(lineText);
return destVect.size();
}
-
c++中vector的size和capacity區別
-
通過/proc/stat計算cpu使用率
http://www.blogjava.net/fjzag/articles/317773.html
1、取樣兩個足夠短的時間間隔的Cpu快照,分別記作t1,t2,其中t1、t2的結構均為:
(user、nice、system、idle、iowait、irq、softirq、stealstolen、guest)的9元組;
2、計算總的Cpu時間片totalCpuTime
a)把第一次的所有cpu使用情況求和,得到s1;
b)把第二次的所有cpu使用情況求和,得到s2;
c)s2 - s1得到這個時間間隔內的所有時間片,即totalCpuTime = j2 - j1 ;
3、計算空閒時間idle
idle對應第四列的資料,用第二次的第四列-第一次的第四列即可
idle=第二次的第四列-第一次的第四列
6、計算cpu使用率
pcpu =100* (total-idle)/total
- c++中string::find的用法
string s;
string s1;
cin>>s>>s1;
s.find(s1);//返回s1在s中的位置,沒找到返回\-1
s.find\_first\_of(s1);//返回任意字元s1在s中第一次出現的位置,s1是字元不可以為字串
s.find(s1, a);//從s下標為a開始查詢字串s1,返回起始位置,找不到返回\-1
原文連結:https://blog.csdn.net/qq_41444888/article/details/79601846
- c++中string::substr用法
1 int main()
2 {
3 string a;
4 string s("123456789");
5
6 a = s.substr(0,5);//拷貝字串s中從第0位開始的長度為5的字串
7 cout << a << endl;//輸出12345
8
9 a=s.substr(); //不加引數即預設拷貝整個字串s
10 cout<<a<<endl;//輸出123456789
11
12 a=s.substr(4);//輸出56789
13 cout<<a<<endl;//單個引數則預設拷貝從第4位開始至末尾的字串
14 }
原文連結:https://www.cnblogs.com/HOLLAY/p/11324452.html
3.Questions
-
為什麼在#include之後還需要使用std?
如果不使用using std::string,就在程式中使用string 型別變數,程式不能識別是標準庫中的string 變數。因為程式自定義標頭檔案中也可能含有string變數。所以一定要宣告using std::string。這樣程式裡面的string型別變數就都是std標準庫中的string變量了
markdown筆記-linux
1.基本命令
- top命令
# 檢視某個程序的PID
pidof php-fpm
# top檢視某個程序資訊
top -p 29618
# 將top的資料每隔5秒輸出到檔案dir中,-b表示bash模式,-d加上數字表示輸出間隔
top -b -d 5 > dir
PID:程序
PR:在android N之前代表執行在哪個核上,在android N上代表優先順序,當然可能裝置廠商會進行自定義
CPU%:cpu佔用
S:執行狀態
#THR:執行緒數
VSS:Virtual Set Size 虛擬耗用記憶體(包含共享庫佔用的記憶體)
RSS:Resident Set Size 實際使用實體記憶體(包含共享庫佔用的記憶體)
PCY:排程策略優先順序,SP_BACKGROUND/SP_FOREGROUND
VIRT: virtual memory usage 虛擬記憶體總量
RES:resident memory usage 常駐記憶體
SHR:shared memory 共享記憶體
UID:程序所有者的使用者id
Thread:執行緒名稱
Name:程序名
- 檢視CPU佔用
/proc/stat
2.基本概念
-
虛擬記憶體、實際記憶體和記憶體管理
3.問題
- 為什麼使用top命令檢視CPU佔用率時會出現超出100%的情況?
CPU為多核時會出現佔用率超出100%的情況,例如8核,則最大佔用率可以達到800%。使用cat /proc/cpuinfo可以檢視CPU資訊
# 總核數 = 物理CPU個數 X 每顆物理CPU的核數
# 總邏輯CPU數 = 物理CPU個數 X 每顆物理CPU的核數 X 超執行緒數
# 檢視物理CPU個數
cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l
# 檢視每個物理CPU中core的個數(即核數)
cat /proc/cpuinfo| grep "cpu cores"| uniq
# 檢視邏輯CPU的個數
cat /proc/cpuinfo| grep "processor"| wc -l
-
為什麼使用多執行緒或是單執行緒時最大佔用都是單核的100%或者是在100%上下波動?是隻使用了一個單核處理器嗎?那為什麼不使用多核處理器?
因為paddle lite使用的是單執行緒,導致只使用一個CPU進行運算
markdown筆記-paddle lite關鍵點檢測模型量化
1.相關資源
# train資料集
http://images.cocodataset.org/zips/train2017.zip
http://images.cocodataset.org/annotations/annotations_trainval2017.zip
# val資料集
http://images.cocodataset.org/zips/val2017.zip
http://images.cocodataset.org/annotations/stuff_annotations_trainval2017.zip
# test資料集
http://images.cocodataset.org/zips/test2017.zip
http://images.cocodataset.org/annotations/image_info_test2017.zip
2.基本概念
-
mAP基本含義:mean averge precision
PR曲線:precision-recall曲線
Precision: TP / (TP + FP)
Recall:
TP: IoU>0.5的檢測框數量(同一Ground Truth只計算一次)
FP: IoU<=0.5的檢測框,或者是檢測到同一個GT的多餘檢測框的數量
FN: 沒有檢測到的GT的數量
Ground Truth:理想的結果或是期望的結果,詳解
3.量化步驟
- 在conda環境下安裝paddlelism
# 安裝最新版本
pip install paddleslim -i https://pypi.tuna.tsinghua.edu.cn/simple
# 安裝指定版本
pip install paddleslim==2.0.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
- 安裝paddle
官網地址:https://github.com/PaddlePaddle/Paddle
# CPU
pip install paddlepaddle
pip install paddlepaddle -ihttps://pypi.tuna.tsinghua.edu.cn/simple
# GPU
pip install paddlepaddle-gpu
- 下載coco資料集,使用cocoapi從coco資料集中分出100張訓練圖片和資料
# 1.下載coco資料集,資料集見相關資源章節
# 2.安裝依賴和coco api
pip install numpy Cython matplotlab
Git clone https://github.com/cocodataset/cocoapi.git
~$ cd coco/PythonAPI
~/cocoapi$ make
未完待續~