Skip to content

Commit b3835d9

Browse files
authored
Merge pull request #142 from artpdr/ft-ap-lgbm-arm64
Add support for ARM64 on LGBM
2 parents dbc561a + 050bfa8 commit b3835d9

9 files changed

Lines changed: 128 additions & 19 deletions

File tree

.github/workflows/build.yml

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121

2222
steps:
2323
- name: Checkout code
24-
uses: actions/checkout@v2
24+
uses: actions/checkout@v3
2525
with:
2626
fetch-depth: 0
2727
- run: |
@@ -30,20 +30,29 @@ jobs:
3030
git tag --list
3131
3232
- name: Set up JDK 1.8
33-
uses: actions/setup-java@v1
33+
uses: actions/setup-java@v3
3434
with:
35-
java-version: 1.8
35+
java-version: '8'
36+
distribution: 'zulu'
3637

3738
- name: Cache Maven packages
38-
uses: actions/cache@v2.1.4
39+
uses: actions/cache@v3.3.2
3940
with:
4041
path: ~/.m2
4142
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
4243
restore-keys: ${{ runner.os }}-m2
4344

45+
- uses: docker/setup-qemu-action@v2
46+
with:
47+
platforms: "arm64"
48+
4449
- name: Build and test
4550
run: mvn test -B
4651

52+
# The skipped tests is because h2o-xgboost isn't ready to use on arm64
53+
- name: Test on arm64
54+
run: docker run --rm --platform=arm64 -t -v ~/.m2:/root/.m2 -v $(pwd):/feedzai-openml-java maven:3.8-openjdk-8-slim /bin/bash -c 'apt update && apt install -y --no-install-recommends git && git config --global --add safe.directory /feedzai-openml-java && git config --global --add safe.directory /feedzai-openml-java/openml-lightgbm/lightgbm-builder/make-lightgbm && cd /feedzai-openml-java && mvn test -B -DfailIfNoTests=false -Dtest=!ClassifyUnknownCategoryTest#test,!H2OModelProviderTrainTest#trainModelsForAllAlgorithms'
55+
4756
- uses: codecov/codecov-action@v1
4857
with:
4958
fail_ci_if_error: true

.github/workflows/deploy.yml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515

1616
steps:
1717
- name: Checkout code
18-
uses: actions/checkout@v2
18+
uses: actions/checkout@v3
1919
with:
2020
fetch-depth: 0
2121
- run: |
@@ -24,13 +24,18 @@ jobs:
2424
git tag --list
2525
2626
- name: Set up JDK 1.8
27-
uses: actions/setup-java@v1
27+
uses: actions/setup-java@v3
2828
with:
29-
java-version: 1.8
29+
java-version: '8'
30+
distribution: 'zulu'
3031
server-id: ossrh
3132
server-username: MAVEN_USERNAME
3233
server-password: MAVEN_PASSWORD
3334

35+
- uses: docker/setup-qemu-action@v2
36+
with:
37+
platforms: "arm64"
38+
3439
- name: Publish maven package
3540
run: mvn deploy -B -Prelease --batch-mode -DskipTests=true
3641
env:

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,20 @@
66
Implementations of the Feedzai OpenML API to allow support for machine
77
learning models in Java.
88

9+
All models may be used in nodes with AMD64 and ARM64 cpu architectures
10+
except for H2O-xgboost that can be used only with AMD64 cpu architectures.
11+
912
## Building
1013
This is a Maven project which you can build using the following command:
1114
```bash
1215
mvn clean install
1316
```
1417

18+
If the build fails compiling for ARM64 you may need to run:
19+
```bash
20+
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
21+
```
22+
1523
## Releasing
1624

1725
For all releases, as the hotfix branch is ready all that's needed to actually release is to create an annotated tag pointing to the hotfix branch head.

openml-lightgbm/lightgbm-builder/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@
4343
<directory>make-lightgbm/build/</directory>
4444
<filtering>false</filtering>
4545
<includes>
46-
<include>*.so</include>
47-
<include>*.so.1.0.0</include>
46+
<include>**/*.so</include>
47+
<include>**/*.so.1.0.0</include>
4848
</includes>
4949
</resource>
5050
<resource>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* The copyright of this file belongs to Feedzai. The file cannot be
3+
* reproduced in whole or in part, stored in a retrieval system,
4+
* transmitted in any form, or by any means electronic, mechanical,
5+
* photocopying, or otherwise, without the prior permission of the owner.
6+
*
7+
* © 2023 Feedzai, Strictly Confidential
8+
*/
9+
package com.feedzai.openml.provider.lightgbm;
10+
11+
/**
12+
* Enum that represents the cpu architecture where code is running and consequent lgbm native libs locations.
13+
*/
14+
public enum CpuArchitecture {
15+
AARCH64("arm64"),
16+
AMD64("amd64");
17+
18+
/**
19+
* This is the name of the folder where the lightgbm native libraries are.
20+
*/
21+
private final String lgbmNativeLibsFolder;
22+
23+
CpuArchitecture(final String lgbmNativeLibsFolder){
24+
this.lgbmNativeLibsFolder = lgbmNativeLibsFolder;
25+
}
26+
27+
/**
28+
* Gets the native libraries folder name according to the cpu architecture.
29+
*
30+
* @return the native libraries folder name according to the cpu architecture.
31+
*/
32+
public String getLgbmNativeLibsFolder() {
33+
return lgbmNativeLibsFolder;
34+
}
35+
}

