/*++ Copyright (c) 2000 Microsoft Corporation Module Name: icecap.c Abstract: Macro definitions for manually-inserted icecap probes Author: Rick Vicik (rickv) 10-Aug-2001 Revision History: --*/ #ifdef _CAPKERN PublicFunction(_CAP_Start_Profiling2) PublicFunction(_CAP_End_Profiling2) #define CAPSTART(parent,child) \ movl out0 = @fptr(parent) ;\ movl out1 = @fptr(child) ;\ br.call.sptk.few b0=_CAP_Start_Profiling2;; #define CAPEND(parent) \ movl out0 = @fptr(parent) ;\ br.call.sptk.few b0=_CAP_End_Profiling2;; #ifdef CAPKERN_SYNCH_POINTS #define REC1INTSIZE 32 #define REC2INTSIZE 40 .global BBTBuffer // // Kernel Icecap logs to Perfmem (BBTBuffer) using the following format: // // BBTBuffer[0] contains the length in pages (4k or 8k) // BBTBuffer[1] is a flagword: 1 = trace // 2 = RDPMD4 // 4 = user stack dump // BBTBuffer[2] is ptr to beginning of cpu0 buffer // BBTBuffer[3] is ptr to beginning of cpu1 buffer (also end of cpu0 buffer) // BBTBuffer[4] is ptr to beginning of cpu2 buffer (also end of cpu1 buffer) // ... // BBTBuffer[n+2] is ptr to beginning of cpu 'n' buffer (also end of cpu 'n-1' buffer) // BBTBuffer[n+3] is ptr the end of cpu 'n' buffer // // The area starting with &BBTBuffer[n+4] is divided into private buffers // for each cpu. The first dword in each cpu-private buffer points to the // beginning of freespace in that buffer. Each one is initialized to point // just after itself. Space is claimed using lock xadd on that dword. // If the resulting value points beyond the beginning of the next cpu's // buffer, this buffer is considered full and nothing further is logged. // Each cpu's freespace pointer is in a separate cacheline. // both of these macros mutate the tmp? register arguments and the ar.ccv register #define CAPSPINLOG1INT(data, spare, tmp1, tmp2, tmp3, tmp4, tmpp) \ ;; \ movl tmp1 = BBTBuffer ;\ ;; \ ld8 tmp1 = [tmp1] /* tmp1 = ptr to BBTBuffer*/ ;\ ;; \ cmp.eq tmpp = r0, tmp1 ;\ (tmpp) br.cond.dpnt.few ENDCAPSPINLOG1INT@__LINE__ ;\ adds tmp2 = 8, tmp1 ;\ ;; \ ld8 tmp2 = [tmp2] /* tmp2 = BBTBuffer[1] */ ;\ ;; \ tbit.z tmpp = tmp2, 0 ;\ (tmpp) br.cond.dpnt.few ENDCAPSPINLOG1INT@__LINE__ ;\ movl tmp3 = KiPcr + PcNumber ;\ ;; \ ld1 tmp3 = [tmp3] /* tmp3 = 1 byte cpu# */ ;\ ;; \ add tmp3 = 2, tmp3 ;\ ;; \ shladd tmp3 = tmp3, 3, tmp1 /* tmp3 = &BBTBuffer[cpu# + 2] */ ;\ ;; \ ld8 tmp1 = [tmp3] /* tmp1 = BBTBuffer[cpu# + 2] (&freeptr) */ ;\ add tmp2 = 8, tmp3 ;\ ;; \ cmp.eq tmpp = r0, tmp1 ;\ ld8 tmp3 = [tmp1] /* tmp3 = BBTBuffer[cpu#+2][0] (freeptr) */ ;\ ld8 tmp2 = [tmp2] /* tmp2 = BBTBuffer[(cpu#+1)+2] (beginnextbuf) */ ;\ (tmpp) br.cond.dpnt.few ENDCAPSPINLOG1INT@__LINE__ ;\ ;; \ cmp.gtu tmpp = tmp3, tmp2 ;\ (tmpp) br.cond.dpnt.few ENDCAPSPINLOG1INT@__LINE__ ;\ ;; \ RETRYCAPSPINLOG1INT@__LINE__: \ ld8 tmp3 = [tmp1] /* tmp3 = reloaded freeptr */ ;\ ;; \ mov.m ar.ccv = tmp3 /* only exchange on our loaded freeptr */ ;\ add tmp4 = REC1INTSIZE, tmp3 /* new freeptr val */ ;\ ;; \ cmpxchg8.acq tmp4=[tmp1], tmp4, ar.ccv /* tmp4 = freeptr before xchng */ ;\ ;; \ cmp.ne tmpp = tmp4, tmp3 /* if cmpxchg failed, retry */ ;\ (tmpp) br.cond.dpnt.few RETRYCAPSPINLOG1INT@__LINE__ ;\ add tmp1 = REC1INTSIZE, tmp4 /* tmp1 = end of record */ ;\ add tmp3 = 8, tmp4 /* tmp3 = 8 bytes into record */ ;\ ;; \ cmp.geu tmpp = tmp1, tmp2 /* check if end of record is within buf */ ;\ (tmpp) br.cond.dpnt.few ENDCAPSPINLOG1INT@__LINE__ ;\ movl tmp2 = (REC1INTSIZE - 4)<<16 ;\ ;; \ add tmp2 = 16|(spare<<8), tmp2 ;\ ;; \ st8 [tmp4] = tmp2, 16 /* store type(16),spare,size */ ;\ mov.m tmp1 = ar.itc ;\ ;; \ st8 [tmp3] = tmp1 /* store TS */ ;\ st8 [tmp4] = data, 8 /* store data */ ;\ mov tmp3 = brp ;\ ;; \ st8 [tmp4] = tmp3 ;\ ;; \ ENDCAPSPINLOG1INT@__LINE__: #define CAPSPINLOG2INT(data1, data2, spare, tmp1, tmp2, tmp3, tmp4, tmpp) \ ;; \ movl tmp1 = BBTBuffer ;\ ;; \ ld8 tmp1 = [tmp1] ;\ ;; \ cmp.eq tmpp = r0, tmp1 ;\ (tmpp) br.cond.dpnt.few ENDCAPSPINLOG2INT@__LINE__ ;\ adds tmp2 = 8, tmp1 ;\ ;; \ ld8 tmp2 = [tmp2] ;\ ;; \ tbit.z tmpp = tmp2, 0 ;\ (tmpp) br.cond.dpnt.few ENDCAPSPINLOG2INT@__LINE__ ;\ movl tmp3 = KiPcr + PcNumber ;\ ;; \ ld1 tmp3 = [tmp3] ;\ ;; \ add tmp3 = 2, tmp3 ;\ ;; \ shladd tmp3 = tmp3, 3, tmp1 ;\ ;; \ ld8 tmp1 = [tmp3] ;\ add tmp2 = 8, tmp3 ;\ ;; \ cmp.eq tmpp = r0, tmp1 ;\ ld8 tmp3 = [tmp1] ;\ ld8 tmp2 = [tmp2] ;\ (tmpp) br.cond.dpnt.few ENDCAPSPINLOG2INT@__LINE__ ;\ ;; \ cmp.gtu tmpp = tmp3, tmp2 ;\ (tmpp) br.cond.dpnt.few ENDCAPSPINLOG2INT@__LINE__ ;\ ;; \ RETRYCAPSPINLOG2INT@__LINE__: \ ld8 tmp3 = [tmp1] ;\ ;; \ mov.m ar.ccv = tmp3 ;\ add tmp4 = REC2INTSIZE, tmp3 ;\ ;; \ cmpxchg8.acq tmp4=[tmp1], tmp4, ar.ccv ;\ ;; \ cmp.ne tmpp = tmp4, tmp3 ;\ (tmpp) br.cond.dpnt.few RETRYCAPSPINLOG2INT@__LINE__ ;\ add tmp1 = REC2INTSIZE, tmp4 ;\ ;; \ cmp.geu tmpp = tmp1, tmp2 ;\ (tmpp) br.cond.dpnt.few ENDCAPSPINLOG2INT@__LINE__ ;\ movl tmp2 = (REC2INTSIZE - 4)<<16 ;\ ;; \ add tmp2 = 16|(spare<<8), tmp2 ;\ add tmp3 = 16, tmp4 ;\ ;; \ st8 [tmp4] = tmp2, 8 ;\ st8 [tmp3] = data1, 8 ;\ mov.m tmp1 = ar.itc ;\ ;; \ st8 [tmp4] = tmp1 ;\ st8 [tmp3] = data2, 8 ;\ mov tmp4 = brp ;\ ;; \ st8 [tmp3] = tmp4 ;\ ;; \ ENDCAPSPINLOG2INT@__LINE__: //++ // Routine: // // CAP_ACQUIRE_SPINLOCK(rpLock, rOwn, Loop) // // Routine Description: // // Acquire a spinlock. Waits for lock to become free // by spinning on the cached lock value. // // Agruments: // // rpLock: pointer to the spinlock (64-bit) // rOwn: value to store in lock to indicate owner // Depending on call location, it could be: // - rpLock // - pointer to process // - pointer to thread // - pointer to PRCB // Loop: unique name for loop label // // Return Value: // // None // // Notes: // // Uses temporaries: predicates pt0, pt1, pt2, and GR t22. //-- #define CAP_ACQUIRE_SPINLOCK(rpLock, rOwn, Loop, rCounter, temp1, temp2, temp3) \ cmp##.##eq pt0, pt1 = zero, zero ;\ cmp##.##eq pt2 = zero, zero ;\ mov rCounter = -1 ;\ ;; ;\ Loop: ;\ .pred.rel "mutex",pt0,pt1 ;\ (pt1) YIELD ;\ (pt0) xchg8 t22 = [rpLock], rOwn ;\ (pt1) ld8##.##nt1 t22 = [rpLock] ;\ ;; ;\ (pt0) cmp##.##ne pt2 = zero, t22 ;\ cmp##.##eq pt0, pt1 = zero, t22 ;\ add rCounter = 1, rCounter ;\ (pt2) br##.##dpnt Loop ;\ ;; ;\ CAPSPINLOG1INT(rpLock, 1, t22, temp1, temp2, temp3, pt2) ;\ cmp##.##eq pt2 = zero, rCounter ;\ (pt2) br##.##cond##.##sptk CAP_SKIP_COLL_LOG@__LINE__ ;\ CAPSPINLOG2INT(rCounter, rpLock, 2, t22, temp1, temp2, temp3, pt2) ;\ CAP_SKIP_COLL_LOG@__LINE__: //++ // Routine: // // CAP_RELEASE_SPINLOCK(rpLock) // // Routine Description: // // Release a spinlock by setting lock to zero. // // Agruments: // // rpLock: pointer to the spinlock. // // Return Value: // // None // // Notes: // // Uses an ordered store to ensure previous memory accesses in // critical section complete. //-- #define CAP_RELEASE_SPINLOCK(rpLock, temp1, temp2, temp3, temp4, tempp) \ st8##.##rel [rpLock] = zero ;\ CAPSPINLOG1INT(rpLock, 7, temp1, temp2, temp3, temp4, tempp) #endif //CAPKERN_SYNCH_POINTS #else //!defined(_CAPKERN) #define CAPSTART(parent,child) #define CAPEND(parent) #endif