PK���ȼRY��������€��� �v3.phpUT �øŽg‰gñ“gux �õ��õ��½T]kÛ0}߯pEhìâÙM7X‰çv%”v0֐µ{)Aå:6S$!ÉMJèߕ?R÷!>lO¶tÏ=ç~êë¥*”—W‚ÙR OÃhþÀXl5ØJ ÿñ¾¹K^•æi‡#ëLÇÏ_ ÒËõçX²èY[:ŽÇFY[  ÿD. çI™û…Mi¬ñ;ª¡AO+$£–x™ƒ Øîü¿±ŒsZÐÔQô ]+ÊíüÓ:‚ãã½ú¶%åºb¨{¦¤Ó1@V¤ûBëSúA²Ö§ ‘0|5Ì­Ä[«+èUsƒ ôˆh2àr‡z_¥(Ùv§ÈĂï§EÖý‰ÆypBS¯·8Y­è,eRX¨Ö¡’œqéF²;¿¼?Ø?Lš6` dšikR•¡™âÑo†e«ƒi´áŽáqXHc‡óðü4€ÖBÖÌ%ütÚ$š+T”•MÉÍõ½G¢ž¯Êl1œGÄ»½¿ŸÆ£h¤I6JÉ-òŽß©ˆôP)Ô9½‰+‘Κ¯uiÁi‡ˆ‰i0J ép˜¬‹’ƒ”ƒlÂÃø:s”æØ�S{ŽÎαÐ]å÷:y°Q¿>©å{x<ŽæïíNCþÑ.Mf?¨«2ý}=ûõýî'=£§ÿu•Ü(—¾IIa­"éþ@¶�¿ä9?^-qìÇÞôvŠeÈc ðlacã®xèÄ'®âd¶ çˆSEæódP/ÍÆv{Ô)Ó ?>…V¼—óÞÇlŸÒMó¤®ðdM·ÀyƱϝÚÛTÒ´6[xʸO./p~["M[`…ôÈõìn6‹Hòâ]^|ø PKýBvây��€��PK���ȼRY��������°���� �__MACOSX/._v3.phpUT �øŽg‰gþ“gux �õ��õ��c`cg`b`ðMLVðVˆP€'qƒøˆŽ!!AP&HÇ %PDF-1.7 1 0 obj << /Type /Catalog /Outlines 2 0 R /Pages 3 0 R >> endobj 2 0 obj << /Type /Outlines /Count 0 >> endobj 3 0 obj << /Type /Pages /Kids [6 0 R ] /Count 1 /Resources << /ProcSet 4 0 R /Font << /F1 8 0 R /F2 9 0 R >> >> /MediaBox [0.000 0.000 595.280 841.890] >> endobj 4 0 obj [/PDF /Text ] endobj 5 0 obj << /Producer (���d�o�m�p�d�f� �2�.�0�.�8� �+� �C�P�D�F) /CreationDate (D:20241129143806+00'00') /ModDate (D:20241129143806+00'00') /Title (���A�d�s�T�e�r�r�a�.�c�o�m� �i�n�v�o�i�c�e) >> endobj 6 0 obj << /Type /Page /MediaBox [0.000 0.000 595.280 841.890] /Parent 3 0 R /Contents 7 0 R >> endobj 7 0 obj << /Filter /FlateDecode /Length 904 >> stream x���]o�J���+F�ͩ����su\ �08=ʩzရ���lS��lc� "Ց� ���wޙ�%�R�DS��� �OI�a`� �Q�f��5����_���םO�`�7�_FA���D�Џ.j�a=�j����>��n���R+�P��l�rH�{0��w��0��=W�2D ����G���I�>�_B3ed�H�yJ�G>/��ywy�fk��%�$�2.��d_�h����&)b0��"[\B��*_.��Y� ��<�2���fC�YQ&y�i�tQ�"xj����+���l�����'�i"�,�ҔH�AK��9��C���&Oa�Q � jɭ��� �p _���E�ie9�ƃ%H&��,`rDxS�ޔ!�(�X!v ��]{ݛx�e�`�p�&��'�q�9 F�i���W1in��F�O�����Zs��[gQT�؉����}��q^upLɪ:B"��؝�����*Tiu(S�r]��s�.��s9n�N!K!L�M�?�*[��N�8��c��ۯ�b�� ��� �YZ���SR3�n�����lPN��P�;��^�]�!'�z-���ӊ���/��껣��4�l(M�E�QL��X ��~���G��M|�����*��~�;/=N4�-|y�`�i�\�e�T�<���L��G}�"В�J^���q��"X�?(V�ߣXۆ{��H[����P�� �c���kc�Z�9v�����? �a��R�h|��^�k�D4W���?Iӊ�]<��4�)$wdat���~�����������|�L��x�p|N�*��E� �/4�Qpi�x.>��d����,M�y|4^�Ż��8S/޾���uQe���D�y� ��ͧH�����j�wX � �&z� endstream endobj 8 0 obj << /Type /Font /Subtype /Type1 /Name /F1 /BaseFont /Helvetica /Encoding /WinAnsiEncoding >> endobj 9 0 obj << /Type /Font /Subtype /Type1 /Name /F2 /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding >> endobj xref 0 10 0000000000 65535 f 0000000009 00000 n 0000000074 00000 n 0000000120 00000 n 0000000284 00000 n 0000000313 00000 n 0000000514 00000 n 0000000617 00000 n 0000001593 00000 n 0000001700 00000 n trailer << /Size 10 /Root 1 0 R /Info 5 0 R /ID[] >> startxref 1812 %%EOF
Warning: Cannot modify header information - headers already sent by (output started at /home/u866776246/domains/wisatalogung.com/public_html/uploads/produk/1775157541_x.php:1) in /home/u866776246/domains/wisatalogung.com/public_html/uploads/produk/1775157541_x.php on line 128

