强强联合,性能提升数倍!Alibaba Dragonwell11+VectorAPI 助力 Java 高性能新时代

简介: VectorAPI 是 Java 在特定领域进行高性能计算的利器。

文/朱文杰、金钟晖

01 背景

Alibaba Dragonwell 作为 OpenJDK 的下游版本,是阿里巴巴针对 10万+ 服务器上运行的在线电商、金融、物流应用优化的 OpenJDK 实现。 阿里巴巴和 OpenJDK 社区紧密合作,将尽可能多的 Alibaba Dragonwell 定制功能带到上游。Dragonwell 是 OpenAnolis 的默认 JDK,Alibaba 的众多 Java 应用,正在逐步迁移到 Dragonwell 上。


Intel Java 团队长期致力于 OpenJDK 的发展,贡献了大量优化特性,这些工作使得 OpenJDK 可以更好利用现代 CPU 的强大特性。VectorAPI 是 Java 在特定领域进行高性能计算的利器,广大 Java 开发者通过 VectorAPI 可以精确地控制和利用现代 CPU 普遍存在的 SIMD (Single Instruction Multiple Data) 硬件单元,特定的应用可以获得数倍以上的性能提升。

02 Java 高性能计算现状

SIMD 计算单元在 X86 平台(非 X86 平台也普遍存在 SIMD)上从 MMX(Multi Media eXtension)时代,演进到当前的 AVX-512 (Advanced Vector Extensions)/AMX(Advanced Matrix Extensions)时代,SIMD 技术在多媒体处理,游戏娱乐,大数据处理和最近火热的 AI 领域都发挥了至关重要的作用。开发者可以利用 C/C++(intrinsic指令),汇编语言等语言工具显式的编写 SIMD 相关代码(称之为向量化编码)来利用 SIMD 单元;也可以利用编译器/解释器的自动向量化功能来进行。JVM(Java Virtual Machine)也具有自动向量化的能力。


在利用编译器/解释器的自动向量化功能的时候,虽然开发人员的负担较小,但由于这些工作都依赖于编译器/解释器的实现,很多时候无法达到预期的目的。而开发人员能做的却很有限,SIMD 硬件的性能往往不能充分发挥;而直接针对 SIMD 硬件编程,较老版本的 Java 却只能通过 JNI(Java Native Interface),调用使用 C/C++ 或者汇编语言实现的库来实现。JNI 的引入,将带来不容忽视的额外性能开销;同时混合编程模式也会增加系统管理维护的复杂度。Java VectorAPI (向量 API)的出现,给了 Java 开发者直接面向 SIMD 硬件的编程能力。使用 SIMD 硬件的途径:


自动向量化 调用本地语言库

直接针对 SIMD 单元编程

C/C++、汇编

等本地语言


 (Intrinsic/汇编)
Java 是(JNI) (VectorAPI)

03 VectorAPI 介绍

VectorAPI (Incubator, JEP 338, JEP:JDK Enhancement Proposals) 最初于 2018 年 4 月开始创建,在 OpenJDK16 作为孵化器项目(2020年10月)被引入。随着后续 OpenJDK 版本的升级,VectorAPI 也得到了同步升级:

  • OpenJDK 17 -> JEP 414,Second Incubator
  • OpenJDK 18 -> JEP 417,Third Incubator
  • OpenJDK 19 -> JEP 426,Fourth Incubator
  • OpenJDK 20 -> JEP 438,Fifth Incubator

每次 VectorAPI 的升级都会带来性能提升,更多功能和 Bugfix。VectorAPI 的编程使用的是纯 Java 代码,下面看一个简单例子

// 传统写法实现2个数组相加
void add (float[] A, float[] B, float[] C) { 
    for (int i = 0; i < C.length; i++) { 
        C[i] = A[i] + B[i]; 
    } 
} 
// 使用VectorAPI的2个数组相加
public class AddClass<S extends Vector.Shape<Vector<?, ?>>> { 
    private final FloatVector.FloatSpecies<S> spec; 
    AddClass (FloatVector.FloatSpecies<S> v) {spec = v; } 
    // vector routine for add  
    void add (float[] A, float[] B, float[] C) { 
        int i=0; 
        for (; i + spec.length() < C.length; i += spec.length()) { 
            FloatVector<S> av = spec.fromArray(A, i); 
            FloatVector<S> bv = spec.fromArray(B, i); 
            av.add (bv).intoArray(C, i); 
        } 
        // clean up loop 
        for (; i < a.length; i++) C[i] = A[i] + B[i]; 
    } 
}


