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
51 changes: 1 addition & 50 deletions .github/workflows/arm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,56 +3,7 @@ name: arm flow
on: [workflow_call, workflow_dispatch]

jobs:
start-runner:
name: Start self-hosted EC2 runner
runs-on: ubuntu-latest
outputs:
label: ${{ steps.start-ec2-runner.outputs.label }}
ec2-instance-id: ${{ steps.start-ec2-runner.outputs.ec2-instance-id }}
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v6
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Start EC2 runner
id: start-ec2-runner
uses: machulav/ec2-github-runner@v2.6.1
with:
mode: start
github-token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}
# Ubuntu 22.04 region AMI for ARM
ec2-image-id: ami-062b37d89f25c958f
ec2-instance-type: t4g.medium
subnet-id: ${{ secrets.AWS_EC2_SUBNET_ID }}
security-group-id: ${{ secrets.AWS_EC2_SG_ID }}
ec2-volume-size: 30

arm:
needs: start-runner # required to start the main job when the runner is ready
uses: ./.github/workflows/task-unit-test.yml
with:
env: ${{ needs.start-runner.outputs.label }} # run the job on the newly created runner

stop-runner:
name: Stop self-hosted EC2 runner
needs:
- start-runner # required to get output from the start-runner job
- arm # required to wait when the main job is done
runs-on: ubuntu-latest
if: ${{ always() }} # required to stop the runner even if the error happened in the previous jobs
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v6
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Stop EC2 runner
uses: machulav/ec2-github-runner@v2.6.1
with:
mode: stop
github-token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}
label: ${{ needs.start-runner.outputs.label }}
ec2-instance-id: ${{ needs.start-runner.outputs.ec2-instance-id }}
env: ubuntu-22.04-arm
25 changes: 25 additions & 0 deletions .github/workflows/benchmark-runner.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,36 @@ jobs:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION_BENCHMARK }}
- name: Prepare EC2 owner tag
id: ec2-tags
# Keep the original workflow actor as owner, including on reruns.
env:
OWNER_HANDLE: ${{ github.actor }}
shell: python
run: |
import os
import re

# Allow only lowercase ASCII letters, digits, and underscores.
owner = os.environ["OWNER_HANDLE"].lower()
owner = re.sub(r"[^a-z0-9_]", "_", owner)
# Collapse repeated separators, cap at 63 characters, and trim edges.
owner = re.sub(r"_+", "_", owner)[:63].strip("_")
if not owner:
raise SystemExit("Cannot derive an EC2 owner tag from github.actor")

with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as output:
output.write(f"owner={owner}\n")
- name: Start EC2 runner
id: start-ec2-runner
uses: machulav/ec2-github-runner@v2.6.1
with:
mode: start
aws-resource-tags: >-
[
{"Key": "team", "Value": "ai_and_search"},
{"Key": "owner", "Value": "${{ steps.ec2-tags.outputs.owner }}"}
]
github-token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}
ec2-image-id: ${{ inputs.ami-id }}
ec2-instance-type: ${{ inputs.instance-type }}
Expand Down
25 changes: 25 additions & 0 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,36 @@ jobs:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION_BENCHMARK }}
- name: Prepare EC2 owner tag
id: ec2-tags
# Keep the original workflow actor as owner, including on reruns.
env:
OWNER_HANDLE: ${{ github.actor }}
shell: python
run: |
import os
import re

# Allow only lowercase ASCII letters, digits, and underscores.
owner = os.environ["OWNER_HANDLE"].lower()
owner = re.sub(r"[^a-z0-9_]", "_", owner)
# Collapse repeated separators, cap at 63 characters, and trim edges.
owner = re.sub(r"_+", "_", owner)[:63].strip("_")
if not owner:
raise SystemExit("Cannot derive an EC2 owner tag from github.actor")

