You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					371 lines
				
				14 KiB
			
		
		
			
		
	
	
					371 lines
				
				14 KiB
			| 
								 
											6 years ago
										 
									 | 
							
								#!/usr/bin/env python3
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# Copyright (C) 2016 The Android Open Source Project
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# Licensed under the Apache License, Version 2.0 (the "License");
							 | 
						||
| 
								 | 
							
								# you may not use this file except in compliance with the License.
							 | 
						||
| 
								 | 
							
								# You may obtain a copy of the License at
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								#      http://www.apache.org/licenses/LICENSE-2.0
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# Unless required by applicable law or agreed to in writing, software
							 | 
						||
| 
								 | 
							
								# distributed under the License is distributed on an "AS IS" BASIS,
							 | 
						||
| 
								 | 
							
								# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
							 | 
						||
| 
								 | 
							
								# See the License for the specific language governing permissions and
							 | 
						||
| 
								 | 
							
								# limitations under the License.
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								"""simpleperf_report_lib.py: a python wrapper of libsimpleperf_report.so.
							 | 
						||
| 
								 | 
							
								   Used to access samples in perf.data.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								"""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import ctypes as ct
							 | 
						||
| 
								 | 
							
								import os
							 | 
						||
| 
								 | 
							
								import subprocess
							 | 
						||
| 
								 | 
							
								import sys
							 | 
						||
| 
								 | 
							
								import unittest
							 | 
						||
| 
								 | 
							
								from utils import *
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _get_native_lib():
							 | 
						||
| 
								 | 
							
								    return get_host_binary_path('libsimpleperf_report.so')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _is_null(p):
							 | 
						||
| 
								 | 
							
								    if p:
							 | 
						||
| 
								 | 
							
								        return False
							 | 
						||
| 
								 | 
							
								    return ct.cast(p, ct.c_void_p).value is None
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _char_pt(s):
							 | 
						||
| 
								 | 
							
								    return str_to_bytes(s)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _char_pt_to_str(char_pt):
							 | 
						||
| 
								 | 
							
								    return bytes_to_str(char_pt)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class SampleStruct(ct.Structure):
							 | 
						||
| 
								 | 
							
								    """ Instance of a sample in perf.data.
							 | 
						||
| 
								 | 
							
								        ip: the program counter of the thread generating the sample.
							 | 
						||
| 
								 | 
							
								        pid: process id (or thread group id) of the thread generating the sample.
							 | 
						||
| 
								 | 
							
								        tid: thread id.
							 | 
						||
| 
								 | 
							
								        thread_comm: thread name.
							 | 
						||
| 
								 | 
							
								        time: time at which the sample was generated. The value is in nanoseconds.
							 | 
						||
| 
								 | 
							
								              The clock is decided by the --clockid option in `simpleperf record`.
							 | 
						||
| 
								 | 
							
								        in_kernel: whether the instruction is in kernel space or user space.
							 | 
						||
| 
								 | 
							
								        cpu: the cpu generating the sample.
							 | 
						||
| 
								 | 
							
								        period: count of events have happened since last sample. For example, if we use
							 | 
						||
| 
								 | 
							
								             -e cpu-cycles, it means how many cpu-cycles have happened.
							 | 
						||
| 
								 | 
							
								             If we use -e cpu-clock, it means how many nanoseconds have passed.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    _fields_ = [('ip', ct.c_uint64),
							 | 
						||
| 
								 | 
							
								                ('pid', ct.c_uint32),
							 | 
						||
| 
								 | 
							
								                ('tid', ct.c_uint32),
							 | 
						||
| 
								 | 
							
								                ('thread_comm', ct.c_char_p),
							 | 
						||
| 
								 | 
							
								                ('time', ct.c_uint64),
							 | 
						||
| 
								 | 
							
								                ('in_kernel', ct.c_uint32),
							 | 
						||
| 
								 | 
							
								                ('cpu', ct.c_uint32),
							 | 
						||
| 
								 | 
							
								                ('period', ct.c_uint64)]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class EventStruct(ct.Structure):
							 | 
						||
| 
								 | 
							
								    """ Name of the event. """
							 | 
						||
| 
								 | 
							
								    _fields_ = [('name', ct.c_char_p)]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class MappingStruct(ct.Structure):
							 | 
						||
| 
								 | 
							
								    """ A mapping area in the monitored threads, like the content in /proc/<pid>/maps.
							 | 
						||
