Skip to content

Optimize LF test compilation with CMake#346

Merged
tanneberger merged 46 commits into
mainfrom
opt-lftests
May 15, 2026
Merged

Optimize LF test compilation with CMake#346
tanneberger merged 46 commits into
mainfrom
opt-lftests

Conversation

@sbgaia
Copy link
Copy Markdown
Member

@sbgaia sbgaia commented Apr 14, 2026

This PR reworks how LF and unit tests are built and executed. Instead of compiling reactor-uc from scratch for each LF test via the Makefile, we now use CMake to share a single reactor-uc build across all tests and compile them in parallel.

I also added a batch processing function in lfc.cmake so we can invoke LFC once for multiple test files instead of calling it repeatedly, and added coverage support for LF tests (previously we only had it for unit tests).

Minor changes:

  • Moved federated LF tests into test/lf/src/federated/ with a dedicated runner script;
  • Improved runtime symlink handling in UcPlatformGenerator.kt;
  • Fixed a couple of ASAN errors in connection logging and the event payload pool test;
  • Cleaned up the build config so unit tests and LF tests are properly decoupled.

Closes #275 and #136.

Benchmark

This is the improvement I got on my laptop:

Approach Time
Makefile (compiles reactor-uc per test, sequential) 1210s
CMake (shared reactor-uc, -j16) 182s
Speedup 6.6x

CMake breakdown:

  • LFC generation (cmake configure): ~101s
  • Compilation: ~18s
  • Test execution (ctest): ~63s

We can squeeze more out of this:

  1. Batch generation in LFC for federates: LFC reports an error if the batch contains more than one main federate. Currently, we still must process each federate individually, adding a lot of overhead.
  2. Move re-generation checks inside LFC: Currently, when a .lf file has already been built, LFC re-executes the entire generation pipeline and checks for each file whether the output it wants to write matches what's already on disk. Instead, we could take the same approach as make and check whether the output directory was modified more recently than the .lf file and its imports. This would allow us to cache the generated output in the CI pipeline and skip the generation step entirely when the tests haven't changed.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 14, 2026

Memory usage after merging this PR will be:

Memory Report

action_buffer_full_defer_test_c

from to increase (%)
text 78247 78281 0.04
data 752 752 0.00
bss 12448 12448 0.00
dec 91447 91481 0.04

action_buffer_full_drop_test_c

from to increase (%)
text 78247 78281 0.04
data 752 752 0.00
bss 12448 12448 0.00
dec 91447 91481 0.04

action_buffer_full_replace_test_c

from to increase (%)
text 78247 78281 0.04
data 752 752 0.00
bss 12448 12448 0.00
dec 91447 91481 0.04

action_buffer_full_update_test_c

from to increase (%)
text 78247 78281 0.04
data 752 752 0.00
bss 12448 12448 0.00
dec 91447 91481 0.04

action_defer_test_c

from to increase (%)
text 78361 78395 0.04
data 752 752 0.00
bss 12512 12512 0.00
dec 91625 91659 0.04

action_drop_test_c

from to increase (%)
text 78185 78219 0.04
data 752 752 0.00
bss 12512 12512 0.00
dec 91449 91483 0.04

action_empty_test_c

from to increase (%)
text 77866 77900 0.04
data 752 752 0.00
bss 12448 12448 0.00
dec 91066 91100 0.04

action_microstep_test_c

from to increase (%)
text 78396 78430 0.04
data 760 760 0.00
bss 12512 12512 0.00
dec 91668 91702 0.04

action_overwrite_test_c

from to increase (%)
text 78079 78113 0.04
data 752 752 0.00
bss 12512 12512 0.00
dec 91343 91377 0.04

action_replace_test_c

from to increase (%)
text 78185 78219 0.04
data 752 752 0.00
bss 12512 12512 0.00
dec 91449 91483 0.04

action_test_c

from to increase (%)
text 78173 78207 0.04
data 760 760 0.00
bss 12512 12512 0.00
dec 91445 91479 0.04

action_update_test_c

from to increase (%)
text 78282 78316 0.04
data 752 752 0.00
bss 12512 12512 0.00
dec 91546 91580 0.04

deadline_test_c

from to increase (%)
text 72475 72509 0.05
data 768 768 0.00
bss 11808 11808 0.00
dec 85051 85085 0.04

delayed_conn_test_c

from to increase (%)
text 76671 76705 0.04
data 752 752 0.00
bss 13280 13280 0.00
dec 90703 90737 0.04

event_payload_pool_test_c

from to increase (%)
text 24314 24314 0.00
data 720 720 0.00
bss 480 480 0.00
dec 25514 25514 0.00