with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as output:
output.write(f"owner={owner}\n")
- name: Start EC2 runner
id: start-ec2-runner
uses: machulav/ec2-github-runner@v2.6.1
with:
mode: start
aws-resource-tags: >-
[
{"Key": "team", "Value": "ai_and_search"},
{"Key": "owner", "Value": "${{ steps.ec2-tags.outputs.owner }}"}
]
github-token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}
# Ubuntu 22.04 AMI
ec2-image-id: ami-09fabd03bb09b3704
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
name: debian bullseye flow
name: debian trixie flow

on: [workflow_dispatch, workflow_call]

jobs:
bullseye:
trixie:
uses: ./.github/workflows/task-unit-test.yml
with:
container: gcc:11-bullseye
container: gcc:14-trixie
pre-checkout-script: apt-get update && apt-get -y install git

7 changes: 3 additions & 4 deletions .github/workflows/event-merge-to-queue.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ jobs:
# uses: ./.github/workflows/task-unit-test.yml
# with:
# container: ubuntu:bionic
bullseye:
uses: ./.github/workflows/debian11.yml
trixie:
uses: ./.github/workflows/debian13.yml
# amazonlinux2:
# needs: [check-if-docs-only]
# if: ${{ needs.check-if-docs-only.outputs.only-docs-changed == 'false' }}
Expand All @@ -38,7 +38,6 @@ jobs:
uses: ./.github/workflows/macos.yml
arm:
uses: ./.github/workflows/arm.yml
secrets: inherit

