diff --git a/.param b/.param new file mode 100644 index 00000000..534c734e --- /dev/null +++ b/.param @@ -0,0 +1,22 @@ +# export POST_CONFIG=dts_FM_100P_VI_GPU_NPU_VO_DSI0_HDMI_V1.txt +# export BOARD_NAME=light_fpga_fm_c910 +# ROOT_DIR=${WORKDIR} +# KERNELVERSION=5.10.112 + +# Set build parameters +export ARCH=riscv +# export BUILDROOT_DIR=${ROOT_DIR}/buildroot +# export TOOLCHAIN_DIR?="${EXTERNAL_TOOLCHAIN}" +# export TOOLCHAIN_PREFIX=riscv64-unknown-linux-gnu- +# export CROSS_COMPILE=${TOOLCHAIN_DIR}/${TOOLCHAIN_PREFIX} +# export CC=${CROSS_COMPILE}gcc +# export CXX=${CROSS_COMPILE}g++ +# export CFLAGS_COMMON="-march=rv64imafdc -mabi=lp64d -Wall" +# export LINUX_DIR="/home/zhangjb/riscv_yocto/thead-build/light-fm/tmp-glibc/work/light_fm-oe-linux/linux-thead/5.10.4-r0/linux-light_fm-standard-build" +# export INSTALL_DIR_ROOTFS=${ROOT_DIR}/buildroot/output/target +# export INSTALL_DIR_SDK=${ROOT_DIR}/output/sdk + +# LTP-DDT +# export SKIP_IDCHECK=1 +# export KERNEL_USR_INC=${LINUX_DIR} +# export DESTDIR=${INSTALL_DIR_ROOTFS} diff --git a/Makefile b/Makefile index 40ab3778..8b2c4f2a 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ ## # Copyright (C) 2020 Alibaba Group Holding Limited ## -include ../.param +include .param CONFIG_BUILD_DRV_EXTRA_PARAM:="" CONFIG_BUILD_LIB_EXTRA_PARAM:="" @@ -12,39 +12,11 @@ DIR_TARGET_LIB =bsp/gpu/lib DIR_TARGET_KO =bsp/gpu/ko DIR_TARGET_TEST=bsp/gpu/test -MODULE_NAME=GPU -BUILD_LOG_START="\033[47;30m>>> $(MODULE_NAME) $@ begin\033[0m" -BUILD_LOG_END ="\033[47;30m<<< $(MODULE_NAME) $@ end\033[0m" - - -export PATH+=:$(ROOT_DIR)/buildroot/output/host/bin -#export WINDOW_SYSTEM=nulldrmws -#export WINDOW_SYSTEM=xorg -export WINDOW_SYSTEM=lws-generic -#export WINDOW_SYSTEM=wayland -#export WINDOW_SYSTEM=nullws -export MIPS_ELF_ROOT=$(ROOT_DIR)/gpu_bxm_4_64/tools/mips-mti-elf/2014.07-1 -export SYSROOT=$(ROOT_DIR)/buildroot/output/host/opt/ext-toolchain/sysroot -export DISCIMAGE=$(ROOT_DIR)/buildroot/output/host/opt/ext-toolchain/sysroot -export KERNELDIR=$(ROOT_DIR)/buildroot/output/build/linux-custom -export BUILD=debug -#export BUILD=release -export LINUX_ROOT=$(ROOT_DIR)/gpu_bxm_4_64 -export LLVM_BUILD_DIR=$(ROOT_DIR)/gpu_bxm_4_64/tools/llvm export RGX_BVNC=36.52.104.182 export DRIVERDIR=rogue_km export LIBDIR=rogue -#export CC=gcc +export DISCIMAGE=$(shell pwd)/output -#$(warning *****$(origin CC)) -#$(warning *****$(PATH)) - -# -# Do a parallel build with multiple jobs, based on the number of CPUs online -# in this system: 'make -j8' on a 8-CPU system, etc. -# -# (To override it, run 'make JOBS=1' and similar.) -# ifeq ($(JOBS),) JOBS := $(shell grep -c ^processor /proc/cpuinfo 2>/dev/null) ifeq ($(JOBS),) @@ -52,98 +24,88 @@ ifeq ($(JOBS),) endif endif -all: info driver lib test install_local_output install_rootfs -.PHONY: info driver lib test install_local_output install_rootfs \ - install_addons clean_driver clean_lib clean_test clean_output clean +export CROSS_COMPILE=riscv64-unknown-linux-gnu- +export BUILD=release + +#all: info driver test install_local_output install_rootfs +#.PHONY: info driver test install_local_output install_rootfs \ +# install_addons clean_driver clean_test clean_output clean +all: info driver test install_local_output +.PHONY: info driver test install_local_output \ + install_addons clean_driver clean_test clean_output clean info: - @echo $(BUILD_LOG_START) @echo " ====== Build Info from repo project ======" @echo " BUILDROOT_DIR="$(BUILDROOT_DIR) @echo " CROSS_COMPILE="$(CROSS_COMPILE) - @echo " LINUX_DIR="$(LINUX_DIR) + #@echo " LINUX_DIR="$(LINUX_DIR) @echo " ARCH="$(ARCH) @echo " BOARD_NAME="$(BOARD_NAME) @echo " KERNEL_ID="$(KERNELVERSION) - @echo " KERNEL_DIR="$(LINUX_DIR) + #@echo " KERNEL_DIR="$(LINUX_DIR) @echo " INSTALL_DIR_ROOTFS="$(INSTALL_DIR_ROOTFS) @echo " INSTALL_DIR_SDK="$(INSTALL_DIR_SDK) + @echo " ROOT_DIR="$(ROOT_DIR) @echo " ====== Build configuration by settings ======" @echo " JOBS="$(JOBS) - @echo $(BUILD_LOG_END) driver: - @echo $(BUILD_LOG_START) - make -C $(DRIVERDIR)/build/linux/thead_linux CROSS_COMPILE=$(CROSS_COMPILE) ARCH=$(ARCH) BUILD=$(BUILD) RGX_BVNC=$(RGX_BVNC) - @echo $(BUILD_LOG_END) + make -j 64 -C $(DRIVERDIR)/build/linux/thead_linux CROSS_COMPILE=$(CROSS_COMPILE) ARCH=$(ARCH) BUILD=$(BUILD) RGX_BVNC=$(RGX_BVNC) clean_driver: - @echo $(BUILD_LOG_START) make -C $(DRIVERDIR)/build/linux/thead_linux CROSS_COMPILE=$(CROSS_COMPILE) ARCH=$(ARCH) BUILD=$(BUILD) RGX_BVNC=$(RGX_BVNC) clean - @echo $(BUILD_LOG_END) -prepare_lib: - @bash ./tools/prepare.sh $(SYSROOT) $(KERNELDIR) $(DISCIMAGE) +prepare_driver: + @echo " prepare_driver " + @bash ./tools/prepare_driver.sh $(KERNELDIR) $(DISCIMAGE) -lib: prepare_lib - @echo $(BUILD_LOG_START) - make -C $(LIBDIR)/build/linux/thead_linux CROSS_COMPILE=$(TOOLCHAIN_PREFIX) ARCH=$(ARCH) BUILD=$(BUILD) RGX_BVNC=$(RGX_BVNC) - @echo $(BUILD_LOG_END) -clean_lib: - @echo $(BUILD_LOG_START) - make -C $(LIBDIR)/build/linux/thead_linux CROSS_COMPILE=$(TOOLCHAIN_PREFIX) ARCH=$(ARCH) BUILD=$(BUILD) RGX_BVNC=$(RGX_BVNC) clean - @echo $(BUILD_LOG_END) - -test: lib driver - @echo $(BUILD_LOG_START) - @echo "Test cases are built when build lib" - @echo $(BUILD_LOG_END) +test: driver clean_test: - @echo $(BUILD_LOG_START) - @echo $(BUILD_LOG_END) -install_driver: - sudo -E make -C $(DRIVERDIR)/build/linux/thead_linux CROSS_COMPILE=$(CROSS_COMPILE) ARCH=$(ARCH) BUILD=$(BUILD) RGX_BVNC=$(RGX_BVNC) kbuild_install - -install_lib: - sudo -E make -C $(LIBDIR)/build/linux/thead_linux CROSS_COMPILE=$(CROSS_COMPILE) ARCH=$(ARCH) BUILD=$(BUILD) RGX_BVNC=$(RGX_BVNC) install +install_driver: prepare_driver + make -C $(DRIVERDIR)/build/linux/thead_linux CROSS_COMPILE=$(CROSS_COMPILE) ARCH=$(ARCH) BUILD=$(BUILD) RGX_BVNC=$(RGX_BVNC) kbuild_install install_prepare: mkdir -p ./output/rootfs/$(DIR_TARGET_KO) mkdir -p ./output/rootfs/$(DIR_TARGET_LIB) mkdir -p ./output/rootfs/$(DIR_TARGET_TEST) + mkdir -p ./output/usr/bin + mkdir -p ./output/usr/lib + mkdir -p ./output/usr/share/gpu + mkdir -p ./output/lib/systemd/system + mkdir -p ./output/lib/systemd/system-preset + mkdir -p ./output/usr/share/gpu + mkdir -p ./output/lib/firmware -install_addons: install_prepare install_driver install_lib - @if [ -d addons/$(BOARD_NAME) ]; then \ - cp -rf addons/$(BOARD_NAME)/* ./output/rootfs/$(DIR_TARGET_BASE); \ +install_addons: install_prepare install_driver + @if [ -d addons/ko ]; then \ + cp -rf addons/ko/*.sh ./output/usr/share/gpu; \ + cp -rf addons/ko/98-pvrsrvkm.preset ./output/lib/systemd/system-preset; \ + cp -rf addons/ko/pvrsrvkm.service ./output/lib/systemd/system; \ fi - -install_local_output: driver lib test install_addons - @echo $(BUILD_LOG_START) - find $(DRIVERDIR) -name "*.ko" | xargs -i cp -f {} ./output/rootfs/$(DIR_TARGET_KO) - chmod +x ./output/rootfs/$(DIR_TARGET_KO)/*.sh - find $(LIBDIR) -name "*.so*" | xargs -i cp -f {} ./output/rootfs/$(DIR_TARGET_LIB) - cp -rf $(LIBDIR)/*/target_riscv64/* ./output/rootfs/$(DIR_TARGET_TEST) - cp -rf $(LIBDIR)/*/target_neutral/*.txt ./output/rootfs/$(DIR_TARGET_TEST) - cp -rf $(LIBDIR)/*/target_neutral/rgx.* ./output/rootfs/$(DIR_TARGET_TEST) - cp -rf $(LIBDIR)/*/target_neutral/*pvr* ./output/rootfs/$(DIR_TARGET_TEST) + @if [ -d addons/lib ]; then \ + cp -rf addons/lib/etc ./output/; \ + cp -rf addons/lib/lib/firmware/* ./output/lib/firmware/; \ + cp -rf addons/lib/usr/lib ./output/usr/; \ + cp -rf addons/lib/usr/local ./output/usr/; \ + fi +install_local_output: driver test install_addons + chmod +x ./output/usr/share/gpu/*.sh + rm -rf ./output/etc/powervr_ddk_install_km.log rm -rf ./output/rootfs/$(DIR_TARGET_TEST)/*.so* rm -rf ./output/rootfs/$(DIR_TARGET_TEST)/*.a* rm -rf ./output/rootfs/$(DIR_TARGET_TEST)/*.sh - @echo $(BUILD_LOG_END) - -install_rootfs: install_local_output - @echo $(BUILD_LOG_START) -# cp -rf output/rootfs/* $(INSTALL_DIR_ROOTFS) - @echo $(BUILD_LOG_END) + # cleanup unnecessary files + rm -rf ./output/rootfs + rm -rf ./output/lib/modules/*/kernel + rm -rf ./output/lib/modules/*/modules* + rm -rf ./output/lib/modules/*/build + rm -rf ./output/lib/modules/*/source clean_output: - @echo $(BUILD_LOG_START) rm -rf ./output rm -rf $(INSTALL_DIR_ROOTFS)/$(DIR_TARGET_BASE) - @echo $(BUILD_LOG_END) - -clean: clean_output clean_driver clean_lib clean_test +clean: clean_output clean_driver clean_test diff --git a/addons/ko/98-pvrsrvkm.preset b/addons/ko/98-pvrsrvkm.preset new file mode 100644 index 00000000..a6158274 --- /dev/null +++ b/addons/ko/98-pvrsrvkm.preset @@ -0,0 +1 @@ +enable pvrsrvkm.service diff --git a/addons/ko/insmod.sh b/addons/ko/insmod.sh new file mode 100755 index 00000000..112fb21d --- /dev/null +++ b/addons/ko/insmod.sh @@ -0,0 +1,5 @@ +#!/bin/sh +KERNEL_VER=$(uname -r) +BASE_PATH=/lib/modules/${KERNEL_VER}/extra + +insmod $BASE_PATH/pvrsrvkm.ko diff --git a/addons/ko/pvrsrvkm.service b/addons/ko/pvrsrvkm.service new file mode 100644 index 00000000..7ae2e91c --- /dev/null +++ b/addons/ko/pvrsrvkm.service @@ -0,0 +1,12 @@ +[Unit] +Description=Imagination GPU BXM-4-64 driver init Service. + +[Service] +Type=simple +EnvironmentFile=-/usr/share/gpu/gpu.env +ExecStart=sh usr/share/gpu/insmod.sh +ExecStop=sh usr/share/gpu/rmmod.sh +RemainAfterExit=y + +[Install] +WantedBy=multi-user.target diff --git a/addons/ko/rmmod.sh b/addons/ko/rmmod.sh new file mode 100755 index 00000000..3634dd86 --- /dev/null +++ b/addons/ko/rmmod.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +rmmod pvrsrvkm diff --git a/addons/lib/etc/OpenCL/vendors/IMG.icd b/addons/lib/etc/OpenCL/vendors/IMG.icd new file mode 100755 index 00000000..16cf40fa --- /dev/null +++ b/addons/lib/etc/OpenCL/vendors/IMG.icd @@ -0,0 +1 @@ +libPVROCL.so diff --git a/addons/lib/lib/firmware/rgx.fw.36.52.104.182 b/addons/lib/lib/firmware/rgx.fw.36.52.104.182 new file mode 100755 index 00000000..259fff3a Binary files /dev/null and b/addons/lib/lib/firmware/rgx.fw.36.52.104.182 differ diff --git a/addons/lib/lib/firmware/rgx.sh.36.52.104.182 b/addons/lib/lib/firmware/rgx.sh.36.52.104.182 new file mode 100755 index 00000000..0adc82fd Binary files /dev/null and b/addons/lib/lib/firmware/rgx.sh.36.52.104.182 differ diff --git a/addons/lib/usr/lib/libGLESv1_CM_PVR_MESA.so b/addons/lib/usr/lib/libGLESv1_CM_PVR_MESA.so new file mode 100755 index 00000000..fda98e6a Binary files /dev/null and b/addons/lib/usr/lib/libGLESv1_CM_PVR_MESA.so differ diff --git a/addons/lib/usr/lib/libGLESv2_PVR_MESA.so b/addons/lib/usr/lib/libGLESv2_PVR_MESA.so new file mode 100755 index 00000000..1029a7ca Binary files /dev/null and b/addons/lib/usr/lib/libGLESv2_PVR_MESA.so differ diff --git a/addons/lib/usr/lib/libPVROCL.so b/addons/lib/usr/lib/libPVROCL.so new file mode 100755 index 00000000..26bcbf6e Binary files /dev/null and b/addons/lib/usr/lib/libPVROCL.so differ diff --git a/addons/lib/usr/lib/libPVROCL.so.1 b/addons/lib/usr/lib/libPVROCL.so.1 new file mode 100755 index 00000000..26bcbf6e Binary files /dev/null and b/addons/lib/usr/lib/libPVROCL.so.1 differ diff --git a/addons/lib/usr/lib/libPVRScopeServices.so b/addons/lib/usr/lib/libPVRScopeServices.so new file mode 100755 index 00000000..b9aa5af4 Binary files /dev/null and b/addons/lib/usr/lib/libPVRScopeServices.so differ diff --git a/addons/lib/usr/lib/libVK_IMG.so b/addons/lib/usr/lib/libVK_IMG.so new file mode 100755 index 00000000..9288ff45 Binary files /dev/null and b/addons/lib/usr/lib/libVK_IMG.so differ diff --git a/addons/lib/usr/lib/libVK_IMG.so.1 b/addons/lib/usr/lib/libVK_IMG.so.1 new file mode 100755 index 00000000..9288ff45 Binary files /dev/null and b/addons/lib/usr/lib/libVK_IMG.so.1 differ diff --git a/addons/lib/usr/lib/libglslcompiler.so b/addons/lib/usr/lib/libglslcompiler.so new file mode 100755 index 00000000..2bab5f53 Binary files /dev/null and b/addons/lib/usr/lib/libglslcompiler.so differ diff --git a/addons/lib/usr/lib/libpvr_dri_support.so b/addons/lib/usr/lib/libpvr_dri_support.so new file mode 100755 index 00000000..203ca233 Binary files /dev/null and b/addons/lib/usr/lib/libpvr_dri_support.so differ diff --git a/addons/lib/usr/lib/libsrv_um.so b/addons/lib/usr/lib/libsrv_um.so new file mode 100755 index 00000000..c4db58cd Binary files /dev/null and b/addons/lib/usr/lib/libsrv_um.so differ diff --git a/addons/lib/usr/lib/libsutu_display.so b/addons/lib/usr/lib/libsutu_display.so new file mode 100755 index 00000000..de2db9de Binary files /dev/null and b/addons/lib/usr/lib/libsutu_display.so differ diff --git a/addons/lib/usr/lib/libufwriter.so b/addons/lib/usr/lib/libufwriter.so new file mode 100755 index 00000000..3bb2215c Binary files /dev/null and b/addons/lib/usr/lib/libufwriter.so differ diff --git a/addons/lib/usr/lib/libusc.so b/addons/lib/usr/lib/libusc.so new file mode 100755 index 00000000..4636420c Binary files /dev/null and b/addons/lib/usr/lib/libusc.so differ diff --git a/addons/lib/usr/lib/libvulkan.so b/addons/lib/usr/lib/libvulkan.so new file mode 100755 index 00000000..a4a785f0 Binary files /dev/null and b/addons/lib/usr/lib/libvulkan.so differ diff --git a/addons/lib/usr/lib/libvulkan.so.1 b/addons/lib/usr/lib/libvulkan.so.1 new file mode 100755 index 00000000..a4a785f0 Binary files /dev/null and b/addons/lib/usr/lib/libvulkan.so.1 differ diff --git a/addons/lib/usr/local/bin/hwperfbin2jsont b/addons/lib/usr/local/bin/hwperfbin2jsont new file mode 100755 index 00000000..c0cc3aa8 Binary files /dev/null and b/addons/lib/usr/local/bin/hwperfbin2jsont differ diff --git a/addons/lib/usr/local/bin/hwperfjsonmerge.py b/addons/lib/usr/local/bin/hwperfjsonmerge.py new file mode 100755 index 00000000..0962f6c8 --- /dev/null +++ b/addons/lib/usr/local/bin/hwperfjsonmerge.py @@ -0,0 +1,802 @@ +#!/usr/bin/python +############################################################################### +#@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +#@License Strictly Confidential. +############################################################################### + +""" +This script combines json files holding data from HWPerf streams. Files +hold data from firmware, host and client streams. +Attempt is made to change time domain of all events coming from firmware +to CPU time domain. All json objects are marked with appropriate value of +'tdomain' filed (this should help with identification of objects in the +merged json file): + + CPU packet originated from host buffer + + GPU packet originated from firmware buffer and it was impossible to + calculate CPU time stamp from available data (probably + synchronisation packets were not available) + + G2CPU time domain changed from GPU to CPU thanks to synchronisation + data + + G2CPU_NTW some synchronisation data was available somewhere before this + packet but it was lost at some point, so the time stamp of this + packet may be inaccurate +""" + +# pylint: disable=I0011,C0103,C0325,C0330,R0201,R0902,R0903,R0912 + +import sys +import os +import re +import json +import logging +from argparse import ArgumentParser + +logging.basicConfig(level=logging.WARN, format='%(levelname)s: %(message)s') +log = logging.getLogger(__name__) + +if (sys.stdout.isatty()): + logging.addLevelName(logging.INFO, '\033[1mInfo\033[0m') + logging.addLevelName(logging.WARN, '\033[1;35mWarning\033[0m') + logging.addLevelName(logging.ERROR, '\033[1;31mError\033[0m') +else: + logging.addLevelName(logging.INFO, 'Info') + logging.addLevelName(logging.WARN, 'Warning') + logging.addLevelName(logging.ERROR, 'Error') + +def print_exception(): + """Prints exception's stack trace.""" + dummy, ex_obj, tb = sys.exc_info() + l = tb.tb_lineno + f = tb.tb_frame.f_code.co_filename + print('Exception: "{}" in {}:{}'.format(ex_obj, f, l)) + +def s2ns(ts): + """Converts seconds to nanoseconds.""" + return ts * 1e9 + +def ns2us(ts): + """Converts nanoseconds to microseconds.""" + return int(ts / 1000.0 + 0.5) + +class InvalidArgumentException(Exception): + """Throws when invalid arguments are passed from command line.""" + def __init__(self, msg=None): + self._msg = msg + super(self.__class__, self).__init__() + + def __str__(self): + return self._msg if self._msg else "InvalidArgumentException" + +class WrongFormatException(Exception): + """Streams have inconsistent format e.g. raw and normal.""" + def __init__(self): + super(self.__class__, self).__init__() + + def __str__(self): + return 'Files format mismatch.' + +class Args(object): + """Processes and validates command line arguments.""" + def __init__(self, args=None): + self._clockspeed = None + self._keepgputs = None + self._keepsyncev = None + self._dir = None + self._gpu = dict() + self._host = dict() + self._client = dict() + self._out = dict() + + self._devices = set() + + self._is_fw_default = False + self._is_host_default = False + self._is_client_default = False + + self._parser = ArgumentParser() + self._define() + self._parse(args) + + def _define(self): + self._parser.add_argument('-v', '--verbose', action='count', + help='Verbosity level of the messages') + self._parser.add_argument('-d', '--dir', dest='dirr', + help='Path to directory containing hwperf.json and' + ' hwperf_host.json. If not specified, current' + ' directory will be used.', metavar='PATH', + default='.') + self._parser.add_argument('-f', '--fw', dest='fw', + help='File name of the json file produced from' + ' hwperf.bin file. If --dir option not given full' + ' file path needs to be specified.' + ' If this option is not given default name will be' + ' assumed (hwperf.json or hwperf.raw.json).', + metavar='FILE') + self._parser.add_argument('-s', '--host', dest='host', + help='File name of the json file produced from' + ' hwperf.bin file. If --dir option not given full' + ' file path needs to be specified.' + ' If this option is not given default name will be' + ' assumed (hwperf_host.json or hwper_host.raw.json).', + metavar='FILE') + self._parser.add_argument('-c', '--prefix', dest='client', + help='File name prefix of json files produced from' + ' hwperf_client_.bin files. If --dir option' + ' not given full path needs to be specified.' + ' If this option is not given the default prefix will' + ' be assumed (hwperf_client_.json).', + metavar='PREFIX') + self._parser.add_argument('--clockspeed', dest='clk', + help='Overrides clock speed received in firmware' + ' packages. This is useful e.g. for emulators.' + ' The value is in Hz. It\'s possible to use "kHz"' + ' and "MHz" postfix e.g. 3.45MHz will override' + ' the GPU clock with value 3450000Hz.', + metavar='CLK') + self._parser.add_argument('--keepgputs', dest='keepgputs', + action='store_true', help='If this option is used the' + ' GPU packets will keep original timestamps in' + ' "start_gpu" and "end_gpu" fileds') + self._parser.add_argument('--keepsyncev', dest='keepsyncev', + action='store_true', help='If this option is used the' + ' synchronisation events will not be removed from' + ' the merged json file.') + self._parser.add_argument('-o', '--out', dest='out', + help='Output file. If not given default name will be' + ' assumed (hwperf_merged_.json).', + metavar='FILE') + + def _parse(self, args=None): + args = self._parser.parse_args(args) + + # set verbosity level + if args.verbose: + log.setLevel(logging.INFO) + + self._validate_clockspeed(args.clk) + self._validate_dir(args.dirr) + self._validate_fw_files(args.fw) + self._validate_host_files(args.host) + self._validate_client_files(args.client) + self._validate_input_format() + self._validate_out(args.out) + + self._keepgputs = args.keepgputs + if self._clockspeed: + log.info('GPU clock will be overwritten with specified value:' + ' %0.2fHz', self._clockspeed) + + self._keepsyncev = args.keepsyncev + + def _validate_clockspeed(self, clk): + # no value so nothing to do here + if not clk: + return + + m = 1.0 + + if clk[-3:] == 'kHz': + m = 1e3 + clk = clk[:-3] + elif clk[-3:] == 'MHz': + m = 1e6 + clk = clk[:-3] + + clk = float(clk) * m + + if clk > 0: + self._clockspeed = clk + else: + raise ValueError('Invalid clock value: "{}"'.format(clk)) + + def _validate_dir(self, dirr): + if not os.path.isdir(dirr): + raise IOError('Directory `' + dirr + '` does not exist.') + self._dir = dirr + + def _validate_fw_files(self, fw): + if not fw: + # # look for default names 'hwperf_fw_.json' and + # # 'hwperf_fw_.raw.json' + fname_re = re.compile(r'hwperf_fw_(?P\d+)\.(raw\.)*json') + + for entry in os.listdir(self._dir): + match = fname_re.match(entry) + if match: + fpath = os.path.join(self._dir, entry) + devid = int(match.group('devid')) + log.info('found firmware stream file: %s', fpath) + if devid not in self._gpu: + self._gpu[devid] = list() + self._gpu[devid].append(fpath) + self._devices.add(devid) + self._is_fw_default = True + else: + fpath = os.path.join(self._dir, fw) + if os.path.isfile(fpath): + log.info('found firmware stream file: %s', fpath) + self._gpu = {0: [fpath]} + self._devices.add(0) + else: + raise IOError('File `{}` does not exist.'.format(fpath)) + + def _validate_host_files(self, host): + if not host: + # look for default names 'hwperf_host_.json' and + # 'hwperf_host_.raw.json' + fname_re = re.compile(r'hwperf_host_(?P\d+)\.(raw\.)*json') + for entry in os.listdir(self._dir): + match = fname_re.match(entry) + if match: + fpath = os.path.join(self._dir, entry) + devid = int(match.group('devid')) + log.info('found host stream file: %s', fpath) + if devid not in self._host: + self._host[devid] = list() + self._host[devid].append(fpath) + self._devices.add(devid) + self._is_host_default = True + else: + fpath = os.path.join(self._dir, host) + if os.path.isfile(fpath): + log.info('found host stream file: %s', fpath) + self._host = {0: [fpath]} + self._devices.add(0) + else: + raise IOError('File `{}` does not exist.'.format(fpath)) + + def _validate_client_files(self, prefix): + fname_re = re.compile(r'hwperf_client_(?P\d+)_(?P\d+)' + r'\.(raw\.)*json') + + for entry in os.listdir(self._dir): + if not prefix: + match = fname_re.match(entry) + if match: + fpath = os.path.join(self._dir, entry) + devid = int(match.group('devid')) + log.info('found client stream file: %s', fpath) + if devid not in self._client: + self._client[devid] = list() + self._client[devid].append(fpath) + self._devices.add(devid) + self._is_client_default = True + else: + if entry.startswith(prefix) and entry.endswith('.json'): + fpath = os.path.join(self._dir, entry) + log.info('found client stream file: %s', fpath) + if 0 not in self._client: + self._client[0] = list() + self._client[0].append(fpath) + self._devices.add(0) + + if prefix and not self._client: + raise IOError('No files starting with `{}` prefix found.' + .format(prefix)) + + def _validate_input_format(self): + """Preliminary check of the input format based on the file names.""" + if self._is_fw_default and self._is_host_default and \ + self._is_client_default: + + def file_check(lst, files): + """Checks if file contains 'raw'.""" + is_raw = False + for fname in files: + if 'raw' in fname: + is_raw = True + lst.append(is_raw) + + for devid in self._devices: + to_check = list() + + if devid in self._client: + file_check(to_check, self._client[devid]) + if devid in self._gpu: + file_check(to_check, self._gpu[devid]) + if devid in self._host: + file_check(to_check, self._host[devid]) + + if to_check: + last = to_check[0] + for curr in to_check[1:]: + if curr != last: + raise WrongFormatException() + + def _validate_out(self, out): + # do output filename initialisation + if not out: + # after _validate_input_format() we know that files should have + # same format so check only first file for the extension + # we do this assumption only at this stage and don't modify filename + # later even if the real formats don't match + + get_name = lambda l, d: 'hwperf_merged_' + str(d) + \ + ('.raw.json' if 'raw' in l[0] else '.json') + + for devid in self._devices: + self._out[devid] = 'hwperf_merged_{}.json'.format(devid) + + if devid in self._gpu: + self._out[devid] = get_name(self._gpu[devid], devid) + elif devid in self._host: + self._out[devid] = get_name(self._host[devid], devid) + elif devid in self._client: + self._out[devid] = get_name(self._client[devid], devid) + else: + if self._is_fw_default and self._is_host_default \ + and self._is_client_default: + raise InvalidArgumentException("input file not given") + + self._out[0] = out + + def clockspeed(self): + """Override GPU's clock speed.""" + return self._clockspeed + + def keepgputs(self): + """Keep GPU time stamp in json file.""" + return self._keepgputs + + def keepsyncev(self): + """Keep synchronisation events in merged json.""" + return self._keepsyncev + + def fwjson_fname(self): + """Returns dictionary with Firmware file names.""" + return self._gpu + + def hostjson_fname(self): + """Returns dictionary with Host file names.""" + return self._host + + def clientjson_fnames(self): + """Returns dictionary of lists with Client file names.""" + return self._client + + def device_list(self): + """Returns list of all device IDs that has been detected.""" + return self._devices + + def out_fname(self): + """Returns list of all output files names as a dictionary where the + key is iDeviceID.""" + return self._out + +class SyncPoint(object): + """Represents synchronisation point between Host and Firmware time + domains""" + def __init__(self, tcpu=None, tgpu=None, fgpu=None): + self.tcpu = tcpu + self.tgpu = tgpu + self.fgpu = fgpu + self.tw = True + + def __str__(self): + return 'SyncPoint: tCPU: {}; tGPU: {}; fGPU: {}'\ + .format(self.tcpu, self.tgpu, self.fgpu) + + def __eq__(self, other): + return self.tcpu == other.tcpu and \ + self.tgpu == other.tgpu and \ + self.fgpu == other.fgpu + +class Hwperf(object): + """Base class for all HWPerf JSON streams.""" + def __init__(self, filename=None, jfile=None): + self._js = self._load(filename, jfile) + + def _load(self, filename, jfile): + if jfile: + return json.load(jfile) + else: + with open(filename, 'r') as f: + return json.load(f) + + def is_raw(self): + """Returns True if RAW json.""" + return True if 'hwperf_packets' in self._js else False + + def get_json(self): + """Returns json dictionary.""" + return self._js + + def process(self): + """Preprocess all of the events in the stream.""" + pass + +class HwperfFw(Hwperf): + """Represents HWPerf Firmware stream.""" + def __init__(self, args, syncline, filename=None, jfile=None): + super(self.__class__, self).__init__(filename, jfile) + self._to_remove = list() + self._syncline = syncline + self._td_switch = False + self._sync_types = {'PWRCHG': self._process_normal_pwrchg, + 'CLKCHG': self._process_normal_clkchg, + '23_PWR_CHG': self._process_raw_pwrchg, + '1A_CLKS_CHG': self._process_raw_clkchg} + self._clk = args.clockspeed() + self._keepgputs = args.keepgputs() + self._keepsyncev = args.keepsyncev + + def process(self): + if self.is_raw(): + self._process_raw() + else: + self._process_normal() + + def _process_raw(self): + packets = self._js['hwperf_packets'] + name_key = 'type' + + for packet in packets: + self._keep_gpu_ts(packet) + + name = packet[name_key] + if name in self._sync_types: + self._sync_types[name](packet) + else: + self._process_raw_other(packet) + + if not self._keepsyncev: + # remove synchronisation packets + for packet in self._to_remove: + packets.remove(packet) + + def _process_normal(self): + packets = self._js['timeperiods'] + name_key = 'name' + + for packet in packets: + self._keep_gpu_ts(packet) + + name = packet[name_key] + if name in self._sync_types: + self._sync_types[name](packet) + else: + self._process_normal_other(packet) + + if not self._keepsyncev: + # remove synchronisation packets + for packet in self._to_remove: + packets.remove(packet) + + def _keep_gpu_ts(self, packet): + if self._keepgputs: + packet['start_gpu'] = packet['start'] + packet['end_gpu'] = packet['end'] + + def _process_raw_pwrchg(self, packet): + pwr_data = packet['pwrchg'] + self._process_pwrchg(packet, pwr_data) + if self._keepsyncev: + self._process_raw_other(packet) + + def _process_normal_pwrchg(self, packet): + pwr_data = packet['prop'] + self._process_pwrchg(packet, pwr_data) + if self._keepsyncev: + self._process_normal_other(packet) + + def _process_pwrchg(self, packet, pwr_data): + if 'PowerOn' in pwr_data['change']: + if 'ostimestamp' not in pwr_data: + # means that it's an old version of a packet which + # doesn't have synchronisation info inside, so we just ignore + # it because it's useless for us + return + + if self._clk: + # force clock speed + pwr_data['gpuclockspeed'] = self._clk + + self._syncline.append(SyncPoint(int(pwr_data['ostimestamp']), + int(pwr_data['crtimestamp'] * 256), + float(pwr_data['gpuclockspeed']))) + elif 'PowerOff' in pwr_data['change']: + # We're not clearing time information but it may be + # no longer valid. We will mark all of packets after this + # as not trustworthy until we receive next valid synchronisation + # packet. We're still changing time domain though. + if self._syncline: + self._syncline[-1].tw = False + + if not self._keepsyncev: + self._to_remove.append(packet) + + def _process_raw_clkchg(self, packet): + clk_data = packet['clkschgdata'] + self._process_clkchg(packet, clk_data) + if self._keepsyncev: + self._process_raw_other(packet) + + def _process_normal_clkchg(self, packet): + clk_data = packet['prop'] + self._process_clkchg(packet, clk_data) + if self._keepsyncev: + self._process_normal_other(packet) + + def _process_clkchg(self, packet, clk_data): + if 'ostimestamp' not in clk_data: + # means that it's an old version of a packet which + # doesn't have synchronisation info inside, so we just ignore + # it because it's useless for us + return + + if self._clk: + # force clock speed + clk_data['speed'] = self._clk + + self._syncline.append(SyncPoint(int(clk_data['ostimestamp']), + int(clk_data['crtimestamp']) * 256, + float(clk_data['speed']))) + + if not self._keepsyncev: + self._to_remove.append(packet) + + def _process_raw_other(self, packet): + if self._syncline: + sync = self._syncline[-1] + ts = int(packet['rgxtimer']) * 256 + + if ts >= sync.tgpu: + start = s2ns((ts - sync.tgpu) / sync.fgpu) + else: + start = -s2ns((sync.tgpu - ts) / sync.fgpu) + + packet['rgxtimer'] = ns2us(sync.tcpu + start) + packet['tdomain'] = 'G2CPU' if sync.tw else 'G2CPU_NTW' + else: + # means that we didn't have any synchronisation packets + # yet so we don't change time domain + packet['tdomain'] = 'GPU' + + packet['source'] = 'FW' + + def _process_normal_other(self, packet): + if self._syncline: + sync = self._syncline[-1] + + if packet['start'] >= sync.tgpu: + start = s2ns((packet['start'] - sync.tgpu) / sync.fgpu) + end = s2ns((packet['end'] - sync.tgpu) / sync.fgpu) + else: + start = -s2ns((sync.tgpu - packet['start']) / sync.fgpu) + end = -s2ns((sync.tgpu - packet['end']) / sync.fgpu) + + packet['start'] = ns2us(sync.tcpu + start) + packet['end'] = ns2us(sync.tcpu + end) + packet['tdomain'] = 'G2CPU' if sync.tw else 'G2CPU_NTW' + else: + # means that we didn't have any synchronisation packets + # yet so we don't change time domain + packet['tdomain'] = 'GPU' + + packet['source'] = 'FW' + +class HwperfHost(Hwperf): + """Represents HWPerf Host stream.""" + def __init__(self, args, syncline, filename=None, jfile=None): + super(self.__class__, self).__init__(filename, jfile) + self._to_remove = list() + self._syncline = syncline + self._sync_types = {'CLK_SYNC': self._process_normal_clksync, + '04_CLK_SYNC': self._process_raw_clksync} + self._keepsyncev = args.keepsyncev() + + def process(self): + if self.is_raw(): + self._process_raw() + else: + self._process_normal() + + def _process_raw(self): + packets = self._js['hwperf_packets'] + name_key = 'type' + self._process(packets, name_key) + + def _process_normal(self): + packets = self._js['timeperiods'] + name_key = 'name' + self._process(packets, name_key) + + def _process(self, packets, name_key): + for packet in packets: + name = packet[name_key] + + if name in self._sync_types: + self._sync_types[name](packet) + else: + self._process_other(packet) + + if not self._keepsyncev: + # remove all synchronisation packets + for packet in self._to_remove: + packets.remove(packet) + + def _process_raw_clksync(self, packet): + clk_data = packet['clksync'] + self._process_clksync(packet, clk_data) + + def _process_normal_clksync(self, packet): + clk_data = packet['prop'] + self._process_clksync(packet, clk_data) + + def _process_clksync(self, packet, clk_data): + self._syncline.append(SyncPoint(int(clk_data['ostimestamp']), + int(clk_data['crtimestamp']) * 256, + float(clk_data['speed']))) + if not self._keepsyncev: + self._to_remove.append(packet) + + def _process_other(self, packet): + packet['tdomain'] = 'CPU' + packet['source'] = 'Host' + +class HwperfClient(Hwperf): + """Represents HWPerf Client stream.""" + def __init__(self, syncline, filename=None, jfile=None): + super(self.__class__, self).__init__(filename, jfile) + self._syncline = syncline + + def process(self): + packets = self._js['hwperf_packets'] if self.is_raw() else \ + self._js['timeperiods'] + + for packet in packets: + packet['tdomain'] = 'CPU' + packet['source'] = 'Client' + +class Merger(object): + """Processes all streams and merges the files to produce complete, + correlated JSON files.""" + def __init__(self, args): + self._args = args + self._syncline = dict() + self._to_process = dict() + + # initialise list dictionary of streams to process + for devid in args.device_list(): + self._syncline[devid] = list() + self._to_process[devid] = list() + + if devid in args.hostjson_fname(): + for fname in args.hostjson_fname()[devid]: + try: + host = HwperfHost(self._args, self._syncline[devid], + fname) + log.info('processing file: %s', fname) + host.process() + self._to_process[devid].append(host) + except Exception: + log.error('Error while loading "%s" file', fname, + exc_info=True) + + if devid in args.fwjson_fname(): + for fname in args.fwjson_fname()[devid]: + try: + fw = HwperfFw(self._args, self._syncline[devid], fname) + log.info('processing file: %s', fname) + fw.process() + self._to_process[devid].append(fw) + except Exception: + log.error('Error while loading "%s" file', fname, + exc_info=True) + + if devid in args.clientjson_fnames(): + for fname in args.clientjson_fnames()[devid]: + try: + client = HwperfClient(self._syncline[devid], fname) + log.info('processing file: %s', fname) + client.process() + self._to_process[devid].append(client) + except Exception: + log.error('Error while loading "%s" file', fname, + exc_info=True) + + # do the final check if formats of the streams match + if self._to_process[devid]: + is_raw = self._to_process[devid][0].is_raw() + for j in self._to_process[devid]: + if j.is_raw() != is_raw: + raise WrongFormatException() + + # see comment in merge() + if devid == 0: + break + + def merge(self): + """Merges all of the processed files.""" + if not self._to_process: + log.error('No input data.') + exit(1) + + for devid in self._syncline: + if len(self._to_process[devid]) == 1 and \ + isinstance(self._to_process[devid][0], HwperfFw): + self._change_timedomain_only(devid) + else: + self._merge(devid) + + # id 0 is special, it means that filename was manually given + # so we're processing only this file + if devid == 0: + break + + def _change_timedomain_only(self, devid): + log.info('No host stream data. Only time domain of stream will' + ' be changed.') + + self._dump_json(self._args.out_fname()[devid], + self._to_process[devid][0].get_json()) + + def _merge(self, devid): + if devid in self._syncline: + if len(self._syncline[devid]) == 0: + msg = '''No synchronisation events have been detected for iDeviceID = %d. + Please consider enabling PWRCHG and CLKCHG events e.g.: + + $ echo 0x804000000 > /(sys/kernel/debug|proc)/pvr/apphint/X/HWPerfFWFilter + + Otherwise correlating Host and Firmware streams will be impossible.''' + log.warning(msg, devid) + if len(self._syncline[devid]) == 1: + msg = '''Only one synchronisation event has been detected for iDeviceID = %d. + If capture process was run on a device supporting APM please consider + enabling PWRCHG and CLKCHG events e.g.: + + $ echo 0x804000000 > /(sys/kernel/debug|proc)/pvr/apphint/X/HWPerfFWFilter + + Otherwise correlating Host and Firmware streams will be impossible.''' + log.warning(msg, devid) + + if devid in self._to_process: + root_key = self._to_process[devid][0].get_json().keys()[0] + ts_key = 'rgxtimer' if self._to_process[devid][0].is_raw() \ + else 'start' + + out = list() + for curr in self._to_process[devid]: + j1 = out + j2 = curr.get_json()[root_key] + out = list() + + (i, j) = (0, 0) + while i < len(j1) or j < len(j2): + if i < len(j1) and j < len(j2): + if j1[i][ts_key] <= j2[j][ts_key]: + out.append(j1[i]) + i += 1 + else: + out.append(j2[j]) + j += 1 + elif i < len(j1): + out.append(j1[i]) + i += 1 + else: + out.append(j2[j]) + j += 1 + + log.info('writing output: %s', self._args.out_fname()[devid]) + self._dump_json(self._args.out_fname()[devid], {root_key: out}) + + def _dump_json(self, fpath, jsn): + with open(fpath, 'w') as f: + json.dump(jsn, f, indent=4) + +def main(): + """ Main entry point """ + try: + Merger(Args()).merge() + except IOError as ex: + log.error(ex) + except WrongFormatException as ex: + log.error(ex) + +if __name__ == '__main__': + main() diff --git a/addons/lib/usr/local/bin/ocl_extended_test b/addons/lib/usr/local/bin/ocl_extended_test new file mode 100755 index 00000000..b7d8b085 Binary files /dev/null and b/addons/lib/usr/local/bin/ocl_extended_test differ diff --git a/addons/lib/usr/local/bin/ocl_unit_test b/addons/lib/usr/local/bin/ocl_unit_test new file mode 100755 index 00000000..9b2f713b Binary files /dev/null and b/addons/lib/usr/local/bin/ocl_unit_test differ diff --git a/addons/lib/usr/local/bin/pvr_memory_test b/addons/lib/usr/local/bin/pvr_memory_test new file mode 100755 index 00000000..361c844b Binary files /dev/null and b/addons/lib/usr/local/bin/pvr_memory_test differ diff --git a/addons/lib/usr/local/bin/pvr_mutex_perf_test_mx b/addons/lib/usr/local/bin/pvr_mutex_perf_test_mx new file mode 100755 index 00000000..a0ea3d2e Binary files /dev/null and b/addons/lib/usr/local/bin/pvr_mutex_perf_test_mx differ diff --git a/addons/lib/usr/local/bin/pvrdebug b/addons/lib/usr/local/bin/pvrdebug new file mode 100755 index 00000000..0fbfc647 Binary files /dev/null and b/addons/lib/usr/local/bin/pvrdebug differ diff --git a/addons/lib/usr/local/bin/pvrhtb2txt b/addons/lib/usr/local/bin/pvrhtb2txt new file mode 100755 index 00000000..62d95348 Binary files /dev/null and b/addons/lib/usr/local/bin/pvrhtb2txt differ diff --git a/addons/lib/usr/local/bin/pvrhtbd b/addons/lib/usr/local/bin/pvrhtbd new file mode 100755 index 00000000..db44d376 --- /dev/null +++ b/addons/lib/usr/local/bin/pvrhtbd @@ -0,0 +1,314 @@ +############################################################################### +# @File pvrhtbd +# @Title HTB Log dump tool +# @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +# @Description Script to execute a set of tests and collate the benchmark +# performance into a single report. +# @License Strictly Confidential. +############################################################################### + +usage() { + echo "" + echo "Usage: ./pvrhtbd [pvrdebug hostlog options and arguments]" + echo "Dump the processed output of the Host Trace Buffer to a file." + echo "" + echo "This tool starts a reader daemon, then applies any hostlog" + echo "configuration options." + echo "Data logging continues until is pressed to stop log capture" + echo "" + echo "There are two main use-cases supported by this tool:" + echo "Crash Logging:" + echo " Where the Host Trace Buffer has been configured via powervr.ini" + echo " to drop the oldest logs, this tool can be used without arguments" + echo " after the driver has crashed to capture the logs leading up to" + echo " the crash point." + echo "Continuous Logging:" + echo " The tool may be stated, applying any Host Trace configuration" + echo " options required and left running until the data required has" + echo " been captured." + echo " If the Host Trace Buffer size specified in powervr.ini is large" + echo " enough, and this tool started early enough putting the Host Trace" + echo " in blocking mode, it should be possible to capture all Host Trace" + echo " events" + echo "" + echo " -h, --help prints this message" + echo "" +} + +# write_cfg_file(tld_output_folder, cfg_file) +write_cfg_file() { +echo " +[pvrtld] +output_folder_name=$1 +output_type=file +omit_header=yes +output_file_save_previous=yes + +[PVRHTBuffer] +enabled=yes +output_file_name=$2 +wait_for_stream=yes +" > $3 +} + + +PVRINI_FILE="/etc/powervr.ini" + +TLD_CFG_FILE="htbtld.conf" +FIFO_FILE="tldctrl.fifo" + +HT_BASENAME="hosttrace" +HT_OUTFILE="${HT_BASENAME}.bin" +HOSTTRACE_FILE="${HT_BASENAME}.log" + +PVRDBG_DROPLATEST="-hostlogtype droplatest" +BLOCK_STR="block" +APPHINT_EN_STR="EnableHTBLogGroup" +PVRDEBUG_EN_STR="hostloggroups" +PVRDEBUG_ARGS="" + +GRAB_LOG=0 + +init() { + # detect os + if [ -x "/system/bin/logcat" ]; then + OS="Android" + elif [ -c "/dev/slog" ]; then + OS="QNX" + else + OS="Linux" + fi + echo "Detected OS: $OS" + + # set OS dependent variables here + if [ $OS = 'Android' ]; then + TMP_DIR="/data/local/tmp" + BIN_DIR="/system/vendor/bin" + TLD_BIN="$BIN_DIR/pvrtld" + PVRDEBUG_BIN="$BIN_DIR/pvrdebug" + HTB_BIN="$BIN_DIR/pvrhtb2txt" + elif [ $OS = 'QNX' ]; then + TMP_DIR="/tmp" + TLD_BIN="`command -v pvrtld`" + PVRDEBUG_BIN="`command -v pvrdebug`" + HTB_BIN="`command -v pvrhtb2txt`" + # QNX does not have /etc/powervr.ini by default. Check current directory first. + if [ -e "`pwd`/powervr.ini" ]; then + PVRINI_FILE="`pwd`/powervr.ini" + fi + else + TMP_DIR="/tmp" + TLD_BIN="`command -v \"pvrtld\"`" + PVRDEBUG_BIN="`command -v \"pvrdebug\"`" + HTB_BIN="`command -v \"pvrhtb2txt\"`" + fi + + if [ ! -x "$TLD_BIN" ]; then + echo "[Error] pvrtld not found" + exit 1 + fi + + if [ ! -x "$PVRDEBUG_BIN" ]; then + echo "[Error] pvrdebug not found" + exit 1 + fi + + if [ ! -x "$HTB_BIN" ]; then + echo "[Error] pvrhtb2txt not found" + exit 1 + fi + + if [ $OS = 'QNX' ]; then + # QNX not support creating folder in /tmp. User must cd to a mount point (NFS or external disk) + WORK_DIR="`pwd`/`date +pvrhtbd_%y%m%d%H%M`" + else + WORK_DIR="$TMP_DIR/`date +pvrhtbd_%y%m%d%H%M`" + fi + + mkdir -p $WORK_DIR + if [ $? -ne 0 ]; then + echo "Failed to create folder $WORK_DIR" + if [ $OS = 'QNX' ]; then + # Worst case that user do not have NFS mount or external disk. + echo + echo "Using $TMP_DIR as output directory" + echo -n "Old data files will be deleted. Press to continue..." + dd bs=1 count=1 2> /dev/null + + WORK_DIR=$TMP_DIR + + # Remove existing files + rm -f $WORK_DIR/$TLD_CFG_FILE + rm -f $WORK_DIR/$HT_OUTFILE + rm -f $WORK_DIR/$HOSTTRACE_FILE + else + exit 1 + fi + fi + # Should print out working variables + echo "TMP_DIR=$TMP_DIR" + echo "TLD_BIN=$TLD_BIN" + echo "PVRDEBUG_BIN=$PVRDEBUG_BIN" + echo "HTB_BIN=$HTB_BIN" + echo "WORK_DIR=$WORK_DIR" +} + + +arg_parse() { + arg_add=0 + for argument in "$@" + do + case "$argument" in + -hostloggroups|-hostlogmode|-hostlogtype|-hostloglevel) + PVRDEBUG_ARGS="$PVRDEBUG_ARGS $argument" + arg_add=1 + ;; + + -h|--help) + usage + exit 0 + ;; + + -g|--grab) + GRAB_LOG=1 + ;; + + *) + if [ "$arg_add" -eq "1" ]; then + PVRDEBUG_ARGS="$PVRDEBUG_ARGS $argument" + arg_add=0 + else + echo "[Error] Argument '$argument' not recognized." + echo " Run '$0 -h' for more information."; exit 1 + fi + ;; + esac + done +} + + +capture_hosttrace() { + # fifo to send keypress to backgrounded app + # mknod $WORK_DIR/$FIFO_FILE p + + # run pvrtld in background + # (redirecting stdout causes pvrtld to fail to write output) + #$TLD_BIN -f=$WORK_DIR/$TLD_CFG_FILE < $WORK_DIR/$FIFO_FILE & + $TLD_BIN -f=$WORK_DIR/$TLD_CFG_FILE & + proc_num=$! + sleep 3 + + # set the logging parameters as requested + # this has to be done after starting capture to support blocking logs + if [ ! -z "$PVRDEBUG_ARGS" ]; then + echo "Using pvrdebug to set logging parameters:" + echo " $PVRDEBUG_ARGS" + $PVRDEBUG_BIN $PVRDEBUG_ARGS + fi + + if [ "0" -eq "$GRAB_LOG" ]; then + # wait for a keypress (Android does not give a lot of options for this) + echo "Please press to stop log capture" + dd bs=1 count=1 2> /dev/null + else + sleep 3 + fi + + # safely stop if reading a blocking log + echo $PVRDEBUG_ARGS | grep -q "$BLOCK_STR" + if [ "0" -eq "$?" ]; then + echo "Using pvrdebug to reset logging parameters:" + echo " $PVRDBG_DROPLATEST" + $PVRDEBUG_BIN $PVRDBG_DROPLATEST + fi + + # stop pvrtld + #echo -n "x" > $WORK_DIR/$FIFO_FILE + #rm $WORK_DIR/$FIFO_FILE + echo "Stopping..." + kill -s QUIT $proc_num + + # wait some because pvrtld is slow to stop + sleep 3 + + if [ ! $OS = 'QNX' ]; then + # flush to disk + sync + fi +} + + +process_binfile() { + $HTB_BIN -bin $WORK_DIR/$HT_OUTFILE > $WORK_DIR/$HOSTTRACE_FILE + echo "Host Trace Data written to: $WORK_DIR/$HOSTTRACE_FILE" +} + + +perform_check() { + if [ -e $PVRINI_FILE ]; then + grep -q "$APPHINT_EN_STR" $PVRINI_FILE + app_en=$? + else + app_en=1 + fi + + echo $PVRDEBUG_ARGS > $WORK_DIR/args.tmp + grep -q "$PVRDEBUG_EN_STR" $WORK_DIR/args.tmp + arg_en=$? + + if [ "0" -ne "$app_en" -a "0" -ne "$arg_en" ]; then + echo "Host Trace Logging is not enabled in either:" + echo " $PVRINI_FILE" + echo " or cmdline args" + echo "Nothing will be captured" + exit 1 + fi +} + + +archive() { + if [ $OS = "Android" ]; then + if [ ! -x /system/bin/gzip ]; then + return + fi + else + if ! command gzip -h >/dev/null 2>&1; then + return + fi + fi + + echo -n "Archiving data ...................... " + gzip -f $OUT + echo "done" + echo "" + echo "File $OUT.gz was created." +} + + +run_main() { + echo "" + echo "========================== HTB Log Dump ============================" + + init + + arg_parse $@ + + perform_check + + write_cfg_file $WORK_DIR $HT_BASENAME $WORK_DIR/$TLD_CFG_FILE + + echo "" + echo "======================== Capturing HTB Log =========================" + capture_hosttrace + + echo "" + echo "======================== Write out HTB Log =========================" + process_binfile + + echo "" + echo "" +} + +# main function +run_main $@ + diff --git a/addons/lib/usr/local/bin/pvrhwperf b/addons/lib/usr/local/bin/pvrhwperf new file mode 100755 index 00000000..507c0803 --- /dev/null +++ b/addons/lib/usr/local/bin/pvrhwperf @@ -0,0 +1,488 @@ +OS="LINUX" +TMP_ROOT="/tmp" +TXT_READER=more +CAT_LOG=no +RETAIN_TL_HEADERS=no + +DEVICE="all" +DEVICES=0 +MIN_DEVICE_ID=0 +MAX_DEVICE_ID=15 + +HWPERF_FW_FILTER="" +HWPERF_HOST_FILTER="" + +HWPERF_RESET_STREAMS="false" + +HWPERF_V1CNT="false" + +if [ x"$PVRHWPERF_TMP" != x ]; then + if [ -d "$PVRHWPERF_TMP" ]; then + TMP_ROOT="$PVRHWPERF_TMP" + fi +fi + +if [ -x "/system/bin/logcat" ]; then + OS="ANDROID" + BIN_DIR=/system/vendor/bin + TMP_ROOT="/data/local/tmp" + TXT_READER=cat +fi + +TLD_RET= +EXEC_LINE="" +H2J_NAME="hwperfbin2jsont" +JSM_NAME="hwperfjsonmerge.py" + +if [ x"$OS" = xLINUX ]; then + PYTHON_BIN="`which \"python\"`" +fi + +# FUNCTIONS FOR SAVING AND RESTORING STATE +preserve_state() { + PVR_DBG_LEVEL_OLD="$PVRDebugLevel" + + for ID in $DEVICES; do + eval "_FW_FILTER_FILE=\$HWPERF_FW_FILTER_FILE_$ID" + if [ x"$HWPERF_FW_FILTER" != x ] && [ -f $_FW_FILTER_FILE ]; then + eval "HWPERF_FW_FILTER_${ID}_OLD=\"\$(cat $_FW_FILTER_FILE)\"" + fi + + eval "_HOST_FILTER_FILE=\$HWPERF_HOST_FILTER_FILE_$ID" + if [ x"$HWPERF_HOST_FILTER" != x ] && [ -f $_HOST_FILTER_FILE ]; then + eval "HWPERF_HOST_FILTER_${ID}_OLD=\"\$(cat $_HOST_FILTER_FILE)\"" + fi + done +} + +restore_state() { + export PVRDebugLevel=$PVR_DBG_LEVEL_OLD + + for ID in $DEVICES; do + eval "_FW_FILTER=\$HWPERF_FW_FILTER_${ID}_OLD" + eval "_FW_FILTER_FILE=\$HWPERF_FW_FILTER_FILE_${ID}" + if [ x"$_FW_FILTER" != x ]; then + echo $_FW_FILTER > $_FW_FILTER_FILE + fi + + eval "_HOST_FILTER=\$HWPERF_HOST_FILTER_${ID}_OLD" + eval "_HOST_FILTER_FILE=\$HWPERF_HOST_FILTER_FILE_${ID}" + + if [ x"$_HOST_FILTER" != x ]; then + echo $_HOST_FILTER > $_HOST_FILTER_FILE + fi + done +} + +OUT1_JSON_FILE_PREFIX="hwperf_fw_" +OUT2_JSON_FILE_PREFIX="hwperf_host_" +OUT_JSON_MERGE_FILE_PREFIX="hwperf_merge_" +# PARAMETERS PARSING +args="$@ dummy" +next= +skip_next="true" +for argument in $args +do + curr=$next + next=$argument + + if [ "$skip_next" = "true" ]; then + skip_next="false" + continue + fi + + case "$curr" in + -device) + DEVICE=$next + skip_next="true" + ;; + -t) EXEC_LINE=$H2J_NAME + OUT1_JSON_FILE_TMP=$OUT1_JSON_FILE_PREFIX"*.json" + OUT1_JSON_FILE="./" + OUT2_JSON_FILE_TMP=$OUT2_JSON_FILE_PREFIX"*.json" + OUT2_JSON_FILE="./" + OUT3_JSON_FILE_TMP="hwperf_client_*.json" + OUT3_JSON_DIR="./" + ;; + -rt) EXEC_LINE="$H2J_NAME $ -raw" + OUT1_JSON_FILE_TMP=$OUT1_JSON_FILE_PREFIX"*.raw.json" + OUT1_JSON_FILE="./" + OUT2_JSON_FILE_TMP=$OUT2_JSON_FILE_PREFIX"*.raw.json" + OUT2_JSON_FILE="./" + OUT3_JSON_FILE_TMP="hwperf_client_*.raw.json" + OUT3_JSON_DIR="./" + ;; + -m) OUT_JSON_MERGE_FILE_TMP=$OUT_JSON_MERGE_FILE_PREFIX"*.json" + OUT_JSON_MERGE_FILE="./" + ;; + -c) CAT_LOG=yes ;; + -h) echo "+-----------------------------------------------------------------------------+" + echo "| pvrhwperf : run pvrtld (Transport Layer Daemon) for gathering HWPerf data" + echo "|" + echo "| The HWPerf output data (firmware, host and client) is generated" + echo "| per-device and is segregated accordingly in files named:" + echo "| * hwperf_fw_.[bin/json]" + echo "| * hwperf_host_.[bin/json]" + echo "| * hwperf_client__.[bin/json]" + echo "| where is unique identifier for a GPU device." + echo "+-----------------------------------------------------------------------------+" + echo "| Usage:" + echo "| -device ID : Device ID (0-15 or \"all\") for which data will be captured" + echo "| (default \"all\"). If not specified or \"all\", data from all" + echo "| devices will be captured." + echo "| -t : Call hwperfbin2jsont (if present), to process the generated" + echo "| *.bin output files, after pvrtld end." + echo "| -rt : Call hwperfbin2jsont, adding the -raw parameter, to process the" + echo "| generated *.bin output files, after pvrtld end." + if [ x"$PYTHON_BIN" != x ]; then + echo "| -m : Call hwperfjsonmerge.py (if present), to merge generated *.json" + echo "| files (python interpreter required)." + fi + echo "| -c : Prints the log files to the std output just after pvrtld execution." + echo "| -h : Print this message." + echo "| -fw 0xFILTER : Specify a 64-bit hexadecimal filter value for FW events" + echo "| (original value is restored afterwards)." + echo "| -host 0xFILTER : Specify a 32-bit hexadecimal filter value for Server host" + echo "| host events (original value is restored afterwards)." + echo "| -r : Reset streams before capturing data." + echo "| -tlbin : In addition to regular data also retain packet headers" + echo "| in the binary file (generates *.tlbin files)." + echo "| -wa-v1cntids : Insert counter IDs alongside the performance counter" + echo "| values in the processed hwperfbin2jsont output." + echo "| NOTE: For Volcanic Drivers ONLY" + echo "+-----------------------------------------------------------------------------+" + exit 0 + ;; + -fw) HWPERF_FW_FILTER=$next + skip_next="true" + ;; + -host) HWPERF_HOST_FILTER=$next + skip_next="true" + ;; + -r) HWPERF_RESET_STREAMS="true" + ;; + -tlbin) RETAIN_TL_HEADERS=yes + ;; + -wa-v1cntids) + HWPERF_V1CNT="true" + ;; + *) echo "[Error] Argument '$curr' not recognized." + echo " Run '$0 -h' for more information."; exit 1 ;; + esac +done + + +# ENVIRONMENT CHECK +if [ x"$OS" = xANDROID ]; then + TLD_BIN="$BIN_DIR/pvrtld" + H2J_BIN="$BIN_DIR/$H2J_NAME" +else + TLD_BIN="`which \"pvrtld\"`" + H2J_BIN="`which \"$H2J_NAME\"`" + JSM_BIN="`which \"$JSM_NAME\"`" +fi + +if [ x"$DEVICE" != xall ]; then + if ! [ $DEVICE -ge $MIN_DEVICE_ID ] 2>/dev/null; then + echo "[Error] invalid device id" + exit 1 + fi + if ! [ $DEVICE -le $MAX_DEVICE_ID ] 2>/dev/null; then + echo "[Error] invalid device id" + exit 1 + fi +fi + +if [ ! -f "$TLD_BIN" ]; then + echo "[Error] pvrtld not found" + exit 1 +fi + +if [ x"$EXEC_LINE" != x ]; then + if [ ! -f "$H2J_BIN" ]; then + echo "[Error] hwperfbin2jsont not found" + exit 1 + fi + if [ "$HWPERF_V1CNT" = "true" ]; then + EXEC_LINE="$EXEC_LINE -wa-v1cntids" + fi +fi + +# ENVIRONMENT VARIABLES +WORK_DIR="$TMP_ROOT/hwperf/`date +%s`" +OUT1_JSON_FILE_TMP="$WORK_DIR/$OUT1_JSON_FILE_TMP" +OUT2_JSON_FILE_TMP="$WORK_DIR/$OUT2_JSON_FILE_TMP" +if [ -n "$OUT3_JSON_FILE_TMP" ]; then + OUT3_JSON_FILE_TMP="$WORK_DIR/$OUT3_JSON_FILE_TMP" +fi +OUT_JSON_MERGE_FILE_TMP="$WORK_DIR/$OUT_JSON_MERGE_FILE_TMP" +CFG_FILE=$WORK_DIR/"tld.conf" +TLD_LOG_FILE=$WORK_DIR/"tld.log" +HWP_LOG_FILE=$WORK_DIR/"hwp.log" +OUT1_FILE_TMP=$WORK_DIR/"hwperf_fw_*.*bin" +OUT2_FILE_TMP=$WORK_DIR/"hwperf_host_*.*bin" +OUT3_FILE_TMP=$WORK_DIR/"hwperf_client_*.*bin" +OUT1_FILE="./" +OUT2_FILE="./" +OUT3_DIR="./" + +# check if any filter is enabled first so that we can terminate before any +# filter is set +if [ x"$HWPERF_FW_FILTER" != x ] || [ x"$HWPERF_HOST_FILTER" != x ]; then + if [ x"$OS" = xANDROID ]; then + USERID=$USER_ID + else + USERID=`id -u` + fi + + # root privileges are needed to set filters - return error if executed + # as regular user + if [ "$USERID" != "0" ]; then + echo "[Error] This script needs to be executed with root privileges" + exit 1 + fi + + # if we have root privileges we can check for the debug files + if [ -d "/sys/kernel/debug/pvr" ]; then + DEBUG_DIR="/sys/kernel/debug/pvr" + elif [ -d "/proc/pvr" ]; then + DEBUG_DIR="/proc/pvr" + else + echo "Error: No valid debug path (Neither /sys/kernel/debug/pvr or /proc/pvr exist)" + exit 1 + fi +fi + +if [ x"$DEVICE" = xall ]; then + DEVICES=$(seq $MIN_DEVICE_ID $MAX_DEVICE_ID) +else + DEVICES=$DEVICE +fi + +# needs to be executed before "preserve_state" +for ID in $DEVICES; do + eval "HWPERF_FW_FILTER_FILE_$ID=\"$DEBUG_DIR/apphint/$ID/HWPerfFWFilter\"" + eval "HWPERF_HOST_FILTER_FILE_$ID=\"$DEBUG_DIR/apphint/$ID/HWPerfHostFilter\"" +done + +preserve_state + +export PVRDebugLevel=0x00 + +for ID in $DEVICES; do + eval "_FW_FILTER_FILE=\$HWPERF_FW_FILTER_FILE_$ID" + eval "_HOST_FILTER_FILE=\$HWPERF_HOST_FILTER_FILE_$ID" + + if [ x"$HWPERF_FW_FILTER" != x ] || [ x"$HWPERF_HOST_FILTER" != x ]; then + if [ x"$HWPERF_FW_FILTER" != x ]; then + if [ ! -f $_FW_FILTER_FILE ] && [ x"$DEVICE" != xall ]; then + echo "[Error] Could not set HW performance events filter" + restore_state + exit 1 + fi + + echo $HWPERF_FW_FILTER 2>/dev/null > $_FW_FILTER_FILE 2>/dev/null + if [ $? != 0 ] && [ x"$DEVICE" != xall ]; then + echo "[Error] Failed to set HW performance filter" + echo " Check if the parameters passed to the script are valid" + restore_state + exit 1 + fi + fi + + if [ x"$HWPERF_HOST_FILTER" != x ]; then + if [ ! -f $_HOST_FILTER_FILE ] && [ x"$DEVICE" != xall ]; then + echo "[Error] Could not set host events filter" + restore_state + exit 1 + fi + + echo $HWPERF_HOST_FILTER 2>/dev/null > $_HOST_FILTER_FILE 2>/dev/null + if [ $? != 0 ] && [ x"$DEVICE" != xall ]; then + echo "[Error] Failed to set host events filter" + echo " Check if the parameters passed to the script are valid" + restore_state + exit 1 + fi + fi + fi +done + +# ENVIRONMENT SETUP +# - Create working directory +mkdir -p $WORK_DIR + +# - Create configuration file +echo "[pvrtld] +output_folder_name=$WORK_DIR +output_file_save_previous=yes" > $CFG_FILE + +if [ "$RETAIN_TL_HEADERS" = "yes" ]; then +echo "omit_header=no" >> $CFG_FILE +else +echo "omit_header=yes" >> $CFG_FILE +fi + +echo " +[tlctrl] +enabled=yes +wait_for_stream=yes +ctrl_stream=yes + +[hwperf_fw_] +enabled=yes +discover=yes +wait_for_stream=yes +server_block_nodata=no" >> $CFG_FILE + +# - Add the post processing command if the tool exists +if [ x"$H2J_BIN" != x ] && [ x"$EXEC_LINE" != x ]; then +echo "exec=\"$EXEC_LINE\"" >> $CFG_FILE +fi + +if [ "$HWPERF_RESET_STREAMS" = "true" ]; then +echo "reset_on_open=\"yes\"" >> $CFG_FILE +fi + +if [ x"$DEVICE" != xall ]; then +echo "device=$DEVICE" >> $CFG_FILE +fi + +echo " +[hwperf_host_] +enabled=yes +discover=yes +wait_for_stream=yes" >> $CFG_FILE + +# - Add the post processing command if the tool exists +if [ x"$H2J_BIN" != x ] && [ x"$EXEC_LINE" != x ]; then +echo "exec=\"$EXEC_LINE\"" >> $CFG_FILE +fi + +if [ "$HWPERF_RESET_STREAMS" = "true" ]; then +echo "reset_on_open=\"yes\"" >> $CFG_FILE +fi + +if [ x"$DEVICE" != xall ]; then +echo "device=$DEVICE" >> $CFG_FILE +fi + +echo " +[hwperf_client_] +enabled=yes +discover=yes" >> $CFG_FILE + +# - Add the post processing command if the tool exists +if [ x"$H2J_BIN" != x ] && [ x"$EXEC_LINE" != x ]; then +echo "exec=\"$EXEC_LINE\"" >> $CFG_FILE +fi + +if [ "$HWPERF_RESET_STREAMS" = "true" ]; then +echo "reset_on_open=\"yes\"" >> $CFG_FILE +fi + +if [ x"$DEVICE" != xall ]; then +echo "device=$DEVICE" >> $CFG_FILE +fi + +# EXECUTION +echo "+-----------------------------------------------------------------------------+" +echo "| Starting capture of HWPerf data..." +echo "+-----------------------------------------------------------------------------+" +echo "| Using these temporary files:" +echo "| - TLDaemon configuration file: $CFG_FILE" +echo "| - TLDaemon log file: $TLD_LOG_FILE" +echo "| - HWPerf binary file(s): $OUT1_FILE_TMP" +echo "| - HWPerfHost binary file(s): $OUT2_FILE_TMP" +echo "| - HWPerfClient binary file(s): $OUT3_FILE_TMP" +if [ x"$H2J_BIN" = x ] || [ x"$EXEC_LINE" = x ]; then + echo "| - No JSON output selected" +else + echo "| - HWPerf raw json file(s): $OUT1_JSON_FILE_TMP" + echo "| - HWPerfHost raw json file(s): $OUT2_JSON_FILE_TMP" + echo "| - HWPerfClient raw json file: $OUT3_JSON_FILE_TMP" + if [ x"$JSM_BIN" != x ] && [ x"$PYTHON_BIN" != x ] && [ x"$OUT_JSON_MERGE_FILE" != x ]; then + echo "| - HWPerf merged json file(s): $OUT_JSON_MERGE_FILE_TMP" + fi + echo "| - JSON conversion log file: $TLD_LOG_FILE" +fi +echo "+-----------------------------------------------------------------------------+" + +$TLD_BIN -f=$CFG_FILE -q -s 2> $TLD_LOG_FILE +TLD_RET=$? + +# LAST MESSAGES +if [ "$TLD_RET" -ne "0" ]; then + echo "+-----------------------------------------------------------------------------+" + echo "| Capture process exited with error code $TLD_RET" +else + out1filecnt=$(ls $OUT1_FILE_TMP 2>>$HWP_LOG_FILE | wc -l 2>>$HWP_LOG_FILE) + out2filecnt=$(ls $OUT2_FILE_TMP 2>>$HWP_LOG_FILE | wc -l 2>>$HWP_LOG_FILE) + out3filecnt=$(ls $OUT3_FILE_TMP 2>>$HWP_LOG_FILE | wc -l 2>>$HWP_LOG_FILE) + if [ $out1filecnt -ne 0 ] || [ $out2filecnt -ne 0 ] || [ $out3filecnt -ne 0 ]; then + if [ x"$OUT1_JSON_FILE" != x ]; then + out1jsonlist=$(ls $OUT1_JSON_FILE_TMP 2>>$HWP_LOG_FILE) + out1jsonfilecnt=$(ls $OUT1_JSON_FILE_TMP 2>>$HWP_LOG_FILE | wc -l 2>>$HWP_LOG_FILE) + fi + if [ x"$OUT2_JSON_FILE" != x ]; then + out2jsonfilecnt=$(ls $OUT2_JSON_FILE_TMP 2>>$HWP_LOG_FILE | wc -l 2>>$HWP_LOG_FILE) + fi + if [ x"$JSM_BIN" != x ] && [ x"$PYTHON_BIN" != x ] && [ x"$OUT_JSON_MERGE_FILE" != x ]; then + echo "+-----------------------------------------------------------------------------+" + echo "| Merging JSON files..." + echo "+-----------------------------------------------------------------------------+" + for i in $out1jsonlist; do + DEVICE_ID_POSTFIX=$(echo $i | sed -n /.*$OUT1_JSON_FILE_PREFIX/s/.*$OUT1_JSON_FILE_PREFIX//p) + $PYTHON_BIN $JSM_BIN -d $WORK_DIR -f $OUT1_JSON_FILE_PREFIX$DEVICE_ID_POSTFIX \ + -s $OUT2_JSON_FILE_PREFIX$DEVICE_ID_POSTFIX \ + -o $WORK_DIR/$OUT_JSON_MERGE_FILE_PREFIX$DEVICE_ID_POSTFIX + done + fi + echo "+-----------------------------------------------------------------------------+" + echo "| Data captured, files moved to CWD." + if [ $out1filecnt -ne 0 ]; then + mv $OUT1_FILE_TMP $OUT1_FILE + fi + if [ x"$OUT1_JSON_FILE" != x ] && [ $out1jsonfilecnt -ne 0 ]; then + mv $OUT1_JSON_FILE_TMP $OUT1_JSON_FILE + fi + if [ $out2filecnt -ne 0 ]; then + mv $OUT2_FILE_TMP $OUT2_FILE + fi + if [ x"$OUT2_JSON_FILE" != x ] && [ $out2jsonfilecnt -ne 0 ]; then + mv $OUT2_JSON_FILE_TMP $OUT2_JSON_FILE + fi + if [ x"$OUT_JSON_MERGE_FILE" != x ]; then + if [ $(ls $OUT_JSON_MERGE_FILE_TMP | wc -l 2>>$HWP_LOG_FILE) -ne 0 ]; then + mv $OUT_JSON_MERGE_FILE_TMP $OUT_JSON_MERGE_FILE + fi + fi + if ls $OUT3_FILE_TMP >>$HWP_LOG_FILE 2>&1; then + mv $OUT3_FILE_TMP $OUT3_DIR + if [ -n "$OUT3_JSON_FILE_TMP" ] && ls $OUT3_JSON_FILE_TMP >>$HWP_LOG_FILE 2>&1; then + mv $OUT3_JSON_FILE_TMP $OUT3_JSON_DIR + fi + fi + else + echo "+-----------------------------------------------------------------------------+" + echo "| No data captured, binary files do not exist." + fi +fi + +# Give time for the Log file to be flushed to disk +sync +if [ "$CAT_LOG" = "yes" ]; then + echo "+-----------------------------------------------------------------------------+" + echo "| TLDaemon debug log file..." + echo "| $TXT_READER $TLD_LOG_FILE" + echo "+-----------------------------------------------------------------------------+" + $TXT_READER $TLD_LOG_FILE + echo "+-----------------------------------------------------------------------------+" + echo "| pvrhwperf debug log file..." + echo "| $TXT_READER $HWP_LOG_FILE" + echo "+-----------------------------------------------------------------------------+" + $TXT_READER $HWP_LOG_FILE +fi +echo "+-----------------------------------------------------------------------------+" + +restore_state diff --git a/addons/lib/usr/local/bin/pvrlogdump b/addons/lib/usr/local/bin/pvrlogdump new file mode 100755 index 00000000..76e1f5c4 --- /dev/null +++ b/addons/lib/usr/local/bin/pvrlogdump @@ -0,0 +1,729 @@ +################################################################################ +# @Copyright Copyright (c) Imagination Technologies Ltd. +# All Rights Reserved +# @License MIT +# +# The contents of this file are subject to the MIT license as set out below. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +################################################################################ + +ARGC=$# +ARGV=$1 + +# snapshot timestamp used to determine how much time passed since last +# call to snapshot +SSTS=0 + +usage() { + echo "" + echo "Usage: $0 [OPTIONS | APP_NAME]" + echo "Gathers diagnostic information for IMG." + echo "If APP_NAME is specified also gather diagnostics on that specific app." + echo "Note that APP_NAME should contain full path to the app binary." + echo "" + echo " -h, --help prints this message" + echo "" +} + +log_timestamp() { + local ts="$(cat /proc/uptime)" + + echo "" + if [ -z "$1" ]; then + echo "[TS: ${ts% *}]" + else + echo "[TS ($1): ${ts% *}]" + fi + echo "" +} + +init() { + # detect os + if [ -x "/system/bin/logcat" ]; then + OS="Android" + elif [ -d "/var/log/ui" ]; then + OS="Chrome" + else + OS="Linux" + fi + + if [ $OS = 'Android' ]; then + USERID=$USER_ID + # grep's '-o' option is not POSIX compliant but since this case is + # Android specific and it's supported we don't care + VER_MAJOR=$(getprop ro.build.version.release | grep -oE "^[[:digit:]]+") + # we assume major.minor version format which is used since Android 5 + # major part is always correct + VER_MINOR=$(getprop ro.build.version.release | grep -oE "[[:digit:]]+$") + else + USERID=`id -u` + fi + + if [ "$USERID" != "0" ]; then + echo "This script needs to be executed with root privileges." + exit 1 + fi + + if [ "$ARGC" -gt "1" ]; then + echo "Error: Too many arguments." + usage + exit 1 + fi + + if [ "$ARGV" = "--help" ] || [ "$ARGV" = "-h" ]; then + usage + exit 0 + fi + + # output file + if [ -d /tmp ]; then + OUT=/tmp/`date +pvrlogdump_%y%m%d%H%M.txt` + else + OUT=`date +pvrlogdump_%y%m%d%H%M.txt` + fi + + # some useful variables + DEBUGFS_PATH=/sys/kernel/debug + if [ -d $DEBUGFS_PATH/pvr ]; then + PVR_DEBUGFS_PATH=$DEBUGFS_PATH/pvr + elif [ -d /proc/pvr ]; then + PVR_DEBUGFS_PATH=/proc/pvr + fi + + if [ -d $DEBUG_PATH ]; then + FTRACE_PATH=$DEBUGFS_PATH/tracing + elif [ -d /sys/kernel/tracing ]; then + FTRACE_PATH=/sys/kernel/tracing + fi + + LOCKDEP_PATH=/proc/lockdep + PVRINI_PATH=/etc/powervr.ini + INSTKMLOG_PATH=/etc/powervr_ddk_install_km.log + INSTUMLOG_PATH=/etc/powervr_ddk_install_um.log + + if [ "$ARGC" -eq "1" ]; then + APPNAME=$ARGV + fi +} + +perform_check() { + echo -n "Checking driver state ............... " + if [ -d $PVR_DEBUGFS_PATH ]; then + LOADED=true + DRIVER_STATE="initialised" + else + if [ -d /sys/module/pvrsrvkm ]; then + LOADED=true + DRIVER_STATE="loaded" + else + LOADED=false + DRIVER_STATE="not loaded" + fi + fi + + echo "$DRIVER_STATE" + if [ "$LOADED" = "false" ]; then + echo " Driver is not loaded. Not all crucial information can be" + echo " gathered in that state. Please consider running the driver." + fi + + echo -n "Checking for debugfs ................ " + if [ -d $PVR_DEBUGFS_PATH ]; then + echo "found" + else + echo "not found" + fi + + echo -n "Checking for lockdep ................ " + if [ -f $LOCKDEP_PATH ]; then + echo "found" + else + echo "not found" + fi + + echo -n "Checking for ftrace ................. " + if [ -d $FTRACE_PATH ]; then + echo "found" + else + echo "not found" + fi + + echo -n "Checking for firmware log groups .... " + local FW_LOG_GROUPS_EN=false + if [ -f $PVR_DEBUGFS_PATH/apphint/0/EnableLogGroup ] && \ + [ $(cat $PVR_DEBUGFS_PATH/apphint/0/EnableLogGroup) != "none" ]; then + FW_LOG_GROUPS_EN=true + else + if [ -f $PVRINI_PATH ]; then + if [ -n "$(grep -E ^EnableLogGroup.+[#\;]* $PVRINI_PATH)" ]; then + FW_LOG_GROUPS_EN=true + fi + fi + fi + if [ "$FW_LOG_GROUPS_EN" = "true" ]; then + echo "found" + else + echo "not found" + echo " There are no AppHints enabled in $PVRINI_PATH or in debugfs" + echo " for any of the firmware log groups. Unless 'pvrdebug' tool" + echo " was used for that purpose there will be no information in" + echo " firmware log." + echo " Please consider enabling some of the firmware log groups" + echo " before the problem occurs." + fi +} + +dump_env_info() { + echo "" + echo "===== Dumping environment info ======================================" + echo "" + + log_timestamp + + echo "Date:" `date` + echo "/proc/version:" `cat /proc/version` + + echo "" + echo "Driver state: $DRIVER_STATE" + + echo "" + echo "env:" + export -p + + echo "" + echo "lsmod:" + lsmod + + echo "" + echo "/cpu/info" + cat /proc/cpuinfo + + echo "" + echo "/proc/meminfo" + cat /proc/meminfo + + if [ $OS = "Linux" ]; then + echo "" + echo "lshw" + lshw -quiet + fi +} + +dump_installation_log() { + echo "" + echo "===== Dumping powervr_ddk_install_km.log ============================" + echo "" + + log_timestamp + + if [ -f $INSTKMLOG_PATH ]; then + cat $INSTKMLOG_PATH + else + echo "Not found" + fi + + echo "" + echo "===== Dumping powervr_ddk_install_um.log ============================" + echo "" + + if [ -f $INSTUMLOG_PATH ]; then + head $INSTUMLOG_PATH + else + echo "Not found" + fi +} + +dump_apphints() { + echo "" + echo "===== Dumping powervr.ini ===========================================" + echo "" + + log_timestamp + + if [ -f $PVRINI_PATH ]; then + cat $PVRINI_PATH + else + echo "Not found" + fi +} + +dump_fw_snapshot() { + echo "" + echo "===== Dumping fw snapshot ===========================================" + echo "" + + log_timestamp + + if [ $SSTS -eq 0 ]; then + # save current time for the next call + SSTS=$(date +%s) + else + local DIFF=$(($(date +%s) - $SSTS)) + if [ $DIFF -lt 3 ]; then + # wait before making 2nd snapshot + sleep 2; + fi + fi + + # handle multidevice case where there can be per device (gpuXX) + # subdirectories + local DEVICES="$(ls -d $PVR_DEBUGFS_PATH/gpu* 2>/dev/null)" + if [ -z "$DEVICES" ]; then + local DEVICES="$PVR_DEBUGFS_PATH" + fi + + for PVR_DEBUGFS_DEVICE_PATH in $DEVICES; do + local DEVICE_ID=$(basename $PVR_DEBUGFS_DEVICE_PATH) + local FW_TRACE=$(readlink -f $PVR_DEBUGFS_DEVICE_PATH)/firmware_trace + local DEBUG_DUMP=$(readlink -f $PVR_DEBUGFS_DEVICE_PATH)/debug_dump + + # in case the script is run on an older DDK with no device subdirs + if [ "${DEVICE_ID}" = "pvr" ]; then + local DEVICE_ID="gpu00" + fi + + for IDX in 1 2; do + # if there is a firmware log file dump it for our convenience + if [ -f $FW_TRACE ]; then + echo "" + echo "==== firmware_trace ($DEVICE_ID, $IDX) ====" + echo "" + cat $FW_TRACE + fi + + # if there is debug_dump file then dump it but if for some reason + # it's absent use dmesg to obtain it + if [ -f $DEBUG_DUMP ]; then + echo "" + echo "==== debug_dump ($DEVICE_ID, $IDX) ====" + echo "" + cat $DEBUG_DUMP + else + echo "" + echo "==== dmesg ($DEVICE_ID, $IDX) ====" + echo "" + if [ -c /dev/kmsg ]; then + echo "" >/dev/kmsg + echo "==== debug_dump ($DEVICE_ID, $IDX) ====" >/dev/kmsg + echo "" >/dev/kmsg + fi + if command -v pvrdebug >/dev/null 2>&1; then + if ! pvrdebug -dd >/dev/null 2>&1; then + if [ -c /dev/kmsg ]; then + echo "pvrdebug failed" >/dev/kmsg + fi + fi + fi + dmesg + fi + + # skip sleep on last iteration + if [ $IDX -ne 2 ]; then + # Android, ChromeOS and most Linux distributions accept time as + # a floating point number so wait for 10ms + # but e.g. busybox supports only integers so wait for 1s + if ! sleep 0.01 >/dev/null 2>&1; then sleep 1; fi + fi + done + done +} + +dump_dmesg() { + echo "" + echo "===== Dumping dmesg =================================================" + echo "" + + log_timestamp + + dmesg + + # even if debugfs exists dump firmware log to dmesg because + # there may be some additional information that are not present in debugfs + if command pvrdebug >/dev/null 2>&1; then + if [ "$LOADED" = "true" ]; then + echo "" + echo "===== Running pvrdebug -dd then dumping dmesg =======================" + echo "" + pvrdebug -dd >/dev/null 2>&1 + dmesg + fi + fi +} + +dump_debugfs() { + local BLACKLIST=" + $PVR_DEBUGFS_PATH/rgxregs + " + + echo "" + echo "===== Dumping files from pvr debugfs ================================" + echo "" + + log_timestamp + + if [ -d $PVR_DEBUGFS_PATH ]; then + # android below version 6 (Marshmallow) doesn't have 'find' command + if [ $OS = "Android" ] && [ $VER_MAJOR -lt 6 ]; then + ls -FR $PVR_DEBUGFS_PATH | while read FILE; do + if echo $FILE | grep / >/dev/null 2>&1; then + # save last found full directory path + DIR=$FILE + continue + fi + if echo $FILE | grep -E "^d .+" >/dev/null 2>&1; then + # ignore as it is a subdirectory + continue + fi + if echo $FILE | grep -E "^- .+" >/dev/null 2>&1; then + echo -e "\n==== ${DIR%:}/${FILE#- } ====\n" + cat ${DIR%:}/${FILE#- } + fi + done + else + local FILES="`find $PVR_DEBUGFS_PATH -type f`" + for FILE in $FILES; do + local IGNORE=false + for ELEMENT in $BLACKLIST; do + if [ $ELEMENT = $FILE ]; then + IGNORE=true + break + fi + done + + if [ "$IGNORE" = "true" ]; then + continue + fi + + echo "" + echo "==== $FILE ====" + echo "" + cat $FILE + done + fi + else + echo "Not found" + fi +} + +# check if SurfaceFlinger is running +# this function is Android-specific +android_check_surfaceflinger_running() { + # 'dumpsys -l' will return a list of all services running. + # use grep to see if SurfaceFlinger is running. + dumpsys -l | grep SurfaceFlinger >/dev/null 2>&1 + + # return the exit code from grep. + # if SurfaceFlinger was found in the services list then grep will have + # exited with exit code 0 (true) + return $? +} + +dump_android() { + echo "" + echo "===== Dumping android logs ==========================================" + echo "" + + log_timestamp + + if [ -x /system/bin/logcat ]; then + echo "" + echo "==== android/logcat ====" + echo "" + logcat -d + fi + + if [ -x /system/bin/dumpsys ]; then + echo "" + echo "==== android/dumpsys ====" + echo "" + android_check_surfaceflinger_running + if [ $? = 0 ]; then + dumpsys + else + echo "Android services not running. dumpsys skipped." + fi + fi + + # NOTE: It might be worth to call also dumpstate (which runs procrank) here + # but procrank causes some of the targets to crash. It's left out for now. +} + +dump_chrome() { + echo "" + echo "===== Dumping ChromeOS UI logs ======================================" + echo "" + + log_timestamp + + local UILOGS="/var/log/chrome/chrome /home/chronos/user/log/chrome \ + /var/log/ui/ui.LATEST" + + for FILE in $UILOGS; do + echo "" + echo "==== $FILE ====" + echo "" + + if [ -f $FILE ]; then + cat $FILE + else + echo "Not found" + fi + done +} + +dump_native_sync_info() { + echo "" + echo "==== Dumping native syncs info ======================================" + echo "" + + log_timestamp + + if [ -f $DEBUGFS_PATH/sync ]; then + echo "" + echo "==== $DEBUGFS_PATH/sync ====" + echo "" + cat $DEBUGFS_PATH/sync + elif [ -f $DEBUGFS_PATH/sync/info ]; then + echo "" + echo "==== $DEBUGFS_PATH/sync/info ====" + echo "" + cat $DEBUGFS_PATH/sync/info + else + echo "Not found" + fi +} + +dump_lockdep() { + echo "" + echo "===== Dumping lockdep related files =================================" + echo "" + + log_timestamp + + if [ -f $LOCKDEP_PATH ]; then + local FILES="/proc/lockdep_stats $LOCKDEP_PATH /proc/lockdep_chains" + + for FILE in $FILES; do + echo "" + echo "==== $FILE ====" + echo "" + + if [ -f $FILE ]; then + cat $FILE + else + echo "Not found" + fi + done + else + echo "Not found" + fi +} + +dump_ftrace() { + echo "" + echo "===== Dumping ftrace files ==========================================" + echo "" + + log_timestamp + + if [ -d $FTRACE_PATH ]; then + local FILES="$FTRACE_PATH/trace $FTRACE_PATH/trace_clock \ + $FTRACE_PATH/tracing_on $FTRACE_PATH/buffer_size_kb \ + $FTRACE_PATH/buffer_total_size_kb" + + for FILE in $FILES; do + echo "" + echo "==== $FILE ====" + echo "" + + if [ -f $FILE ]; then + cat $FILE + else + echo "Not found" + fi + done + + if [ -d $FTRACE_PATH/per_cpu ]; then + local PERCPU_FILES="buffer_size_kb stats" + for CPU in `ls $FTRACE_PATH/per_cpu`; do + for FILE in $PERCPU_FILES; do + echo "" + echo "==== $FTRACE_PATH/per_cpu/$CPU/$FILE ====" + echo "" + + if [ -f $FTRACE_PATH/per_cpu/$CPU/$FILE ]; then + cat $FTRACE_PATH/per_cpu/$CPU/$FILE + else + echo "Not found" + fi + done + done + fi + else + echo "Not found" + fi +} + +dump_pvrhtb() { + echo "" + echo "===== Dumping HTB trace file ========================================" + echo "" + + log_timestamp + + if ! command pvrhtbd -h >/dev/null 2>&1; then + return + fi + + TMP_HTB_FILE="pvrhtbd_output" + if [ "$OS" = "Android" ]; then + TMP_HTB_FILE="/data/local/tmp/$TMP_HTB_FILE" + else + TMP_HTB_FILE="/tmp/$TMP_HTB_FILE" + fi + + if [ "$LOADED" = "true" ]; then + pvrhtbd --grab > $TMP_HTB_FILE 2>&1 + + HTBD_OUT_FILE=`grep "Host Trace Data written to" $TMP_HTB_FILE` + + # if we fail to parse the output and find the file name then + # add this information to the output, in addition to + # the output from pvrhtbd so we can see any errors it printed + if [ -z "$HTBD_OUT_FILE" ]; then + echo "Failed to get pvrhtbd output file name. Command output" + echo "follows." + cat $TMP_HTB_FILE + rm $TMP_HTB_FILE + return + fi + + HTBD_OUT_FILE=${HTBD_OUT_FILE#Host Trace Data written to: } + rm $TMP_HTB_FILE + + if [ -f $HTBD_OUT_FILE ]; then + cat $HTBD_OUT_FILE + fi + fi +} + +dump_app_info() { + echo "" + echo "===== Dumping app info ==============================================" + echo "" + + log_timestamp + + if [ -f "$APPNAME" ]; then + echo "Analysing $APPNAME" + if [ -f `dirname $APPNAME`/powervr.ini ]; then + echo `dirname $APPNAME`/powervr.ini + cat `dirname $APPNAME`/powervr.ini + fi + echo "" + echo "Checking nature of $APPNAME:" + file $APPNAME + echo + echo "Checking linkage of $APPNAME:" + ldd $APPNAME + else + if [ -n "$APPNAME" ]; then + echo "Not app with name '$APPNAME' exists." + echo "" + fi + + if [ -f /usr/local/bin/gltest1 ]; then + echo "Checking linkage of gltest1:" + ldd /usr/local/bin/gltest1 + fi + if [ -f /usr/local/bin/gles1test1 ]; then + echo "" + echo "Checking linkage of gles1test1:" + ldd /usr/local/bin/gles1test1 + fi + if [ -f /usr/local/bin/xgltest1 ]; then + echo "" + echo "Checking linkage of xgltest1:" + ldd /usr/local/bin/xgltest1 + fi + if [ -f /usr/local/bin/xgles1test1 ]; then + echo "" + echo "Checking linkage of xgles1test1:" + ldd /usr/local/bin/xgles1test1 + fi + fi +} + +dump_all() { + echo "" + echo -n "Dumping data ........................ " + log_timestamp "START" >> $OUT + dump_env_info >> $OUT 2>&1 + dump_installation_log >> $OUT + dump_apphints >> $OUT + dump_fw_snapshot >> $OUT + dump_dmesg >> $OUT + dump_pvrhtb >> $OUT + dump_debugfs >> $OUT 2>&1 + if [ $OS = "Android" ]; then + dump_android >> $OUT 2>&1 + fi + if [ $OS = "Chrome" ]; then + dump_chrome >> $OUT 2>&1 + fi + dump_native_sync_info >> $OUT 2>&1 + dump_lockdep >> $OUT + dump_ftrace >> $OUT + dump_app_info >> $OUT + dump_fw_snapshot >> $OUT + log_timestamp "END" >> $OUT + echo "done" +} + +archive() { + if [ $OS = "Android" ]; then + if [ ! -x /system/bin/gzip ]; then + return + fi + else + if ! command -v gzip >/dev/null 2>&1; then + return + fi + fi + + echo -n "Archiving data ...................... " + gzip -f $OUT + echo "done" + echo "" + echo "File $OUT.gz was created." +} + +main() { + init + + touch $OUT + + perform_check + dump_all + archive +} + +# main function +main diff --git a/addons/lib/usr/local/bin/pvrlogsplit b/addons/lib/usr/local/bin/pvrlogsplit new file mode 100755 index 00000000..a8152efd --- /dev/null +++ b/addons/lib/usr/local/bin/pvrlogsplit @@ -0,0 +1,547 @@ +#!/usr/bin/python + +import sys, os +import os.path as pu # path utils +import struct +import gzip +import re +from getopt import getopt, GetoptError +from tempfile import mkdtemp, NamedTemporaryFile +from subprocess import Popen, STDOUT, PIPE + +usage = """ +Usage: + %s [OPTION] logfile + +Script parses output file from 'pvrlogdump' and stores separate files +in a temporary location. + +'logfile' can be either in txt format or in gzip format. + +If 'tracebuf' tool is not in PATH it has to be define with --tracebuf option. + +Options: + -h, --help prints this message + -v verbose + --keeptree keeps directory structure of debugfs, and lockdep + --movehere moves created temporary directory to current CWD + --dumpfwlog prints decoded firmware log + --dumpregs prints decoded firmware registers + --tracebuf= path to 'tracebuf' tool, if not given tracebuf + needs to be in PATH +""" % (pu.basename(sys.argv[0])) + +# internal options +""" +If 'regdecode' tool is not in PATH it has to be define with --regdecode option. + +Note: If 'regdecode' fails due to missing *.h file, please refer to 'regdecode' +help about ROGUEDDK_ROOT variable. + + --regdecode= path to 'regdecode' tool, if not given regdecode + needs to be in PATH +""" + +def is_gzip(filepath): + """Returns True if file is a gzip archive and False otherwise""" + try: + with open(filepath, "rb") as f: + mn = f.read(2) + except Exception as ex: + raise ex + + ext = filepath.split('.')[-1] + + # gzip magic number is 0x1f8b + if mn == '\x1f\x8b' and ext == 'gz': + return True + else: + return False + +def is_exec(filepath): + """Returns True if command is executable. This function looks + either in PATH env or in a destination if fullpath is provided""" + if not filepath: + return False + + if pu.isfile(filepath) and os.access(filepath, os.X_OK): + return True + else: + for path in os.environ['PATH'].split(os.pathsep): + fexec = pu.join(path.strip('"'), filepath) + if pu.isfile(fexec) and os.access(fexec, os.X_OK): + return True + return False + +class Executor: + """Utility class for running various external tools""" + def __init__(self): + self._args = Args() + self._output = None + self._status = None + + def tracebuf(self, filepath): + """Runs 'tracebuf' tool""" + path = self._args.get_tracebuf_path() + proc = Popen([path, '-txt', filepath], + stdout = PIPE, stderr = STDOUT, universal_newlines = True) + self._output = proc.communicate()[0] + self._status = proc.returncode + + def regdecode(self, filepath): + """Runs 'regdecode' tool""" + path = self._args.get_regdecode_path() + proc = Popen([path, '-d', filepath], + stdout = PIPE, stderr = STDOUT, universal_newlines = True) + self._output = proc.communicate()[0] + self._status = proc.returncode + + def get_output(self): + return self._output + + def get_status(self): + return self._status + +class Section: + def __init__(self, name): + self._name = name + self._content = list() + + def __str__(self): + return 'Section: ' + self._name + + def append(self, text): + self._content.append(text) + + def get_name(self): + return self._name + + def get_content(self): + return self._content + +class SubLog: + def __init__(self, section): + self._args = Args() + self._section = section + + def dump(self, tmpdir): + name = self._section.get_name() + '.txt' + if self._args.is_verbose(): + print('Dumping file ' + pu.join(tmpdir, name)) + with open(pu.join(tmpdir, name), 'w') as f: + for line in self._section.get_content(): + f.write(line) + +class FilesListLog(SubLog): + def __init__(self, section): + SubLog.__init__(self, section) + + self._re_filepath = re.compile('[=]{4}\s([\w/]+)\s[=]{4}') + + self._files = dict() + self._parse() + + def _parse(self): + current = None + for line in self._section.get_content(): + result = self._re_filepath.match(line) + if result: + current = result.group(1)[1:] if result.group(1)[0] == os.sep \ + else result.group(1) + self._files[current] = list() + continue + if current: + self._files[current].append(line) + + def dump(self, tmpdir): + for name in self._files.keys(): + if self._args.keeptree(): + if not pu.isdir(pu.join(tmpdir, pu.dirname(name))): + try: + os.makedirs(pu.join(tmpdir, pu.dirname(name))) + except OSError as ex: + print('Error: ' + str(ex)) + filename = name + else: + filename = name.replace(os.sep, '_') + if self._args.is_verbose(): + print('Dumping file ' + pu.join(tmpdir, filename + '.txt')) + with open(pu.join(tmpdir, filename + '.txt'), 'w') as f: + self.dump_file(name, outfile = f) + + def dump_file(self, filename, outfile = sys.stdout): + for line in self._files[filename]: + outfile.write(line) + outfile.flush() + + def has_file(self, filename): + return any(filename in s for s in self._files.keys()) + +class DebugFsLog(FilesListLog): + _DEBUG_PATH = '' + + def __init__(self, section): + FilesListLog.__init__(self, section) + self._exec = Executor() + + self._re_fwreg_line = re.compile('.*:\s*0x[\dA-Fa-f]+.+') + + debug_paths = ['/sys/kernel/debug/pvr', '/proc/pvr'] + + for path in debug_paths: + if os.path.exists(path): + self._DEBUG_PATH = path + break + else: + print("Failed to find valid debug path.") + + def dumpfwlog(self, outfile = sys.stdout): + if self.has_file(self._DEBUG_PATH + '/firmware_trace'): + self.dump_file(self._DEBUG_PATH + '/firmware_trace', + outfile = outfile) + elif self.has_file(self._DEBUG_PATH + '/debug_dump'): + tmpfile = NamedTemporaryFile(mode = 'w+', prefix = 'fwlog_') + self.dump_file(self._DEBUG_PATH + '/debug_dump', outfile = tmpfile) + self._exec.tracebuf(tmpfile.name) + + if self._exec.get_status() == 0: + outfile.write(self._exec.get_output()) + else: + outfile.write('Error: tracebuf returned error status (%d).' + % self._exec.get_status()) + else: + outfile.write('Error: Could not find firmware log.') + outfile.flush() + + def dumpregs(self, outfile = sys.stdout): + tmpfile = NamedTemporaryFile(mode = 'w+', prefix = 'fwlog_') + self.dump_file(self._DEBUG_PATH + '/debug_dump', outfile = tmpfile) + self._exec.regdecode(tmpfile.name) + + if self._exec.get_status() == 0: + outfile.write(self._exec.get_output()) + else: + outfile.write('Error: regdecode returned error status (%d).' + % self._exec.get_status()) + outfile.flush() + +class DmesgLog(SubLog): + def __init__(self, section): + SubLog.__init__(self, section) + self._exec = Executor() + + self._re_fwdump_line = re.compile('.*PVR_K.*FWT\[\d+\]:\s[\w\s]+') + self._re_fwreg_line = re.compile('.*PVR_K.*:\s*0x[\dA-Fa-f]+.*') + + def dumpfwlog(self, outfile = sys.stdout): + content = '' + tmpfile = NamedTemporaryFile(mode = 'w+', prefix = 'fwlog_') + for line in self._section.get_content(): + result = self._re_fwdump_line.match(line) + if result: + content += line + + if not content: + outfile.write('Error: Could not find firmware log.') + return + + tmpfile.write(content) + tmpfile.flush() + + self._exec.tracebuf(tmpfile.name) + if self._exec.get_status() == 0: + outfile.write(self._exec.get_output()) + else: + outfile.write('Error: tracebuf returned error status (%d).' + % self._exec.get_status()) + outfile.flush() + + def dumpregs(self, outfile = sys.stdout): + content = '' + tmpfile = NamedTemporaryFile(mode = 'w+', prefix = 'fwlog_') + for line in self._section.get_content(): + result = self._re_fwreg_line.match(line) + if result: + content += line + + if not content: + print('Error: Could not find firmware log.') + return + + tmpfile.write(content) + tmpfile.flush() + + self._exec.regdecode(tmpfile.name) + if self._exec.get_status() == 0: + outfile.write(self._exec.get_output()) + else: + outfile.write('Error: tracebuf returned error status (%d).' + % self._exec.get_status()) + outfile.flush() + +class Log: + def __init__(self, logpath): + self._args = Args() + self._logpath = logpath + self._log = None + self._sections = list() + + self._re_section = re.compile('[=]{5}\sDumping\s([\w\s\.\_]+)[=]+') + + self._read_log() + + def _read_log(self): + if is_gzip(self._logpath): + fopen = gzip.open + else: + fopen = open + + try: + with fopen(self._logpath, "r") as fin: + current = None + for line in fin: + result = self._re_section.match(line) + if result: + name = result.group(1).strip().replace(' ', '_') + current = Section(name) + self._sections.append(current) + if current: + current.append(line) + except IOError as ex: + print('Error: ' + str(ex)) + exit(1) + + def dump_all(self, tmpdir): + for section in self._sections: + filelist_sections = ['lockdep', 'ftrace', 'android'] + if any(substr in section.get_name() for substr in filelist_sections): + log = FilesListLog(section) + log.dump(tmpdir) + elif 'debugfs' in section.get_name(): + log = DebugFsLog(section) + log.dump(tmpdir) + self._dumpfwlog_tofile(log, tmpdir, 'debugfs') + self._dumpregs_tofile(log, tmpdir, 'debugfs') + elif 'dmesg' in section.get_name(): + log = DmesgLog(section) + log.dump(tmpdir) + self._dumpfwlog_tofile(log, tmpdir, 'dmesg') + self._dumpregs_tofile(log, tmpdir, 'dmesg') + else: + log = SubLog(section) + log.dump(tmpdir) + + def _dumpfwlog_tofile(self, log, tmpdir, prefix): + filename = pu.join(tmpdir, prefix + '_tracebuf.txt') + if not self._args.is_tracebuf_exec(): + print('Warning: tracebuf has not been found (please see option' + ' "--tracebuf"). "%s" will not be created.' % filename) + return + + if self._args.is_verbose(): + print('Dumping file ' + filename) + with open(filename, 'w') as fout: + log.dumpfwlog(fout) + + def _dumpregs_tofile(self, log, tmpdir, prefix): + filename = pu.join(tmpdir, prefix + '_regdecode.txt') + if not self._args.is_regdecode_exec(): + # don't print warning as this is an internal option + + # print('Warning: regdecode has not been found. "%s" will not be ' + # 'created.' % filename) + return + + if self._args.is_verbose(): + print('Dumping file ' + filename) + with open(filename, 'w') as fout: + log.dumpregs(fout) + + def dumpfwlog(self): + if any(('debugfs' in s.get_name()) for s in self._sections): + section = (s for s in self._sections if 'debugfs' in s.get_name())\ + .next() + log = DebugFsLog(section) + log.dumpfwlog() + elif any(('dmesg' in section.get_name()) for section in self._sections): + section = (s for s in self._sections if 'dmesg' in s.get_name())\ + .next() + log = DmesgLog(section) + log.dumpfwlog() + else: + print("Could not find firmware log") + + def dumpregs(self): + if any(('debugfs' in s.get_name()) for s in self._sections): + section = (s for s in self._sections if 'debugfs' in s.get_name())\ + .next() + log = DebugFsLog(section) + log.dumpregs() + elif any(('dmesg' in section.get_name()) for section in self._sections): + section = (s for s in self._sections if 'dmesg' in s.get_name())\ + .next() + log = DmesgLog(section) + log.dumpregs() + else: + print("Could not find firmware log") + +class Args: + """Represents command line options.""" + + _args = None + _opts = None + + _verbose = False + _dumpfwlog = False + _dumpregs = False + _keeptree = False + _move2cwd = False + _tracebuf_path = '' + _regdecode_path = '' + _logpath = None + _logname = None + _is_tracebuf_exec = False + _is_regdecode_exec = False + + def __init__(self): + if not Args._opts and not Args._args: + self._getopts() + self._parse_opts() + self._parse_args() + self._validate() + + def _getopts(self): + try: + longOpts = ['help', 'tracebuf=', 'regdecode=', + 'dumpfwlog', 'dumpregs', 'keeptree', 'movehere'] + shortOpts = 'hv' + Args._opts, Args._args = getopt(sys.argv[1:], shortOpts, longOpts) + except GetoptError as ex: + print('Error: ' + str(ex)) + print(usage) + exit(1) + + def _parse_opts(self): + for opt, arg in Args._opts: + if opt in ('-h', '--help'): + print(usage) + exit(0) + elif opt in ('-v'): + Args._verbose = True + elif opt in ('--withreg'): + Args._withreg = True + elif opt in ('--dumpfwlog'): + Args._dumpfwlog = True + elif opt in ('--dumpregs'): + Args._dumpregs = True + elif opt in ('--tracebuf'): + Args._tracebuf_path = pu.expanduser(arg) + elif opt in ('--regdecode'): + Args._regdecode_path = pu.expanduser(arg) + elif opt in ('--keeptree'): + Args._keeptree = True + elif opt in ('--movehere'): + Args._move2cwd = True + else: + print('Unhandled option') + exit(1) + + def _parse_args(self): + if not Args._args: + print('Error: No input file given.') + print(usage) + exit(1) + + if len(Args._args) > 1: + print('Error: Wrong number of parameters passed.') + print(usage) + exit(1) + + if not pu.isfile(Args._args[0]): + print('Error: %s is not a file.' % Args._args[0]) + exit(1) + + Args._logpath = Args._args[0] + Args._logname = pu.basename(Args._args[0]).split('.')[0] + + def _validate(self): + is_exe1 = is_exec(Args._regdecode_path) + is_exe2 = is_exec(pu.join(Args._regdecode_path, 'regdecode.py')) + if is_exe1 or is_exe2: + Args._is_regdecode_exec = True + if not is_exec(Args._regdecode_path): + Args._regdecode_path = pu.join(Args._regdecode_path, + 'regdecode.py') + elif Args._dumpregs: + print('Error: regdecode.py tool is not a valid executable. Please' + + ' use --regdecode option to set valid path.') + exit(1) + + if is_exec(Args._tracebuf_path) or is_exec(pu.join(Args._tracebuf_path, + 'tracebuf')): + Args._is_tracebuf_exec = True + if not is_exec(Args._tracebuf_path): + Args._tracebuf_path = pu.join(Args._tracebuf_path, 'tracebuf') + elif Args._dumpfwlog: + print('Error: tracebuf tool is not a valid executable. Please' + + ' use --tracebuf option to set valid path.') + exit(1) + + def get_logpath(self): + return Args._logpath + + def get_logname(self): + return Args._logname + + def get_tracebuf_path(self): + return Args._tracebuf_path + + def get_regdecode_path(self): + return Args._regdecode_path + + def dumpfwlog(self): + return Args._dumpfwlog + + def dumpregs(self): + return Args._dumpregs + + def keeptree(self): + return Args._keeptree + + def move2cwd(self): + return Args._move2cwd + + def is_verbose(self): + return Args._verbose + + def is_tracebuf_exec(self): + return Args._is_tracebuf_exec + + def is_regdecode_exec(self): + return Args._is_regdecode_exec + +def main(): + args = Args() + + log = Log(args.get_logpath()) + if args.dumpfwlog(): + log.dumpfwlog() + elif args.dumpregs(): + log.dumpregs() + else: + tmpdir = mkdtemp(prefix = args.get_logname() + '_') + print('Temporary directory created: ' + tmpdir) + log.dump_all(tmpdir) + + if args.move2cwd(): + # try to move the directory to CWD + cwd = os.getcwd() + try: + import shutil + shutil.move(tmpdir, cwd) + print('Temporary directory "%s" moved to "%s".' % (tmpdir, cwd)) + except: + print('Warning: Could not move "%s" to "%s".' % (tmpdir, cwd)) + +if __name__ == "__main__": + main() diff --git a/addons/lib/usr/local/bin/pvrsrvctl b/addons/lib/usr/local/bin/pvrsrvctl new file mode 100755 index 00000000..d3ce1931 Binary files /dev/null and b/addons/lib/usr/local/bin/pvrsrvctl differ diff --git a/addons/lib/usr/local/bin/pvrtld b/addons/lib/usr/local/bin/pvrtld new file mode 100755 index 00000000..9cff5393 Binary files /dev/null and b/addons/lib/usr/local/bin/pvrtld differ diff --git a/addons/lib/usr/local/bin/rgx_blit_test b/addons/lib/usr/local/bin/rgx_blit_test new file mode 100755 index 00000000..beef3171 Binary files /dev/null and b/addons/lib/usr/local/bin/rgx_blit_test differ diff --git a/addons/lib/usr/local/bin/rgx_compute_test b/addons/lib/usr/local/bin/rgx_compute_test new file mode 100755 index 00000000..e58e0137 Binary files /dev/null and b/addons/lib/usr/local/bin/rgx_compute_test differ diff --git a/addons/lib/usr/local/bin/rgx_kicksync_test b/addons/lib/usr/local/bin/rgx_kicksync_test new file mode 100755 index 00000000..a48edb17 Binary files /dev/null and b/addons/lib/usr/local/bin/rgx_kicksync_test differ diff --git a/addons/lib/usr/local/bin/rgx_triangle_test b/addons/lib/usr/local/bin/rgx_triangle_test new file mode 100755 index 00000000..7fcea1e9 Binary files /dev/null and b/addons/lib/usr/local/bin/rgx_triangle_test differ diff --git a/addons/lib/usr/local/bin/rgx_twiddling_test b/addons/lib/usr/local/bin/rgx_twiddling_test new file mode 100755 index 00000000..3e569e30 Binary files /dev/null and b/addons/lib/usr/local/bin/rgx_twiddling_test differ diff --git a/addons/lib/usr/local/bin/rogue2d_fbctest b/addons/lib/usr/local/bin/rogue2d_fbctest new file mode 100755 index 00000000..9449a823 Binary files /dev/null and b/addons/lib/usr/local/bin/rogue2d_fbctest differ diff --git a/addons/lib/usr/local/bin/rogue2d_unittest b/addons/lib/usr/local/bin/rogue2d_unittest new file mode 100755 index 00000000..9838d3fc Binary files /dev/null and b/addons/lib/usr/local/bin/rogue2d_unittest differ diff --git a/readme b/readme new file mode 100644 index 00000000..623ac93d --- /dev/null +++ b/readme @@ -0,0 +1,17 @@ +Steps: +1, build-chain prepare + https://occ-oss-prod.oss-cn-hangzhou.aliyuncs.com/resource/1836682/1640771208032/Xuantie-900-gcc-linux-5.10.4-glibc-x86_64-V2.2.4-20211227.tar.gz + set PATH env, for example: + PATH=$PATH:/path/to/build-chain/bin +2, build kernel + git clone git@gitee.com:openanolis/riscv-cloud-kernel.git + cd riscv-cloud-kernel + git checkout devel-5.10 + make -j16 CROSS_COMPILE=riscv64-unknown-linux-gnu- ARCH=riscv light_defconfig + make -j16 CROSS_COMPILE=riscv64-unknown-linux-gnu- ARCH=riscv +3, set KERNELDIR env as the kernel dir + for example: + export KERNELDIR=/path/to/anolis/riscv-cloud-kernel/ +4, just run "make" +5, get the files in output dir +6, run "make clean" to do the cleanup diff --git a/rogue_km/kernel/drivers/staging/imgtec/plato/plato_drv.c b/rogue_km/kernel/drivers/staging/imgtec/plato/plato_drv.c index 5bab0b74..ee9503f9 100644 --- a/rogue_km/kernel/drivers/staging/imgtec/plato/plato_drv.c +++ b/rogue_km/kernel/drivers/staging/imgtec/plato/plato_drv.c @@ -91,7 +91,7 @@ static struct pci_driver plato_pci_driver = { }; module_pci_driver(plato_pci_driver); -MODULE_DEVICE_TABLE(pci, plato_pci_tbl); +//MODULE_DEVICE_TABLE(pci, plato_pci_tbl); static struct plato_debug_register plato_noc_regs[] = { {"NOC Offset 0x00", 0x00, 0}, diff --git a/rogue_km/kernel/drivers/staging/imgtec/tc/drm_pdp_drv.c b/rogue_km/kernel/drivers/staging/imgtec/tc/drm_pdp_drv.c index 7b12b1ca..0cdeb904 100644 --- a/rogue_km/kernel/drivers/staging/imgtec/tc/drm_pdp_drv.c +++ b/rogue_km/kernel/drivers/staging/imgtec/tc/drm_pdp_drv.c @@ -880,5 +880,5 @@ module_platform_driver(pdp_platform_driver); MODULE_AUTHOR("Imagination Technologies Ltd. "); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_DEVICE_TABLE(platform, pdp_platform_device_id_table); +//MODULE_DEVICE_TABLE(platform, pdp_platform_device_id_table); MODULE_LICENSE("Dual MIT/GPL"); diff --git a/rogue_km/kernel/drivers/staging/imgtec/tc/tc_drv.c b/rogue_km/kernel/drivers/staging/imgtec/tc/tc_drv.c index fd9ba461..c69498fd 100644 --- a/rogue_km/kernel/drivers/staging/imgtec/tc/tc_drv.c +++ b/rogue_km/kernel/drivers/staging/imgtec/tc/tc_drv.c @@ -666,7 +666,7 @@ static struct pci_driver tc_pci_driver = { module_pci_driver(tc_pci_driver); -MODULE_DEVICE_TABLE(pci, tc_pci_tbl); +//MODULE_DEVICE_TABLE(pci, tc_pci_tbl); int tc_enable(struct device *dev) { diff --git a/rogue_km/services/server/env/linux/pvr_platform_drv.c b/rogue_km/services/server/env/linux/pvr_platform_drv.c index b1586c9b..172f8e52 100644 --- a/rogue_km/services/server/env/linux/pvr_platform_drv.c +++ b/rogue_km/services/server/env/linux/pvr_platform_drv.c @@ -259,7 +259,7 @@ static const struct of_device_id pvr_of_ids[] = { }; #if !defined(CHROMIUMOS_KERNEL) || !defined(MODULE) -MODULE_DEVICE_TABLE(of, pvr_of_ids); +//MODULE_DEVICE_TABLE(of, pvr_of_ids); #endif #endif @@ -271,7 +271,7 @@ static struct platform_device_id pvr_platform_ids[] = { }; #if !defined(CHROMIUMOS_KERNEL) || !defined(MODULE) -MODULE_DEVICE_TABLE(platform, pvr_platform_ids); +//MODULE_DEVICE_TABLE(platform, pvr_platform_ids); #endif static struct platform_driver pvr_platform_driver = { diff --git a/tools/prepare.sh b/tools/prepare.sh index ab269d0d..67fd3c2c 100755 --- a/tools/prepare.sh +++ b/tools/prepare.sh @@ -1,16 +1,16 @@ #!/bin/bash -if [ ! -d $1/usr/local ]; then - echo "Install libdrm in the $SYSROOT" - cd tools/drm/libdrm-2.4.101/riscv64-unknown-linux-gnu-binaries/ - DESTDIR="$SYSROOT" sudo -E ninja install -# sudo -E make -C libdrm-2.4.99/riscv64-unknown-linux-gnu-binaries DESTDIR="$SYSROOT" install - sudo cp $1/usr/local/lib/riscv64-unknown-linux-gnu $1/usr/local/lib/riscv64-linux-gnu -rf - cd - - cd $2 - make INSTALL_MOD_PATH=$3 modules_install - cd - -fi +#if [ ! -d $1/usr/local ]; then +# echo "Install libdrm in the $SYSROOT" +# cd tools/drm/libdrm-2.4.101/riscv64-unknown-linux-gnu-binaries/ +# DESTDIR="$SYSROOT" sudo -E ninja install +## sudo -E make -C libdrm-2.4.99/riscv64-unknown-linux-gnu-binaries DESTDIR="$SYSROOT" install +# sudo cp $1/usr/local/lib/riscv64-unknown-linux-gnu $1/usr/local/lib/riscv64-linux-gnu -rf +# cd - +# cd $2 +# make INSTALL_MOD_PATH=$3 modules_install +# cd - +#fi if [ ! -d tools/mips-mti-elf ]; then echo "unzip the MIPS TOOLCHAIN" diff --git a/tools/prepare_driver.sh b/tools/prepare_driver.sh new file mode 100755 index 00000000..4e54022c --- /dev/null +++ b/tools/prepare_driver.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +cd $1 +make INSTALL_MOD_PATH=$2 modules_install +cd -