| 
								 | 
							
								        start: start addr in memory.
							 | 
						||
| 
								 | 
							
								        end: end addr in memory.
							 | 
						||
| 
								 | 
							
								        pgoff: offset in the mapped shared library.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    _fields_ = [('start', ct.c_uint64),
							 | 
						||
| 
								 | 
							
								                ('end', ct.c_uint64),
							 | 
						||
| 
								 | 
							
								                ('pgoff', ct.c_uint64)]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class SymbolStruct(ct.Structure):
							 | 
						||
| 
								 | 
							
								    """ Symbol info of the instruction hit by a sample or a callchain entry of a sample.
							 | 
						||
| 
								 | 
							
								        dso_name: path of the shared library containing the instruction.
							 | 
						||
| 
								 | 
							
								        vaddr_in_file: virtual address of the instruction in the shared library.
							 | 
						||
| 
								 | 
							
								        symbol_name: name of the function containing the instruction.
							 | 
						||
| 
								 | 
							
								        symbol_addr: start addr of the function containing the instruction.
							 | 
						||
| 
								 | 
							
								        symbol_len: length of the function in the shared library.
							 | 
						||
| 
								 | 
							
								        mapping: the mapping area hit by the instruction.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    _fields_ = [('dso_name', ct.c_char_p),
							 | 
						||
| 
								 | 
							
								                ('vaddr_in_file', ct.c_uint64),
							 | 
						||
| 
								 | 
							
								                ('symbol_name', ct.c_char_p),
							 | 
						||
| 
								 | 
							
								                ('symbol_addr', ct.c_uint64),
							 | 
						||
| 
								 | 
							
								                ('symbol_len', ct.c_uint64),
							 | 
						||
| 
								 | 
							
								                ('mapping', ct.POINTER(MappingStruct))]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class CallChainEntryStructure(ct.Structure):
							 | 
						||
| 
								 | 
							
								    """ A callchain entry of a sample.
							 | 
						||
| 
								 | 
							
								        ip: the address of the instruction of the callchain entry.
							 | 
						||
| 
								 | 
							
								        symbol: symbol info of the callchain entry.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    _fields_ = [('ip', ct.c_uint64),
							 | 
						||
| 
								 | 
							
								                ('symbol', SymbolStruct)]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class CallChainStructure(ct.Structure):
							 | 
						||
| 
								 | 
							
								    """ Callchain info of a sample.
							 | 
						||
| 
								 | 
							
								        nr: number of entries in the callchain.
							 | 
						||
| 
								 | 
							
								        entries: a pointer to an array of CallChainEntryStructure.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        For example, if a sample is generated when a thread is running function C
							 | 
						||
| 
								 | 
							
								        with callchain function A -> function B -> function C.
							 | 
						||
| 
								 | 
							
								        Then nr = 2, and entries = [function B, function A].
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    _fields_ = [('nr', ct.c_uint32),
							 | 
						||
| 
								 | 
							
								                ('entries', ct.POINTER(CallChainEntryStructure))]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class FeatureSectionStructure(ct.Structure):
							 | 
						||
| 
								 | 
							
								    """ A feature section in perf.data to store information like record cmd, device arch, etc.
							 | 
						||
| 
								 | 
							
								        data: a pointer to a buffer storing the section data.
							 | 
						||
| 
								 | 
							
								        data_size: data size in bytes.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    _fields_ = [('data', ct.POINTER(ct.c_char)),
							 | 
						||
| 
								 | 
							
								                ('data_size', ct.c_uint32)]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# convert char_p to str for python3.
							 | 
						||
| 
								 | 
							
								class SampleStructUsingStr(object):
							 | 
						||
| 
								 | 
							
								    def __init__(self, sample):
							 | 
						||
| 
								 | 
							
								        self.ip = sample.ip
							 | 
						||
| 
								 | 
							
								        self.pid = sample.pid
							 | 
						||
| 
								 | 
							
								        self.tid = sample.tid
							 | 
						||
