|
| 1 | +# Copyright 2026 PerfKitBenchmarker Authors. All rights reserved. |
| 2 | +# |
| 3 | +# Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | +# you may not use this file except in compliance with the License. |
| 5 | +# You may obtain a copy of the License at |
| 6 | +# |
| 7 | +# http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | +# |
| 9 | +# Unless required by applicable law or agreed to in writing, software |
| 10 | +# distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | +# See the License for the specific language governing permissions and |
| 13 | +# limitations under the License. |
| 14 | + |
| 15 | +r"""Runs Conversational Analytics performance benchmarks using BigQuery geminidataanalytics.""" |
| 16 | + |
| 17 | +import logging |
| 18 | + |
| 19 | +from absl import flags |
| 20 | +from perfkitbenchmarker import configs |
| 21 | +from perfkitbenchmarker import edw_benchmark_results_aggregator as results_aggregator |
| 22 | +from perfkitbenchmarker import errors |
| 23 | +from perfkitbenchmarker import vm_util |
| 24 | + |
| 25 | +BENCHMARK_NAME = 'edw_conversational_analytics_benchmark' |
| 26 | + |
| 27 | +BENCHMARK_CONFIG = """ |
| 28 | +edw_conversational_analytics_benchmark: |
| 29 | + description: Conversational Analytics performance benchmark using BigQuery. |
| 30 | + edw_service: |
| 31 | + type: bigquery |
| 32 | + cluster_identifier: _cluster_id_ |
| 33 | + endpoint: cluster.endpoint |
| 34 | + db: _database_name_ |
| 35 | + user: _username_ |
| 36 | + password: _password_ |
| 37 | + vm_groups: |
| 38 | + client: |
| 39 | + vm_spec: *default_dual_core |
| 40 | +""" |
| 41 | + |
| 42 | +_DATASET = flags.DEFINE_enum( |
| 43 | + 'dataset', |
| 44 | + 'ecomm', |
| 45 | + ['ecomm', 'call_center'], |
| 46 | + 'The dataset to run: ecomm or call_center.', |
| 47 | +) |
| 48 | + |
| 49 | +FLAGS = flags.FLAGS |
| 50 | + |
| 51 | + |
| 52 | +def GetConfig(user_config): |
| 53 | + return configs.LoadConfig(BENCHMARK_CONFIG, user_config, BENCHMARK_NAME) |
| 54 | + |
| 55 | + |
| 56 | +def CheckPrerequisites(_): |
| 57 | + if not FLAGS.bq_ca_agent: |
| 58 | + raise errors.Config.InvalidValue('Missing required flag: --bq_ca_agent') |
| 59 | + |
| 60 | + |
| 61 | +def Prepare(benchmark_spec): |
| 62 | + """Install script execution environment on the client vm.""" |
| 63 | + benchmark_spec.always_call_cleanup = True |
| 64 | + edw_service_instance = benchmark_spec.edw_service |
| 65 | + |
| 66 | + # Assign provisioned attributes |
| 67 | + query_client = edw_service_instance.GetClientInterface() |
| 68 | + query_client.SetProvisionedAttributes(benchmark_spec) |
| 69 | + |
| 70 | + ca_client = edw_service_instance.GetConversationalAnalyticsClientInterface() |
| 71 | + ca_client.SetProvisionedAttributes(benchmark_spec) |
| 72 | + benchmark_spec.ca_client = ca_client |
| 73 | + |
| 74 | + # Prepare the client environment for both clients |
| 75 | + query_client.Prepare('edw_common') |
| 76 | + ca_client.Prepare('edw_common') |
| 77 | + |
| 78 | + |
| 79 | +def _RunConversationalQuery(q, ca_client, ca_iteration_performance): |
| 80 | + """Ask the conversational analytics question and record performance.""" |
| 81 | + execution_time, metadata = ca_client.ExecuteQuery(q.question) |
| 82 | + ca_iteration_performance.add_query_performance( |
| 83 | + q.question, execution_time, metadata |
| 84 | + ) |
| 85 | + |
| 86 | + |
| 87 | +def _RunGroundTruthQuery(q, query_client, gt_iteration_performance): |
| 88 | + """Execute ground truth SQL and record performance.""" |
| 89 | + sql_file_name = f'{q.db_id}_gt.sql' |
| 90 | + vm_util.CreateRemoteFile( |
| 91 | + query_client.client_vm, q.ground_truth_sql, sql_file_name |
| 92 | + ) |
| 93 | + gt_execution_time, gt_metadata = query_client.ExecuteQuery( |
| 94 | + sql_file_name, print_results=True |
| 95 | + ) |
| 96 | + gt_metadata['question'] = q.question |
| 97 | + gt_metadata['ground_truth_sql'] = q.ground_truth_sql |
| 98 | + if 'query_results' in gt_metadata: |
| 99 | + gt_metadata['ground_truth_data'] = gt_metadata['query_results'] |
| 100 | + else: |
| 101 | + logging.warning( |
| 102 | + 'No query results found in ground truth query execution' |
| 103 | + ' metadata: %s', |
| 104 | + gt_metadata, |
| 105 | + ) |
| 106 | + gt_iteration_performance.add_query_performance( |
| 107 | + f'{q.question}_gt', gt_execution_time, gt_metadata |
| 108 | + ) |
| 109 | + |
| 110 | + |
| 111 | +def _RunIteration( |
| 112 | + iteration_id, |
| 113 | + question_list, |
| 114 | + ca_client, |
| 115 | + query_client, |
| 116 | + ca_expected_queries, |
| 117 | + gt_expected_queries, |
| 118 | +): |
| 119 | + """Run a single iteration of the benchmark suite.""" |
| 120 | + ca_iteration_performance = results_aggregator.EdwPowerIterationPerformance( |
| 121 | + iteration_id=iteration_id, total_queries=len(ca_expected_queries) |
| 122 | + ) |
| 123 | + gt_iteration_performance = results_aggregator.EdwPowerIterationPerformance( |
| 124 | + iteration_id=iteration_id, total_queries=len(gt_expected_queries) |
| 125 | + ) |
| 126 | + |
| 127 | + for q in question_list: |
| 128 | + _RunConversationalQuery(q, ca_client, ca_iteration_performance) |
| 129 | + _RunGroundTruthQuery(q, query_client, gt_iteration_performance) |
| 130 | + |
| 131 | + return ca_iteration_performance, gt_iteration_performance |
| 132 | + |
| 133 | + |
| 134 | +def Run(benchmark_spec): |
| 135 | + """Run phase executes conversational queries and collects latencies and metadata.""" |
| 136 | + edw_service_instance = benchmark_spec.edw_service |
| 137 | + query_client = edw_service_instance.GetClientInterface() |
| 138 | + ca_client = benchmark_spec.ca_client |
| 139 | + |
| 140 | + # Load dataset |
| 141 | + question_list = [ |
| 142 | + q |
| 143 | + for q in edw_service_instance.GetConversationalAnalyticsQuestionList() |
| 144 | + if q.db_id == _DATASET.value |
| 145 | + ] |
| 146 | + |
| 147 | + # Determine expected queries (both the question and the ground truth) |
| 148 | + ca_expected_queries = [q.question for q in question_list] |
| 149 | + gt_expected_queries = [f'{q.question}_gt' for q in question_list] |
| 150 | + |
| 151 | + # Accumulator for the entire benchmark's performance |
| 152 | + ca_performance = results_aggregator.EdwBenchmarkPerformance( |
| 153 | + total_iterations=FLAGS.edw_suite_iterations, |
| 154 | + expected_queries=ca_expected_queries, |
| 155 | + ) |
| 156 | + gt_query_performance = results_aggregator.EdwBenchmarkPerformance( |
| 157 | + total_iterations=FLAGS.edw_suite_iterations, |
| 158 | + expected_queries=gt_expected_queries, |
| 159 | + ) |
| 160 | + |
| 161 | + # Multiple iterations of the suite |
| 162 | + for i in range(1, FLAGS.edw_suite_iterations + 1): |
| 163 | + ca_iter_perf, gt_iter_perf = _RunIteration( |
| 164 | + iteration_id=str(i), |
| 165 | + question_list=question_list, |
| 166 | + ca_client=ca_client, |
| 167 | + query_client=query_client, |
| 168 | + ca_expected_queries=ca_expected_queries, |
| 169 | + gt_expected_queries=gt_expected_queries, |
| 170 | + ) |
| 171 | + ca_performance.add_iteration_performance(ca_iter_perf) |
| 172 | + gt_query_performance.add_iteration_performance(gt_iter_perf) |
| 173 | + |
| 174 | + # Execution complete, generate results only if the benchmark was successful. |
| 175 | + if not gt_query_performance.is_successful(): |
| 176 | + raise errors.Benchmarks.RunError( |
| 177 | + 'Ground Truth query execution failed.' |
| 178 | + ) |
| 179 | + |
| 180 | + benchmark_metadata = { |
| 181 | + 'agent': FLAGS.bq_ca_agent, |
| 182 | + 'dataset': _DATASET.value, |
| 183 | + } |
| 184 | + benchmark_metadata.update(edw_service_instance.GetMetadata()) |
| 185 | + |
| 186 | + results = [] |
| 187 | + results.extend( |
| 188 | + ca_performance.get_all_query_performance_samples( |
| 189 | + metadata=benchmark_metadata |
| 190 | + ) |
| 191 | + ) |
| 192 | + if ca_performance.is_successful(): |
| 193 | + results.extend( |
| 194 | + ca_performance.get_queries_geomean_performance_samples( |
| 195 | + metadata=benchmark_metadata |
| 196 | + ) |
| 197 | + ) |
| 198 | + results.extend( |
| 199 | + gt_query_performance.get_all_query_performance_samples( |
| 200 | + metadata=benchmark_metadata |
| 201 | + ) |
| 202 | + ) |
| 203 | + results.extend( |
| 204 | + gt_query_performance.get_queries_geomean_performance_samples( |
| 205 | + metadata=benchmark_metadata |
| 206 | + ) |
| 207 | + ) |
| 208 | + |
| 209 | + return results |
| 210 | + |
| 211 | + |
| 212 | +def Cleanup(benchmark_spec): |
| 213 | + benchmark_spec.edw_service.Cleanup() |
0 commit comments