Deepity
Ultra-fast, SIMD-accelerated Predictive Coding
Loading...
Searching...
No Matches
Profile.h
Go to the documentation of this file.
1#pragma once
2#include <chrono>
3#include <iostream>
4#include <iomanip>
5#include <string>
6#include <vector>
7#include <utility>
8
28
29namespace Deep
30{
35 {
36 double errorConstruction = 0.0;
37 double energyCalculation = 0.0;
38 double forwardGemm = 0.0;
39 double biasAdd = 0.0;
40 double activationForward = 0.0;
41
42 double activationDerivative = 0.0;
43 double localErrorTerm = 0.0;
44 double bottomUpConstruction = 0.0;
45 double feedbackGemm = 0.0;
46 double saxpyUpdate = 0.0;
47
48 double updateWeightsTotal = 0.0;
49 double updatePrecisionTotal = 0.0;
50
51 // Top-level timers -- wrap the ENTIRE function body, separate from
52 // (and in addition to) the sub-phase timers above, so you can see
53 // "UpdateState 78%" before drilling into its five sub-phases.
54 double calculateStateTotal = 0.0;
55 double updateStateTotal = 0.0;
56
57 long long calculateStateCalls = 0;
58 long long updateStateCalls = 0;
59
63 double PhaseSum() const noexcept
64 {
65 // Sub-phases only -- does NOT include calculateStateTotal/
66 // updateStateTotal, since those measure the SAME work the
67 // sub-phases already measure (they'd double-count if summed
68 // together). calculateStateTotal/updateStateTotal exist purely
69 // as an independent top-level cross-check against the sub-phase
70 // sum, and against everything outside CalculateState/UpdateState
71 // (e.g. UpdateWeights, UpdatePrecision, caller-side overhead).
75 }
76
82 void Print(const std::string &label) const
83 {
84 double phaseSum = PhaseSum();
85 auto row = [&](const char *name, double t)
86 {
87 std::cout << " " << std::left << std::setw(24) << name
88 << std::right << std::setw(10) << std::fixed << std::setprecision(4) << t << " s"
89 << std::setw(8) << std::setprecision(1) << (phaseSum > 0 ? 100.0 * t / phaseSum : 0.0) << "%\n";
90 };
91
92 std::cout << "\n--- " << label << " (" << calculateStateCalls
93 << " CalculateState calls, " << updateStateCalls << " UpdateState calls) ---\n";
94 std::cout << " CalculateState() [top-level: " << std::fixed << std::setprecision(4)
95 << calculateStateTotal << " s]\n";
96 row("error construction", errorConstruction);
97 row("energy calculation", energyCalculation);
98 row("forward GEMM", forwardGemm);
99 row("bias add", biasAdd);
100 row("activation (fwd)", activationForward);
101 std::cout << " UpdateState() [top-level: " << updateStateTotal << " s]\n";
102 row("activation derivative", activationDerivative);
103 row("local error term", localErrorTerm);
104 row("bottom-up construction", bottomUpConstruction);
105 row("feedback GEMM", feedbackGemm);
106 row("SAXPY update", saxpyUpdate);
107 std::cout << " Other:\n";
108 row("UpdateWeights (total)", updateWeightsTotal);
109 row("UpdatePrecision (total)", updatePrecisionTotal);
110 std::cout << " Sub-phase sum: " << phaseSum << " s"
111 << " (top-level CalcState+UpdateState: " << (calculateStateTotal + updateStateTotal) << " s"
112 << " -- these should be CLOSE; large divergence means the sub-phase"
113 << " timers aren't capturing everything the function does)\n";
114 }
115 };
116
120 {
121 std::string label;
123 };
124
125 // Registry: linear vector, not a hash map -- small layer counts, and
126 // preserves insertion order (== network layer order) for printing.
129 inline std::vector<std::pair<const void *, ProfileEntry>> &ProfileRegistry()
130 {
131 static std::vector<std::pair<const void *, ProfileEntry>> registry;
132 return registry;
133 }
134
135 // Looks up (or creates, on first call) this layer's accumulator. Label
136 // is generated from the layer's own GetInputSize()/GetOutputSize() --
137 // works for any layer type with those methods (DiscriminativePCLayer,
138 // ConvPCLayer, ...) via duck-typed template, no coupling to a specific
139 // class or forward declaration needed.
143 template <typename LayerT>
144 inline ProfileAccumulator &LayerProfile(LayerT *layer)
145 {
146 auto &registry = ProfileRegistry();
147 for (auto &entry : registry)
148 if (entry.first == layer)
149 return entry.second.acc;
150
151 ProfileEntry entry;
152 entry.label = "layer(" + std::to_string(layer->GetInputSize()) + "->"
153 + std::to_string(layer->GetOutputSize()) + ") @ " + std::to_string((size_t)layer);
154 registry.emplace_back(layer, std::move(entry));
155 return registry.back().second.acc;
156 }
157
158 // Call once, after the training run, with an INDEPENDENTLY measured
159 // wall-clock duration (std::chrono around the whole run in the harness,
160 // NOT derived from these accumulators) -- this is the reconciliation
161 // check from review point 2.
167 inline void PrintAllProfiles(double wallClockSeconds)
168 {
169 double grandTotal = 0.0;
170 for (auto &entry : ProfileRegistry())
171 {
172 entry.second.acc.Print(entry.second.label);
173 grandTotal += entry.second.acc.PhaseSum();
174 }
175 std::cout << "\n=== Reconciliation ===\n";
176 std::cout << " Wall-clock (measured around whole run): " << std::fixed << std::setprecision(4)
177 << wallClockSeconds << " s\n";
178 std::cout << " Sum of all layers' phase sums: " << grandTotal << " s\n";
179 std::cout << " Unaccounted-for time: " << (wallClockSeconds - grandTotal) << " s"
180 << " (" << (wallClockSeconds > 0 ? 100.0 * (wallClockSeconds - grandTotal) / wallClockSeconds : 0.0)
181 << "% -- data loading, Python/pybind overhead, timer overhead itself, etc.)\n";
182 }
183
184#ifdef PCN_PROFILE
189 class ScopedTimer
190 {
191 public:
194 explicit ScopedTimer(double &accumulator) noexcept
195 : accumulator(accumulator), start(std::chrono::steady_clock::now()) {}
196 ~ScopedTimer() noexcept
197 {
198 auto end = std::chrono::steady_clock::now();
199 accumulator += std::chrono::duration<double>(end - start).count();
200 }
201 ScopedTimer(const ScopedTimer &) = delete;
202 ScopedTimer &operator=(const ScopedTimer &) = delete;
203 private:
204 double &accumulator;
205 std::chrono::steady_clock::time_point start;
206 };
209 #define PCN_TIME(accumulator) ::Deep::ScopedTimer _pcn_timer_##__LINE__(accumulator)
210#else
214 {
215 public:
217 explicit ScopedTimer(double &) noexcept {}
218 };
219
221 #define PCN_TIME(accumulator) do {} while (0)
222#endif
223} // namespace Deep
ScopedTimer(double &) noexcept
No-op; the accumulator reference is discarded.
Definition Profile.h:217
This file exists to provide both Tensor.h and IComputeBackend.h with device types without introducing...
Definition Backend.cpp:10
void PrintAllProfiles(double wallClockSeconds)
Prints every registered layer's profile, then a grand-total reconciliation against an independently m...
Definition Profile.h:167
std::vector< std::pair< const void *, ProfileEntry > > & ProfileRegistry()
The process-wide table of every layer that's had LayerProfile() called on it at least once,...
Definition Profile.h:129
ProfileAccumulator & LayerProfile(LayerT *layer)
Looks up (or creates, on first call) layer's accumulator in the process-wide registry,...
Definition Profile.h:144
One layer's accumulated time-per-phase, in seconds – see the file-level note for the reconciliation i...
Definition Profile.h:35
double forwardGemm
CalculateState: the forward prediction GEMM.
Definition Profile.h:38
double bottomUpConstruction
UpdateState: assembling the bottom-up term.
Definition Profile.h:44
double energyCalculation
CalculateState: the energy reduction itself.
Definition Profile.h:37
void Print(const std::string &label) const
Prints this accumulator's per-phase breakdown (with percentages of PhaseSum()) plus the top-level/sub...
Definition Profile.h:82
double errorConstruction
CalculateState: building the error term.
Definition Profile.h:36
double activationForward
CalculateState: forward activation function.
Definition Profile.h:40
double biasAdd
CalculateState: bias-add after the forward GEMM.
Definition Profile.h:39
long long updateStateCalls
Number of UpdateState() calls recorded.
Definition Profile.h:58
double feedbackGemm
UpdateState: the feedback GEMM.
Definition Profile.h:45
double updatePrecisionTotal
UpdatePrecision(), whole-call total.
Definition Profile.h:49
double updateWeightsTotal
UpdateWeights(), whole-call total.
Definition Profile.h:48
double PhaseSum() const noexcept
Sum of every sub-phase timer (excludes the top-level calculateStateTotal/updateStateTotal,...
Definition Profile.h:63
double localErrorTerm
UpdateState: dz_dt = -p*e (was ownGradientTerm – not a backprop gradient).
Definition Profile.h:43
double updateStateTotal
UpdateState(), whole-call total.
Definition Profile.h:55
double saxpyUpdate
UpdateState: the final z += ir*dz SAXPY.
Definition Profile.h:46
double calculateStateTotal
CalculateState(), whole-call total.
Definition Profile.h:54
long long calculateStateCalls
Number of CalculateState() calls recorded.
Definition Profile.h:57
double activationDerivative
UpdateState: activation derivative.
Definition Profile.h:42
One registered layer's profiling data: its print label paired with its accumulator.
Definition Profile.h:120
std::string label
Printed heading, e.g. "layer(784->512) @ 0x...".
Definition Profile.h:121
ProfileAccumulator acc
That layer's accumulated phase timings.
Definition Profile.h:122