chore(internal): minimal fix for PeriodicThread.awake() after stop()#18040
Conversation
Codeowners resolved as |
Performance SLOsComparing candidate unknown (unknown) with baseline main (56e77c7) 📈 Performance Regressions (2 suites)📈 iastaspects - 118/118✅ add_aspectTime: ✅ 103.990µs (SLO: <130.000µs 📉 -20.0%) vs baseline: +3.2% Memory: ✅ 43.981MB (SLO: <46.000MB -4.4%) vs baseline: +5.1% ✅ add_inplace_aspectTime: ✅ 101.802µs (SLO: <130.000µs 📉 -21.7%) vs baseline: +0.3% Memory: ✅ 43.851MB (SLO: <46.000MB -4.7%) vs baseline: +4.7% ✅ add_inplace_noaspectTime: ✅ 28.216µs (SLO: <40.000µs 📉 -29.5%) vs baseline: +0.1% Memory: ✅ 43.900MB (SLO: <46.000MB -4.6%) vs baseline: +4.9% ✅ add_noaspectTime: ✅ 49.541µs (SLO: <70.000µs 📉 -29.2%) vs baseline: +0.2% Memory: ✅ 43.821MB (SLO: <46.000MB -4.7%) vs baseline: +4.3% ✅ bytearray_aspectTime: ✅ 261.040µs (SLO: <400.000µs 📉 -34.7%) vs baseline: +0.5% Memory: ✅ 43.954MB (SLO: <46.000MB -4.4%) vs baseline: +5.0% ✅ bytearray_extend_aspectTime: ✅ 651.463µs (SLO: <800.000µs 📉 -18.6%) vs baseline: -0.4% Memory: ✅ 43.925MB (SLO: <46.000MB -4.5%) vs baseline: +5.0% ✅ bytearray_extend_noaspectTime: ✅ 269.410µs (SLO: <400.000µs 📉 -32.6%) vs baseline: +0.3% Memory: ✅ 43.895MB (SLO: <46.000MB -4.6%) vs baseline: +4.8% ✅ bytearray_noaspectTime: ✅ 143.036µs (SLO: <300.000µs 📉 -52.3%) vs baseline: -0.4% Memory: ✅ 43.973MB (SLO: <46.000MB -4.4%) vs baseline: +4.6% ✅ bytes_aspectTime: ✅ 224.200µs (SLO: <300.000µs 📉 -25.3%) vs baseline: -1.1% Memory: ✅ 43.910MB (SLO: <46.000MB -4.5%) vs baseline: +4.8% ✅ bytes_noaspectTime: ✅ 136.419µs (SLO: <200.000µs 📉 -31.8%) vs baseline: +0.4% Memory: ✅ 43.927MB (SLO: <46.000MB -4.5%) vs baseline: +4.8% ✅ bytesio_aspectTime: ✅ 3.823ms (SLO: <5.000ms 📉 -23.5%) vs baseline: +0.5% Memory: ✅ 43.942MB (SLO: <46.000MB -4.5%) vs baseline: +5.1% ✅ bytesio_noaspectTime: ✅ 318.400µs (SLO: <420.000µs 📉 -24.2%) vs baseline: -0.8% Memory: ✅ 43.923MB (SLO: <46.000MB -4.5%) vs baseline: +4.8% ✅ capitalize_aspectTime: ✅ 90.294µs (SLO: <300.000µs 📉 -69.9%) vs baseline: +1.2% Memory: ✅ 44.006MB (SLO: <46.000MB -4.3%) vs baseline: +5.1% ✅ capitalize_noaspectTime: ✅ 254.559µs (SLO: <300.000µs 📉 -15.1%) vs baseline: +0.4% Memory: ✅ 43.924MB (SLO: <46.000MB -4.5%) vs baseline: +4.7% ✅ casefold_aspectTime: ✅ 92.745µs (SLO: <500.000µs 📉 -81.5%) vs baseline: +3.4% Memory: ✅ 43.925MB (SLO: <46.000MB -4.5%) vs baseline: +4.7% ✅ casefold_noaspectTime: ✅ 315.364µs (SLO: <500.000µs 📉 -36.9%) vs baseline: +2.6% Memory: ✅ 43.850MB (SLO: <46.000MB -4.7%) vs baseline: +4.8% ✅ decode_aspectTime: ✅ 86.556µs (SLO: <100.000µs 📉 -13.4%) vs baseline: -0.2% Memory: ✅ 43.758MB (SLO: <46.000MB -4.9%) vs baseline: +4.6% ✅ decode_noaspectTime: ✅ 156.499µs (SLO: <210.000µs 📉 -25.5%) vs baseline: +0.4% Memory: ✅ 43.907MB (SLO: <46.000MB -4.6%) vs baseline: +5.0% ✅ encode_aspectTime: ✅ 84.746µs (SLO: <200.000µs 📉 -57.6%) vs baseline: -0.3% Memory: ✅ 43.815MB (SLO: <46.000MB -4.8%) vs baseline: +4.6% ✅ encode_noaspectTime: ✅ 144.114µs (SLO: <200.000µs 📉 -27.9%) vs baseline: -0.1% Memory: ✅ 43.866MB (SLO: <46.000MB -4.6%) vs baseline: +4.6% ✅ format_aspectTime: ✅ 14.717ms (SLO: <19.200ms 📉 -23.4%) vs baseline: ~same Memory: ✅ 44.043MB (SLO: <46.000MB -4.3%) vs baseline: +5.1% ✅ format_map_aspectTime: ✅ 16.502ms (SLO: <21.500ms 📉 -23.2%) vs baseline: +0.2% Memory: ✅ 43.865MB (SLO: <46.000MB -4.6%) vs baseline: +4.7% ✅ format_map_noaspectTime: ✅ 369.529µs (SLO: <500.000µs 📉 -26.1%) vs baseline: -0.4% Memory: ✅ 43.838MB (SLO: <46.000MB -4.7%) vs baseline: +4.6% ✅ format_noaspectTime: ✅ 315.400µs (SLO: <500.000µs 📉 -36.9%) vs baseline: ~same Memory: ✅ 43.879MB (SLO: <46.000MB -4.6%) vs baseline: +4.7% ✅ index_aspectTime: ✅ 120.509µs (SLO: <300.000µs 📉 -59.8%) vs baseline: -2.5% Memory: ✅ 43.782MB (SLO: <46.000MB -4.8%) vs baseline: +4.6% ✅ index_noaspectTime: ✅ 41.273µs (SLO: <300.000µs 📉 -86.2%) vs baseline: +0.5% Memory: ✅ 43.848MB (SLO: <46.000MB -4.7%) vs baseline: +5.1% ✅ join_aspectTime: ✅ 210.904µs (SLO: <300.000µs 📉 -29.7%) vs baseline: +0.5% Memory: ✅ 43.967MB (SLO: <46.000MB -4.4%) vs baseline: +5.2% ✅ join_noaspectTime: ✅ 141.349µs (SLO: <300.000µs 📉 -52.9%) vs baseline: -0.3% Memory: ✅ 43.926MB (SLO: <46.000MB -4.5%) vs baseline: +5.0% ✅ ljust_aspectTime: ✅ 498.079µs (SLO: <700.000µs 📉 -28.8%) vs baseline: -0.3% Memory: ✅ 43.934MB (SLO: <46.000MB -4.5%) vs baseline: +4.9% ✅ ljust_noaspectTime: ✅ 256.226µs (SLO: <300.000µs 📉 -14.6%) vs baseline: -0.5% Memory: ✅ 43.877MB (SLO: <46.000MB -4.6%) vs baseline: +4.8% ✅ lower_aspectTime: ✅ 311.720µs (SLO: <500.000µs 📉 -37.7%) vs baseline: -0.1% Memory: ✅ 43.909MB (SLO: <46.000MB -4.5%) vs baseline: +4.9% ✅ lower_noaspectTime: ✅ 237.774µs (SLO: <300.000µs 📉 -20.7%) vs baseline: +0.8% Memory: ✅ 43.908MB (SLO: <46.000MB -4.5%) vs baseline: +4.8% ✅ lstrip_aspectTime: ✅ 0.341ms (SLO: <3.000ms 📉 -88.6%) vs baseline: 📈 +26.4% Memory: ✅ 43.995MB (SLO: <46.000MB -4.4%) vs baseline: +5.0% ✅ lstrip_noaspectTime: ✅ 0.177ms (SLO: <3.000ms 📉 -94.1%) vs baseline: +0.6% Memory: ✅ 43.931MB (SLO: <46.000MB -4.5%) vs baseline: +4.9% ✅ modulo_aspectTime: ✅ 14.396ms (SLO: <18.750ms 📉 -23.2%) vs baseline: +0.3% Memory: ✅ 43.988MB (SLO: <46.000MB -4.4%) vs baseline: +5.3% ✅ modulo_aspect_for_bytearray_bytearrayTime: ✅ 14.799ms (SLO: <19.350ms 📉 -23.5%) vs baseline: -0.6% Memory: ✅ 43.856MB (SLO: <46.000MB -4.7%) vs baseline: +4.3% ✅ modulo_aspect_for_bytesTime: ✅ 14.519ms (SLO: <18.900ms 📉 -23.2%) vs baseline: +0.3% Memory: ✅ 44.063MB (SLO: <46.000MB -4.2%) vs baseline: +5.0% ✅ modulo_aspect_for_bytes_bytearrayTime: ✅ 14.704ms (SLO: <19.150ms 📉 -23.2%) vs baseline: -0.1% Memory: ✅ 44.084MB (SLO: <46.000MB -4.2%) vs baseline: +5.2% ✅ modulo_noaspectTime: ✅ 0.364ms (SLO: <3.000ms 📉 -87.9%) vs baseline: -0.1% Memory: ✅ 43.944MB (SLO: <46.000MB -4.5%) vs baseline: +5.1% ✅ replace_aspectTime: ✅ 19.156ms (SLO: <24.000ms 📉 -20.2%) vs baseline: +3.2% Memory: ✅ 43.928MB (SLO: <46.000MB -4.5%) vs baseline: +4.8% ✅ replace_noaspectTime: ✅ 288.299µs (SLO: <400.000µs 📉 -27.9%) vs baseline: +0.2% Memory: ✅ 43.853MB (SLO: <46.000MB -4.7%) vs baseline: +4.8% ✅ repr_aspectTime: ✅ 326.686µs (SLO: <420.000µs 📉 -22.2%) vs baseline: -0.2% Memory: ✅ 43.858MB (SLO: <46.000MB -4.7%) vs baseline: +5.1% ✅ repr_noaspectTime: ✅ 46.867µs (SLO: <90.000µs 📉 -47.9%) vs baseline: +0.8% Memory: ✅ 43.991MB (SLO: <46.000MB -4.4%) vs baseline: +5.0% ✅ rstrip_aspectTime: ✅ 381.126µs (SLO: <500.000µs 📉 -23.8%) vs baseline: -0.4% Memory: ✅ 43.948MB (SLO: <46.000MB -4.5%) vs baseline: +5.0% ✅ rstrip_noaspectTime: ✅ 186.573µs (SLO: <300.000µs 📉 -37.8%) vs baseline: +1.3% Memory: ✅ 43.794MB (SLO: <46.000MB -4.8%) vs baseline: +4.6% ✅ slice_aspectTime: ✅ 181.755µs (SLO: <300.000µs 📉 -39.4%) vs baseline: ~same Memory: ✅ 43.960MB (SLO: <46.000MB -4.4%) vs baseline: +5.2% ✅ slice_noaspectTime: ✅ 54.363µs (SLO: <90.000µs 📉 -39.6%) vs baseline: +0.8% Memory: ✅ 43.900MB (SLO: <46.000MB -4.6%) vs baseline: +4.9% ✅ stringio_aspectTime: ✅ 3.876ms (SLO: <5.000ms 📉 -22.5%) vs baseline: -0.3% Memory: ✅ 43.917MB (SLO: <46.000MB -4.5%) vs baseline: +5.1% ✅ stringio_noaspectTime: ✅ 357.025µs (SLO: <500.000µs 📉 -28.6%) vs baseline: +0.9% Memory: ✅ 43.967MB (SLO: <46.000MB -4.4%) vs baseline: +5.1% ✅ strip_aspectTime: ✅ 271.145µs (SLO: <350.000µs 📉 -22.5%) vs baseline: +0.5% Memory: ✅ 43.884MB (SLO: <46.000MB -4.6%) vs baseline: +5.1% ✅ strip_noaspectTime: ✅ 175.789µs (SLO: <240.000µs 📉 -26.8%) vs baseline: +0.5% Memory: ✅ 43.785MB (SLO: <46.000MB -4.8%) vs baseline: +4.5% ✅ swapcase_aspectTime: ✅ 346.504µs (SLO: <500.000µs 📉 -30.7%) vs baseline: +0.5% Memory: ✅ 43.938MB (SLO: <46.000MB -4.5%) vs baseline: +4.8% ✅ swapcase_noaspectTime: ✅ 275.119µs (SLO: <400.000µs 📉 -31.2%) vs baseline: +1.3% Memory: ✅ 43.907MB (SLO: <46.000MB -4.5%) vs baseline: +4.7% ✅ title_aspectTime: ✅ 334.713µs (SLO: <500.000µs 📉 -33.1%) vs baseline: +0.7% Memory: ✅ 43.924MB (SLO: <46.000MB -4.5%) vs baseline: +5.2% ✅ title_noaspectTime: ✅ 264.629µs (SLO: <400.000µs 📉 -33.8%) vs baseline: +0.8% Memory: ✅ 43.927MB (SLO: <46.000MB -4.5%) vs baseline: +5.0% ✅ translate_aspectTime: ✅ 579.878µs (SLO: <700.000µs 📉 -17.2%) vs baseline: 📈 +11.5% Memory: ✅ 43.859MB (SLO: <46.000MB -4.7%) vs baseline: +4.7% ✅ translate_noaspectTime: ✅ 427.165µs (SLO: <500.000µs 📉 -14.6%) vs baseline: -2.5% Memory: ✅ 43.926MB (SLO: <46.000MB -4.5%) vs baseline: +4.7% ✅ upper_aspectTime: ✅ 309.229µs (SLO: <500.000µs 📉 -38.2%) vs baseline: -0.2% Memory: ✅ 43.970MB (SLO: <46.000MB -4.4%) vs baseline: +4.8% ✅ upper_noaspectTime: ✅ 241.661µs (SLO: <400.000µs 📉 -39.6%) vs baseline: +2.7% Memory: ✅ 43.881MB (SLO: <46.000MB -4.6%) vs baseline: +4.9% 📈 iastaspectsospath - 24/24✅ ospathbasename_aspectTime: ✅ 521.390µs (SLO: <700.000µs 📉 -25.5%) vs baseline: 📈 +25.5% Memory: ✅ 43.905MB (SLO: <46.000MB -4.6%) vs baseline: +4.7% ✅ ospathbasename_noaspectTime: ✅ 422.869µs (SLO: <700.000µs 📉 -39.6%) vs baseline: +0.1% Memory: ✅ 43.810MB (SLO: <46.000MB -4.8%) vs baseline: +4.9% ✅ ospathjoin_aspectTime: ✅ 626.856µs (SLO: <700.000µs 📉 -10.4%) vs baseline: -0.2% Memory: ✅ 43.962MB (SLO: <46.000MB -4.4%) vs baseline: +5.3% ✅ ospathjoin_noaspectTime: ✅ 632.528µs (SLO: <700.000µs -9.6%) vs baseline: -0.7% Memory: ✅ 43.915MB (SLO: <46.000MB -4.5%) vs baseline: +4.9% ✅ ospathnormcase_aspectTime: ✅ 349.849µs (SLO: <700.000µs 📉 -50.0%) vs baseline: ~same Memory: ✅ 43.786MB (SLO: <46.000MB -4.8%) vs baseline: +4.6% ✅ ospathnormcase_noaspectTime: ✅ 355.130µs (SLO: <700.000µs 📉 -49.3%) vs baseline: -0.5% Memory: ✅ 43.914MB (SLO: <46.000MB -4.5%) vs baseline: +4.8% ✅ ospathsplit_aspectTime: ✅ 477.041µs (SLO: <700.000µs 📉 -31.9%) vs baseline: -0.4% Memory: ✅ 43.899MB (SLO: <46.000MB -4.6%) vs baseline: +4.8% ✅ ospathsplit_noaspectTime: ✅ 488.152µs (SLO: <700.000µs 📉 -30.3%) vs baseline: +0.6% Memory: ✅ 43.909MB (SLO: <46.000MB -4.5%) vs baseline: +5.0% ✅ ospathsplitdrive_aspectTime: ✅ 365.485µs (SLO: <700.000µs 📉 -47.8%) vs baseline: -0.1% Memory: ✅ 43.895MB (SLO: <46.000MB -4.6%) vs baseline: +5.0% ✅ ospathsplitdrive_noaspectTime: ✅ 73.324µs (SLO: <700.000µs 📉 -89.5%) vs baseline: -0.8% Memory: ✅ 43.806MB (SLO: <46.000MB -4.8%) vs baseline: +4.7% ✅ ospathsplitext_aspectTime: ✅ 454.030µs (SLO: <700.000µs 📉 -35.1%) vs baseline: -0.1% Memory: ✅ 43.756MB (SLO: <46.000MB -4.9%) vs baseline: +4.4% ✅ ospathsplitext_noaspectTime: ✅ 459.071µs (SLO: <700.000µs 📉 -34.4%) vs baseline: -0.4% Memory: ✅ 43.919MB (SLO: <46.000MB -4.5%) vs baseline: +4.8% 🟡 Near SLO Breach (7 suites)🟡 djangosimple - 28/28✅ appsecTime: ✅ 19.623ms (SLO: <22.300ms 📉 -12.0%) vs baseline: -0.5% Memory: ✅ 71.526MB (SLO: <73.500MB -2.7%) vs baseline: +5.0% ✅ exception-replay-enabledTime: ✅ 1.361ms (SLO: <1.450ms -6.1%) vs baseline: ~same Memory: ✅ 69.728MB (SLO: <71.500MB -2.5%) vs baseline: +4.9% ✅ iastTime: ✅ 19.664ms (SLO: <22.250ms 📉 -11.6%) vs baseline: ~same Memory: ✅ 71.576MB (SLO: <75.000MB -4.6%) vs baseline: +5.0% ✅ profilerTime: ✅ 15.228ms (SLO: <16.550ms -8.0%) vs baseline: -0.2% Memory: ✅ 60.496MB (SLO: <61.000MB 🟡 -0.8%) vs baseline: +5.1% ✅ resource-renamingTime: ✅ 19.505ms (SLO: <21.750ms 📉 -10.3%) vs baseline: +0.4% Memory: ✅ 71.632MB (SLO: <73.500MB -2.5%) vs baseline: +5.0% ✅ span-code-originTime: ✅ 20.215ms (SLO: <28.200ms 📉 -28.3%) vs baseline: +1.6% Memory: ✅ 71.739MB (SLO: <75.000MB -4.3%) vs baseline: +4.8% ✅ tracerTime: ✅ 19.611ms (SLO: <21.750ms -9.8%) vs baseline: ~same Memory: ✅ 71.613MB (SLO: <75.000MB -4.5%) vs baseline: +5.1% ✅ tracer-and-profilerTime: ✅ 20.972ms (SLO: <23.500ms 📉 -10.8%) vs baseline: -0.5% Memory: ✅ 73.501MB (SLO: <75.000MB 🟡 -2.0%) vs baseline: +4.8% ✅ tracer-dont-create-db-spansTime: ✅ 19.684ms (SLO: <21.500ms -8.4%) vs baseline: -0.3% Memory: ✅ 71.495MB (SLO: <75.000MB -4.7%) vs baseline: +5.0% ✅ tracer-minimalTime: ✅ 17.853ms (SLO: <18.500ms -3.5%) vs baseline: -0.9% Memory: ✅ 71.468MB (SLO: <75.000MB -4.7%) vs baseline: +4.9% ✅ tracer-no-cachesTime: ✅ 18.748ms (SLO: <19.650ms -4.6%) vs baseline: -0.5% Memory: ✅ 71.427MB (SLO: <75.000MB -4.8%) vs baseline: +4.8% ✅ tracer-no-databasesTime: ✅ 20.810ms (SLO: <21.100ms 🟡 -1.4%) vs baseline: +0.6% Memory: ✅ 71.566MB (SLO: <75.000MB -4.6%) vs baseline: +5.0% ✅ tracer-no-middlewareTime: ✅ 20.607ms (SLO: <21.500ms -4.2%) vs baseline: ~same Memory: ✅ 71.546MB (SLO: <75.000MB -4.6%) vs baseline: +5.1% ✅ tracer-no-templatesTime: ✅ 19.668ms (SLO: <22.000ms 📉 -10.6%) vs baseline: +1.9% Memory: ✅ 71.479MB (SLO: <73.500MB -2.7%) vs baseline: +4.9% 🟡 iastpropagation - 8/8✅ no-propagationTime: ✅ 48.296µs (SLO: <60.000µs 📉 -19.5%) vs baseline: -0.5% Memory: ✅ 41.347MB (SLO: <42.000MB 🟡 -1.6%) vs baseline: +6.0% ✅ propagation_enabledTime: ✅ 136.919µs (SLO: <190.000µs 📉 -27.9%) vs baseline: -0.5% Memory: ✅ 41.229MB (SLO: <42.000MB 🟡 -1.8%) vs baseline: +4.9% ✅ propagation_enabled_100Time: ✅ 1.589ms (SLO: <2.300ms 📉 -30.9%) vs baseline: ~same Memory: ✅ 41.111MB (SLO: <42.000MB -2.1%) vs baseline: +4.5% ✅ propagation_enabled_1000Time: ✅ 29.018ms (SLO: <34.550ms 📉 -16.0%) vs baseline: -0.4% Memory: ✅ 41.268MB (SLO: <42.000MB 🟡 -1.7%) vs baseline: +5.1% 🟡 otelspan - 22/22✅ add-eventTime: ✅ 41.334ms (SLO: <47.150ms 📉 -12.3%) vs baseline: -1.0% Memory: ✅ 41.540MB (SLO: <47.000MB 📉 -11.6%) vs baseline: +4.7% ✅ add-metricsTime: ✅ 234.882ms (SLO: <344.800ms 📉 -31.9%) vs baseline: -0.8% Memory: ✅ 45.651MB (SLO: <47.500MB -3.9%) vs baseline: +5.2% ✅ add-tagsTime: ✅ 264.238ms (SLO: <330.000ms 📉 -19.9%) vs baseline: -0.6% Memory: ✅ 45.660MB (SLO: <47.500MB -3.9%) vs baseline: +5.2% ✅ get-contextTime: ✅ 81.036ms (SLO: <92.350ms 📉 -12.3%) vs baseline: -0.2% Memory: ✅ 41.111MB (SLO: <46.500MB 📉 -11.6%) vs baseline: +5.0% ✅ is-recordingTime: ✅ 37.941ms (SLO: <44.500ms 📉 -14.7%) vs baseline: ~same Memory: ✅ 40.995MB (SLO: <47.500MB 📉 -13.7%) vs baseline: +5.2% ✅ record-exceptionTime: ✅ 62.776ms (SLO: <67.650ms -7.2%) vs baseline: ~same Memory: ✅ 41.802MB (SLO: <47.000MB 📉 -11.1%) vs baseline: +5.0% ✅ set-statusTime: ✅ 43.607ms (SLO: <50.400ms 📉 -13.5%) vs baseline: ~same Memory: ✅ 41.158MB (SLO: <47.000MB 📉 -12.4%) vs baseline: +5.2% ✅ startTime: ✅ 38.677ms (SLO: <44.500ms 📉 -13.1%) vs baseline: +4.1% Memory: ✅ 40.981MB (SLO: <47.000MB 📉 -12.8%) vs baseline: +4.6% ✅ start-finishTime: ✅ 89.624ms (SLO: <92.000ms -2.6%) vs baseline: ~same Memory: ✅ 38.810MB (SLO: <46.500MB 📉 -16.5%) vs baseline: +5.0% ✅ start-finish-telemetryTime: ✅ 91.676ms (SLO: <93.000ms 🟡 -1.4%) vs baseline: +0.2% Memory: ✅ 38.810MB (SLO: <46.500MB 📉 -16.5%) vs baseline: +4.5% ✅ update-nameTime: ✅ 38.935ms (SLO: <45.150ms 📉 -13.8%) vs baseline: -0.5% Memory: ✅ 40.946MB (SLO: <47.000MB 📉 -12.9%) vs baseline: +4.7% 🟡 packagesupdateimporteddependencies - 24/24 (1 unstable)✅ import_manyTime: ✅ 167.947µs (SLO: <170.000µs 🟡 -1.2%) vs baseline: +0.2% Memory: ✅ 41.682MB (SLO: <46.000MB -9.4%) vs baseline: +5.4% ✅ import_many_cachedTime: ✅ 131.286µs (SLO: <170.000µs 📉 -22.8%) vs baseline: -0.6% Memory: ✅ 41.404MB (SLO: <46.000MB -10.0%) vs baseline: +5.0% ✅ import_many_stdlibTime: ✅ 1.257ms (SLO: <1.750ms 📉 -28.2%) vs baseline: +0.5% Memory: ✅ 41.418MB (SLO: <46.000MB -10.0%) vs baseline: +5.2%
|
P403n1x87
left a comment
There was a problem hiding this comment.
Generally LGTM but I feel like we only need the checks on entry in awake, the extra locking should be redundant with the GIL.
Per review feedback (#18040): surfacing a RuntimeError on the stopped path makes a timing-dependent race (in-flight awake() vs concurrent stop()) visible to callers, which is worse than a no-op. awake() now returns silently on the stopped path at both the GIL-fast-path entry check and the under-mutex re-check. The inner re-check + _awake_mutex on stop() are kept intentionally: awake() releases the GIL via AllowThreads mid-call, so a concurrent Python-thread stop() can flip _stopping while awake() is in C++ land. The stress test in tests/internal/test_periodic_race.py (test_race_callback_stop_with_concurrent_awakes, 1250 iters x 8 awakers) deterministically hits this race when the mutex/re-check are removed. Tests updated to assert "returns without hanging" instead of "raises RuntimeError" — same scenarios, same watchdog/iteration counts, just dropped the over-specific RuntimeError assertion. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 007b13d5d8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Per review feedback (#18040): surfacing a RuntimeError on the stopped path makes a timing-dependent race (in-flight awake() vs concurrent stop()) visible to callers, which is worse than a no-op. awake() now returns silently on the stopped path at both the GIL-fast-path entry check and the under-mutex re-check. The inner re-check + _awake_mutex on stop() are kept intentionally: awake() releases the GIL via AllowThreads mid-call, so a concurrent Python-thread stop() can flip _stopping while awake() is in C++ land. The stress test in tests/internal/test_periodic_race.py (test_race_callback_stop_with_concurrent_awakes, 1250 iters x 8 awakers) deterministically hits this race when the mutex/re-check are removed. Tests updated to assert "returns without hanging" instead of "raises RuntimeError" — same scenarios, same watchdog/iteration counts, just dropped the over-specific RuntimeError assertion. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
007b13d to
d551c89
Compare
BenchmarksBenchmark execution time: 2026-05-18 14:26:19 Comparing candidate commit ad85156 in PR branch Found 0 performance improvements and 4 performance regressions! Performance is the same for 587 metrics, 10 unstable metrics. scenario:iastaspects-stringio_aspect
scenario:iastaspectsospath-ospathbasename_aspect
scenario:span-start
scenario:telemetryaddmetric-1-count-metric-1-times
|
emmettbutler
left a comment
There was a problem hiding this comment.
Tests look good. Consider a release note.
@emmettbutler Ok, thanks. I thought this would not require a changelog as it does not change the functional behaviour of dd-trace-py. I will add one. |
Same bug as #17707 (awake() after a completed stop() blocks forever on _served->wait() because the worker is gone), drafted as a smaller diff for comparison against the cond_var-based fix in that PR. Approach: - awake(): GIL-fast-path early check on _stopping (under the GIL, a prior Python-thread stop() is fully ordered before us). Then re-check under _awake_mutex and release the mutex *before* _served->wait(), so a callback that calls stop() on itself (Timer._periodic) cannot deadlock on the mutex. - stop(): now takes _awake_mutex around _stopping + set(STOP), ordering it against awake()'s clear-_served / set(AWAKE) setup. - _before_fork() already takes _awake_mutex on main; unchanged. - _served Event, worker loop and helpers all unchanged. Diff size: 43+/-6 lines vs #17707's 159+/-20. Tradeoff: this design relies on the worker's unconditional cleanup _served->set() at loop exit to wake an in-flight awake() that raced with stop(); #17707's _awake_served flag gives finer "my callback ran" semantics. Testing: Regression tests from #17707 copied verbatim (both pass): - test_periodic_awake_after_stop_raises_not_hangs - test_periodic_awake_does_not_deadlock_with_stop_from_callback New tests/internal/test_periodic_race.py (race-injection stress, 5000 iters default, override with PERIODIC_RACE_ITERATIONS): - test_race_stop_concurrent_with_awake - test_race_awake_after_completed_stop_always_raises - test_race_callback_stop_with_concurrent_awakes Validated against a "partial-fix" baseline (early check only, no mutex on stop): test_race_callback_stop_with_concurrent_awakes watchdog fires at the expected awaker index, confirming the test exercises the race window. All three pass against the full middle-ground fix. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per review feedback (#18040): surfacing a RuntimeError on the stopped path makes a timing-dependent race (in-flight awake() vs concurrent stop()) visible to callers, which is worse than a no-op. awake() now returns silently on the stopped path at both the GIL-fast-path entry check and the under-mutex re-check. The inner re-check + _awake_mutex on stop() are kept intentionally: awake() releases the GIL via AllowThreads mid-call, so a concurrent Python-thread stop() can flip _stopping while awake() is in C++ land. The stress test in tests/internal/test_periodic_race.py (test_race_callback_stop_with_concurrent_awakes, 1250 iters x 8 awakers) deterministically hits this race when the mutex/re-check are removed. Tests updated to assert "returns without hanging" instead of "raises RuntimeError" — same scenarios, same watchdog/iteration counts, just dropped the over-specific RuntimeError assertion. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
d551c89 to
0ff0042
Compare
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0ff0042 to
ad85156
Compare
|
/merge |
|
View all feedbacks in Devflow UI.
This pull request is not mergeable according to GitHub. Common reasons include pending required checks, missing approvals, or merge conflicts — but it could also be blocked by other repository rules or settings.
The expected merge time in
|
…18040) ## Description Alternative to #17707 for the same bug: `PeriodicThread.awake()` blocks forever on `_served->wait()` when called after `stop()` has completed (worker already exited, `_served` will never be set again). ### Approach - **`awake()`**: GIL-fast-path early check on `_stopping` — a prior Python-thread `stop()` is fully ordered before us under the GIL. Then a re-check under `_awake_mutex` and `_served->wait()` *outside* the mutex so a worker callback that calls `stop()` on itself (the `Timer._periodic` pattern) cannot deadlock. On the stopped path `awake()` returns silently (no `RuntimeError`) so a racy `stop()` / `awake()` interleaving never surfaces a timing-dependent exception to callers. - **`stop()`**: takes `_awake_mutex` around `_stopping = true` + `_request->set(STOP)`, ordering it against `awake()`'s `_served->clear()` + `set(AWAKE)` setup. - **`_before_fork()`** already takes `_awake_mutex` on main; unchanged. - **`_served` Event, worker loop and helpers** are all unchanged. ## Testing Regression tests from #17707 are copied and adapted to the no-op semantics: - `test_periodic_awake_after_stop_returns_not_hangs` - `test_periodic_awake_does_not_deadlock_with_stop_from_callback` New `tests/internal/test_periodic_race.py` (race-injection stress; default 5000 iterations, override with `PERIODIC_RACE_ITERATIONS`): - `test_race_stop_concurrent_with_awake` - `test_race_awake_after_completed_stop_does_not_hang` - `test_race_callback_stop_with_concurrent_awakes` Each test has a 5s per-operation watchdog so a regression fails fast. ## Risks Low. `awake()` after a completed `stop()` + `join()` now returns silently instead of hanging. Internal API; `changelog/no-changelog`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: erwan.viollet <erwan.viollet@datadoghq.com>
…read (#18183) ## Description Adds `tests/internal/test_periodic_stress.py` — a randomized lifecycle fuzzer for `PeriodicThread` that interleaves create / start / stop / join / awake / drop-last-ref / fork / gc / thread-churn across a pool of `PeriodicThread` and `PeriodicService` objects. This is the harness that surfaced #17707 and #18040 (`PeriodicThread.awake()` blocking forever after `stop()`). ### What's in the file - `test_periodic_thread_lifecycle_stress` — the randomized fuzzer. Default budget kept short for CI (`DD_STRESS_ITERS=200`, ~10s). Documented env vars for soaks (`DD_STRESS_ITERS`, `DD_STRESS_SECONDS`, `DD_STRESS_SEED`, `DD_STRESS_POOL`, `DD_STRESS_FORK_EVERY`, `DD_STRESS_TRACE_FILE`). Seed is printed on every run so a failing random seed can be pinned with `DD_STRESS_SEED=N`. - `test_periodic_thread_concurrent_dealloc_race` — focused regression for #17485 (refcount TOCTOU between `std::thread` creation and the lambda acquiring the GIL). - `test_periodic_thread_stop_without_join_then_fork_repeat` — focused regression for #16955 (`pthread_t` recycling after stop-without-join then fork). ### How to run it when modifying the periodic thread framework The module docstring documents the exact commands. tl;dr: ``` # ~30s soak DD_STRESS_ITERS=10000 scripts/run-tests -- -- tests/internal/test_periodic_stress.py # 120s wall-clock soak (recommended under ASan/TSan) DD_STRESS_SECONDS=120 scripts/run-tests -- -- tests/internal/test_periodic_stress.py # Reproduce a failing seed (the seed is printed to stderr by every run) DD_STRESS_SEED=12345 scripts/run-tests -- -- tests/internal/test_periodic_stress.py ``` ## Testing All three tests pass locally on Python 3.13 in the testrunner image: ``` tests/internal/test_periodic_stress.py::test_periodic_thread_lifecycle_stress PASSED tests/internal/test_periodic_stress.py::test_periodic_thread_concurrent_dealloc_race PASSED tests/internal/test_periodic_stress.py::test_periodic_thread_stop_without_join_then_fork_repeat PASSED ``` ## Risks None — test-only addition. Existing test discovery and CI suites are unchanged. `changelog/no-changelog` — test-only. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: brettlangdon <brett.langdon@datadoghq.com> Co-authored-by: erwan.viollet <erwan.viollet@datadoghq.com>
Description
Alternative to #17707 for the same bug:
PeriodicThread.awake()blocksforever on
_served->wait()when called afterstop()has completed(worker already exited,
_servedwill never be set again).Approach
awake(): GIL-fast-path early check on_stopping— a priorPython-thread
stop()is fully ordered before us under the GIL.Then a re-check under
_awake_mutexand_served->wait()outsidethe mutex so a worker callback that calls
stop()on itself(the
Timer._periodicpattern) cannot deadlock.On the stopped path
awake()returns silently (noRuntimeError)so a racy
stop()/awake()interleaving never surfaces atiming-dependent exception to callers.
stop(): takes_awake_mutexaround_stopping = true+_request->set(STOP), ordering it againstawake()'s_served->clear()+set(AWAKE)setup._before_fork()already takes_awake_mutexon main; unchanged._servedEvent, worker loop and helpers are all unchanged.Testing
Regression tests from #17707 are copied and adapted to the no-op
semantics:
test_periodic_awake_after_stop_returns_not_hangstest_periodic_awake_does_not_deadlock_with_stop_from_callbackNew
tests/internal/test_periodic_race.py(race-injection stress;default 5000 iterations, override with
PERIODIC_RACE_ITERATIONS):test_race_stop_concurrent_with_awaketest_race_awake_after_completed_stop_does_not_hangtest_race_callback_stop_with_concurrent_awakesEach test has a 5s per-operation watchdog so a regression fails fast.
Risks
Low.
awake()after a completedstop()+join()now returnssilently instead of hanging. Internal API;
changelog/no-changelog.🤖 Generated with Claude Code