| File: | t/08-validation.t |
| Coverage: | 99.5% |
| line | stmt | bran | cond | sub | pod | time | code |
|---|---|---|---|---|---|---|---|
| 1 | 1 1 1 | 2957 2 24 | use strict; | ||||
| 2 | 1 1 1 | 3 0 36 | use warnings; | ||||
| 3 | |||||||
| 4 | 1 1 1 | 249 1338 116 | use FindBin qw/$Bin/; | ||||
| 5 | 1 1 1 | 287 605 6 | use lib qq{$Bin/../lib}; | ||||
| 6 | 1 1 1 | 545 83285 7 | use Test::More; | ||||
| 7 | |||||||
| 8 | 1 | 3111 | use OpenMP::Environment::Validation qw/ | ||||
| 9 | validate_value validate_assignment assert_variable assert_environment | ||||||
| 10 | analyze_environment validation_rules | ||||||
| 11 | 1 1 | 726 3 | /; | ||||
| 12 | |||||||
| 13 | sub rejects { | ||||||
| 14 | 58 | 120 | my ( $name, $value, $label, $pattern ) = @_; | ||||
| 15 | 58 | 65 | local $@; | ||||
| 16 | 58 58 | 79 119 | eval { validate_value( $name, $value ) }; | ||||
| 17 | 58 | 169 | ok length($@), $label; | ||||
| 18 | 58 | 16346 | like $@, $pattern || qr/\Q$name\E/, qq{$label reports a useful diagnostic}; | ||||
| 19 | } | ||||||
| 20 | |||||||
| 21 | 1 | 73850 | my $rules = validation_rules(); | ||||
| 22 | 1 1 | 3 6 | is scalar( @{ $rules->{fields} } ), 25, q{validation metadata contains every supported field}; | ||||
| 23 | 1 1 | 341 5 | is scalar( keys %{ $rules->{validators} } ), 25, q{validation metadata contains every validator}; | ||||
| 24 | 1 6 1 | 273 10 2 | ok grep( { $_ eq q{OMP_CANCELLATION} } @{ $rules->{normalized} } ), q{validation metadata records legacy-normalized variables}; | ||||
| 25 | 1 15 1 | 251 18 3 | ok grep( { $_ eq q{OMP_NUM_THREADS} } @{ $rules->{assignment_validated} } ), q{validation metadata records variables validated during compatible assignment}; | ||||
| 26 | 1 | 248 | is_deeply $rules->{whitespace_significant}, [ q{OMP_AFFINITY_FORMAT} ], q{validation metadata identifies the OpenMP whitespace-significant exception}; | ||||
| 27 | 1 | 507 | is $rules->{profile}, q{OpenMP 5.2 + GCC 16.2/libgomp}, q{validation metadata names the selected standards/runtime profile}; | ||||
| 28 | |||||||
| 29 | 1 | 269 | local $@; | ||||
| 30 | 1 1 | 1 3 | eval { validate_value( undef, 1 ) }; | ||||
| 31 | 1 | 13 | like $@, qr/name is required/, q{validate_value requires a variable name}; | ||||
| 32 | 1 1 | 459 4 | eval { validate_value( q{OMP_NOT_REAL}, 1 ) }; | ||||
| 33 | 1 | 10 | like $@, qr/Unsupported/, q{validate_value rejects unsupported names}; | ||||
| 34 | 1 | 455 | is validate_value( q{OMP_NUM_THREADS}, undef ), undef, q{validate_value passes undef through}; | ||||
| 35 | |||||||
| 36 | 1 | 634 | is validate_assignment( q{GOMP_SPINCOUNT}, q{historical pass through} ), q{historical pass through}, q{assignment compatibility keeps formerly unvalidated values pass-through}; | ||||
| 37 | 1 | 514 | is validate_assignment( q{OMP_CANCELLATION}, q{true} ), q{TRUE}, q{assignment validation retains legacy normalization}; | ||||
| 38 | 1 1 | 485 5 | eval { validate_assignment( undef, 1 ) }; | ||||
| 39 | 1 | 10 | like $@, qr/name is required/, q{validate_assignment requires a variable name}; | ||||
| 40 | 1 1 | 454 4 | eval { validate_assignment( q{OMP_NOT_REAL}, 1 ) }; | ||||
| 41 | 1 | 9 | like $@, qr/Unsupported/, q{validate_assignment rejects unsupported names}; | ||||
| 42 | 1 | 490 | is validate_assignment( q{GOMP_SPINCOUNT}, undef ), undef, q{validate_assignment passes undef through}; | ||||
| 43 | |||||||
| 44 | 1 | 598 | is validate_value( q{OMP_CANCELLATION}, q{true} ), q{TRUE}, q{OMP_CANCELLATION accepts true}; | ||||
| 45 | 1 | 484 | is validate_value( q{OMP_CANCELLATION}, q{ true } ), q{TRUE}, q{OMP_CANCELLATION accepts OpenMP-permitted surrounding whitespace}; | ||||
| 46 | 1 | 485 | rejects( q{OMP_CANCELLATION}, q{sometimes}, q{OMP_CANCELLATION rejects unknown boolean}, qr/TRUE/ ); | ||||
| 47 | 1 | 451 | is validate_value( q{OMP_DISPLAY_ENV}, q{verbose} ), q{VERBOSE}, q{OMP_DISPLAY_ENV accepts VERBOSE}; | ||||
| 48 | 1 | 495 | rejects( q{OMP_DISPLAY_ENV}, q{ALL}, q{OMP_DISPLAY_ENV rejects unknown display level} ); | ||||
| 49 | 1 | 446 | is validate_value( q{OMP_DEFAULT_DEVICE}, 0 ), 0, q{OMP_DEFAULT_DEVICE accepts zero}; | ||||
| 50 | 1 | 504 | is validate_value( q{OMP_DEFAULT_DEVICE}, q{ 0 } ), q{0}, q{OMP_DEFAULT_DEVICE ignores surrounding OpenMP whitespace in strict validation}; | ||||
| 51 | 1 | 486 | rejects( q{OMP_DEFAULT_DEVICE}, -1, q{OMP_DEFAULT_DEVICE rejects negative values}, qr/integer/ ); | ||||
| 52 | 1 | 448 | rejects( q{OMP_DEFAULT_DEVICE}, q{gpu0}, q{OMP_DEFAULT_DEVICE rejects non-integers}, qr/integer/ ); | ||||
| 53 | 1 | 441 | is validate_value( q{OMP_NUM_TEAMS}, 1 ), 1, q{OMP_NUM_TEAMS accepts a positive integer}; | ||||
| 54 | 1 | 478 | rejects( q{OMP_NUM_TEAMS}, 0, q{OMP_NUM_TEAMS rejects zero} ); | ||||
| 55 | 1 | 482 | is validate_value( q{OMP_DYNAMIC}, q{true} ), q{true}, q{OMP_DYNAMIC accepts true without changing historical case}; | ||||
| 56 | 1 | 476 | is validate_value( q{OMP_DYNAMIC}, 1 ), 1, q{OMP_DYNAMIC retains historical numeric true support}; | ||||
| 57 | 1 | 478 | rejects( q{OMP_DYNAMIC}, q{maybe}, q{OMP_DYNAMIC rejects non-boolean value} ); | ||||
| 58 | 1 | 454 | is validate_value( q{OMP_MAX_ACTIVE_LEVELS}, 1 ), 1, q{OMP_MAX_ACTIVE_LEVELS follows libgomp positive-integer rule}; | ||||
| 59 | 1 | 481 | rejects( q{OMP_MAX_ACTIVE_LEVELS}, 0, q{OMP_MAX_ACTIVE_LEVELS applies the documented libgomp/legacy positive-integer profile even though OpenMP 5.2 permits zero} ); | ||||
| 60 | 1 | 451 | is validate_value( q{OMP_MAX_TASK_PRIORITY}, 0 ), 0, q{OMP_MAX_TASK_PRIORITY accepts zero}; | ||||
| 61 | 1 | 479 | rejects( q{OMP_MAX_TASK_PRIORITY}, -1, q{OMP_MAX_TASK_PRIORITY rejects negative values} ); | ||||
| 62 | 1 | 445 | is validate_value( q{OMP_NESTED}, q{true} ), q{TRUE}, q{OMP_NESTED retains uppercase filter}; | ||||
| 63 | 1 | 478 | is validate_value( q{OMP_NESTED}, 0 ), 0, q{OMP_NESTED retains numeric false compatibility}; | ||||
| 64 | 1 | 480 | rejects( q{OMP_NESTED}, q{maybe}, q{OMP_NESTED rejects non-boolean value} ); | ||||
| 65 | 1 | 448 | is validate_value( q{OMP_NUM_THREADS}, q{8, 4, 2} ), q{8, 4, 2}, q{OMP_NUM_THREADS accepts nested positive-integer lists}; | ||||
| 66 | 1 | 480 | rejects( q{OMP_NUM_THREADS}, q{8,0,2}, q{OMP_NUM_THREADS rejects zero in a list}, qr/comma-separated/ ); | ||||
| 67 | |||||||
| 68 | 1 | 445 | for my $value ( q{TRUE}, q{FALSE}, q{PRIMARY}, q{CLOSE}, q{SPREAD}, q{MASTER,CLOSE,SPREAD}, q{spread,close,primary} ) { | ||||
| 69 | 7 | 2905 | is validate_value( q{OMP_PROC_BIND}, $value ), $value, qq{OMP_PROC_BIND accepts $value}; | ||||
| 70 | } | ||||||
| 71 | 1 | 481 | rejects( q{OMP_PROC_BIND}, q{TRUE,CLOSE}, q{OMP_PROC_BIND does not mix boolean and policy-list syntax} ); | ||||
| 72 | 1 | 449 | rejects( q{OMP_PROC_BIND}, q{NEAR}, q{OMP_PROC_BIND rejects an unknown policy} ); | ||||
| 73 | |||||||
| 74 | 1 | 447 | for my $value ( | ||||
| 75 | q{cores}, q{cores(4)}, q{vendor_places(2)}, q{{0,1,2},{3,4,5}}, | ||||||
| 76 | q{{0:4},{4:4}}, q{!{0},1:3}, q{{0}:4:2}, q{0:4:2} | ||||||
| 77 | ) { | ||||||
| 78 | 8 | 3475 | is validate_value( q{OMP_PLACES}, $value ), $value, qq{OMP_PLACES accepts $value}; | ||||
| 79 | } | ||||||
| 80 | 1 | 486 | rejects( q{OMP_PLACES}, q{}, q{OMP_PLACES rejects an empty value} ); | ||||
| 81 | 1 | 450 | rejects( q{OMP_PLACES}, q{{0,,2}}, q{OMP_PLACES rejects an empty resource} ); | ||||
| 82 | 1 | 452 | rejects( q{OMP_PLACES}, q{{0,2},}, q{OMP_PLACES rejects an empty place} ); | ||||
| 83 | 1 | 450 | rejects( q{OMP_PLACES}, '{0,2}, {3', q{OMP_PLACES rejects unbalanced braces} ); | ||||
| 84 | 1 | 450 | rejects( q{OMP_PLACES}, q{{x}}, q{OMP_PLACES rejects a nonnumeric explicit resource} ); | ||||
| 85 | 1 | 448 | is validate_value( q{OMP_PLACES}, q{{!0,1}} ), q{{!0,1}}, q{OMP_PLACES accepts resource exclusion syntax}; | ||||
| 86 | 1 | 212 | rejects( q{OMP_PLACES}, q{@}, q{OMP_PLACES rejects a malformed explicit place} ); | ||||
| 87 | 1 | 193 | rejects( q{OMP_PLACES}, '0}', q{OMP_PLACES rejects an unmatched closing brace} ); | ||||
| 88 | 1 | 190 | rejects( q{OMP_PLACES}, q{{}}, q{OMP_PLACES rejects an empty explicit resource list} ); | ||||
| 89 | 1 | 197 | rejects( q{OMP_PLACES}, q{0:0}, q{OMP_PLACES rejects a zero-length place interval} ); | ||||
| 90 | |||||||
| 91 | 1 | 192 | for my $value ( q{1}, q{1024}, q{64M}, q{2G}, q{4096K} ) { | ||||
| 92 | 5 | 831 | is validate_value( q{OMP_STACKSIZE}, $value ), $value, qq{OMP_STACKSIZE accepts $value}; | ||||
| 93 | } | ||||||
| 94 | 1 | 205 | rejects( q{OMP_STACKSIZE}, q{0}, q{OMP_STACKSIZE rejects zero} ); | ||||
| 95 | 1 | 194 | rejects( q{OMP_STACKSIZE}, q{4T}, q{OMP_STACKSIZE rejects an unsupported unit} ); | ||||
| 96 | |||||||
| 97 | 1 | 191 | for my $value ( q{static}, q{dynamic,4}, q{guided,8}, q{auto}, q{monotonic:static}, q{nonmonotonic:dynamic,4} ) { | ||||
| 98 | 6 | 1032 | is validate_value( q{OMP_SCHEDULE}, $value ), $value, qq{OMP_SCHEDULE accepts $value}; | ||||
| 99 | } | ||||||
| 100 | 1 | 207 | rejects( q{OMP_SCHEDULE}, q{banana}, q{OMP_SCHEDULE rejects an unknown kind} ); | ||||
| 101 | 1 | 196 | rejects( q{OMP_SCHEDULE}, q{dynamic,0}, q{OMP_SCHEDULE rejects zero chunk size} ); | ||||
| 102 | 1 | 200 | rejects( q{OMP_SCHEDULE}, q{random:dynamic,4}, q{OMP_SCHEDULE rejects an unknown modifier} ); | ||||
| 103 | 1 | 190 | is validate_value( q{OMP_SCHEDULE}, q{ dynamic,4 } ), q{dynamic,4}, q{OMP_SCHEDULE ignores surrounding OpenMP whitespace}; | ||||
| 104 | |||||||
| 105 | 1 | 208 | is validate_value( q{OMP_TARGET_OFFLOAD}, q{mandatory} ), q{MANDATORY}, q{OMP_TARGET_OFFLOAD normalizes a standard value}; | ||||
| 106 | 1 | 205 | rejects( q{OMP_TARGET_OFFLOAD}, q{FORCE}, q{OMP_TARGET_OFFLOAD rejects an unknown mode} ); | ||||
| 107 | 1 | 204 | is validate_value( q{OMP_THREAD_LIMIT}, 1 ), 1, q{OMP_THREAD_LIMIT accepts positive integer}; | ||||
| 108 | 1 | 206 | rejects( q{OMP_THREAD_LIMIT}, 0, q{OMP_THREAD_LIMIT rejects zero} ); | ||||
| 109 | 1 | 204 | is validate_value( q{OMP_WAIT_POLICY}, q{active} ), q{ACTIVE}, q{OMP_WAIT_POLICY accepts ACTIVE}; | ||||
| 110 | 1 | 205 | rejects( q{OMP_WAIT_POLICY}, q{SLEEP}, q{OMP_WAIT_POLICY rejects unknown policy} ); | ||||
| 111 | |||||||
| 112 | 1 | 189 | for my $value ( q{0}, q{0 3 1-2 4-15:2}, q{0,2,4-8:2} ) { | ||||
| 113 | 3 | 417 | is validate_value( q{GOMP_CPU_AFFINITY}, $value ), $value, qq{GOMP_CPU_AFFINITY accepts $value}; | ||||
| 114 | } | ||||||
| 115 | 1 | 207 | rejects( q{GOMP_CPU_AFFINITY}, q{cpu0}, q{GOMP_CPU_AFFINITY rejects symbolic CPUs} ); | ||||
| 116 | 1 | 191 | rejects( q{GOMP_CPU_AFFINITY}, q{4-8:0}, q{GOMP_CPU_AFFINITY rejects zero stride} ); | ||||
| 117 | 1 | 192 | is validate_value( q{GOMP_DEBUG}, 0 ), 0, q{GOMP_DEBUG accepts zero}; | ||||
| 118 | 1 | 207 | is validate_value( q{GOMP_DEBUG}, 1 ), 1, q{GOMP_DEBUG accepts one}; | ||||
| 119 | 1 | 204 | rejects( q{GOMP_DEBUG}, 2, q{GOMP_DEBUG rejects values outside 0/1} ); | ||||
| 120 | 1 | 192 | is validate_value( q{GOMP_STACKSIZE}, q{1024} ), q{1024}, q{GOMP_STACKSIZE accepts the GNU-native numeric-kilobyte form}; | ||||
| 121 | 1 | 206 | is validate_value( q{GOMP_STACKSIZE}, q{1024G} ), q{1024G}, q{GOMP_STACKSIZE retains the documented OpenMP::Environment unit-suffix compatibility extension}; | ||||
| 122 | 1 | 205 | is validate_assignment( q{GOMP_STACKSIZE}, q{1024G} ), q{1024G}, q{GOMP_STACKSIZE assignment remains pass-through for pre-1.5 compatibility}; | ||||
| 123 | 1 | 204 | rejects( q{GOMP_STACKSIZE}, 0, q{GOMP_STACKSIZE rejects zero} ); | ||||
| 124 | 1 | 205 | for my $value ( q{0}, q{300000}, q{4k}, q{30M}, q{2G}, q{1T}, q{INFINITE}, q{INFINITY} ) { | ||||
| 125 | 8 | 1440 | is validate_value( q{GOMP_SPINCOUNT}, $value ), $value, qq{GOMP_SPINCOUNT accepts $value}; | ||||
| 126 | } | ||||||
| 127 | 1 | 221 | rejects( q{GOMP_SPINCOUNT}, q{4m}, q{GOMP_SPINCOUNT preserves documented suffix case} ); | ||||
| 128 | 1 | 192 | rejects( q{GOMP_SPINCOUNT}, q{forever}, q{GOMP_SPINCOUNT rejects unknown words} ); | ||||
| 129 | 1 | 194 | is validate_value( q{GOMP_RTEMS_THREAD_POOLS}, q{1@WRK0:3$4@WRK1} ), q{1@WRK0:3$4@WRK1}, q{GOMP_RTEMS_THREAD_POOLS accepts libgomp example grammar}; | ||||
| 130 | 1 | 208 | rejects( q{GOMP_RTEMS_THREAD_POOLS}, q{0@WRK0}, q{GOMP_RTEMS_THREAD_POOLS rejects zero pool count} ); | ||||
| 131 | 1 | 190 | rejects( q{GOMP_RTEMS_THREAD_POOLS}, q{1WRK0}, q{GOMP_RTEMS_THREAD_POOLS requires scheduler separator} ); | ||||
| 132 | 1 | 190 | is validate_value( q{OMP_TEAMS_THREAD_LIMIT}, 1 ), 1, q{OMP_TEAMS_THREAD_LIMIT accepts positive integer}; | ||||
| 133 | 1 | 232 | rejects( q{OMP_TEAMS_THREAD_LIMIT}, 0, q{OMP_TEAMS_THREAD_LIMIT rejects zero} ); | ||||
| 134 | |||||||
| 135 | 1 | 192 | for my $value ( | ||||
| 136 | q{omp_default_mem_alloc}, q{omp_high_bw_mem_alloc}, q{omp_default_mem_space}, | ||||||
| 137 | q{omp_large_cap_mem_space:alignment=16,pinned=true}, | ||||||
| 138 | q{omp_low_lat_mem_space:sync_hint=private,access=thread,pool_size=1024,partition=nearest}, | ||||||
| 139 | q{ompx_gnu_pinned_mem_alloc}, q{ompx_gnu_managed_mem_alloc}, | ||||||
| 140 | q{ompx_gnu_managed_mem_space} | ||||||
| 141 | ) { | ||||||
| 142 | 8 | 1446 | is validate_value( q{OMP_ALLOCATOR}, $value ), $value, qq{OMP_ALLOCATOR accepts $value}; | ||||
| 143 | } | ||||||
| 144 | 1 | 206 | rejects( q{OMP_ALLOCATOR}, q{not_an_allocator}, q{OMP_ALLOCATOR rejects an unknown allocator} ); | ||||
| 145 | 1 | 192 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:}, q{OMP_ALLOCATOR rejects an empty trait list} ); | ||||
| 146 | 1 | 192 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:alignment=3}, q{OMP_ALLOCATOR requires power-of-two alignment} ); | ||||
| 147 | 1 | 195 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:alignment=foo}, q{OMP_ALLOCATOR requires numeric alignment} ); | ||||
| 148 | 1 | 193 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:pool_size=0}, q{OMP_ALLOCATOR requires positive pool size} ); | ||||
| 149 | 1 | 193 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:pinned=maybe}, q{OMP_ALLOCATOR validates boolean traits} ); | ||||
| 150 | 1 | 190 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:partition=random}, q{OMP_ALLOCATOR validates partition values} ); | ||||
| 151 | 1 | 191 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:access=process}, q{OMP_ALLOCATOR validates access values} ); | ||||
| 152 | 1 | 191 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:sync_hint=often}, q{OMP_ALLOCATOR validates sync_hint values} ); | ||||
| 153 | 1 | 206 | is validate_value( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:fallback=allocator_fb} ), q{omp_low_lat_mem_space:fallback=allocator_fb}, q{OMP_ALLOCATOR accepts allocator_fb because libgomp explicitly lists it as an allowed fallback token}; | ||||
| 154 | 1 | 205 | is validate_value( q{OMP_ALLOCATOR}, q{OMP_HIGH_BW_MEM_ALLOC} ), q{OMP_HIGH_BW_MEM_ALLOC}, q{OMP_ALLOCATOR values are case-insensitive under the general OpenMP environment rule}; | ||||
| 155 | 1 | 207 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:fb_data=not_an_allocator}, q{OMP_ALLOCATOR validates fb_data allocator names before applying the libgomp restriction} ); | ||||
| 156 | 1 | 192 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:fb_data=omp_default_mem_alloc}, q{OMP_ALLOCATOR rejects OpenMP fb_data because libgomp documents it as unsupported} ); | ||||
| 157 | 1 | 191 | is validate_value( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:fallback=default_mem_fb} ), q{omp_low_lat_mem_space:fallback=default_mem_fb}, q{OMP_ALLOCATOR accepts non-handle fallback choices}; | ||||
| 158 | 1 | 206 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:alignment=16,alignment=32}, q{OMP_ALLOCATOR rejects duplicate traits} ); | ||||
| 159 | 1 | 212 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:mystery=yes}, q{OMP_ALLOCATOR rejects unknown traits} ); | ||||
| 160 | 1 | 190 | rejects( q{OMP_ALLOCATOR}, q{omp_low_lat_mem_space:pinned}, q{OMP_ALLOCATOR rejects malformed traits} ); | ||||
| 161 | |||||||
| 162 | 1 | 190 | for my $value ( q{literal text}, q{thread %n affinity %A}, q{level %4L thread %0.2n}, q{host %.12{host}}, q{%% %n}, q{%{thread_num}}, q{vendor %x} ) { | ||||
| 163 | 7 | 1255 | is validate_value( q{OMP_AFFINITY_FORMAT}, $value ), $value, qq{OMP_AFFINITY_FORMAT accepts $value}; | ||||
| 164 | } | ||||||
| 165 | 1 | 208 | is validate_value( q{OMP_AFFINITY_FORMAT}, q{ %n } ), q{ %n }, q{OMP_AFFINITY_FORMAT preserves significant leading and trailing whitespace}; | ||||
| 166 | 1 | 206 | rejects( q{OMP_AFFINITY_FORMAT}, q{thread %}, q{OMP_AFFINITY_FORMAT rejects a trailing percent} ); | ||||
| 167 | 1 | 192 | rejects( q{OMP_AFFINITY_FORMAT}, q{thread %0n}, q{OMP_AFFINITY_FORMAT rejects malformed width syntax} ); | ||||
| 168 | 1 | 192 | rejects( q{OMP_AFFINITY_FORMAT}, q{thread %.0L}, q{OMP_AFFINITY_FORMAT rejects a zero minimum width} ); | ||||
| 169 | 1 | 214 | rejects( q{OMP_AFFINITY_FORMAT}, q{thread %0.0L}, q{OMP_AFFINITY_FORMAT rejects a zero-padded zero minimum width} ); | ||||
| 170 | 1 | 191 | rejects( q{OMP_AFFINITY_FORMAT}, q{thread %{bad-name}}, q{OMP_AFFINITY_FORMAT rejects malformed long field name} ); | ||||
| 171 | 1 | 189 | is validate_value( q{OMP_DISPLAY_AFFINITY}, q{false} ), q{FALSE}, q{OMP_DISPLAY_AFFINITY accepts and normalizes false}; | ||||
| 172 | 1 | 206 | rejects( q{OMP_DISPLAY_AFFINITY}, q{sometimes}, q{OMP_DISPLAY_AFFINITY rejects non-boolean value} ); | ||||
| 173 | |||||||
| 174 | 1 | 190 | local $@; | ||||
| 175 | 1 1 | 1 2 | eval { assert_variable( [], q{OMP_NUM_THREADS} ) }; | ||||
| 176 | 1 | 4 | like $@, qr/hash reference/, q{assert_variable requires a hash reference}; | ||||
| 177 | 1 1 | 192 2 | eval { assert_variable( {}, q{OMP_NOT_REAL} ) }; | ||||
| 178 | 1 | 4 | like $@, qr/Unsupported/, q{assert_variable rejects unknown names}; | ||||
| 179 | 1 | 196 | my %one = ( OMP_NUM_THREADS => q{4,2} ); | ||||
| 180 | 1 | 2 | ok assert_variable( \%one, q{OMP_NUM_THREADS} ), q{assert_variable validates a set variable}; | ||||
| 181 | 1 | 219 | my %unset; | ||||
| 182 | 1 | 3 | ok assert_variable( \%unset, q{OMP_NUM_THREADS} ), q{assert_variable accepts an unset variable}; | ||||
| 183 | 1 | 209 | my %unrelated_conflict = ( OMP_NESTED => q{FALSE}, OMP_MAX_ACTIVE_LEVELS => 4, OMP_SCHEDULE => q{static} ); | ||||
| 184 | 1 | 3 | ok assert_variable( \%unrelated_conflict, q{OMP_SCHEDULE} ), q{assert_variable ignores a cross-variable conflict unrelated to the requested variable}; | ||||
| 185 | |||||||
| 186 | 1 | 197 | local $@; | ||||
| 187 | 1 1 | 1 2 | eval { assert_environment([]) }; | ||||
| 188 | 1 | 4 | like $@, qr/hash reference/, q{assert_environment requires a hash reference}; | ||||
| 189 | 1 | 195 | my %strict = ( OMP_CANCELLATION => q{true}, OMP_SCHEDULE => q{guided,4} ); | ||||
| 190 | 1 | 3 | ok assert_environment( \%strict ), q{assert_environment validates a portable environment}; | ||||
| 191 | 1 | 198 | is $strict{OMP_CANCELLATION}, q{TRUE}, q{assert_environment writes normalized values back}; | ||||
| 192 | 1 | 210 | my %conflict = ( OMP_NESTED => q{FALSE}, OMP_MAX_ACTIVE_LEVELS => 4 ); | ||||
| 193 | 1 1 | 1 2 | eval { assert_environment( \%conflict ) }; | ||||
| 194 | 1 | 3 | like $@, qr/conflict/, q{assert_environment rejects an explicit OpenMP implementation-defined conflict}; | ||||
| 195 | |||||||
| 196 | 1 | 194 | local $@; | ||||
| 197 | 1 1 | 1 2 | eval { analyze_environment([]) }; | ||||
| 198 | 1 | 6 | like $@, qr/hash reference/, q{analyze_environment requires a hash reference}; | ||||
| 199 | 1 | 199 | my %analysis_env = ( | ||||
| 200 | OMP_NESTED => q{TRUE}, | ||||||
| 201 | OMP_MAX_ACTIVE_LEVELS => 4, | ||||||
| 202 | OMP_NUM_THREADS => q{8,4}, | ||||||
| 203 | OMP_PROC_BIND => q{SPREAD,CLOSE}, | ||||||
| 204 | GOMP_CPU_AFFINITY => q{0-7}, | ||||||
| 205 | OMP_PLACES => q{cores}, | ||||||
| 206 | OMP_DEFAULT_DEVICE => 7, | ||||||
| 207 | OMP_STACKSIZE => q{64G}, | ||||||
| 208 | OMP_ALLOCATOR => q{omp_high_bw_mem_alloc}, | ||||||
| 209 | OMP_THREAD_LIMIT => 1024, | ||||||
| 210 | GOMP_RTEMS_THREAD_POOLS => q{1@WRK0}, | ||||||
| 211 | ); | ||||||
| 212 | 1 | 3 | my $analysis = analyze_environment( \%analysis_env ); | ||||
| 213 | 1 | 5 | ok $analysis->{valid}, q{runtime-dependent but syntactically valid environment remains valid}; | ||||
| 214 | 1 1 | 204 4 | ok @{ $analysis->{runtime_dependent} } >= 8, q{analysis identifies runtime-dependent settings without probing the system}; | ||||
| 215 | 1 1 | 194 11 | ok grep( /OMP_PROC_BIND takes precedence/, @{ $analysis->{notes} } ), q{analysis documents GNU precedence relationship}; | ||||
| 216 | 1 1 | 193 5 | ok grep( /OMP_NESTED has no effect/, @{ $analysis->{notes} } ), q{analysis documents nonconflicting OMP_NESTED relationship}; | ||||
| 217 | 1 1 | 189 5 | ok grep( /max-active-levels-var/, @{ $analysis->{notes} } ), q{analysis documents nested list effect on max-active-levels-var}; | ||||
| 218 | |||||||
| 219 | 1 | 191 | my $bad_analysis = analyze_environment( { OMP_SCHEDULE => q{banana} } ); | ||||
| 220 | 1 | 4 | ok !$bad_analysis->{valid}, q{analysis marks malformed environment invalid}; | ||||
| 221 | 1 1 | 204 2 | is scalar( @{ $bad_analysis->{errors} } ), 1, q{analysis reports malformed value as an error}; | ||||
| 222 | 1 | 209 | my $conflict_analysis = analyze_environment( { OMP_NESTED => q{false}, OMP_MAX_ACTIVE_LEVELS => 2 } ); | ||||
| 223 | 1 | 4 | ok !$conflict_analysis->{valid}, q{analysis marks cross-variable conflict invalid}; | ||||
| 224 | 1 | 196 | is $conflict_analysis->{conflicts}->[0]->{class}, q{implementation-defined}, q{analysis classifies the OpenMP conflict}; | ||||
| 225 | |||||||
| 226 | 1 | 209 | done_testing; | ||||
| 227 | |||||||