1 // SPDX-License-Identifier: GPL-2.0-only
3 * linux/kernel/profile.c
4 * Simple profiling. Manages a direct-mapped profile hit count buffer,
5 * with configurable resolution, support for restricting the cpus on
6 * which profiling is done, and switching between cpu time and
7 * schedule() calls via kernel command line parameters passed at boot.
9 * Scheduler profiling support, Arjan van de Ven and Ingo Molnar,
11 * Consolidation of architecture support code for profiling,
12 * Nadia Yvette Chambers, Oracle, July 2004
13 * Amortized hit count accounting via per-cpu open-addressed hashtables
14 * to resolve timer interrupt livelocks, Nadia Yvette Chambers,
18 #include <linux/export.h>
19 #include <linux/profile.h>
20 #include <linux/memblock.h>
21 #include <linux/notifier.h>
23 #include <linux/cpumask.h>
24 #include <linux/cpu.h>
25 #include <linux/highmem.h>
26 #include <linux/mutex.h>
27 #include <linux/slab.h>
28 #include <linux/vmalloc.h>
29 #include <linux/sched/stat.h>
31 #include <asm/sections.h>
32 #include <asm/irq_regs.h>
33 #include <asm/ptrace.h>
38 #define PROFILE_GRPSHIFT 3
39 #define PROFILE_GRPSZ (1 << PROFILE_GRPSHIFT)
40 #define NR_PROFILE_HIT (PAGE_SIZE/sizeof(struct profile_hit))
41 #define NR_PROFILE_GRP (NR_PROFILE_HIT/PROFILE_GRPSZ)
43 static atomic_t
*prof_buffer
;
44 static unsigned long prof_len
;
45 static unsigned short int prof_shift
;
47 int prof_on __read_mostly
;
48 EXPORT_SYMBOL_GPL(prof_on
);
50 int profile_setup(char *str
)
52 static const char schedstr
[] = "schedule";
53 static const char kvmstr
[] = "kvm";
54 const char *select
= NULL
;
57 if (!strncmp(str
, schedstr
, strlen(schedstr
))) {
58 prof_on
= SCHED_PROFILING
;
60 } else if (!strncmp(str
, kvmstr
, strlen(kvmstr
))) {
61 prof_on
= KVM_PROFILING
;
63 } else if (get_option(&str
, &par
)) {
64 prof_shift
= clamp(par
, 0, BITS_PER_LONG
- 1);
65 prof_on
= CPU_PROFILING
;
66 pr_info("kernel profiling enabled (shift: %u)\n",
71 if (str
[strlen(select
)] == ',')
72 str
+= strlen(select
) + 1;
73 if (get_option(&str
, &par
))
74 prof_shift
= clamp(par
, 0, BITS_PER_LONG
- 1);
75 pr_info("kernel %s profiling enabled (shift: %u)\n",
81 __setup("profile=", profile_setup
);
84 int __ref
profile_init(void)
90 /* only text is profiled */
91 prof_len
= (_etext
- _stext
) >> prof_shift
;
94 pr_warn("profiling shift: %u too large\n", prof_shift
);
99 buffer_bytes
= prof_len
*sizeof(atomic_t
);
101 prof_buffer
= kzalloc(buffer_bytes
, GFP_KERNEL
|__GFP_NOWARN
);
105 prof_buffer
= alloc_pages_exact(buffer_bytes
,
106 GFP_KERNEL
|__GFP_ZERO
|__GFP_NOWARN
);
110 prof_buffer
= vzalloc(buffer_bytes
);
117 static void do_profile_hits(int type
, void *__pc
, unsigned int nr_hits
)
120 pc
= ((unsigned long)__pc
- (unsigned long)_stext
) >> prof_shift
;
122 atomic_add(nr_hits
, &prof_buffer
[pc
]);
125 void profile_hits(int type
, void *__pc
, unsigned int nr_hits
)
127 if (prof_on
!= type
|| !prof_buffer
)
129 do_profile_hits(type
, __pc
, nr_hits
);
131 EXPORT_SYMBOL_GPL(profile_hits
);
133 void profile_tick(int type
)
135 struct pt_regs
*regs
= get_irq_regs();
137 /* This is the old kernel-only legacy profiling */
138 if (!user_mode(regs
))
139 profile_hit(type
, (void *)profile_pc(regs
));
142 #ifdef CONFIG_PROC_FS
143 #include <linux/proc_fs.h>
144 #include <linux/seq_file.h>
145 #include <linux/uaccess.h>
148 * This function accesses profiling information. The returned data is
149 * binary: the sampling step and the actual contents of the profile
150 * buffer. Use of the program readprofile is recommended in order to
151 * get meaningful info out of these data.
154 read_profile(struct file
*file
, char __user
*buf
, size_t count
, loff_t
*ppos
)
156 unsigned long p
= *ppos
;
159 unsigned long sample_step
= 1UL << prof_shift
;
161 if (p
>= (prof_len
+1)*sizeof(unsigned int))
163 if (count
> (prof_len
+1)*sizeof(unsigned int) - p
)
164 count
= (prof_len
+1)*sizeof(unsigned int) - p
;
167 while (p
< sizeof(unsigned int) && count
> 0) {
168 if (put_user(*((char *)(&sample_step
)+p
), buf
))
170 buf
++; p
++; count
--; read
++;
172 pnt
= (char *)prof_buffer
+ p
- sizeof(atomic_t
);
173 if (copy_to_user(buf
, (void *)pnt
, count
))
180 /* default is to not implement this call */
181 int __weak
setup_profiling_timer(unsigned mult
)
187 * Writing to /proc/profile resets the counters
189 * Writing a 'profiling multiplier' value into it also re-sets the profiling
190 * interrupt frequency, on architectures that support this.
192 static ssize_t
write_profile(struct file
*file
, const char __user
*buf
,
193 size_t count
, loff_t
*ppos
)
196 if (count
== sizeof(int)) {
197 unsigned int multiplier
;
199 if (copy_from_user(&multiplier
, buf
, sizeof(int)))
202 if (setup_profiling_timer(multiplier
))
206 memset(prof_buffer
, 0, prof_len
* sizeof(atomic_t
));
210 static const struct proc_ops profile_proc_ops
= {
211 .proc_read
= read_profile
,
212 .proc_write
= write_profile
,
213 .proc_lseek
= default_llseek
,
216 int __ref
create_proc_profile(void)
218 struct proc_dir_entry
*entry
;
223 entry
= proc_create("profile", S_IWUSR
| S_IRUGO
,
224 NULL
, &profile_proc_ops
);
226 proc_set_size(entry
, (1 + prof_len
) * sizeof(atomic_t
));
229 subsys_initcall(create_proc_profile
);
230 #endif /* CONFIG_PROC_FS */