diff options
-rw-r--r-- | include/migration.h | 15 | ||||
-rw-r--r-- | src/migration.c | 67 | ||||
-rw-r--r-- | tests/core_api.c | 38 |
3 files changed, 90 insertions, 30 deletions
diff --git a/include/migration.h b/include/migration.h index f60dfe9..bd52dd4 100644 --- a/include/migration.h +++ b/include/migration.h | |||
@@ -3,6 +3,7 @@ | |||
3 | * Functions to migrate tasks to different CPUs, partitions, clusters... | 3 | * Functions to migrate tasks to different CPUs, partitions, clusters... |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <sched.h> | ||
6 | typedef int pid_t; | 7 | typedef int pid_t; |
7 | 8 | ||
8 | /** | 9 | /** |
@@ -58,6 +59,20 @@ int be_migrate_to_cluster(int cluster, int cluster_sz); | |||
58 | int be_migrate_to_domain(int domain); | 59 | int be_migrate_to_domain(int domain); |
59 | 60 | ||
60 | /** | 61 | /** |
62 | * Parse CPU set given as string, and return corresponding cpu_set_t variable | ||
63 | * and its size as parameters. | ||
64 | * @param buf CPU mapping as string. Specific format is explained in | ||
65 | * src/migration.c:82 | ||
66 | * @param len Length of input string in bytes | ||
67 | * @param set cpu_set_t type variable with bits set as according to input | ||
68 | * @param sz Size of CPU set in bytes | ||
69 | * @return void | ||
70 | */ | ||
71 | |||
72 | void set_mapping(char* buf, int len, cpu_set_t** set, size_t *sz); | ||
73 | |||
74 | |||
75 | /** | ||
61 | * Return the number of CPUs currently online | 76 | * Return the number of CPUs currently online |
62 | * @return The number of online CPUs | 77 | * @return The number of online CPUs |
63 | */ | 78 | */ |
diff --git a/src/migration.c b/src/migration.c index c1e5a80..efd8d81 100644 --- a/src/migration.c +++ b/src/migration.c | |||
@@ -27,43 +27,17 @@ int num_online_cpus() | |||
27 | return sysconf(_SC_NPROCESSORS_ONLN); | 27 | return sysconf(_SC_NPROCESSORS_ONLN); |
28 | } | 28 | } |
29 | 29 | ||
30 | static int read_mapping(int idx, const char* which, cpu_set_t** set, size_t *sz) | 30 | void set_mapping(char* buf, int len, cpu_set_t** set, size_t *sz) |
31 | { | 31 | { |
32 | /* Max CPUs = 4096 */ | 32 | int nbits; |
33 | 33 | char *chunk_str; | |
34 | int ret = -1; | ||
35 | char buf[4096/4 /* enough chars for hex data (4 CPUs per char) */ | ||
36 | + 4096/(4*8) /* for commas (separate groups of 8 chars) */ | ||
37 | + 1] = {0}; /* for \0 */ | ||
38 | char fname[80] = {0}; | ||
39 | |||
40 | char* chunk_str; | ||
41 | int len, nbits; | ||
42 | int i; | 34 | int i; |
43 | 35 | ||
44 | /* init vals returned to callee */ | 36 | /* init vals returned to callee */ |
45 | *set = NULL; | 37 | *set = NULL; |
46 | *sz = 0; | 38 | *sz = 0; |
47 | 39 | ||
48 | if (num_online_cpus() > 4096) | ||
49 | goto out; | ||
50 | |||
51 | /* Read string is in the format of <mask>[,<mask>]*. All <mask>s following | ||
52 | a comma are 8 chars (representing a 32-bit mask). The first <mask> may | ||
53 | have fewer chars. Bits are MSB to LSB, left to right. */ | ||
54 | snprintf(fname, sizeof(fname), "/proc/litmus/%s/%d", which, idx); | ||
55 | ret = read_file(fname, &buf, sizeof(buf)-1); | ||
56 | if (ret <= 0) | ||
57 | goto out; | ||
58 | |||
59 | len = strnlen(buf, sizeof(buf)); | ||
60 | /* if there is, omit newline at the end of string */ | ||
61 | if (buf[len-1] == '\n') { | ||
62 | buf[len-1] = '\0'; | ||
63 | len -= 1; | ||
64 | } | ||
65 | nbits = 32*(len/9) + 4*(len%9); /* compute bits, accounting for commas */ | 40 | nbits = 32*(len/9) + 4*(len%9); /* compute bits, accounting for commas */ |
66 | |||
67 | *set = CPU_ALLOC(nbits); | 41 | *set = CPU_ALLOC(nbits); |
68 | *sz = CPU_ALLOC_SIZE(nbits); | 42 | *sz = CPU_ALLOC_SIZE(nbits); |
69 | CPU_ZERO_S(*sz, *set); | 43 | CPU_ZERO_S(*sz, *set); |
@@ -74,7 +48,7 @@ static int read_mapping(int idx, const char* which, cpu_set_t** set, size_t *sz) | |||
74 | do { | 48 | do { |
75 | unsigned long chunk; | 49 | unsigned long chunk; |
76 | /* since strtoul stops processing the string with occurrence of | 50 | /* since strtoul stops processing the string with occurrence of |
77 | first non-digit character, it is necessary to read 8-bytes | 51 | first non-digit character, it is necessary to read 8-bytes |
78 | on first iteration for ignoring the leading comma*/ | 52 | on first iteration for ignoring the leading comma*/ |
79 | chunk_str -= (9 + ((i == 0) ? -1 : 0)); | 53 | chunk_str -= (9 + ((i == 0) ? -1 : 0)); |
80 | if (chunk_str < buf) | 54 | if (chunk_str < buf) |
@@ -88,6 +62,39 @@ static int read_mapping(int idx, const char* which, cpu_set_t** set, size_t *sz) | |||
88 | } | 62 | } |
89 | i += 1; | 63 | i += 1; |
90 | } while (chunk_str > buf); | 64 | } while (chunk_str > buf); |
65 | } | ||
66 | |||
67 | static int read_mapping(int idx, const char* which, cpu_set_t** set, size_t *sz) | ||
68 | { | ||
69 | /* Max CPUs = 4096 */ | ||
70 | |||
71 | int ret = -1; | ||
72 | char buf[4096/4 /* enough chars for hex data (4 CPUs per char) */ | ||
73 | + 4096/(4*8) /* for commas (separate groups of 8 chars) */ | ||
74 | + 1] = {0}; /* for \0 */ | ||
75 | char fname[80] = {0}; | ||
76 | |||
77 | int len; | ||
78 | |||
79 | if (num_online_cpus() > 4096) | ||
80 | goto out; | ||
81 | |||
82 | /* Read string is in the format of <mask>[,<mask>]*. All <mask>s following | ||
83 | a comma are 8 chars (representing a 32-bit mask). The first <mask> may | ||
84 | have fewer chars. Bits are MSB to LSB, left to right. */ | ||
85 | snprintf(fname, sizeof(fname), "/proc/litmus/%s/%d", which, idx); | ||
86 | ret = read_file(fname, &buf, sizeof(buf)-1); | ||
87 | if (ret <= 0) | ||
88 | goto out; | ||
89 | |||
90 | len = strnlen(buf, sizeof(buf)); | ||
91 | /* if there is, omit newline at the end of string */ | ||
92 | if (buf[len-1] == '\n') { | ||
93 | buf[len-1] = '\0'; | ||
94 | len -= 1; | ||
95 | } | ||
96 | |||
97 | set_mapping(buf, len, set, sz); | ||
91 | 98 | ||
92 | ret = 0; | 99 | ret = 0; |
93 | 100 | ||
diff --git a/tests/core_api.c b/tests/core_api.c index feb60c5..065c1fc 100644 --- a/tests/core_api.c +++ b/tests/core_api.c | |||
@@ -193,6 +193,44 @@ TESTCASE(ctrl_page_writable, ALL, | |||
193 | ctrl_page[32] = 0x12345678; | 193 | ctrl_page[32] = 0x12345678; |
194 | } | 194 | } |
195 | 195 | ||
196 | TESTCASE(set_cpu_mapping, LITMUS, | ||
197 | "task's CPU affinity is set to CPU set that is read from file") | ||
198 | { | ||
199 | char buf[4096/4 /* enough chars for hex data (4 CPUs per char) */ | ||
200 | + 4096/(4*8) /* for commas (separate groups of 8 chars) */ | ||
201 | + 1] = {0}; /* for \0 */ | ||
202 | int len; | ||
203 | cpu_set_t *set; | ||
204 | size_t sz; | ||
205 | |||
206 | /*set affinity to CPU 0 */ | ||
207 | strcpy(buf, "20"); | ||
208 | len = strnlen(buf, sizeof(buf)); | ||
209 | set_mapping(buf, len, &set, &sz); | ||
210 | ASSERT( CPU_ISSET_S(5, sz, set) ); | ||
211 | |||
212 | /*set affinity to CPU 29 */ | ||
213 | strcpy(buf, "20000000"); | ||
214 | len = strnlen(buf, sizeof(buf)); | ||
215 | set_mapping(buf, len, &set, &sz); | ||
216 | ASSERT( CPU_ISSET_S(29, sz, set) ); | ||
217 | |||
218 | /*set affinity to CPUS 27 and 39 */ | ||
219 | strcpy(buf, "80,08000000"); | ||
220 | len = strnlen(buf, sizeof(buf)); | ||
221 | set_mapping(buf, len, &set, &sz); | ||
222 | ASSERT( CPU_ISSET_S(27, sz, set) ); | ||
223 | ASSERT( CPU_ISSET_S(39, sz, set) ); | ||
224 | |||
225 | /*set affinity to CPUS 96 */ | ||
226 | strcpy(buf, "1,00000000,00000000,00000000"); | ||
227 | len = strnlen(buf, sizeof(buf)); | ||
228 | set_mapping(buf, len, &set, &sz); | ||
229 | ASSERT( CPU_ISSET_S(96, sz, set) ); | ||
230 | |||
231 | } | ||
232 | |||
233 | |||
196 | 234 | ||
197 | TESTCASE(suspended_admission, LITMUS, | 235 | TESTCASE(suspended_admission, LITMUS, |
198 | "admission control handles suspended tasks correctly") | 236 | "admission control handles suspended tasks correctly") |