Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ComputeLibrary] Add new package for ARM-software/ComputeLibrary #19958

Merged
merged 12 commits into from
Aug 22, 2024
7 changes: 7 additions & 0 deletions recipes/compute_library/all/conandata.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
sources:
"23.08":
url: "https://github.com/ARM-software/ComputeLibrary/archive/refs/tags/v23.08.tar.gz"
sha256: "62f514a555409d4401e5250b290cdf8cf1676e4eb775e5bd61ea6a740a8ce24f"
jcar87 marked this conversation as resolved.
Show resolved Hide resolved
"23.02.1":
url: "https://github.com/ARM-software/ComputeLibrary/archive/refs/tags/v23.02.1.tar.gz"
sha256: "c3a443e26539f866969242e690cf0651ef629149741ee18732f954c734da6763"
149 changes: 149 additions & 0 deletions recipes/compute_library/all/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
from conan import ConanFile
from conan.errors import ConanInvalidConfiguration
from conan.tools.files import get, copy, rm, chdir
from conan.tools.build import check_min_cppstd, cross_building, build_jobs
from conan.tools.scm import Version
from conan.tools.env import VirtualBuildEnv
from conan.tools.gnu import AutotoolsDeps, AutotoolsToolchain
from conan.tools.layout import basic_layout
import os


required_conan_version = ">=1.53.0"


class ComputeLibraryConan(ConanFile):
name = "compute_library"
description = "The Compute Library is a set of computer vision and machine learning functions optimized for both Arm CPUs and GPUs using SIMD technologies"
license = "MIT"
url = "https://github.com/conan-io/conan-center-index"
homepage = "https://github.com/ARM-software/ComputeLibrary"
topics = ("android", "linux", "machine-learning", "arm", "computer-vision", "neural-network")
package_type = "library"
settings = "os", "arch", "compiler", "build_type"
options = {
"shared": [True, False],
"enable_openmp": [True, False],
"enable_opencl": [True, False],
"enable_neon": [True, False],
"enable_multi_isa": [True, False],
}
default_options = {
"shared": False,
"enable_openmp": False,
"enable_opencl": True,
"enable_neon": True,
"enable_multi_isa": False,
}

@property
def _min_cppstd(self):
return 14
uilianries marked this conversation as resolved.
Show resolved Hide resolved

@property
def _compilers_minimum_version(self):
return {
"gcc": "6",
"clang": "5",
"apple-clang": "5.1",
}

def config_options(self):
# INFO: Neon option is reserved to arm architecture
if "arm" not in str(self.settings.arch):
del self.options.enable_neon
# INFO: OpenMP option only works with g++, according to the documentation
if self.settings.compiler == "clang":
del self.options.enable_openmp
# INFO: OpenCL fails to build with MacOS
if self.settings.os == "Macos":
del self.options.enable_opencl

def configure(self):
if self.options.shared:
self.options.rm_safe("fPIC")

def layout(self):
basic_layout(self, src_folder="src")

def build_requirements(self):
self.tool_requires("scons/4.3.0")

def requirements(self):
if self.options.get_safe("enable_opencl"):
self.requires("opencl-headers/2023.04.17")

def validate(self):
if self.settings.compiler.cppstd:
check_min_cppstd(self, self._min_cppstd)
minimum_version = self._compilers_minimum_version.get(str(self.settings.compiler), False)
if minimum_version and Version(self.settings.compiler.version) < minimum_version:
raise ConanInvalidConfiguration(f"{self.ref} requires C++{self._min_cppstd}, which your compiler does not support.")
# INFO: https://github.com/ARM-software/ComputeLibrary#supported-systems
supported_os = ["Android", "Linux", "OpenBSD", "Macos", "Tizen", "Windows"]
if str(self.settings.os) not in supported_os:
raise ConanInvalidConfiguration(f"{self.ref} does not support {self.settings.os}. It is only supported on {supported_os}.")
if self.settings.os == "Windows":
if cross_building(self):
# INFO: https://arm-software.github.io/ComputeLibrary/latest/how_to_build.xhtml#S1_6_windows_host
raise ConanInvalidConfiguration(f"Using scons directly from the Windows command line is known to cause problems. Please, try native native build on Windows ARM or cross-build on Linux Ubuntu.")

