]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/arm-ds5-gator.git/blob - driver/gator_events_mali_t6xx.c
gator: Version 5.17
[android-sdk/arm-ds5-gator.git] / driver / gator_events_mali_t6xx.c
1 /**
2  * Copyright (C) ARM Limited 2011-2013. All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  */
10 #include "gator.h"
12 #include <linux/module.h>
13 #include <linux/time.h>
14 #include <linux/math64.h>
15 #include <linux/slab.h>
16 #include <asm/io.h>
18 #include "linux/mali_linux_trace.h"
20 #include "gator_events_mali_common.h"
22 /*
23  * Check that the MALI_SUPPORT define is set to one of the allowable device codes.
24  */
25 #if (MALI_SUPPORT != MALI_T6xx)
26 #error MALI_SUPPORT set to an invalid device code: expecting MALI_T6xx
27 #endif
29 /* Counters for Mali-T6xx:
30  *
31  *  - Timeline events
32  *    They are tracepoints, but instead of reporting a number they report a START/STOP event.
33  *    They are reported in Streamline as number of microseconds while that particular counter was active.
34  *
35  *  - SW counters
36  *    They are tracepoints reporting a particular number.
37  *    They are accumulated in sw_counter_data array until they are passed to Streamline, then they are zeroed.
38  *
39  *  - Accumulators
40  *    They are the same as software counters but their value is not zeroed.
41  */
43 /* Timeline (start/stop) activity */
44 static const char *timeline_event_names[] = {
45         "PM_SHADER_0",
46         "PM_SHADER_1",
47         "PM_SHADER_2",
48         "PM_SHADER_3",
49         "PM_SHADER_4",
50         "PM_SHADER_5",
51         "PM_SHADER_6",
52         "PM_SHADER_7",
53         "PM_TILER_0",
54         "PM_L2_0",
55         "PM_L2_1",
56         "MMU_AS_0",
57         "MMU_AS_1",
58         "MMU_AS_2",
59         "MMU_AS_3"
60 };
62 enum {
63         PM_SHADER_0 = 0,
64         PM_SHADER_1,
65         PM_SHADER_2,
66         PM_SHADER_3,
67         PM_SHADER_4,
68         PM_SHADER_5,
69         PM_SHADER_6,
70         PM_SHADER_7,
71         PM_TILER_0,
72         PM_L2_0,
73         PM_L2_1,
74         MMU_AS_0,
75         MMU_AS_1,
76         MMU_AS_2,
77         MMU_AS_3
78 };
79 /* The number of shader blocks in the enum above */
80 #define NUM_PM_SHADER (8)
82 /* Software Counters */
83 static const char *software_counter_names[] = {
84         "MMU_PAGE_FAULT_0",
85         "MMU_PAGE_FAULT_1",
86         "MMU_PAGE_FAULT_2",
87         "MMU_PAGE_FAULT_3"
88 };
90 enum {
91         MMU_PAGE_FAULT_0 = 0,
92         MMU_PAGE_FAULT_1,
93         MMU_PAGE_FAULT_2,
94         MMU_PAGE_FAULT_3
95 };
97 /* Software Counters */
98 static const char *accumulators_names[] = {
99         "TOTAL_ALLOC_PAGES"
100 };
102 enum {
103         TOTAL_ALLOC_PAGES = 0
104 };
106 #define FIRST_TIMELINE_EVENT (0)
107 #define NUMBER_OF_TIMELINE_EVENTS (sizeof(timeline_event_names) / sizeof(timeline_event_names[0]))
108 #define FIRST_SOFTWARE_COUNTER (FIRST_TIMELINE_EVENT + NUMBER_OF_TIMELINE_EVENTS)
109 #define NUMBER_OF_SOFTWARE_COUNTERS (sizeof(software_counter_names) / sizeof(software_counter_names[0]))
110 #define FIRST_ACCUMULATOR (FIRST_SOFTWARE_COUNTER + NUMBER_OF_SOFTWARE_COUNTERS)
111 #define NUMBER_OF_ACCUMULATORS (sizeof(accumulators_names) / sizeof(accumulators_names[0]))
112 #define FILMSTRIP (NUMBER_OF_TIMELINE_EVENTS + NUMBER_OF_SOFTWARE_COUNTERS + NUMBER_OF_ACCUMULATORS)
113 #define NUMBER_OF_EVENTS (NUMBER_OF_TIMELINE_EVENTS + NUMBER_OF_SOFTWARE_COUNTERS + NUMBER_OF_ACCUMULATORS + 1)
115 /*
116  * gatorfs variables for counter enable state
117  */
118 static mali_counter counters[NUMBER_OF_EVENTS];
119 static unsigned long filmstrip_event;
121 /* An array used to return the data we recorded
122  * as key,value pairs hence the *2
123  */
124 static unsigned long counter_dump[NUMBER_OF_EVENTS * 2];
126 /*
127  * Array holding counter start times (in ns) for each counter.  A zero here
128  * indicates that the activity monitored by this counter is not running.
129  */
130 static struct timespec timeline_event_starttime[NUMBER_OF_TIMELINE_EVENTS];
132 /* The data we have recorded */
133 static unsigned int timeline_data[NUMBER_OF_TIMELINE_EVENTS];
134 static unsigned int sw_counter_data[NUMBER_OF_SOFTWARE_COUNTERS];
135 static unsigned int accumulators_data[NUMBER_OF_ACCUMULATORS];
137 /* Hold the previous timestamp, used to calculate the sample interval. */
138 static struct timespec prev_timestamp;
140 /**
141  * Returns the timespan (in microseconds) between the two specified timestamps.
142  *
143  * @param start Ptr to the start timestamp
144  * @param end Ptr to the end timestamp
145  *
146  * @return Number of microseconds between the two timestamps (can be negative if start follows end).
147  */
148 static inline long get_duration_us(const struct timespec *start, const struct timespec *end)
150         long event_duration_us = (end->tv_nsec - start->tv_nsec) / 1000;
151         event_duration_us += (end->tv_sec - start->tv_sec) * 1000000;
153         return event_duration_us;
156 static void record_timeline_event(unsigned int timeline_index, unsigned int type)
158         struct timespec event_timestamp;
159         struct timespec *event_start = &timeline_event_starttime[timeline_index];
161         switch (type) {
162         case ACTIVITY_START:
163                 /* Get the event time... */
164                 getnstimeofday(&event_timestamp);
166                 /* Remember the start time if the activity is not already started */
167                 if (event_start->tv_sec == 0) {
168                         *event_start = event_timestamp; /* Structure copy */
169                 }
170                 break;
172         case ACTIVITY_STOP:
173                 /* if the counter was started... */
174                 if (event_start->tv_sec != 0) {
175                         /* Get the event time... */
176                         getnstimeofday(&event_timestamp);
178                         /* Accumulate the duration in us */
179                         timeline_data[timeline_index] += get_duration_us(event_start, &event_timestamp);
181                         /* Reset the start time to indicate the activity is stopped. */
182                         event_start->tv_sec = 0;
183                 }
184                 break;
186         default:
187                 /* Other activity events are ignored. */
188                 break;
189         }
192 /*
193  * Documentation about the following tracepoints is in mali_linux_trace.h
194  */
196 GATOR_DEFINE_PROBE(mali_pm_status, TP_PROTO(unsigned int event_id, unsigned long long value))
198 #define SHADER_PRESENT_LO       0x100   /* (RO) Shader core present bitmap, low word */
199 #define TILER_PRESENT_LO        0x110   /* (RO) Tiler core present bitmap, low word */
200 #define L2_PRESENT_LO           0x120   /* (RO) Level 2 cache present bitmap, low word */
201 #define BIT_AT(value, pos) ((value >> pos) & 1)
203         static unsigned long long previous_shader_bitmask = 0;
204         static unsigned long long previous_tiler_bitmask = 0;
205         static unsigned long long previous_l2_bitmask = 0;
207         switch (event_id) {
208         case SHADER_PRESENT_LO:
209                 {
210                         unsigned long long changed_bitmask = previous_shader_bitmask ^ value;
211                         int pos;
213                         for (pos = 0; pos < NUM_PM_SHADER; ++pos) {
214                                 if (BIT_AT(changed_bitmask, pos)) {
215                                         record_timeline_event(PM_SHADER_0 + pos, BIT_AT(value, pos) ? ACTIVITY_START : ACTIVITY_STOP);
216                                 }
217                         }
219                         previous_shader_bitmask = value;
220                         break;
221                 }
223         case TILER_PRESENT_LO:
224                 {
225                         unsigned long long changed = previous_tiler_bitmask ^ value;
227                         if (BIT_AT(changed, 0)) {
228                                 record_timeline_event(PM_TILER_0, BIT_AT(value, 0) ? ACTIVITY_START : ACTIVITY_STOP);
229                         }
231                         previous_tiler_bitmask = value;
232                         break;
233                 }
235         case L2_PRESENT_LO:
236                 {
237                         unsigned long long changed = previous_l2_bitmask ^ value;
239                         if (BIT_AT(changed, 0)) {
240                                 record_timeline_event(PM_L2_0, BIT_AT(value, 0) ? ACTIVITY_START : ACTIVITY_STOP);
241                         }
242                         if (BIT_AT(changed, 4)) {
243                                 record_timeline_event(PM_L2_1, BIT_AT(value, 4) ? ACTIVITY_START : ACTIVITY_STOP);
244                         }
246                         previous_l2_bitmask = value;
247                         break;
248                 }
250         default:
251                 /* No other blocks are supported at present */
252                 break;
253         }
255 #undef SHADER_PRESENT_LO
256 #undef TILER_PRESENT_LO
257 #undef L2_PRESENT_LO
258 #undef BIT_AT
261 GATOR_DEFINE_PROBE(mali_page_fault_insert_pages, TP_PROTO(int event_id, unsigned long value))
263         /* We add to the previous since we may receive many tracepoints in one sample period */
264         sw_counter_data[MMU_PAGE_FAULT_0 + event_id] += value;
267 GATOR_DEFINE_PROBE(mali_mmu_as_in_use, TP_PROTO(int event_id))
269         record_timeline_event(MMU_AS_0 + event_id, ACTIVITY_START);
272 GATOR_DEFINE_PROBE(mali_mmu_as_released, TP_PROTO(int event_id))
274         record_timeline_event(MMU_AS_0 + event_id, ACTIVITY_STOP);
277 GATOR_DEFINE_PROBE(mali_total_alloc_pages_change, TP_PROTO(long long int event_id))
279         accumulators_data[TOTAL_ALLOC_PAGES] = event_id;
282 static int create_files(struct super_block *sb, struct dentry *root)
284         int event;
285         /*
286          * Create the filesystem for all events
287          */
288         int counter_index = 0;
289         const char *mali_name = gator_mali_get_mali_name();
290         mali_profiling_control_type *mali_control;
292         for (event = FIRST_TIMELINE_EVENT; event < FIRST_TIMELINE_EVENT + NUMBER_OF_TIMELINE_EVENTS; event++) {
293                 if (gator_mali_create_file_system(mali_name, timeline_event_names[counter_index], sb, root, &counters[event], NULL) != 0) {
294                         return -1;
295                 }
296                 counter_index++;
297         }
298         counter_index = 0;
299         for (event = FIRST_SOFTWARE_COUNTER; event < FIRST_SOFTWARE_COUNTER + NUMBER_OF_SOFTWARE_COUNTERS; event++) {
300                 if (gator_mali_create_file_system(mali_name, software_counter_names[counter_index], sb, root, &counters[event], NULL) != 0) {
301                         return -1;
302                 }
303                 counter_index++;
304         }
305         counter_index = 0;
306         for (event = FIRST_ACCUMULATOR; event < FIRST_ACCUMULATOR + NUMBER_OF_ACCUMULATORS; event++) {
307                 if (gator_mali_create_file_system(mali_name, accumulators_names[counter_index], sb, root, &counters[event], NULL) != 0) {
308                         return -1;
309                 }
310                 counter_index++;
311         }
313         mali_control = symbol_get(_mali_profiling_control);
314         if (mali_control) {     
315                 if (gator_mali_create_file_system(mali_name, "Filmstrip_cnt0", sb, root, &counters[FILMSTRIP], &filmstrip_event) != 0) {
316                         return -1;
317                 }
318                 symbol_put(_mali_profiling_control);
319         }
321         return 0;
324 static int register_tracepoints(void)
326         if (GATOR_REGISTER_TRACE(mali_pm_status)) {
327                 pr_debug("gator: Mali-T6xx: mali_pm_status tracepoint failed to activate\n");
328                 return 0;
329         }
331         if (GATOR_REGISTER_TRACE(mali_page_fault_insert_pages)) {
332                 pr_debug("gator: Mali-T6xx: mali_page_fault_insert_pages tracepoint failed to activate\n");
333                 return 0;
334         }
336         if (GATOR_REGISTER_TRACE(mali_mmu_as_in_use)) {
337                 pr_debug("gator: Mali-T6xx: mali_mmu_as_in_use tracepoint failed to activate\n");
338                 return 0;
339         }
341         if (GATOR_REGISTER_TRACE(mali_mmu_as_released)) {
342                 pr_debug("gator: Mali-T6xx: mali_mmu_as_released tracepoint failed to activate\n");
343                 return 0;
344         }
346         if (GATOR_REGISTER_TRACE(mali_total_alloc_pages_change)) {
347                 pr_debug("gator: Mali-T6xx: mali_total_alloc_pages_change tracepoint failed to activate\n");
348                 return 0;
349         }
351         pr_debug("gator: Mali-T6xx: start\n");
352         pr_debug("gator: Mali-T6xx: mali_pm_status probe is at %p\n", &probe_mali_pm_status);
353         pr_debug("gator: Mali-T6xx: mali_page_fault_insert_pages probe is at %p\n", &probe_mali_page_fault_insert_pages);
354         pr_debug("gator: Mali-T6xx: mali_mmu_as_in_use probe is at %p\n", &probe_mali_mmu_as_in_use);
355         pr_debug("gator: Mali-T6xx: mali_mmu_as_released probe is at %p\n", &probe_mali_mmu_as_released);
356         pr_debug("gator: Mali-T6xx: mali_total_alloc_pages_change probe is at %p\n", &probe_mali_total_alloc_pages_change);
358         return 1;
361 static int start(void)
363         unsigned int cnt;
364         mali_profiling_control_type *mali_control;
366         /* Clean all data for the next capture */
367         for (cnt = 0; cnt < NUMBER_OF_TIMELINE_EVENTS; cnt++) {
368                 timeline_event_starttime[cnt].tv_sec = timeline_event_starttime[cnt].tv_nsec = 0;
369                 timeline_data[cnt] = 0;
370         }
372         for (cnt = 0; cnt < NUMBER_OF_SOFTWARE_COUNTERS; cnt++) {
373                 sw_counter_data[cnt] = 0;
374         }
376         for (cnt = 0; cnt < NUMBER_OF_ACCUMULATORS; cnt++) {
377                 accumulators_data[cnt] = 0;
378         }
380         /* Register tracepoints */
381         if (register_tracepoints() == 0) {
382                 return -1;
383         }
385         /* Generic control interface for Mali DDK. */
386         mali_control = symbol_get(_mali_profiling_control);
387         if (mali_control) {
388                 /* The event attribute in the XML file keeps the actual frame rate. */
389                 unsigned int enabled = counters[FILMSTRIP].enabled ? 1 : 0;
390                 unsigned int rate = filmstrip_event & 0xff;
391                 unsigned int resize_factor = (filmstrip_event >> 8) & 0xff;
393                 pr_debug("gator: mali online _mali_profiling_control symbol @ %p\n", mali_control);
395 #define FBDUMP_CONTROL_ENABLE (1)
396 #define FBDUMP_CONTROL_RATE (2)
397 #define FBDUMP_CONTROL_RESIZE_FACTOR (4)
398                 mali_control(FBDUMP_CONTROL_ENABLE, enabled);
399                 mali_control(FBDUMP_CONTROL_RATE, rate);
400                 mali_control(FBDUMP_CONTROL_RESIZE_FACTOR, resize_factor);
402                 pr_debug("gator: sent mali_control enabled=%d, rate=%d, resize_factor=%d\n", enabled, rate, resize_factor);
404                 symbol_put(_mali_profiling_control);
405         } else {
406                 printk("gator: mali online _mali_profiling_control symbol not found\n");
407         }
409         /*
410          * Set the first timestamp for calculating the sample interval. The first interval could be quite long,
411          * since it will be the time between 'start' and the first 'read'.
412          * This means that timeline values will be divided by a big number for the first sample.
413          */
414         getnstimeofday(&prev_timestamp);
416         return 0;
419 static void stop(void)
421         mali_profiling_control_type *mali_control;
423         pr_debug("gator: Mali-T6xx: stop\n");
425         /*
426          * It is safe to unregister traces even if they were not successfully
427          * registered, so no need to check.
428          */
429         GATOR_UNREGISTER_TRACE(mali_pm_status);
430         pr_debug("gator: Mali-T6xx: mali_pm_status tracepoint deactivated\n");
432         GATOR_UNREGISTER_TRACE(mali_page_fault_insert_pages);
433         pr_debug("gator: Mali-T6xx: mali_page_fault_insert_pages tracepoint deactivated\n");
435         GATOR_UNREGISTER_TRACE(mali_mmu_as_in_use);
436         pr_debug("gator: Mali-T6xx: mali_mmu_as_in_use tracepoint deactivated\n");
438         GATOR_UNREGISTER_TRACE(mali_mmu_as_released);
439         pr_debug("gator: Mali-T6xx: mali_mmu_as_released tracepoint deactivated\n");
441         GATOR_UNREGISTER_TRACE(mali_total_alloc_pages_change);
442         pr_debug("gator: Mali-T6xx: mali_total_alloc_pages_change tracepoint deactivated\n");
444         /* Generic control interface for Mali DDK. */
445         mali_control = symbol_get(_mali_profiling_control);
446         if (mali_control) {
447                 pr_debug("gator: mali offline _mali_profiling_control symbol @ %p\n", mali_control);
449                 mali_control(FBDUMP_CONTROL_ENABLE, 0);
451                 symbol_put(_mali_profiling_control);
452         } else {
453                 printk("gator: mali offline _mali_profiling_control symbol not found\n");
454         }
457 static int read(int **buffer)
459         int cnt;
460         int len = 0;
461         long sample_interval_us = 0;
462         struct timespec read_timestamp;
464         if (!on_primary_core()) {
465                 return 0;
466         }
468         /* Get the start of this sample period. */
469         getnstimeofday(&read_timestamp);
471         /*
472          * Calculate the sample interval if the previous sample time is valid.
473          * We use tv_sec since it will not be 0.
474          */
475         if (prev_timestamp.tv_sec != 0) {
476                 sample_interval_us = get_duration_us(&prev_timestamp, &read_timestamp);
477         }
479         /* Structure copy. Update the previous timestamp. */
480         prev_timestamp = read_timestamp;
482         /*
483          * Report the timeline counters (ACTIVITY_START/STOP)
484          */
485         for (cnt = FIRST_TIMELINE_EVENT; cnt < (FIRST_TIMELINE_EVENT + NUMBER_OF_TIMELINE_EVENTS); cnt++) {
486                 mali_counter *counter = &counters[cnt];
487                 if (counter->enabled) {
488                         const int index = cnt - FIRST_TIMELINE_EVENT;
489                         unsigned int value;
491                         /* If the activity is still running, reset its start time to the start of this sample period
492                          * to correct the count.  Add the time up to the end of the sample onto the count. */
493                         if (timeline_event_starttime[index].tv_sec != 0) {
494                                 const long event_duration = get_duration_us(&timeline_event_starttime[index], &read_timestamp);
495                                 timeline_data[index] += event_duration;
496                                 timeline_event_starttime[index] = read_timestamp;       /* Activity is still running. */
497                         }
499                         if (sample_interval_us != 0) {
500                                 /* Convert the counter to a percent-of-sample value */
501                                 value = (timeline_data[index] * 100) / sample_interval_us;
502                         } else {
503                                 pr_debug("gator: Mali-T6xx: setting value to zero\n");
504                                 value = 0;
505                         }
507                         /* Clear the counter value ready for the next sample. */
508                         timeline_data[index] = 0;
510                         counter_dump[len++] = counter->key;
511                         counter_dump[len++] = value;
512                 }
513         }
515         /* Report the software counters */
516         for (cnt = FIRST_SOFTWARE_COUNTER; cnt < (FIRST_SOFTWARE_COUNTER + NUMBER_OF_SOFTWARE_COUNTERS); cnt++) {
517                 const mali_counter *counter = &counters[cnt];
518                 if (counter->enabled) {
519                         const int index = cnt - FIRST_SOFTWARE_COUNTER;
520                         counter_dump[len++] = counter->key;
521                         counter_dump[len++] = sw_counter_data[index];
522                         /* Set the value to zero for the next time */
523                         sw_counter_data[index] = 0;
524                 }
525         }
527         /* Report the accumulators */
528         for (cnt = FIRST_ACCUMULATOR; cnt < (FIRST_ACCUMULATOR + NUMBER_OF_ACCUMULATORS); cnt++) {
529                 const mali_counter *counter = &counters[cnt];
530                 if (counter->enabled) {
531                         const int index = cnt - FIRST_ACCUMULATOR;
532                         counter_dump[len++] = counter->key;
533                         counter_dump[len++] = accumulators_data[index];
534                         /* Do not zero the accumulator */
535                 }
536         }
538         /* Update the buffer */
539         if (buffer) {
540                 *buffer = (int *)counter_dump;
541         }
543         return len;
546 static struct gator_interface gator_events_mali_t6xx_interface = {
547         .create_files = create_files,
548         .start = start,
549         .stop = stop,
550         .read = read
551 };
553 extern int gator_events_mali_t6xx_init(void)
555         pr_debug("gator: Mali-T6xx: sw_counters init\n");
557         gator_mali_initialise_counters(counters, NUMBER_OF_EVENTS);
559         return gator_events_install(&gator_events_mali_t6xx_interface);