@@ -98,16 +98,30 @@ def setup(self):
9898 # least one CPU available for it. Memory is intentionally uncapped for
9999 # every role; the harness reports actual RSS instead.
100100 required = self .generator_core_count + len (PROCESSOR_ROLES ) + 1
101- if len (cores ) < required :
101+ shared_infrastructure = len (cores ) < required and self .args .allow_shared_infrastructure
102+ if len (cores ) < required and not shared_infrastructure :
102103 raise RuntimeError (
103104 f"dedicated placement needs { required } CPUs: { self .generator_core_count } "
104105 f"traffic-generator CPUs plus one CPU for each of { len (PROCESSOR_ROLES )} processors "
105106 "and at least one backend CPU; "
106107 f"only { len (cores )} are available"
107108 )
108- generators = cores [:self .generator_core_count ]
109- component_cores = dict (zip (PROCESSOR_ROLES , cores [self .generator_core_count :self .generator_core_count + len (PROCESSOR_ROLES )]))
110- backend_cores = cores [self .generator_core_count + len (PROCESSOR_ROLES ):]
109+ if shared_infrastructure :
110+ if len (cores ) < len (PROCESSOR_ROLES ):
111+ raise RuntimeError (
112+ f"shared-infrastructure smoke placement still needs { len (PROCESSOR_ROLES )} CPUs "
113+ f"for distinct processor assignments; only { len (cores )} are available"
114+ )
115+ # Correctness smoke mode for small CI runners. The four evaluated
116+ # processors remain distinct, while generator/backend infrastructure
117+ # may overlap them. Results from this placement are not capacity data.
118+ generators = cores [:min (self .generator_core_count , len (cores ))]
119+ component_cores = dict (zip (PROCESSOR_ROLES , cores [:len (PROCESSOR_ROLES )]))
120+ backend_cores = cores
121+ else :
122+ generators = cores [:self .generator_core_count ]
123+ component_cores = dict (zip (PROCESSOR_ROLES , cores [self .generator_core_count :self .generator_core_count + len (PROCESSOR_ROLES )]))
124+ backend_cores = cores [self .generator_core_count + len (PROCESSOR_ROLES ):]
111125 for suffix in ("data" , "control" ):
112126 network = self .prefix + "-" + suffix
113127 self .command ("network" , "create" , "--internal" , network )
@@ -191,6 +205,7 @@ def generator_ready():
191205 "warmup_seconds" : self .args .warmup , "observation_seconds" : self .observation_seconds ,
192206 "generator_cores" : generators , "component_cores" : component_cores ,
193207 "backend_cores" : backend_cores ,
208+ "placement" : "shared-infrastructure-smoke" if shared_infrastructure else "exclusive-capacity" ,
194209 "measurement_clock" : "CLOCK_MONOTONIC, shared host kernel" , "max_source_skew_windows" : 1024 , "pdata_channel_capacity" : 8 , "exporter_max_in_flight" : 1 ,
195210 "transport" : "standard OTLP/HTTP protobuf, uncompressed, persistent connections" ,
196211 "data_interfaces" : self .data_ifaces ,
@@ -461,6 +476,8 @@ def main():
461476 help = "target signals/s per source to sweep using OTAP's traffic_generator receiver" )
462477 parser .add_argument ("--generator-cores" , type = int , default = 4 ,
463478 help = "OTAP traffic_generator pipeline workers per source; each measured processor gets one dedicated CPU and the backend gets all remaining CPUs" )
479+ parser .add_argument ("--allow-shared-infrastructure" , action = "store_true" ,
480+ help = "CI correctness smoke mode: keep processors on distinct CPUs but allow generator/backend overlap; results are not capacity measurements" )
464481 parser .add_argument ("--profile-cpu" , action = "store_true" , help = "exclusive synchronous processor thread CPU scopes" )
465482 parser .add_argument ("--account-cpu" , action = "store_true" , help = "match CPU/input boundaries with warmup and final drains; implied by --profile-cpu" )
466483 parser .add_argument ("--perf-command" , default = "" , help = "optional host sampler, e.g. 'sudo -n perf'; records four worker processes" )
0 commit comments