1/* 2 * Copyright 2014, General Dynamics C4 Systems 3 * 4 * SPDX-License-Identifier: GPL-2.0-only 5 */ 6 7/* 8 * Kernel Profiler 9 * 10 * 2007 David Greenaway 11 * 2007 Ported to seL4 C kernel by Philip Derrin 12 */ 13 14#ifdef PROFILER 15 16#include <util.h> 17#include <machine.h> 18#include <machine/profiler.h> 19 20#ifdef CHECKPOINT_PROFILER 21/* The current checkpoint value */ 22volatile unsigned int checkpoint VISIBLE; 23unsigned int max_checkpoint; 24 25/* Event count for each checkpoint value */ 26profiler_entry_t profiler_entries[MAX_UNIQUE_CHECKPOINTS]; 27#else 28/* Number of entries the profiler currently keeps track of */ 29int profiler_num_entries; 30 31/* Number of instructions the profiler could not record */ 32long long profiler_dropped_instructions; 33 34/* The instructions recorded by the profiler */ 35profiler_entry_t profiler_entries[MAX_UNIQUE_INSTRUCTIONS]; 36#endif 37 38/* Should we be profiling the system? */ 39bool_t profiler_enabled VISIBLE = true; 40 41#ifdef CHECKPOINT_PROFILER 42void profiler_reset(void) 43{ 44 word_t i; 45 46 for (i = 0; i < MAX_UNIQUE_CHECKPOINTS; i++) { 47 profiler_entries[i].pc = 0; 48 profiler_entries[i].count = 0; 49 } 50 checkpoint = 0; 51} 52 53void profiler_list(void) 54{ 55 unsigned int samples, i, count; 56 57 printf("checkpoint count\n"); 58 59 samples = 0; 60 count = 0; 61 for (i = 0; i <= max_checkpoint; i++) { 62 if (profiler_entries[i].pc != 0) { 63 printf("%u %u\n", i, (unsigned int)profiler_entries[i].count); 64 samples += profiler_entries[i].count; 65 count++; 66 } 67 } 68 69 printf("%u checkpoints, %u sample(s)\n", count, samples); 70} 71 72void profiler_record_sample(word_t pc) 73{ 74 if (checkpoint > max_checkpoint) { 75 max_checkpoint = checkpoint; 76 } 77 78 if (!profiler_entries[checkpoint].pc) { 79 profiler_entries[checkpoint].pc = 1; 80 } 81 profiler_entries[checkpoint].count++; 82} 83#else 84/* 85 * Reset all counters 86 */ 87void profiler_reset(void) 88{ 89 for (word_t i = 0; i < MAX_UNIQUE_INSTRUCTIONS; i++) { 90 profiler_entries[i].pc = 0; 91 profiler_entries[i].count = 0; 92 } 93 profiler_num_entries = 0; 94 profiler_dropped_instructions = 0; 95} 96 97/* 98 * Dump out recorded values to stdout 99 */ 100void profiler_list(void) 101{ 102 long long samples; 103 104 /* Print header */ 105 printf("addr count\n"); 106 107 /* Print out each address */ 108 samples = 0; 109 for (word_t i = 0; i < MAX_UNIQUE_INSTRUCTIONS; i++) { 110 if (profiler_entries[i].pc != 0) { 111 printf("%x %d\n", (unsigned int)profiler_entries[i].pc, 112 (int)profiler_entries[i].count); 113 samples += profiler_entries[i].count; 114 } 115 } 116 117 /* Print statistics */ 118 printf("\n%d unique address(es), %d sample(s)\n", 119 (int)profiler_num_entries, (int)samples); 120 if (profiler_dropped_instructions > 0) { 121 printf("*** WARNING : %d instructions dropped\n", 122 (int)profiler_dropped_instructions); 123 } 124} 125 126/* 127 * Record a sample 128 */ 129void profiler_record_sample(word_t pc) 130{ 131 /* Number used for hashing such that the gcd of MAX_UNIQUE_INSTRUCTIONS and 132 * (1 .. hashVal) is 1. 133 * 134 * As MAX_UNIQUE_INSTRUCTIONS is prime, this can be ensured mearly by 135 * having hashVal < MAX_UNIQUE_INSTRUCTIONS. */ 136 const int hashVal = 1024; 137 138 /* Hash optimised for valid ARM instruction addresses, which are always 139 * word aligned. */ 140 word_t hash = (pc >> 2) % MAX_UNIQUE_INSTRUCTIONS; 141 word_t hash2 = ((pc >> 2) % hashVal) + 1; 142 143 if (!profiler_enabled) { 144 return; 145 } 146 147 while (true) { 148 149 if (profiler_entries[hash].pc == pc) { 150 151 /* Found the correct entry */ 152 profiler_entries[hash].count++; 153 break; 154 155 } else if (profiler_entries[hash].pc == 0) { 156 157 /* Found a spot for a new entry */ 158 if (profiler_num_entries < (MAX_UNIQUE_INSTRUCTIONS / 4) * 3) { 159 profiler_entries[hash].pc = pc; 160 profiler_entries[hash].count = 1; 161 profiler_num_entries++; 162 break; 163 } else { 164 /* Too many entries. Abort the record. */ 165 profiler_dropped_instructions++; 166 break; 167 } 168 } 169 170 /* Keep searching */ 171 hash += hash2; 172 hash %= MAX_UNIQUE_INSTRUCTIONS; 173 } 174} 175#endif 176 177#endif /* CONFIG_KDB_PROFILER */ 178