Jared Duke | 13689fe | 2019-04-16 16:22:07 -0400 | [diff] [blame] | 1 | /* Copyright 2019 Google LLC. All Rights Reserved. |
| 2 | |
| 3 | Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | you may not use this file except in compliance with the License. |
| 5 | You may obtain a copy of the License at |
| 6 | |
| 7 | http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | |
| 9 | Unless required by applicable law or agreed to in writing, software |
| 10 | distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | See the License for the specific language governing permissions and |
| 13 | limitations under the License. |
| 14 | ==============================================================================*/ |
| 15 | |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 16 | #include "trace.h" |
| 17 | |
| 18 | #include <algorithm> |
Alex Stark | 8221a67 | 2019-08-07 17:41:19 -0400 | [diff] [blame] | 19 | #include <cerrno> // IWYU pragma: keep |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 20 | #include <cstdio> |
Alex Stark | 8221a67 | 2019-08-07 17:41:19 -0400 | [diff] [blame] | 21 | #include <cstdlib> |
Benoit Jacob | 14d1d8a | 2019-06-06 16:41:42 -0400 | [diff] [blame] | 22 | #include <string> |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 23 | #include <vector> |
| 24 | |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 25 | #include "check_macros.h" |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 26 | #include "side_pair.h" |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 27 | #include "time.h" |
| 28 | |
| 29 | namespace ruy { |
| 30 | |
| 31 | #ifdef RUY_TRACE |
| 32 | |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 33 | enum class TraceEvent : std::uint8_t { |
| 34 | kNone, |
| 35 | kThreadStart, |
| 36 | kThreadLoopStart, |
| 37 | kThreadEnd, |
| 38 | kBlockReserved, |
| 39 | kBlockPackedLhs, |
| 40 | kBlockPackedRhs, |
| 41 | kBlockFinished |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 42 | }; |
| 43 | |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 44 | struct TraceEntry { |
| 45 | TimePoint time_point; |
| 46 | TraceEvent event; |
| 47 | // ruy-internal thread id i.e. contiguous index into array of threads, |
| 48 | // with 0 designating the main thread. |
| 49 | std::uint16_t thread_id = 0; |
| 50 | // Additional parameters whose meaning depends on the 'event' type. |
| 51 | std::uint32_t params[1]; |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 52 | }; |
| 53 | |
| 54 | struct Trace { |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 55 | BlockMap block_map; |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 56 | // During recording, to avoid having to use locks or atomics, we let |
| 57 | // each thread append to its own specific vector. |
| 58 | std::vector<std::vector<TraceEntry>> thread_specific_entries; |
| 59 | // Global vector of entries into which we coalesce thread_specific_entries |
| 60 | // after recording is finished, when dumping a trace. See |
| 61 | // AggregateThreadSpecificEntries. |
| 62 | std::vector<TraceEntry> entries; |
Benoit Jacob | 842bfaf | 2019-04-11 10:43:28 -0400 | [diff] [blame] | 63 | TimePoint time_start; |
| 64 | TimePoint time_execute; |
| 65 | TimePoint time_end; |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 66 | }; |
| 67 | |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 68 | namespace { |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 69 | |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 70 | // Coalesce Trace::thread_specific_entries into Trace::entries. |
| 71 | void AggregateThreadSpecificEntries(Trace* trace) { |
| 72 | RUY_CHECK(trace->entries.empty()); |
| 73 | for (auto& thread_specific_entries_vector : trace->thread_specific_entries) { |
| 74 | for (const TraceEntry& entry : thread_specific_entries_vector) { |
| 75 | trace->entries.push_back(entry); |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 76 | } |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 77 | thread_specific_entries_vector.clear(); |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 78 | } |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 79 | } |
| 80 | |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 81 | // Sort Trace::entries by ascending time. In case of equal timepoints, |
| 82 | // sort by some semi-arbitrary ordering of event types. |
| 83 | void Sort(Trace* trace) { |
| 84 | std::sort(std::begin(trace->entries), std::end(trace->entries), |
| 85 | [](const TraceEntry& a, const TraceEntry& b) -> bool { |
| 86 | return a.time_point < b.time_point || |
| 87 | (a.time_point == b.time_point && |
| 88 | static_cast<int>(a.event) < static_cast<int>(b.event)); |
| 89 | }); |
| 90 | } |
| 91 | |
| 92 | // Dump a trace. Assumes that AggregateThreadSpecificEntries and Sort have |
| 93 | // already been called on it. |
Alex Stark | 8221a67 | 2019-08-07 17:41:19 -0400 | [diff] [blame] | 94 | // |
| 95 | // On some architectures long long ints are not same as std::int64_t, and |
| 96 | // time is printed as %lld, so static_casts are necessary. |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 97 | void Dump(const Trace& trace) { |
| 98 | const char* trace_filename = getenv("RUY_TRACE_FILE"); |
| 99 | FILE* trace_file = trace_filename ? fopen(trace_filename, "w") : stderr; |
| 100 | if (!trace_file) { |
| 101 | fprintf(stderr, "Failed to open %s for write, errno=%d\n", trace_filename, |
| 102 | errno); |
| 103 | RUY_CHECK(false); |
| 104 | } |
Benoit Jacob | f585116 | 2019-09-19 16:16:33 -0400 | [diff] [blame] | 105 | fprintf(trace_file, "thread_count:%d\n", trace.block_map.thread_count); |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 106 | fprintf(trace_file, "rows:%d\n", trace.block_map.dims[Side::kLhs]); |
| 107 | fprintf(trace_file, "cols:%d\n", trace.block_map.dims[Side::kRhs]); |
Alex Stark | 8221a67 | 2019-08-07 17:41:19 -0400 | [diff] [blame] | 108 | fprintf(trace_file, "Execute: %lld\n", |
| 109 | static_cast<long long int>( |
| 110 | ToInt64Nanoseconds(trace.time_execute - trace.time_start))); |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 111 | for (const TraceEntry& entry : trace.entries) { |
Alex Stark | 8221a67 | 2019-08-07 17:41:19 -0400 | [diff] [blame] | 112 | long long int time = static_cast<long long int>( |
| 113 | ToInt64Nanoseconds(entry.time_point - trace.time_start)); |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 114 | switch (entry.event) { |
| 115 | case TraceEvent::kThreadStart: |
Alex Stark | 8221a67 | 2019-08-07 17:41:19 -0400 | [diff] [blame] | 116 | fprintf(trace_file, "ThreadStart: %lld, %d\n", time, entry.thread_id); |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 117 | break; |
| 118 | case TraceEvent::kThreadLoopStart: |
Alex Stark | 8221a67 | 2019-08-07 17:41:19 -0400 | [diff] [blame] | 119 | fprintf(trace_file, "ThreadLoopStart: %lld, %d\n", time, |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 120 | entry.thread_id); |
| 121 | break; |
| 122 | case TraceEvent::kThreadEnd: |
Alex Stark | 8221a67 | 2019-08-07 17:41:19 -0400 | [diff] [blame] | 123 | fprintf(trace_file, "ThreadEnd: %lld, %d\n", time, entry.thread_id); |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 124 | break; |
| 125 | case TraceEvent::kBlockReserved: { |
| 126 | std::uint32_t block_id = entry.params[0]; |
| 127 | SidePair<int> block; |
| 128 | GetBlockByIndex(trace.block_map, block_id, &block); |
| 129 | SidePair<int> start, end; |
| 130 | GetBlockMatrixCoords(trace.block_map, block, &start, &end); |
| 131 | fprintf(trace_file, |
Alex Stark | 8221a67 | 2019-08-07 17:41:19 -0400 | [diff] [blame] | 132 | "BlockReserved: %lld, %d, %d, %d, %d, %d, %d, %d, %d\n", time, |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 133 | entry.thread_id, block_id, block[Side::kLhs], block[Side::kRhs], |
| 134 | start[Side::kLhs], start[Side::kRhs], end[Side::kLhs], |
| 135 | end[Side::kRhs]); |
| 136 | break; |
| 137 | } |
| 138 | case TraceEvent::kBlockPackedLhs: { |
| 139 | std::uint32_t block = entry.params[0]; |
| 140 | int start, end; |
| 141 | GetBlockMatrixCoords(Side::kLhs, trace.block_map, block, &start, &end); |
Alex Stark | 8221a67 | 2019-08-07 17:41:19 -0400 | [diff] [blame] | 142 | fprintf(trace_file, "BlockPackedLhs: %lld, %d, %d, %d, %d\n", time, |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 143 | entry.thread_id, block, start, end); |
| 144 | break; |
| 145 | } |
| 146 | case TraceEvent::kBlockPackedRhs: { |
| 147 | std::uint32_t block = entry.params[0]; |
| 148 | int start, end; |
| 149 | GetBlockMatrixCoords(Side::kRhs, trace.block_map, block, &start, &end); |
Alex Stark | 8221a67 | 2019-08-07 17:41:19 -0400 | [diff] [blame] | 150 | fprintf(trace_file, "BlockPackedRhs: %lld, %d, %d, %d, %d\n", time, |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 151 | entry.thread_id, block, start, end); |
| 152 | break; |
| 153 | } |
| 154 | case TraceEvent::kBlockFinished: { |
| 155 | std::uint32_t block_id = entry.params[0]; |
| 156 | SidePair<int> block; |
| 157 | GetBlockByIndex(trace.block_map, block_id, &block); |
Alex Stark | 8221a67 | 2019-08-07 17:41:19 -0400 | [diff] [blame] | 158 | fprintf(trace_file, "BlockFinished: %lld, %d, %d, %d, %d\n", time, |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 159 | entry.thread_id, block_id, block[Side::kLhs], |
| 160 | block[Side::kRhs]); |
| 161 | break; |
| 162 | } |
| 163 | default: |
| 164 | RUY_CHECK(false); |
| 165 | } |
| 166 | } |
Alex Stark | 8221a67 | 2019-08-07 17:41:19 -0400 | [diff] [blame] | 167 | fprintf(trace_file, "End: %lld\n", |
| 168 | static_cast<long long int>( |
| 169 | ToInt64Nanoseconds(trace.time_end - trace.time_start))); |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 170 | if (trace_filename) { |
| 171 | fclose(trace_file); |
| 172 | } |
| 173 | } |
| 174 | |
| 175 | } // anonymous namespace |
| 176 | |
| 177 | // Get a Trace object to record to, or null of tracing is not enabled. |
Benoit Jacob | 842bfaf | 2019-04-11 10:43:28 -0400 | [diff] [blame] | 178 | Trace* NewTraceOrNull(TracingContext* tracing, int rows, int depth, int cols) { |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 179 | if (!tracing->initialized) { |
| 180 | tracing->initialized = true; |
| 181 | tracing->enabled = getenv("RUY_TRACE"); |
| 182 | if (!tracing->enabled) { |
| 183 | return nullptr; |
| 184 | } |
| 185 | if (getenv("RUY_TRACE_FILTER_ROWS")) { |
| 186 | tracing->filter_shape_rows = std::stoi(getenv("RUY_TRACE_FILTER_ROWS")); |
| 187 | } |
| 188 | if (getenv("RUY_TRACE_FILTER_DEPTH")) { |
| 189 | tracing->filter_shape_depth = std::stoi(getenv("RUY_TRACE_FILTER_DEPTH")); |
| 190 | } |
| 191 | if (getenv("RUY_TRACE_FILTER_COLS")) { |
| 192 | tracing->filter_shape_cols = std::stoi(getenv("RUY_TRACE_FILTER_COLS")); |
| 193 | } |
| 194 | } |
| 195 | if (!tracing->enabled) { |
| 196 | return nullptr; |
| 197 | } |
| 198 | if (tracing->filter_shape_rows && rows != tracing->filter_shape_rows) { |
| 199 | return nullptr; |
| 200 | } |
| 201 | if (tracing->filter_shape_depth && depth != tracing->filter_shape_depth) { |
| 202 | return nullptr; |
| 203 | } |
| 204 | if (tracing->filter_shape_cols && cols != tracing->filter_shape_cols) { |
| 205 | return nullptr; |
| 206 | } |
Benoit Jacob | 842bfaf | 2019-04-11 10:43:28 -0400 | [diff] [blame] | 207 | // Delete any existing trace. |
| 208 | delete tracing->trace; |
| 209 | // Create a new one. |
| 210 | tracing->trace = new Trace; |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 211 | return tracing->trace; |
| 212 | } |
| 213 | |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 214 | // The trace recorded on a context is finalized and dumped by |
| 215 | // this TracingContext destructor. |
| 216 | // |
| 217 | // The idea of dumping on context destructor is that typically one wants to |
| 218 | // run many matrix multiplications, e.g. to hit a steady state in terms of |
| 219 | // performance characteristics, but only trace the last repetition of the |
| 220 | // workload, when that steady state was attained. |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 221 | TracingContext::~TracingContext() { |
| 222 | if (trace) { |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 223 | AggregateThreadSpecificEntries(trace); |
| 224 | Sort(trace); |
| 225 | Dump(*trace); |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 226 | } |
| 227 | delete trace; |
| 228 | } |
| 229 | |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 230 | void TraceRecordStart(Trace* trace) { |
| 231 | if (trace) { |
Benoit Jacob | 4ac87c7 | 2019-07-30 13:23:08 -0400 | [diff] [blame] | 232 | trace->time_start = Now(); |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 233 | } |
| 234 | } |
| 235 | |
Benoit Jacob | f585116 | 2019-09-19 16:16:33 -0400 | [diff] [blame] | 236 | void TraceRecordExecute(const BlockMap& block_map, Trace* trace) { |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 237 | if (trace) { |
Benoit Jacob | 4ac87c7 | 2019-07-30 13:23:08 -0400 | [diff] [blame] | 238 | trace->time_execute = Now(); |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 239 | trace->block_map = block_map; |
Benoit Jacob | f585116 | 2019-09-19 16:16:33 -0400 | [diff] [blame] | 240 | trace->thread_specific_entries.resize(block_map.thread_count); |
| 241 | for (int thread = 0; thread < block_map.thread_count; thread++) { |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 242 | trace->thread_specific_entries[thread].clear(); |
| 243 | // Reserve some large size to avoid frequent heap allocations |
| 244 | // affecting the recorded timings. |
| 245 | trace->thread_specific_entries[thread].reserve(16384); |
| 246 | } |
| 247 | } |
| 248 | } |
| 249 | |
| 250 | void TraceRecordEnd(Trace* trace) { |
| 251 | if (trace) { |
Benoit Jacob | 4ac87c7 | 2019-07-30 13:23:08 -0400 | [diff] [blame] | 252 | trace->time_end = Now(); |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 253 | } |
| 254 | } |
| 255 | |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 256 | void TraceRecordThreadStart(std::uint32_t thread_id, Trace* trace) { |
| 257 | if (trace) { |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 258 | TraceEntry entry; |
| 259 | entry.event = TraceEvent::kThreadStart; |
Benoit Jacob | 4ac87c7 | 2019-07-30 13:23:08 -0400 | [diff] [blame] | 260 | entry.time_point = Now(); |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 261 | entry.thread_id = thread_id; |
| 262 | trace->thread_specific_entries[thread_id].push_back(entry); |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 263 | } |
| 264 | } |
| 265 | |
| 266 | void TraceRecordThreadLoopStart(std::uint32_t thread_id, Trace* trace) { |
| 267 | if (trace) { |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 268 | TraceEntry entry; |
| 269 | entry.event = TraceEvent::kThreadLoopStart; |
Benoit Jacob | 4ac87c7 | 2019-07-30 13:23:08 -0400 | [diff] [blame] | 270 | entry.time_point = Now(); |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 271 | entry.thread_id = thread_id; |
| 272 | trace->thread_specific_entries[thread_id].push_back(entry); |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 273 | } |
| 274 | } |
| 275 | |
| 276 | void TraceRecordBlockReserved(std::uint32_t thread_id, std::uint32_t block_id, |
| 277 | Trace* trace) { |
| 278 | if (trace) { |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 279 | TraceEntry entry; |
| 280 | entry.event = TraceEvent::kBlockReserved; |
Benoit Jacob | 4ac87c7 | 2019-07-30 13:23:08 -0400 | [diff] [blame] | 281 | entry.time_point = Now(); |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 282 | entry.thread_id = thread_id; |
| 283 | entry.params[0] = block_id; |
| 284 | trace->thread_specific_entries[thread_id].push_back(entry); |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 285 | } |
| 286 | } |
| 287 | |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 288 | void TraceRecordBlockPacked(std::uint32_t thread_id, Side side, int block, |
| 289 | Trace* trace) { |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 290 | if (trace) { |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 291 | TraceEntry entry; |
| 292 | entry.event = side == Side::kLhs ? TraceEvent::kBlockPackedLhs |
| 293 | : TraceEvent::kBlockPackedRhs; |
Benoit Jacob | 4ac87c7 | 2019-07-30 13:23:08 -0400 | [diff] [blame] | 294 | entry.time_point = Now(); |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 295 | entry.thread_id = thread_id; |
| 296 | entry.params[0] = block; |
| 297 | trace->thread_specific_entries[thread_id].push_back(entry); |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 298 | } |
| 299 | } |
| 300 | |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 301 | void TraceRecordBlockFinished(std::uint32_t thread_id, std::uint32_t block_id, |
| 302 | Trace* trace) { |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 303 | if (trace) { |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 304 | TraceEntry entry; |
| 305 | entry.event = TraceEvent::kBlockFinished; |
Benoit Jacob | 4ac87c7 | 2019-07-30 13:23:08 -0400 | [diff] [blame] | 306 | entry.time_point = Now(); |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 307 | entry.thread_id = thread_id; |
| 308 | entry.params[0] = block_id; |
| 309 | trace->thread_specific_entries[thread_id].push_back(entry); |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 310 | } |
| 311 | } |
| 312 | |
| 313 | void TraceRecordThreadEnd(std::uint32_t thread_id, Trace* trace) { |
| 314 | if (trace) { |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 315 | TraceEntry entry; |
| 316 | entry.event = TraceEvent::kThreadEnd; |
Benoit Jacob | 4ac87c7 | 2019-07-30 13:23:08 -0400 | [diff] [blame] | 317 | entry.time_point = Now(); |
Benoit Jacob | 2756b86 | 2019-07-25 15:15:39 -0400 | [diff] [blame] | 318 | entry.thread_id = thread_id; |
| 319 | trace->thread_specific_entries[thread_id].push_back(entry); |
Benoit Jacob | a0ba3ac | 2019-04-08 12:00:37 -0400 | [diff] [blame] | 320 | } |
| 321 | } |
| 322 | |
| 323 | #endif |
| 324 | |
| 325 | } // namespace ruy |