From 51b7bf59b3c745fd9eaa11e8e07b91f1d4c01a93 Mon Sep 17 00:00:00 2001 From: Benjamin Pelletier Date: Thu, 8 Oct 2026 11:50:18 +0900 Subject: [PATCH] Add separated_ops.jsonnet --- .../interuss/scd/actions.libsonnet | 10 ++ .../interuss/scd/congested_area.jsonnet | 144 +++--------------- .../interuss/scd/scenarios.libsonnet | 96 ++++++++++++ .../interuss/scd/separated_ops.jsonnet | 49 ++++++ .../interuss/scd/sites.libsonnet | 16 ++ .../interuss/scd/users.libsonnet | 24 ++- 6 files changed, 213 insertions(+), 126 deletions(-) create mode 100644 monitoring/benchmarker/configurations/interuss/scd/scenarios.libsonnet create mode 100644 monitoring/benchmarker/configurations/interuss/scd/separated_ops.jsonnet create mode 100644 monitoring/benchmarker/configurations/interuss/scd/sites.libsonnet diff --git a/monitoring/benchmarker/configurations/interuss/scd/actions.libsonnet b/monitoring/benchmarker/configurations/interuss/scd/actions.libsonnet index be61e0c512..c46609a1d4 100644 --- a/monitoring/benchmarker/configurations/interuss/scd/actions.libsonnet +++ b/monitoring/benchmarker/configurations/interuss/scd/actions.libsonnet @@ -21,4 +21,14 @@ local s2_latlng_rect_part = std.native('s2.latlng_rect_part'); }, }, }, + + delete_subscription: function(name, sub_id) { + name: name, + f3548: { + delete_subscription: { + subscription_id: sub_id, + mode: 'GetDeleteIfExist', + }, + }, + }, } diff --git a/monitoring/benchmarker/configurations/interuss/scd/congested_area.jsonnet b/monitoring/benchmarker/configurations/interuss/scd/congested_area.jsonnet index 490148e4af..608e733593 100644 --- a/monitoring/benchmarker/configurations/interuss/scd/congested_area.jsonnet +++ b/monitoring/benchmarker/configurations/interuss/scd/congested_area.jsonnet @@ -3,141 +3,37 @@ * separate the performance of addressing a leader or a follower. */ -local s2_cell_of = std.native('s2.cell_of'); - // Top-level constants local test_name = 'Congested Area'; local num_uss = 3; local num_nodes = 3; local num_subscriptions = 8; // Should not exceed 10 because of how subscription IDs are constructed below -local users_per_step = 3; -local s2cell = s2_cell_of(34, -118, 13); +local initial_users = 3; local lat_size = 0.00001; local lng_size = 0.00001; -// Imports and constructed values -local actions = import './actions.libsonnet'; -local artifacts = import '../artifacts.libsonnet'; -local environment = import './local_environment.libsonnet'; -local flights = import '../flights.libsonnet'; -local loads = import '../loads.libsonnet'; +local scenarios = import './scenarios.libsonnet'; local users = import './users.libsonnet'; +local s2_cell_of = std.native('s2.cell_of'); local s2_inscribed_latlng_rect = std.native('s2.inscribed_latlng_rect'); -local s2_expand_latlng_rect = std.native('s2.expand_latlng_rect'); -local rect = s2_inscribed_latlng_rect(s2cell); - -{ - resources: { - resource_declarations: { - utm_auth: environment.dummy_oauth_resource_declaration, - } + { - ['uss%d_dss_pool' % uss]: environment.dss_instances_resource_declaration( - std.range(uss - 1, uss - 1), std.range(0, num_nodes - 1), 'utm_auth' - ) for uss in std.range(1, num_uss) - }, - }, - - actions: [ - { - name: 'Generate intermediate artifacts', - generate_artifacts: { - subfolder: 'f"intermediate{action_invocation}"', - defined_artifact_indices: [0, 1, 2], +local rect = s2_inscribed_latlng_rect(s2_cell_of(34, -118, 13)); + +scenarios.flight_planner_search( + test_name, num_nodes, initial_users, + [ + [ + { + name: 'FPU%d' % uss, + flight_planner: users.basic_flight_planner( + ['uss%d_dss_pool' % uss], '3bdb0b88-a522-4286-9499-060e56c953bb', rect, lat_size, lng_size + ), }, - }, - ] + [ - actions.create_subscription( - 'Create subscription %d' % sub_index, - '3bdb0b88-a522-4286-9499-%d60e56c953bb' % (sub_index - 1), - rect, - ) for sub_index in std.range(1, num_subscriptions) - ] + [ - { - name: 'Delete subscription %d' % sub_index, - f3548: { - delete_subscription: { - subscription_id: '3bdb0b88-a522-4286-9499-%d60e56c953bb' % (sub_index - 1), - mode: 'GetDeleteIfExist', - }, - }, - } for sub_index in std.range(1, num_subscriptions) + ] for uss in std.range(1, num_uss) ], - - user_types: [ + [ { - name: 'FPU%d' % uss, // Flight planner user using DSS instance from uss - flight_planner: { - flight_generation: { - independent_time_location_shape: { - time: { - fixed_spacing: '36s', - uniform_random_spacing: '7.2s', - }, - location: flights.laglng_rect_location(s2_expand_latlng_rect(rect, -lat_size, -lng_size)), - shape: flights.latlng_rect_shape(lat_size, lng_size), - }, - }, - flight_execution: { - end_flight_after_start: '5s', - }, - scd_behavior: users.basic_scd_behavior(['uss%d_dss_pool' % uss], '3bdb0b88-a522-4286-9499-060e56c953bb', '20s', '10s'), - }, - } for uss in std.range(1, num_uss) - ], - - loads: [ - { - name: 'Flight planner ramp for USS %d' % uss, - user_ramp: { - user_type: 'FPU%d' % uss, - initial_users: users_per_step, - additional_users_per_step: users_per_step, - random_seed: 1234, - throughput_stability_criteria: loads.normal_flights_stability_criteria, - throughput_instability_criteria: loads.normal_flights_instability_criteria, - step_completion_criteria: loads.normal_flights_completion_criteria, - load_completion_criteria: { - any_of: [ - { - throughput_lower_than_peak: { - operations: ['workflow.flight_planner.flight'], - fraction_of_peak: 0.7, - }, - }, - ], - }, - }, - } for uss in std.range(1, num_uss) - ], - - scenarios: [ - { - name: 'DSS instance %d' % uss, - [if uss == 1 then "setup"]: ['Create subscription %d' % sub_index for sub_index in std.range(1, num_subscriptions)], - load: 'Flight planner ramp for USS %d' % uss, - teardown: - (if uss < num_uss then ['Generate intermediate artifacts'] else []) - + (if uss == num_uss then ['Delete subscription %d' % sub_index for sub_index in std.range(1, num_subscriptions)] else []), - } for uss in std.range(1, num_uss) - ], - - artifacts: [ - { - raw_report: { - name: 'report', - }, - }, - artifacts.scd_flights_timeline, - artifacts.throughput_latency_plots( - 'scalability_curve', - test_name, - num_uss, - num_uss, - ), - { - usslogset: { - include_headers: ['Authorization'], - }, - }, + id: '3bdb0b88-a522-4286-9499-%d60e56c953bb' % (sub_index - 1), + rect: rect, + } for sub_index in std.range(1, num_subscriptions) ], -} +) diff --git a/monitoring/benchmarker/configurations/interuss/scd/scenarios.libsonnet b/monitoring/benchmarker/configurations/interuss/scd/scenarios.libsonnet new file mode 100644 index 0000000000..0d933f29ac --- /dev/null +++ b/monitoring/benchmarker/configurations/interuss/scd/scenarios.libsonnet @@ -0,0 +1,96 @@ +local actions = import './actions.libsonnet'; +local artifacts = import '../artifacts.libsonnet'; +local environment = import './local_environment.libsonnet'; +local loads = import '../loads.libsonnet'; + +{ + /* Apply a flight planner user-count search to each DSS instance in turn. user_types_by_uss is an + * array of arrays of user specifications, one array per USS. Users are assigned + * round-robin within each array; repeated entries can weight traffic toward busy sites. + * subscriptions is an array of {id, rect} objects, established before the first search + * and removed after the last. + */ + flight_planner_search: function(test_name, num_nodes, initial_users, user_types_by_uss, subscriptions) { + local num_uss = std.length(user_types_by_uss), + local subscription_indices = std.range(0, std.length(subscriptions) - 1), + + resources: { + resource_declarations: { + utm_auth: environment.dummy_oauth_resource_declaration, + } + { + ['uss%d_dss_pool' % uss]: environment.dss_instances_resource_declaration( + [uss - 1], std.range(0, num_nodes - 1), 'utm_auth' + ) for uss in std.range(1, num_uss) + }, + }, + + actions: [ + { + name: 'Generate intermediate artifacts', + generate_artifacts: { + subfolder: 'f"intermediate{action_invocation}"', + defined_artifact_indices: [0, 1, 2], + }, + }, + ] + [ + actions.create_subscription( + 'Create subscription %d' % (i + 1), subscriptions[i].id, subscriptions[i].rect + ) for i in subscription_indices + ] + [ + actions.delete_subscription( + 'Delete subscription %d' % (i + 1), subscriptions[i].id + ) for i in subscription_indices + ], + + user_types: std.flattenArrays(user_types_by_uss), + + loads: [ + local user_types = user_types_by_uss[uss - 1]; + { + name: 'Flight planner search for USS %d' % uss, + user_search: { + user_types: [u.name for u in user_types], + initial_users: initial_users, + user_expansion_ratio: 2, + random_seed: 1234, + throughput_stability_criteria: loads.normal_flights_stability_criteria, + throughput_instability_criteria: loads.normal_flights_instability_criteria, + step_completion_criteria: loads.normal_flights_completion_criteria, + search_completion_criteria: { + adjacency_user_count: 2, + consecutive_unstable_user_counts: 3, + consecutive_stable_user_counts: 3, + maximum_left_side_spacing: 0.2, + max_throughput_adjacent_user_counts: 2, + }, + }, + } for uss in std.range(1, num_uss) + ], + + scenarios: [ + { + name: 'DSS instance %d' % uss, + [if uss == 1 then 'setup']: ['Create subscription %d' % (i + 1) for i in subscription_indices], + load: 'Flight planner search for USS %d' % uss, + teardown: + (if uss < num_uss then ['Generate intermediate artifacts'] else []) + + (if uss == num_uss then ['Delete subscription %d' % (i + 1) for i in subscription_indices] else []), + } for uss in std.range(1, num_uss) + ], + + artifacts: [ + { + raw_report: { + name: 'report', + }, + }, + artifacts.scd_flights_timeline, + artifacts.throughput_latency_plots('scalability_curve', test_name, num_uss, num_uss), + { + usslogset: { + include_headers: ['Authorization'], + }, + }, + ], + }, +} diff --git a/monitoring/benchmarker/configurations/interuss/scd/separated_ops.jsonnet b/monitoring/benchmarker/configurations/interuss/scd/separated_ops.jsonnet new file mode 100644 index 0000000000..4054fbcff2 --- /dev/null +++ b/monitoring/benchmarker/configurations/interuss/scd/separated_ops.jsonnet @@ -0,0 +1,49 @@ +/* Widely separated SCD flight operations, corresponding to the intent of + * "Global Throughput (Multi Site) Test Part 1": + * https://github.com/interuss/dss/issues/1541#issuecomment-4846753840 + * + * Distribute planners across 116 sites with one subscription and one OVN coordination + * group per site. Sites share neither subscriptions nor operational intents, while + * planners at the same site still contend on its subscription and may overlap. + * As in congested_area, load one DSS instance at a time, selecting its nodes randomly. + */ + +local test_name = 'Separated Operations'; +local num_uss = 3; +local num_nodes = 3; +local num_sites = 116; +local initial_users = 16; +local site_columns = 11; +local site_spacing_cells = 4; +local lat_size = 0.00001; +local lng_size = 0.00001; + +local scenarios = import './scenarios.libsonnet'; +local sites = import './sites.libsonnet'; +local users = import './users.libsonnet'; +local s2_cell_of = std.native('s2.cell_of'); +// Level 11 gives each site a several-kilometer operating area. Four-cell spacing +// leaves gaps between sites; S2 offsets avoid assuming a fixed km-per-degree scale. +local rects = sites.grid(s2_cell_of(34, -118, 11), num_sites, site_columns, site_spacing_cells); +local subscriptions = [ + { + id: '48ff9727-d204-4cc3-9b7a-%012x' % i, + rect: rects[i], + } for i in std.range(0, num_sites - 1) +]; + +scenarios.flight_planner_search( + test_name, num_nodes, initial_users, + [ + [ + { + name: 'FPU%d_s%d' % [uss, i + 1], + flight_planner: users.basic_flight_planner( + ['uss%d_dss_pool' % uss], subscriptions[i].id, rects[i], lat_size, lng_size, + 'site%d' % (i + 1), + ), + } for i in std.range(0, num_sites - 1) + ] for uss in std.range(1, num_uss) + ], + subscriptions, +) diff --git a/monitoring/benchmarker/configurations/interuss/scd/sites.libsonnet b/monitoring/benchmarker/configurations/interuss/scd/sites.libsonnet new file mode 100644 index 0000000000..9ec21c0835 --- /dev/null +++ b/monitoring/benchmarker/configurations/interuss/scd/sites.libsonnet @@ -0,0 +1,16 @@ +local s2_offset_cell = std.native('s2.offset_cell'); +local s2_inscribed_latlng_rect = std.native('s2.inscribed_latlng_rect'); + +{ + /* Generate operating rectangles on a grid of S2 cells at the origin cell's level. + * spacing_cells > 1 leaves unused cells between sites. The rectangles are strictly + * inside their cells so subscriptions at different sites do not overlap. + */ + grid: function(origin_cell, num_sites, columns, spacing_cells) [ + s2_inscribed_latlng_rect(s2_offset_cell( + origin_cell, + (i % columns) * spacing_cells, + std.floor(i / columns) * spacing_cells, + )) for i in std.range(0, num_sites - 1) + ], +} diff --git a/monitoring/benchmarker/configurations/interuss/scd/users.libsonnet b/monitoring/benchmarker/configurations/interuss/scd/users.libsonnet index 7dcecaecea..6757edb07e 100644 --- a/monitoring/benchmarker/configurations/interuss/scd/users.libsonnet +++ b/monitoring/benchmarker/configurations/interuss/scd/users.libsonnet @@ -1,5 +1,8 @@ +local flights = import '../flights.libsonnet'; +local s2_expand_latlng_rect = std.native('s2.expand_latlng_rect'); + { - basic_scd_behavior: function(dss_pool, sub_id, accept_notice, activate_notice) { + basic_scd_behavior: function(dss_pool, sub_id, accept_notice, activate_notice, coordination_group='cluster1') { dss_pool: dss_pool, dss_selection_strategy: 'Random', subscription_strategy: { @@ -8,7 +11,7 @@ }, }, op_intent_ref_creation_strategy: { - ovn_coordination_group: 'cluster1', + ovn_coordination_group: coordination_group, coordinate_requested_ovns: true, retries: 2, accept_before_flight_start: accept_notice, @@ -20,4 +23,21 @@ }, }, + // Keep the whole flight footprint inside the subscription's rectangle. + basic_flight_planner: function(dss_pool, sub_id, rect, lat_size, lng_size, coordination_group='cluster1') { + flight_generation: { + independent_time_location_shape: { + time: { + fixed_spacing: '36s', + uniform_random_spacing: '7.2s', + }, + location: flights.laglng_rect_location(s2_expand_latlng_rect(rect, -lat_size, -lng_size)), + shape: flights.latlng_rect_shape(lat_size, lng_size), + }, + }, + flight_execution: { + end_flight_after_start: '5s', + }, + scd_behavior: $.basic_scd_behavior(dss_pool, sub_id, '20s', '10s', coordination_group), + }, }