aboutsummaryrefslogtreecommitdiffstats
path: root/src/migration.c
blob: 3bd6d0a1949c4cbf39f3c995c5d8474b140d0cee (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sched.h> /* for cpu sets */
#include <unistd.h>

#include "migration.h"

extern ssize_t read_file(const char* fname, void* buf, size_t maxlen);

int release_master()
{
	static const char NO_CPU[] = "NO_CPU";
	char buf[7] = {0}; /* up to 999999 CPUs */
	int master = -1;

	int ret = read_file("/proc/litmus/release_master", &buf, sizeof(buf)-1);

	if ((ret > 0) && (strncmp(buf, NO_CPU, sizeof(NO_CPU)-1) != 0))
		master = atoi(buf);

	return master;
}

int num_online_cpus()
{
	return sysconf(_SC_NPROCESSORS_ONLN);
}

static int read_mapping(int idx, const char* which, unsigned long long int* mask)
{
	int	ret = -1;
	char buf[129] = {0};
	char fname[80] = {0};

	if (num_online_cpus() > 64) {
		/* XXX: Support more than 64 CPUs.
		 * User can still set appropriate values directly. */
		goto out;
	}

	snprintf(fname, sizeof(fname), "/proc/litmus/%s/%d", which, idx);

	ret = read_file(fname, &buf, sizeof(buf)-1);
	if (ret <= 0)
		goto out;

	*mask = strtoull(buf, NULL, 16);
	ret = 0;

out:
	return ret;
}

int domain_to_cpus(int domain, unsigned long long int* mask)
{
	return read_mapping(domain, "domains", mask);
}

int cpu_to_domains(int cpu, unsigned long long int* mask)
{
	return read_mapping(cpu, "cpus", mask);
}

int domain_to_first_cpu(int domain)
{
	unsigned long long int mask;
	int ret = domain_to_cpus(domain, &mask);
	if(ret == 0)
		return (ffsll(mask)-1);
	return ret;
}

int be_migrate_thread_to_cpu(pid_t tid, int target_cpu)
{
	cpu_set_t *cpu_set;
	size_t sz;
	int num_cpus;
	int ret;

	/* TODO: Error check to make sure that tid is not a real-time task. */

	if (target_cpu < 0)
		return -1;

	num_cpus = num_online_cpus();
	if (num_cpus == -1)
		return -1;

	if (target_cpu >= num_cpus)
		return -1;

	cpu_set = CPU_ALLOC(num_cpus);
	sz = CPU_ALLOC_SIZE(num_cpus);
	CPU_ZERO_S(sz, cpu_set);
	CPU_SET_S(target_cpu, sz, cpu_set);

	/* apply to caller */
	if (tid == 0)
		tid = gettid();

	ret = sched_setaffinity(tid, sz, cpu_set);

	CPU_FREE(cpu_set);

	return ret;
}

int be_migrate_thread_to_domain(pid_t tid, int domain)
{
	int	ret, num_cpus;
	cpu_set_t *cpu_set;
	size_t sz;
	unsigned long long int mask;

	ret = domain_to_cpus(domain, &mask);
	if (ret != 0)
		return ret;

	num_cpus = num_online_cpus();
	if (num_cpus == -1)
		return -1;

	cpu_set = CPU_ALLOC(num_cpus);
	sz = CPU_ALLOC_SIZE(num_cpus);
	CPU_ZERO_S(sz, cpu_set);

	while(mask) {
		int idx = ffsll(mask) - 1;
		CPU_SET_S(idx, sz, cpu_set);
		mask &= ~(1ull<<idx);
	}

	/* apply to caller */
	if (tid == 0)
		tid = gettid();

	ret = sched_setaffinity(tid, sz, cpu_set);

	CPU_FREE(cpu_set);

	return ret;
}

int be_migrate_to_cpu(int target_cpu)
{
	return be_migrate_thread_to_cpu(0, target_cpu);
}

int be_migrate_to_domain(int domain)
{
	return be_migrate_thread_to_domain(0, domain);
}


/* deprecated functions. */

int be_migrate_to_cluster(int cluster, int cluster_size)
{
	return be_migrate_to_domain(cluster);
}

int cluster_to_first_cpu(int cluster, int cluster_size)
{
	return domain_to_first_cpu(cluster);
}

int partition_to_cpu(int partition)
{
	return domain_to_first_cpu(partition);
}