Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 39 additions & 13 deletions ci/build_linux_wheels.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
Environment:
- GITHUB_WORKSPACE (optional; defaults to cwd)
"""

from __future__ import annotations
import argparse
import os
Expand All @@ -33,7 +34,9 @@
from typing import List

# Define Python version sets directly in the Python script
RELEASE_PYTHON_VERSIONS = "cp38-cp38 cp39-cp39 cp310-cp310 cp311-cp311 cp312-cp312 cp313-cp313"
RELEASE_PYTHON_VERSIONS = (
"cp38-cp38 cp39-cp39 cp310-cp310 cp311-cp311 cp312-cp312 cp313-cp313"
)
DEFAULT_PYTHON_VERSIONS = "cp38-cp38 cp313-cp313"

# Path to the container build script
Expand All @@ -42,15 +45,13 @@
DEFAULT_X86_IMAGES = [
"quay.io/pypa/manylinux2014_x86_64:latest",
# "quay.io/pypa/manylinux_2_28_x86_64:latest",

# bazel binaries do not work with musl
# "quay.io/pypa/musllinux_1_2_x86_64:latest",
]

DEFAULT_AARCH64_IMAGES = [
"quay.io/pypa/manylinux2014_aarch64:latest",
# "quay.io/pypa/manylinux_2_28_aarch64:latest",

# bazel binaries do not work with musl
# "quay.io/pypa/musllinux_1_2_aarch64:latest",
]
Expand All @@ -65,17 +66,26 @@
"AARCH64": "arm64",
}


def parse_args():
p = argparse.ArgumentParser()
p.add_argument("--arch", required=True, help="Architecture (e.g. X86, X64, AARCH64)")
p.add_argument("--release", action="store_true", help="Run full test suite for release")
p.add_argument("--dry-run", action="store_true", help="Print docker commands without running")
p.add_argument(
"--arch", required=True, help="Architecture (e.g. X86, X64, AARCH64)"
)
p.add_argument(
"--release", action="store_true", help="Run full test suite for release"
)
p.add_argument(
"--dry-run", action="store_true", help="Print docker commands without running"
)
return p.parse_args()


def normalize_arch(raw: str) -> str:
key = raw.strip().upper()
return ARCH_ALIASES.get(key, raw.strip().lower())


def collect_images_for_arch(arch_normalized: str) -> List[str]:
if arch_normalized == "x86":
imgs = DEFAULT_X86_IMAGES # dedupe preserving order
Expand All @@ -85,6 +95,7 @@ def collect_images_for_arch(arch_normalized: str) -> List[str]:
raise SystemExit(f"Unsupported arch: {arch_normalized!r}")
return imgs


def build_docker_cmd(workspace: str, image: str, release: bool = False) -> List[str]:
workspace = os.path.abspath(workspace)
python_versions = RELEASE_PYTHON_VERSIONS if release else DEFAULT_PYTHON_VERSIONS
Expand All @@ -93,11 +104,18 @@ def build_docker_cmd(workspace: str, image: str, release: bool = False) -> List[
github_ref_name = os.environ.get("GITHUB_REF_NAME", "")

cmd = [
"docker", "run", "-i", "--rm",
"-v", f"{workspace}:/work", # (v)olume
"-w", "/work", # (w)orking directory
"-e", f"PYTHON_VERSIONS={python_versions}", # (e)nvironment variables
"-e", f"RELEASE_BUILD={'1' if release else '0'}"
"docker",
"run",
"-i",
"--rm",
"-v",
f"{workspace}:/work", # (v)olume
"-w",
"/work", # (w)orking directory
"-e",
f"PYTHON_VERSIONS={python_versions}", # (e)nvironment variables
"-e",
f"RELEASE_BUILD={'1' if release else '0'}",
]

# Pass GitHub reference name if available
Expand All @@ -107,7 +125,10 @@ def build_docker_cmd(workspace: str, image: str, release: bool = False) -> List[
cmd.extend([image, "bash", CONTAINER_SCRIPT_PATH])
return cmd

def run_for_images(images: List[str], workspace: str, dry_run: bool, release: bool = False) -> int:

def run_for_images(
images: List[str], workspace: str, dry_run: bool, release: bool = False
) -> int:
rc_overall = 0
for image in images:
docker_cmd = build_docker_cmd(workspace, image, release=release)
Expand All @@ -118,7 +139,10 @@ def run_for_images(images: List[str], workspace: str, dry_run: bool, release: bo
try:
completed = subprocess.run(docker_cmd)
if completed.returncode != 0:
print(f"Container {image} exited with {completed.returncode}", file=sys.stderr)
print(
f"Container {image} exited with {completed.returncode}",
file=sys.stderr,
)
rc_overall = completed.returncode if rc_overall == 0 else rc_overall
else:
print(f"Container {image} completed successfully.")
Expand All @@ -130,6 +154,7 @@ def run_for_images(images: List[str], workspace: str, dry_run: bool, release: bo
return 2
return rc_overall


def main() -> int:
args = parse_args()
arch = normalize_arch(args.arch)
Expand All @@ -148,5 +173,6 @@ def main() -> int:
print(f"Selected images for arch {args.arch}: {images}")
return run_for_images(images, workspace, args.dry_run, release=args.release)


if __name__ == "__main__":
sys.exit(main())
17 changes: 16 additions & 1 deletion ci/run_ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -289,9 +289,24 @@ case $1 in
set -e
rustup component add clippy-preview
rustup component add rustfmt
echo "Installing protoc for protobuf compilation"
if command -v apt-get >/dev/null; then
sudo apt-get update
sudo apt-get install -y protobuf-compiler
elif command -v brew >/dev/null; then
brew install protobuf
elif command -v yum >/dev/null; then
sudo yum install -y protobuf-compiler
else
echo "Package manager not found, downloading protoc binary"
curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protoc-21.12-linux-x86_64.zip
unzip protoc-21.12-linux-x86_64.zip -d protoc
sudo mv protoc/bin/* /usr/local/bin/
sudo mv protoc/include/* /usr/local/include/
fi
echo "Executing fory rust tests"
cd "$ROOT/rust"
cargo doc --no-deps --document-private-items --all-features --open
cargo doc --no-deps --document-private-items --all-features
cargo fmt --all -- --check
cargo fmt --all
cargo clippy --workspace --all-features --all-targets
Expand Down
34 changes: 33 additions & 1 deletion ci/tasks/rust.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,38 @@ def run():
logging.info("Executing fory rust tests")
common.cd_project_subdir("rust")

# Install protoc for protobuf compilation
try:
if common.is_windows():
raise Exception("Not supported on Windows")
else:
# On Linux/macOS, install via package manager
logging.info("Installing protoc")
import shutil

if shutil.which("apt-get"):
# Ubuntu/Debian
common.exec_cmd("sudo apt-get update")
common.exec_cmd("sudo apt-get install -y protobuf-compiler")
elif shutil.which("brew"):
# macOS
common.exec_cmd("brew install protobuf")
elif shutil.which("yum"):
# CentOS/RHEL
common.exec_cmd("sudo yum install -y protobuf-compiler")
else:
# Fallback: download binary
logging.info("Package manager not found, downloading protoc binary")
common.exec_cmd(
"curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protoc-21.12-linux-x86_64.zip"
)
common.exec_cmd("unzip protoc-21.12-linux-x86_64.zip -d protoc")
common.exec_cmd("sudo mv protoc/bin/* /usr/local/bin/")
common.exec_cmd("sudo mv protoc/include/* /usr/local/include/")
except Exception as e:
logging.warning(f"Failed to install protoc: {e}")
logging.warning("Continuing without protoc - benchmarks may fail")

# From run_ci.sh, we should also add rustup components
try:
common.exec_cmd("rustup component add clippy-preview")
Expand All @@ -33,7 +65,7 @@ def run():
logging.warning("Continuing with existing components")

cmds = (
"cargo doc --no-deps --document-private-items --all-features --open",
"cargo doc --no-deps --document-private-items --all-features",
"cargo fmt --all -- --check",
"cargo fmt --all",
"cargo clippy --workspace --all-features --all-targets -- -D warnings",
Expand Down
1 change: 1 addition & 0 deletions rust/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
Cargo.lock
/target
**/generated
3 changes: 2 additions & 1 deletion rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ members = [
"fory-core",
"fory",
"fory-derive",
"tests"
"tests",
"benches"
]

exclude = [
Expand Down
6 changes: 6 additions & 0 deletions rust/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,12 @@ Fory is designed to work across multiple programming languages, making it ideal
- **Data pipelines** spanning multiple language ecosystems
- **API communication** between different technology stacks

## Benchmark

```bash
cargo bench --package fory-benchmarks
```

## 🛠️ Development Status

Fory Rust implementation roadmap:
Expand Down
41 changes: 41 additions & 0 deletions rust/benches/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

[package]
name = "fory-benchmarks"
version = "0.1.0"
edition = "2021"

[[bench]]
name = "serialization_bench"
path = "benches/serialization_bench.rs"
harness = false

[dependencies]
fory = { path = "../fory" }
fory-core = { path = "../fory-core" }
fory-derive = { path = "../fory-derive" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
chrono = { version = "0.4", features = ["serde"] }
prost = "0.12"
prost-types = "0.12"
rand = "0.8"
criterion = "0.5"

[build-dependencies]
prost-build = "0.12"
22 changes: 22 additions & 0 deletions rust/benches/benches/serialization_bench.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

use criterion::{criterion_group, criterion_main};
use fory_benchmarks::run_serialization_benchmarks;

criterion_group!(benches, run_serialization_benchmarks);
criterion_main!(benches);
51 changes: 51 additions & 0 deletions rust/benches/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

use std::path::Path;

fn main() {
println!("cargo:warning=Build script running");
println!(
"cargo:warning=OUT_DIR: {}",
std::env::var("OUT_DIR").unwrap()
);

let proto_files = [
"proto/simple.proto",
"proto/medium.proto",
"proto/complex.proto",
"proto/realworld.proto",
];

for proto_file in &proto_files {
if Path::new(proto_file).exists() {
println!("cargo:rerun-if-changed={}", proto_file);
println!("cargo:warning=Found proto file: {}", proto_file);
} else {
println!("cargo:warning=Proto file not found: {}", proto_file);
}
}

let mut config = prost_build::Config::new();
// Don't set out_dir, use the default OUT_DIR

println!("cargo:warning=About to compile protobuf files");
config
.compile_protos(&proto_files, &["proto/"])
.expect("Failed to compile protobuf files");
println!("cargo:warning=Protobuf compilation completed");
}
Loading
Loading