| 1 | // RUN: %libomp-compile -D_GNU_SOURCE |
| 2 | // RUN: env OMP_PLACES=threads %libomp-run 1 0 |
| 3 | // RUN: env OMP_PLACES=threads %libomp-run 1 1 |
| 4 | // RUN: env OMP_PLACES=threads %libomp-run 2 1 |
| 5 | // RUN: env OMP_PLACES=threads %libomp-run 2 2 |
| 6 | // RUN: env OMP_PLACES=threads %libomp-run 3 1 |
| 7 | // RUN: env OMP_PLACES=threads %libomp-run 3 2 |
| 8 | // REQUIRES: linux |
| 9 | // |
| 10 | // The test requires topologies with sockets, cores, threads layers where |
| 11 | // the socket layer contains multiple threads. |
| 12 | // The s390x architecture does not produce this topology and seems to have |
| 13 | // one thread per socket. |
| 14 | // UNSUPPORTED: s390x-target-arch |
| 15 | |
| 16 | #include <stdio.h> |
| 17 | #include <stdlib.h> |
| 18 | #include <string.h> |
| 19 | #include "libomp_test_affinity.h" |
| 20 | #include "libomp_test_topology.h" |
| 21 | |
| 22 | // Check openmp place list to make sure it follow KMP_HW_SUBSET restriction |
| 23 | static int compare_abs_hw_subset_places(const place_list_t *openmp_places, |
| 24 | int nthreads, int offset) { |
| 25 | int i, j, expected_per_place; |
| 26 | if (openmp_places->num_places != nthreads) { |
| 27 | fprintf( |
| 28 | stderr, |
| 29 | format: "error: KMP_HW_SUBSET did not restrict the thread resource layer!\n" ); |
| 30 | printf(format: "openmp_places places:\n" ); |
| 31 | topology_print_places(p: openmp_places); |
| 32 | printf(format: "\n" ); |
| 33 | return EXIT_FAILURE; |
| 34 | } |
| 35 | for (i = 0; i < openmp_places->num_places; ++i) { |
| 36 | int count = affinity_mask_count(mask: openmp_places->masks[i]); |
| 37 | if (count != 1) { |
| 38 | fprintf(stderr, format: "error: place %d has %d OS procs instead of %d\n" , i, |
| 39 | count, expected_per_place); |
| 40 | return EXIT_FAILURE; |
| 41 | } |
| 42 | } |
| 43 | return EXIT_SUCCESS; |
| 44 | } |
| 45 | |
| 46 | static int check_places(int nthreads, int offset) { |
| 47 | char buf[100]; |
| 48 | topology_obj_type_t type; |
| 49 | const char *value; |
| 50 | int status = EXIT_SUCCESS; |
| 51 | place_list_t *threads, *openmp_places; |
| 52 | threads = topology_alloc_type_places(type: TOPOLOGY_OBJ_THREAD); |
| 53 | |
| 54 | if (threads->num_places <= 1) { |
| 55 | printf(format: "Only one hardware thread to execute on. Skipping test.\n" ); |
| 56 | return status; |
| 57 | } |
| 58 | |
| 59 | if (nthreads + offset > threads->num_places) { |
| 60 | printf(format: "Only %d total hardware threads to execute on. Skipping test with " |
| 61 | "nthreads=%d and offset=%d (too big).\n" , |
| 62 | threads->num_places, nthreads, offset); |
| 63 | return status; |
| 64 | } |
| 65 | |
| 66 | value = getenv(name: "OMP_PLACES" ); |
| 67 | if (!value) { |
| 68 | fprintf(stderr, format: "error: OMP_PLACES must be set to threads!\n" ); |
| 69 | return EXIT_FAILURE; |
| 70 | } |
| 71 | |
| 72 | snprintf(s: buf, maxlen: sizeof(buf), format: ":1s,%dt@%d" , nthreads, offset); |
| 73 | setenv(name: "KMP_HW_SUBSET" , value: buf, replace: 1); |
| 74 | |
| 75 | openmp_places = topology_alloc_openmp_places(); |
| 76 | status = compare_abs_hw_subset_places(openmp_places, nthreads, offset); |
| 77 | topology_free_places(places: threads); |
| 78 | topology_free_places(places: openmp_places); |
| 79 | return status; |
| 80 | } |
| 81 | |
| 82 | int main(int argc, char **argv) { |
| 83 | int offset = 0; |
| 84 | int nthreads = 1; |
| 85 | |
| 86 | if (!topology_using_full_mask()) { |
| 87 | printf(format: "Thread does not have access to all logical processors. Skipping " |
| 88 | "test.\n" ); |
| 89 | return EXIT_SUCCESS; |
| 90 | } |
| 91 | |
| 92 | if (argc != 3) { |
| 93 | fprintf(stderr, format: "usage: %s <nthreads> <offset>\n" , argv[0]); |
| 94 | return EXIT_FAILURE; |
| 95 | } |
| 96 | |
| 97 | nthreads = atoi(nptr: argv[1]); |
| 98 | offset = atoi(nptr: argv[2]); |
| 99 | |
| 100 | return check_places(nthreads, offset); |
| 101 | } |
| 102 | |