• [迁移工具] 鲲鹏代码迁移工具实践:CMake软件迁移评估-分析软件包
    1      验证CMake x86软件包在arm服务器上不可执行点击如下地址获取x86源码包。         https://github.com/Kitware/CMake/releases/tag/v3.19.8         图1 下载x86软件包              2.上传并解压CMake软件包,如图 上传并解压所示。         图2 上传并解压                  图3 解压后的文件目录如图              3.执行解压后的二进制文件,结果显示不可执行,如图 执行解压后的二进制文件所示。         图4 执行解压后的二进制文件                ----结束↵2      扫描软件包并按迁移建议修改上传软件包执行扫描,目标操作系统选择的是CentOS 7.6。         图1 扫描               2. 查看扫描报告,如图 扫描报告所示。          图2 扫描报告                3. 下载报告中依赖文件的链接,并解压,如图 下载并解压依赖文件所示。          图3 下载并解压依赖文件                    解压后如图 解压后的文件所示。          图4 解压后的文件                 4. 验证该二进制文件。          图5 验证1                    图6 验证2                    图7 验证3                    图8 验证4                ----结束↵
  • [加速器] 鲲鹏BoostKit加速库对基础软件深度性能优化,助力客户极致性能提升
    1.1      背景与价值业务的持续增长往往带来对于应用系统性能要求的提升,业务应用如何基于既有软硬件资源,充分发挥计算算力,提升并发性能,处理更多事务,是开发者面临的最大挑战。鲲鹏加速库对软件基础库做深度性能优化,通过硬件加速和软件加速,给客户带来更高的性价比。1.2      鲲鹏BoostKit加速库全景鲲鹏应用使能套件BoostKit,释放倍级性能优势,提供以下八大场景化应用使能套件:大数据、分布式存储、数据库、虚拟化、 ARM原生、Web/CDN、NFV和HPC。其中的基础加速软件包,华为提供基础性能优化、基础加速库和加速算法等基础加速软件包和文档,合作伙伴可以从从鲲鹏社区获取基础加速软件包,在鲲鹏创新中心指导下进行编译、部署和性能优化。鲲鹏BoostKit加速库共支持3种加速库,分别是:ARM支持的加速库:开源社区提供的ARM支持的加速库,已在鲲鹏平台完成验证;基于鲲鹏指令的加速库:基于鲲鹏指令深度优化的加速库,并向开源社区开放基于KAE(Kunpeng Accelerator Engine,鲲鹏加速引擎)的加速库:基于鲲鹏硬件加速引擎的加速库,提供领先业界的性能加速能力。包含ZIP(硬加速-压缩),HPRE(硬加速-非对称加解密),SEC(硬加速-对称加解密)。上述3种加速库,依据使用的场景不同,一共可以分为7类,分别是:系统库、压缩库、加解密库、媒体与信号库、数学库、存储库、网络库。这7类加速库,在架构上,对上适用于各种解决方案,比如说大数据、分布式存储、数据库、虚拟化、ARM生web、CDN等,从而支撑这些解决方案服务于政府、运营商、金融等其它领域,对下适配主流的操作系统,比如说openEuler、CentOS等等。鲲鹏BoostKit加速库充分发挥硬件的能力,或者内嵌于操作系统,以及单独作为一个函数库,去支撑解决方案,提升解决方案的性能,最终提升客户的性价比,即不需要去加购硬件的配置,就可以提升算力和性能。1.3      鲲鹏BoostKit加速库实现原理及应用1.3.1        KAE加速库原理及应用KAE使用流程如下:BMC子系统管理芯片加速子系统的License,当系统初始化时,BMC将License传递给BIOS系统。BIOS子系统解析License信息,并根据解析结果对芯片加速子系统进行使能控制,并上报加速器ACPI表到内核。上层应用基于OpenSSL/zlib加速库调用鲲鹏加速引擎,并通过寄存器操作调用芯片加速子系统。从用户层的角度来看,apps在使用KAE时,只需进行简单的配置。如果应用程序已经调用了openSSL或者已经调用了Zlib,无需修改代码,便可获取KAE带来的加速能力,反之,我们提供了Warpdrive层,其算法进行了抽象,提供了API,供上层软件调用。同时提供统一的用户态加速框架,帮助降低调用路径性能损耗。KAE的应用场景十分广泛,包括Web应用方案、分布式存储、大数据、虚拟化。Web应用方案,在互联网和金融行业应用非常普遍,使用KAE的RSA去硬加速Nginx。Nginx负责短连接接入的负载均衡,其性能会直接决定系统能否接入,同时并发处理多少个客户请求。如果硬加速能够对RSA的处理做性能优化,就可以同时处理更多请求。通过实测发现Nginx在使用RSA硬加速之后,并发数量可以提升一倍。相比业界友商的加速卡整体性能领先35%。在分布式存储混合读写7:3典型场景中,对带宽性能验证发现:块存储和对象存储都平均提升15%以上,最高能接近40%。大数据场景,用到了国密的加解密。在大数据的节点之间同步时,需把数据加密之后再传输,或者把数据压缩之后再存储。此前CPU占比较高,约占20%。使用KAE后,整个加密性能有所提升,且CPU损耗不超过5%。省下的CPU就可以去做很多业务上的事情,比如MapReduce的任务数增加,这样整个端到端的性能就会有所提升。虚拟化场景,目前KAE引擎完全按照SR-IOV的标准实现。在虚拟化和容器场景下,使用KAE,不会导致虚拟化调用带来的额外损耗,使用KAE的效果和物理机几乎等同。1.3.2     鲲鹏指令加速库原理及应用Avx2NeonAvx2Neon加速库是一款接口集合库,将AVX指令封装为独立的接口模块,并采用NEON SIMD指令替换对应的AVX指令,解决迁移问题。x86 Intrinsic函数总共6000多个,目前已完成其中5000+个的函数接口适配;Avx2Neon对常用的SSE/AVX Intrinsics函数进行深度优化适配,使用鲲鹏920指令以及ARM Intrinsics函数进行深度性能优化。目前,适配函数以头文件方式集成到Porting Advisor工具,通过工具识别迁移点,并提供一键式快速迁移HyperscanHyperscan是一款高性能的正则表达式匹配库,其中包含大量高效算法。它基于官网5.2.0版本优化,除了使用ARM Neon指令加速外,还使用数据预取、分支预测、结构重排及循环展开等多种优化手段实现加速。Hyperscan支持块模式(适用于对一段现成的完整数据进行匹配)和流模式(网络场景下跨报文匹配设计的特殊匹配模式)两种匹配模式,适用于入侵检测系统、DPI解决方案、互联网营销、网络威胁检测等诸多场景。HMPPHMPP是华为自研高性能媒体性能原语库,包括图像处理HMPPI函数库以及信号处理HMPPS函数库两个子库,适配多个操作系统,提供函数API,应用于运动跟踪、雷达信号、图像分析、视频增强、AI加速、医学扫描、通信工程等诸多行业。目前已经完成信号库HMPPS完成1000+个函数接口开发包括以下方面:基础向量运算:逻辑移位运算、向量转换、向量统计、采样函数、初始化函数信号变换:FFT、CZT、功率谱、希尔伯特滤波:卷积、FIR滤波、重采样、中值滤波、自相关窗口函数:Blackman、Hann、Kaiser、Hamming、Bartlett数学运算:算数运算、三角运算、幂、根、指数运算HW265HW265是用于编码符合高效率视频编码(HEVC/H.265)标准的影片的开源自由软件及函数库。其支持8bit高清低码,性能与码率相比开源有倍级提升;其中8bit标准版实现相比x86开源x265有1~5倍的性能优势;其中8bit高清低码版实现平均50%的码率节省。应用于热门影片、短视频场景、OTT点播、秀场、游戏、在线教育等诸多场景。经测试验证,视频质量与转码速度均得到了大幅的提升,对于直播的场景,单机并发路数也实现倍级提升。数学库数学库KML(Kunpeng Math Library),目前一共包含6个子库,包含处理实复数快速傅里叶变换的KML_FFT,处理稀疏线性代数运算的KML_SPBLAS,处理线性代数运算(向量-向量/向量-矩阵/矩阵-矩阵)的KML_BLAS,处理向量计算的KML_VML,处理基础计算的KML_MATH,处理线性代数运算(矩阵分解/方程组求解/特征值)的KML_LAPACK。数学库广泛应用于大数据分析算法(如KAL)、科学计算(如气象、制造、化学等行业)、AI推理(如卷积算子等)。数学库在保证数学运算精度的同事,利用NEON指令、循环展开、汇编代码重构等方法,大幅度提升计算性能,其中KML_FFT与开源FFTW进行对比的,性能提升约有1倍,和基础库LIBM进行比较,性能提升约有50%。GlibcGlibc是c运行库,是linux系统中最底层、最基础的软件库,其它任何运行库几乎都会依赖于glibc。华为通过使用Q寄存器代替X寄存器、读写内存对齐、结合鲲鹏CPU芯片分支预测特性、算法优化等诸多优化方案,对内存、字符串等接口进行了加速优化,充分利用鲲鹏Neon指令优势提高算力。已优化的接口已合入GNU社区,随glibc2.31主干版本发布,同时openEuler1.0已收编相比于主流OS集成的glibc2.17,接口平均性能提升35+%。1.4      总结鲲鹏BoostKit加速库通过鲲鹏社区,社区化运作,针对合作伙伴和开发者,均可以通过鲲鹏社区(https://www.hikunpeng.com/zh/developer/devkit/library)联系华为和获取相关加速库。同时,加速库项目在github(https://github.com/kunpengcompute/Kunpeng)上进行了部分库的开源,以供开发者合作交流。另外,在鲲鹏众智(https://www.hikunpeng.com/ecosystem/ecology_remit)项目中发布了高回报的开发任务,如果您对加速库感兴趣,可以与鲲鹏BoostKit加速库团队一起共创ARM高性能生态。
  • [技术干货] ACE 7.0.0移植指南 for openEuler 20.03【鲲鹏920(ARM64) 】
    ACE 7.0.0移植指南 for openEuler文档版本 V1.0发布日期 2022-3-11修订记录日期修订版本CR号修改章节修改描述2022-3-11V1.0初稿新建1简介ACE是一个开放源代码框架,为开发高性能,分布式实时和嵌入式系统提供了许多组件和模式。 ACE为套接字,解复用循环,线程,同步原语提供了强大而高效的抽象。官方链接:http://download.dre.vanderbilt.edu/类别:开放源代码框架语言:C/C++2环境类别子项版本获取地址(方法)硬件CPUKunpeng 920iBMC网络Ethernet-10GEiBMC存储SATA 4TiBMC内存240G 2933MHziBMCOSopenEuler20.03cat /etc/centos-releaseKernel4.19.90-2112cat /proc/version软件GCC7.3.0gcc -vGlibc2.2.8ldd --versionOpenJDK1.8.0_191参考下面安装说明cmake3.13.2cmake --version3依赖安装3.1安装OpenJDK1. 下载aarch64二进制包并安装curl -O https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u191-b12/OpenJDK8U-jdk_aarch64_linux_hotspot_8u191b12.tar.gz tar -zxf OpenJDK8U-jdk_aarch64_linux_hotspot_8u191b12.tar.gzmv jdk8u191-b12 /opt/tools/installed/2. 使用yum安装yum install java-1.8.0-openjdk*3. 配置java环境变量,在/etc/profile文件末尾处增加下面的代码:# 手动安装的JAVA_HOME设置export JAVA_HOME=/opt/tools/installed/jdk8u191-b12# yum安装的JAVA_HOME设置export JAVA_HOME=/usr/lib/jvm/java-1.8.0export JRE_HOME=$JAVA_HOME/jreexport CLASSPATH=$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATHexport PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH4. 运行下面命令,使修改的环境变量生效:source /etc/profile3.2安装GCC等依赖项sudo yum install -y snappy snappy-devel autoconf automake \libtool git gcc gcc-c++ make cmake openssl \openssl-devel ncurses-devel zlib zlib-devel \bzip2 bzip2-devel bzip2-libs readline readline-devel \bison zip unzip tar tcl3.3对gcc、g++和c++增加-fsigned-char选项1、对gcc增加-fsigned-char选项1)使用which gcc命令寻找gcc所在路径(一般位于/usr/bin/gcc)which gcc2)、更改gcc的名字(比如改成gcc-arm)mv /usr/bin/gcc /usr/bin/gcc-arm3)、进入gcc所在目录执行vim gcc,并填入如下内容保存:cd /usr/bin/vim gcc# 添加以下内容#! /bin/sh/usr/bin/gcc-arm -fsigned-char "$@"4)、执行chmod +x gcc给脚本添加执行权限chmod +x gcc2、对g++增加-fsigned-char选项1)使用which g++命令寻找g++所在路径(一般位于/usr/bin/g++)which g++2)、更改g++的名字(比如改成g++-arm)mv /usr/bin/g++ /usr/bin/g++-arm3)、进入g++所在目录执行vi g++,并填入如下内容保存:cd /usr/bin/vim g++# 填入以下内容#! /bin/sh/usr/bin/g++-arm -fsigned-char "$@"4)、执行chmod +x g++给脚本添加执行权限chmod +x g++3、对c++增加-fsigned-char选项1)使用which c++命令寻找g++所在路径(一般位于/usr/bin/c++)which c++2)、更改c++的名字(比如改成c++-arm)mv /usr/bin/c++ /usr/bin/c++-arm3)、进入c++所在目录执行vi c++,并填入如下内容保存:cd /usr/bin/vim c++# 填入以下内容#! /bin/sh/usr/bin/c++-arm -fsigned-char "$@"4)、执行chmod +x c++给脚本添加执行权限chmod +x c++4移植分析使用checkSo工具检查ACE 6.5.0对应x86的安装包或源码包是否有依赖x86的so文件,通过检查ACE 6.5.0的源码没有发现有依赖的x86架构的so文件。工具获取地址:http://3ms.huawei.com/km/groups/2351/blogs/details/10361837?l=en_US&moduleId=614273918841663488 5依赖库暂无6编译安装1、从ACE官网下载源码并解压wget http://download.dre.vanderbilt.edu/previous_versions/ACE-6.5.0.tar.gztar zxvf ACE-6.5.0.tar.gz2、进入解压目录mv ACE_wrappers /usr/local/cd /usr/local/ACE_wrappers/3、配置ACE环境变量cat >/etc/profile.d/ace.sh <<'EOF'export ACE_ROOT=/usr/local/ACE_wrappersexport LD_LIBRARY_PATH=$ACE_ROOT:$LD_LIBRARY_PATHEOFsource /etc/profile.d/ace.shcat /etc/profile.d/ace.sh4、ACE编译前配置echo '#include "ace/config-linux.h"' > $ACE_ROOT/ace/config.hecho 'include $(ACE_ROOT)/include/makeinclude/platform_linux.GNU' > $ACE_ROOT/include/makeinclude/platform_macros.GNUecho 'INSTALL_PREFIX = /usr/local' >> $ACE_ROOT/include/makeinclude/platform_macros.GNU#如果需要生成静态库,需要加入static_libs = 1(该命令根据实际需求选择是否执行)echo 'static_libs = 1' >> $ACE_ROOT/include/makeinclude/platform_macros.GNU5、进入$ACE_ROOT/ace目录进行ACE编译安装cd $ACE_ROOT/acemake && make install6、回到$ACE_ROOT目录进行ACE编译安装(可选)cd $ACE_ROOT/make –j64make install7验证1、编译验证使用checkSo工具检查编译后的/usr/local/ACE_wrappers/路径中是否不再含有依赖的x86架构的so文件,检查方法参考工具中的 《CheckSo使用说明.docx》,如果还有依赖的x86架构的so文件,则需要继续完成对应jar包的编译,直到无依赖的x86架构的so文件后,再次编译该组件并通过checkSo工具检查确认,编译后的组件包不再有依赖的x86架构的so文件则表明编译成功。工具获取地址:http://3ms.huawei.com/km/groups/2351/blogs/details/10361837?l=en_US&moduleId=6142739188416634882、功能验证暂无8参考信息1、http://download.dre.vanderbilt.edu/ 9FAQ1. Make install 报错/usr/bin/env: “perl\r”: 没有那个文件或目录make[1]: *** [GNUmakefile.ACE:529:install] 错误 127make[1]: 离开目录“/usr/local/ACE_wrappers/ace”make: *** [GNUmakefile:31:install] 错误 2解决:sed -i 's/\r$//' /usr/local/ACE_wrappers/MPC/prj_install.pl
  • [技术干货] 鲲鹏920(ARM64)MariaDB_10.3.8 移植_for_银河麒麟V10
     1介绍MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可。MariaDB的目的是完全兼容MySQL,包括API和命令行,使之能轻松成为MySQL的代替品,MariaDB还提供了许多更好的新特性。2环境要求2.1硬件要求项目说明服务器TaiShan 200 服务器(型号2280)CPU鲲鹏920处理器磁盘分区进行性能测试时,数据目录需使用单独硬盘,即一个系统盘,一个数据盘,至少两块硬盘。非性能测试时,直接在系统盘上建数据目录即可。具体硬盘数量根据实际需求配置。网络可访问外网  2.2操作系统项目版本银河麒麟V10 3     配置编译环境3.1       配置代理3.1.1      打开/etc/profile文件vim /etc/profile3.1.2      在/etc/profile文件中增加以下内容(根据实际情况填写)。export http_proxy="http://用户名:密码@代理IP:代理端口"export https_proxy=$http_proxyexport no_proxy=127.0.0.1,.huawei.com,localhost,local,.local3.1.3      使代理生效。source /etc/profile 3.2       配置yum源3.2.1      配置源文件#mv /etc/yum.repos.d/ /etc/yum.repos.d-bak#mkdir /etc/yum.repos.d#echo -e "[local]\nname=local\nbaseurl=file:///mnt\ngpgcheck=0\nenabled=1" > /etc/yum.repos.d/local.repo3.2.2      挂载OS镜像文件至“/mnt”目录下mount /root/CentOS-7-aarch64-Everything-1810.iso /mnt3.2.3      使yum源生效yum clean allyum makecacheyum list3.3       安装依赖包yum -y install readline-devel zlib-devel openssl* git perl* bison wget4     编译和安装4.1       下载MariaDB 10.3.8源码包cd /root/wget https://archive.mariadb.org//mariadb-10.3.8/source/mariadb-10.3.8.tar.gz --no-check-certificate4.2       解压源码包tar zxvf mariadb-10.3.8.tar.gz4.3       进入解压目录cd mariadb-10.3.84.4       执行编译cmake . -DCMAKE_INSTALL_PREFIX=/usr/local/mariadb -DMYSQL_DATADIR=/data/mariadb/data -DSYSCONFDIR=/etc -DWITHOUT_TOKUDB=1 -DWITH_INNOBASE_STORAGE_ENGINE=1 -DWITH_ARCHIVE_STORAGE_ENGINE=1 -DWITH_BLACKHOLE_STORAGE_ENGINE=1 -DWITH_READLINE=1 -DWITH_SSL=system -DWITH_ZLIB=system -DWITH_LOBWRAP=0 -DMYSQL_UNIX_ADDR=/data/mariadb/run/mysql.sock -DDEFAULT_CHARSET=utf8 -DDEFAULT_COLLATION=utf8_general_ci部分的路径参数说明如表1所示,请根据实际情况修改。表1 关键路径说明路径说明-DCMAKE_INSTALL_PREFIX软件安装路径-DMYSQL_DATADIR数据文件路径-DSYSCONFDIR配置文件路径-DMYSQL_UNIX_ADDRsock文件路径 4.5       执行安装make -j 64 && make install说明:-j 64参数充分利用多核CPU优势,加快编译速度。编译命令参数-j后数字为CPU核数,可用“cat /proc/cpuinfo | grep processor | wc -l”进行查看,此数值应小于等于CPU核数。4.6       查看安装目录ls /usr/local/mariadb/4.7       查看数据库版本/usr/local/mariadb/bin/mysqld --version
  • [分布式存储] 数据压紧 特性指南(openEuler 20.03)
    简介鲲鹏BoostKit分布式存储数据压紧算法(以下简称“数据压紧算法”)部署在开源分布式存储集群Ceph上,通过消除补零对齐操作带来的数据浪费问题,结合压紧封装、空间计数分配、粒度分流、聚合提交、批量回调等手段提升数据缩减率并提升系统整体IOPS,实现成本性能双收益。本文指导用户如何在Ceph上使能数据压紧算法。安全加固声明建议关注Ceph官网和Ceph官方Github上的漏洞信息,按照需求及时地进行漏洞修复。环境要求说明:由于数据压紧算法是华为自研闭源算法,算法仅支持在华为鲲鹏处理器上使用。硬件要求项目描述CPU型号鲲鹏920处理器服务器型号TaiShan 200服务器(型号2280)软件要求项目描述OSopenEuler 20.03 LTS SP1GCCGCC version 7.3.0CephCeph 14.2.8Ceph合入数据压紧功能1. 下载源码。源码下载链接:https://download.ceph.com/tarballs/2. 将源码包放入服务器“/home”目录下解压。cd /home tar zxvf ceph-14.2.8.tar.gz3. 合入数据压紧插件。获取patch放入“/home/ceph-14.2.8”目录。下载链接:https://github.com/kunpengcompute/ceph/releases/tag/datacompaction     2. 合入patch。cd /home/ceph-14.2.8 patch -p2 < ceph-14.2.8-compaction.patch4. 将数据压紧软件包下载至目录“/home/ceph-14.2.8”。方式一:华为企业网BoostKit-compaction_1.0.0.zip方式二:华为运营商网BoostKit-compaction_1.0.0.zip5.  获取软件校验工具。下载地址:https://support.huawei.com/enterprise/zh/tool/pgp-verify-TL10000000546. 参见5中下载的《OpenPGP签名验证指南》进行软件包完整性检查。7. 解压安装包。cd /home/ceph-14.2.8/ unzip BoostKit-compaction_1.0.0.zip生成boostKit-compaction-1.0.0-1.aarch64.rpm文件。8. 安装RPM包。rpm -ivh boostKit-compaction-1.0.0-1.aarch64.rpm
  • [分布式存储] 压缩算法特性指南
    简介鲲鹏BoostKit分布式存储压缩算法(以下简称“压缩算法”)是华为自研无损压缩算法。相对于开源压缩算法,压缩算法压缩率更高,性能更好。与主流开源压缩算法相比,压缩率可提升25%,带宽性能提升10%。安全加固声明建议关注Ceph官网和Ceph官方Github上的漏洞信息,按照需求及时地进行漏洞修复。环境要求由于压缩算法是华为自研闭源算法,算法仅支持华为鲲鹏处理器使用。硬件要求项目描述CPU型号华为鲲鹏920处理器服务器型号TaiShan 200服务器(型号2280)TaiShan 200服务器(型号5280)软件要求项目描述OSCentOS Linux release 7.6.1810openEuler 20.03 LTS SP1ZSTDZSTD-1.4.5GCCgcc version 4.8.5 或 gcc version 7.3.0编译压缩算法1. 下载压缩算法安装包:下载压缩算法安装包_鲲鹏BoostKit分布式存储使能套件_特性指南_压缩算法 特性指南_编译压缩算法_华为云 (huaweicloud.com)2.  获取编译依赖:获取编译依赖_鲲鹏BoostKit分布式存储使能套件_特性指南_压缩算法 特性指南_编译压缩算法_华为云 (huaweicloud.com)3.  编译动态库:   编译动态库_鲲鹏BoostKit分布式存储使能套件_特性指南_压缩算法 特性指南_编译压缩算法_华为云 (huaweicloud.com)4.  生成压缩算法RPM包: 生成压缩算法RPM包_鲲鹏BoostKit分布式存储使能套件_特性指南_压缩算法 特性指南_编译压缩算法_华为云 (huaweicloud.com)编译部署Ceph1. Ceph源码合入压缩算法特性: Ceph源码合入压缩算法插件_鲲鹏BoostKit分布式存储使能套件_特性指南_压缩算法 特性指南_编译部署Ceph_华为云 (huaweicloud.com)2. 编译Ceph并验证: 编译Ceph并验证_鲲鹏BoostKit分布式存储使能套件_特性指南_压缩算法 特性指南_编译部署Ceph_华为云 (huaweicloud.com)3. 生成Ceph RPM包:  生成Ceph RPM包_鲲鹏BoostKit分布式存储使能套件_特性指南_压缩算法 特性指南_编译部署Ceph_华为云 (huaweicloud.com)4. 部署Ceph集群:  部署Ceph集群_鲲鹏BoostKit分布式存储使能套件_特性指南_压缩算法 特性指南_编译部署Ceph_华为云 (huaweicloud.com)使能压缩算法1. 块存储使能:  块存储使能_鲲鹏BoostKit分布式存储使能套件_特性指南_压缩算法 特性指南_使能压缩算法_华为云 (huaweicloud.com)2. 对象存储使能:  对象存储使能_鲲鹏BoostKit分布式存储使能套件_特性指南_压缩算法 特性指南_使能压缩算法_华为云 (huaweicloud.com)验证压缩算法1. 块存储压缩验证:  块存储压缩验证_鲲鹏BoostKit分布式存储使能套件_特性指南_压缩算法 特性指南_验证压缩算法_华为云 (huaweicloud.com)2. 对象存储压缩验证:  对象存储压缩验证_鲲鹏BoostKit分布式存储使能套件_特性指南_压缩算法 特性指南_验证压缩算法_华为云 (huaweicloud.com)补丁升级获取补丁文件。方式一:华为企业网站下载glz-1.0.0-centos.aarch64-patch.zip方式二:华为运营商网站下载glz-1.0.0-centos.aarch64-patch.zip解压补丁文件。unzip glz-1.0.0-centos.aarch64-patch.zip 按照编译动态库重新编译生成动态库。替换动态库。mv libglz.so /usr/lib64/libglz.so
  • [基础服务] 【ECS服务器】鲲鹏和x86两种ECS中,单vCPU的处理能力是一样的吗?
    比如一个软件在x86架构下需要50个vCPU能正常运行,那在鲲鹏架构下,大概需要多少vCPU才能正常运行呢?
  • [分布式存储] 智能写Cache 特性指南(openEuler 20.03)
    介绍智能写Cache(Smart Write Cache)包含Bcache内核补丁以及相关配套的工具两部分。智能写Cache通过IO直通、Bcache QoS策略控制、Writeback策略控制以及GC策略控制来提升Bcache性能,最终达到提升Ceph集群性能的目的。安全加固声明建议关注Ceph官网和Ceph官方Github上的漏洞信息,按照需求及时地进行漏洞修复。兼容规格硬件兼容列表兼容项目兼容性规格描述CPU型号华为鲲鹏916处理器华为鲲鹏920处理器服务器型号TaiShan 100系列服务器TaiShan 200服务器(型号2280)TaiShan 200服务器(型号5280)软件兼容列表软件名称软件版本OSopenEuler-20.03-LTS-SP1内核版本4.19.90-2012.4.0.0053.oe1CephCeph 14.2.x适用场景智能写Cache是在使用Bcache设备做为Ceph OSD的存储场景下,对其中的Ceph IO流程进行了优化,仅对采用BlueStore存储引擎的OSD有效,考虑到实际应用中Ceph集群中OSD的增加与修改操作,工具需要获取集群内的OSD信息,因此需要保证OSD部署路径使用官方默认路径“/var/lib/ceph/osd”,如果采用其他路径则不会进行优化。说明:Ceph存储场景介绍如下:均衡型:集群采用SSD盘和HDD盘混合部署OSD,使用SSD盘存储OSD的元数据(DB)、日志数据(WAL),使用HDD盘存储真实数据(Data)。全闪存:集群采用全SSD盘部署OSD,OSD的Data、DB、WAL一起存储在SSD盘中。冷存储:集群采用全HDD盘部署OSD,OSD的Data、DB、WAL一起存储在HDD盘中。Bcache:将SSD与HDD绑定为一个Bcache分区,SSD做为HDD的缓存,集群采用Bcache分区部署OSD,OSD的Data存储在Bcache分区中,DB和WAL存放在单独的NVMe分区。目前智能写Cache只对Bcache场景有效。openEuler-20.03-LTS-SP1的内核默认为64K PAGESIZE,智能写Cache工具需要运行在4K PAGESIZE环境下。为方便使用,本文提供两种方式供选择:环境为64K PAGESIZE,需要重新编译替换整个内核,可以选择内核与bcache同时编译安装的方式,请参见“内核编译与安装”。环境已为4K PAGESIZE(通过"getconf PAGESIZE"查询),仅需要安装替换bcache.ko时,可以选择单独编译bcache.ko安装的方式,请参见“Bcache编译与安装”使用指导1. 安装Bcache    1)内核编译与安装:https://support.huaweicloud.com/fg-kunpengsdss/kunpengswceuler_20_0006.html    2)Bcache编译与安装:https://support.huaweicloud.com/fg-kunpengsdss/kunpengswceuler_20_0007.html2. 安装智能写cache工具     https://support.huaweicloud.com/fg-kunpengsdss/kunpengswceuler_20_0008.html3. 安装Bcache-tools工具     https://support.huaweicloud.com/fg-kunpengsdss/kunpengswceuler_20_0009.html4. Ceph使能智能写cache     https://support.huaweicloud.com/fg-kunpengsdss/kunpengswceuler_20_0010.html
  • [技术干货] 鲲鹏920(ARM64)Influxdb_1.8.2移植_for_centos7.6
    简介InfluxDB是一个开源的时序数据库,使用GO语言开发,特别适合用于处理和分析资源监控数据这种时序相关数据。而InfluxDB自带的各种特殊函数如求标准差,随机取样数据,统计数据变化比等,使数据统计和实时分析变得十分方便。安装依赖库yum install -y wget vim openssl openssl-devel curl curl-devel expat expat-devel gcc.aarch64 gcc-c++.aarch64 gcc-gfortran.aarch64 libgcc.4 tcl gettext #能访问互联网,或是有epel源,可直接yum安装go、git。yum install -y epel-release yum install -y golanggo version #centos7.6默认版本1.13git --version  #centos7.6默认版本1.8.3.1安装gitwget https://mirrors.edge.kernel.org/pub/software/scm/git/git-2.28.0.tar.gztar -zxvf git-2.28.0.tar.gz -C /opt/ && cd /opt/git-2.28.0/编译:./configuremake prefix=/usr/local all安装到/usr/local/bin :make prefix=/usr/local install验证git版本:ln -s /usr/local/bin/git /usr/bin/git --version 安装gowget https://studygolang.com/dl/golang/go1.14.6.linux-arm64.tar.gz tar -zxvf go1.14.6.linux-arm64.tar.gz -C /usr/local/ln -sf /usr/local/go/bin/{go,gofmt} /usr/bin/go version安装influxdb可以将dep通俗的理解为go语言的依赖管理工具,类似于python中的pip,java中的Maven以及node.js中的npm工具通过以下命令来安装depgo get github.com/golang/dep/cmd/depgo get github.com/influxdata/influxdb#若出现类似下图错误,由网络问题导致cd /root/go/src/mkdir -p golang.org/x/cd golang.org/x/git clone https://github.com/golang/xerrors.git###########################################################################cd /root/go/src/github.com/influxdata/influxdbgit checkout 1.8git pull vim build.py #将521、522行注释或删除python build.py如果您使用的 Go 版本是 1.13 及以上 (推荐):go env -w GO111MODULE=ongo env -w GOPROXY=https://goproxy.io,direct如果您使用的 Go 版本是 1.12 及以下:# 启用 Go Modules 功能export GO111MODULE=on# 配置 GOPROXY 环境变量export GOPROXY=https://goproxy.io############################################################安装成功后,指令存放在./build目录下 
  • [优秀实践] 鲲鹏安全库远程证明项目实践心得
      很荣幸地能参与到华为鲲鹏众智计划项目中,本次参与的项目主要是实现在通用计算场景下的远程证明,包括对基础的主机完整性、可信容器完整性、以及PCIE设备系统镜像完整性的远程证明支持。在本次项目中,我从初期架构设计到中期模块开发再到后期测试以及文档编写等环节都完整地参与了进来,感受到了完整的开发流程,极大地提高了我的开发能力,受益匪浅。  在项目初期,先是由华为方面的老师介绍了项目的总体方案与实现分析,并根据服务器主场景把任务划分为story,给团队的每个成员分配大致的模块和具体的story作为首要任务,让我们很快的明确了自己要学习努力的方向。我负责的是远程证明客户端的开发,向上要和服务器端进行通信,处理服务器端传来的各种请求;向下要调用tpm进行各种操作来完成远程证明的流程。  在项目开发中,我学到了很多。首先是通过具体的开发实现,我对可信计算远程证明的相关内容理解的更深了,很多书上一笔带过的细小内容,要了自己要实现的时候都是非常重要的。比如在复现物理tpm的Endorsement Key时,其中有一个EKParams,我把TCG规范EK部分的文档翻了好多遍,问了老师很多问题,把里面每个字段的功能含义都了解之后才成功复现出来。其次,在这个项目的开发过程中我养好了良好的开发习惯。老师们不厌其烦地一次次评阅我们提交的代码,指出我们的问题并帮助我们改正。比如某些函数功能太多复杂,嵌套过深;某些注释写的不够简洁、易懂;某些错误的处理方式不好等。此外,每周的大小组会提高了我的团队交流合作能力,大的方向上需要逐步实现自己负责的模块,小的方向上需要和其他模块的负责人员沟通来帮助实现他们的模块,不断地交流让我对项目整体有了更深的认识。  最后,非常感谢华为鲲鹏众智平台给我们提供了项目实践的机会,让我们能实际参与一个优秀的大公司项目的完整开发流程。希望我以后能有更多机会参与到类似的项目中,学到更多的知识,也为华为的软件生态建设贡献自己的一份薄力。武汉大学 - 张立强研究团队 - 贾韵昊指导老师:张立强
  • [优秀实践] 鲲鹏众智-虚拟化软件适配1期项目-calico 实践分享
     非常有幸能够参加华为众智开源使能虚拟化软件适配1期项目,在本次项目中我得到了大幅的提示,对于一些虚拟化组件有了更加深刻的认识,在本次项目中,我负责对calico组件进行验证  在这个云的时代,Kubernetes是大家十分熟悉的一个开源项目,在k8s中网络组件是十分重要的,calico作为众多组件之一,calico有着易扩展,资源使用更少等特点。 下面是我的项目经验的分享docker Driver问题原因: 是由于docker的Cgroup Driver和kubelet的Cgroup Driver不一致导致的,此处选择修改docker的和kubelet一致问题查看: docker info | grep Cgroup         Cgroup Driver: cgroupfs解决办法: 编辑文件/usr/lib/systemd/system/docker.service修改ExecStart=/usr/bin/dockerd --exec-opt native.cgroupdriver=systemdsystemctl daemon-reloadsystemctl restart dockerdocker info | grep CgroupCgroup Driver: systemd  十分荣幸能够加入到这个项目中,为国产生态系统奉献出自己的一份力量,通过本次项目,我对于k8s有了更深刻的了解,极大的提高了自己的能力。视同智能科技有限公司-华为鲲鹏众智项目团队-杨广业指导老师:徐志威
  • [优秀实践] 鲲鹏众智-虚拟化软件适配1期项目-qemu 实践分享
      很荣幸参加鲲鹏众智的虚拟化适配1期项目,项目主要是在TaiShan200 2280服务器上验证虚拟化软件的兼容性,项目中我主要负责Qume安装以及基本功能验证确保对应版本的软件组件功能正常。  项目刚开始的时候,对于qemu这一个软件我并不是那么的熟悉,我对于qemu的认知停留qemu在是kvm虚拟机的一个组件,qemu是什么?qemu具体的作用是什么?这些我都不了解。我开始去官方网站和一些论坛上仔细了解Qemu,在项目初期的时候进行的不是那么顺利,因为网络上单独使用Qemu的数量并不是很多,有关Qemu的信息也不是特别多,只能够在官网上了解一下功能的实现,但是官方网站的示例都是x86的,只能根据官方示例而不断尝试。   下面是在项目实施过程中的一些经验分享编译安装 #在Arm上编译安装Qemu先安装edk2-aarch64.noarch#对于Arm系统运行Qemu需要运用QEMU_EFI.fd 进行启动#关于Qemu 的VNC登陆在编译安装之前需要安装gnutls-devel #Qemu VNC 的秘钥生成certtool --generate-privkey > ca-key.pem================================cat > ca.info <<EOFcn = Name of your organizationcacert_signing_key EOF================================certtool --generate-self-signed \           --load-privkey ca-key.pem \           --template ca.info \           --outfile ca-cert.pem================================cat > server.info <<EOForganization = Name  of your organizationcn = hostNNN.foo.example.comdns_name = hostNNNdns_name = hostNNN.foo.example.comip_address = 10.0.1.87ip_address = 192.8.0.92ip_address = 2620:0:cafe::87ip_address = 2001:24::92tls_www_serverencryption_keysigning_keyEOF=================================certtool --generate-privkey > server-key.pem=================================certtool --generate-certificate \           --load-ca-certificate ca-cert.pem \           --load-ca-privkey ca-key.pem \           --load-privkey server-key.pem \           --template server.info \           --outfile server-cert.pem=================================cat > client.info <<EOFcountry = GBstate = Londonlocality = City Of Londonorganization = Name of your organizationcn = hostNNN.foo.example.comtls_www_clientencryption_keysigning_keyEOF=================================certtool --generate-privkey > client-key.pem=================================certtool --generate-certificate \           --load-ca-certificate ca-cert.pem \           --load-ca-privkey ca-key.pem \           --load-privkey client-key.pem \           --template client.info \           --outfile client-cert.pem===================================  近些年来,国家计算机行业在飞速的发展,但是随着发展,国家之间的竞争也开始渐渐激烈,如今这种环境下,发展国产处理器以及arm生态系统是十分重要的,我十分荣幸能够加入到这个项目中,为本国生态系统贡献自己的一份力量。视同智能科技有限公司-华为鲲鹏众智项目团队-朱时锦指导老师:徐志威
  • [优秀实践] HPC软件SWAN、CDO、eccodes等7款软件迁移openEuler平台实践心得
    本次迁移实践的目的,是将气象解决方案迁移到openEuler+鲲鹏的计算平台,充分发挥openEuler+鲲鹏在HPC场景的性能优势。项目中的软件主要由c/c++、Fortran语言编写。在移植过程中有源码编译,需要掌握编码语言,能分析并处理出现的源码问题。掌握clang和gcc编译相关知识,处理编译问题。还需掌握HPC相关技能,如MPI的应用。要求编译器为毕昇编译器,MPI为HyperMPI。移植过程中部分软件指定MPI编译源码;测试过程部分HPC软件需要进行多节点布置测试也依赖于MPI。要求HPC软件是源码安装。依赖包安装首选源码安装,其次yum安装。安装需要分析部署,考虑HPC软件依赖包的所需版本,达到有效兼容,合理匹配,实现优性能安装。由客户指定的算例得到测试结果。根据记录数据,分析制作性能对比图,直观了解软件移植的性能差异。软件测试的方式分为单节点和多节点方式,根据实际情况选择。最终实现CentOS和openEuler两个平台的测试性能对比,达到客户的要求。迁移目标:气象HPC组件运行在openEuler+Kunpeng平台。性能调优,保证HPC组件迁移至鲲鹏后的性能不低于X86平台的90%;主要工作:使用社区最新发布的毕昇编译器进行编译;MPI软件使用HyperMPI;使用IMB、IOR、Stream工具进行性能测试,并于CentOS平台性能对比。性能调优:OS调优:页大小设置:关闭透明大页内存THP,内存页64K。资源限制:ulimits取消解除硬资源和软资源的限制(CPU时间、最大线程数等)。IO优化:开启pageCache、预读,减少磁盘IO操作。基础软件调优:编译器设置:使用GCC最新版本,配置-march(针对鲲鹏优化)、-Ofast参数。MPI调优:配置MPI绑核、配置rank减少跨节点通信。线程核绑定:配置线程与核绑定HPC-WAN调优实现鲲鹏平台性能超过X86调优结果:气象HPC组件运行在openEuler+Kunpeng平台正常运行,整体性能超过通用平台,超过迁移性能目标。 
  • [优秀实践] 基于KML_SPBLAS的JAVA语言适配项目经验分享
    # 基于KML_SPBLAS的JAVA语言适配 ### 项目介绍 本项目的主要任务是为鲲鹏处理器的高性能稀疏线性代数库函数提供Java平台适配,包括向量与矩阵,矩阵与矩阵等共32个函数。基本原理是利用Java语言的JNI调用C语言的高性能库函数接口。 下面详细介绍我们团队在此次项目中的经验总结。 ### JNI简述 **JNI**是Java Native Interface的缩写,为Java程序提供与本地程序交互的能力。使用JNI技术,能够使得Java程序充分利用本地代码的优势,如高性能,不必重复造轮子等,在生产中,有着诸多实用价值。 ![JNI原理图](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/7/1646617085507647995.png) ### JNI工作流程 JNI的典型使用场景是:Java程序调用C,C++代码编译而成的动态库文件。动态库文件在Windows下是.dll文件,在Linux下为.so文件。其主要工作流程如图所示: ![JNI工作流程图](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/7/1646617122292724177.png) 1. 编写.java源代码,其中用native关键字标明需要本地实现的函数。 2. 使用命令 `javac -h 输出位置> 源代码路径>` 编译出.h头文件。 3. 编写.cpp源代码实现.h文件中声明的native函数。 4. 编译.h头文件和.cpp源文件生成.dll动态库,并移动到.java源代码中指定的位置。 5. 使用命令 `javac 源代码路径>` 将.java源代码编译成.class字节码。 6. 使用命令 `java 类名>` 执行类名.class文件,调用.dll库文件得到输出。 ### Hello, world! 这里实现一个简单的Windows版本的demo,带读者来熟悉上述流程。 1. 编写Hello.java源代码 ```java public class Hello { // native 关键字声明native函数 native void sayHelloToC(); // 加载 java2c.dll库文件 static { System.loadLibrary("java2c");} public static void main(String []args){ Hello hello = new Hello(); hello.sayHelloToC(); } } ``` 2. 在Hello.java所在目录,打开cmd命令行,编译出Hello.h头文件。(也一并编译出了Hello.class文件) ```sh javac -encoding utf-8 -h . Hello.java ``` utf-8防止中文注释乱码,. 表示输出到当前路径下。 3. 为了简化较长的.dll编译命令,此处我们借助 Dev-C++ 开发工具来完成C++代码的编写和编译。 1. 打开Dev-C++,新建dll项目,将自动生成dll.h和dllmain.cpp两个文件。 2. 将dll.h的内容替换为Hello.h。 ```c++ /* DO NOT EDIT THIS FILE - it is machine generated */ #include /* Header for class Hello */ #ifndef _Included_Hello #define _Included_Hello #ifdef __cplusplus extern "C" { #endif /* * Class: Hello * Method: sayHelloToC * Signature: ()V */ JNIEXPORT void JNICALL Java_Hello_sayHelloToC (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif ``` 3. 清空dllmain.cpp中的内容,修改为如下 ```c++ #include"dll.h" #include // 实现dll.h中声明的函数 JNIEXPORT void JNICALL Java_Hello_sayHelloToC (JNIEnv * env, jobject obj){ printf("Hello, C! I am Java."); } ``` 4. 编译生成.dll库文件。 dll.h的第一行,引入了jni.h头文件。在java安装目录下的include文件夹,找到**jni.h**文件和**jni_md.h**。将它们复制到dev-c++项目的 工具->编译选项->目录->C++包含文件 中的任一目录下。 ![dev截图](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/7/1646617206795769913.png) 点击编译,生成hello_c++.dll文件(hello_c++为项目名),将其重命名为java2c.dll(与1中的java源代码保持一致),移动到Hello.java所在的文件夹。 5. 编译Hello.java生成Hello.class字节码,其实在第2步已经顺带完成。 ```sh javac -encoding utf-8 Hello.java ``` 6. 在Hello.class目录下,打开cmd命令行,执行字节码程序。 ```sh java Hello ``` ![运行命令行](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/7/1646617252851244387.png) 以上实现一个简单的demo,完成Java程序调用C++编写的动态库的目标。通过JNI技术还可以实现Java程序和C/C++程序间的数据传递,下面将一一陈述。 ### 基本数据 | Java类型 | JNI类型 | 描述 | | :------- | :------- | :--------------- | | boolean | jboolean | unsigned 8 bits | | byte | jbyte | signed 8 bits | | char | jchar | unsigned 16 bits | | short | jshort | signed 16 bits | | int | jint | signed 32 bits | | long | jlong | signed 64 bits | | float | jfloat | 32 bits | | double | jdouble | 64 bits | | void | void | void | JNI的基本数据类型与Java类型的对照表如上,下面演示传递基本类型的数据。 Hello.java中添加: ```java native double average(int x, int y); ``` Hello.h中新增: ```c++ /* * Class: Hello * Method: average * Signature: (II)D */ JNIEXPORT jdouble JNICALL Java_Hello_average (JNIEnv *, jobject, jint, jint); ``` java编译程序自动添加了三行注释,Class表示类名,Method表示方法名,Signature是java的函数签名,告诉我们函数的参数类型和返回类型。参数是两个Interger,返回是Double。 函数体代码中,函数返回值为jdouble与java中的double对映,函数名为程序自动生成的**Java _类名 _方法名**形式,JNIEnv参数为jni环境,jobject为native函数所在的java对象,这两个是jni自带的。后面两个jint参数对应原本java方法的int参数。 在dllmain.cpp中实现average的逻辑: ```c++ JNIEXPORT jdouble JNICALL Java_Hello_average (JNIEnv * env, jobject obj, jint x, jint y){ return jdouble(x + y) / 2; } ``` 执行输出: ```java System.out.println(hello.average(1, 2)); // 1.5 ``` ### 字符串 JNI的字符串处理函数丰富全面,此处演示传递字符串的简单例子,并以此引出JNI处理复杂数据类型时的一般流程。更多API文件见参考链接的官方文档。 Hello.java中添加: ```java native String sendMessage(String msg); ``` Hello.h中生成: ```c++ /* * Class: Hello * Method: sendMessage * Signature: (Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_Hello_sendMessage (JNIEnv *, jobject, jstring); ``` dllmain.cpp中实现: ```c++ JNIEXPORT jstring JNICALL Java_Hello_sendMessage (JNIEnv * env, jobject obj, jstring msg){ // 1.convert jstring to cstring const char* cMsg = env->GetStringUTFChars(msg, NULL); if(NULL == cMsg) return NULL; // 2.use cstring printf("Java: %s\n", cMsg); // 3.release resources env->ReleaseStringUTFChars(msg, cMsg); // 4.return const char* cMsg2 = "Good afternoon! Miss.Java."; return env->NewStringUTF(cMsg2); } ``` 注意:JNI中需要手动显式地释放资源,否则会造成内存泄漏。 执行输出: ```java String msg = "Good morning! Mr.C++."; System.out.println("C++: " + hello.sendMessage(msg)); // Java: Good morning! Mr.C++. // C++: Good afternoon! Miss.Java. ``` ### 对象 JNI同样可以传递对象,也就是说,JNI让C/C++代码能够访问Java类中的成员变量和方法。 从这里开始,我们使用Maven来管理我们的代码。 新建maven项目,其目录结构如下: ![目录结构](https://bbs-img.huaweicloud.com/data/forums/attachment/forum/20223/7/1646617294351902606.png) Hello.java的代码如下 ```java package org.example; public class Hello { static { System.loadLibrary("java2c"); } private int num = 2021; private void printNum(){ System.out.println("In Java, num is " + num); } // 演示访问成员变量和方法 native void jniMethod(); public static void main(String []args){ Hello hello = new Hello(); hello.jniMethod(); } } ``` 此处引入了java包,且Hello中导入了Color类,所以如果直接在Hello.java同级文件夹下调用**javac**命令,会报找不到符号的错误,应在所有源文件的根目录,即maven项目的java文件夹下,调用**javac**命令。这样编译器能将包名和路径对应起来。 进入src\main\java路径,运行: ```sh javac -encoding utf-8 -h . ./org/example/Hello.java ``` 如果源文件还引入了其他位置的包,如test文件夹下的源文件引入了main文件夹下的包,可使用`javac -cp 依赖路径>`告知java编译器依赖包的位置。更多javac选项,可使用`javac -help`自行查看。 Hello.h中生成: ```c++ /* * Class: org_example_Hello * Method: jniMethod * Signature: ()V */ JNIEXPORT void JNICALL Java_org_example_Hello_jniMethod (JNIEnv *, jobject); ``` dllmain.h中实现定义的函数: ```c++ JNIEXPORT void JNICALL Java_org_example_Hello_jniMethod (JNIEnv* env, jobject obj){ jclass cls = env->GetObjectClass(obj); // fieldID is certain for a class jfieldID numField = env->GetFieldID(cls, "num", "I"); // get number jint num = env->GetIntField(obj, numField); printf("In C++, num is %d\n", num); // change number env->SetIntField(obj, numField, 2035); // call method jmethodID printNumField = env->GetMethodID(cls, "printNum", "()V"); env->CallVoidMethod(obj, printNumField); return; } ``` 执行编译,在maven项目中编译执行的路径不再是源文件所在的路径。为简单起见,我们将生成的dll文件放到系统环境变量中,以便java虚拟机能够找到。执行输出得到: ```c++ public static void main(String []args){ Hello hello = new Hello(); hello.jniMethod(); } // In Java, num is 2035 // In C++, num is 2021 ``` 通过JNI,获取对象的成员变量或调用对象的主要过程如下: 1. `GetObjectClass`通过jobject获得jclass,或者`FindClass`通过类名直接获得jclass 2. 通过jclass获得jfieldID获得jmethodID。 3. 使用jfieldID获取成员变量的值或使用jmethodID调用对象的方法。 dllmain.cpp中的"I"、"()V"是java的签名字符串,可以在终端通过`javap`命令获取。 ### 数组 jni也可以传递基本类型的数组和对象数组,此处通过向量加法来演示此功能。 Hello.java中新增: ```java native void vectorAdd(int[] a, int[] b, int[] c); public static void main(String []args){ Hello hello = new Hello(); int []a = {1, 2, 3}; int []b = {4, 5, 6}; int []c = new int[3]; hello.vectorAdd(a, b, c); for(int i:c){ System.out.print(i + " "); } ``` `javac -h`重新编译后,Hello.h中生成: ```c++ /* * Class: org_example_Hello * Method: vectorAdd * Signature: ([I[I[I)V */ JNIEXPORT void JNICALL Java_org_example_Hello_vectorAdd (JNIEnv *, jobject, jintArray, jintArray, jintArray); ``` 在dllmain.h中实现上述函数: ```c++ JNIEXPORT void JNICALL Java_org_example_Hello_vectorAdd (JNIEnv *env, jobject obj, jintArray a, jintArray b, jintArray c){ // 1.convert JNI jintArray to C jint[] jint *cA = env->GetIntArrayElements(a, NULL); jint *cB = env->GetIntArrayElements(b, NULL); jint *cC = env->GetIntArrayElements(c, NULL); jint len = env->GetArrayLength(a); // 2.use array for(jint i=0; i+ cB[i]; } // 3.release resources env->ReleaseIntArrayElements(a, cA, JNI_ABORT); env->ReleaseIntArrayElements(b, cB, JNI_ABORT); env->ReleaseIntArrayElements(c, cC, 0); return; } ``` 函数依旧分为:转化数据、使用数据、释放资源三步。 Release函数第三个参数为mode,有三个备选值如下: | mode | 行为 | | :--------- | :-------------------------------------------------------- | | 0 | copy back the content and free the elems buffer | | JNI_COMMIT | copy back the content but do not free the elems buffer | | JNI_ABORT | free the buffer without copying back the possible changes | 编译后执行得输出如下: ``` 5 7 9 ``` 对象数组与基本类型数组的方法相似,但是没有**Get``ArrayElements**对数组元素进行批量转化,究其原因,Java对象不能直接转化为C/C++的对象。 使用如下两个函数,可以操作基本数据类型数组的直接指针,极大的加快程序运行的效率。但同时,我们要保证在调用ReleasePrimitiveArrayCritical函数之前,不能进行任何可能导致线程阻塞的操作。 void * **GetPrimitiveArrayCritical**(JNIEnv *env, jarray array, jboolean *isCopy); void **ReleasePrimitiveArrayCritical**(JNIEnv *env, jarray array, void *carray, jint mode); ### 工程经验 #### c语言宏定义 观察`javac -h`生成的函数声明,我们会发现都是如下结构: ``` Java_包名_方法名 JNIEXPORT void JNICALL Java_org_example_Hello_jniMethod(...) JNIEXPORT void JNICALL Java_org_example_Hello_vectorAdd(...) ``` 当程序越来越复杂,我们调整Java的包结构,每一个地方都要修改。可以使用C++的宏替换来减少这种冗余如下: ```c++ #define FULL_FUNC_NAME(SHORT_NAME) Java_org_example_Hello_##SHORT_NAME JNIEXPORT void JNICALL FULL_FUNC_NAME(jniMethod)(...) JNIEXPORT void JNICALL FULL_FUNC_NAME(vectorAdd)(...) ``` #### 将dll动态库打入jar包 首先我们要明白Java加载动态库的方式: 1. **System.load** System.load加载绝对路径下的库文件,如: ```java System.load("D:\\workplace\\java2c.dll"); ``` 2. **System.loadLibrary** System.loadLibrary加载相对路径下的库文件,参数为库文件名,不包含库文件的扩展名,如: ```java System.loadLibrary("java2c"); ``` 这里java2c.dll必须在**java.library.path**这一jvm变量指向的路径中。 可以通过如下方法来获得该变量的值: ```java System.getProperty("java.library.path"); ``` 默认情况下,在Windows平台下,该值包含如下位置: 1)和jre相关的一些目录 2)程序当前目录 3)Windows目录 4)系统目录(system32) 5)系统环境变量path指定目录 上述两个函数都是以路径作为参数的,但是jar包中的文件没有路径,只能以文件流的形式获取。为了能将动态库文件打入jar包,并且能够顺利调用,我们的策略是将jar包中的动态库写入系统临时目录下,再调用System.load载入,参考代码如下: ```java static { // copy .so from jar to syetem tmp dir String libName = "java2c.dll"; String nativeTempDir = System.getProperty("java.io.tmpdir"); File extractedLibFile = new File(nativeTempDir + File.separator + libName); InputStream in = null; BufferedInputStream reader = null; FileOutputStream writer = null; if(!extractedLibFile.exists()){ try{ in = Level2.class.getClassLoader().getResourceAsStream(libName); reader = new BufferedInputStream(in); writer = new FileOutputStream(extractedLibFile); byte[] buffer = new byte[1024]; while(reader.read(buffer) > 0){ writer.write(buffer); } }catch(IOException e){ e.printStackTrace(); }finally { if (in != null){ try { in.close(); } catch (IOException e) { e.printStackTrace(); } } if (writer != null){ try { writer.close(); } catch (IOException e) { e.printStackTrace(); } } } } System.load(extractedLibFile.toString()); } ``` ### 参考链接 [JNIdemo图文](https://blog.csdn.net/WeiHao0240/article/details/99568579) [JNI完全指南文档](https://www.zybuluo.com/cxm-2016/note/563686) [JNI 官方文档](https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/jniTOC.html)
  • [优秀实践] 鲲鹏众智-Java性能分析工具IntelliJ插件实现
    很荣幸参加《鲲鹏Java性能分析工具IntelliJ插件实现》项目开发工作的,我们项目主要是做Inellij插件开发实现性能分析工具功能。由于插件开发的特殊性,常常需要和一些命令行打交道,下面记录一次通过Java代码打开Windows证书安装窗口安装证书cer文件。思路如下:第一步:下载证书,保存到本地    通过cer文件下载接口将文件保存到本地,记录文件的保存位置第二步:通过代码在IDEA的Terminal命令窗口输入命令打开证书安装窗口    // 将项目对象,ToolWindow的id传入,获取控件对象    ToolWindow toolWindow = ToolWindowManager.getInstance(e.getProject()).getToolWindow("Terminal");        if (toolWindow != null) {            // 无论当前状态为关闭/打开,进行强制打开ToolWindow            toolWindow.show(new Runnable() {                @Override                public void run() {                Process p  =  Runtime.getRuntime().exec("rundll32.exe cryptext.dll,CryptExtAddCER "+ path);                }            });        }    }第三步:提醒用户重启IDEA,使证书生效    Messages.showMessageDialog("安装证书", "安装证书后请重启IDEA,证书才能生效", Messages.getInformationIcon());