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

source code of openmp/runtime/test/affinity/kmp-hw-subset.c