aboutsummaryrefslogtreecommitdiff
path: root/driver/gator_events_threads.c
blob: 9de85862fe6cdafd48a87780471e6e792a993908 (plain)
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
/*
 * Sample activity provider
 *
 * Copyright (C) ARM Limited 2014. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * See gator_events_mmapped.c for additional directions and
 * troubleshooting.
 *
 * For this sample to work these entries must be present in the
 * events.xml file. So create an events-threads.xml in the gator
 * daemon source directory with the following contents and rebuild
 * gatord:
 *
 * <category name="threads">
 *   <event counter="Linux_threads" title="Linux" name="Threads" class="activity" activity1="odd" activity_color1="0x000000ff" rendering_type="bar" average_selection="yes" average_cores="yes" percentage="yes" description="Linux syscall activity"/>
 * </category>
 */

#include <trace/events/sched.h>

#include "gator.h"

static ulong threads_enabled;
static ulong threads_key;
static ulong threads_cores;

#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct rq *rq, struct task_struct *prev, struct task_struct *next))
#else
GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_struct *next))
#endif
{
	int cpu = get_physical_cpu();
	int pid = next->pid;
	if (pid == 0) {
		// idle
		gator_marshal_activity_switch(cpu, threads_key, 0, 0);
	} else if (pid & 1) {
		// odd
		gator_marshal_activity_switch(cpu, threads_key, 1, pid);
	} else {
		// even
		//gator_marshal_activity_switch(cpu, threads_key, 2, current->pid);
		// Multiple activities are not yet supported so emit idle
		gator_marshal_activity_switch(cpu, threads_key, 0, 0);
	}
}

// Adds Linux_threads directory and enabled, key, and cores files to /dev/gator/events
static int gator_events_threads_create_files(struct super_block *sb, struct dentry *root)
{
	struct dentry *dir;

	dir = gatorfs_mkdir(sb, root, "Linux_threads");
	if (!dir) {
		return -1;
	}
	gatorfs_create_ulong(sb, dir, "enabled", &threads_enabled);
	gatorfs_create_ro_ulong(sb, dir, "key", &threads_key);
	// Number of cores associated with this activity
	gatorfs_create_ro_ulong(sb, dir, "cores", &threads_cores);

	return 0;
}

static int gator_events_threads_start(void)
{
	int cpu;

	if (threads_enabled) {
		preempt_disable();
		for (cpu = 0; cpu < nr_cpu_ids; ++cpu) {
			gator_marshal_activity_switch(cpu, threads_key, 0, 0);
		}
		preempt_enable();

		if (GATOR_REGISTER_TRACE(sched_switch)) {
			goto fail_sched_switch;
		}
	}

	return 0;

fail_sched_switch:
	return -1;
}

static void gator_events_threads_stop(void)
{
	if (threads_enabled) {
		GATOR_UNREGISTER_TRACE(sched_switch);
	}

	threads_enabled = 0;
}

static struct gator_interface gator_events_threads_interface = {
	.create_files = gator_events_threads_create_files,
	.start = gator_events_threads_start,
	.stop = gator_events_threads_stop,
};

// Must not be static. Ensure that this init function is added to GATOR_EVENTS_LIST in gator_main.c
int __init gator_events_threads_init(void)
{
	threads_enabled = 0;
	threads_key = gator_events_get_key();
	threads_cores = nr_cpu_ids;

	return gator_events_install(&gator_events_threads_interface);
}