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>
using namespace std;
void main()
{
// int 转 string
stringstream ss;
int n = 123;
string str;
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 -i https://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
未完待续~
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 提示词工程——AI应用必不可少的技术
· 地球OL攻略 —— 某应届生求职总结
· 字符编码:从基础到乱码解决
· SpringCloud带你走进微服务的世界