mirror of
https://github.com/esphome/esphome.git
synced 2025-10-11 14:23:47 +01:00
tweak
This commit is contained in:
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -392,7 +392,7 @@ jobs:
|
|||||||
python3 script/test_build_components.py -e compile -c ${{ matrix.file }}
|
python3 script/test_build_components.py -e compile -c ${{ matrix.file }}
|
||||||
|
|
||||||
test-build-components-splitter:
|
test-build-components-splitter:
|
||||||
name: Split components for intelligent grouping (30 per batch)
|
name: Split components for intelligent grouping (40 weighted per batch)
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
needs:
|
needs:
|
||||||
- common
|
- common
|
||||||
@@ -417,7 +417,7 @@ jobs:
|
|||||||
components='${{ needs.determine-jobs.outputs.changed-components }}'
|
components='${{ needs.determine-jobs.outputs.changed-components }}'
|
||||||
|
|
||||||
echo "Splitting components intelligently..."
|
echo "Splitting components intelligently..."
|
||||||
output=$(python3 script/split_components_for_ci.py --components "$components" --batch-size 30 --output github)
|
output=$(python3 script/split_components_for_ci.py --components "$components" --batch-size 40 --output github)
|
||||||
|
|
||||||
echo "$output" >> $GITHUB_OUTPUT
|
echo "$output" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
@@ -27,6 +27,12 @@ from script.analyze_component_buses import (
|
|||||||
create_grouping_signature,
|
create_grouping_signature,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Weighting for batch creation
|
||||||
|
# Isolated components can't be grouped/merged, so they count as 10x
|
||||||
|
# Groupable components can be merged into single builds, so they count as 1x
|
||||||
|
ISOLATED_WEIGHT = 10
|
||||||
|
GROUPABLE_WEIGHT = 1
|
||||||
|
|
||||||
|
|
||||||
def has_test_files(component_name: str, tests_dir: Path) -> bool:
|
def has_test_files(component_name: str, tests_dir: Path) -> bool:
|
||||||
"""Check if a component has test files.
|
"""Check if a component has test files.
|
||||||
@@ -49,7 +55,7 @@ def has_test_files(component_name: str, tests_dir: Path) -> bool:
|
|||||||
def create_intelligent_batches(
|
def create_intelligent_batches(
|
||||||
components: list[str],
|
components: list[str],
|
||||||
tests_dir: Path,
|
tests_dir: Path,
|
||||||
batch_size: int = 30,
|
batch_size: int = 40,
|
||||||
) -> list[list[str]]:
|
) -> list[list[str]]:
|
||||||
"""Create batches optimized for component grouping.
|
"""Create batches optimized for component grouping.
|
||||||
|
|
||||||
@@ -125,23 +131,34 @@ def create_intelligent_batches(
|
|||||||
|
|
||||||
sorted_groups = sorted(signature_groups.items(), key=sort_key)
|
sorted_groups = sorted(signature_groups.items(), key=sort_key)
|
||||||
|
|
||||||
# Strategy: Sort all components by signature group, then take batch_size at a time
|
# Strategy: Create batches using weighted sizes
|
||||||
# - Components with the same signature stay together (sorted first by signature)
|
# - Isolated components count as 10x (since they can't be grouped/merged)
|
||||||
# - Simply split into batches of batch_size for CI parallelization
|
# - Groupable components count as 1x (can be merged into single builds)
|
||||||
# - Natural grouping occurs because components with same signature are consecutive
|
# - This distributes isolated components across more runners
|
||||||
|
# - Ensures each runner has a good mix of groupable vs isolated components
|
||||||
|
|
||||||
# Flatten all groups in signature-sorted order
|
current_batch = []
|
||||||
# Components within each signature group stay in their natural order
|
current_weight = 0
|
||||||
all_components = [
|
|
||||||
comp for _, group_components in sorted_groups for comp in group_components
|
|
||||||
]
|
|
||||||
|
|
||||||
# Split into batches of batch_size
|
for signature, group_components in sorted_groups:
|
||||||
# Isolated components are included in all_components (in "isolated" group)
|
is_isolated = signature.startswith("isolated_")
|
||||||
# and will be batched together - they just won't be merged during testing
|
weight_per_component = ISOLATED_WEIGHT if is_isolated else GROUPABLE_WEIGHT
|
||||||
for i in range(0, len(all_components), batch_size):
|
|
||||||
batch = all_components[i : i + batch_size]
|
for component in group_components:
|
||||||
batches.append(batch)
|
# Check if adding this component would exceed the batch size
|
||||||
|
if current_weight + weight_per_component > batch_size and current_batch:
|
||||||
|
# Start a new batch
|
||||||
|
batches.append(current_batch)
|
||||||
|
current_batch = []
|
||||||
|
current_weight = 0
|
||||||
|
|
||||||
|
# Add component to current batch
|
||||||
|
current_batch.append(component)
|
||||||
|
current_weight += weight_per_component
|
||||||
|
|
||||||
|
# Don't forget the last batch
|
||||||
|
if current_batch:
|
||||||
|
batches.append(current_batch)
|
||||||
|
|
||||||
return batches
|
return batches
|
||||||
|
|
||||||
@@ -161,8 +178,8 @@ def main() -> int:
|
|||||||
"--batch-size",
|
"--batch-size",
|
||||||
"-b",
|
"-b",
|
||||||
type=int,
|
type=int,
|
||||||
default=30,
|
default=40,
|
||||||
help="Target batch size (default: 30)",
|
help="Target batch size (default: 40, weighted)",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--tests-dir",
|
"--tests-dir",
|
||||||
@@ -213,19 +230,33 @@ def main() -> int:
|
|||||||
# Count actual components being batched
|
# Count actual components being batched
|
||||||
actual_components = sum(len(batch.split()) for batch in batch_strings)
|
actual_components = sum(len(batch.split()) for batch in batch_strings)
|
||||||
|
|
||||||
|
# Re-analyze to get isolated component counts for summary
|
||||||
|
_, non_groupable, _ = analyze_all_components(args.tests_dir)
|
||||||
|
|
||||||
|
# Count isolated vs groupable components
|
||||||
|
all_batched_components = [comp for batch in batches for comp in batch]
|
||||||
|
isolated_count = sum(
|
||||||
|
1
|
||||||
|
for comp in all_batched_components
|
||||||
|
if comp in ISOLATED_COMPONENTS or comp in non_groupable
|
||||||
|
)
|
||||||
|
groupable_count = actual_components - isolated_count
|
||||||
|
|
||||||
print("\n=== Intelligent Batch Summary ===", file=sys.stderr)
|
print("\n=== Intelligent Batch Summary ===", file=sys.stderr)
|
||||||
print(f"Total components requested: {len(components)}", file=sys.stderr)
|
print(f"Total components requested: {len(components)}", file=sys.stderr)
|
||||||
print(f"Components with test files: {actual_components}", file=sys.stderr)
|
print(f"Components with test files: {actual_components}", file=sys.stderr)
|
||||||
|
print(f" - Groupable (weight=1): {groupable_count}", file=sys.stderr)
|
||||||
|
print(f" - Isolated (weight=10): {isolated_count}", file=sys.stderr)
|
||||||
if actual_components < len(components):
|
if actual_components < len(components):
|
||||||
print(
|
print(
|
||||||
f"Components skipped (no test files): {len(components) - actual_components}",
|
f"Components skipped (no test files): {len(components) - actual_components}",
|
||||||
file=sys.stderr,
|
file=sys.stderr,
|
||||||
)
|
)
|
||||||
print(f"Number of batches: {len(batches)}", file=sys.stderr)
|
print(f"Number of batches: {len(batches)}", file=sys.stderr)
|
||||||
print(f"Batch size target: {args.batch_size}", file=sys.stderr)
|
print(f"Batch size target (weighted): {args.batch_size}", file=sys.stderr)
|
||||||
if len(batches) > 0:
|
if len(batches) > 0:
|
||||||
print(
|
print(
|
||||||
f"Average batch size: {actual_components / len(batches):.1f}",
|
f"Average components per batch: {actual_components / len(batches):.1f}",
|
||||||
file=sys.stderr,
|
file=sys.stderr,
|
||||||
)
|
)
|
||||||
print(file=sys.stderr)
|
print(file=sys.stderr)
|
||||||
|
Reference in New Issue
Block a user