1b8e80941Smrg/* 2b8e80941Smrg * Copyright (C) 2019 Alyssa Rosenzweig 3b8e80941Smrg * 4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5b8e80941Smrg * copy of this software and associated documentation files (the "Software"), 6b8e80941Smrg * to deal in the Software without restriction, including without limitation 7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the 9b8e80941Smrg * Software is furnished to do so, subject to the following conditions: 10b8e80941Smrg * 11b8e80941Smrg * The above copyright notice and this permission notice (including the next 12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the 13b8e80941Smrg * Software. 14b8e80941Smrg * 15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20b8e80941Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21b8e80941Smrg * SOFTWARE. 22b8e80941Smrg * 23b8e80941Smrg */ 24b8e80941Smrg 25b8e80941Smrg#include <stdio.h> 26b8e80941Smrg#include <stdlib.h> 27b8e80941Smrg#include <stdbool.h> 28b8e80941Smrg#include <panfrost-job.h> 29b8e80941Smrg#include "pan_trace.h" 30b8e80941Smrg#include "util/list.h" 31b8e80941Smrg 32b8e80941Smrg/* The pandecode utility is capable of parsing a command stream trace and 33b8e80941Smrg * disassembling any referenced shaders. Traces themselves are glorified memory 34b8e80941Smrg * dumps, a directory consisting of .bin's for each memory segment, and a 35b8e80941Smrg * simple plain-text description of the interesting kernel activity. 36b8e80941Smrg * Historically, these dumps have been produced via panwrap, an LD_PRELOAD shim 37b8e80941Smrg * sitting between the driver and the kernel. However, for modern Panfrost, we 38b8e80941Smrg * can just produce the dumps ourselves, which is rather less fragile. This 39b8e80941Smrg * file (pantrace) implements this functionality. */ 40b8e80941Smrg 41b8e80941Smrgstatic FILE *pan_control_log; 42b8e80941Smrgstatic const char *pan_control_base; 43b8e80941Smrg 44b8e80941Smrg/* Represent the abstraction for a single mmap chunk */ 45b8e80941Smrg 46b8e80941Smrgstatic unsigned pantrace_memory_count = 0; 47b8e80941Smrg 48b8e80941Smrgstruct pantrace_memory { 49b8e80941Smrg struct list_head node; 50b8e80941Smrg 51b8e80941Smrg mali_ptr gpu; 52b8e80941Smrg void *cpu; 53b8e80941Smrg size_t sz; 54b8e80941Smrg char *full_filename; 55b8e80941Smrg}; 56b8e80941Smrg 57b8e80941Smrgstatic struct pantrace_memory mmaps; 58b8e80941Smrg 59b8e80941Smrgvoid 60b8e80941Smrgpantrace_initialize(const char *base) 61b8e80941Smrg{ 62b8e80941Smrg /* Open the control.log */ 63b8e80941Smrg char fn[128]; 64b8e80941Smrg snprintf(fn, 128, "%s/control.log", base); 65b8e80941Smrg pan_control_log = fopen(fn, "w+"); 66b8e80941Smrg assert(pan_control_log); 67b8e80941Smrg 68b8e80941Smrg /* Save the base for later */ 69b8e80941Smrg pan_control_base = base; 70b8e80941Smrg 71b8e80941Smrg /* Initialize the mmap list */ 72b8e80941Smrg list_inithead(&mmaps.node); 73b8e80941Smrg} 74b8e80941Smrg 75b8e80941Smrgstatic bool 76b8e80941Smrgpantrace_is_initialized(void) 77b8e80941Smrg{ 78b8e80941Smrg return pan_control_log && pan_control_base; 79b8e80941Smrg} 80b8e80941Smrg 81b8e80941Smrg/* Traces a submitted job with a given job chain, core requirements, and 82b8e80941Smrg * platform */ 83b8e80941Smrg 84b8e80941Smrgvoid 85b8e80941Smrgpantrace_submit_job(mali_ptr jc, unsigned core_req, unsigned is_bifrost) 86b8e80941Smrg{ 87b8e80941Smrg if (!pantrace_is_initialized()) 88b8e80941Smrg return; 89b8e80941Smrg 90b8e80941Smrg fprintf(pan_control_log, "JS %" PRIx64 " %x %x\n", 91b8e80941Smrg jc, core_req, is_bifrost); 92b8e80941Smrg fflush(pan_control_log); 93b8e80941Smrg} 94b8e80941Smrg 95b8e80941Smrg/* Dumps a given mapped memory buffer with the given label. If no label 96b8e80941Smrg * is given (label == NULL), one is created */ 97b8e80941Smrg 98b8e80941Smrgvoid 99b8e80941Smrgpantrace_mmap(mali_ptr gpu, void *cpu, size_t sz, char *label) 100b8e80941Smrg{ 101b8e80941Smrg if (!pantrace_is_initialized()) 102b8e80941Smrg return; 103b8e80941Smrg 104b8e80941Smrg char *filename = NULL; 105b8e80941Smrg char *full_filename = NULL; 106b8e80941Smrg 107b8e80941Smrg /* Create a filename based on the label or count */ 108b8e80941Smrg 109b8e80941Smrg if (label) { 110b8e80941Smrg asprintf(&filename, "%s.bin", label); 111b8e80941Smrg } else { 112b8e80941Smrg asprintf(&filename, "memory_%d.bin", pantrace_memory_count++); 113b8e80941Smrg } 114b8e80941Smrg 115b8e80941Smrg /* Emit an mmap for it */ 116b8e80941Smrg fprintf(pan_control_log, "MMAP %" PRIx64 " %s\n", gpu, filename); 117b8e80941Smrg fflush(pan_control_log); 118b8e80941Smrg 119b8e80941Smrg /* Dump the memory itself */ 120b8e80941Smrg asprintf(&full_filename, "%s/%s", pan_control_base, filename); 121b8e80941Smrg free(filename); 122b8e80941Smrg 123b8e80941Smrg struct pantrace_memory *mem = malloc(sizeof(*mem)); 124b8e80941Smrg list_inithead(&mem->node); 125b8e80941Smrg mem->gpu = gpu; 126b8e80941Smrg mem->cpu = cpu; 127b8e80941Smrg mem->sz = sz; 128b8e80941Smrg mem->full_filename = full_filename; 129b8e80941Smrg list_add(&mem->node, &mmaps.node); 130b8e80941Smrg} 131b8e80941Smrg 132b8e80941Smrg/* Dump all memory at once, once everything has been written */ 133b8e80941Smrg 134b8e80941Smrgvoid 135b8e80941Smrgpantrace_dump_memory(void) 136b8e80941Smrg{ 137b8e80941Smrg if (!pantrace_is_initialized()) 138b8e80941Smrg return; 139b8e80941Smrg 140b8e80941Smrg list_for_each_entry(struct pantrace_memory, pos, &mmaps.node, node) { 141b8e80941Smrg /* Save the mapping */ 142b8e80941Smrg FILE *fp = fopen(pos->full_filename, "wb"); 143b8e80941Smrg fwrite(pos->cpu, 1, pos->sz, fp); 144b8e80941Smrg fclose(fp); 145b8e80941Smrg } 146b8e80941Smrg} 147