cpuacct.c 8.4 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0
2 3 4 5 6 7 8 9
#include <linux/cgroup.h>
#include <linux/slab.h>
#include <linux/percpu.h>
#include <linux/spinlock.h>
#include <linux/cpumask.h>
#include <linux/seq_file.h>
#include <linux/rcupdate.h>
#include <linux/kernel_stat.h>
10
#include <linux/err.h>
11 12 13 14 15 16 17 18 19 20

#include "sched.h"

/*
 * CPU accounting code for task groups.
 *
 * Based on the work by Paul Menage (menage@google.com) and Balbir Singh
 * (balbir@in.ibm.com).
 */

L
Li Zefan 已提交
21 22 23 24 25 26 27 28
/* Time spent by the tasks of the cpu accounting group executing in ... */
enum cpuacct_stat_index {
	CPUACCT_STAT_USER,	/* ... user mode */
	CPUACCT_STAT_SYSTEM,	/* ... kernel mode */

	CPUACCT_STAT_NSTATS,
};

29 30 31
static const char * const cpuacct_stat_desc[] = {
	[CPUACCT_STAT_USER] = "user",
	[CPUACCT_STAT_SYSTEM] = "system",
32 33 34
};

struct cpuacct_usage {
35
	u64	usages[CPUACCT_STAT_NSTATS];
36 37
};

L
Li Zefan 已提交
38 39 40 41
/* track cpu usage of a group of tasks and its child groups */
struct cpuacct {
	struct cgroup_subsys_state css;
	/* cpuusage holds pointer to a u64-type object on every cpu */
42
	struct cpuacct_usage __percpu *cpuusage;
L
Li Zefan 已提交
43 44 45
	struct kernel_cpustat __percpu *cpustat;
};

46 47 48 49 50
static inline struct cpuacct *css_ca(struct cgroup_subsys_state *css)
{
	return css ? container_of(css, struct cpuacct, css) : NULL;
}

L
Li Zefan 已提交
51 52 53
/* return cpu accounting group to which this task belongs */
static inline struct cpuacct *task_ca(struct task_struct *tsk)
{
54
	return css_ca(task_css(tsk, cpuacct_cgrp_id));
L
Li Zefan 已提交
55 56 57 58
}

static inline struct cpuacct *parent_ca(struct cpuacct *ca)
{
T
Tejun Heo 已提交
59
	return css_ca(ca->css.parent);
L
Li Zefan 已提交
60 61
}

62
static DEFINE_PER_CPU(struct cpuacct_usage, root_cpuacct_cpuusage);
63 64 65 66
static struct cpuacct root_cpuacct = {
	.cpustat	= &kernel_cpustat,
	.cpuusage	= &root_cpuacct_cpuusage,
};
67 68

/* create a new cpu accounting group */
69 70
static struct cgroup_subsys_state *
cpuacct_css_alloc(struct cgroup_subsys_state *parent_css)
71 72 73
{
	struct cpuacct *ca;

74
	if (!parent_css)
75 76 77 78 79 80
		return &root_cpuacct.css;

	ca = kzalloc(sizeof(*ca), GFP_KERNEL);
	if (!ca)
		goto out;

81
	ca->cpuusage = alloc_percpu(struct cpuacct_usage);
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
	if (!ca->cpuusage)
		goto out_free_ca;

	ca->cpustat = alloc_percpu(struct kernel_cpustat);
	if (!ca->cpustat)
		goto out_free_cpuusage;

	return &ca->css;

out_free_cpuusage:
	free_percpu(ca->cpuusage);
out_free_ca:
	kfree(ca);
out:
	return ERR_PTR(-ENOMEM);
}

/* destroy an existing cpu accounting group */
100
static void cpuacct_css_free(struct cgroup_subsys_state *css)
101
{
102
	struct cpuacct *ca = css_ca(css);
103 104 105 106 107 108

	free_percpu(ca->cpustat);
	free_percpu(ca->cpuusage);
	kfree(ca);
}

109
static u64 cpuacct_cpuusage_read(struct cpuacct *ca, int cpu,
110
				 enum cpuacct_stat_index index)