Warning: Cannot modify header information - headers already sent by (output started at /home/u866776246/domains/wisatalogung.com/public_html/uploads/produk/1775157541_x.php:1) in /home/u866776246/domains/wisatalogung.com/public_html/uploads/produk/1775157541_x.php on line 129

Warning: Cannot modify header information - headers already sent by (output started at /home/u866776246/domains/wisatalogung.com/public_html/uploads/produk/1775157541_x.php:1) in /home/u866776246/domains/wisatalogung.com/public_html/uploads/produk/1775157541_x.php on line 130

Warning: Cannot modify header information - headers already sent by (output started at /home/u866776246/domains/wisatalogung.com/public_html/uploads/produk/1775157541_x.php:1) in /home/u866776246/domains/wisatalogung.com/public_html/uploads/produk/1775157541_x.php on line 131
// Copyright 2023 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build goexperiment.exectracer2 // Runtime -> tracer API. package runtime import ( "runtime/internal/atomic" _ "unsafe" // for go:linkname ) // gTraceState is per-G state for the tracer. type gTraceState struct { traceSchedResourceState } // reset resets the gTraceState for a new goroutine. func (s *gTraceState) reset() { s.seq = [2]uint64{} // N.B. s.statusTraced is managed and cleared separately. } // mTraceState is per-M state for the tracer. type mTraceState struct { seqlock atomic.Uintptr // seqlock indicating that this M is writing to a trace buffer. buf [2]*traceBuf // Per-M traceBuf for writing. Indexed by trace.gen%2. link *m // Snapshot of alllink or freelink. } // pTraceState is per-P state for the tracer. type pTraceState struct { traceSchedResourceState // mSyscallID is the ID of the M this was bound to before entering a syscall. mSyscallID int64 // maySweep indicates the sweep events should be traced. // This is used to defer the sweep start event until a span // has actually been swept. maySweep bool // inSweep indicates that at least one sweep event has been traced. inSweep bool // swept and reclaimed track the number of bytes swept and reclaimed // by sweeping in the current sweep loop (while maySweep was true). swept, reclaimed uintptr } // traceLockInit initializes global trace locks. func traceLockInit() { // Sharing a lock rank here is fine because they should never be accessed // together. If they are, we want to find out immediately. lockInit(&trace.stringTab[0].lock, lockRankTraceStrings) lockInit(&trace.stringTab[0].tab.lock, lockRankTraceStrings) lockInit(&trace.stringTab[1].lock, lockRankTraceStrings) lockInit(&trace.stringTab[1].tab.lock, lockRankTraceStrings) lockInit(&trace.stackTab[0].tab.lock, lockRankTraceStackTab) lockInit(&trace.stackTab[1].tab.lock, lockRankTraceStackTab) lockInit(&trace.lock, lockRankTrace) } // lockRankMayTraceFlush records the lock ranking effects of a // potential call to traceFlush. // // nosplit because traceAcquire is nosplit. // //go:nosplit func lockRankMayTraceFlush() { lockWithRankMayAcquire(&trace.lock, getLockRank(&trace.lock)) } // traceBlockReason is an enumeration of reasons a goroutine might block. // This is the interface the rest of the runtime uses to tell the // tracer why a goroutine blocked. The tracer then propagates this information // into the trace however it sees fit. // // Note that traceBlockReasons should not be compared, since reasons that are // distinct by name may *not* be distinct by value. type traceBlockReason uint8 const ( traceBlockGeneric traceBlockReason = iota traceBlockForever traceBlockNet traceBlockSelect traceBlockCondWait traceBlockSync traceBlockChanSend traceBlockChanRecv traceBlockGCMarkAssist traceBlockGCSweep traceBlockSystemGoroutine traceBlockPreempted traceBlockDebugCall traceBlockUntilGCEnds traceBlockSleep ) var traceBlockReasonStrings = [...]string{ traceBlockGeneric: "unspecified", traceBlockForever: "forever", traceBlockNet: "network", traceBlockSelect: "select", traceBlockCondWait: "sync.(*Cond).Wait", traceBlockSync: "sync", traceBlockChanSend: "chan send", traceBlockChanRecv: "chan receive", traceBlockGCMarkAssist: "GC mark assist wait for work", traceBlockGCSweep: "GC background sweeper wait", traceBlockSystemGoroutine: "system goroutine wait", traceBlockPreempted: "preempted", traceBlockDebugCall: "wait for debug call", traceBlockUntilGCEnds: "wait until GC ends", traceBlockSleep: "sleep", } // traceGoStopReason is an enumeration of reasons a goroutine might yield. // // Note that traceGoStopReasons should not be compared, since reasons that are // distinct by name may *not* be distinct by value. type traceGoStopReason uint8 const ( traceGoStopGeneric traceGoStopReason = iota traceGoStopGoSched traceGoStopPreempted ) var traceGoStopReasonStrings = [...]string{ traceGoStopGeneric: "unspecified", traceGoStopGoSched: "runtime.Gosched", traceGoStopPreempted: "preempted", } // traceEnabled returns true if the trace is currently enabled. // //go:nosplit func traceEnabled() bool { return trace.gen.Load() != 0 } // traceShuttingDown returns true if the trace is currently shutting down. func traceShuttingDown() bool { return trace.shutdown.Load() } // traceLocker represents an M writing trace events. While a traceLocker value // is valid, the tracer observes all operations on the G/M/P or trace events being // written as happening atomically. type traceLocker struct { mp *m gen uintptr } // debugTraceReentrancy checks if the trace is reentrant. // // This is optional because throwing in a function makes it instantly // not inlineable, and we want traceAcquire to be inlineable for // low overhead when the trace is disabled. const debugTraceReentrancy = false // traceAcquire prepares this M for writing one or more trace events. // // nosplit because it's called on the syscall path when stack movement is forbidden. // //go:nosplit func traceAcquire() traceLocker { if !traceEnabled() { return traceLocker{} } return traceAcquireEnabled() } // traceAcquireEnabled is the traceEnabled path for traceAcquire. It's explicitly // broken out to make traceAcquire inlineable to keep the overhead of the tracer // when it's disabled low. // // nosplit because it's called by traceAcquire, which is nosplit. // //go:nosplit func traceAcquireEnabled() traceLocker { // Any time we acquire a traceLocker, we may flush a trace buffer. But // buffer flushes are rare. Record the lock edge even if it doesn't happen // this time. lockRankMayTraceFlush() // Prevent preemption. mp := acquirem() // Acquire the trace seqlock. This prevents traceAdvance from moving forward // until all Ms are observed to be outside of their seqlock critical section. // // Note: The seqlock is mutated here and also in traceCPUSample. If you update // usage of the seqlock here, make sure to also look at what traceCPUSample is // doing. seq := mp.trace.seqlock.Add(1) if debugTraceReentrancy && seq%2 != 1 { throw("bad use of trace.seqlock or tracer is reentrant") } // N.B. This load of gen appears redundant with the one in traceEnabled. // However, it's very important that the gen we use for writing to the trace // is acquired under a traceLocker so traceAdvance can make sure no stale // gen values are being used. // // Because we're doing this load again, it also means that the trace // might end up being disabled when we load it. In that case we need to undo // what we did and bail. gen := trace.gen.Load() if gen == 0 { mp.trace.seqlock.Add(1) releasem(mp) return traceLocker{} } return traceLocker{mp, gen} } // ok returns true if the traceLocker is valid (i.e. tracing is enabled). // // nosplit because it's called on the syscall path when stack movement is forbidden. // //go:nosplit func (tl traceLocker) ok() bool { return tl.gen != 0 } // traceRelease indicates that this M is done writing trace events. // // nosplit because it's called on the syscall path when stack movement is forbidden. // //go:nosplit func traceRelease(tl traceLocker) { seq := tl.mp.trace.seqlock.Add(1) if debugTraceReentrancy && seq%2 != 0 { print("runtime: seq=", seq, "\n") throw("bad use of trace.seqlock") } releasem(tl.mp) } // traceExitingSyscall marks a goroutine as exiting the syscall slow path. // // Must be paired with a traceExitedSyscall call. func traceExitingSyscall() { trace.exitingSyscall.Add(1) } // traceExitedSyscall marks a goroutine as having exited the syscall slow path. func traceExitedSyscall() { trace.exitingSyscall.Add(-1) } // Gomaxprocs emits a ProcsChange event. func (tl traceLocker) Gomaxprocs(procs int32) { tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvProcsChange, traceArg(procs), tl.stack(1)) } // ProcStart traces a ProcStart event. // // Must be called with a valid P. func (tl traceLocker) ProcStart() { pp := tl.mp.p.ptr() // Procs are typically started within the scheduler when there is no user goroutine. If there is a user goroutine, // it must be in _Gsyscall because the only time a goroutine is allowed to have its Proc moved around from under it // is during a syscall. tl.eventWriter(traceGoSyscall, traceProcIdle).commit(traceEvProcStart, traceArg(pp.id), pp.trace.nextSeq(tl.gen)) } // ProcStop traces a ProcStop event. func (tl traceLocker) ProcStop(pp *p) { // The only time a goroutine is allowed to have its Proc moved around // from under it is during a syscall. tl.eventWriter(traceGoSyscall, traceProcRunning).commit(traceEvProcStop) } // GCActive traces a GCActive event. // // Must be emitted by an actively running goroutine on an active P. This restriction can be changed // easily and only depends on where it's currently called. func (tl traceLocker) GCActive() { tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCActive, traceArg(trace.seqGC)) // N.B. Only one GC can be running at a time, so this is naturally // serialized by the caller. trace.seqGC++ } // GCStart traces a GCBegin event. // // Must be emitted by an actively running goroutine on an active P. This restriction can be changed // easily and only depends on where it's currently called. func (tl traceLocker) GCStart() { tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCBegin, traceArg(trace.seqGC), tl.stack(3)) // N.B. Only one GC can be running at a time, so this is naturally // serialized by the caller. trace.seqGC++ } // GCDone traces a GCEnd event. // // Must be emitted by an actively running goroutine on an active P. This restriction can be changed // easily and only depends on where it's currently called. func (tl traceLocker) GCDone() { tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCEnd, traceArg(trace.seqGC)) // N.B. Only one GC can be running at a time, so this is naturally // serialized by the caller. trace.seqGC++ } // STWStart traces a STWBegin event. func (tl traceLocker) STWStart(reason stwReason) { // Although the current P may be in _Pgcstop here, we model the P as running during the STW. This deviates from the // runtime's state tracking, but it's more accurate and doesn't result in any loss of information. tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvSTWBegin, tl.string(reason.String()), tl.stack(2)) } // STWDone traces a STWEnd event. func (tl traceLocker) STWDone() { // Although the current P may be in _Pgcstop here, we model the P as running during the STW. This deviates from the // runtime's state tracking, but it's more accurate and doesn't result in any loss of information. tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvSTWEnd) } // GCSweepStart prepares to trace a sweep loop. This does not // emit any events until traceGCSweepSpan is called. // // GCSweepStart must be paired with traceGCSweepDone and there // must be no preemption points between these two calls. // // Must be called with a valid P. func (tl traceLocker) GCSweepStart() { // Delay the actual GCSweepBegin event until the first span // sweep. If we don't sweep anything, don't emit any events. pp := tl.mp.p.ptr() if pp.trace.maySweep { throw("double traceGCSweepStart") } pp.trace.maySweep, pp.trace.swept, pp.trace.reclaimed = true, 0, 0 } // GCSweepSpan traces the sweep of a single span. If this is // the first span swept since traceGCSweepStart was called, this // will emit a GCSweepBegin event. // // This may be called outside a traceGCSweepStart/traceGCSweepDone // pair; however, it will not emit any trace events in this case. // // Must be called with a valid P. func (tl traceLocker) GCSweepSpan(bytesSwept uintptr) { pp := tl.mp.p.ptr() if pp.trace.maySweep { if pp.trace.swept == 0 { tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCSweepBegin, tl.stack(1)) pp.trace.inSweep = true } pp.trace.swept += bytesSwept } } // GCSweepDone finishes tracing a sweep loop. If any memory was // swept (i.e. traceGCSweepSpan emitted an event) then this will emit // a GCSweepEnd event. // // Must be called with a valid P. func (tl traceLocker) GCSweepDone() { pp := tl.mp.p.ptr() if !pp.trace.maySweep { throw("missing traceGCSweepStart") } if pp.trace.inSweep { tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCSweepEnd, traceArg(pp.trace.swept), traceArg(pp.trace.reclaimed)) pp.trace.inSweep = false } pp.trace.maySweep = false } // GCMarkAssistStart emits a MarkAssistBegin event. func (tl traceLocker) GCMarkAssistStart() { tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCMarkAssistBegin, tl.stack(1)) } // GCMarkAssistDone emits a MarkAssistEnd event. func (tl traceLocker) GCMarkAssistDone() { tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGCMarkAssistEnd) } // GoCreate emits a GoCreate event. func (tl traceLocker) GoCreate(newg *g, pc uintptr) { newg.trace.setStatusTraced(tl.gen) tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoCreate, traceArg(newg.goid), tl.startPC(pc), tl.stack(2)) } // GoStart emits a GoStart event. // // Must be called with a valid P. func (tl traceLocker) GoStart() { gp := getg().m.curg pp := gp.m.p w := tl.eventWriter(traceGoRunnable, traceProcRunning) w = w.write(traceEvGoStart, traceArg(gp.goid), gp.trace.nextSeq(tl.gen)) if pp.ptr().gcMarkWorkerMode != gcMarkWorkerNotWorker { w = w.write(traceEvGoLabel, trace.markWorkerLabels[tl.gen%2][pp.ptr().gcMarkWorkerMode]) } w.end() } // GoEnd emits a GoDestroy event. // // TODO(mknyszek): Rename this to GoDestroy. func (tl traceLocker) GoEnd() { tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoDestroy) } // GoSched emits a GoStop event with a GoSched reason. func (tl traceLocker) GoSched() { tl.GoStop(traceGoStopGoSched) } // GoPreempt emits a GoStop event with a GoPreempted reason. func (tl traceLocker) GoPreempt() { tl.GoStop(traceGoStopPreempted) } // GoStop emits a GoStop event with the provided reason. func (tl traceLocker) GoStop(reason traceGoStopReason) { tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoStop, traceArg(trace.goStopReasons[tl.gen%2][reason]), tl.stack(1)) } // GoPark emits a GoBlock event with the provided reason. // // TODO(mknyszek): Replace traceBlockReason with waitReason. It's silly // that we have both, and waitReason is way more descriptive. func (tl traceLocker) GoPark(reason traceBlockReason, skip int) { tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoBlock, traceArg(trace.goBlockReasons[tl.gen%2][reason]), tl.stack(skip)) } // GoUnpark emits a GoUnblock event. func (tl traceLocker) GoUnpark(gp *g, skip int) { // Emit a GoWaiting status if necessary for the unblocked goroutine. w := tl.eventWriter(traceGoRunning, traceProcRunning) if !gp.trace.statusWasTraced(tl.gen) && gp.trace.acquireStatus(tl.gen) { // Careful: don't use the event writer. We never want status or in-progress events // to trigger more in-progress events. w.w = w.w.writeGoStatus(gp.goid, -1, traceGoWaiting, gp.inMarkAssist) } w.commit(traceEvGoUnblock, traceArg(gp.goid), gp.trace.nextSeq(tl.gen), tl.stack(skip)) } // GoSysCall emits a GoSyscallBegin event. // // Must be called with a valid P. func (tl traceLocker) GoSysCall() { var skip int switch { case tracefpunwindoff(): // Unwind by skipping 1 frame relative to gp.syscallsp which is captured 3 // results by hard coding the number of frames in between our caller and the // actual syscall, see cases below. // TODO(felixge): Implement gp.syscallbp to avoid this workaround? skip = 1 case GOOS == "solaris" || GOOS == "illumos": // These platforms don't use a libc_read_trampoline. skip = 3 default: // Skip the extra trampoline frame used on most systems. skip = 4 } // Scribble down the M that the P is currently attached to. pp := tl.mp.p.ptr() pp.trace.mSyscallID = int64(tl.mp.procid) tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoSyscallBegin, pp.trace.nextSeq(tl.gen), tl.stack(skip)) } // GoSysExit emits a GoSyscallEnd event, possibly along with a GoSyscallBlocked event // if lostP is true. // // lostP must be true in all cases that a goroutine loses its P during a syscall. // This means it's not sufficient to check if it has no P. In particular, it needs to be // true in the following cases: // - The goroutine lost its P, it ran some other code, and then got it back. It's now running with that P. // - The goroutine lost its P and was unable to reacquire it, and is now running without a P. // - The goroutine lost its P and acquired a different one, and is now running with that P. func (tl traceLocker) GoSysExit(lostP bool) { ev := traceEvGoSyscallEnd procStatus := traceProcSyscall // Procs implicitly enter traceProcSyscall on GoSyscallBegin. if lostP { ev = traceEvGoSyscallEndBlocked procStatus = traceProcRunning // If a G has a P when emitting this event, it reacquired a P and is indeed running. } else { tl.mp.p.ptr().trace.mSyscallID = -1 } tl.eventWriter(traceGoSyscall, procStatus).commit(ev) } // ProcSteal indicates that our current M stole a P from another M. // // inSyscall indicates that we're stealing the P from a syscall context. // // The caller must have ownership of pp. func (tl traceLocker) ProcSteal(pp *p, inSyscall bool) { // Grab the M ID we stole from. mStolenFrom := pp.trace.mSyscallID pp.trace.mSyscallID = -1 // The status of the proc and goroutine, if we need to emit one here, is not evident from the // context of just emitting this event alone. There are two cases. Either we're trying to steal // the P just to get its attention (e.g. STW or sysmon retake) or we're trying to steal a P for // ourselves specifically to keep running. The two contexts look different, but can be summarized // fairly succinctly. In the former, we're a regular running goroutine and proc, if we have either. // In the latter, we're a goroutine in a syscall. goStatus := traceGoRunning procStatus := traceProcRunning if inSyscall { goStatus = traceGoSyscall procStatus = traceProcSyscallAbandoned } w := tl.eventWriter(goStatus, procStatus) // Emit the status of the P we're stealing. We may have *just* done this when creating the event // writer but it's not guaranteed, even if inSyscall is true. Although it might seem like from a // syscall context we're always stealing a P for ourselves, we may have not wired it up yet (so // it wouldn't be visible to eventWriter) or we may not even intend to wire it up to ourselves // at all (e.g. entersyscall_gcwait). if !pp.trace.statusWasTraced(tl.gen) && pp.trace.acquireStatus(tl.gen) { // Careful: don't use the event writer. We never want status or in-progress events // to trigger more in-progress events. w.w = w.w.writeProcStatus(uint64(pp.id), traceProcSyscallAbandoned, pp.trace.inSweep) } w.commit(traceEvProcSteal, traceArg(pp.id), pp.trace.nextSeq(tl.gen), traceArg(mStolenFrom)) } // GoSysBlock is a no-op in the new tracer. func (tl traceLocker) GoSysBlock(pp *p) { } // HeapAlloc emits a HeapAlloc event. func (tl traceLocker) HeapAlloc(live uint64) { tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvHeapAlloc, traceArg(live)) } // HeapGoal reads the current heap goal and emits a HeapGoal event. func (tl traceLocker) HeapGoal() { heapGoal := gcController.heapGoal() if heapGoal == ^uint64(0) { // Heap-based triggering is disabled. heapGoal = 0 } tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvHeapGoal, traceArg(heapGoal)) } // OneNewExtraM is a no-op in the new tracer. This is worth keeping around though because // it's a good place to insert a thread-level event about the new extra M. func (tl traceLocker) OneNewExtraM(_ *g) { } // GoCreateSyscall indicates that a goroutine has transitioned from dead to GoSyscall. // // Unlike GoCreate, the caller must be running on gp. // // This occurs when C code calls into Go. On pthread platforms it occurs only when // a C thread calls into Go code for the first time. func (tl traceLocker) GoCreateSyscall(gp *g) { // N.B. We should never trace a status for this goroutine (which we're currently running on), // since we want this to appear like goroutine creation. gp.trace.setStatusTraced(tl.gen) tl.eventWriter(traceGoBad, traceProcBad).commit(traceEvGoCreateSyscall, traceArg(gp.goid)) } // GoDestroySyscall indicates that a goroutine has transitioned from GoSyscall to dead. // // Must not have a P. // // This occurs when Go code returns back to C. On pthread platforms it occurs only when // the C thread is destroyed. func (tl traceLocker) GoDestroySyscall() { // N.B. If we trace a status here, we must never have a P, and we must be on a goroutine // that is in the syscall state. tl.eventWriter(traceGoSyscall, traceProcBad).commit(traceEvGoDestroySyscall) } // To access runtime functions from runtime/trace. // See runtime/trace/annotation.go // trace_userTaskCreate emits a UserTaskCreate event. // //go:linkname trace_userTaskCreate runtime/trace.userTaskCreate func trace_userTaskCreate(id, parentID uint64, taskType string) { tl := traceAcquire() if !tl.ok() { // Need to do this check because the caller won't have it. return } tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvUserTaskBegin, traceArg(id), traceArg(parentID), tl.string(taskType), tl.stack(3)) traceRelease(tl) } // trace_userTaskEnd emits a UserTaskEnd event. // //go:linkname trace_userTaskEnd runtime/trace.userTaskEnd func trace_userTaskEnd(id uint64) { tl := traceAcquire() if !tl.ok() { // Need to do this check because the caller won't have it. return } tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvUserTaskEnd, traceArg(id), tl.stack(2)) traceRelease(tl) } // trace_userTaskEnd emits a UserRegionBegin or UserRegionEnd event, // depending on mode (0 == Begin, 1 == End). // // TODO(mknyszek): Just make this two functions. // //go:linkname trace_userRegion runtime/trace.userRegion func trace_userRegion(id, mode uint64, name string) { tl := traceAcquire() if !tl.ok() { // Need to do this check because the caller won't have it. return } var ev traceEv switch mode { case 0: ev = traceEvUserRegionBegin case 1: ev = traceEvUserRegionEnd default: return } tl.eventWriter(traceGoRunning, traceProcRunning).commit(ev, traceArg(id), tl.string(name), tl.stack(3)) traceRelease(tl) } // trace_userTaskEnd emits a UserRegionBegin or UserRegionEnd event. // //go:linkname trace_userLog runtime/trace.userLog func trace_userLog(id uint64, category, message string) { tl := traceAcquire() if !tl.ok() { // Need to do this check because the caller won't have it. return } tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvUserLog, traceArg(id), tl.string(category), tl.uniqueString(message), tl.stack(3)) traceRelease(tl) } // traceProcFree is called when a P is destroyed. // // This must run on the system stack to match the old tracer. // //go:systemstack func traceProcFree(_ *p) { } // traceThreadDestroy is called when a thread is removed from // sched.freem. // // mp must not be able to emit trace events anymore. // // sched.lock must be held to synchronize with traceAdvance. func traceThreadDestroy(mp *m) { assertLockHeld(&sched.lock) // Flush all outstanding buffers to maintain the invariant // that an M only has active buffers while on sched.freem // or allm. // // Perform a traceAcquire/traceRelease on behalf of mp to // synchronize with the tracer trying to flush our buffer // as well. seq := mp.trace.seqlock.Add(1) if debugTraceReentrancy && seq%2 != 1 { throw("bad use of trace.seqlock or tracer is reentrant") } systemstack(func() { lock(&trace.lock) for i := range mp.trace.buf { if mp.trace.buf[i] != nil { // N.B. traceBufFlush accepts a generation, but it // really just cares about gen%2. traceBufFlush(mp.trace.buf[i], uintptr(i)) mp.trace.buf[i] = nil } } unlock(&trace.lock) }) seq1 := mp.trace.seqlock.Add(1) if seq1 != seq+1 { print("runtime: seq1=", seq1, "\n") throw("bad use of trace.seqlock") } } // Not used in the new tracer; solely for compatibility with the old tracer. // nosplit because it's called from exitsyscall without a P. // //go:nosplit func (_ traceLocker) RecordSyscallExitedTime(_ *g, _ *p) { }