| 
								 | 
							
								        self.thread_comm = _char_pt_to_str(sample.thread_comm)
							 | 
						||
| 
								 | 
							
								        self.time = sample.time
							 | 
						||
| 
								 | 
							
								        self.in_kernel = sample.in_kernel
							 | 
						||
| 
								 | 
							
								        self.cpu = sample.cpu
							 | 
						||
| 
								 | 
							
								        self.period = sample.period
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class EventStructUsingStr(object):
							 | 
						||
| 
								 | 
							
								    def __init__(self, event):
							 | 
						||
| 
								 | 
							
								        self.name = _char_pt_to_str(event.name)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class SymbolStructUsingStr(object):
							 | 
						||
| 
								 | 
							
								    def __init__(self, symbol):
							 | 
						||
| 
								 | 
							
								        self.dso_name = _char_pt_to_str(symbol.dso_name)
							 | 
						||
| 
								 | 
							
								        self.vaddr_in_file = symbol.vaddr_in_file
							 | 
						||
| 
								 | 
							
								        self.symbol_name = _char_pt_to_str(symbol.symbol_name)
							 | 
						||
| 
								 | 
							
								        self.symbol_addr = symbol.symbol_addr
							 | 
						||
| 
								 | 
							
								        self.mapping = symbol.mapping
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class CallChainEntryStructureUsingStr(object):
							 | 
						||
| 
								 | 
							
								    def __init__(self, entry):
							 | 
						||
| 
								 | 
							
								        self.ip = entry.ip
							 | 
						||
| 
								 | 
							
								        self.symbol = SymbolStructUsingStr(entry.symbol)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class CallChainStructureUsingStr(object):
							 | 
						||
| 
								 | 
							
								    def __init__(self, callchain):
							 | 
						||
| 
								 | 
							
								        self.nr = callchain.nr
							 | 
						||
| 
								 | 
							
								        self.entries = []
							 | 
						||
| 
								 | 
							
								        for i in range(self.nr):
							 | 
						||
| 
								 | 
							
								            self.entries.append(CallChainEntryStructureUsingStr(callchain.entries[i]))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class ReportLibStructure(ct.Structure):
							 | 
						||
| 
								 | 
							
								    _fields_ = []
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class ReportLib(object):
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __init__(self, native_lib_path=None):
							 | 
						||
| 
								 | 
							
								        if native_lib_path is None:
							 | 
						||
| 
								 | 
							
								            native_lib_path = _get_native_lib()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        self._load_dependent_lib()
							 | 
						||
| 
								 | 
							
								        self._lib = ct.CDLL(native_lib_path)
							 | 
						||
| 
								 | 
							
								        self._CreateReportLibFunc = self._lib.CreateReportLib
							 | 
						||
| 
								 | 
							
								        self._CreateReportLibFunc.restype = ct.POINTER(ReportLibStructure)
							 | 
						||
| 
								 | 
							
								        self._DestroyReportLibFunc = self._lib.DestroyReportLib
							 | 
						||
| 
								 | 
							
								        self._SetLogSeverityFunc = self._lib.SetLogSeverity
							 | 
						||
| 
								 | 
							
								        self._SetSymfsFunc = self._lib.SetSymfs
							 | 
						||
| 
								 | 
							
								        self._SetRecordFileFunc = self._lib.SetRecordFile
							 | 
						||
| 
								 | 
							
								        self._SetKallsymsFileFunc = self._lib.SetKallsymsFile
							 | 
						||
| 
								 | 
							
								        self._ShowIpForUnknownSymbolFunc = self._lib.ShowIpForUnknownSymbol
							 | 
						||
| 
								 | 
							
								        self._ShowArtFramesFunc = self._lib.ShowArtFrames
							 | 
						||
| 
								 | 
							
								        self._GetNextSampleFunc = self._lib.GetNextSample
							 | 
						||
| 
								 | 
							
								        self._GetNextSampleFunc.restype = ct.POINTER(SampleStruct)
							 | 
						||
| 
								 | 
							
								        self._GetEventOfCurrentSampleFunc = self._lib.GetEventOfCurrentSample
							 | 
						||
