@@ -103,6 +103,21 @@ def generate_record_command(self, pid, output, frequency=None):
103103 cmd += ["--freq" , "{}" .format (frequency )]
104104 return cmd
105105
106+ def generate_report_command (self , input , dso = None ):
107+ cmd = [self .perf , "report" ]
108+ if dso is not None :
109+ cmd += ["--dso" , dso ]
110+ cmd += [
111+ "--header" ,
112+ "--no-children" ,
113+ "--stdio" ,
114+ "-g" ,
115+ "none,1.0,caller,function" ,
116+ "--input" ,
117+ input ,
118+ ]
119+ return cmd
120+
106121 def start_profile (self , pid , output , frequency = 99 ):
107122 """
108123 @param pid: profile events on specified process id
@@ -274,32 +289,78 @@ def generate_outputs(self, use_case, **kwargs):
274289 outputs ["Flame Graph" ] = flame_graph_output
275290 result &= artifact_result
276291
277- if self .pprof_bin is None :
278- logging .error (
279- "Unable to detect pprof. Some of the capabilities will be disabled"
280- )
281- else :
282- logging .info ("Generating pprof text output" )
283- pprof_text_output = self .output + ".pprof.txt"
284- artifact_result , pprof_artifact_text_output = run_pprof (
285- self .pprof_bin ,
286- PPROF_FORMAT_TEXT ,
287- pprof_text_output ,
288- binary ,
289- self .output ,
292+ # save perf output
293+ if artifact_result is True :
294+ outputs ["perf output" ] = os .path .abspath (self .output )
295+
296+ # generate perf report --stdio report
297+ logging .info ("Generating perf report text outputs" )
298+ perf_report_output = self .output + ".perf-report.top-cpu.txt"
299+
300+ artifact_result , perf_report_artifact = self .run_perf_report (
301+ perf_report_output , None
302+ )
303+
304+ if artifact_result is True :
305+ outputs ["perf report top self-cpu" ] = perf_report_artifact
306+ result &= artifact_result
307+
308+ # generate perf report --stdio report
309+ logging .info (
310+ "Generating perf report text outputs only for dso {}" .format (binary )
311+ )
312+ perf_report_output_dso = self .output + ".perf-report.top-cpu.dso.txt"
313+
314+ artifact_result , perf_report_artifact = self .run_perf_report (
315+ perf_report_output_dso , binary
316+ )
317+
318+ if artifact_result is True :
319+ outputs [
320+ "perf report top self-cpu (dso={})" .format (binary )
321+ ] = perf_report_artifact
322+ result &= artifact_result
323+
324+ if self .callgraph_mode == "dwarf" :
325+ logging .warning (
326+ "Unable to use perf output collected with callgraph dwarf mode in pprof. Skipping artifacts generation."
290327 )
291- result &= artifact_result
292-
293- if artifact_result is True :
294- outputs ["Top entries in text form" ] = pprof_artifact_text_output
295- logging .info ("Generating pprof png output" )
296- pprof_png_output = self .output + ".pprof.png"
297- artifact_result , pprof_artifact_png_output = run_pprof (
298- self .pprof_bin , PPROF_FORMAT_PNG , pprof_png_output , binary , self .output
328+ logging .warning (
329+ "Check https://github.com/google/perf_data_converter/issues/40."
299330 )
300- if artifact_result is True :
301- outputs ["Output graph image in PNG format" ] = pprof_artifact_png_output
302- result &= artifact_result
331+ else :
332+ if self .pprof_bin is None :
333+ logging .error (
334+ "Unable to detect pprof. Some of the capabilities will be disabled"
335+ )
336+ else :
337+ logging .info ("Generating pprof text output" )
338+ pprof_text_output = self .output + ".pprof.txt"
339+ artifact_result , pprof_artifact_text_output = run_pprof (
340+ self .pprof_bin ,
341+ PPROF_FORMAT_TEXT ,
342+ pprof_text_output ,
343+ binary ,
344+ self .output ,
345+ )
346+ result &= artifact_result
347+
348+ if artifact_result is True :
349+ outputs ["Top entries in text form" ] = pprof_artifact_text_output
350+ logging .info ("Generating pprof png output" )
351+ pprof_png_output = self .output + ".pprof.png"
352+ artifact_result , pprof_artifact_png_output = run_pprof (
353+ self .pprof_bin ,
354+ PPROF_FORMAT_PNG ,
355+ pprof_png_output ,
356+ binary ,
357+ self .output ,
358+ )
359+ if artifact_result is True :
360+ outputs [
361+ "Output graph image in PNG format"
362+ ] = pprof_artifact_png_output
363+ result &= artifact_result
303364
304365 return result , outputs
305366
@@ -344,3 +405,27 @@ def generate_flame_graph(self, title="Flame Graph", subtitle="", filename=None):
344405
345406 def get_collapsed_stacks (self ):
346407 return self .collapsed_stacks
408+
409+ def run_perf_report (
410+ self ,
411+ output ,
412+ dso ,
413+ ):
414+ status = False
415+ result_artifact = None
416+ args = self .generate_report_command (self .output , dso )
417+ logging .info ("Running {} report with args {}" .format (self .perf , args ))
418+ try :
419+ stdout , _ = subprocess .Popen (
420+ args = args , stdout = subprocess .PIPE
421+ ).communicate ()
422+ logging .debug (stdout )
423+ with open (output , "w" ) as outfile :
424+ outfile .write (stdout .decode ())
425+ status = True
426+ result_artifact = os .path .abspath (output )
427+ except OSError as e :
428+ logging .error (
429+ "Unable to run {} report. Error {}" .format (self .perf , e .__str__ ())
430+ )
431+ return status , result_artifact
0 commit comments