mirror of
				https://github.com/ARM-software/workload-automation.git
				synced 2025-10-31 07:04:17 +00:00 
			
		
		
		
	Initial commit of open source Workload Automation.
This commit is contained in:
		
							
								
								
									
										7
									
								
								wlauto/external/pmu_logger/Makefile
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								wlauto/external/pmu_logger/Makefile
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| # To build the pmu_logger module use the following command line | ||||
| # make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -C ../kernel/out SUBDIRS=$PWD modules | ||||
| # where | ||||
| # CROSS_COMPILE - prefix of the arm linux compiler | ||||
| # -C - location of the configured kernel source tree | ||||
|  | ||||
| obj-m := pmu_logger.o | ||||
							
								
								
									
										35
									
								
								wlauto/external/pmu_logger/README
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										35
									
								
								wlauto/external/pmu_logger/README
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| The pmu_logger module provides the ability to periodically trace CCI PMU counters. The trace destinations can be ftrace buffer and/or kernel logs. This file gives a quick overview of the funcationality provided by the module and how to use it. | ||||
|  | ||||
| The pmu_logger module creates a directory in the debugfs filesystem called cci_pmu_logger which can be used to enable/disable the counters and control the events that are counted. | ||||
|  | ||||
| To configure the events being counted write the corresponding event id to the counter*  files. The list of CCI PMU events can be found at http://arminfo.emea.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0470d/CJHICFBF.html. | ||||
|  | ||||
| The "period_jiffies" can be used to control the periodicity of tracing. It accepts values in kernel jiffies. | ||||
|  | ||||
| To enable tracing, write a 1 to "control". To disable write another 1 to "control". The files "enable_console" and "enable_ftrace" control where the trace is written to. To check if the counters are currently running or not, you can read the control file. | ||||
|  | ||||
| The current values of the counters can be read from the "values" file. | ||||
|  | ||||
| Eg. To trace, A15 and A7 snoop hit rate every 10 jiffies the following command are required -  | ||||
|  | ||||
|  | ||||
| trace-cmd reset | ||||
|  | ||||
| echo 0x63 > counter0 | ||||
| echo 0x6A > counter1 | ||||
| echo 0x83 > counter2 | ||||
| echo 0x8A > counter3 | ||||
|  | ||||
| echo 10 > period_jiffies | ||||
|  | ||||
| trace-cmd start -b 20000 -e "sched:sched_wakeup" | ||||
|  | ||||
| echo 1 > control | ||||
|  | ||||
| # perform the activity for which you would like to collect the CCI PMU trace. | ||||
|  | ||||
| trace-cmd stop && trace-cmd extract | ||||
|  | ||||
| echo 1 > control | ||||
|  | ||||
| trace-cmd report trace.dat | grep print # shows the trace of the CCI PMU counters along with the cycle counter values. | ||||
							
								
								
									
										294
									
								
								wlauto/external/pmu_logger/pmu_logger.c
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										294
									
								
								wlauto/external/pmu_logger/pmu_logger.c
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,294 @@ | ||||
| /*    Copyright 2013-2015 ARM Limited | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
| */ | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * pmu_logger.c - Kernel module to log the CCI PMU counters | ||||
|  */ | ||||
|  | ||||
| #include <linux/init.h> | ||||
| #include <linux/kernel.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/debugfs.h> | ||||
| #include <linux/timer.h> | ||||
| #include <asm/io.h> | ||||
|  | ||||
| #define MODULE_NAME "cci_pmu_logger" | ||||
|  | ||||
| // CCI_BASE needs to be modified to point to the mapped location of CCI in | ||||
| // memory on your device. | ||||
| #define CCI_BASE 0x2C090000  // TC2 | ||||
| //#define CCI_BASE 0x10D20000  | ||||
| #define CCI_SIZE 0x00010000 | ||||
|  | ||||
| #define PMCR 0x100 | ||||
|  | ||||
| #define PMCR_CEN (1 << 0) | ||||
| #define PMCR_RST (1 << 1) | ||||
| #define PMCR_CCR (1 << 2) | ||||
| #define PMCR_CCD (1 << 3) | ||||
| #define PMCR_EX  (1 << 4) | ||||
| #define PMCR_DP  (1 << 5) | ||||
|  | ||||
| #define CC_BASE  0x9000 | ||||
| #define PC0_BASE 0xA000 | ||||
| #define PC1_BASE 0xB000 | ||||
| #define PC2_BASE 0xC000 | ||||
| #define PC3_BASE 0xD000 | ||||
|  | ||||
| #define PC_ESR      0x0 | ||||
| #define CNT_VALUE   0x4 | ||||
| #define CNT_CONTROL 0x8 | ||||
|  | ||||
| #define CNT_ENABLE (1 << 0) | ||||
|  | ||||
| u32 counter0_event = 0x6A; | ||||
| u32 counter1_event = 0x63; | ||||
| u32 counter2_event = 0x8A; | ||||
| u32 counter3_event = 0x83; | ||||
|  | ||||
| u32 enable_console = 0; | ||||
| u32 enable_ftrace = 1; | ||||
|  | ||||
| void *cci_base = 0; | ||||
|  | ||||
| static struct dentry *module_debugfs_root; | ||||
| static int enabled = false; | ||||
|  | ||||
| u32 delay = 10; //jiffies. This translates to 1 sample every 100 ms | ||||
| struct timer_list timer; | ||||
|  | ||||
| static void call_after_delay(void) | ||||
| { | ||||
| 	timer.expires = jiffies + delay; | ||||
| 	add_timer(&timer); | ||||
| } | ||||
|  | ||||
| 	 | ||||
| static void setup_and_call_after_delay(void (*fn)(unsigned long)) | ||||
| { | ||||
| 	init_timer(&timer); | ||||
| 	timer.data = (unsigned long)&timer; | ||||
| 	timer.function = fn; | ||||
|  | ||||
| 	call_after_delay(); | ||||
| } | ||||
|  | ||||
| static void print_counter_configuration(void) | ||||
| { | ||||
| 	if (enable_ftrace) | ||||
| 		trace_printk("Counter_0: %02x Counter_1: %02x Counter_2: %02x Counter_3: %02x\n", \ | ||||
| 			     counter0_event, counter1_event, counter2_event, counter3_event); | ||||
|  | ||||
| 	if (enable_console) | ||||
| 		printk("Counter_0: %02x Counter_1: %02x Counter_2: %02x Counter_3: %02x\n", \ | ||||
| 		       counter0_event, counter1_event, counter2_event, counter3_event); | ||||
| } | ||||
|  | ||||
| static void initialize_cci_pmu(void) | ||||
| { | ||||
| 	u32 val; | ||||
|  | ||||
| 	// Select the events counted | ||||
| 	iowrite32(counter0_event, cci_base + PC0_BASE + PC_ESR); | ||||
| 	iowrite32(counter1_event, cci_base + PC1_BASE + PC_ESR); | ||||
| 	iowrite32(counter2_event, cci_base + PC2_BASE + PC_ESR); | ||||
| 	iowrite32(counter3_event, cci_base + PC3_BASE + PC_ESR); | ||||
|  | ||||
| 	// Enable the individual PMU counters | ||||
| 	iowrite32(CNT_ENABLE, cci_base + PC0_BASE + CNT_CONTROL); | ||||
| 	iowrite32(CNT_ENABLE, cci_base + PC1_BASE + CNT_CONTROL); | ||||
| 	iowrite32(CNT_ENABLE, cci_base + PC2_BASE + CNT_CONTROL); | ||||
| 	iowrite32(CNT_ENABLE, cci_base + PC3_BASE + CNT_CONTROL); | ||||
| 	iowrite32(CNT_ENABLE, cci_base + CC_BASE + CNT_CONTROL); | ||||
|  | ||||
| 	// Reset the counters and configure the Cycle Count Divider | ||||
| 	val = ioread32(cci_base + PMCR); | ||||
| 	iowrite32(val | PMCR_RST | PMCR_CCR | PMCR_CCD, cci_base + PMCR); | ||||
| } | ||||
|  | ||||
| static void enable_cci_pmu_counters(void) | ||||
| { | ||||
| 	u32 val = ioread32(cci_base + PMCR); | ||||
| 	iowrite32(val | PMCR_CEN, cci_base + PMCR); | ||||
| } | ||||
|  | ||||
| static void disable_cci_pmu_counters(void) | ||||
| { | ||||
| 	u32 val = ioread32(cci_base + PMCR); | ||||
| 	iowrite32(val & ~PMCR_CEN, cci_base + PMCR); | ||||
| } | ||||
|  | ||||
| static void trace_values(unsigned long arg) | ||||
| { | ||||
| 	u32 cycles; | ||||
| 	u32 counter[4]; | ||||
|  | ||||
| 	cycles = ioread32(cci_base + CC_BASE + CNT_VALUE); | ||||
| 	counter[0] = ioread32(cci_base + PC0_BASE + CNT_VALUE); | ||||
| 	counter[1] = ioread32(cci_base + PC1_BASE + CNT_VALUE); | ||||
| 	counter[2] = ioread32(cci_base + PC2_BASE + CNT_VALUE); | ||||
| 	counter[3] = ioread32(cci_base + PC3_BASE + CNT_VALUE); | ||||
|  | ||||
| 	if (enable_ftrace) | ||||
| 		trace_printk("Cycles: %08x Counter_0: %08x" | ||||
| 			     " Counter_1: %08x Counter_2: %08x Counter_3: %08x\n", \ | ||||
| 			     cycles, counter[0], counter[1], counter[2], counter[3]); | ||||
|  | ||||
| 	if (enable_console) | ||||
| 		printk("Cycles: %08x Counter_0: %08x" | ||||
| 		       " Counter_1: %08x Counter_2: %08x Counter_3: %08x\n", \ | ||||
| 		       cycles, counter[0], counter[1], counter[2], counter[3]); | ||||
|  | ||||
| 	if (enabled) { | ||||
| 		u32 val; | ||||
| 		// Reset the counters | ||||
| 		val = ioread32(cci_base + PMCR); | ||||
| 		iowrite32(val | PMCR_RST | PMCR_CCR, cci_base + PMCR); | ||||
|  | ||||
| 		call_after_delay(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static ssize_t read_control(struct file *file, char __user *buf, size_t count, loff_t *ppos) | ||||
| { | ||||
| 	char status[16]; | ||||
| 	/* printk(KERN_DEBUG "%s\n", __func__); */ | ||||
|  | ||||
| 	if (enabled) | ||||
| 		snprintf(status, 16, "enabled\n"); | ||||
| 	else | ||||
| 		snprintf(status, 16, "disabled\n"); | ||||
|  | ||||
| 	return simple_read_from_buffer(buf, count, ppos, status, strlen(status)); | ||||
| } | ||||
|  | ||||
| static ssize_t write_control(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | ||||
| { | ||||
| 	if (enabled) { | ||||
| 		disable_cci_pmu_counters(); | ||||
| 		enabled = false; | ||||
| 	} else { | ||||
| 		initialize_cci_pmu(); | ||||
| 		enable_cci_pmu_counters(); | ||||
| 		enabled = true; | ||||
|  | ||||
| 		print_counter_configuration(); | ||||
| 		setup_and_call_after_delay(trace_values); | ||||
| 	} | ||||
|  | ||||
| 	return count; | ||||
| } | ||||
|  | ||||
| static ssize_t read_values(struct file *file, char __user *buf, size_t count, loff_t *ppos) | ||||
| { | ||||
| 	char values[256]; | ||||
| 	/* u32 val; */ | ||||
|  | ||||
| 	snprintf(values, 256, "Cycles: %08x Counter_0: %08x" | ||||
| 		 " Counter_1: %08x Counter_2: %08x Counter_3: %08x\n", \ | ||||
| 		 ioread32(cci_base + CC_BASE + CNT_VALUE),  \ | ||||
| 		 ioread32(cci_base + PC0_BASE + CNT_VALUE), \ | ||||
| 		 ioread32(cci_base + PC1_BASE + CNT_VALUE), \ | ||||
| 		 ioread32(cci_base + PC2_BASE + CNT_VALUE), \ | ||||
| 		 ioread32(cci_base + PC3_BASE + CNT_VALUE)); | ||||
|  | ||||
| 	return simple_read_from_buffer(buf, count, ppos, values, strlen(values)); | ||||
| } | ||||
|  | ||||
| static const struct file_operations control_fops = { | ||||
| 	.owner = THIS_MODULE, | ||||
| 	.read = read_control, | ||||
| 	.write = write_control, | ||||
| }; | ||||
|  | ||||
| static const struct file_operations value_fops = { | ||||
| 	.owner = THIS_MODULE, | ||||
| 	.read = read_values, | ||||
| }; | ||||
|  | ||||
| static int __init pmu_logger_init(void) | ||||
| { | ||||
| 	struct dentry *retval; | ||||
| 	 | ||||
| 	module_debugfs_root = debugfs_create_dir(MODULE_NAME, NULL); | ||||
| 	if (!module_debugfs_root || IS_ERR(module_debugfs_root)) { | ||||
| 		printk(KERN_ERR "error creating debugfs dir.\n"); | ||||
| 		goto out; | ||||
| 	} | ||||
| 	 | ||||
| 	retval = debugfs_create_file("control", S_IRUGO | S_IWUGO, module_debugfs_root, NULL, &control_fops); | ||||
| 	if (!retval) | ||||
| 		goto out; | ||||
|  | ||||
| 	retval = debugfs_create_file("values", S_IRUGO, module_debugfs_root, NULL, &value_fops); | ||||
| 	if (!retval) | ||||
| 		goto out; | ||||
|  | ||||
| 	retval = debugfs_create_bool("enable_console", S_IRUGO | S_IWUGO, module_debugfs_root, &enable_console); | ||||
| 	if (!retval) | ||||
| 		goto out; | ||||
|  | ||||
| 	retval = debugfs_create_bool("enable_ftrace", S_IRUGO | S_IWUGO, module_debugfs_root, &enable_ftrace); | ||||
| 	if (!retval) | ||||
| 		goto out; | ||||
|  | ||||
| 	retval = debugfs_create_u32("period_jiffies", S_IRUGO | S_IWUGO, module_debugfs_root, &delay); | ||||
| 	if (!retval) | ||||
| 		goto out; | ||||
|  | ||||
| 	retval = debugfs_create_x32("counter0", S_IRUGO | S_IWUGO, module_debugfs_root, &counter0_event); | ||||
| 	if (!retval) | ||||
| 		goto out; | ||||
| 	retval = debugfs_create_x32("counter1", S_IRUGO | S_IWUGO, module_debugfs_root, &counter1_event); | ||||
| 	if (!retval) | ||||
| 		goto out; | ||||
| 	retval = debugfs_create_x32("counter2", S_IRUGO | S_IWUGO, module_debugfs_root, &counter2_event); | ||||
| 	if (!retval) | ||||
| 		goto out; | ||||
| 	retval = debugfs_create_x32("counter3", S_IRUGO | S_IWUGO, module_debugfs_root, &counter3_event); | ||||
| 	if (!retval) | ||||
| 		goto out; | ||||
|  | ||||
| 	cci_base = ioremap(CCI_BASE, CCI_SIZE); | ||||
| 	if (!cci_base) | ||||
| 		goto out; | ||||
|  | ||||
| 	printk(KERN_INFO "CCI PMU Logger loaded.\n"); | ||||
| 	return 0; | ||||
| 	 | ||||
| out: | ||||
| 	debugfs_remove_recursive(module_debugfs_root); | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static void __exit pmu_logger_exit(void) | ||||
| { | ||||
| 	if (module_debugfs_root) { | ||||
| 		debugfs_remove_recursive(module_debugfs_root); | ||||
| 		module_debugfs_root = NULL; | ||||
| 	} | ||||
| 	if (cci_base) | ||||
| 		iounmap(cci_base); | ||||
|  | ||||
| 	printk(KERN_INFO "CCI PMU Logger removed.\n"); | ||||
| } | ||||
|  | ||||
| module_init(pmu_logger_init); | ||||
| module_exit(pmu_logger_exit); | ||||
|  | ||||
| MODULE_LICENSE("GPL"); | ||||
| MODULE_AUTHOR("Punit Agrawal"); | ||||
| MODULE_DESCRIPTION("logger for CCI PMU counters"); | ||||
							
								
								
									
										
											BIN
										
									
								
								wlauto/external/pmu_logger/pmu_logger.ko
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								wlauto/external/pmu_logger/pmu_logger.ko
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
		Reference in New Issue
	
	Block a user