xref: /aosp_15_r20/external/skia/src/sksl/tracing/SkSLDebugTracePlayer.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2021 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker #ifndef SkSLDebugTracePlayer_DEFINED
8*c8dee2aaSAndroid Build Coastguard Worker #define SkSLDebugTracePlayer_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/tracing/SkSLDebugTracePriv.h"
11*c8dee2aaSAndroid Build Coastguard Worker 
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/utils/SkBitSet.h"
15*c8dee2aaSAndroid Build Coastguard Worker 
16*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
17*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
18*c8dee2aaSAndroid Build Coastguard Worker #include <optional>
19*c8dee2aaSAndroid Build Coastguard Worker #include <unordered_map>
20*c8dee2aaSAndroid Build Coastguard Worker #include <unordered_set>
21*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
22*c8dee2aaSAndroid Build Coastguard Worker 
23*c8dee2aaSAndroid Build Coastguard Worker namespace SkSL {
24*c8dee2aaSAndroid Build Coastguard Worker 
25*c8dee2aaSAndroid Build Coastguard Worker /**
26*c8dee2aaSAndroid Build Coastguard Worker  * Plays back a SkSL debug trace, allowing its contents to be viewed like a traditional debugger.
27*c8dee2aaSAndroid Build Coastguard Worker  */
28*c8dee2aaSAndroid Build Coastguard Worker class SkSLDebugTracePlayer {
29*c8dee2aaSAndroid Build Coastguard Worker public:
30*c8dee2aaSAndroid Build Coastguard Worker     /** Resets playback to the start of the trace. Breakpoints are not cleared. */
31*c8dee2aaSAndroid Build Coastguard Worker     void reset(sk_sp<DebugTracePriv> trace);
32*c8dee2aaSAndroid Build Coastguard Worker 
33*c8dee2aaSAndroid Build Coastguard Worker     /** Advances the simulation to the next Line op. */
34*c8dee2aaSAndroid Build Coastguard Worker     void step();
35*c8dee2aaSAndroid Build Coastguard Worker 
36*c8dee2aaSAndroid Build Coastguard Worker     /**
37*c8dee2aaSAndroid Build Coastguard Worker      * Advances the simulation to the next Line op, skipping past matched Enter/Exit pairs.
38*c8dee2aaSAndroid Build Coastguard Worker      * Breakpoints will also stop the simulation even if we haven't reached an Exit.
39*c8dee2aaSAndroid Build Coastguard Worker      */
40*c8dee2aaSAndroid Build Coastguard Worker     void stepOver();
41*c8dee2aaSAndroid Build Coastguard Worker 
42*c8dee2aaSAndroid Build Coastguard Worker     /**
43*c8dee2aaSAndroid Build Coastguard Worker      * Advances the simulation until we exit from the current stack frame.
44*c8dee2aaSAndroid Build Coastguard Worker      * Breakpoints will also stop the simulation even if we haven't left the stack frame.
45*c8dee2aaSAndroid Build Coastguard Worker      */
46*c8dee2aaSAndroid Build Coastguard Worker     void stepOut();
47*c8dee2aaSAndroid Build Coastguard Worker 
48*c8dee2aaSAndroid Build Coastguard Worker     /** Advances the simulation until we hit a breakpoint, or the trace completes. */
49*c8dee2aaSAndroid Build Coastguard Worker     void run();
50*c8dee2aaSAndroid Build Coastguard Worker 
51*c8dee2aaSAndroid Build Coastguard Worker     /** Breakpoints will force the simulation to stop whenever a desired line is reached. */
52*c8dee2aaSAndroid Build Coastguard Worker     void setBreakpoints(std::unordered_set<int> breakpointLines);
53*c8dee2aaSAndroid Build Coastguard Worker     void addBreakpoint(int line);
54*c8dee2aaSAndroid Build Coastguard Worker     void removeBreakpoint(int line);
55*c8dee2aaSAndroid Build Coastguard Worker     using BreakpointSet = std::unordered_set<int>;
getBreakpoints()56*c8dee2aaSAndroid Build Coastguard Worker     const BreakpointSet& getBreakpoints() { return fBreakpointLines; }
57*c8dee2aaSAndroid Build Coastguard Worker 
58*c8dee2aaSAndroid Build Coastguard Worker     /** Returns true if we have reached the end of the trace. */
59*c8dee2aaSAndroid Build Coastguard Worker     bool traceHasCompleted() const;
60*c8dee2aaSAndroid Build Coastguard Worker 
61*c8dee2aaSAndroid Build Coastguard Worker     /** Returns true if there is a breakpoint set at the current line. */
62*c8dee2aaSAndroid Build Coastguard Worker     bool atBreakpoint() const;
63*c8dee2aaSAndroid Build Coastguard Worker 
64*c8dee2aaSAndroid Build Coastguard Worker     /** Retrieves the cursor position. */
cursor()65*c8dee2aaSAndroid Build Coastguard Worker     size_t cursor() { return fCursor; }
66*c8dee2aaSAndroid Build Coastguard Worker 
67*c8dee2aaSAndroid Build Coastguard Worker     /** Retrieves the current line. */
68*c8dee2aaSAndroid Build Coastguard Worker     int32_t getCurrentLine() const;
69*c8dee2aaSAndroid Build Coastguard Worker 
70*c8dee2aaSAndroid Build Coastguard Worker     /** Retrieves the current line for a given stack frame. */
71*c8dee2aaSAndroid Build Coastguard Worker     int32_t getCurrentLineInStackFrame(int stackFrameIndex) const;
72*c8dee2aaSAndroid Build Coastguard Worker 
73*c8dee2aaSAndroid Build Coastguard Worker     /** Returns the call stack as an array of FunctionInfo indices. */
74*c8dee2aaSAndroid Build Coastguard Worker     std::vector<int> getCallStack() const;
75*c8dee2aaSAndroid Build Coastguard Worker 
76*c8dee2aaSAndroid Build Coastguard Worker     /** Returns the size of the call stack. */
77*c8dee2aaSAndroid Build Coastguard Worker     int getStackDepth() const;
78*c8dee2aaSAndroid Build Coastguard Worker 
79*c8dee2aaSAndroid Build Coastguard Worker     /**
80*c8dee2aaSAndroid Build Coastguard Worker      * Returns every line number reached inside this debug trace, along with the remaining number of
81*c8dee2aaSAndroid Build Coastguard Worker      * times that this trace will reach it. e.g. {100, 2} means line 100 will be reached twice.
82*c8dee2aaSAndroid Build Coastguard Worker      */
83*c8dee2aaSAndroid Build Coastguard Worker     using LineNumberMap = std::unordered_map<int, int>;
getLineNumbersReached()84*c8dee2aaSAndroid Build Coastguard Worker     const LineNumberMap& getLineNumbersReached() const { return fLineNumbers; }
85*c8dee2aaSAndroid Build Coastguard Worker 
86*c8dee2aaSAndroid Build Coastguard Worker     /** Returns variables from a stack frame, or from global scope. */
87*c8dee2aaSAndroid Build Coastguard Worker     struct VariableData {
88*c8dee2aaSAndroid Build Coastguard Worker         int     fSlotIndex;
89*c8dee2aaSAndroid Build Coastguard Worker         bool    fDirty;  // has this slot been written-to since the last step call?
90*c8dee2aaSAndroid Build Coastguard Worker         double  fValue;  // value in slot (with type-conversion applied)
91*c8dee2aaSAndroid Build Coastguard Worker     };
92*c8dee2aaSAndroid Build Coastguard Worker     std::vector<VariableData> getLocalVariables(int stackFrameIndex) const;
93*c8dee2aaSAndroid Build Coastguard Worker     std::vector<VariableData> getGlobalVariables() const;
94*c8dee2aaSAndroid Build Coastguard Worker 
95*c8dee2aaSAndroid Build Coastguard Worker private:
96*c8dee2aaSAndroid Build Coastguard Worker     /**
97*c8dee2aaSAndroid Build Coastguard Worker      * Executes the trace op at the passed-in cursor position. Returns true if we've reached a line
98*c8dee2aaSAndroid Build Coastguard Worker      * or exit trace op, which indicate a stopping point.
99*c8dee2aaSAndroid Build Coastguard Worker      */
100*c8dee2aaSAndroid Build Coastguard Worker     bool execute(size_t position);
101*c8dee2aaSAndroid Build Coastguard Worker 
102*c8dee2aaSAndroid Build Coastguard Worker     /**
103*c8dee2aaSAndroid Build Coastguard Worker      * Cleans up temporary state between steps, such as the dirty mask and function return values.
104*c8dee2aaSAndroid Build Coastguard Worker      */
105*c8dee2aaSAndroid Build Coastguard Worker     void tidyState();
106*c8dee2aaSAndroid Build Coastguard Worker 
107*c8dee2aaSAndroid Build Coastguard Worker     /** Updates fWriteTime for the entire variable at a given slot. */
108*c8dee2aaSAndroid Build Coastguard Worker     void updateVariableWriteTime(int slotIdx, size_t writeTime);
109*c8dee2aaSAndroid Build Coastguard Worker 
110*c8dee2aaSAndroid Build Coastguard Worker     /** Returns a vector of the indices and values of each slot that is enabled in `bits`. */
111*c8dee2aaSAndroid Build Coastguard Worker     std::vector<VariableData> getVariablesForDisplayMask(const SkBitSet& bits) const;
112*c8dee2aaSAndroid Build Coastguard Worker 
113*c8dee2aaSAndroid Build Coastguard Worker     struct StackFrame {
114*c8dee2aaSAndroid Build Coastguard Worker         int32_t   fFunction;     // from fFuncInfo
115*c8dee2aaSAndroid Build Coastguard Worker         int32_t   fLine;         // our current line number within the function
116*c8dee2aaSAndroid Build Coastguard Worker         SkBitSet  fDisplayMask;  // the variable slots which have been touched in this function
117*c8dee2aaSAndroid Build Coastguard Worker     };
118*c8dee2aaSAndroid Build Coastguard Worker     struct Slot {
119*c8dee2aaSAndroid Build Coastguard Worker         int32_t   fValue;        // values in each slot
120*c8dee2aaSAndroid Build Coastguard Worker         int       fScope;        // the scope value of each slot
121*c8dee2aaSAndroid Build Coastguard Worker         size_t    fWriteTime;    // when was the variable in this slot most recently written?
122*c8dee2aaSAndroid Build Coastguard Worker                                  // (by cursor position)
123*c8dee2aaSAndroid Build Coastguard Worker     };
124*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<DebugTracePriv>      fDebugTrace;
125*c8dee2aaSAndroid Build Coastguard Worker     size_t                     fCursor = 0;      // position of the read head
126*c8dee2aaSAndroid Build Coastguard Worker     int                        fScope = 0;       // the current scope depth (as tracked by
127*c8dee2aaSAndroid Build Coastguard Worker                                                  // trace_scope)
128*c8dee2aaSAndroid Build Coastguard Worker     std::vector<Slot>          fSlots;           // the array of all slots
129*c8dee2aaSAndroid Build Coastguard Worker     std::vector<StackFrame>    fStack;           // the execution stack
130*c8dee2aaSAndroid Build Coastguard Worker     std::optional<SkBitSet>    fDirtyMask;       // variable slots touched during the most-recently
131*c8dee2aaSAndroid Build Coastguard Worker                                                  // executed step
132*c8dee2aaSAndroid Build Coastguard Worker     std::optional<SkBitSet>    fReturnValues;    // variable slots containing return values
133*c8dee2aaSAndroid Build Coastguard Worker     LineNumberMap              fLineNumbers;     // holds [line number, the remaining number of
134*c8dee2aaSAndroid Build Coastguard Worker                                                  // times to reach this line during the trace]
135*c8dee2aaSAndroid Build Coastguard Worker     BreakpointSet              fBreakpointLines; // all breakpoints set by setBreakpointLines
136*c8dee2aaSAndroid Build Coastguard Worker };
137*c8dee2aaSAndroid Build Coastguard Worker 
138*c8dee2aaSAndroid Build Coastguard Worker }  // namespace SkSL
139*c8dee2aaSAndroid Build Coastguard Worker 
140*c8dee2aaSAndroid Build Coastguard Worker #endif  // SkSLDebugTracePlayer_DEFINED
141