|
| @@ -362,27 +362,12 @@ func TestSeatRepeatThroughEpoll(t *testing.T) { |
| 362 | | require.Equal(t, n, repeats, "release stops the repeat") | 362 | | require.Equal(t, n, repeats, "release stops the repeat") |
| 363 | | } | 363 | | } |
| 364 | | | 364 | | |
| 365 | - | // xkbAllocsPerPress bounds the allocations of one key press. They all come | | | |
| 366 | - | // from purego-xkbcommon: its functions are registered through purego's | | | |
| 367 | - | // reflection-based RegisterFunc, which allocates the boxed return value (and | | | |
| 368 | - | // more) on every native call, and a press makes four (key_get_one_sym, | | | |
| 369 | - | // compose feed, compose status, key_get_utf8). The library itself adds none; | | | |
| 370 | - | // the zero-allocation guard below proves that. The bound pins the binding's | | | |
| 371 | - | // cost so a regression above it shows. | | | |
| 372 | - | const xkbAllocsPerPress = 20 | | | |
| 373 | - | | | | |
| 374 | - | // xkbAllocsPerMask bounds a mask change: update_mask, serialize_mods and | | | |
| 375 | - | // serialize_layout, boxed the same way. | | | |
| 376 | - | const xkbAllocsPerMask = 12 | | | |
| 377 | - | | | | |
| 378 | | // TestAllocKey measures the steady-state key path over a real socketpair, on | 365 | | // TestAllocKey measures the steady-state key path over a real socketpair, on |
| 379 | | // the real code path (no mocks): key frames in, reader decode, queue, Dispatch | 366 | | // the real code path (no mocks): key frames in, reader decode, queue, Dispatch |
| 380 | | // with xkb state and translation, and the Handler call. | 367 | | // with xkb state and translation, and the Handler call. |
| 381 | | // | 368 | | // |
| 382 | - | // Releases make no native call, so a batch of them measures the library's own | 369 | + | // Every path is zero-allocation: releases, text and secret presses, and |
| 383 | - | // cost, which must be zero. Presses add the purego-xkbcommon cost (see | 370 | + | // modifier masks (purego-xkbcommon v0.2.0 dispatches without allocating). |
| 384 | - | // xkbAllocsPerPress); that is measured for ordinary text and for the secret | | | |
| 385 | - | // buffer. | | | |
| 386 | | func TestAllocKey(t *testing.T) { | 371 | | func TestAllocKey(t *testing.T) { |
| 387 | | skipUnderRace(t) | 372 | | skipUnderRace(t) |
| 388 | | c, srv, peer, s := seatSetup(t) | 373 | | c, srv, peer, s := seatSetup(t) |
|
| @@ -431,11 +416,11 @@ func TestAllocKey(t *testing.T) { |
| 431 | | } | 416 | | } |
| 432 | | step := run(batch, 2*pairs) | 417 | | step := run(batch, 2*pairs) |
| 433 | | text := measure("text, 50 presses + releases", step) | 418 | | text := measure("text, 50 presses + releases", step) |
| 434 | - | require.LessOrEqual(t, text, float64(pairs*xkbAllocsPerPress)) | 419 | + | require.Zero(t, text, "text presses allocate nothing") |
| 435 | | require.Equal(t, "a", h.lastText) | 420 | | require.Equal(t, "a", h.lastText) |
| 436 | | | 421 | | |
| 437 | | // Modifier masks: an identical mask is a no-op and allocates nothing; a | 422 | | // Modifier masks: an identical mask is a no-op and allocates nothing; a |
| 438 | - | // changing one updates the xkb state (purego-xkbcommon calls, bounded). | 423 | + | // changing one updates the xkb state, also without allocating. |
| 439 | | mods := func(depressed uint32) []byte { | 424 | | mods := func(depressed uint32) []byte { |
| 440 | | b := appendU32(appendU32(nil, 1), depressed) | 425 | | b := appendU32(appendU32(nil, 1), depressed) |
| 441 | | return frame(kb, 4, appendU32(appendU32(appendU32(b, 0), 0), 0)) | 426 | | return frame(kb, 4, appendU32(appendU32(appendU32(b, 0), 0), 0)) |
|
| @@ -449,12 +434,12 @@ func TestAllocKey(t *testing.T) { |
| 449 | | } | 434 | | } |
| 450 | | require.Zero(t, measure("modifiers, 100 identical masks", run(same, 100)), "identical masks cost nothing") | 435 | | require.Zero(t, measure("modifiers, 100 identical masks", run(same, 100)), "identical masks cost nothing") |
| 451 | | changes := measure("modifiers, 100 alternating masks", run(changing, 100)) | 436 | | changes := measure("modifiers, 100 alternating masks", run(changing, 100)) |
| 452 | - | require.LessOrEqual(t, changes, float64(100*xkbAllocsPerMask)) | 437 | + | require.Zero(t, changes, "mask changes allocate nothing") |
| 453 | | | 438 | | |
| 454 | | buf := neferclient.NewSecretBuffer(4096) | 439 | | buf := neferclient.NewSecretBuffer(4096) |
| 455 | | c.Seat().SetSecret(buf) | 440 | | c.Seat().SetSecret(buf) |
| 456 | | secret := measure("secret, 50 presses + releases", step) | 441 | | secret := measure("secret, 50 presses + releases", step) |
| 457 | - | require.LessOrEqual(t, secret, float64(pairs*xkbAllocsPerPress)) | 442 | + | require.Zero(t, secret, "secret presses allocate nothing") |
| 458 | | require.Empty(t, h.lastText, "no text reaches the handler in secret mode") | 443 | | require.Empty(t, h.lastText, "no text reaches the handler in secret mode") |
| 459 | | require.Positive(t, buf.Len()) | 444 | | require.Positive(t, buf.Len()) |
| 460 | | buf.Wipe() | 445 | | buf.Wipe() |