openml-lightgbm/lightgbm-provider/src/main/java/com/feedzai/openml/provider/lightgbm/LightGBMUtils.java

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
import org.slf4j.LoggerFactory;
2222

2323
import java.io.*;
24+
import java.util.Arrays;
25+
import java.util.Objects;
26+
import java.util.stream.Collectors;
2427

2528
import static com.google.common.io.ByteStreams.copy;
2629

@@ -56,30 +59,45 @@ public class LightGBMUtils {
5659
static public void loadLibs() {
5760

5861
if (!libsLoaded) {
62+
final CpuArchitecture cpuArchitecture = getCpuArchitecture(System.getProperty("os.arch"));
5963
try {
60-
loadSharedLibraryFromJar("libgomp.so.1.0.0");
61-
loadSharedLibraryFromJar("lib_lightgbm.so");
62-
loadSharedLibraryFromJar("lib_lightgbm_swig.so");
63-
} catch (final IOException e) {
64-
throw new RuntimeException("Failed to load LightGBM shared libraries from jar.", e);
64+
loadSharedLibraryFromJar("libgomp.so.1.0.0", cpuArchitecture);
65+
loadSharedLibraryFromJar("lib_lightgbm.so", cpuArchitecture);
66+
loadSharedLibraryFromJar("lib_lightgbm_swig.so", cpuArchitecture);
67+
} catch (final IOException ex) {
68+
throw new RuntimeException("Failed to load LightGBM shared libraries from jar.", ex);
6569
}
6670

6771
logger.info("Loaded LightGBM libs.");
6872
libsLoaded = true;
6973
}
7074
}
7175

76+
static CpuArchitecture getCpuArchitecture(final String cpuArchName) {
77+
try {
78+
return CpuArchitecture.valueOf(cpuArchName.toUpperCase());
79+
} catch (final IllegalArgumentException ex) {
80+
logger.error("Trying to use LightGBM on an unsupported architecture {}.", cpuArchName, ex);
81+
throw ex;
82+
}
83+
}
84+
7285
/**
7386
* Loads a single shared library from the Jar.
7487
*
7588
* @param sharedLibResourceName library "filename" inside the jar.
89+
* @param cpuArchitecture cpu architecture.
7690
* @throws IOException if any error happens loading the library.
7791
*/
78-
static private void loadSharedLibraryFromJar(final String sharedLibResourceName) throws IOException {
92+
static private void loadSharedLibraryFromJar(
93+
final String sharedLibResourceName,
94+
final CpuArchitecture cpuArchitecture
95+
) throws IOException {
7996

80-
logger.debug("Loading LightGBM shared lib: {}.", sharedLibResourceName);
97+
logger.debug("Loading LightGBM shared lib: {} for {}.", sharedLibResourceName, cpuArchitecture);
8198

82-
final InputStream inputStream = LightGBMUtils.class.getClassLoader().getResourceAsStream(sharedLibResourceName);
99+
final InputStream inputStream = LightGBMUtils.class.getClassLoader()
100+
.getResourceAsStream(cpuArchitecture.getLgbmNativeLibsFolder() + "/" + sharedLibResourceName);
83101
final File tempFile = File.createTempFile("lib", ".so");
84102
final OutputStream outputStream = new FileOutputStream(tempFile);
85103

openml-lightgbm/lightgbm-provider/src/test/java/com/feedzai/openml/provider/lightgbm/LightGBMResultTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ public void ensureLightgbmScoresAndContributions() throws URISyntaxException, IO
236236
.isEqualTo(2);
237237

238238
final double prediction = resultInstance.getValue(9);
239-
final Offset<Double> offset = Offset.offset(1.0e-16);
239+
final Offset<Double> offset = Offset.offset(1.0e-14);
240240

241241
assertThat(scoreDistribution[1])
242242
.as("The score should be expected.")
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* The copyright of this file belongs to Feedzai. The file cannot be
3+
* reproduced in whole or in part, stored in a retrieval system,
4+
* transmitted in any form, or by any means electronic, mechanical,
5+
* photocopying, or otherwise, without the prior permission of the owner.
6+
*
7+
* © 2023 Feedzai, Strictly Confidential
8+
*/
9+
package com.feedzai.openml.provider.lightgbm;
10+
11+
import org.assertj.core.api.Assertions;
12+
import org.junit.Test;
13+
14+
/**
15+
* Tests the retrieval of cpu architecture.
16+
*
17+
* @author Artur Pedroso (artur.pedroso@feedzai.com)
18+
*/
19+
public class TestCpuArchitecture {
20+
@Test
21+
public void unknownCpuArchitectureThrowsException() {
22+
Assertions.assertThatThrownBy(() -> LightGBMUtils.getCpuArchitecture("x86_64"))
23+
.isInstanceOf(IllegalArgumentException.class);
24+
}
25+
26+
@Test
27+
public void canReadKnownCpuArchitectures() {
28+
Assertions.assertThat(LightGBMUtils.getCpuArchitecture("aarch64"))
29+
.isEqualTo(CpuArchitecture.AARCH64);
30+
31+
Assertions.assertThat(LightGBMUtils.getCpuArchitecture("amd64"))
32+
.isEqualTo(CpuArchitecture.AMD64);
33+
}
34+
}

0 commit comments

Comments
 (0)