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