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