| 
								 | 
							
								        self._GetEventOfCurrentSampleFunc.restype = ct.POINTER(EventStruct)
							 | 
						||
| 
								 | 
							
								        self._GetSymbolOfCurrentSampleFunc = self._lib.GetSymbolOfCurrentSample
							 | 
						||
| 
								 | 
							
								        self._GetSymbolOfCurrentSampleFunc.restype = ct.POINTER(SymbolStruct)
							 | 
						||
| 
								 | 
							
								        self._GetCallChainOfCurrentSampleFunc = self._lib.GetCallChainOfCurrentSample
							 | 
						||
| 
								 | 
							
								        self._GetCallChainOfCurrentSampleFunc.restype = ct.POINTER(
							 | 
						||
| 
								 | 
							
								            CallChainStructure)
							 | 
						||
| 
								 | 
							
								        self._GetBuildIdForPathFunc = self._lib.GetBuildIdForPath
							 | 
						||
| 
								 | 
							
								        self._GetBuildIdForPathFunc.restype = ct.c_char_p
							 | 
						||
| 
								 | 
							
								        self._GetFeatureSection = self._lib.GetFeatureSection
							 | 
						||
| 
								 | 
							
								        self._GetFeatureSection.restype = ct.POINTER(FeatureSectionStructure)
							 | 
						||
| 
								 | 
							
								        self._instance = self._CreateReportLibFunc()
							 | 
						||
| 
								 | 
							
								        assert not _is_null(self._instance)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        self.convert_to_str = (sys.version_info >= (3, 0))
							 | 
						||
| 
								 | 
							
								        self.meta_info = None
							 | 
						||
| 
								 | 
							
								        self.current_sample = None
							 | 
						||
| 
								 | 
							
								        self.record_cmd = None
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _load_dependent_lib(self):
							 | 
						||
| 
								 | 
							
								        # As the windows dll is built with mingw we need to load 'libwinpthread-1.dll'.
							 | 
						||
| 
								 | 
							
								        if is_windows():
							 | 
						||
| 
								 | 
							
								            self._libwinpthread = ct.CDLL(get_host_binary_path('libwinpthread-1.dll'))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def Close(self):
							 | 
						||
| 
								 | 
							
								        if self._instance is None:
							 | 
						||
| 
								 | 
							
								            return
							 | 
						||
| 
								 | 
							
								        self._DestroyReportLibFunc(self._instance)
							 | 
						||
| 
								 | 
							
								        self._instance = None
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def SetLogSeverity(self, log_level='info'):
							 | 
						||
| 
								 | 
							
								        """ Set log severity of native lib, can be verbose,debug,info,error,fatal."""
							 | 
						||
| 
								 | 
							
								        cond = self._SetLogSeverityFunc(self.getInstance(), _char_pt(log_level))
							 | 
						||
| 
								 | 
							
								        self._check(cond, 'Failed to set log level')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def SetSymfs(self, symfs_dir):
							 | 
						||
| 
								 | 
							
								        """ Set directory used to find symbols."""
							 | 
						||
| 
								 | 
							
								        cond = self._SetSymfsFunc(self.getInstance(), _char_pt(symfs_dir))
							 | 
						||
| 
								 | 
							
								        self._check(cond, 'Failed to set symbols directory')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def SetRecordFile(self, record_file):
							 | 
						||
| 
								 | 
							
								        """ Set the path of record file, like perf.data."""
							 | 
						||
| 
								 | 
							
								        cond = self._SetRecordFileFunc(self.getInstance(), _char_pt(record_file))
							 | 
						||
| 
								 | 
							
								        self._check(cond, 'Failed to set record file')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def ShowIpForUnknownSymbol(self):
							 | 
						||
| 
								 | 
							
								        self._ShowIpForUnknownSymbolFunc(self.getInstance())
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def ShowArtFrames(self, show=True):
							 | 
						||
| 
								 | 
							
								        """ Show frames of internal methods of the Java interpreter. """
							 | 
						||
| 
								 | 
							
								        self._ShowArtFramesFunc(self.getInstance(), show)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def SetKallsymsFile(self, kallsym_file):
							 | 
						||
| 
								 | 
							
								        """ Set the file path to a copy of the /proc/kallsyms file (for off device decoding) """
							 | 
						||
