UHSDR/UHSDR-active-devel/mchf-eclipse/misc/profiling.h
2022-11-08 16:13:55 +01:00

181 lines
5.6 KiB
C

/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
/************************************************************************************
** **
** mcHF QRP Transceiver **
** K Atanassov - M0NKA 2014 **
** **
**---------------------------------------------------------------------------------**
** **
** File name: **
** Description: Simple Timing Profiler **
** Last Modified: **
** Licence: GNU GPLv3 **
************************************************************************************/
#ifndef __PROFILING_H
#define __PROFILING_H
typedef enum {
ProfileAudioInterrupt = 0,
ProfileTP1,
ProfileTP2,
ProfileTP3,
ProfileTP4,
ProfileTP5,
ProfileTP6,
ProfileTP7,
ProfileTP8,
ProfileTP9,
ProfileFreeDV,
FreeDVTXUnderrun,
EventProfileMax
} ProfiledEventNames;
typedef struct {
uint32_t count;
uint32_t start;
uint32_t stop;
uint64_t duration; // to get average divide duration by count
} ProfilingTimedEvent;
typedef struct {
ProfilingTimedEvent event[EventProfileMax];
} EventProfile_t;
extern EventProfile_t eventProfile;
#define PROFILE_EVENTS
inline void profileEvent(const ProfiledEventNames pe) {
#ifdef PROFILE_EVENTS
if (pe<EventProfileMax) {
eventProfile.event[pe].count++;
}
#endif
}
/***
* How to use:
* First start the cycle timer with profileTimeEventInit()
* This resets the timer and makes it run.
*
* At any time call profileTimedEventStart(EventName)
* to have the start being recorded
* at the end of the event call profileTimedEventStop(EventName)
* Duration of a single event should not be longer then 2^32 / clock frequency
* i.e. ~25s @168 Mhz for a single event
* total duration recorded should not be more than 2^64 cycles
* which is quite a lot, i.e. there is no limit on that for the
* average person in this universe
*
* Due to the approach multiple events can be recorded correctly but
* outer events include the overhead of the calculation of the duration
* only the innermost events are more or less accurate unless you time the profile functions and
* remove the overhead later.
*/
void profileEventsTracePrint(void);
//inline void profileTimedEventInit(void);
//inline void profileTimedEventStart(const ProfiledEventNames pe);
//inline void profileTimedEventStop(const ProfiledEventNames pe);
//inline void profileTimedEventReset(const ProfiledEventNames pe);
//inline ProfilingTimedEvent* profileTimedEventGet(const ProfiledEventNames pe);
// INLINE IMPLEMENTATIONS
#define DWT_CYCCNT ((volatile uint32_t *)0xE0001004)
#define DWT_CONTROL ((volatile uint32_t *)0xE0001000)
#define SCB_DEMCR ((volatile uint32_t *)0xE000EDFC)
#define DWT_LAR ((volatile uint32_t *)0xE0001FB0)
//inline void profileCycleCount_reset(void){
static inline void profileCycleCount_reset(){
*SCB_DEMCR |= 0x01000000;
#ifdef STM32F7
*DWT_LAR = 0xC5ACCE55; // <-- added unlock access to DWT (ITM, etc.)registers
#endif
*DWT_CYCCNT = 0; // reset the counter
*DWT_CONTROL = 0;
}
//inline void profileCycleCount_start(void)
static inline void profileCycleCount_start()
{
*DWT_CONTROL = *DWT_CONTROL | 1;
}
//inline void profileCycleCount_stop(void)
static inline void profileCycleCount_stop(void)
{
*DWT_CONTROL = *DWT_CONTROL & ~1; //
}
//inline uint32_t profileCycleCount_get(void)
static inline uint32_t profileCycleCount_get(void)
{
return *DWT_CYCCNT;
}
//inline void profileTimedEventInit(void)
static inline void profileTimedEventInit(void)
{
profileCycleCount_reset();
profileCycleCount_start();
}
//inline void profileTimedEventStart(const ProfiledEventNames pe)
static inline void profileTimedEventStart(const ProfiledEventNames pe)
{
#ifdef PROFILE_EVENTS
if (pe<EventProfileMax) {
eventProfile.event[pe].start = profileCycleCount_get();
}
#endif
}
//inline void profileTimedEventStop(const ProfiledEventNames pe)
static inline void profileTimedEventStop(const ProfiledEventNames pe)
{
#ifdef PROFILE_EVENTS
uint32_t stop = profileCycleCount_get();
if (pe<EventProfileMax) {
eventProfile.event[pe].stop = stop;
eventProfile.event[pe].count++;
eventProfile.event[pe].duration += (eventProfile.event[pe].stop-eventProfile.event[pe].start);
}
#endif
}
//inline void profileTimedEventReset(const ProfiledEventNames pe)
static inline void profileTimedEventReset(const ProfiledEventNames pe)
{
#ifdef PROFILE_EVENTS
if (pe<EventProfileMax) {
eventProfile.event[pe].start = 0;
eventProfile.event[pe].stop = 0;
eventProfile.event[pe].count = 0;
eventProfile.event[pe].duration = 0;
}
#endif
}
//inline ProfilingTimedEvent* profileTimedEventGet(const ProfiledEventNames pe)
static inline ProfilingTimedEvent* profileTimedEventGet(const ProfiledEventNames pe)
{
ProfilingTimedEvent* pe_ptr = NULL;
#ifdef PROFILE_EVENTS
if (pe<EventProfileMax) {
pe_ptr = &eventProfile.event[pe];
}
#endif
return pe_ptr;
}
#endif