~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/perf/util/intel-tpebs.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /tools/perf/util/intel-tpebs.c (Version linux-6.12-rc7) and /tools/perf/util/intel-tpebs.c (Version linux-4.12.14)


  1 // SPDX-License-Identifier: GPL-2.0-only            1 
  2 /*                                                
  3  * intel_tpebs.c: Intel TPEBS support             
  4  */                                               
  5                                                   
  6                                                   
  7 #include <sys/param.h>                            
  8 #include <subcmd/run-command.h>                   
  9 #include <thread.h>                               
 10 #include "intel-tpebs.h"                          
 11 #include <linux/list.h>                           
 12 #include <linux/zalloc.h>                         
 13 #include <linux/err.h>                            
 14 #include "sample.h"                               
 15 #include "debug.h"                                
 16 #include "evlist.h"                               
 17 #include "evsel.h"                                
 18 #include "session.h"                              
 19 #include "tool.h"                                 
 20 #include "cpumap.h"                               
 21 #include "metricgroup.h"                          
 22 #include <sys/stat.h>                             
 23 #include <sys/file.h>                             
 24 #include <poll.h>                                 
 25 #include <math.h>                                 
 26                                                   
 27 #define PERF_DATA               "-"               
 28                                                   
 29 bool tpebs_recording;                             
 30 static pid_t tpebs_pid = -1;                      
 31 static size_t tpebs_event_size;                   
 32 static LIST_HEAD(tpebs_results);                  
 33 static pthread_t tpebs_reader_thread;             
 34 static struct child_process *tpebs_cmd;           
 35                                                   
 36 struct tpebs_retire_lat {                         
 37         struct list_head nd;                      
 38         /* Event name */                          
 39         const char *name;                         
 40         /* Event name with the TPEBS modifier     
 41         const char *tpebs_name;                   
 42         /* Count of retire_latency values foun    
 43         size_t count;                             
 44         /* Sum of all the retire_latency value    
 45         int sum;                                  
 46         /* Average of retire_latency, val = su    
 47         double val;                               
 48 };                                                
 49                                                   
 50 static int get_perf_record_args(const char **r    
 51                                 const char *cp    
 52 {                                                 
 53         struct tpebs_retire_lat *e;               
 54         int i = 0;                                
 55                                                   
 56         pr_debug("tpebs: Prepare perf record f    
 57                                                   
 58         record_argv[i++] = "perf";                
 59         record_argv[i++] = "record";              
 60         record_argv[i++] = "-W";                  
 61         record_argv[i++] = "--synth=no";          
 62         record_argv[i++] = buf;                   
 63                                                   
 64         if (!cpumap_buf) {                        
 65                 pr_err("tpebs: Require cpumap     
 66                 return -ECANCELED;                
 67         }                                         
 68         /* Use -C when cpumap_buf is not "-1"     
 69         if (strcmp(cpumap_buf, "-1")) {           
 70                 record_argv[i++] = "-C";          
 71                 record_argv[i++] = cpumap_buf;    
 72         }                                         
 73                                                   
 74         list_for_each_entry(e, &tpebs_results,    
 75                 record_argv[i++] = "-e";          
 76                 record_argv[i++] = e->name;       
 77         }                                         
 78                                                   
 79         record_argv[i++] = "-o";                  
 80         record_argv[i++] = PERF_DATA;             
 81                                                   
 82         return 0;                                 
 83 }                                                 
 84                                                   
 85 static int prepare_run_command(const char **ar    
 86 {                                                 
 87         tpebs_cmd = zalloc(sizeof(struct child    
 88         if (!tpebs_cmd)                           
 89                 return -ENOMEM;                   
 90         tpebs_cmd->argv = argv;                   
 91         tpebs_cmd->out = -1;                      
 92         return 0;                                 
 93 }                                                 
 94                                                   
 95 static int start_perf_record(int control_fd[],    
 96                                 const char *cp    
 97 {                                                 
 98         const char **record_argv;                 
 99         int ret;                                  
100         char buf[32];                             
101                                                   
102         scnprintf(buf, sizeof(buf), "--control    
103                                                   
104         record_argv = calloc(12 + 2 * tpebs_ev    
105         if (!record_argv)                         
106                 return -ENOMEM;                   
107                                                   
108         ret = get_perf_record_args(record_argv    
109         if (ret)                                  
110                 goto out;                         
111                                                   
112         ret = prepare_run_command(record_argv)    
113         if (ret)                                  
114                 goto out;                         
115         ret = start_command(tpebs_cmd);           
116 out:                                              
117         free(record_argv);                        
118         return ret;                               
119 }                                                 
120                                                   
121 static int process_sample_event(const struct p    
122                                 union perf_eve    
123                                 struct perf_sa    
124                                 struct evsel *    
125                                 struct machine    
126 {                                                 
127         int ret = 0;                              
128         const char *evname;                       
129         struct tpebs_retire_lat *t;               
130                                                   
131         evname = evsel__name(evsel);              
132                                                   
133         /*                                        
134          * Need to handle per core results? We    
135          * latency value will be used. Save th    
136          * retire latency value for each event    
137          */                                       
138         list_for_each_entry(t, &tpebs_results,    
139                 if (!strcmp(evname, t->name))     
140                         t->count += 1;            
141                         t->sum += sample->reti    
142                         t->val = (double) t->s    
143                         break;                    
144                 }                                 
145         }                                         
146                                                   
147         return ret;                               
148 }                                                 
149                                                   
150 static int process_feature_event(struct perf_s    
151                                  union perf_ev    
152 {                                                 
153         if (event->feat.feat_id < HEADER_LAST_    
154                 return perf_event__process_fea    
155         return 0;                                 
156 }                                                 
157                                                   
158 static void *__sample_reader(void *arg)           
159 {                                                 
160         struct child_process *child = arg;        
161         struct perf_session *session;             
162         struct perf_data data = {                 
163                 .mode = PERF_DATA_MODE_READ,      
164                 .path = PERF_DATA,                
165                 .file.fd = child->out,            
166         };                                        
167         struct perf_tool tool;                    
168                                                   
169         perf_tool__init(&tool, /*ordered_event    
170         tool.sample = process_sample_event;       
171         tool.feature = process_feature_event;     
172         tool.attr = perf_event__process_attr;     
173                                                   
174         session = perf_session__new(&data, &to    
175         if (IS_ERR(session))                      
176                 return NULL;                      
177         perf_session__process_events(session);    
178         perf_session__delete(session);            
179                                                   
180         return NULL;                              
181 }                                                 
182                                                   
183 /*                                                
184  * tpebs_stop - stop the sample data read thre    
185  */                                               
186 static int tpebs_stop(void)                       
187 {                                                 
188         int ret = 0;                              
189                                                   
190         /* Like tpebs_start, we should only ru    
191         if (tpebs_pid != -1) {                    
192                 kill(tpebs_cmd->pid, SIGTERM);    
193                 tpebs_pid = -1;                   
194                 pthread_join(tpebs_reader_thre    
195                 close(tpebs_cmd->out);            
196                 ret = finish_command(tpebs_cmd    
197                 if (ret == -ERR_RUN_COMMAND_WA    
198                         ret = 0;                  
199         }                                         
200         return ret;                               
201 }                                                 
202                                                   
203 /*                                                
204  * tpebs_start - start tpebs execution.           
205  * @evsel_list: retire_latency evsels in this     
206  * to get the average retire_latency value.       
207  *                                                
208  * This function will be called from evlist le    
209  * called consistently.                           
210  */                                               
211 int tpebs_start(struct evlist *evsel_list)        
212 {                                                 
213         int ret = 0;                              
214         struct evsel *evsel;                      
215         char cpumap_buf[50];                      
216                                                   
217         /*                                        
218          * We should only run tpebs_start when    
219          * And we should only run it once with    
220          */                                       
221         if (tpebs_pid != -1 || !tpebs_recordin    
222                 return 0;                         
223                                                   
224         cpu_map__snprint(evsel_list->core.user    
225         /*                                        
226          * Prepare perf record for sampling ev    
227          * prepare workload                       
228          */                                       
229         evlist__for_each_entry(evsel_list, evs    
230                 int i;                            
231                 char *name;                       
232                 struct tpebs_retire_lat *new;     
233                                                   
234                 if (!evsel->retire_lat)           
235                         continue;                 
236                                                   
237                 pr_debug("tpebs: Retire_latenc    
238                 for (i = strlen(evsel->name) -    
239                         if (evsel->name[i] ==     
240                                 break;            
241                 }                                 
242                 if (i <= 0 || evsel->name[i] !    
243                         ret = -1;                 
244                         goto err;                 
245                 }                                 
246                                                   
247                 name = strdup(evsel->name);       
248                 if (!name) {                      
249                         ret = -ENOMEM;            
250                         goto err;                 
251                 }                                 
252                 name[i] = 'p';                    
253                                                   
254                 new = zalloc(sizeof(*new));       
255                 if (!new) {                       
256                         ret = -1;                 
257                         zfree(name);              
258                         goto err;                 
259                 }                                 
260                 new->name = name;                 
261                 new->tpebs_name = evsel->name;    
262                 list_add_tail(&new->nd, &tpebs    
263                 tpebs_event_size += 1;            
264         }                                         
265                                                   
266         if (tpebs_event_size > 0) {               
267                 struct pollfd pollfd = { .even    
268                 int control_fd[2], ack_fd[2],     
269                 char ack_buf[8];                  
270                                                   
271                 /*Create control and ack fd fo    
272                 if (pipe(control_fd) < 0) {       
273                         pr_err("tpebs: Failed     
274                         ret = -1;                 
275                         goto out;                 
276                 }                                 
277                 if (pipe(ack_fd) < 0) {           
278                         pr_err("tpebs: Failed     
279                         ret = -1;                 
280                         goto out;                 
281                 }                                 
282                                                   
283                 ret = start_perf_record(contro    
284                 if (ret)                          
285                         goto out;                 
286                 tpebs_pid = tpebs_cmd->pid;       
287                 if (pthread_create(&tpebs_read    
288                         kill(tpebs_cmd->pid, S    
289                         close(tpebs_cmd->out);    
290                         pr_err("Could not crea    
291                         ret = -1;                 
292                         goto out;                 
293                 }                                 
294                 /* Wait for perf record initia    
295                 len = strlen(EVLIST_CTL_CMD_EN    
296                 ret = write(control_fd[1], EVL    
297                 if (ret != len) {                 
298                         pr_err("perf record co    
299                         goto out;                 
300                 }                                 
301                                                   
302                 /* wait for an ack */             
303                 pollfd.fd = ack_fd[0];            
304                                                   
305                 /*                                
306                  * We need this poll to ensure    
307                  * when perf record failed for    
308                  * 3000ms is an empirical sele    
309                  */                               
310                 if (!poll(&pollfd, 1, 3000)) {    
311                         pr_err("tpebs failed:     
312                         ret = -1;                 
313                         goto out;                 
314                 }                                 
315                                                   
316                 if (!(pollfd.revents & POLLIN)    
317                         pr_err("tpebs failed:     
318                         ret = -1;                 
319                         goto out;                 
320                 }                                 
321                                                   
322                 ret = read(ack_fd[0], ack_buf,    
323                 if (ret > 0)                      
324                         ret = strcmp(ack_buf,     
325                 else {                            
326                         pr_err("tpebs: perf re    
327                         goto out;                 
328                 }                                 
329 out:                                              
330                 close(control_fd[0]);             
331                 close(control_fd[1]);             
332                 close(ack_fd[0]);                 
333                 close(ack_fd[1]);                 
334         }                                         
335 err:                                              
336         if (ret)                                  
337                 tpebs_delete();                   
338         return ret;                               
339 }                                                 
340                                                   
341                                                   
342 int tpebs_set_evsel(struct evsel *evsel, int c    
343 {                                                 
344         __u64 val;                                
345         bool found = false;                       
346         struct tpebs_retire_lat *t;               
347         struct perf_counts_values *count;         
348                                                   
349         /* Non reitre_latency evsel should nev    
350         if (!evsel__is_retire_lat(evsel))         
351                 return -1;                        
352                                                   
353         /*                                        
354          * Need to stop the forked record to e    
355          * PIPE to process and get non-zero re    
356          */                                       
357         tpebs_stop();                             
358         count = perf_counts(evsel->counts, cpu    
359                                                   
360         list_for_each_entry(t, &tpebs_results,    
361                 if (t->tpebs_name == evsel->na    
362                     (evsel->metric_id && !strc    
363                         found = true;             
364                         break;                    
365                 }                                 
366         }                                         
367                                                   
368         /* Set ena and run to non-zero */         
369         count->ena = count->run = 1;              
370         count->lost = 0;                          
371                                                   
372         if (!found) {                             
373                 /*                                
374                  * Set default value or 0 when    
375                  * not found from sampling dat    
376                  * sample recorded).              
377                  */                               
378                 count->val = 0;                   
379                 return 0;                         
380         }                                         
381                                                   
382         /*                                        
383          * Only set retire_latency value to th    
384          */                                       
385         if (cpu_map_idx == 0 && thread == 0)      
386                 val = rint(t->val);               
387         else                                      
388                 val = 0;                          
389                                                   
390         count->val = val;                         
391         return 0;                                 
392 }                                                 
393                                                   
394 static void tpebs_retire_lat__delete(struct tp    
395 {                                                 
396         zfree(&r->name);                          
397         free(r);                                  
398 }                                                 
399                                                   
400                                                   
401 /*                                                
402  * tpebs_delete - delete tpebs related data an    
403  * process by calling tpebs_stop().               
404  *                                                
405  * This function is called from evlist_delete(    
406  * stat_handle_error(). If tpebs_start() is ca    
407  * stat, need to ensure tpebs_delete() is also    
408  * close the data read thread and the forked p    
409  *                                                
410  * This function is also called in evsel__clos    
411  * tpebs_start() being called in evsel__open()    
412  * when move tpebs_start() to evlist level.       
413  */                                               
414 void tpebs_delete(void)                           
415 {                                                 
416         struct tpebs_retire_lat *r, *rtmp;        
417                                                   
418         if (tpebs_pid == -1)                      
419                 return;                           
420                                                   
421         tpebs_stop();                             
422                                                   
423         list_for_each_entry_safe(r, rtmp, &tpe    
424                 list_del_init(&r->nd);            
425                 tpebs_retire_lat__delete(r);      
426         }                                         
427                                                   
428         if (tpebs_cmd) {                          
429                 free(tpebs_cmd);                  
430                 tpebs_cmd = NULL;                 
431         }                                         
432 }                                                 
433                                                   

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php