Check warning on line 89 in recipes/compute_library/all/conanfile.py

View workflow job for this annotation

GitHub Actions / Lint changed conanfile.py (v2 migration)

Using an f-string that does not have any interpolated variables
if "arm" in str(self.settings.arch):
# INFO: https://arm-software.github.io/ComputeLibrary/latest/how_to_build.xhtml#S1_6_3_WoA
self.output.warn("Native builds on Windows are experimental and some features from the library interacting with the OS are missing.")
if "x86" in str(self.settings.arch):
raise ConanInvalidConfiguration(f"{self.ref} does not support native builds on Windows x86/x86_64. It is only supported on Windows ARM.")
if "arm" not in str(self.settings.arch) and "x86" not in str(self.settings.arch):
# INFO: https://github.com/ARM-software/ComputeLibrary#supported-architecturestechnologies
raise ConanInvalidConfiguration(f"{self.ref} does not support {self.settings.arch}. It is only supported on arm and x86.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arm and x86 usually imply 32bits
should we write arm / arm64 and x86_64 ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's a good clarification.

if "x86" in str(self.settings.arch) and self.settings.os != "Macos" and not self.options.get_safe("enable_opencl", False):
raise ConanInvalidConfiguration(f"{self.ref} can be built for x86_64 targets only with enable_neon=False and enable_opencl=True.")
if self.settings.os == "Linux" and self.settings.compiler == "clang":
# INFO: https://arm-software.github.io/ComputeLibrary/latest/how_to_build.xhtml#S1_2_linux
raise ConanInvalidConfiguration(f"{self.ref} does not support Linux with clang. It is only supported on Linux with gcc.")
if "armv8" not in str(self.settings.arch) and self.options.enable_multi_isa:
raise ConanInvalidConfiguration(f"{self.ref} does not support multi_isa option for {self.settings.arch}. It is only supported on armv8.")
if self.settings.arch == "armv8" and self.settings_build.arch == "x86_64" and self.settings.os == "Macos" and self.settings.compiler == "apple-clang":
raise ConanInvalidConfiguration(f"Mac Intel is not supported for armv8-a. Please, use Mac M1 as native build.")

Check warning on line 106 in recipes/compute_library/all/conanfile.py

View workflow job for this annotation

GitHub Actions / Lint changed conanfile.py (v2 migration)

Using an f-string that does not have any interpolated variables
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, cross compilation from macOS arm64 to x86_64 (as vice versa) works well. You need to use -arch <arm64 | x86_64> option.

See https://github.com/openvinotoolkit/openvino/blob/master/src/plugins/intel_cpu/thirdparty/ACLConfig.cmake#L285-L288 as example

Copy link
Member Author

@uilianries uilianries Sep 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is: I'm using scons and it changes to armv8-a that's not identified by apple clang and passing as -march.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also use scons, but it is just run from cmake.


def source(self):
get(self, **self.conan_data["sources"][self.version], strip_root=True)

def generate(self):
tc = AutotoolsToolchain(self)
tc.generate()
tc = AutotoolsDeps(self)
tc.generate()
tc = VirtualBuildEnv(self)
tc.generate(scope="build")

def build(self):
# INFO: Using scons to build the library we don't have control over shared/static and install step, it is done all together always
# INFO: https://arm-software.github.io/ComputeLibrary/latest/how_to_build.xhtml
yes_no = lambda v: "1" if v else "0"
debug = yes_no(self.settings.build_type == "Debug")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we can also add these options for debug debug=1 asserts=1 logging=1

build_os = str(self.settings.os).lower()
arch = {"armv8": "armv8a", "x86": "x86_32", "armv7": "armv7a", "armv7hf": "armv7a-hf"}.get(str(self.settings.arch), str(self.settings.arch))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ARM compute allows to build code with armv8.2a (fp16 support), SVE and SME.
How to use it via this recipe?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for example Apple M1, M2 support fp16, so we need to enable it by default.

neon = yes_no(self.options.get_safe("enable_neon"))
opencl = yes_no(self.options.get_safe("enable_opencl", False))
openmp = yes_no(self.options.get_safe("enable_openmp"))
multi_isa = yes_no(self.options.enable_multi_isa)
build = "cross_compile" if cross_building(self) else "native"
with chdir(self, self.source_folder):
self.run(f"scons Werror=0 validation_tests=0 examples=0 gemm_tuner=0 multi_isa={multi_isa} openmp={openmp} debug={debug} neon={neon} opencl={opencl} os={build_os} arch={arch} build={build} build_dir={self.build_folder} install_dir={self.package_folder} -j{build_jobs(self)} toolchain_prefix=''", env="conanbuild")
Copy link
Contributor

@ilya-lavrenov ilya-lavrenov Sep 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

conan's arch and compute library archs are different. Compute Library allows to specify exact optimizations which are required. Without it, it does not give proper performance.
So, bypassing conan's arch to compute library is not enough. Conan's arch can be used as initial guess, while users still need to have an ability to provide an option for arch to enable specific optimizations like SVE, SME

As I wrote - Apple M1 must set armv8.2-a to enable FP16 optimization. Currently, it's not set and performance is poor.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem, you can customize your settings.yml, providing not only new archs, but also new subsettings: https://docs.conan.io/2/reference/config_files/settings.html#customizing-settings

Conan covers most generic and known archs, but when talking about optimization, is better having a specific profile adapted, so you can be sure about what's in your package.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree with such approach.

If we put it on x64 arch, what I am asking is to provide a way to select between SSE, AVX, AMX optimizations, while you want me to customize whole settings file and add SSE, AVX and so on to be able to properly compile the library. Don't mix different platforms (settings) against different library optimizations capabilities (the arm option of ARM Compute Library).

Any reason why on Apple ARM64 people would not have FP16 support (which is available out of box) and have to change settings to get suitable performance?


def package(self):
copy(self, pattern="LICENSE", dst=os.path.join(self.package_folder, "licenses"), src=self.source_folder)
# INFO: Artifacts are installed during build step, so we just need to remove what we don't want
rm(self, "*.bazel", self.package_folder, recursive=True)
rm(self, "*.cpp", self.package_folder, recursive=True)
if self.options.shared:
rm(self, "*.a", os.path.join(self.package_folder, "lib"))
else:
rm(self, "*.so*", os.path.join(self.package_folder, "lib"))
rm(self, "*.dylib*", os.path.join(self.package_folder, "lib"))

def package_info(self):
suffix = "" if self.options.shared else "-static"
self.cpp_info.libs = [f"arm_compute{suffix}", f"arm_compute_core{suffix}", f"arm_compute_graph{suffix}"]
if self.settings.os in ["Linux", "FreeBSD"]:
self.cpp_info.system_libs = ["m", "pthread"]
8 changes: 8 additions & 0 deletions recipes/compute_library/all/test_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.15)
project(test_package CXX)

