2 * This confidential and proprietary software may be used only as
3 * authorised by a licensing agreement from ARM Limited
4 * (C) COPYRIGHT 2010-2015 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_mutex_signal(lock
);
108 _mali_osk_vfree(new_profile_entries
);
109 return _MALI_OSK_ERR_NOMEM
;
112 if (MALI_PROFILING_MAX_BUFFER_ENTRIES
< *limit
) {
113 *limit
= MALI_PROFILING_MAX_BUFFER_ENTRIES
;
117 while (profile_mask
<= *limit
) {
122 *limit
= profile_mask
;
124 profile_mask
--; /* turns the power of two into a mask of one less */
126 if (MALI_PROFILING_STATE_IDLE
!= prof_state
) {
127 _mali_osk_mutex_signal(lock
);
128 _mali_osk_vfree(new_profile_entries
);
129 return _MALI_OSK_ERR_INVALID_ARGS
; /* invalid to call this function in this state */
132 profile_entries
= new_profile_entries
;
134 ret
= _mali_timestamp_reset();
136 if (_MALI_OSK_ERR_OK
== ret
) {
137 prof_state
= MALI_PROFILING_STATE_RUNNING
;
139 _mali_osk_vfree(profile_entries
);
140 profile_entries
= NULL
;
143 register_trace_mali_timeline_event(probe_mali_timeline_event
, NULL
);
145 _mali_osk_mutex_signal(lock
);
149 static inline void add_event(u32 event_id
, u32 data0
, u32 data1
, u32 data2
, u32 data3
, u32 data4
)
151 u32 cur_index
= (_mali_osk_atomic_inc_return(&profile_insert_index
) - 1) & profile_mask
;
153 profile_entries
[cur_index
].timestamp
= _mali_timestamp_get();
154 profile_entries
[cur_index
].event_id
= event_id
;
155 profile_entries
[cur_index
].data
[0] = data0
;
156 profile_entries
[cur_index
].data
[1] = data1
;
157 profile_entries
[cur_index
].data
[2] = data2
;
158 profile_entries
[cur_index
].data
[3] = data3
;
159 profile_entries
[cur_index
].data
[4] = data4
;
161 /* If event is "leave API function", add current memory usage to the event
162 * as data point 4. This is used in timeline profiling to indicate how
163 * much memory was used when leaving a function. */
164 if (event_id
== (MALI_PROFILING_EVENT_TYPE_SINGLE
| MALI_PROFILING_EVENT_CHANNEL_SOFTWARE
| MALI_PROFILING_EVENT_REASON_SINGLE_SW_LEAVE_API_FUNC
)) {
165 profile_entries
[cur_index
].data
[4] = _mali_ukk_report_memory_usage();
169 _mali_osk_errcode_t
_mali_internal_profiling_stop(u32
*count
)
171 _mali_osk_mutex_wait(lock
);
173 if (MALI_PROFILING_STATE_RUNNING
!= prof_state
) {
174 _mali_osk_mutex_signal(lock
);
175 return _MALI_OSK_ERR_INVALID_ARGS
; /* invalid to call this function in this state */
178 /* go into return state (user to retreive events), no more events will be added after this */
179 prof_state
= MALI_PROFILING_STATE_RETURN
;
181 unregister_trace_mali_timeline_event(probe_mali_timeline_event
, NULL
);
183 _mali_osk_mutex_signal(lock
);
185 tracepoint_synchronize_unregister();
187 *count
= _mali_osk_atomic_read(&profile_insert_index
);
188 if (*count
> profile_mask
) *count
= profile_mask
;
190 return _MALI_OSK_ERR_OK
;
193 u32
_mali_internal_profiling_get_count(void)
197 _mali_osk_mutex_wait(lock
);
198 if (MALI_PROFILING_STATE_RETURN
== prof_state
) {
199 retval
= _mali_osk_atomic_read(&profile_insert_index
);
200 if (retval
> profile_mask
) retval
= profile_mask
;
202 _mali_osk_mutex_signal(lock
);
207 _mali_osk_errcode_t
_mali_internal_profiling_get_event(u32 index
, u64
*timestamp
, u32
*event_id
, u32 data
[5])
209 u32 raw_index
= _mali_osk_atomic_read(&profile_insert_index
);
211 _mali_osk_mutex_wait(lock
);
213 if (index
< profile_mask
) {
214 if ((raw_index
& ~profile_mask
) != 0) {
216 index
&= profile_mask
;
219 if (prof_state
!= MALI_PROFILING_STATE_RETURN
) {
220 _mali_osk_mutex_signal(lock
);
221 return _MALI_OSK_ERR_INVALID_ARGS
; /* invalid to call this function in this state */
224 if (index
>= raw_index
) {
225 _mali_osk_mutex_signal(lock
);
226 return _MALI_OSK_ERR_FAULT
;
229 *timestamp
= profile_entries
[index
].timestamp
;
230 *event_id
= profile_entries
[index
].event_id
;
231 data
[0] = profile_entries
[index
].data
[0];
232 data
[1] = profile_entries
[index
].data
[1];
233 data
[2] = profile_entries
[index
].data
[2];
234 data
[3] = profile_entries
[index
].data
[3];
235 data
[4] = profile_entries
[index
].data
[4];
237 _mali_osk_mutex_signal(lock
);
238 return _MALI_OSK_ERR_FAULT
;
241 _mali_osk_mutex_signal(lock
);
242 return _MALI_OSK_ERR_OK
;
245 _mali_osk_errcode_t
_mali_internal_profiling_clear(void)
247 _mali_osk_mutex_wait(lock
);
249 if (MALI_PROFILING_STATE_RETURN
!= prof_state
) {
250 _mali_osk_mutex_signal(lock
);
251 return _MALI_OSK_ERR_INVALID_ARGS
; /* invalid to call this function in this state */
254 prof_state
= MALI_PROFILING_STATE_IDLE
;
256 _mali_osk_atomic_init(&profile_insert_index
, 0);
258 if (NULL
!= profile_entries
) {
259 _mali_osk_vfree(profile_entries
);
260 profile_entries
= NULL
;
263 _mali_osk_mutex_signal(lock
);
264 return _MALI_OSK_ERR_OK
;
267 mali_bool
_mali_internal_profiling_is_recording(void)
269 return prof_state
== MALI_PROFILING_STATE_RUNNING
? MALI_TRUE
: MALI_FALSE
;
272 mali_bool
_mali_internal_profiling_have_recording(void)
274 return prof_state
== MALI_PROFILING_STATE_RETURN
? MALI_TRUE
: MALI_FALSE
;