event_queue_test_c

from to increase (%)
text 36107 36107 0.00
data 728 728 0.00
bss 640 640 0.00
dec 37475 37475 0.00

nanopb_test_c

from to increase (%)
text 44218 44218 0.00
data 1928 1928 0.00
bss 320 320 0.00
dec 46466 46466 0.00

physical_clock_test_c

from to increase (%)
text 54308 54342 0.06
data 832 832 0.00
bss 640 640 0.00
dec 55780 55814 0.06

port_test_c

from to increase (%)
text 76574 76608 0.04
data 752 752 0.00
bss 13088 13088 0.00
dec 90414 90448 0.04

reaction_queue_test_c

from to increase (%)
text 30420 30420 0.00
data 728 728 0.00
bss 480 480 0.00
dec 31628 31628 0.00

request_shutdown_test_c

from to increase (%)
text 78210 78244 0.04
data 752 752 0.00
bss 12512 12512 0.00
dec 91474 91508 0.04

startup_test_c

from to increase (%)
text 72104 72138 0.05
data 760 760 0.00
bss 11808 11808 0.00
dec 84672 84706 0.04

tcp_channel_test_c

from to increase (%)
text 96862 96896 0.04
data 2288 2288 0.00
bss 14720 14720 0.00
dec 113870 113904 0.03

timer_test_c

from to increase (%)
text 72076 72110 0.05
data 752 752 0.00
bss 11808 11808 0.00
dec 84636 84670 0.04

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 14, 2026

Benchmark results after merging this PR:

Benchmark results

Performance:

PingPongUc:
Best Time: 594.642 msec
Worst Time: 765.766 msec
Median Time: 693.478 msec

PingPongC:
Best Time: 175.908 msec
Worst Time: 176.074 msec
Median Time: 175.686 msec

ReactionLatencyUc:
Best latency: 31871 nsec
Median latency: 66555 nsec
Worst latency: 337964 nsec

ReactionLatencyC:
Best latency: 61262 nsec
Median latency: 66739 nsec
Worst latency: 127535 nsec

Memory usage:

PingPongUc:
text data bss dec hex filename
41026 760 8536 50322 c492 bin/PingPongUc

PingPongC:
text data bss dec hex filename
52194 934 424 53552 d130 bin/PingPongC

ReactionLatencyUc:
text data bss dec hex filename
26151 744 2552 29447 7307 bin/ReactionLatencyUc

ReactionLatencyC:
text data bss dec hex filename
47736 902 424 49062 bfa6 bin/ReactionLatencyC

Copy link
Copy Markdown
Collaborator

@edwardalee edwardalee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but I did not check it carefully. I would say, if it works, and you are sure all tests are running, go for it. I would be curious to know how much it speeds up the CI tests.

Comment thread cmake/lfc.cmake
Comment thread cmake/lfc.cmake Outdated
Comment thread src/connection.c Outdated
Comment thread test/lf/CMakeLists.txt Outdated
Comment thread test/lf/lf_test_functions.cmake Outdated

# Build one executable from a generated Include.cmake directory.
# Optional extra arguments are added as additional include directories.
function(register_lf_target TARGET_NAME SRC_GEN_DIR)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so this function basically adds an executable to cmake and links all the libraries?

Maybe can put this function actually into the generic cmake function file and reuse it here:
https://github.com/lf-lang/reactor-uc/blob/main/lfc/core/src/main/kotlin/org/lflang/generator/uc/UcCmakeGenerator.kt#L55

And I think we need a better name: e.g. lf_add_executable or something like this.

Comment thread CMakeLists.txt Outdated
sbgaia added 24 commits May 14, 2026 13:23
@tanneberger tanneberger self-requested a review May 14, 2026 15:21
@github-actions
Copy link
Copy Markdown
Contributor

Coverage after merging opt-lftests into main will be

84.95%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
include/reactor-uc
   event.h48.78%37.50%66.67%52.63%101, 101–102, 115–116, 116, 116, 116, 116–117, 119–121, 140–141, 141, 141, 141, 141