| 
								 | 
							
								        cond = self._SetKallsymsFileFunc(self.getInstance(), _char_pt(kallsym_file))
							 | 
						||
| 
								 | 
							
								        self._check(cond, 'Failed to set kallsyms file')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def GetNextSample(self):
							 | 
						||
| 
								 | 
							
								        psample = self._GetNextSampleFunc(self.getInstance())
							 | 
						||
| 
								 | 
							
								        if _is_null(psample):
							 | 
						||
| 
								 | 
							
								            self.current_sample = None
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            sample = psample[0]
							 | 
						||
| 
								 | 
							
								            self.current_sample = SampleStructUsingStr(sample) if self.convert_to_str else sample
							 | 
						||
| 
								 | 
							
								        return self.current_sample
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def GetCurrentSample(self):
							 | 
						||
| 
								 | 
							
								        return self.current_sample
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def GetEventOfCurrentSample(self):
							 | 
						||
| 
								 | 
							
								        event = self._GetEventOfCurrentSampleFunc(self.getInstance())
							 | 
						||
| 
								 | 
							
								        assert not _is_null(event)
							 | 
						||
| 
								 | 
							
								        if self.convert_to_str:
							 | 
						||
| 
								 | 
							
								            return EventStructUsingStr(event[0])
							 | 
						||
| 
								 | 
							
								        return event[0]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def GetSymbolOfCurrentSample(self):
							 | 
						||
| 
								 | 
							
								        symbol = self._GetSymbolOfCurrentSampleFunc(self.getInstance())
							 | 
						||
| 
								 | 
							
								        assert not _is_null(symbol)
							 | 
						||
| 
								 | 
							
								        if self.convert_to_str:
							 | 
						||
| 
								 | 
							
								            return SymbolStructUsingStr(symbol[0])
							 | 
						||
| 
								 | 
							
								        return symbol[0]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def GetCallChainOfCurrentSample(self):
							 | 
						||
| 
								 | 
							
								        callchain = self._GetCallChainOfCurrentSampleFunc(self.getInstance())
							 | 
						||
| 
								 | 
							
								        assert not _is_null(callchain)
							 | 
						||
| 
								 | 
							
								        if self.convert_to_str:
							 | 
						||
| 
								 | 
							
								            return CallChainStructureUsingStr(callchain[0])
							 | 
						||
| 
								 | 
							
								        return callchain[0]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def GetBuildIdForPath(self, path):
							 | 
						||
| 
								 | 
							
								        build_id = self._GetBuildIdForPathFunc(self.getInstance(), _char_pt(path))
							 | 
						||
| 
								 | 
							
								        assert not _is_null(build_id)
							 | 
						||
| 
								 | 
							
								        return _char_pt_to_str(build_id)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def GetRecordCmd(self):
							 | 
						||
| 
								 | 
							
								        if self.record_cmd is not None:
							 | 
						||
| 
								 | 
							
								            return self.record_cmd
							 | 
						||
| 
								 | 
							
								        self.record_cmd = ''
							 | 
						||
| 
								 | 
							
								        feature_data = self._GetFeatureSection(self.getInstance(), _char_pt('cmdline'))
							 | 
						||
| 
								 | 
							
								        if not _is_null(feature_data):
							 | 
						||
| 
								 | 
							
								            void_p = ct.cast(feature_data[0].data, ct.c_void_p)
							 | 
						||
| 
								 | 
							
								            arg_count = ct.cast(void_p, ct.POINTER(ct.c_uint32)).contents.value
							 | 
						||
| 
								 | 
							
								            void_p.value += 4
							 | 
						||
| 
								 | 
							
								            args = []
							 | 
						||
| 
								 | 
							
								            for _ in range(arg_count):
							 | 
						||
| 
								 | 
							
								                str_len = ct.cast(void_p, ct.POINTER(ct.c_uint32)).contents.value
							 | 
						||
| 
								 | 
							
								                void_p.value += 4
							 | 
						||
| 
								 | 
							
								                char_p = ct.cast(void_p, ct.POINTER(ct.c_char))
							 | 
						||
| 
								 | 
							
								                current_str = ''
							 | 
						||
