1 // RUN: %libomp-compile -D_GNU_SOURCE
2 // RUN: env OMP_PLACES=threads %libomp-run
3 // RUN: env OMP_PLACES=cores %libomp-run
4 // RUN: env OMP_PLACES=sockets %libomp-run
5 // REQUIRES: linux
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include "libomp_test_affinity.h"
11 #include "libomp_test_topology.h"
12 
13 // Check openmp place list to make sure it follow KMP_HW_SUBSET restriction
compare_hw_subset_places(const place_list_t * openmp_places,topology_obj_type_t type,int nsockets,int ncores_per_socket,int nthreads_per_core)14 static int compare_hw_subset_places(const place_list_t *openmp_places,
15                                     topology_obj_type_t type, int nsockets,
16                                     int ncores_per_socket,
17                                     int nthreads_per_core) {
18   int i, j, expected_total, expected_per_place;
19   if (type == TOPOLOGY_OBJ_THREAD) {
20     expected_total = nsockets * ncores_per_socket * nthreads_per_core;
21     expected_per_place = 1;
22   } else if (type == TOPOLOGY_OBJ_CORE) {
23     expected_total = nsockets * ncores_per_socket;
24     expected_per_place = nthreads_per_core;
25   } else {
26     expected_total = nsockets;
27     expected_per_place = ncores_per_socket;
28   }
29   if (openmp_places->num_places != expected_total) {
30     fprintf(stderr, "error: KMP_HW_SUBSET did not half each resource layer!\n");
31     printf("openmp_places places:\n");
32     topology_print_places(openmp_places);
33     printf("\n");
34     return EXIT_FAILURE;
35   }
36   for (i = 0; i < openmp_places->num_places; ++i) {
37     int count = affinity_mask_count(openmp_places->masks[i]);
38     if (count != expected_per_place) {
39       fprintf(stderr, "error: place %d has %d OS procs instead of %d\n", i,
40               count, expected_per_place);
41       return EXIT_FAILURE;
42     }
43   }
44   return EXIT_SUCCESS;
45 }
46 
check_places()47 static int check_places() {
48   char buf[100];
49   topology_obj_type_t type;
50   const char *value;
51   int status = EXIT_SUCCESS;
52   place_list_t *threads, *cores, *sockets, *openmp_places;
53   threads = topology_alloc_type_places(TOPOLOGY_OBJ_THREAD);
54   cores = topology_alloc_type_places(TOPOLOGY_OBJ_CORE);
55   sockets = topology_alloc_type_places(TOPOLOGY_OBJ_SOCKET);
56 
57   if (threads->num_places <= 1) {
58     printf("Only one hardware thread to execute on. Skipping test.\n");
59     return status;
60   }
61 
62   value = getenv("OMP_PLACES");
63   if (!value) {
64     fprintf(stderr,
65             "error: OMP_PLACES must be set to one of threads,cores,sockets!\n");
66     return EXIT_FAILURE;
67   }
68   if (strcmp(value, "threads") == 0)
69     type = TOPOLOGY_OBJ_THREAD;
70   else if (strcmp(value, "cores") == 0)
71     type = TOPOLOGY_OBJ_CORE;
72   else if (strcmp(value, "sockets") == 0)
73     type = TOPOLOGY_OBJ_SOCKET;
74   else {
75     fprintf(stderr,
76             "error: OMP_PLACES must be one of threads,cores,sockets!\n");
77     return EXIT_FAILURE;
78   }
79 
80   // Calculate of num threads per core, num cores per socket, & num sockets
81   if (cores->num_places <= 0) {
82     printf("Invalid number of cores (%d). Skipping test.\n", cores->num_places);
83     return status;
84   } else if (sockets->num_places <= 0) {
85     printf("Invalid number of sockets (%d). Skipping test.\n",
86            cores->num_places);
87     return status;
88   }
89   int nthreads_per_core = threads->num_places / cores->num_places;
90   int ncores_per_socket = cores->num_places / sockets->num_places;
91   int nsockets = sockets->num_places;
92 
93   if (nsockets * ncores_per_socket * nthreads_per_core != threads->num_places) {
94     printf("Only uniform topologies can be tested. Skipping test.\n");
95     return status;
96   }
97 
98   // Use half the resources of every level
99   if (nthreads_per_core > 1)
100     nthreads_per_core /= 2;
101   if (ncores_per_socket > 1)
102     ncores_per_socket /= 2;
103   if (nsockets > 1)
104     nsockets /= 2;
105 
106   snprintf(buf, sizeof(buf), "%ds,%dc,%dt", nsockets, ncores_per_socket,
107            nthreads_per_core);
108   setenv("KMP_HW_SUBSET", buf, 1);
109 
110   openmp_places = topology_alloc_openmp_places();
111   status = compare_hw_subset_places(openmp_places, type, nsockets,
112                                     ncores_per_socket, nthreads_per_core);
113   topology_free_places(threads);
114   topology_free_places(cores);
115   topology_free_places(sockets);
116   topology_free_places(openmp_places);
117   return status;
118 }
119 
main()120 int main() {
121   if (!topology_using_full_mask()) {
122     printf("Thread does not have access to all logical processors. Skipping "
123            "test.\n");
124     return EXIT_SUCCESS;
125   }
126   return check_places();
127 }
128