Last active
October 28, 2022 22:28
-
-
Save erique/8721cf413e5b2771f36d44e72a10294d to your computer and use it in GitHub Desktop.
Quick hack to monitor hit count, ECLK ticks and rough CPU usage for each interrupt level
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// m68k-amigaos-gcc irq_perf.c -o irq_perf -noixemul -O2 -m68020 --omit-frame-pointer | |
#include <stdio.h> | |
#include <stdarg.h> | |
#include <proto/exec.h> | |
#include <proto/timer.h> | |
#include <exec/execbase.h> | |
#include <devices/timer.h> | |
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
#define RawPutChar(___ch) \ | |
LP1NR(516, RawPutChar , BYTE, ___ch, d0,\ | |
, EXEC_BASE_NAME) | |
void raw_put_char(uint32_t c __asm("d0"), struct ExecBase* SysBase __asm("a3")) | |
{ | |
RawPutChar(c); | |
} | |
void kprintf(const char *format, ...) | |
{ | |
va_list args; | |
struct ExecBase* SysBase = *((struct ExecBase **) (4L)); | |
va_start(args, format); | |
// 115200 bps 8N1 | |
__asm volatile("move.w #(3546895/115200),0xdff032": : : "cc", "memory"); | |
RawDoFmt((STRPTR) format, (APTR) args, | |
(__fpt) raw_put_char, (APTR) SysBase); | |
va_end(args); | |
} | |
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
struct Device* TimerBase; | |
struct TimerData | |
{ | |
uint32_t hits; | |
uint32_t ticks; | |
struct IntVector vector; | |
}; | |
void perfVector( uint32_t d0 __asm("d0"), | |
uint32_t req __asm("d1"), | |
uint32_t custom __asm("a0"), | |
void* data __asm("a1"), | |
uint32_t jmp __asm("a5"), | |
uint32_t exec __asm("a6") ) | |
{ | |
struct TimerData* perf = (struct TimerData*)data; | |
struct EClockVal sample; | |
ReadEClock(&sample); | |
perf->ticks -= sample.ev_lo; | |
struct IntVector* vector = &perf->vector; | |
typedef void (*ISR)(uint32_t d0 __asm("d0"), | |
uint32_t req __asm("d1"), | |
uint32_t custom __asm("a0"), | |
void* data __asm("a1"), | |
uint32_t jmp __asm("a5"), | |
uint32_t exec __asm("a6")); | |
ISR code = vector->iv_Code; | |
data = vector->iv_Data; | |
code(d0, req, custom, data, jmp, exec); | |
ReadEClock(&sample); | |
perf->ticks += sample.ev_lo; | |
perf->hits++; | |
} | |
#define NUM_INT_LEVELS (16) | |
struct TimerData perfData[NUM_INT_LEVELS] = { 0 }; | |
struct Interrupt* wrappedSetIntVector(ULONG intNumber __asm("d0"), | |
struct Interrupt* interrupt __asm("a1"), | |
struct ExecBase* SysBase __asm("a6")) | |
{ | |
struct IntVector* vector = &perfData[intNumber].vector; | |
Disable(); | |
struct Interrupt* old = (struct Interrupt*)vector->iv_Node; | |
if ((vector->iv_Node = &interrupt->is_Node)) | |
{ | |
vector->iv_Data = interrupt->is_Data; | |
vector->iv_Code = interrupt->is_Code; | |
} | |
else | |
{ | |
vector->iv_Data = (void*)-1; | |
vector->iv_Code = (void*)-1; | |
} | |
Enable(); | |
return old; | |
} | |
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
int main() | |
{ | |
struct MsgPort* timerPort = CreateMsgPort(); | |
struct timerequest* timeReq = CreateIORequest(timerPort, sizeof(struct timerequest)); | |
if (OpenDevice((STRPTR)TIMERNAME, UNIT_MICROHZ, (struct IORequest*)timeReq, 0)) | |
{ | |
printf("failed to open timer.device\n"); | |
return -1; | |
} | |
TimerBase = timeReq->tr_node.io_Device; | |
static const uint8_t intLevels = NUM_INT_LEVELS; | |
const char* vecNames[NUM_INT_LEVELS] = | |
{ | |
"TBE ", | |
"DSKBLK", | |
"SOFT ", | |
"PORTS ", | |
"COPER ", | |
"VERTB ", | |
"BLIT ", | |
"AUD0 ", | |
"AUD1 ", | |
"AUD2 ", | |
"AUD3 ", | |
"RBF ", | |
"DSKSYN", | |
"EXTER ", | |
"INTEN ", | |
"NMI " | |
}; | |
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
Disable(); | |
for(int16_t i = intLevels-1; i >= 0; --i) | |
{ | |
struct IntVector* vector = &SysBase->IntVects[i]; | |
struct TimerData* perf = &perfData[i]; | |
perf->vector = *vector; | |
vector->iv_Data = perf; | |
vector->iv_Code = perfVector; | |
vector->iv_Node = 0; | |
} | |
void* oldFunc = SetFunction((struct Library*)SysBase, -162, (APTR) wrappedSetIntVector); | |
Enable(); | |
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
printf("ctrl-c to exit; output via serial (115kbps 8N1)\n"); | |
struct EClockVal lastSample; | |
ReadEClock(&lastSample); | |
while(1) | |
{ | |
timeReq->tr_node.io_Command = TR_ADDREQUEST; | |
timeReq->tr_time.tv_sec = 1; | |
timeReq->tr_time.tv_micro = 0; | |
SendIO((struct IORequest*)timeReq); | |
uint32_t signals = Wait( (1L << timerPort->mp_SigBit) | SIGBREAKF_CTRL_C); | |
AbortIO((struct IORequest*)timeReq); | |
WaitIO((struct IORequest*)timeReq); | |
if (signals & SIGBREAKF_CTRL_C) | |
break; | |
kprintf("\033[2J"); | |
struct TimerData currPerf[NUM_INT_LEVELS] = { 0 }; | |
Disable(); | |
for(int16_t i = intLevels-1; i >= 0; --i) | |
{ | |
currPerf[i] = perfData[i]; | |
perfData[i].hits = 0; | |
perfData[i].ticks = 0; | |
} | |
Enable(); | |
struct EClockVal currSample; | |
ReadEClock(&currSample); | |
uint64_t prev = *((uint64_t*)&lastSample); | |
uint64_t curr = *((uint64_t*)&currSample); | |
uint64_t delta = curr - prev; | |
for(int16_t i = intLevels-1; i >= 0; --i) | |
{ | |
uint32_t ratio = (uint32_t)100 * (uint32_t)currPerf[i].ticks / (uint32_t)delta; | |
kprintf(" %s = [%4ld] = %6ld = %3ld%%%\n", vecNames[i], currPerf[i].hits, currPerf[i].ticks, ratio); | |
} | |
lastSample = currSample; | |
} | |
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
Disable(); | |
SetFunction((struct Library*)SysBase, -162, (APTR) oldFunc); | |
for(int16_t i = intLevels-1; i >= 0; --i) | |
{ | |
struct IntVector* vector = &SysBase->IntVects[i]; | |
struct TimerData* perf = &perfData[i]; | |
*vector = perf->vector; | |
} | |
Enable(); | |
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
CloseDevice((struct IORequest*)timeReq); | |
DeleteIORequest(timeReq); | |
DeleteMsgPort(timerPort); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment