Repository navigation
Expand file tree
/
Copy pathCMakeLists.txt
More file actions
1414 lines (1361 loc) · 43.5 KB
/
Copy pathCMakeLists.txt
File metadata and controls
1414 lines (1361 loc) · 43.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
cmake_minimum_required(VERSION 3.25)
if(POLICY CMP0206)
cmake_policy(SET CMP0206 NEW)
endif()
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
message(
FATAL_ERROR
"In-source builds are unsupported; configure with a preset or pass a "
"separate build directory with -B"
)
endif()
project(
ParallelAssemblyCpp
VERSION 0.1.0
DESCRIPTION "Compute molecular and string assembly indices, pathways, and Re-Pair upper bounds"
HOMEPAGE_URL "https://github.com/ELIFE-ASU/parallelassemblycpp"
LANGUAGES CXX
)
include(GNUInstallDirs)
set(
PARALLELASSEMBLYCPP_EXECUTABLE_PERMISSIONS
OWNER_READ OWNER_WRITE OWNER_EXECUTE
GROUP_READ GROUP_EXECUTE
WORLD_READ WORLD_EXECUTE
)
set(
PARALLELASSEMBLYCPP_FILE_PERMISSIONS
OWNER_READ OWNER_WRITE
GROUP_READ
WORLD_READ
)
set(
CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS
${PARALLELASSEMBLYCPP_EXECUTABLE_PERMISSIONS}
)
option(
PARALLELASSEMBLYCPP_BUILD_TELEMETRY
"Build the instrumented ParallelAssemblyCppTelemetry executable"
OFF
)
option(
PARALLELASSEMBLYCPP_X86_64_V3
"Target x86-64-v3 with POPCNT"
OFF
)
option(
PARALLELASSEMBLYCPP_ENABLE_LTO
"Enable link-time optimization"
OFF
)
option(
PARALLELASSEMBLYCPP_VECTOR_CHAIN_BOUNDS
"Use certified composition bounds in addition to scalar addition-chain bounds"
ON
)
option(
PARALLELASSEMBLYCPP_STRICT_WARNINGS
"Treat high-signal compiler warnings as errors"
ON
)
set(
PARALLELASSEMBLYCPP_PGO_PHASE
"OFF"
CACHE STRING
"PGO phase: OFF, GENERATE, or USE"
)
set_property(
CACHE PARALLELASSEMBLYCPP_PGO_PHASE
PROPERTY STRINGS OFF GENERATE USE
)
set(
PARALLELASSEMBLYCPP_PGO_PROFILE_DIR
"${CMAKE_BINARY_DIR}/pgo-profiles"
CACHE PATH
"Shared PGO profile directory"
)
option(
PARALLELASSEMBLYCPP_FULL_REGRESSION_TESTS
"Run the full regression manifest"
OFF
)
option(
PARALLELASSEMBLYCPP_BUILD_OPENMP
"Build the experimental OpenMP executable"
OFF
)
option(
PARALLELASSEMBLYCPP_BUILD_MPI
"Build the experimental MPI executable"
OFF
)
option(
PARALLELASSEMBLYCPP_BUILD_HYBRID
"Build the experimental MPI/OpenMP executable"
OFF
)
set(_PARALLELASSEMBLYCPP_PGO_PHASES OFF GENERATE USE)
if(NOT PARALLELASSEMBLYCPP_PGO_PHASE IN_LIST _PARALLELASSEMBLYCPP_PGO_PHASES)
message(
FATAL_ERROR
"PARALLELASSEMBLYCPP_PGO_PHASE must be OFF, GENERATE, or USE; got "
"${PARALLELASSEMBLYCPP_PGO_PHASE}"
)
endif()
if(PARALLELASSEMBLYCPP_PGO_PHASE STREQUAL "OFF")
set(PARALLELASSEMBLYCPP_PGO_PROFILE_DIR_ABSOLUTE "")
else()
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
message(FATAL_ERROR "PGO requires GCC")
endif()
if(PARALLELASSEMBLYCPP_PGO_PROFILE_DIR STREQUAL "")
message(FATAL_ERROR "PARALLELASSEMBLYCPP_PGO_PROFILE_DIR must not be empty")
endif()
cmake_path(
ABSOLUTE_PATH PARALLELASSEMBLYCPP_PGO_PROFILE_DIR
BASE_DIRECTORY "${CMAKE_BINARY_DIR}"
NORMALIZE
OUTPUT_VARIABLE PARALLELASSEMBLYCPP_PGO_PROFILE_DIR_ABSOLUTE
)
set(
PARALLELASSEMBLYCPP_PGO_DIRECTORY_MARKER
"${PARALLELASSEMBLYCPP_PGO_PROFILE_DIR_ABSOLUTE}/.parallelassemblycpp-pgo-profile-directory"
)
if(PARALLELASSEMBLYCPP_PGO_PHASE STREQUAL "GENERATE")
file(MAKE_DIRECTORY "${PARALLELASSEMBLYCPP_PGO_PROFILE_DIR_ABSOLUTE}")
if(NOT EXISTS "${PARALLELASSEMBLYCPP_PGO_DIRECTORY_MARKER}")
file(
GLOB PARALLELASSEMBLYCPP_PGO_PROFILE_DIRECTORY_ENTRIES
LIST_DIRECTORIES true
"${PARALLELASSEMBLYCPP_PGO_PROFILE_DIR_ABSOLUTE}/*"
)
if(PARALLELASSEMBLYCPP_PGO_PROFILE_DIRECTORY_ENTRIES)
message(
FATAL_ERROR
"PGO profile directory is non-empty but unmarked: "
"${PARALLELASSEMBLYCPP_PGO_PROFILE_DIR_ABSOLUTE}"
)
endif()
file(
WRITE "${PARALLELASSEMBLYCPP_PGO_DIRECTORY_MARKER}"
"Dedicated ParallelAssemblyCpp PGO profile directory.\n"
)
elseif(
IS_DIRECTORY "${PARALLELASSEMBLYCPP_PGO_DIRECTORY_MARKER}"
OR IS_SYMLINK "${PARALLELASSEMBLYCPP_PGO_DIRECTORY_MARKER}"
)
message(FATAL_ERROR "PGO profile marker must be a regular file")
endif()
else()
if(
NOT EXISTS "${PARALLELASSEMBLYCPP_PGO_DIRECTORY_MARKER}"
OR IS_DIRECTORY "${PARALLELASSEMBLYCPP_PGO_DIRECTORY_MARKER}"
OR IS_SYMLINK "${PARALLELASSEMBLYCPP_PGO_DIRECTORY_MARKER}"
)
message(
FATAL_ERROR
"PGO profile marker is missing or invalid; configure preset "
"pgo-generate first"
)
endif()
set(
PARALLELASSEMBLYCPP_PGO_COMPLETION_FILE
"${PARALLELASSEMBLYCPP_PGO_PROFILE_DIR_ABSOLUTE}/parallelassemblycpp-pgo-complete.json"
)
if(NOT EXISTS "${PARALLELASSEMBLYCPP_PGO_COMPLETION_FILE}")
message(
FATAL_ERROR
"PGO training is incomplete; build preset pgo-train first"
)
endif()
file(READ "${PARALLELASSEMBLYCPP_PGO_COMPLETION_FILE}" PARALLELASSEMBLYCPP_PGO_COMPLETION)
string(
JSON PARALLELASSEMBLYCPP_PGO_COMPLETION_SCHEMA
ERROR_VARIABLE PARALLELASSEMBLYCPP_PGO_COMPLETION_ERROR
GET "${PARALLELASSEMBLYCPP_PGO_COMPLETION}" schema_version
)
if(
PARALLELASSEMBLYCPP_PGO_COMPLETION_ERROR
OR NOT PARALLELASSEMBLYCPP_PGO_COMPLETION_SCHEMA EQUAL 2
)
message(
FATAL_ERROR
"Invalid PGO training completion record: "
"${PARALLELASSEMBLYCPP_PGO_COMPLETION_FILE}"
)
endif()
string(
JSON PARALLELASSEMBLYCPP_PGO_RECORDED_WEIGHTS_SHA256
ERROR_VARIABLE PARALLELASSEMBLYCPP_PGO_WEIGHTS_ERROR
GET "${PARALLELASSEMBLYCPP_PGO_COMPLETION}" weights sha256
)
file(
SHA256 "${PROJECT_SOURCE_DIR}/benchmarks/pgo-training.tsv"
PARALLELASSEMBLYCPP_PGO_CURRENT_WEIGHTS_SHA256
)
if(
PARALLELASSEMBLYCPP_PGO_WEIGHTS_ERROR
OR NOT PARALLELASSEMBLYCPP_PGO_RECORDED_WEIGHTS_SHA256
STREQUAL PARALLELASSEMBLYCPP_PGO_CURRENT_WEIGHTS_SHA256
)
message(
FATAL_ERROR
"PGO training weights changed; rebuild preset pgo-train"
)
endif()
set(
PARALLELASSEMBLYCPP_PGO_MANIFEST
"${PROJECT_SOURCE_DIR}/benchmarks/cases.tsv"
)
string(
JSON PARALLELASSEMBLYCPP_PGO_RECORDED_MANIFEST_SHA256
ERROR_VARIABLE PARALLELASSEMBLYCPP_PGO_MANIFEST_ERROR
GET "${PARALLELASSEMBLYCPP_PGO_COMPLETION}" corpus manifest sha256
)
file(
SHA256 "${PARALLELASSEMBLYCPP_PGO_MANIFEST}"
PARALLELASSEMBLYCPP_PGO_CURRENT_MANIFEST_SHA256
)
if(
PARALLELASSEMBLYCPP_PGO_MANIFEST_ERROR
OR NOT PARALLELASSEMBLYCPP_PGO_RECORDED_MANIFEST_SHA256
STREQUAL PARALLELASSEMBLYCPP_PGO_CURRENT_MANIFEST_SHA256
)
message(
FATAL_ERROR
"Benchmark manifest changed; rebuild preset pgo-train"
)
endif()
string(
JSON PARALLELASSEMBLYCPP_PGO_INPUT_COUNT
ERROR_VARIABLE PARALLELASSEMBLYCPP_PGO_INPUT_COUNT_ERROR
LENGTH "${PARALLELASSEMBLYCPP_PGO_COMPLETION}" corpus inputs
)
if(
PARALLELASSEMBLYCPP_PGO_INPUT_COUNT_ERROR
OR PARALLELASSEMBLYCPP_PGO_INPUT_COUNT LESS 1
)
message(FATAL_ERROR "Invalid PGO corpus input fingerprints")
endif()
math(EXPR PARALLELASSEMBLYCPP_PGO_LAST_INPUT "${PARALLELASSEMBLYCPP_PGO_INPUT_COUNT} - 1")
set(PARALLELASSEMBLYCPP_PGO_CORPUS_FILES "${PARALLELASSEMBLYCPP_PGO_MANIFEST}")
foreach(PARALLELASSEMBLYCPP_PGO_INPUT_INDEX RANGE ${PARALLELASSEMBLYCPP_PGO_LAST_INPUT})
string(
JSON PARALLELASSEMBLYCPP_PGO_RECORDED_INPUT_PATH
ERROR_VARIABLE PARALLELASSEMBLYCPP_PGO_INPUT_PATH_ERROR
GET "${PARALLELASSEMBLYCPP_PGO_COMPLETION}"
corpus inputs ${PARALLELASSEMBLYCPP_PGO_INPUT_INDEX} path
)
string(
JSON PARALLELASSEMBLYCPP_PGO_RECORDED_INPUT_SHA256
ERROR_VARIABLE PARALLELASSEMBLYCPP_PGO_INPUT_SHA256_ERROR
GET "${PARALLELASSEMBLYCPP_PGO_COMPLETION}"
corpus inputs ${PARALLELASSEMBLYCPP_PGO_INPUT_INDEX} sha256
)
if(
PARALLELASSEMBLYCPP_PGO_INPUT_PATH_ERROR
OR PARALLELASSEMBLYCPP_PGO_INPUT_SHA256_ERROR
)
message(FATAL_ERROR "Invalid PGO corpus input fingerprint")
endif()
cmake_path(
ABSOLUTE_PATH PARALLELASSEMBLYCPP_PGO_RECORDED_INPUT_PATH
BASE_DIRECTORY "${PROJECT_SOURCE_DIR}"
NORMALIZE
OUTPUT_VARIABLE PARALLELASSEMBLYCPP_PGO_CURRENT_INPUT
)
if(
NOT EXISTS "${PARALLELASSEMBLYCPP_PGO_CURRENT_INPUT}"
OR IS_DIRECTORY "${PARALLELASSEMBLYCPP_PGO_CURRENT_INPUT}"
)
message(
FATAL_ERROR
"PGO input is missing: ${PARALLELASSEMBLYCPP_PGO_CURRENT_INPUT}; rebuild "
"preset pgo-train"
)
endif()
file(
SHA256 "${PARALLELASSEMBLYCPP_PGO_CURRENT_INPUT}"
PARALLELASSEMBLYCPP_PGO_CURRENT_INPUT_SHA256
)
if(
NOT PARALLELASSEMBLYCPP_PGO_RECORDED_INPUT_SHA256
STREQUAL PARALLELASSEMBLYCPP_PGO_CURRENT_INPUT_SHA256
)
message(
FATAL_ERROR
"PGO input changed: ${PARALLELASSEMBLYCPP_PGO_CURRENT_INPUT}; rebuild "
"preset pgo-train"
)
endif()
list(APPEND PARALLELASSEMBLYCPP_PGO_CORPUS_FILES "${PARALLELASSEMBLYCPP_PGO_CURRENT_INPUT}")
endforeach()
file(
GLOB_RECURSE PARALLELASSEMBLYCPP_PGO_PROFILE_DATA
LIST_DIRECTORIES false
"${PARALLELASSEMBLYCPP_PGO_PROFILE_DIR_ABSOLUTE}/*.gcda"
)
if(NOT PARALLELASSEMBLYCPP_PGO_PROFILE_DATA)
message(
FATAL_ERROR
"PGO data is missing from ${PARALLELASSEMBLYCPP_PGO_PROFILE_DIR_ABSOLUTE}; "
"build preset pgo-train first"
)
endif()
# Reconfigure when training inputs change to reject partial or stale data.
set_property(
DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
"${PARALLELASSEMBLYCPP_PGO_COMPLETION_FILE}"
"${PROJECT_SOURCE_DIR}/benchmarks/pgo-training.tsv"
${PARALLELASSEMBLYCPP_PGO_CORPUS_FILES}
)
endif()
endif()
if(PARALLELASSEMBLYCPP_ENABLE_LTO)
include(CheckIPOSupported)
check_ipo_supported(
RESULT PARALLELASSEMBLYCPP_LTO_SUPPORTED
OUTPUT PARALLELASSEMBLYCPP_LTO_ERROR
LANGUAGES CXX
)
if(NOT PARALLELASSEMBLYCPP_LTO_SUPPORTED)
message(FATAL_ERROR "LTO is unavailable: ${PARALLELASSEMBLYCPP_LTO_ERROR}")
endif()
endif()
function(parallelassemblycpp_configure_target target)
target_compile_features(${target} PRIVATE cxx_std_20)
if(NOT PARALLELASSEMBLYCPP_VECTOR_CHAIN_BOUNDS)
target_compile_definitions(
${target} PRIVATE PARALLELASSEMBLYCPP_DISABLE_VECTOR_CHAIN_BOUNDS
)
endif()
set_target_properties(
${target}
PROPERTIES
CXX_EXTENSIONS OFF
CXX_STANDARD_REQUIRED ON
INSTALL_REMOVE_ENVIRONMENT_RPATH ON
)
if(MSVC)
# These are language-conformance requirements, independent of diagnostics.
target_compile_options(
${target}
PRIVATE
/permissive-
/Zc:__cplusplus
/Zc:preprocessor
)
endif()
if(PARALLELASSEMBLYCPP_STRICT_WARNINGS)
set_property(TARGET ${target} PROPERTY COMPILE_WARNING_AS_ERROR ON)
if(MSVC)
target_compile_options(
${target}
PRIVATE
/W4
# Match the GNU/Clang policy: conversion warnings are handled in
# focused audits, cache-line alignment intentionally adds padding,
# and forced-inline failures are optimizer decisions rather than bugs.
/wd4244
/wd4267
/wd4324
/wd4714
)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
target_compile_options(
${target}
PRIVATE
-Wall
-Wextra
-Wpedantic
-Wcast-align
-Wcast-qual
-Wdouble-promotion
-Wextra-semi
-Wformat=2
-Wimplicit-fallthrough
-Wnon-virtual-dtor
-Wnull-dereference
-Wold-style-cast
-Woverloaded-virtual
-Wshadow
-Wswitch-enum
-Wundef
-Wzero-as-null-pointer-constant
)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_compile_options(
${target}
PRIVATE
-Walloc-zero
-Warray-bounds=2
-Wcast-function-type
-Wdate-time
-Wduplicated-branches
-Wduplicated-cond
-Wformat-overflow=2
-Wformat-signedness
-Wformat-truncation=2
-Wlogical-op
-Wredundant-decls
-Wstringop-overflow=4
-Wstringop-truncation
-Wtrampolines
-Wuseless-cast
-Wvla
)
endif()
else()
message(
FATAL_ERROR
"PARALLELASSEMBLYCPP_STRICT_WARNINGS supports GNU, Clang-compatible, and "
"MSVC toolchains; disable it only for unsupported compiler diagnosis"
)
endif()
endif()
if(PARALLELASSEMBLYCPP_ENABLE_LTO)
set_property(
TARGET ${target}
PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE
)
if(
CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
AND PARALLELASSEMBLYCPP_PGO_PHASE STREQUAL "OFF"
)
# One-partition LTO outperformed GCC's default without PGO.
set(
_PARALLELASSEMBLYCPP_GNU_LTO_OPTIONS
-flto-partition=one
-fipa-pta
-fno-semantic-interposition
-fdevirtualize-at-ltrans
-fno-plt
)
target_compile_options(
${target}
PRIVATE ${_PARALLELASSEMBLYCPP_GNU_LTO_OPTIONS}
)
target_link_options(
${target}
PRIVATE ${_PARALLELASSEMBLYCPP_GNU_LTO_OPTIONS}
)
endif()
endif()
if(WIN32)
target_compile_definitions(${target} PRIVATE NOMINMAX WIN32_LEAN_AND_MEAN)
endif()
if(PARALLELASSEMBLYCPP_X86_64_V3)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag("-march=x86-64-v3" PARALLELASSEMBLYCPP_HAS_X86_64_V3)
check_cxx_compiler_flag("-mpopcnt" PARALLELASSEMBLYCPP_HAS_MPOPCNT)
if(NOT PARALLELASSEMBLYCPP_HAS_X86_64_V3 OR NOT PARALLELASSEMBLYCPP_HAS_MPOPCNT)
message(
FATAL_ERROR
"PARALLELASSEMBLYCPP_X86_64_V3 requires compiler support for "
"-march=x86-64-v3 and -mpopcnt"
)
endif()
target_compile_options(${target} PRIVATE -march=x86-64-v3 -mpopcnt)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# Allow more inlining for template-heavy search loops.
target_compile_options(
${target}
PRIVATE --param=inline-unit-growth=104
)
if(
NOT PARALLELASSEMBLYCPP_ENABLE_LTO
AND PARALLELASSEMBLYCPP_PGO_PHASE STREQUAL "OFF"
)
# GCC's versioned AVX2 loops bloat short-circuit mask operations.
# Keep straight-line SLP vectorization while disabling loop
# vectorization.
target_compile_options(
${target}
PRIVATE -fno-tree-loop-vectorize
)
endif()
endif()
else()
message(
FATAL_ERROR
"PARALLELASSEMBLYCPP_X86_64_V3 is supported only by GCC-compatible and "
"Clang-compatible compilers"
)
endif()
endif()
endfunction()
function(parallelassemblycpp_configure_test_target target)
parallelassemblycpp_configure_target(${target})
# Release-style configurations define NDEBUG globally. Keep standard assert
# checks active in test executables until they use an always-active helper.
if(MSVC)
target_compile_options(${target} PRIVATE /UNDEBUG)
else()
target_compile_options(${target} PRIVATE -UNDEBUG)
endif()
endfunction()
function(parallelassemblycpp_configure_pgo_target target)
if(PARALLELASSEMBLYCPP_PGO_PHASE STREQUAL "GENERATE")
set(
_PARALLELASSEMBLYCPP_PGO_OPTIONS
"-fprofile-generate=${PARALLELASSEMBLYCPP_PGO_PROFILE_DIR_ABSOLUTE}"
"-fprofile-prefix-path=${CMAKE_BINARY_DIR}"
)
elseif(PARALLELASSEMBLYCPP_PGO_PHASE STREQUAL "USE")
set(
_PARALLELASSEMBLYCPP_PGO_OPTIONS
"-fprofile-use=${PARALLELASSEMBLYCPP_PGO_PROFILE_DIR_ABSOLUTE}"
"-fprofile-prefix-path=${CMAKE_BINARY_DIR}"
-fno-tracer
-fno-reorder-blocks-and-partition
-Werror=missing-profile
-Werror=coverage-mismatch
)
else()
return()
endif()
# Only the CLI is trained; instrumenting other targets creates profile gaps.
target_compile_options(${target} PRIVATE ${_PARALLELASSEMBLYCPP_PGO_OPTIONS})
target_link_options(${target} PRIVATE ${_PARALLELASSEMBLYCPP_PGO_OPTIONS})
endfunction()
function(parallelassemblycpp_add_solver target)
cmake_parse_arguments(
PARSE_ARGV 1
PARALLELASSEMBLYCPP_SOLVER
"MPI;OPENMP;TELEMETRY"
""
""
)
if(PARALLELASSEMBLYCPP_SOLVER_UNPARSED_ARGUMENTS)
message(
FATAL_ERROR
"Unknown options for ${target}: ${PARALLELASSEMBLYCPP_SOLVER_UNPARSED_ARGUMENTS}"
)
endif()
add_executable(${target} src/main.cpp)
set(PARALLELASSEMBLYCPP_SOLVER_DEFINITIONS)
set(PARALLELASSEMBLYCPP_SOLVER_LIBRARIES)
if(PARALLELASSEMBLYCPP_SOLVER_MPI)
list(APPEND PARALLELASSEMBLYCPP_SOLVER_DEFINITIONS PARALLELASSEMBLYCPP_USE_MPI)
list(APPEND PARALLELASSEMBLYCPP_SOLVER_LIBRARIES MPI::MPI_CXX Threads::Threads)
endif()
if(PARALLELASSEMBLYCPP_SOLVER_OPENMP)
list(APPEND PARALLELASSEMBLYCPP_SOLVER_DEFINITIONS PARALLELASSEMBLYCPP_USE_OPENMP)
list(APPEND PARALLELASSEMBLYCPP_SOLVER_LIBRARIES OpenMP::OpenMP_CXX)
endif()
if(PARALLELASSEMBLYCPP_SOLVER_TELEMETRY)
list(APPEND PARALLELASSEMBLYCPP_SOLVER_DEFINITIONS ASSEMBLY_ENABLE_TELEMETRY)
endif()
if(PARALLELASSEMBLYCPP_SOLVER_DEFINITIONS)
target_compile_definitions(
${target}
PRIVATE ${PARALLELASSEMBLYCPP_SOLVER_DEFINITIONS}
)
endif()
if(PARALLELASSEMBLYCPP_SOLVER_LIBRARIES)
target_link_libraries(${target} PRIVATE ${PARALLELASSEMBLYCPP_SOLVER_LIBRARIES})
endif()
parallelassemblycpp_configure_target(${target})
endfunction()
add_library(ParallelAssemblyCppLibrary STATIC src/main.cpp src/stringApi.cpp)
add_library(ParallelAssemblyCpp::Library ALIAS ParallelAssemblyCppLibrary)
target_compile_definitions(
ParallelAssemblyCppLibrary
PRIVATE PARALLELASSEMBLYCPP_LIBRARY_BUILD PARALLELASSEMBLYCPP_NO_MAIN
)
target_include_directories(
ParallelAssemblyCppLibrary
PUBLIC
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/parallelassemblycpp>"
)
target_compile_features(ParallelAssemblyCppLibrary PUBLIC cxx_std_20)
set_target_properties(
ParallelAssemblyCppLibrary
PROPERTIES
EXPORT_NAME Library
OUTPUT_NAME parallelassemblycpp
POSITION_INDEPENDENT_CODE ON
)
parallelassemblycpp_configure_target(ParallelAssemblyCppLibrary)
parallelassemblycpp_add_solver(ParallelAssemblyCpp)
parallelassemblycpp_configure_pgo_target(ParallelAssemblyCpp)
if(PARALLELASSEMBLYCPP_BUILD_OPENMP OR PARALLELASSEMBLYCPP_BUILD_HYBRID)
find_package(OpenMP REQUIRED COMPONENTS CXX)
endif()
if(PARALLELASSEMBLYCPP_BUILD_MPI OR PARALLELASSEMBLYCPP_BUILD_HYBRID)
find_package(MPI REQUIRED COMPONENTS CXX)
find_package(Threads REQUIRED)
endif()
if(PARALLELASSEMBLYCPP_BUILD_OPENMP)
parallelassemblycpp_add_solver(ParallelAssemblyCppOMP OPENMP)
endif()
if(PARALLELASSEMBLYCPP_BUILD_MPI)
parallelassemblycpp_add_solver(ParallelAssemblyCppMPI MPI)
endif()
if(PARALLELASSEMBLYCPP_BUILD_HYBRID)
parallelassemblycpp_add_solver(ParallelAssemblyCppHybrid MPI OPENMP)
endif()
if(PARALLELASSEMBLYCPP_BUILD_TELEMETRY)
parallelassemblycpp_add_solver(ParallelAssemblyCppTelemetry TELEMETRY)
if(PARALLELASSEMBLYCPP_BUILD_OPENMP)
parallelassemblycpp_add_solver(ParallelAssemblyCppOMPTelemetry OPENMP TELEMETRY)
endif()
if(PARALLELASSEMBLYCPP_BUILD_MPI)
parallelassemblycpp_add_solver(ParallelAssemblyCppMPITelemetry MPI TELEMETRY)
endif()
if(PARALLELASSEMBLYCPP_BUILD_HYBRID)
parallelassemblycpp_add_solver(ParallelAssemblyCppHybridTelemetry MPI OPENMP TELEMETRY)
endif()
endif()
if(PARALLELASSEMBLYCPP_X86_64_V3 AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# Internalize single-file targets while preserving public library symbols.
foreach(
PARALLELASSEMBLYCPP_WHOLE_PROGRAM_TARGET
ParallelAssemblyCpp
ParallelAssemblyCppLibrary
ParallelAssemblyCppOMP
ParallelAssemblyCppMPI
ParallelAssemblyCppHybrid
ParallelAssemblyCppTelemetry
ParallelAssemblyCppOMPTelemetry
ParallelAssemblyCppMPITelemetry
ParallelAssemblyCppHybridTelemetry
)
if(TARGET ${PARALLELASSEMBLYCPP_WHOLE_PROGRAM_TARGET})
target_compile_options(
${PARALLELASSEMBLYCPP_WHOLE_PROGRAM_TARGET}
PRIVATE -fwhole-program
)
endif()
endforeach()
endif()
install(
TARGETS ParallelAssemblyCpp ParallelAssemblyCppLibrary
EXPORT ParallelAssemblyCppTargets
RUNTIME
DESTINATION "${CMAKE_INSTALL_BINDIR}"
PERMISSIONS ${PARALLELASSEMBLYCPP_EXECUTABLE_PERMISSIONS}
ARCHIVE
DESTINATION "${CMAKE_INSTALL_LIBDIR}"
PERMISSIONS ${PARALLELASSEMBLYCPP_FILE_PERMISSIONS}
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/parallelassemblycpp"
)
install(
FILES src/parallelassemblycpp.h
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/parallelassemblycpp"
PERMISSIONS ${PARALLELASSEMBLYCPP_FILE_PERMISSIONS}
)
install(
FILES README.md License.md
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/doc/parallelassemblycpp"
PERMISSIONS ${PARALLELASSEMBLYCPP_FILE_PERMISSIONS}
)
install(
DIRECTORY docs/
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/doc/parallelassemblycpp/docs"
FILE_PERMISSIONS ${PARALLELASSEMBLYCPP_FILE_PERMISSIONS}
DIRECTORY_PERMISSIONS ${PARALLELASSEMBLYCPP_EXECUTABLE_PERMISSIONS}
FILES_MATCHING PATTERN "*.md"
)
foreach(PARALLELASSEMBLYCPP_GUIDE_DIRECTORY benchmarks unitTests)
install(
FILES "${PARALLELASSEMBLYCPP_GUIDE_DIRECTORY}/README.md"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/doc/parallelassemblycpp/${PARALLELASSEMBLYCPP_GUIDE_DIRECTORY}"
PERMISSIONS ${PARALLELASSEMBLYCPP_FILE_PERMISSIONS}
)
endforeach()
install(
EXPORT ParallelAssemblyCppTargets
FILE ParallelAssemblyCppTargets.cmake
NAMESPACE ParallelAssemblyCpp::
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ParallelAssemblyCpp"
)
include(CMakePackageConfigHelpers)
configure_package_config_file(
cmake/ParallelAssemblyCppConfig.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/ParallelAssemblyCppConfig.cmake"
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ParallelAssemblyCpp"
)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/ParallelAssemblyCppConfigVersion.cmake"
VERSION "${PROJECT_VERSION}"
COMPATIBILITY SameMajorVersion
)
install(
FILES
"${CMAKE_CURRENT_BINARY_DIR}/ParallelAssemblyCppConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/ParallelAssemblyCppConfigVersion.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/ParallelAssemblyCpp"
)
if(UNIX AND NOT APPLE)
# Remove absolute RPATHs injected by Conda compiler wrappers.
if(IS_ABSOLUTE "${CMAKE_INSTALL_BINDIR}")
set(
PARALLELASSEMBLYCPP_INSTALLED_EXECUTABLE
"\$ENV{DESTDIR}${CMAKE_INSTALL_BINDIR}/ParallelAssemblyCpp"
)
else()
set(
PARALLELASSEMBLYCPP_INSTALLED_EXECUTABLE
"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/ParallelAssemblyCpp"
)
endif()
install(
CODE
"file(RPATH_REMOVE FILE \"${PARALLELASSEMBLYCPP_INSTALLED_EXECUTABLE}\")"
)
endif()
include(CTest)
if(PARALLELASSEMBLYCPP_FULL_REGRESSION_TESTS AND NOT BUILD_TESTING)
message(
FATAL_ERROR
"PARALLELASSEMBLYCPP_FULL_REGRESSION_TESTS requires BUILD_TESTING=ON"
)
endif()
if(BUILD_TESTING OR PARALLELASSEMBLYCPP_PGO_PHASE STREQUAL "GENERATE")
find_package(Python3 3.10 REQUIRED COMPONENTS Interpreter)
endif()
if(PARALLELASSEMBLYCPP_PGO_PHASE STREQUAL "GENERATE")
add_custom_target(
pgo-train
COMMAND
"${Python3_EXECUTABLE}"
"${PROJECT_SOURCE_DIR}/benchmarks/pgo_training.py"
--executable "$<TARGET_FILE:ParallelAssemblyCpp>"
--profile-dir "${PARALLELASSEMBLYCPP_PGO_PROFILE_DIR_ABSOLUTE}"
--weights "${PROJECT_SOURCE_DIR}/benchmarks/pgo-training.tsv"
DEPENDS ParallelAssemblyCpp
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
USES_TERMINAL
VERBATIM
)
endif()
function(parallelassemblycpp_add_unit_test name target source)
add_executable(${target} ${source})
parallelassemblycpp_configure_test_target(${target})
add_test(NAME unit.${name} COMMAND ${target} ${ARGN})
set_tests_properties(
unit.${name}
PROPERTIES
LABELS "unit"
TIMEOUT 300
)
endfunction()
function(parallelassemblycpp_add_python_test name timeout)
add_test(NAME ${name} COMMAND "${Python3_EXECUTABLE}" ${ARGN})
set_tests_properties(
${name}
PROPERTIES
LABELS "tooling"
TIMEOUT ${timeout}
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
)
endfunction()
if(BUILD_TESTING)
find_package(Threads REQUIRED)
parallelassemblycpp_add_unit_test(
clock-ticks
parallelassemblycpp_clock_ticks_tests
unitTests/clockTicksTester.cpp
)
parallelassemblycpp_add_unit_test(
consolidation-kernels
parallelassemblycpp_consolidation_kernels_tests
unitTests/consolidationKernelsTester.cpp
)
target_compile_definitions(
parallelassemblycpp_consolidation_kernels_tests
PRIVATE ASSEMBLY_ENABLE_TELEMETRY
)
parallelassemblycpp_add_unit_test(
addition-chain-bounds
parallelassemblycpp_addition_chain_bounds_tests
unitTests/additionChainBoundsTester.cpp
)
parallelassemblycpp_add_unit_test(
active-word-mask
parallelassemblycpp_active_word_mask_tests
unitTests/activeWordMaskTester.cpp
)
parallelassemblycpp_add_unit_test(
active-word-mask-lifetime
parallelassemblycpp_active_word_mask_lifetime_tests
unitTests/activeWordMaskLifetimeTester.cpp
)
target_link_libraries(
parallelassemblycpp_active_word_mask_lifetime_tests
PRIVATE Threads::Threads
)
set_tests_properties(
unit.active-word-mask-lifetime
PROPERTIES LABELS "unit;parallel"
)
parallelassemblycpp_add_unit_test(
assembly-transposition-table
parallelassemblycpp_transposition_table_tests
unitTests/assemblyTranspositionTableTester.cpp
)
parallelassemblycpp_add_unit_test(
assembly-transposition-table-telemetry
parallelassemblycpp_transposition_table_telemetry_tests
unitTests/assemblyTranspositionTableTester.cpp
)
target_compile_definitions(
parallelassemblycpp_transposition_table_telemetry_tests
PRIVATE ASSEMBLY_ENABLE_TELEMETRY
)
set_tests_properties(
unit.assembly-transposition-table-telemetry
PROPERTIES LABELS "unit;telemetry"
)
add_executable(
parallelassemblycpp_tree_canon_tests
unitTests/treeCanonTester.cpp
)
parallelassemblycpp_configure_test_target(parallelassemblycpp_tree_canon_tests)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
add_test(
NAME unit.tree-canonicalisation
COMMAND
sh -c "ulimit -s 64 && exec \"$1\"" _
"$<TARGET_FILE:parallelassemblycpp_tree_canon_tests>"
)
else()
add_test(
NAME unit.tree-canonicalisation
COMMAND parallelassemblycpp_tree_canon_tests
)
endif()
set_tests_properties(
unit.tree-canonicalisation
PROPERTIES
LABELS "unit"
TIMEOUT 300
)
parallelassemblycpp_add_unit_test(
cyclic-canonicalisation
parallelassemblycpp_cyclic_canon_tests
unitTests/cyclicCanonTester.cpp
)
parallelassemblycpp_add_unit_test(
search-stop-polling
parallelassemblycpp_search_stop_poll_tests
unitTests/searchStopPollTester.cpp
)
parallelassemblycpp_add_unit_test(
matching-bound-refresh
parallelassemblycpp_matching_bound_refresh_tests
unitTests/matchingBoundRefreshTester.cpp
)
parallelassemblycpp_add_unit_test(
matching-bound-refresh-telemetry
parallelassemblycpp_matching_bound_refresh_telemetry_tests
unitTests/matchingBoundRefreshTester.cpp
)
target_compile_definitions(
parallelassemblycpp_matching_bound_refresh_telemetry_tests
PRIVATE ASSEMBLY_ENABLE_TELEMETRY
)
set_tests_properties(
unit.matching-bound-refresh-telemetry
PROPERTIES LABELS "unit;telemetry"
)
parallelassemblycpp_add_unit_test(
fragmentation-metadata
parallelassemblycpp_fragmentation_metadata_tests
unitTests/fragmentationMetadataTester.cpp
)
parallelassemblycpp_add_unit_test(
parallel-task-transfer
parallelassemblycpp_parallel_task_transfer_tests
unitTests/parallelTaskTransferTester.cpp
)
set_tests_properties(
unit.parallel-task-transfer
PROPERTIES LABELS "unit;parallel"
)
target_compile_definitions(
parallelassemblycpp_parallel_task_transfer_tests
PRIVATE ASSEMBLY_ENABLE_TELEMETRY
)
if(TARGET OpenMP::OpenMP_CXX)
target_compile_definitions(
parallelassemblycpp_parallel_task_transfer_tests
PRIVATE PARALLELASSEMBLYCPP_USE_OPENMP
)
target_link_libraries(
parallelassemblycpp_parallel_task_transfer_tests
PRIVATE OpenMP::OpenMP_CXX
)
endif()
if(TARGET MPI::MPI_CXX)
add_executable(
parallelassemblycpp_mpi_refill_tests
unitTests/mpiRefillTester.cpp
)
parallelassemblycpp_configure_test_target(parallelassemblycpp_mpi_refill_tests)
target_compile_definitions(
parallelassemblycpp_mpi_refill_tests
PRIVATE PARALLELASSEMBLYCPP_USE_MPI ASSEMBLY_ENABLE_TELEMETRY
)
target_link_libraries(
parallelassemblycpp_mpi_refill_tests
PRIVATE MPI::MPI_CXX Threads::Threads
)
add_test(
NAME unit.mpi-refill
COMMAND
"${MPIEXEC_EXECUTABLE}" "${MPIEXEC_NUMPROC_FLAG}" 2
${MPIEXEC_PREFLAGS}
"$<TARGET_FILE:parallelassemblycpp_mpi_refill_tests>"
${MPIEXEC_POSTFLAGS}
)
set_tests_properties(
unit.mpi-refill
PROPERTIES
LABELS "unit;parallel;mpi;telemetry"
PROCESSORS 8
TIMEOUT 60
)
endif()
parallelassemblycpp_add_unit_test(
molfile-parser
parallelassemblycpp_molfile_parser_tests
unitTests/molfileParserTester.cpp
)
parallelassemblycpp_add_unit_test(
native-graph-parser
parallelassemblycpp_graphio_tests
unitTests/graphioTester.cpp
)
parallelassemblycpp_add_unit_test(
pathway-generator
parallelassemblycpp_pathway_generator_tests
unitTests/pathwayGeneratorTester.cpp
)
add_executable(parallelassemblycpp_graph_repair_probe unitTests/graphRepairProbe.cpp)
parallelassemblycpp_configure_test_target(parallelassemblycpp_graph_repair_probe)
add_executable(
parallelassemblycpp_graph_addition_chain_probe
unitTests/graphAdditionChainProbe.cpp
)
parallelassemblycpp_configure_test_target(parallelassemblycpp_graph_addition_chain_probe)
target_link_libraries(
parallelassemblycpp_graph_addition_chain_probe PRIVATE ParallelAssemblyCppLibrary
)
set(graph_addition_chain_test_options)
if(PARALLELASSEMBLYCPP_FULL_REGRESSION_TESTS)
list(APPEND graph_addition_chain_test_options --full)
endif()
add_test(
NAME unit.graph-addition-chain-bounds
COMMAND "${Python3_EXECUTABLE}"
"${PROJECT_SOURCE_DIR}/unitTests/graphAdditionChainTester.py"
"$<TARGET_FILE:parallelassemblycpp_graph_addition_chain_probe>"