可以看出,在使用 VectorAPI 后,在支持 AVX-512 的硬件平台上,一次加法可以处理 (512/32=16) 16 个浮点数;而传统加法一次只能处理一个浮点数。下面是一些 VectorAPI 的实际例子:

  • 高性能计算、AI、多媒体领域广泛使用的 BLAS (Basic Linear Algebra Subprograms,基本线性代数子程序),可以得到 2.2X~4.5X 的提升。

  • 图像处理 Sepia 过滤 ,最多得到 6 倍提升:

  • 数据库应用 2 倍以上提升:

由于 VectorAPI 是一个比较新的模块,更多利用 VectorAPI 的新项目正在开发中。

04 业界 Java 版本现状

在 Apache Parquet-mr 项目中,使用 VectorAPI 需要 JDK17 的支持。一方面 JDK17 是 Java 的 LTS (Long-Term Support) 版本,更为重要的是前一个 Java LTS 版本 JDK11 并不支持 VectorAPI。但是业界 JDK11 的使用比 JDK17 更为广泛,而在成熟的生产环境中升级 Java 版本是一件代价高昂的事情,这就造成了 VectorAPI 在业界推广使用的一个显而易见的巨大障碍。对此业界也做了不少努力和尝试,比如阿里巴巴在其内部使用的 AJDK上,已经加入了 VectorAPI 的支持,但是其实现和 OpenJDK 社区还是有差别,后续的升级维护不是一件容易的事情。因此阿里巴巴和英特尔开始了将 VectorAPI  (JEP 338)移植到 Dragonwell11 上的项目。这样既可以利用 VectorAPI 的强大功能,又保护了现在的投资,避免了升级 JDK 的风险

05 移植难点

  • 涉及代码量巨大

社区 JEP 338 涉及 336 文件修改,涉及代码行数 29 万行。而这些都是以 JDK16 为基准的和基于 JDK11 的 Dragonwell 相比,差异会更大。

  • 保持和上游 OpenJDK 的关联

而且一方面要让 Dragonwell11 能继续方便追踪上游 OpenJDK11 的修正增强,还要让 VectorAPI 也能较为方便跟踪上游 OpenJDK 后续 VectorAPI 的演进,对移植工作带来了不小挑战。

  • 性能要和上游 OpenJDK 接近

OpenJDK11 以后的版本的一些性能相关改动以及如何引入 Dragonwell11?

  • 稳定可靠的强需求

Dragonwell 需要支持现有的大量业务,稳定可靠是第一位的要求。


06 解决方案


针对海量的代码,阿里巴巴和英特尔都投入了大量资源,其中双方都包括了上游 OpenJDK 社区 VectorAPI 的关键贡献者,双方紧密合作,讨论方案,检查代码。在移植过程中,尽量保持 Dragonwell11 的原有结构,只涉及 VectorAPI 的部分才采用上游的实现。一些上游 JDK11 以后的改动,分析其实现,如果可以使用现有 Dragonwell11 的组件,就不引入额外的改动。这样把对 Dragonwell11 的影响降到最小。并且利用 OpenJDK 内建的测试集,完整覆盖移植后的 Dragonwell11,来保证移植的质量。

07 Dragonwell11 + VectorAPI

目前,VectorAPI 已经合并到 Dragonwell11 的主分支(master),且完全兼容 VectorAPI 1st Incubator (JEP 338),后续还会把 JEP 414、JEP 417、JEP 426、JEP 438 的功能移植到 Dragonwel11 上。


相关链接:

Alibaba Dragonwell:https://github.com/alibaba/dragonwell11

OpenJDK :https://github.com/openjdk/jdk


—— 完 ——

