1 #include "cado.h" // IWYU pragma: keep
2 #include <stdio.h>
3 #include <ctype.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <hwloc.h>
7 #include "cpubinding.h"
8 #include "macros.h"
9 #include "params.h"
10 #include "misc.h"
11 
12 /* Example quick use:
13  * $build_tree/tests/linalg/bwc/test_cpubinding  -s "NUMANode:4 Socket:1 Core:12 PU:2" thr=8x8   cpubinding="NUMANode=>2x2 Core*12=>4x4"
14  */
15 
usage()16 void usage() {
17     fprintf(stderr, "cpubinding example program\n"
18             "Options:\n"
19             "--input-topology-file <filename>     take <filename> as an hwloc hardware description\n"
20             "--input-topology-string <string>       take <string> as an hwloc synthetic hardware description\n"
21             "thr=<int>x<int>   give results for this target mapping\n"
22             "cpubinding=<string>   use this mapping (or file)\n"
23            );
24     exit(1);
25 }
26 
27 int verbose = 0;
28 
do_cpubinding_tests(const char * cpubinding_conf)29 int do_cpubinding_tests(const char * cpubinding_conf)
30 {
31     FILE * f = fopen(cpubinding_conf, "r");
32     if (f == NULL) {
33         fprintf(stderr, "%s: fopen failed\n", cpubinding_conf);
34         exit(1);
35     }
36 
37     char line[1024];
38 
39     int nb_ok = 0;
40     int nb_nok = 0;
41     int idx = 0;
42     for( ; fgets(line, sizeof(line), f) ; ) {
43         int pos = 0;
44         int want = 0;
45         const char * find_magic2 =  "# EXPECT_FIND2";
46         const char * find_magic =  "# EXPECT_FIND";
47         const char * fail_magic =  "# EXPECT_FAIL";
48         if (strncmp(line, find_magic2, strlen(find_magic2)) == 0) {
49 #if HWLOC_API_VERSION >= 0x020000
50             pos += strlen(find_magic2);
51             want = 1;
52 #else
53             continue;
54 #endif
55         } else if (strncmp(line, find_magic, strlen(find_magic)) == 0) {
56             pos += strlen(find_magic);
57             want = 1;
58         } else if (strncmp(line, fail_magic, strlen(fail_magic)) == 0) {
59             pos += strlen(fail_magic);
60             want = 0;
61         } else {
62             continue;
63         }
64 
65         int pos2;
66         int t[2];
67         int rc = sscanf(line + pos, "%d %d %n", &t[0], &t[1], &pos2);
68         for(int n = strlen(line); n && isspace(line[n-1]); line[--n]='\0');
69         ASSERT_ALWAYS(rc >= 2);
70 
71         if (verbose) printf("doing subtest %d: %s\n", idx, line);
72         idx++;
73 
74         param_list pl2;
75         param_list_init(pl2);
76         param_list_add_key(pl2, "cpubinding", cpubinding_conf, PARAMETER_FROM_CMDLINE);
77         param_list_add_key(pl2, "input-topology-string", line + pos + pos2, PARAMETER_FROM_CMDLINE);
78 
79         char * msg;
80         void * cc = cpubinding_get_info(&msg, pl2, t);
81         /* don't make the tests too verbose */
82         if (msg) {
83             if (verbose) puts(msg);
84             free(msg);
85         }
86         int ok = want == (cc != NULL);
87         if (verbose) printf("result: %s\n", ok_NOK(ok));
88         nb_ok += ok;
89         nb_nok += !ok;
90 
91         cpubinding_do_pinning(cc, 0, 0);
92         cpubinding_free_info(cc, t);
93 
94         param_list_clear(pl2);
95     }
96     fclose(f);
97     return !nb_nok;
98 }
99 
main(int argc,char * argv[])100 int main(int argc, char * argv[])
101 {
102     const char * cpubinding_conf = NULL;
103     param_list pl;
104     param_list_init(pl);
105     argv++,argc--;
106     param_list_configure_alias(pl, "input-topology-file", "-i");
107     param_list_configure_alias(pl, "input-topology-string", "-s");
108     param_list_configure_alias(pl, "cpubinding", "-c");
109     param_list_configure_switch(pl, "-v", &verbose);
110     for( ; argc ; ) {
111         if (param_list_update_cmdline(pl, &argc, &argv)) { continue; }
112         /* Do perhaps some other things on the argument that haven't
113          * been eaten at all. Like check whether it is a valid file to
114          * source in order to get more options. See
115          * param_list_read_stream and param_list_read_file for that. */
116         fprintf (stderr, "Unknown option: %s\n", argv[0]);
117         usage();
118     }
119 
120     int seen_i = param_list_lookup_string(pl, "input-topology-file") != NULL;
121     int seen_s = param_list_lookup_string(pl, "input-topology-string") != NULL;
122 
123     if (seen_i && seen_s) {
124         fprintf(stderr, "Cannot have both -i and -s\n");
125         exit(1);
126     }
127 
128     cpubinding_conf = param_list_lookup_string(pl, "cpubinding");
129 
130     int thr[2] = {1,1};
131     int parsed_thr = param_list_parse_int_and_int(pl, "thr", thr, "x");
132 
133     if (param_list_warn_unused(pl)) {
134         usage();
135     }
136 
137     char * msg;
138 
139     int rc = 0;
140     if (parsed_thr) {
141         /* This mode is here because this binary also serves as a quick
142          * debug program, just to see how a given mapping string is
143          * interpreted.
144          */
145         void * cc = cpubinding_get_info(&msg, pl, thr);
146         if (msg) {
147             puts(msg);
148             free(msg);
149         }
150         cpubinding_do_pinning(cc, 0, 0);
151         cpubinding_free_info(cc, thr);
152     } else if (cpubinding_conf) {
153         rc = do_cpubinding_tests(cpubinding_conf) ? EXIT_SUCCESS : EXIT_FAILURE;
154     } else {
155         fprintf(stderr, "don't know what to do !\n");
156         exit(1);
157     }
158 
159     param_list_clear(pl);
160 
161     return rc;
162 }
163