1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/kernel.h> 3 #include "cache.h" 4 #include "config.h" 5 #include <stdlib.h> 6 #include <stdio.h> 7 #include "color.h" 8 #include <math.h> 9 #include <unistd.h> 10 11 int perf_use_color_default = -1; 12 13 int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty) 14 { 15 if (value) { 16 if (!strcasecmp(value, "never")) 17 return 0; 18 if (!strcasecmp(value, "always")) 19 return 1; 20 if (!strcasecmp(value, "auto")) 21 goto auto_color; 22 } 23 24 /* Missing or explicit false to turn off colorization */ 25 if (!perf_config_bool(var, value)) 26 return 0; 27 28 /* any normal truth value defaults to 'auto' */ 29 auto_color: 30 if (stdout_is_tty < 0) 31 stdout_is_tty = isatty(1); 32 if (stdout_is_tty || pager_in_use()) { 33 char *term = getenv("TERM"); 34 if (term && strcmp(term, "dumb")) 35 return 1; 36 } 37 return 0; 38 } 39 40 int perf_color_default_config(const char *var, const char *value, 41 void *cb __maybe_unused) 42 { 43 if (!strcmp(var, "color.ui")) { 44 perf_use_color_default = perf_config_colorbool(var, value, -1); 45 return 0; 46 } 47 48 return 0; 49 } 50 51 static int __color_vsnprintf(char *bf, size_t size, const char *color, 52 const char *fmt, va_list args, const char *trail) 53 { 54 int r = 0; 55 56 /* 57 * Auto-detect: 58 */ 59 if (perf_use_color_default < 0) { 60 if (isatty(1) || pager_in_use()) 61 perf_use_color_default = 1; 62 else 63 perf_use_color_default = 0; 64 } 65 66 if (perf_use_color_default && *color) 67 r += scnprintf(bf, size, "%s", color); 68 r += vscnprintf(bf + r, size - r, fmt, args); 69 if (perf_use_color_default && *color) 70 r += scnprintf(bf + r, size - r, "%s", PERF_COLOR_RESET); 71 if (trail) 72 r += scnprintf(bf + r, size - r, "%s", trail); 73 return r; 74 } 75 76 /* Colors are not included in return value */ 77 static int __color_vfprintf(FILE *fp, const char *color, const char *fmt, 78 va_list args) 79 { 80 int r = 0; 81 82 /* 83 * Auto-detect: 84 */ 85 if (perf_use_color_default < 0) { 86 if (isatty(fileno(fp)) || pager_in_use()) 87 perf_use_color_default = 1; 88 else 89 perf_use_color_default = 0; 90 } 91 92 if (perf_use_color_default && *color) 93 fprintf(fp, "%s", color); 94 r += vfprintf(fp, fmt, args); 95 if (perf_use_color_default && *color) 96 fprintf(fp, "%s", PERF_COLOR_RESET); 97 return r; 98 } 99 100 int color_vsnprintf(char *bf, size_t size, const char *color, 101 const char *fmt, va_list args) 102 { 103 return __color_vsnprintf(bf, size, color, fmt, args, NULL); 104 } 105 106 int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args) 107 { 108 return __color_vfprintf(fp, color, fmt, args); 109 } 110 111 int color_snprintf(char *bf, size_t size, const char *color, 112 const char *fmt, ...) 113 { 114 va_list args; 115 int r; 116 117 va_start(args, fmt); 118 r = color_vsnprintf(bf, size, color, fmt, args); 119 va_end(args); 120 return r; 121 } 122 123 int color_fprintf(FILE *fp, const char *color, const char *fmt, ...) 124 { 125 va_list args; 126 int r; 127 128 va_start(args, fmt); 129 r = color_vfprintf(fp, color, fmt, args); 130 va_end(args); 131 return r; 132 } 133 134 /* 135 * This function splits the buffer by newlines and colors the lines individually. 136 * 137 * Returns 0 on success. 138 */ 139 int color_fwrite_lines(FILE *fp, const char *color, 140 size_t count, const char *buf) 141 { 142 if (!*color) 143 return fwrite(buf, count, 1, fp) != 1; 144 145 while (count) { 146 char *p = memchr(buf, '\n', count); 147 148 if (p != buf && (fputs(color, fp) < 0 || 149 fwrite(buf, p ? (size_t)(p - buf) : count, 1, fp) != 1 || 150 fputs(PERF_COLOR_RESET, fp) < 0)) 151 return -1; 152 if (!p) 153 return 0; 154 if (fputc('\n', fp) < 0) 155 return -1; 156 count -= p + 1 - buf; 157 buf = p + 1; 158 } 159 return 0; 160 } 161 162 const char *get_percent_color(double percent) 163 { 164 const char *color = PERF_COLOR_NORMAL; 165 166 /* 167 * We color high-overhead entries in red, mid-overhead 168 * entries in green - and keep the low overhead places 169 * normal: 170 */ 171 if (fabs(percent) >= MIN_RED) 172 color = PERF_COLOR_RED; 173 else { 174 if (fabs(percent) > MIN_GREEN) 175 color = PERF_COLOR_GREEN; 176 } 177 return color; 178 } 179 180 int percent_color_fprintf(FILE *fp, const char *fmt, double percent) 181 { 182 int r; 183 const char *color; 184 185 color = get_percent_color(percent); 186 r = color_fprintf(fp, color, fmt, percent); 187 188 return r; 189 } 190 191 int value_color_snprintf(char *bf, size_t size, const char *fmt, double value) 192 { 193 const char *color = get_percent_color(value); 194 return color_snprintf(bf, size, color, fmt, value); 195 } 196 197 int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...) 198 { 199 va_list args; 200 double percent; 201 202 va_start(args, fmt); 203 percent = va_arg(args, double); 204 va_end(args); 205 return value_color_snprintf(bf, size, fmt, percent); 206 } 207 208 int percent_color_len_snprintf(char *bf, size_t size, const char *fmt, ...) 209 { 210 va_list args; 211 int len; 212 double percent; 213 const char *color; 214 215 va_start(args, fmt); 216 len = va_arg(args, int); 217 percent = va_arg(args, double); 218 va_end(args); 219 220 color = get_percent_color(percent); 221 return color_snprintf(bf, size, color, fmt, len, percent); 222 } 223