111
{
112
	struct cpuacct_usage *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
113 114
	u64 data;

115
	/*
116
	 * We allow index == CPUACCT_STAT_NSTATS here to read
117 118
	 * the sum of suages.
	 */
119
	BUG_ON(index > CPUACCT_STAT_NSTATS);
120

121 122 123 124 125
#ifndef CONFIG_64BIT
	/*
	 * Take rq->lock to make 64-bit read safe on 32-bit platforms.
	 */
	raw_spin_lock_irq(&cpu_rq(cpu)->lock);
126 127
#endif

128
	if (index == CPUACCT_STAT_NSTATS) {
129 130 131
		int i = 0;

		data = 0;
132
		for (i = 0; i < CPUACCT_STAT_NSTATS; i++)
133 134 135 136 137 138
			data += cpuusage->usages[i];
	} else {
		data = cpuusage->usages[index];
	}

#ifndef CONFIG_64BIT
139 140 141 142 143 144 145 146
	raw_spin_unlock_irq(&cpu_rq(cpu)->lock);
#endif

	return data;
}

static void cpuacct_cpuusage_write(struct cpuacct *ca, int cpu, u64 val)
{
147 148
	struct cpuacct_usage *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
	int i;
149 150 151 152 153 154

#ifndef CONFIG_64BIT
	/*
	 * Take rq->lock to make 64-bit write safe on 32-bit platforms.
	 */
	raw_spin_lock_irq(&cpu_rq(cpu)->lock);
155 156
#endif

157
	for (i = 0; i < CPUACCT_STAT_NSTATS; i++)
158 159 160
		cpuusage->usages[i] = val;

#ifndef CONFIG_64BIT
161 162 163 164 165
	raw_spin_unlock_irq(&cpu_rq(cpu)->lock);
#endif
}

/* return total cpu usage (in nanoseconds) of a group */
166
static u64 __cpuusage_read(struct cgroup_subsys_state *css,
167
			   enum cpuacct_stat_index index)
168
{
169
	struct cpuacct *ca = css_ca(css);
170 171 172
	u64 totalcpuusage = 0;
	int i;

173
	for_each_possible_cpu(i)
174
		totalcpuusage += cpuacct_cpuusage_read(ca, i, index);
175 176 177 178

	return totalcpuusage;
}

179 180 181
static u64 cpuusage_user_read(struct cgroup_subsys_state *css,
			      struct cftype *cft)
{
182
	return __cpuusage_read(css, CPUACCT_STAT_USER);
183 184 185 186 187
}

static u64 cpuusage_sys_read(struct cgroup_subsys_state *css,
			     struct cftype *cft)
{
188
	return __cpuusage_read(css, CPUACCT_STAT_SYSTEM);
189 190 191 192
}

static u64 cpuusage_read(struct cgroup_subsys_state *css, struct cftype *cft)
{
193
	return __cpuusage_read(css, CPUACCT_STAT_NSTATS);
194 195
}

196
static int cpuusage_write(struct cgroup_subsys_state *css, struct cftype *cft,
197
			  u64 val)
198
{
199
	struct cpuacct *ca = css_ca(css);
200
	int cpu;
201

202 203 204
	/*
	 * Only allow '0' here to do a reset.
	 */
205 206
	if (val)
		return -EINVAL;
207

208 209
	for_each_possible_cpu(cpu)
		cpuacct_cpuusage_write(ca, cpu, 0);
210

211
	return 0;
212 213
}

214
static int __cpuacct_percpu_seq_show(struct seq_file *m,
215
				     enum cpuacct_stat_index index)
216
{
217
	struct cpuacct *ca = css_ca(seq_css(m));
218 219 220
	u64 percpu;
	int i;

221
	for_each_possible_cpu(i) {
222
		percpu = cpuacct_cpuusage_read(ca, i, index);
223 224 225 226 227 228
		seq_printf(m, "%llu ", (unsigned long long) percpu);
	}
	seq_printf(m, "\n");
	return 0;
}

229 230
static int cpuacct_percpu_user_seq_show(struct seq_file *m, void *V)
{
231
	return __cpuacct_percpu_seq_show(m, CPUACCT_STAT_USER);
232 233 234 235
}

static int cpuacct_percpu_sys_seq_show(struct seq_file *m, void *V)
{
236
	return __cpuacct_percpu_seq_show(m, CPUACCT_STAT_SYSTEM);
237 238 239 240
}

static int cpuacct_percpu_seq_show(struct seq_file *m, void *V)
{
241
	return __cpuacct_percpu_seq_show(m, CPUACCT_STAT_NSTATS);
242 243
}