| 
								 | 
							
								                for j in range(str_len):
							 | 
						||
| 
								 | 
							
								                    c = bytes_to_str(char_p[j])
							 | 
						||
| 
								 | 
							
								                    if c != '\0':
							 | 
						||
| 
								 | 
							
								                        current_str += c
							 | 
						||
| 
								 | 
							
								                if ' ' in current_str:
							 | 
						||
| 
								 | 
							
								                    current_str = '"' + current_str + '"'
							 | 
						||
| 
								 | 
							
								                args.append(current_str)
							 | 
						||
| 
								 | 
							
								                void_p.value += str_len
							 | 
						||
| 
								 | 
							
								            self.record_cmd = ' '.join(args)
							 | 
						||
| 
								 | 
							
								        return self.record_cmd
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _GetFeatureString(self, feature_name):
							 | 
						||
| 
								 | 
							
								        feature_data = self._GetFeatureSection(self.getInstance(), _char_pt(feature_name))
							 | 
						||
| 
								 | 
							
								        result = ''
							 | 
						||
| 
								 | 
							
								        if not _is_null(feature_data):
							 | 
						||
| 
								 | 
							
								            void_p = ct.cast(feature_data[0].data, ct.c_void_p)
							 | 
						||
| 
								 | 
							
								            str_len = ct.cast(void_p, ct.POINTER(ct.c_uint32)).contents.value
							 | 
						||
| 
								 | 
							
								            void_p.value += 4
							 | 
						||
| 
								 | 
							
								            char_p = ct.cast(void_p, ct.POINTER(ct.c_char))
							 | 
						||
| 
								 | 
							
								            for i in range(str_len):
							 | 
						||
| 
								 | 
							
								                c = bytes_to_str(char_p[i])
							 | 
						||
| 
								 | 
							
								                if c == '\0':
							 | 
						||
| 
								 | 
							
								                    break
							 | 
						||
| 
								 | 
							
								                result += c
							 | 
						||
| 
								 | 
							
								        return result
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def GetArch(self):
							 | 
						||
| 
								 | 
							
								        return self._GetFeatureString('arch')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def MetaInfo(self):
							 | 
						||
| 
								 | 
							
								        """ Return a string to string map stored in meta_info section in perf.data.
							 | 
						||
| 
								 | 
							
								            It is used to pass some short meta information.
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        if self.meta_info is None:
							 | 
						||
| 
								 | 
							
								            self.meta_info = {}
							 | 
						||
| 
								 | 
							
								            feature_data = self._GetFeatureSection(self.getInstance(), _char_pt('meta_info'))
							 | 
						||
| 
								 | 
							
								            if not _is_null(feature_data):
							 | 
						||
| 
								 | 
							
								                str_list = []
							 | 
						||
| 
								 | 
							
								                data = feature_data[0].data
							 | 
						||
| 
								 | 
							
								                data_size = feature_data[0].data_size
							 | 
						||
| 
								 | 
							
								                current_str = ''
							 | 
						||
| 
								 | 
							
								                for i in range(data_size):
							 | 
						||
| 
								 | 
							
								                    c = bytes_to_str(data[i])
							 | 
						||
| 
								 | 
							
								                    if c != '\0':
							 | 
						||
| 
								 | 
							
								                        current_str += c
							 | 
						||
| 
								 | 
							
								                    else:
							 | 
						||
| 
								 | 
							
								                        str_list.append(current_str)
							 | 
						||
| 
								 | 
							
								                        current_str = ''
							 | 
						||
| 
								 | 
							
								                for i in range(0, len(str_list), 2):
							 | 
						||
| 
								 | 
							
								                    self.meta_info[str_list[i]] = str_list[i + 1]
							 | 
						||
| 
								 | 
							
								        return self.meta_info
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def getInstance(self):
							 | 
						||
| 
								 | 
							
								        if self._instance is None:
							 | 
						||
| 
								 | 
							
								            raise Exception('Instance is Closed')
							 | 
						||
| 
								 | 
							
								        return self._instance
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def _check(self, cond, failmsg):
							 | 
						||
| 
								 | 
							
								        if not cond:
							 | 
						||
| 
								 | 
							
								            raise Exception(failmsg)
							 |