diff --git a/.github/workflows/test-audience-sample-app.yml b/.github/workflows/test-audience-sample-app.yml index 452aab382..0d88bfc25 100644 --- a/.github/workflows/test-audience-sample-app.yml +++ b/.github/workflows/test-audience-sample-app.yml @@ -46,20 +46,26 @@ jobs: strategy: fail-fast: false matrix: - unity: ['2021.3.45f2', '6000.4.0f1', '2022.3.62f2'] - target: [StandaloneWindows64, StandaloneOSX] - backend: [IL2CPP, Mono2x] + # Explicit per-cell entries instead of cartesian + partial-key + # include. The cartesian + partial-include shape used here + # previously had the include entries fail to merge runner and + # changeset onto the generated combos, so every cell had no + # runner and the playmode job spawned zero jobs (verified on + # runs 25604434621 and 25613048568). 12 explicit entries below + # is the bulletproof shape. include: - - unity: '2021.3.45f2' - changeset: 88f88f591b2e - - unity: '6000.4.0f1' - changeset: 8cf496087c8f - - unity: '2022.3.62f2' - changeset: 7670c08855a9 - - target: StandaloneWindows64 - runner: [self-hosted, Windows, X64] - - target: StandaloneOSX - runner: [self-hosted, macOS, ARM64] + - { target: StandaloneWindows64, backend: IL2CPP, unity: '2021.3.45f2', changeset: 88f88f591b2e, runner: [self-hosted, Windows, X64] } + - { target: StandaloneWindows64, backend: Mono2x, unity: '2021.3.45f2', changeset: 88f88f591b2e, runner: [self-hosted, Windows, X64] } + - { target: StandaloneOSX, backend: IL2CPP, unity: '2021.3.45f2', changeset: 88f88f591b2e, runner: [self-hosted, macOS, ARM64] } + - { target: StandaloneOSX, backend: Mono2x, unity: '2021.3.45f2', changeset: 88f88f591b2e, runner: [self-hosted, macOS, ARM64] } + - { target: StandaloneWindows64, backend: IL2CPP, unity: '6000.4.0f1', changeset: 8cf496087c8f, runner: [self-hosted, Windows, X64] } + - { target: StandaloneWindows64, backend: Mono2x, unity: '6000.4.0f1', changeset: 8cf496087c8f, runner: [self-hosted, Windows, X64] } + - { target: StandaloneOSX, backend: IL2CPP, unity: '6000.4.0f1', changeset: 8cf496087c8f, runner: [self-hosted, macOS, ARM64] } + - { target: StandaloneOSX, backend: Mono2x, unity: '6000.4.0f1', changeset: 8cf496087c8f, runner: [self-hosted, macOS, ARM64] } + - { target: StandaloneWindows64, backend: IL2CPP, unity: '2022.3.62f2', changeset: 7670c08855a9, runner: [self-hosted, Windows, X64] } + - { target: StandaloneWindows64, backend: Mono2x, unity: '2022.3.62f2', changeset: 7670c08855a9, runner: [self-hosted, Windows, X64] } + - { target: StandaloneOSX, backend: IL2CPP, unity: '2022.3.62f2', changeset: 7670c08855a9, runner: [self-hosted, macOS, ARM64] } + - { target: StandaloneOSX, backend: Mono2x, unity: '2022.3.62f2', changeset: 7670c08855a9, runner: [self-hosted, macOS, ARM64] } exclude: ${{ fromJSON(github.event_name == 'pull_request' && '[{"unity":"2022.3.62f2"}]' || '[]') }} runs-on: ${{ matrix.runner }} # Healthy cells finish in ~10 min. 30 min covers cold caches + diff --git a/examples/audience/Assets/SampleApp/Tests/Runtime/LinuxLogPaneSuppression.cs b/examples/audience/Assets/SampleApp/Tests/Runtime/LinuxLogPaneSuppression.cs deleted file mode 100644 index 0a8ffff38..000000000 --- a/examples/audience/Assets/SampleApp/Tests/Runtime/LinuxLogPaneSuppression.cs +++ /dev/null @@ -1,68 +0,0 @@ -#nullable enable - -#if UNITY_STANDALONE_LINUX -using NUnit.Framework; -using UnityEngine; -using UnityEngine.SceneManagement; -using UnityEngine.UIElements; - -namespace Immutable.Audience.Samples.SampleApp.Tests -{ - // Linux PlayMode test optimisation: hide the SampleApp log pane so UI - // Toolkit does not generate triangles for its rows during test runs. - // - // The player profile captured on PR 765 showed Render Thread spending - // roughly 4.5 seconds per frame in Gfx.PresentFrame self time on Unity - // 6 Linux cells, with ~2920 batches and ~7520 triangles per frame. - // Camera.Render is 2 ms, UI.RenderOverlays 1.45 ms; the rest is - // llvmpipe rasterising the deferred command buffer at present time. - // The bulk of those triangles come from the log pane, which - // accumulates one row per logged event over the course of a session. - // - // display:none keeps elements in the visual tree (so VisualElement.Q - // and contentContainer.Children() still find them) but skips layout - // and render entirely. Tests assert on log entries via userData on - // each row, which is reference-based, not layout-based, so the - // assertions stay correct. - // - // Engages only on StandaloneLinux64 builds (gated by the #if). Mac - // and Windows PlayMode runs are unaffected. - [SetUpFixture] - public sealed class LinuxLogPaneSuppression - { - [OneTimeSetUp] - public void RegisterSceneHook() - { - SceneManager.sceneLoaded += HideLogPane; - } - - [OneTimeTearDown] - public void DeregisterSceneHook() - { - SceneManager.sceneLoaded -= HideLogPane; - } - - // Re-fires for every scene load. The SampleApp's UIDocument runs - // its UI initialisation in Awake, so by the time sceneLoaded - // fires the log ScrollView is in the tree and ready to be - // styled. The hook is idempotent across loads. - private static void HideLogPane(Scene scene, LoadSceneMode mode) - { - var sample = Object.FindFirstObjectByType(FindObjectsInactive.Include); - if (sample == null) return; - - var doc = sample.GetComponent(); - if (doc == null) return; - - var root = doc.rootVisualElement; - if (root == null) return; - - var log = root.Q(SampleAppUi.LogScrollView); - if (log == null) return; - - log.style.display = new StyleEnum(DisplayStyle.None); - Debug.Log("[LinuxLogPaneSuppression] log pane hidden for Linux PlayMode test run."); - } - } -} -#endif diff --git a/examples/audience/Assets/SampleApp/Tests/Runtime/LinuxLogPaneSuppression.cs.meta b/examples/audience/Assets/SampleApp/Tests/Runtime/LinuxLogPaneSuppression.cs.meta deleted file mode 100644 index 375feaffe..000000000 --- a/examples/audience/Assets/SampleApp/Tests/Runtime/LinuxLogPaneSuppression.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 3a7e9d4b8c1f5a6e2b8d9c0e1f2a3b4c -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/src/Packages/Audience/Runtime/Transport/HttpTransport.cs b/src/Packages/Audience/Runtime/Transport/HttpTransport.cs index 6ac6e5357..19e3585c9 100644 --- a/src/Packages/Audience/Runtime/Transport/HttpTransport.cs +++ b/src/Packages/Audience/Runtime/Transport/HttpTransport.cs @@ -95,8 +95,23 @@ internal async Task SendBatchAsync(CancellationToken ct = default) request.Content = new StringContent(payload, Encoding.UTF8, "application/json"); #endif + // Temporary diagnostic markers to measure where SendBatchAsync + // spends time on Unity 6 Linux PlayMode cells (where each test + // sits at the 30 sec WaitForLogEntry budget on Mono Linux but + // finishes in 1-2 sec on Unity 2021.3 Linux). T1 is request + // start, T2 is response received (continuation alive), T3 is + // batch deletion + state reset done. Comparing T1->T2 vs + // T2->T3 gaps across Unity versions disambiguates whether the + // stall is in HttpClient.SendAsync (network/socket) or in the + // continuation back onto Unity's main thread (SyncContext). + var __t1 = System.Diagnostics.Stopwatch.StartNew(); + Log.Debug($"[HttpTransport][T1] SendAsync start url={_url} count={batch.Count}"); + using var response = await _client.SendAsync(request, ct).ConfigureAwait(false); + var __t2Ms = __t1.Elapsed.TotalMilliseconds; + Log.Debug($"[HttpTransport][T2] SendAsync done t1->t2={__t2Ms:F1}ms status={(int)response.StatusCode}"); + var statusCode = (int)response.StatusCode; if (statusCode >= 200 && statusCode < 300) @@ -113,6 +128,7 @@ internal async Task SendBatchAsync(CancellationToken ct = default) NotifyError(AudienceErrorCode.ValidationRejected, $"Batch partially rejected: {rejected} of {batch.Count} events dropped"); } + Log.Debug($"[HttpTransport][T3] batch handled t1->t3={__t1.Elapsed.TotalMilliseconds:F1}ms (t2->t3={(__t1.Elapsed.TotalMilliseconds - __t2Ms):F1}ms)"); } else if (statusCode == 429) {