相关文章
|
1天前
|
算法 安全 Java
性能工具之 JMeter 自定义 Java Sampler 支持国密 SM2 算法
【4月更文挑战第28天】性能工具之 JMeter 自定义 Java Sampler 支持国密 SM2 算法
32 1
性能工具之 JMeter 自定义 Java Sampler 支持国密 SM2 算法
|
1天前
|
存储 安全 算法
【JAVA】HashMap扩容性能影响及优化策略
【JAVA】HashMap扩容性能影响及优化策略
|
1天前
|
存储 安全 Java
12条通用编程原则✨全面提升Java编码规范性、可读性及性能表现
12条通用编程原则✨全面提升Java编码规范性、可读性及性能表现
|
1天前
|
缓存 算法 Java
Java本地高性能缓存实践
本篇博文将首先介绍常见的本地缓存技术,对本地缓存有个大概的了解;其次介绍本地缓存中号称性能最好的Cache,可以探讨看看到底有多好?怎么做到这么好?最后通过几个实战样例,在日常工作中应用高性能的本地缓存。
|
1天前
|
缓存 NoSQL Java
构建高性能微服务架构:Java后端的实践之路
【5月更文挑战第5天】在当今快速迭代和高并发需求的软件开发领域,微服务架构因其灵活性、可扩展性而受到青睐。本文将深入探讨如何在Java后端环境中构建一个高性能的微服务系统,涵盖关键的设计原则、常用的框架选择以及性能优化技巧。我们将重点讨论如何通过合理的服务划分、高效的数据存储策略、智能的缓存机制以及有效的负载均衡技术来提升整体系统的响应速度和处理能力。
|
1天前
|
移动开发 Java Android开发
构建高效Android应用:探究Kotlin与Java的性能对比
【5月更文挑战第4天】在移动开发的世界中,性能一直是衡量应用质量的重要指标。随着Kotlin的兴起,许多Android开发者开始考虑是否应该从传统的Java迁移到Kotlin。本文通过深入分析两者在Android平台上的性能差异,帮助开发者理解Kotlin在实际项目中的表现,并提供选择编程语言时的参考依据。
24 5
|
1天前
|
存储 缓存 前端开发
Java串口通信技术探究3:RXTX库线程 优化系统性能的SerialPortEventListener类
Java串口通信技术探究3:RXTX库线程 优化系统性能的SerialPortEventListener类
44 3
|
1天前
|
Java 编译器 Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【5月更文挑战第1天】 在移动开发的世界中,性能优化始终是开发者关注的焦点。随着Kotlin的兴起,许多团队和开发者面临着一个选择:是坚持传统的Java语言,还是转向现代化、更加简洁的Kotlin?本文通过深入分析和对比Kotlin与Java在Android应用开发中的性能表现,揭示两者在编译效率、运行速度和内存消耗等方面的差异。我们将探讨如何根据项目需求和团队熟悉度,选择最适合的语言,以确保应用的高性能和流畅体验。
|
1天前
|
Java 编译器 Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【4月更文挑战第30天】在Android开发领域,Kotlin作为一种现代化的编程语言,因其简洁性和功能性受到了开发者的广泛欢迎。尽管与传统的Java相比,Kotlin提供了诸多便利,但关于其性能表现的讨论始终未息。本文将深入分析Kotlin和Java在Android平台上的性能差异,通过实际测试数据揭示两种语言在编译效率、运行速度以及内存占用方面的具体表现,并探讨如何利用Kotlin的优势来提升Android应用的整体性能。
|
1天前
|
存储 安全 Java
【亮剑】`ConcurrentHashMap`是Java中线程安全的哈希表,采用锁定分离技术提高并发性能
【4月更文挑战第30天】`ConcurrentHashMap`是Java中线程安全的哈希表,采用锁定分离技术提高并发性能。数据被分割成多个Segment,每个拥有独立锁,允许多线程并发访问不同Segment。当写操作发生时,计算键的哈希值定位Segment并获取其锁;读操作通常无需锁定。内部会根据负载动态调整Segment,减少锁竞争。虽然使用不公平锁,但Java 8及以上版本提供了公平锁选项。理解其工作原理对开发高性能并发应用至关重要。

热门文章

最新文章