find_package(compute_library REQUIRED CONFIG)

add_executable(${PROJECT_NAME} test_package.cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE compute_library::compute_library)
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_14)
26 changes: 26 additions & 0 deletions recipes/compute_library/all/test_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from conan import ConanFile
from conan.tools.build import can_run
from conan.tools.cmake import cmake_layout, CMake
import os


class TestPackageConan(ConanFile):
settings = "os", "arch", "compiler", "build_type"
generators = "CMakeDeps", "CMakeToolchain", "VirtualRunEnv"
test_type = "explicit"

def requirements(self):
self.requires(self.tested_reference_str)

def layout(self):
cmake_layout(self)

def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()

def test(self):
if can_run(self):
bin_path = os.path.join(self.cpp.build.bindir, "test_package")
self.run(bin_path, env="conanrun")
11 changes: 11 additions & 0 deletions recipes/compute_library/all/test_package/test_package.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include <cstdlib>
#include <iostream>
#include "arm_compute/core/Version.h"


int main(void) {
std::cout << "ComputeLibrary information:" << std::endl;
std::cout << arm_compute::build_information() << std::endl;

return EXIT_SUCCESS;
}
5 changes: 5 additions & 0 deletions recipes/compute_library/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
versions:
"23.08":
folder: all
"23.02.1":
folder: all