diff --git a/include/coreinit/performancemonitor.h b/include/coreinit/performancemonitor.h new file mode 100644 index 000000000..248626c57 --- /dev/null +++ b/include/coreinit/performancemonitor.h @@ -0,0 +1,206 @@ +#pragma once +#include + +/** + * \defgroup coreinit_performancemonitor Performance Monitor + * \ingroup coreinit + * + * @{ + */ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/// Used to tell OSSetPerformanceMonitor() which arguments are valid. +typedef enum OSPerfMonArg { + OS_PM_ARG_MMCR0 = 1u << 0u, + OS_PM_ARG_MMCR1 = 1u << 1u, + OS_PM_ARG_PMC1 = 1u << 2u, + OS_PM_ARG_PMC2 = 1u << 3u, + OS_PM_ARG_PMC3 = 1u << 4u, + OS_PM_ARG_PMC4 = 1u << 5u, +} OSPerfMonArg; + +/** + * Flags to write to (U)MMCR0 register. + * + * \sa OSSetPerformanceMonitor + */ +typedef enum OSPerfMonMMCR0Flags { + OS_PM_MMCR0_PMC1_CURRENT = 0b0000000u << 6, + OS_PM_MMCR0_PMC1_CPU_CYCLES = 0b0000001u << 6, + OS_PM_MMCR0_PMC1_INSTRUCTIONS_COMPLETED = 0b0000010u << 6, + OS_PM_MMCR0_PMC1_TBL_RISING_TRANSITIONS = 0b0000011u << 6, + OS_PM_MMCR0_PMC1_INSTRUCTIONS_DISPATCHED = 0b0000100u << 6, + OS_PM_MMCR0_PMC1_EIEIO_INSTRUCTIONS_COMPLETED = 0b0000101u << 6, + OS_PM_MMCR0_PMC1_ITLB_SEARCH_CYCLES = 0b0000110u << 6, + OS_PM_MMCR0_PMC1_L2_HITS = 0b0000111u << 6, + OS_PM_MMCR0_PMC1_INSTRUCTIONS_EA_DELIVERED = 0b0001000u << 6, + OS_PM_MMCR0_PMC1_INSTRUCTIONS_COMPLETED_MATCHES_IABR = 0b0001001u << 6, + OS_PM_MMCR0_PMC1_SLOW_L1_MISSES = 0b0001010u << 6, + OS_PM_MMCR0_PMC1_UNRESOLVED_BRANCHES = 0b0001011u << 6, + OS_PM_MMCR0_PMC1_UNRESOLVED_STALL_CYCLES = 0b0001100u << 6, + OS_PM_MMCR0_PMC1_L1_SHARED_STORES = 0b0001110u << 6, + OS_PM_MMCR0_PMC1_L2_SHARED_INTERVENTIONS = 0b0001111u << 6, + OS_PM_MMCR0_PMC1_CACHE_PARADOXES = 0b0010000u << 6, + OS_PM_MMCR0_PMC1_CIU_LOAD_REQUESTS = 0b0010100u << 6, + OS_PM_MMCR0_PMC1_BIU_ADDRESS_ONLY_REQUESTS = 0b0010101u << 6, + OS_PM_MMCR0_PMC1_CIU_PARADOXES = 0b0010110u << 6, + OS_PM_MMCR0_PMC1_60XE_BUS_DATA_BEATS = 0b0010111u << 6, + + OS_PM_MMCR0_PMC2_CURRENT = 0b000000u, + OS_PM_MMCR0_PMC2_CPU_CYCLES = 0b000001u, + OS_PM_MMCR0_PMC2_INSTRUCTIONS_COMPLETED = 0b000010u, + OS_PM_MMCR0_PMC2_TBL_RISING_TRANSITIONS = 0b000011u, + OS_PM_MMCR0_PMC2_INSTRUCTIONS_DISPATCHED = 0b000100u, + OS_PM_MMCR0_PMC2_L1_ICACHE_MISSES = 0b000101u, + OS_PM_MMCR0_PMC2_ITLB_MISSES = 0b000110u, + OS_PM_MMCR0_PMC2_L2_INSTRUCTION_MISSES = 0b000111u, + OS_PM_MMCR0_PMC2_PRED_BRANCHES_NOT_TAKEN = 0b001000u, + OS_PM_MMCR0_PMC2_RESERVED_LOADS = 0b001010u, + OS_PM_MMCR0_PMC2_LOADS_AND_STORES = 0b001011u, + OS_PM_MMCR0_PMC2_CACHE_SNOOPS = 0b001100u, + OS_PM_MMCR0_PMC2_L1_TO_L2_CASTOUTS = 0b001101u, + OS_PM_MMCR0_PMC2_SYSTEM_UNIT_INSTRUCTIONS = 0b001110u, + OS_PM_MMCR0_PMC2_L1_INSTRUCTION_MISS_CYCLES = 0b001111u, + OS_PM_MMCR0_PMC2_FIRST_SPECULATIVE_BRANCH_RESOLVES = 0b010000u, + OS_PM_MMCR0_PMC2_L2_SHARED_STORES = 0b010001u, + OS_PM_MMCR0_PMC2_L1_SHARED_INTERVENTIONS = 0b010010u, + OS_PM_MMCR0_PMC2_CIU_STORE_REQUESTS = 0b010100u, + OS_PM_MMCR0_PMC2_SLOW_OUTSTANDING_BIU_TRANSACTIONS = 0b010101u, + OS_PM_MMCR0_PMC2_CIU_MODIFIED_INTERVENTIONS = 0b010110u, +} OSPerfMonMMCR0Flags; + +/** + * Flags to write to (U)MMCR1 register. + * + * \sa OSSetPerformanceMonitor + */ +typedef enum OSPerfMonMMCR1Flags { + OS_PM_MMCR1_PMC3_CURRENT = 0b00000u << 27, + OS_PM_MMCR1_PMC3_CPU_CYCLES = 0b00001u << 27, + OS_PM_MMCR1_PMC3_INSTRUCTIONS_COMPLETED = 0b00010u << 27, + OS_PM_MMCR1_PMC3_TBL_RISING_TRANSITIONS = 0b00011u << 27, + OS_PM_MMCR1_PMC3_INSTRUCTIONS_DISPATCHED = 0b00100u << 27, + OS_PM_MMCR1_PMC3_L1_DCACHE_MISSES = 0b00101u << 27, + OS_PM_MMCR1_PMC3_DTLB_MISSES = 0b00110u << 27, + OS_PM_MMCR1_PMC3_L2_DATA_MISSES = 0b00111u << 27, + OS_PM_MMCR1_PMC3_PRED_BRANCHES_TAKEN = 0b01000u << 27, + OS_PM_MMCR1_PMC3_COND_STORES_COMPLETED = 0b01010u << 27, + OS_PM_MMCR1_PMC3_FPU_INSTRUCTIONS_COMPLETED = 0b01011u << 27, + OS_PM_MMCR1_PMC3_L2_CASTOUTS_BY_SNOOPS = 0b01100u << 27, + OS_PM_MMCR1_PMC3_L2_CACHE_OPERATIONS = 0b01101u << 27, + OS_PM_MMCR1_PMC3_L1_LOAD_MISS_CYCLES = 0b01111u << 27, + OS_PM_MMCR1_PMC3_SECOND_SPECULATIVE_BRANCH_RESOLVES = 0b10000u << 27, + OS_PM_MMCR1_PMC3_BPU_STALL_LR_CR_CYCLES = 0b10001u << 27, + OS_PM_MMCR1_PMC3_L1_MODIFIED_INTERVENTIONS = 0b10010u << 27, + OS_PM_MMCR1_PMC3_ICBI_SNOOPS = 0b10011u << 27, + OS_PM_MMCR1_PMC3_CIU_ADDRESS_ONLY_REQUESTS = 0b10100u << 27, + OS_PM_MMCR1_PMC3_BIU_LOAD_REQUESTS = 0b10101u << 27, + OS_PM_MMCR1_PMC3_CIU_SHARED_INTERVENTIONS = 0b10110u << 27, + + OS_PM_MMCR1_PMC4_CURRENT = 0b00000u << 22, + OS_PM_MMCR1_PMC4_CPU_CYCLES = 0b00001u << 22, + OS_PM_MMCR1_PMC4_INSTRUCTIONS_COMPLETED = 0b00010u << 22, + OS_PM_MMCR1_PMC4_TBL_RISING_TRANSITIONS = 0b00011u << 22, + OS_PM_MMCR1_PMC4_INSTRUCTIONS_DISPATCHED = 0b00100u << 22, + OS_PM_MMCR1_PMC4_L2_CASTOUTS = 0b00101u << 22, + OS_PM_MMCR1_PMC4_DTLB_SEARCH_CYCLES = 0b00110u << 22, + OS_PM_MMCR1_PMC4_BRANCHES_MISPREDICTED = 0b01000u << 22, + OS_PM_MMCR1_PMC4_INTACT_COND_STORES_COMPLETED = 0b01010u << 22, + OS_PM_MMCR1_PMC4_SYNC_INSTRUCTIONS_COMPLETED = 0b01011u << 22, + OS_PM_MMCR1_PMC4_SNOOP_RETRIES = 0b01100u << 22, + OS_PM_MMCR1_PMC4_INTEGER_OPERATIONS = 0b01101u << 22, + OS_PM_MMCR1_PMC4_BPU_STALL_TWO_BRANCHES_CYCLES = 0b01110u << 22, + OS_PM_MMCR1_PMC4_L2_MODIFIED_INTERVENTIONS = 0b10000u << 22, + OS_PM_MMCR1_PMC4_TLBIE_SNOOPS = 0b10001u << 22, + OS_PM_MMCR1_PMC4_L2_BANK_REFRESH_OVERFLOWS = 0b10010u << 22, + OS_PM_MMCR1_PMC4_CIU_ARTRY_COUNT = 0b10100u << 22, + OS_PM_MMCR1_PMC4_BIU_STORE_REQUESTS = 0b10101u << 22, + OS_PM_MMCR1_PMC4_CIU_TWO_CORE_SHARED_INTERVENTIONS = 0b10110u << 22, +} OSPerfMonMMCR1Flags; + +/** + * Write to performance monitor registers. + * + * Performance monitor registers can only be written by the kernel, this allows userspace + * to write to them. + * + * \param arg_mask OR-ed values from `OSPerfMonArg`, indicating which of the following + * arguments are to be written to registers. + * + * \param mmcr0 OR-ed values from `OSPerfMonMMCR0Flags` to write to register MMCR0. + * \param mmcr1 OR-ed values from `OSPerfMonMMCR1Flags` to write to register MMCR1. + * \param pmc1 Value to write to register PMC1. + * \param pmc2 Value to write to register PMC2. + * \param pmc3 Value to write to register PMC3. + * \param pmc4 Value to write to register PMC4. + */ +void OSSetPerformanceMonitor(uint32_t arg_mask, + uint32_t mmcr0, + uint32_t mmcr1, + uint32_t pmc1, + uint32_t pmc2, + uint32_t pmc3, + uint32_t pmc4); + +/** + * Convenience function to read from UPMC1. + */ +static inline +uint32_t +OSGetUPMC1() +{ + uint32_t result; + asm("mfupmc1 %[result]" + : [result] "=r"(result)); + return result; +} + +/** + * Convenience function to read from UPMC2. + */ +static inline +uint32_t +OSGetUPMC2() +{ + uint32_t result; + asm("mfupmc2 %[result]" + : [result] "=r"(result)); + return result; +} + +/** + * Convenience function to read from UPMC3. + */ +static inline +uint32_t +OSGetUPMC3() +{ + uint32_t result; + asm("mfupmc3 %[result]" + : [result] "=r"(result)); + return result; +} + +/** + * Convenience function to read from UPMC4. + */ +static inline +uint32_t +OSGetUPMC4() +{ + uint32_t result; + asm("mfupmc4 %[result]" + : [result] "=r"(result)); + return result; +} + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/tests/test_compile_headers_common/test_compile_headers_list.h b/tests/test_compile_headers_common/test_compile_headers_list.h index a47ededac..dc9250698 100644 --- a/tests/test_compile_headers_common/test_compile_headers_list.h +++ b/tests/test_compile_headers_common/test_compile_headers_list.h @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include