Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(42)

Side by Side Diff: src/IceGlobalContext.h

Issue 848193003: Subzero: Add locking to prepare for multithreaded translation. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: Simply the LockedPtr implementation Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/IceConverter.cpp ('k') | src/IceGlobalContext.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 //===- subzero/src/IceGlobalContext.h - Global context defs -----*- C++ -*-===// 1 //===- subzero/src/IceGlobalContext.h - Global context defs -----*- C++ -*-===//
2 // 2 //
3 // The Subzero Code Generator 3 // The Subzero Code Generator
4 // 4 //
5 // This file is distributed under the University of Illinois Open Source 5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details. 6 // License. See LICENSE.TXT for details.
7 // 7 //
8 //===----------------------------------------------------------------------===// 8 //===----------------------------------------------------------------------===//
9 // 9 //
10 // This file declares aspects of the compilation that persist across 10 // This file declares aspects of the compilation that persist across
11 // multiple functions. 11 // multiple functions.
12 // 12 //
13 //===----------------------------------------------------------------------===// 13 //===----------------------------------------------------------------------===//
14 14
15 #ifndef SUBZERO_SRC_ICEGLOBALCONTEXT_H 15 #ifndef SUBZERO_SRC_ICEGLOBALCONTEXT_H
16 #define SUBZERO_SRC_ICEGLOBALCONTEXT_H 16 #define SUBZERO_SRC_ICEGLOBALCONTEXT_H
17 17
18 #include <memory> 18 #include <memory>
19 #include <mutex>
19 20
20 #include "IceDefs.h" 21 #include "IceDefs.h"
21 #include "IceClFlags.h" 22 #include "IceClFlags.h"
22 #include "IceIntrinsics.h" 23 #include "IceIntrinsics.h"
23 #include "IceRNG.h" 24 #include "IceRNG.h"
24 #include "IceTimerTree.h" 25 #include "IceTimerTree.h"
25 #include "IceTypes.h" 26 #include "IceTypes.h"
26 27
27 namespace Ice { 28 namespace Ice {
28 29
29 class ClFlags; 30 class ClFlags;
31 class ConstantPool;
30 class FuncSigType; 32 class FuncSigType;
31 33
32 // This class collects rudimentary statistics during translation. 34 typedef std::mutex GlobalLockType;
33 class CodeStats {
34 CodeStats(const CodeStats &) = delete;
35 CodeStats &operator=(const CodeStats &) = default;
36 35
36 // LockedPtr is a way to provide automatically locked access to some object.
37 template <typename T> class LockedPtr {
38 LockedPtr(const LockedPtr &) = delete;
39 LockedPtr &operator=(const LockedPtr &) = delete;
JF 2015/01/20 01:23:05 `LockedPtr() = delete;`
Jim Stichnoth 2015/01/20 16:22:54 Oops. Done.
37 public: 40 public:
38 CodeStats() 41 LockedPtr(T *Value, GlobalLockType &Lock) : Value(Value), Lock(Lock) {
39 : InstructionsEmitted(0), RegistersSaved(0), FrameBytes(0), Spills(0), 42 Lock.lock();
40 Fills(0) {} 43 }
41 void reset() { *this = CodeStats(); } 44 LockedPtr(LockedPtr &&Other) : Value(Other.Value), Lock(Other.Lock) {
42 void updateEmitted(uint32_t InstCount) { InstructionsEmitted += InstCount; } 45 Other.Value = nullptr;
JF 2015/01/20 01:23:05 It's probably better to hold Lock as a pointer ins
Jim Stichnoth 2015/01/20 16:22:54 Done.
43 void updateRegistersSaved(uint32_t Num) { RegistersSaved += Num; } 46 }
44 void updateFrameBytes(uint32_t Bytes) { FrameBytes += Bytes; } 47 ~LockedPtr() { Lock.unlock(); }
45 void updateSpills() { ++Spills; } 48 T *operator->() const { return Value; }
46 void updateFills() { ++Fills; }
47 void dump(const IceString &Name, Ostream &Str);
48
49 private: 49 private:
50 uint32_t InstructionsEmitted; 50 T *Value;
51 uint32_t RegistersSaved; 51 GlobalLockType &Lock;
52 uint32_t FrameBytes;
53 uint32_t Spills;
54 uint32_t Fills;
55 }; 52 };
56 53
57 // TODO: Accesses to all non-const fields of GlobalContext need to
58 // be synchronized, especially the constant pool, the allocator, and
59 // the output streams.
60 class GlobalContext { 54 class GlobalContext {
61 GlobalContext(const GlobalContext &) = delete; 55 GlobalContext(const GlobalContext &) = delete;
62 GlobalContext &operator=(const GlobalContext &) = delete; 56 GlobalContext &operator=(const GlobalContext &) = delete;
63 57
58 // CodeStats collects rudimentary statistics during translation.
59 class CodeStats {
60 CodeStats(const CodeStats &) = delete;
61 CodeStats &operator=(const CodeStats &) = default;
62
63 public:
64 CodeStats()
65 : InstructionsEmitted(0), RegistersSaved(0), FrameBytes(0), Spills(0),
66 Fills(0) {}
67 void reset() { *this = CodeStats(); }
68 void updateEmitted(uint32_t InstCount) { InstructionsEmitted += InstCount; }
69 void updateRegistersSaved(uint32_t Num) { RegistersSaved += Num; }
70 void updateFrameBytes(uint32_t Bytes) { FrameBytes += Bytes; }
71 void updateSpills() { ++Spills; }
72 void updateFills() { ++Fills; }
73 void dump(const IceString &Name, Ostream &Str);
74
75 private:
76 uint32_t InstructionsEmitted;
77 uint32_t RegistersSaved;
78 uint32_t FrameBytes;
79 uint32_t Spills;
80 uint32_t Fills;
81 };
82
83 // ThreadContext contains thread-local data. This data can be
84 // combined/reduced as needed after all threads complete.
85 class ThreadContext {
86 ThreadContext(const ThreadContext &) = delete;
87 ThreadContext &operator=(const ThreadContext &) = delete;
88
89 public:
90 ThreadContext() {}
91 CodeStats StatsFunction;
92 std::vector<TimerStack> Timers;
93 };
94
64 public: 95 public:
65 GlobalContext(Ostream *OsDump, Ostream *OsEmit, ELFStreamer *ELFStreamer, 96 GlobalContext(Ostream *OsDump, Ostream *OsEmit, ELFStreamer *ELFStreamer,
66 VerboseMask Mask, TargetArch Arch, OptLevel Opt, 97 VerboseMask Mask, TargetArch Arch, OptLevel Opt,
67 IceString TestPrefix, const ClFlags &Flags); 98 IceString TestPrefix, const ClFlags &Flags);
68 ~GlobalContext(); 99 ~GlobalContext();
69 100
70 // Returns true if any of the specified options in the verbose mask 101 // Returns true if any of the specified options in the verbose mask
71 // are set. If the argument is omitted, it checks if any verbose 102 // are set. If the argument is omitted, it checks if any verbose
72 // options at all are set. 103 // options at all are set.
73 VerboseMask getVerbose() const { return VMask; } 104 VerboseMask getVerbose() const { return VMask; }
74 bool isVerbose(VerboseMask Mask = IceV_All) const { return VMask & Mask; } 105 bool isVerbose(VerboseMask Mask = IceV_All) const { return VMask & Mask; }
75 void setVerbose(VerboseMask Mask) { VMask = Mask; } 106 void setVerbose(VerboseMask Mask) { VMask = Mask; }
76 void addVerbose(VerboseMask Mask) { VMask |= Mask; } 107 void addVerbose(VerboseMask Mask) { VMask |= Mask; }
77 void subVerbose(VerboseMask Mask) { VMask &= ~Mask; } 108 void subVerbose(VerboseMask Mask) { VMask &= ~Mask; }
78 109
79 Ostream &getStrDump() { return *StrDump; } 110 // The dump and emit streams need to be used by only one thread at a
80 Ostream &getStrEmit() { return *StrEmit; } 111 // time. This is done by exclusively reserving the streams via
112 // lockStr() and unlockStr(). The OstreamLocker class can be used
113 // to conveniently manage this.
114 //
115 // The model is that a thread grabs the stream lock, then does an
116 // arbitrary amount of work during which far-away callees may grab
117 // the stream and do something with it, and finally the thread
118 // releases the stream lock. This allows large chunks of output to
119 // be dumped or emitted without risking interleaving from multiple
120 // threads. When a worker locks the streams via lockStr(), we use
121 // IsStrLocked to verify that it wasn't already locked (i.e. no
122 // recursive lockStr() calls). When a worker grabs one of the
123 // streams via getStrDump() or getStrEmit(), we lock StrLock
124 // (recursively, if lockStr() was correctly used, hence the need for
125 // recursive_mutex) and check that IsStrLocked is set.
126 void lockStr() {
127 StrLock.lock();
128 assert(!isStrLocked());
129 IsStrLocked = true;
130 }
131 void unlockStr() {
132 assert(isStrLocked());
133 IsStrLocked = false;
134 StrLock.unlock();
135 }
136 // Test whether we are already holding StrLock, by first doing a
137 // lock() and when it (eventually) succeeds, checking that we didn't
138 // recursively lock it.
139 bool isStrLocked() {
140 StrLock.lock();
141 bool WasLocked = IsStrLocked;
142 StrLock.unlock();
143 return WasLocked;
144 }
145 Ostream &getStrDump() {
146 assert(isStrLocked());
147 return *StrDump;
148 }
149 Ostream &getStrEmit() {
150 assert(isStrLocked());
151 return *StrEmit;
152 }
81 153
82 TargetArch getTargetArch() const { return Arch; } 154 TargetArch getTargetArch() const { return Arch; }
83 OptLevel getOptLevel() const { return Opt; } 155 OptLevel getOptLevel() const { return Opt; }
84 156
85 // When emitting assembly, we allow a string to be prepended to 157 // When emitting assembly, we allow a string to be prepended to
86 // names of translated functions. This makes it easier to create an 158 // names of translated functions. This makes it easier to create an
87 // execution test against a reference translator like llc, with both 159 // execution test against a reference translator like llc, with both
88 // translators using the same bitcode as input. 160 // translators using the same bitcode as input.
89 IceString getTestPrefix() const { return TestPrefix; } 161 IceString getTestPrefix() const { return TestPrefix; }
90 IceString mangleName(const IceString &Name) const; 162 IceString mangleName(const IceString &Name) const;
(...skipping 11 matching lines...) Expand all
102 Constant *getConstantDouble(double Value); 174 Constant *getConstantDouble(double Value);
103 // Returns a symbolic constant. 175 // Returns a symbolic constant.
104 Constant *getConstantSym(RelocOffsetT Offset, const IceString &Name, 176 Constant *getConstantSym(RelocOffsetT Offset, const IceString &Name,
105 bool SuppressMangling); 177 bool SuppressMangling);
106 // Returns an undef. 178 // Returns an undef.
107 Constant *getConstantUndef(Type Ty); 179 Constant *getConstantUndef(Type Ty);
108 // Returns a zero value. 180 // Returns a zero value.
109 Constant *getConstantZero(Type Ty); 181 Constant *getConstantZero(Type Ty);
110 // getConstantPool() returns a copy of the constant pool for 182 // getConstantPool() returns a copy of the constant pool for
111 // constants of a given type. 183 // constants of a given type.
112 ConstantList getConstantPool(Type Ty) const; 184 ConstantList getConstantPool(Type Ty);
113 // Returns a new function declaration, allocated in an internal 185 // Returns a new function declaration, allocated in an internal
114 // memory pool. Ownership of the function is maintained by this 186 // memory pool. Ownership of the function is maintained by this
115 // class instance. 187 // class instance.
116 FunctionDeclaration *newFunctionDeclaration(const FuncSigType *Signature, 188 FunctionDeclaration *newFunctionDeclaration(const FuncSigType *Signature,
117 unsigned CallingConv, 189 unsigned CallingConv,
118 unsigned Linkage, bool IsProto); 190 unsigned Linkage, bool IsProto);
119 191
120 // Returns a new global variable declaration, allocated in an 192 // Returns a new global variable declaration, allocated in an
121 // internal memory pool. Ownership of the function is maintained by 193 // internal memory pool. Ownership of the function is maintained by
122 // this class instance. 194 // this class instance.
123 VariableDeclaration *newVariableDeclaration(); 195 VariableDeclaration *newVariableDeclaration();
124 196
125 const ClFlags &getFlags() const { return Flags; } 197 const ClFlags &getFlags() const { return Flags; }
126 198
127 bool isIRGenerationDisabled() const { 199 bool isIRGenerationDisabled() const {
128 return ALLOW_DISABLE_IR_GEN ? getFlags().DisableIRGeneration : false; 200 return ALLOW_DISABLE_IR_GEN ? getFlags().DisableIRGeneration : false;
129 } 201 }
130 202
131 // Allocate data of type T using the global allocator. 203 // Allocate data of type T using the global allocator.
132 template <typename T> T *allocate() { return Allocator.Allocate<T>(); } 204 template <typename T> T *allocate() {
205 return getAllocator()->Allocate<T>();
206 }
133 207
134 const Intrinsics &getIntrinsicsInfo() const { return IntrinsicsInfo; } 208 const Intrinsics &getIntrinsicsInfo() const { return IntrinsicsInfo; }
135 209
136 // TODO(wala,stichnot): Make the RNG play nicely with multithreaded 210 // TODO(wala,stichnot): Make the RNG play nicely with multithreaded
137 // translation. 211 // translation.
138 RandomNumberGenerator &getRNG() { return RNG; } 212 RandomNumberGenerator &getRNG() { return RNG; }
139 213
140 ELFObjectWriter *getObjectWriter() const { return ObjectWriter.get(); } 214 ELFObjectWriter *getObjectWriter() const { return ObjectWriter.get(); }
141 215
142 // Reset stats at the beginning of a function. 216 // Reset stats at the beginning of a function.
143 void resetStats() { 217 void resetStats() {
144 if (ALLOW_DUMP) 218 if (ALLOW_DUMP)
145 StatsFunction.reset(); 219 TLS->StatsFunction.reset();
146 } 220 }
147 void dumpStats(const IceString &Name, bool Final = false); 221 void dumpStats(const IceString &Name, bool Final = false);
148 void statsUpdateEmitted(uint32_t InstCount) { 222 void statsUpdateEmitted(uint32_t InstCount) {
149 if (!ALLOW_DUMP) 223 if (!ALLOW_DUMP || !getFlags().DumpStats)
150 return; 224 return;
151 StatsFunction.updateEmitted(InstCount); 225 TLS->StatsFunction.updateEmitted(InstCount);
152 StatsCumulative.updateEmitted(InstCount); 226 getStatsCumulative()->updateEmitted(InstCount);
153 } 227 }
154 void statsUpdateRegistersSaved(uint32_t Num) { 228 void statsUpdateRegistersSaved(uint32_t Num) {
155 if (!ALLOW_DUMP) 229 if (!ALLOW_DUMP || !getFlags().DumpStats)
156 return; 230 return;
157 StatsFunction.updateRegistersSaved(Num); 231 TLS->StatsFunction.updateRegistersSaved(Num);
158 StatsCumulative.updateRegistersSaved(Num); 232 getStatsCumulative()->updateRegistersSaved(Num);
159 } 233 }
160 void statsUpdateFrameBytes(uint32_t Bytes) { 234 void statsUpdateFrameBytes(uint32_t Bytes) {
161 if (!ALLOW_DUMP) 235 if (!ALLOW_DUMP || !getFlags().DumpStats)
162 return; 236 return;
163 StatsFunction.updateFrameBytes(Bytes); 237 TLS->StatsFunction.updateFrameBytes(Bytes);
164 StatsCumulative.updateFrameBytes(Bytes); 238 getStatsCumulative()->updateFrameBytes(Bytes);
165 } 239 }
166 void statsUpdateSpills() { 240 void statsUpdateSpills() {
167 if (!ALLOW_DUMP) 241 if (!ALLOW_DUMP || !getFlags().DumpStats)
168 return; 242 return;
169 StatsFunction.updateSpills(); 243 TLS->StatsFunction.updateSpills();
170 StatsCumulative.updateSpills(); 244 getStatsCumulative()->updateSpills();
171 } 245 }
172 void statsUpdateFills() { 246 void statsUpdateFills() {
173 if (!ALLOW_DUMP) 247 if (!ALLOW_DUMP || !getFlags().DumpStats)
174 return; 248 return;
175 StatsFunction.updateFills(); 249 TLS->StatsFunction.updateFills();
176 StatsCumulative.updateFills(); 250 getStatsCumulative()->updateFills();
177 } 251 }
178 252
179 // These are predefined TimerStackIdT values. 253 // These are predefined TimerStackIdT values.
180 enum TimerStackKind { 254 enum TimerStackKind {
181 TSK_Default = 0, 255 TSK_Default = 0,
182 TSK_Funcs, 256 TSK_Funcs,
183 TSK_Num 257 TSK_Num
184 }; 258 };
185 259
260 TimerStackIdT newTimerStackID(const IceString &Name);
186 TimerIdT getTimerID(TimerStackIdT StackID, const IceString &Name); 261 TimerIdT getTimerID(TimerStackIdT StackID, const IceString &Name);
187 TimerStackIdT newTimerStackID(const IceString &Name);
188 void pushTimer(TimerIdT ID, TimerStackIdT StackID = TSK_Default); 262 void pushTimer(TimerIdT ID, TimerStackIdT StackID = TSK_Default);
189 void popTimer(TimerIdT ID, TimerStackIdT StackID = TSK_Default); 263 void popTimer(TimerIdT ID, TimerStackIdT StackID = TSK_Default);
190 void resetTimer(TimerStackIdT StackID); 264 void resetTimer(TimerStackIdT StackID);
191 void setTimerName(TimerStackIdT StackID, const IceString &NewName); 265 void setTimerName(TimerStackIdT StackID, const IceString &NewName);
192 void dumpTimers(TimerStackIdT StackID = TSK_Default, 266 void dumpTimers(TimerStackIdT StackID = TSK_Default,
193 bool DumpCumulative = true); 267 bool DumpCumulative = true);
194 268
195 private: 269 private:
270 // Try to make sure the mutexes are allocated on separate cache
271 // lines, assuming the maximum cache line size is 64.
272 const static size_t MaxCacheLineSize = 64;
273 alignas(MaxCacheLineSize) GlobalLockType AllocLock;
274 alignas(MaxCacheLineSize) GlobalLockType ConstPoolLock;
275 alignas(MaxCacheLineSize) GlobalLockType StatsLock;
276 alignas(MaxCacheLineSize) GlobalLockType TimerLock;
277
278 // StrLock is a global lock on the dump and emit output streams.
279 // IsStrLocked is used to validate the locking protocol, and can
280 // only be meaningfully inspected when StrLock is held. Note that
281 // in a production build, the dump and emit streams are not used in
282 // any meaningful way, so this locking is more for
283 // development/debugging purposes.
284 typedef std::recursive_mutex StrLockType;
285 StrLockType StrLock;
286 bool IsStrLocked;
287
196 Ostream *StrDump; // Stream for dumping / diagnostics 288 Ostream *StrDump; // Stream for dumping / diagnostics
197 Ostream *StrEmit; // Stream for code emission 289 Ostream *StrEmit; // Stream for code emission
198 290
199 ArenaAllocator<> Allocator; 291 ArenaAllocator<> Allocator;
200 VerboseMask VMask; 292 VerboseMask VMask;
201 std::unique_ptr<class ConstantPool> ConstPool; 293 std::unique_ptr<ConstantPool> ConstPool;
202 Intrinsics IntrinsicsInfo; 294 Intrinsics IntrinsicsInfo;
203 const TargetArch Arch; 295 const TargetArch Arch;
204 const OptLevel Opt; 296 const OptLevel Opt;
205 const IceString TestPrefix; 297 const IceString TestPrefix;
206 const ClFlags &Flags; 298 const ClFlags &Flags;
207 RandomNumberGenerator RNG; 299 RandomNumberGenerator RNG;
208 std::unique_ptr<ELFObjectWriter> ObjectWriter; 300 std::unique_ptr<ELFObjectWriter> ObjectWriter;
209 CodeStats StatsFunction;
210 CodeStats StatsCumulative; 301 CodeStats StatsCumulative;
211 std::vector<TimerStack> Timers; 302 std::vector<TimerStack> Timers;
212 std::vector<GlobalDeclaration *> GlobalDeclarations; 303 std::vector<GlobalDeclaration *> GlobalDeclarations;
213 304
305 LockedPtr<ArenaAllocator<>> getAllocator() {
306 return LockedPtr<ArenaAllocator<>>(&Allocator, AllocLock);
307 }
308 LockedPtr<ConstantPool> getConstPool() {
309 return LockedPtr<ConstantPool>(ConstPool.get(), ConstPoolLock);
310 }
311 LockedPtr<CodeStats> getStatsCumulative() {
312 return LockedPtr<CodeStats>(&StatsCumulative, StatsLock);
313 }
314 LockedPtr<std::vector<TimerStack>> getTimers() {
315 return LockedPtr<std::vector<TimerStack>>(&Timers, TimerLock);
316 }
317
318 std::vector<ThreadContext *> AllThreadContexts;
319 // Each thread has its own TLS pointer which is also held in
320 // AllThreadContexts.
321 thread_local static ThreadContext *TLS;
322
214 // Private helpers for mangleName() 323 // Private helpers for mangleName()
215 typedef llvm::SmallVector<char, 32> ManglerVector; 324 typedef llvm::SmallVector<char, 32> ManglerVector;
216 void incrementSubstitutions(ManglerVector &OldName) const; 325 void incrementSubstitutions(ManglerVector &OldName) const;
217 }; 326 };
218 327
219 // Helper class to push and pop a timer marker. The constructor 328 // Helper class to push and pop a timer marker. The constructor
220 // pushes a marker, and the destructor pops it. This is for 329 // pushes a marker, and the destructor pops it. This is for
221 // convenient timing of regions of code. 330 // convenient timing of regions of code.
222 class TimerMarker { 331 class TimerMarker {
223 TimerMarker(const TimerMarker &) = delete; 332 TimerMarker(const TimerMarker &) = delete;
(...skipping 14 matching lines...) Expand all
238 if (ALLOW_DUMP && Active) 347 if (ALLOW_DUMP && Active)
239 Ctx->popTimer(ID); 348 Ctx->popTimer(ID);
240 } 349 }
241 350
242 private: 351 private:
243 TimerIdT ID; 352 TimerIdT ID;
244 GlobalContext *const Ctx; 353 GlobalContext *const Ctx;
245 bool Active; 354 bool Active;
246 }; 355 };
247 356
357 // Helper class for locking the streams and then automatically
358 // unlocking them.
359 class OstreamLocker {
360 private:
361 OstreamLocker() = delete;
362 OstreamLocker(const OstreamLocker &) = delete;
363 OstreamLocker &operator=(const OstreamLocker &) = delete;
364
365 public:
366 explicit OstreamLocker(GlobalContext *Ctx) : Ctx(Ctx) { Ctx->lockStr(); }
367 ~OstreamLocker() { Ctx->unlockStr(); }
368
369 private:
370 GlobalContext *const Ctx;
371 };
372
248 } // end of namespace Ice 373 } // end of namespace Ice
249 374
250 #endif // SUBZERO_SRC_ICEGLOBALCONTEXT_H 375 #endif // SUBZERO_SRC_ICEGLOBALCONTEXT_H
OLDNEW
« no previous file with comments | « src/IceConverter.cpp ('k') | src/IceGlobalContext.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698