coverage:
uses: ./.github/workflows/coverage.yml
Expand All @@ -49,7 +48,7 @@ jobs:
- jammy
# - focal
# - bionic
- bullseye
- trixie
# - amazonlinux2
- mariner2
- rocky8
Expand Down
7 changes: 3 additions & 4 deletions .github/workflows/event-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ jobs:
# uses: ./.github/workflows/task-unit-test.yml
# with:
# container: ubuntu:bionic
bullseye:
uses: ./.github/workflows/debian11.yml
trixie:
uses: ./.github/workflows/debian13.yml
# amazonlinux2:
# needs: [check-if-docs-only]
# if: ${{ needs.check-if-docs-only.outputs.only-docs-changed == 'false' }}
Expand All @@ -41,7 +41,6 @@ jobs:
uses: ./.github/workflows/macos.yml
arm:
uses: ./.github/workflows/arm.yml
secrets: inherit
coverage:
uses: ./.github/workflows/coverage.yml
secrets: inherit
Expand All @@ -56,7 +55,7 @@ jobs:
- jammy
# - focal
# - bionic
- bullseye
- trixie
# - amazonlinux2
- mariner2
- rocky8
Expand Down
File renamed without changes.
35 changes: 22 additions & 13 deletions tests/unit/test_fp16.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -502,36 +502,42 @@ template <typename params_t>
void FP16Test::test_override(params_t params) {
size_t n = 100;
size_t new_n = 250;
// Scale factor to avoid FP16 overflow. FP16 max value is 65504, and L2² = dim × diff².
// With scale=0.1 and max diff=250: L2² = 4 × (250×0.1)² = 10000 < 65504.
constexpr float scale = 0.1f;
SetUp(params);

// Insert n vectors.
for (size_t i = 0; i < n; i++) {
ASSERT_EQ(GenerateAndAddVector(i, i), 1);
ASSERT_EQ(GenerateAndAddVector(i, i * scale), 1);
}
ASSERT_EQ(VecSimIndex_IndexSize(index), n);

// Override n vectors, the first 100 will be overwritten (deleted first).
for (size_t i = 0; i < n; i++) {
ASSERT_EQ(GenerateAndAddVector(i, i), 0);
ASSERT_EQ(GenerateAndAddVector(i, i * scale), 0);
}

// Add up to new_n vectors.
for (size_t i = n; i < new_n; i++) {
ASSERT_EQ(GenerateAndAddVector(i, i), 1);
ASSERT_EQ(GenerateAndAddVector(i, i * scale), 1);
}

float16 query[dim];
GenerateVector(query, new_n);
GenerateVector(query, new_n * scale);

// Vectors values equals their id, so we expect the larger the id the closest it will be to the
// query.
// Vectors values equals their id (scaled), so we expect the larger the id the closest it will
// be to the query.
auto verify_res = [&](size_t id, double score, size_t index) {
ASSERT_EQ(id, new_n - 1 - index) << "id: " << id << " score: " << score;
float16 a = vecsim_types::FP32_to_FP16(new_n);
float16 b = vecsim_types::FP32_to_FP16(id);
float16 a = vecsim_types::FP32_to_FP16(new_n * scale);
float16 b = vecsim_types::FP32_to_FP16(id * scale);
float diff = vecsim_types::FP16_to_FP32(a) - vecsim_types::FP16_to_FP32(b);
float exp_score = 4 * diff * diff;
ASSERT_EQ(score, exp_score) << "id: " << id << " score: " << score;
// Use tolerance-based comparison due to FP16 precision loss in SVE accumulation.
// FP16 has ~3 decimal digits of precision, so we allow ~0.2% relative tolerance.
float tolerance = std::max(1.0f, std::abs(exp_score) * 0.002f);
ASSERT_NEAR(score, exp_score, tolerance) << "id: " << id << " score: " << score;
};
runTopKSearchTest(index, query, 300, verify_res);
}
Expand Down Expand Up @@ -666,18 +672,21 @@ TEST_F(FP16TieredTest, GetDistanceIPTest) {
template <typename params_t>
void FP16Test::test_batch_iterator_basic(params_t params) {
size_t n = params.initialCapacity;
// Scale factor to avoid FP16 overflow. FP16 max value is 65504, and L2² = dim × diff².
// With scale=0.1 and max diff=250: L2² = 4 × (250×0.1)² = 10000 < 65504.
constexpr float scale = 0.1f;
SetUp(params);

// For every i, add the vector (i,i,i,i) under the label i.
// For every i, add the vector (i*scale, i*scale, i*scale, i*scale) under the label i.
for (size_t i = 0; i < n; i++) {
ASSERT_EQ(GenerateAndAddVector(i, i), 1);
ASSERT_EQ(GenerateAndAddVector(i, i * scale), 1);
}

ASSERT_EQ(VecSimIndex_IndexSize(index), n);

// Query for (n,n,n,n) vector (recall that n-1 is the largest id in te index).
// Query for (n*scale, n*scale, n*scale, n*scale) vector (recall that n-1 is the largest id).
float16 query[dim];
GenerateVector(query, n);
GenerateVector(query, n * scale);

VecSimBatchIterator *batchIterator = VecSimBatchIterator_New(index, query, nullptr);
size_t iteration_num = 0;
Expand Down
10 changes: 6 additions & 4 deletions tests/unit/test_svs_fp16.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2764,6 +2764,8 @@ TYPED_TEST(FP16SVSTieredIndexTest, BatchIterator) {
}
constexpr size_t d = 4;
constexpr size_t n = 1000;
// Keep FP16 squared L2 distances below 65504: 4 * (1000 * 0.1)^2 = 40000.
constexpr float scale = 0.1f;

// Create TieredSVS index instance with a mock queue.
SVSParams params = {
Expand All @@ -2785,16 +2787,16 @@ TYPED_TEST(FP16SVSTieredIndexTest, BatchIterator) {
auto *svs = tiered_index->GetBackendIndex();
auto *flat = tiered_index->GetFlatIndex();

// For every i, add the vector (i,i,i,i) under the label i.
// For every i, add the vector (i*scale, i*scale, i*scale, i*scale) under the label i.
for (size_t i = 0; i < n; i++) {
auto cur = decider(i, n) ? svs : flat;
this->GenerateAndAddVector(cur, d, i, i);
this->GenerateAndAddVector(cur, d, i, i * scale);
}
ASSERT_EQ(VecSimIndex_IndexSize(tiered_index), n) << decider_name;

// Query for (n,n,n,n) vector (recall that n-1 is the largest id in te index).
// Query for the scaled vector; n-1 is the largest label in the index.
float16 query[d];
this->GenerateVector(query, d, n);
this->GenerateVector(query, d, n * scale);

VecSimBatchIterator *batchIterator = VecSimBatchIterator_New(tiered_index, query, nullptr);
size_t iteration_num = 0;
Expand Down
Loading