src
   action.c94.35%84%100%98.32%106, 145, 25, 42, 42, 60, 75, 97–99
   builtin_triggers.c90.91%70%100%96.77%14, 18, 40, 43
   clock_synchronization.c75.45%62.16%92.31%78.54%106–109, 116–118, 143, 149–151, 154, 158, 160–161, 161, 161–163, 163, 163, 166, 166, 166–167, 170–175, 175, 175–176, 180, 182–188, 188, 188–189, 192, 214–215, 224–225, 238–239, 241, 254–256, 26, 264–266, 27, 30, 310–311, 323, 323–326, 33–35, 49–52, 79–80, 95–97
   connection.c90.45%76.60%100%96.04%106, 112, 14, 140–141, 147, 149–150, 152, 27–28, 35, 50, 56, 99
   environment.c94.12%83.33%100%100%16, 29
   event.c100%100%100%100%
   federated.c80.50%57.29%100%90%120, 123–124, 148–149, 17, 176, 18–20, 202–203, 21, 210, 214, 214, 214, 214–217, 224–225, 228–230, 233–234, 236–239, 243, 246, 256, 275–277, 285–287, 30, 301–302, 304–307, 310–313, 33–34, 40–41, 45, 58, 58, 58–59, 65
   logging.c88.52%83.33%100%89.36%25, 38–40, 47, 60–61
   network_channel.c80.77%75%100%82.35%40, 40, 45–46, 57
   physical_clock.c97.40%83.33%100%100%26, 41
   port.c92.50%78.57%100%100%10, 15, 22, 26, 46–47
   queues.c91.90%84.21%100%94.15%128, 132, 132, 132–133, 181, 188–191, 217–219, 221, 234, 250, 255, 261, 55, 62–65
   reaction.c95.90%89.13%100%100%21, 30, 32, 56, 72
   reactor.c86%69.70%100%98.73%10, 101–102, 14–19, 22, 28, 32–34, 37–38, 43, 60, 77, 83, 91
   serialization.c75%50%100%80%16–17, 26–27, 34–35, 42–43
   startup_coordinator.c57.34%48.78%71.43%60.88%104–106, 116, 122, 124–125, 128, 138, 144, 149, 153–154, 174, 177–178, 188, 188, 188–189, 191, 193, 196, 21, 222, 226–227, 227, 227–228, 232, 235, 237, 242–243, 264, 273, 276, 293–294, 303, 303–304, 308, 316, 32, 362–364, 364, 364–365, 365, 365–368, 371–372, 372, 372, 375, 380, 380, 380–390, 393, 395, 398, 400–401, 401, 401–402, 405, 405, 405–407, 407, 407–408, 408, 408–410, 414, 414, 414–416, 420–423, 423, 423, 425–426, 429, 429, 429–430, 430, 430, 430, 430–431, 436–437, 437, 437–438, 438, 438–439, 443–444, 446, 448, 448, 448–457, 457, 457–465, 467, 471, 473, 473, 473, 475–476, 476, 476–477, 477, 477, 480–481, 481, 481–483, 488, 494, 494, 494, 494, 510–513, 515–518, 520–523, 525–527, 544, 544, 544, 544, 64, 67, 67, 67–69, 69, 69–76, 76, 76, 79, 79, 79–80, 82, 91–92, 94
   tag.c45.79%37.04%60%54.17%14, 17, 23–24, 24, 24, 24, 24–25, 27, 27, 27, 27, 27–28, 30, 30, 30–31, 33–34, 34, 34–35, 37, 37, 37, 37, 37–38, 40, 40, 40, 40, 40–41, 43, 63, 67–68, 83–85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85–87, 89
   timer.c97.50%83.33%100%100%14
   trigger.c100%100%100%100%
   util.c56.41%33.33%75%65.22%12–13, 13, 13–14, 14, 14–15, 15, 15–16, 18–19, 21, 24, 5
src/environments
   federated_environment.c85.11%70%100%90.22%113–116, 116, 116–119, 119, 119–121, 147–149, 25, 31, 43, 52, 55
   unfederated_environment.c93.41%71.43%100%96.88%13, 42, 42–43, 59–60
src/platform/posix
   posix.c84.87%63.64%86.67%90.24%114, 121, 126, 133, 17, 19, 21–23, 36–37, 59, 63, 77, 81, 95
   tcp_ip_channel.c70.56%57.31%100%79.38%102–103, 103, 103–104, 107–108, 108, 108–109, 112–113, 113, 113–114, 125–126, 128, 130, 134–135, 143, 146–147, 147, 147–148, 153–154, 154, 154–155, 161–162, 162, 162–163, 179, 182, 186, 186, 186, 186, 186–187, 187, 187–188, 188, 188–189, 191, 193, 193, 193–194, 203, 210–211, 216, 220–222, 222, 222–223, 226, 235, 235, 235–236, 269–270, 270, 270–271, 277, 282–283, 283, 283–284, 284, 284–285, 287–288, 288, 288–289, 289, 289, 291–292,

@tanneberger tanneberger merged commit bae8a83 into main May 15, 2026
11 of 15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Reduce test compilation times

3 participants