2 * This confidential and proprietary software may be used only as
3 * authorised by a licensing agreement from ARM Limited
4 * (C) COPYRIGHT 2010-2013 ARM Limited
6 * The entire notice above must be reproduced on all authorised
7 * copies and copies may only be made to the extent permitted
8 * by a licensing agreement from ARM Limited.
11 #include "mali_kernel_common.h"
13 #include "mali_osk_mali.h"
15 #include "mali_timestamp.h"
16 #include "mali_osk_profiling.h"
17 #include "mali_user_settings_db.h"
18 #include "mali_profiling_internal.h"
20 typedef struct mali_profiling_entry
{
24 } mali_profiling_entry
;
26 typedef enum mali_profiling_state
{
27 MALI_PROFILING_STATE_UNINITIALIZED
,
28 MALI_PROFILING_STATE_IDLE
,
29 MALI_PROFILING_STATE_RUNNING
,
30 MALI_PROFILING_STATE_RETURN
,
31 } mali_profiling_state
;
33 static _mali_osk_mutex_t
*lock
= NULL
;
34 static mali_profiling_state prof_state
= MALI_PROFILING_STATE_UNINITIALIZED
;
35 static mali_profiling_entry
* profile_entries
= NULL
;
36 static _mali_osk_atomic_t profile_insert_index
;
37 static u32 profile_mask
= 0;
39 static inline void add_event(u32 event_id
, u32 data0
, u32 data1
, u32 data2
, u32 data3
, u32 data4
);
41 void probe_mali_timeline_event(void *data
, TP_PROTO(unsigned int event_id
, unsigned int d0
, unsigned int d1
, unsigned
42 int d2
, unsigned int d3
, unsigned int d4
))
44 add_event(event_id
, d0
, d1
, d2
, d3
, d4
);
47 _mali_osk_errcode_t
_mali_internal_profiling_init(mali_bool auto_start
)
49 profile_entries
= NULL
;
51 _mali_osk_atomic_init(&profile_insert_index
, 0);
53 lock
= _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_ORDERED
, _MALI_OSK_LOCK_ORDER_PROFILING
);
55 return _MALI_OSK_ERR_FAULT
;
58 prof_state
= MALI_PROFILING_STATE_IDLE
;
60 if (MALI_TRUE
== auto_start
) {
61 u32 limit
= MALI_PROFILING_MAX_BUFFER_ENTRIES
; /* Use maximum buffer size */
63 mali_set_user_setting(_MALI_UK_USER_SETTING_SW_EVENTS_ENABLE
, MALI_TRUE
);
64 if (_MALI_OSK_ERR_OK
!= _mali_internal_profiling_start(&limit
)) {
65 return _MALI_OSK_ERR_FAULT
;
69 return _MALI_OSK_ERR_OK
;
72 void _mali_internal_profiling_term(void)
76 /* Ensure profiling is stopped */
77 _mali_internal_profiling_stop(&count
);
79 prof_state
= MALI_PROFILING_STATE_UNINITIALIZED
;
81 if (NULL
!= profile_entries
) {
82 _mali_osk_vfree(profile_entries
);
83 profile_entries
= NULL
;
87 _mali_osk_mutex_term(lock
);
92 _mali_osk_errcode_t
_mali_internal_profiling_start(u32
* limit
)
94 _mali_osk_errcode_t ret
;
95 mali_profiling_entry
*new_profile_entries
;
97 _mali_osk_mutex_wait(lock
);
99 if (MALI_PROFILING_STATE_RUNNING
== prof_state
) {
100 _mali_osk_mutex_signal(lock
);
101 return _MALI_OSK_ERR_BUSY
;
104 new_profile_entries
= _mali_osk_valloc(*limit
* sizeof(mali_profiling_entry
));
106 if (NULL
== new_profile_entries
) {
107 _mali_osk_vfree(new_profile_entries
);
108 return _MALI_OSK_ERR_NOMEM
;
111 if (MALI_PROFILING_MAX_BUFFER_ENTRIES
< *limit
) {
112 *limit
= MALI_PROFILING_MAX_BUFFER_ENTRIES
;
116 while (profile_mask
<= *limit
) {
121 *limit
= profile_mask
;
123 profile_mask
--; /* turns the power of two into a mask of one less */
125 if (MALI_PROFILING_STATE_IDLE
!= prof_state
) {
126 _mali_osk_mutex_signal(lock
);
127 _mali_osk_vfree(new_profile_entries
);
128 return _MALI_OSK_ERR_INVALID_ARGS
; /* invalid to call this function in this state */
131 profile_entries
= new_profile_entries
;
133 ret
= _mali_timestamp_reset();
135 if (_MALI_OSK_ERR_OK
== ret
) {
136 prof_state
= MALI_PROFILING_STATE_RUNNING
;
138 _mali_osk_vfree(profile_entries
);
139 profile_entries
= NULL
;
142 register_trace_mali_timeline_event(probe_mali_timeline_event
, NULL
);
144 _mali_osk_mutex_signal(lock
);
148 static inline void add_event(u32 event_id
, u32 data0
, u32 data1
, u32 data2
, u32 data3
, u32 data4
)
150 u32 cur_index
= (_mali_osk_atomic_inc_return(&profile_insert_index
) - 1) & profile_mask
;
152 profile_entries
[cur_index
].timestamp
= _mali_timestamp_get();
153 profile_entries
[cur_index
].event_id
= event_id
;
154 profile_entries
[cur_index
].data
[0] = data0
;
155 profile_entries
[cur_index
].data
[1] = data1
;
156 profile_entries
[cur_index
].data
[2] = data2
;
157 profile_entries
[cur_index
].data
[3] = data3
;
158 profile_entries
[cur_index
].data
[4] = data4
;
160 /* If event is "leave API function", add current memory usage to the event
161 * as data point 4. This is used in timeline profiling to indicate how
162 * much memory was used when leaving a function. */
163 if (event_id
== (MALI_PROFILING_EVENT_TYPE_SINGLE
|MALI_PROFILING_EVENT_CHANNEL_SOFTWARE
|MALI_PROFILING_EVENT_REASON_SINGLE_SW_LEAVE_API_FUNC
)) {
164 profile_entries
[cur_index
].data
[4] = _mali_ukk_report_memory_usage();
168 _mali_osk_errcode_t
_mali_internal_profiling_stop(u32
* count
)
170 _mali_osk_mutex_wait(lock
);
172 if (MALI_PROFILING_STATE_RUNNING
!= prof_state
) {
173 _mali_osk_mutex_signal(lock
);
174 return _MALI_OSK_ERR_INVALID_ARGS
; /* invalid to call this function in this state */
177 /* go into return state (user to retreive events), no more events will be added after this */
178 prof_state
= MALI_PROFILING_STATE_RETURN
;
180 unregister_trace_mali_timeline_event(probe_mali_timeline_event
, NULL
);
182 _mali_osk_mutex_signal(lock
);
184 tracepoint_synchronize_unregister();
186 *count
= _mali_osk_atomic_read(&profile_insert_index
);
187 if (*count
> profile_mask
) *count
= profile_mask
;
189 return _MALI_OSK_ERR_OK
;
192 u32
_mali_internal_profiling_get_count(void)
196 _mali_osk_mutex_wait(lock
);
197 if (MALI_PROFILING_STATE_RETURN
== prof_state
) {
198 retval
= _mali_osk_atomic_read(&profile_insert_index
);
199 if (retval
> profile_mask
) retval
= profile_mask
;
201 _mali_osk_mutex_signal(lock
);
206 _mali_osk_errcode_t
_mali_internal_profiling_get_event(u32 index
, u64
* timestamp
, u32
* event_id
, u32 data
[5])
208 u32 raw_index
= _mali_osk_atomic_read(&profile_insert_index
);
210 _mali_osk_mutex_wait(lock
);
212 if (index
< profile_mask
) {
213 if ((raw_index
& ~profile_mask
) != 0) {
215 index
&= profile_mask
;
218 if (prof_state
!= MALI_PROFILING_STATE_RETURN
) {
219 _mali_osk_mutex_signal(lock
);
220 return _MALI_OSK_ERR_INVALID_ARGS
; /* invalid to call this function in this state */
223 if(index
>= raw_index
) {
224 _mali_osk_mutex_signal(lock
);
225 return _MALI_OSK_ERR_FAULT
;
228 *timestamp
= profile_entries
[index
].timestamp
;
229 *event_id
= profile_entries
[index
].event_id
;
230 data
[0] = profile_entries
[index
].data
[0];
231 data
[1] = profile_entries
[index
].data
[1];
232 data
[2] = profile_entries
[index
].data
[2];
233 data
[3] = profile_entries
[index
].data
[3];
234 data
[4] = profile_entries
[index
].data
[4];
236 _mali_osk_mutex_signal(lock
);
237 return _MALI_OSK_ERR_FAULT
;
240 _mali_osk_mutex_signal(lock
);
241 return _MALI_OSK_ERR_OK
;
244 _mali_osk_errcode_t
_mali_internal_profiling_clear(void)
246 _mali_osk_mutex_wait(lock
);
248 if (MALI_PROFILING_STATE_RETURN
!= prof_state
) {
249 _mali_osk_mutex_signal(lock
);
250 return _MALI_OSK_ERR_INVALID_ARGS
; /* invalid to call this function in this state */
253 prof_state
= MALI_PROFILING_STATE_IDLE
;
255 _mali_osk_atomic_init(&profile_insert_index
, 0);
257 if (NULL
!= profile_entries
) {
258 _mali_osk_vfree(profile_entries
);
259 profile_entries
= NULL
;
262 _mali_osk_mutex_signal(lock
);
263 return _MALI_OSK_ERR_OK
;
266 mali_bool
_mali_internal_profiling_is_recording(void)
268 return prof_state
== MALI_PROFILING_STATE_RUNNING
? MALI_TRUE
: MALI_FALSE
;
271 mali_bool
_mali_internal_profiling_have_recording(void)
273 return prof_state
== MALI_PROFILING_STATE_RETURN
? MALI_TRUE
: MALI_FALSE
;