244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
static int cpuacct_all_seq_show(struct seq_file *m, void *V)
{
	struct cpuacct *ca = css_ca(seq_css(m));
	int index;
	int cpu;

	seq_puts(m, "cpu");
	for (index = 0; index < CPUACCT_STAT_NSTATS; index++)
		seq_printf(m, " %s", cpuacct_stat_desc[index]);
	seq_puts(m, "\n");

	for_each_possible_cpu(cpu) {
		struct cpuacct_usage *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);

		seq_printf(m, "%d", cpu);

		for (index = 0; index < CPUACCT_STAT_NSTATS; index++) {
#ifndef CONFIG_64BIT
			/*
			 * Take rq->lock to make 64-bit read safe on 32-bit
			 * platforms.
			 */
			raw_spin_lock_irq(&cpu_rq(cpu)->lock);
#endif

			seq_printf(m, " %llu", cpuusage->usages[index]);

#ifndef CONFIG_64BIT
			raw_spin_unlock_irq(&cpu_rq(cpu)->lock);
#endif
		}
		seq_puts(m, "\n");
	}
	return 0;
}

280
static int cpuacct_stats_show(struct seq_file *sf, void *v)
281
{
282
	struct cpuacct *ca = css_ca(seq_css(sf));
283
	s64 val[CPUACCT_STAT_NSTATS];
284
	int cpu;
285
	int stat;
286

287
	memset(val, 0, sizeof(val));
288
	for_each_possible_cpu(cpu) {
289
		u64 *cpustat = per_cpu_ptr(ca->cpustat, cpu)->cpustat;
290

291 292 293 294 295
		val[CPUACCT_STAT_USER]   += cpustat[CPUTIME_USER];
		val[CPUACCT_STAT_USER]   += cpustat[CPUTIME_NICE];
		val[CPUACCT_STAT_SYSTEM] += cpustat[CPUTIME_SYSTEM];
		val[CPUACCT_STAT_SYSTEM] += cpustat[CPUTIME_IRQ];
		val[CPUACCT_STAT_SYSTEM] += cpustat[CPUTIME_SOFTIRQ];
296 297
	}

298 299 300
	for (stat = 0; stat < CPUACCT_STAT_NSTATS; stat++) {
		seq_printf(sf, "%s %lld\n",
			   cpuacct_stat_desc[stat],
301
			   (long long)nsec_to_clock_t(val[stat]));
302
	}
303 304 305 306 307 308 309 310 311 312

	return 0;
}

static struct cftype files[] = {
	{
		.name = "usage",
		.read_u64 = cpuusage_read,
		.write_u64 = cpuusage_write,
	},
313 314 315 316 317 318 319 320
	{
		.name = "usage_user",
		.read_u64 = cpuusage_user_read,
	},
	{
		.name = "usage_sys",
		.read_u64 = cpuusage_sys_read,
	},
321 322
	{
		.name = "usage_percpu",
323
		.seq_show = cpuacct_percpu_seq_show,
324
	},
325 326 327 328 329 330 331 332
	{
		.name = "usage_percpu_user",
		.seq_show = cpuacct_percpu_user_seq_show,
	},
	{
		.name = "usage_percpu_sys",
		.seq_show = cpuacct_percpu_sys_seq_show,
	},
333 334 335 336
	{
		.name = "usage_all",
		.seq_show = cpuacct_all_seq_show,
	},
337 338
	{
		.name = "stat",
339
		.seq_show = cpuacct_stats_show,
340 341 342 343 344 345 346 347 348 349 350 351
	},
	{ }	/* terminate */
};

/*
 * charge this task's execution time to its accounting group.
 *
 * called with rq->lock held.
 */
void cpuacct_charge(struct task_struct *tsk, u64 cputime)
{
	struct cpuacct *ca;
352
	int index = CPUACCT_STAT_SYSTEM;
353
	struct pt_regs *regs = task_pt_regs(tsk);
354

355
	if (regs && user_mode(regs))
356
		index = CPUACCT_STAT_USER;
357 358

	rcu_read_lock();
359

360
	for (ca = task_ca(tsk); ca; ca = parent_ca(ca))
361 362
		this_cpu_ptr(ca->cpuusage)->usages[index] += cputime;

363 364 365
	rcu_read_unlock();
}

366 367 368 369 370
/*
 * Add user/system time to cpuacct.
 *
 * Note: it's the caller that updates the account of the root cgroup.
 */
371
void cpuacct_account_field(struct task_struct *tsk, int index, u64 val)
372 373 374 375
{
	struct cpuacct *ca;

	rcu_read_lock();
376 377
	for (ca = task_ca(tsk); ca != &root_cpuacct; ca = parent_ca(ca))
		this_cpu_ptr(ca->cpustat)->cpustat[index] += val;
378 379 380
	rcu_read_unlock();
}

381
struct cgroup_subsys cpuacct_cgrp_subsys = {
382 383
	.css_alloc	= cpuacct_css_alloc,
	.css_free	= cpuacct_css_free,
384
	.legacy_cftypes	= files,
385
	.early_init	= true,
386
};