SCCSID equ "@(#)perfvwa.asm     6.18 92/05/21"

;
;       IBM/Microsoft Confidential
;
;       Copyright (c) IBM Corporation 1987, 1989
;       Copyright (c) Microsoft Corporation 1987, 1989
;
;       All Rights Reserved

        PAGE    , 132
        TITLE   'PerfvwA--Perfview (Assembler)'

;       PERFVWA.ASM
;
;       Perfview (PVW) functions (Assembly language)
;
;       NOTES   In order to be callable from C code, procedures must obey the
;               following interface rules:
;               1) All procedure names must start with '_'
;               2) Upon entry all procedures have DS = ES = FLAT
;               3) All procedures must preserve EBX,ESI,EDI,SS,ESP,EBP,DS,ES
;               4) All procedures must receive parameters from stack (4 bytes
;                  for each parameter)
;               5) All procedures must return their return code in EAX.
;
; b727647 10/1/91  Steve Best add reclaim counter for memory component
; b728729 10/23/91 Steve Best add prc present page counter macro
; b729110 10/29/91 Steve Best remove vdm counters name change qlen
; aa04447 11/14/91 Steve Best remove tmwrt and qlQWrt from FBC group
; aa04482 01/30/92 Steve Best decrease perfview overhead for thd group counters
;                             placing fil, sem, pipe counters into retail kernel
; aa04677 02/02/92 Steve Best added pvwp.inc (private inc for DosAliasPerfCtrs
;                             DosConfigurePerf
; aa04610 02/10/92 Steve Best correct the way that prc.qlq is updated
; aa04705 02/17/92 Steve Best add file name to fil transient entity
; aa04740 02/27/92 Steve Best correct the way that thd.ctready is updated
; b734380 03/09/92 Steve Best take out 16 bit sem, 32 bit sem, prc group
;                             qlqpg counter, tmpipeowait,tmpipeiwait,tmpipecwait
;                             tmsleep, qlqrdy, qlqpgfault
; b735306 03/28/92 Steve Best place cpu ct ints and time ints back int code.
;                             this fix was to not patch in the counters in the interrupt
;                             manager(int.asm). These 3 counters are 0 - 2 in pvwmtroutertable
;                             placed the linear address into pbpvwmthook table
;                             for these counters.
;
; aa05232 04/13/92 Steve Best fix the order of etint_etnotidle and stint_st_notidle
;                             pbPvwMthook table
; aa05235 05/01/92 Steve Best fix for qresident and qfree counters
; aa05233 05/05/92 Steve Best fix for tmrun and tmready thread counters
;                             change the name of ctready to ctflg
; aa05408 05/22/92 Steve Best fix for pre-existing transient entities
; aa05449 06/19/92 Steve Best fix for thdsched counters
; aa05448 06/22/92 Steve Best fix for tmrun and tmready
; sfb     07/09/92 Steve Best fix for qresident leave queue
; 46691   07/29/92 Steve Best write macro for leave qlreclaim
; 51579   09/09/92 C. Romero  Revamp memory hooks
; 53160   09/16/92 Steve Best change the way tmrun is calculated
;                             take out tmready
; sfb2    09/16/92 Steve Best only check ax for return code when incrementing
;                             ctwrtbyte for files
; sfb3    09/23/92 Steve Best end tmrun for pervious thread in the right macro
; 63556   03/12/93 Steve Best fix
; 74471   11/19/92 Doug Barra DosHlp.QueryTmr32Value has a bug that can cause
;                             negative usage counts, check for negative and
;                             set to zero when seen, its a HACK but it will
;                             give better results than we are currently getting!
INCL_DOSERRORS equ 0            ;for bseerr.inc error codes

.XLIST
        INCLUDE dosseg.inc
        INCLUDE basemaca.inc
        INCLUDE fnoperf.inc
        INCLUDE osmaca.inc
        INCLUDE osconst.inc
        INCLUDE dossymc.inc
        INCLUDE sigdef.inc
        INCLUDE except.inc
        INCLUDE infoseg.inc
        INCLUDE pgexport.inc
        INCLUDE vmexport.inc
        INCLUDE tkexport.inc    ;TCB_pPVDBThd
        INCLUDE devhlp.inc      ;Devhlp function equates
        INCLUDE doshlp.inc
        INCLUDE int.inc
        INCLUDE curdir.inc
        INCLUDE dirent.inc
        INCLUDE screen.inc
        INCLUDE sem.inc
        INCLUDE find.inc
        INCLUDE tkptda.inc      ;ptda_pPVDBPrc
        INCLUDE sft.inc         ;sf_pPVDBFil
        INCLUDE sched.inc
        INCLUDE kmode.inc       ;thunksef_s
        INCLUDE mi.inc
        INCLUDE bseerr.inc
        INCLUDE mft.inc                                                ;aa04705
        INCLUDE pglocal.inc
        INCLUDE pvwxport.inc
        INCLUDE pvwp.inc        ;DosAliasPerfCtrs and DosConfigurePerf aa04677
        INCLUDE perfvw.inc      ;needs mi.inc
        INCLUDE pvwkdata.inc    ;Perfview kernel entity data structures.
ifdef   ALLSTRICT
    ifdef   PMDEBUG
        INCLUDE pvwframd.inc    ;Perfview measurement function stack Frames.
    else
        INCLUDE pvwframe.inc    ;Perfview measurement function stack Frames.
    endif
else
    ifdef   PMDEBUG
        INCLUDE pvwframb.inc    ;Perfview measurement function stack Frames.
    else
        INCLUDE pvwframr.inc    ;Perfview measurement function stack Frames.
    endif
endif
        INCLUDE pvwlocal.inc
.LIST

        ModName , FNO_PERFVWA_ASM
        CPUMode 386

ifdef PERFVIEW

;       EXTERNALS

ReferGlobal     DHF,DWORD                       ; Dos Help Function table.
ReferFlat       _papTCBSlots,DWORD              ; Pointer to TCB pointer array
ReferFlat       _pgcPageFaultsActive,DWORD      ; Count of faults in progress
ReferFlat       _pgListCount,DWORD              ; Idle list data
ReferFlat       _pgResidentPages,DWORD          ; Count of resident pages
ReferFlat       _ked_pers,DWORD                 ; Ptr to PerfView Kernel
                                                ;  Entity Descriptors --
                                                ;  Persistent entities.
ReferFlat       _ked_tran,DWORD                 ; Ptr to PerfView Kernel
                                                ;  Entity Descriptors --
                                                ;  Transient entities.
ReferFlat       fIdle,BYTE
ReferFlat       _fPerfview,DWORD                ; Perfview active flag.
ReferFlat       _flPvwFlags,DWORD               ; Perfview status flags.
ReferFlat       _ThreadCount,WORD               ; Upper limit on TCB numbers

EXTRN32         cpu_int                         ;b735306
EXTRN32         cpu_stint                       ;b735306
EXTRN32         cpu_etint                       ;b735306

EXTRN32         TMR32AddNTimes
EXTRN32         TMR32AddTime
EXTRN32         TMR32ClrTime
EXTRN32         TMR32SubNTimes
EXTRN32         TMR32SubTime
EXTRN32         _PGMapTmpAlias
EXTRN32         _PGPhysAvail
EXTRN32         _PGPhysPresent
EXTRN32         _PVWRegisterPerfCtrs
EXTRN32         _TMR32AddTime
EXTRN32         _TMR32SubTime
EXTRN32         _pvwCalCTimer
EXTRN32         _pTCBCur
EXTRN32         _pPTDACur
EXTRN32         _SELConvertToLinear
EXTRN16         SFFromSFN                                              ;aa05408


;b734380EXTRN32         _PGPhysPresentInProcess                            ;b728729
;       DGROUP data (USE32)

; Macro to check for negative result from Tmr32AddTime          ;;@DB74471
; HACK ALERT!!!!!!!!!!                                          ;;@DB74471
chk_neg macro                                                   ;;@DB74471
        local out                                               ;;@DB74471
        cmp     [ecx].qw_ulHi,0                                 ;;@DB74471
        jge     out                                             ;;@DB74471
        CCALL32 TMR32ClrTime                                    ;;@DB74471
out:                                                            ;;@DB74471
        endm                                                    ;;@DB74471

_DATA   SEGMENT

;       Pointer to a table which parallels the Perfview Measurement Router
;       table, and which contains the addresses of the original callers to
;       the Perfview Patch functions.

GenPublic       _ppbPvwMtHook
_ppbPvwMtHook   dd      OFFSET FLAT:_pbPvwMtHook

GenPublic       fbPvwPatch
fbPvwPatch      db      TRUE            ;Prevent patching until after SysInit.
GenPublic       _Pvwptcblast            ;pointer to last tcb           ;53160
_Pvwptcblast     dd      0                                             ;53160

_DATA   ENDS

endif ;PERFVIEW

        FARCODE LOW         ;DevHlp router segment (see DHROUTER.ASM).
CODE    SEGMENT


;***EP  dh_RegisterPerfCtrs
;
;       Dev Help procedure:
;               Register a device driver with PERFVIEW.
;               Get the addresses of a device driver's counter and text blocks.
;
;       ENTRY   This function is ONLY called at Device Driver Initialization.
;
;               (SI:AX) (16-bit) OR (EAX) (32-bit) -> counter block.
;               (DI:BX) (16-bit) OR (EBX) (32-bit) -> text block.
;               (CX) = flags (specifies 16-bit OR 32-bit)
;
;       EXIT    (ax) = return code
;                       0 - success
;                       nonzero - error
;               NO_ERROR (=0) -- success
;               ERROR_INVALID_PARAMETER
;               ERROR_PVW_INVALID_COUNTER_BLK
;               ERROR_PVW_INVALID_TEXT_BLK
;
;       USES    EAX, EBX, ECX, DX
;
;               FS and GS MUST be preserved (DevHelp requirement)

Procedure dh_RegisterPerfCtrs,near
        ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING

ifdef PERFVIEW

        SaveReg <ds,es>

        movzx   ecx,cx
        or      ecx,RPC_FL_DD

        test    cx,RPC_FL_32BIT         ;32-bit interface?
        jnz     short dhrpc32           ;  Yes.

        rol     eax,WORDSHIFT
        mov     ax,si
        ror     eax,WORDSHIFT           ;eax = si:ax

        rol     ebx,WORDSHIFT
        mov     bx,di
        ror     ebx,WORDSHIFT           ;ebx = di:bx

dhrpc32:
        FlatContext <ds,es>,dx
        CCALL32   _PVWRegisterPerfCtrs,<eax,ebx,ecx>

dhrpcx: RestoreReg <es,ds>
        ASSUME DS:NOTHING,ES:NOTHING

endif ; PERFVIEW

        RETC

EndProc dh_RegisterPerfCtrs


CODE    ENDS


        FARCODE HIGH32
PERFSWAP_TEXT   SEGMENT

ifdef PERFVIEW

;***EP  _PvwMtRouterTable - PERFVIEW Measurement Router Table
;
;       Used for routing the Perfview measurement functions.
;
;       NOTES   Any change in the number of table entries MUST be reflected
;               in the definition "LAST_PVMRT_INDEX" in pvwlocal.h.
;
;               The Perfview hooks are patched-in according to their order
;               in the _PvwMtRouterTable. (0 first, 1 next, etc.).
;               For timers, the End Time (ET) entry should always precede the
;               corresponding Start Time (ST) entry.  Likewise for queue
;               lengths, the Leave Queue (LQ) entry should always precede the
;               Enter Queue (EQ) entry.  This is so that when the hooks are
;               patched in, the ET or LQ hook is active when the ST or EQ
;               hook becomes active.  Otherwise, it is possible to get
;               2 STs or 2 EQs in a row without an intervening ET or LQ.
;
;               Currently, the index into this table is accessed as a BYTE
;               by the PvwPatch routines.  Therefore, this table is limited
;               to 255 entries.  Note that the 0th index is invalid.
;
;               Place all entries which appear only in PERFSTRICT kernels
;               at the end of this section within the PERFSTRICT conditional.

ALIGN 4

GenPublic _PvwMtRouterTable
_PvwMtRouterTable:                                              ;Table Index

                                                ;All non-PERFSTRICT entries.
        PvwMtRoutEntry  Ct, cpu, Int, 0, ,                      ; 0
        PvwMtRoutEntry  Mt, cpu, ETInt_ETNotIdle, 0, ,          ; 1
        PvwMtRoutEntry  Mt, cpu, STInt_STNotIdle, 0, ,          ; 2
        PvwMtRoutEntry  ET, cpu, NotIdle, 0, ,                  ; 3
        PvwMtRoutEntry  ST, cpu, NotIdle, 0, ,                  ; 4
        PvwMtRoutEntry  Ct, cpu, Sched, 0, ,                    ; 5
;53160  PvwMtRoutEntry  Mt, cpu, StateChange, 0, Init,          ;

        PvwMtRoutEntry  Mt, mem, PageFault, 0, Init,            ; 6
        PvwMtRoutEntry  Mt, mem, PageFault, 1, ,                ; 7


        PvwMtRoutEntry  Ct, mem, DemandLd, 0, ,                 ; 8   ;b727647

        PvwMtRoutEntry  Ct, mem, Discard, 0, ,                  ; 9

        PvwMtRoutEntry  Ct, mem, SwapOut, 0, ,                  ; 10
        PvwMtRoutEntry  Ct, mem, SwapIn,  0, ,                  ; 11



;//51579
;//51579 remove all instances of QReclaim
;//51579 remove all instances of QPresent
;//51579 remove all instances of QResident
;//51579 Add QUsed, QReassigned, and QRecovered
        PvwMtRoutEntry  Ct, mem, Reassigned,  0, ,              ; 12 - 51579
        PvwMtRoutEntry  Ct, mem, Reassigned,  1, ,              ; 13 - 51579

        PvwMtRoutEntry  LQ, mem, QUsed   , 0, Init,             ; 14 //51579
        PvwMtRoutEntry  EQ, mem, QUsed   , 0, Init,             ; 15 //51579

;51579 QResident was replaced by QCTResident.
        PvwMtRoutEntry  LQ, mem, QCTResident, 0, Init,          ; 16 51579
        PvwMtRoutEntry  EQ, mem, QCTResident, 0, Init,          ; 17 51579

        PvwMtRoutEntry  LQ, mem, QFree, 0, Init,                ; 18
        PvwMtRoutEntry  EQ, mem, QFree, 0, Init,                ; 19


        PvwMtRoutEntry  Ct, mem, Idled,  0, ,                   ; 20
        PvwMtRoutEntry  Ct, mem, Recovered,  0, ,               ; 21 //51579

        PvwMtRoutEntry  ET,   cal, Masm, 0, ,                   ; 22
        PvwMtRoutEntry  CtST, cal, Masm, 0, ,                   ; 23

        PvwMtRoutEntry  ET,   cal, C, 0, ,                      ; 24
        PvwMtRoutEntry  CtST, cal, C, 0, ,                      ; 25

;b734380PvwMtRoutEntry  ET, thd, Sleep, 0, ,                    ;
;b734380PvwMtRoutEntry  ST, thd, Sleep, 0, ,                    ;

        PvwMtRoutEntry  ET, thd, FileIOWait, 0, , far32         ; 26
        PvwMtRoutEntry  ET, thd, FileIOWait, 1, , far32         ; 27
        PvwMtRoutEntry  ET, thd, FileIOWait, 2, , far32         ; 28
        PvwMtRoutEntry  ET, thd, FileIOWait, 3, , far32         ; 29
        PvwMtRoutEntry  ST, thd, FileIOWait, 0, , far32         ; 30
        PvwMtRoutEntry  ST, thd, FileIOWait, 1, , far32         ; 31
        PvwMtRoutEntry  ST, thd, FileIOWait, 2, , far32         ; 32
        PvwMtRoutEntry  ST, thd, FileIOWait, 3, , far32         ; 33

;b734380PvwMtRoutEntry  ET, thd, PipeIWait, 0, , far32          ;
;b734380PvwMtRoutEntry  ST, thd, PipeIWait, 0, , far32          ;

;b734380PvwMtRoutEntry  ET, thd, PipeOWait, 0, , far32          ;
;b734380PvwMtRoutEntry  ST, thd, PipeOWait, 0, , far32          ;

;b734380PvwMtRoutEntry  ET, thd, PipeCWait, 0, , far32          ;
;b734380PvwMtRoutEntry  ST, thd, PipeCWait, 0, , far32          ;

;b734380PvwMtRoutEntry  SmET, sem, Set, 0,                      ;
;b734380PvwMtRoutEntry  SmTm, sem, Set, 0,                      ;
;b734380PvwMtRoutEntry  SmET, sem, Blk, 0,                      ;
;b734380PvwMtRoutEntry  SmTm, sem, Blk, 0,                      ;

;b734380PvwMtRoutEntry  ET, sem, Set, 1, , far32                ;
;b734380PvwMtRoutEntry  CtST, sem, Set, 1, , far32              ;
;b734380PvwMtRoutEntry  ET, sem, Blk, 1, , far32                ;
;b734380PvwMtRoutEntry  CtST, sem, Blk, 1, , far32              ;

        PvwMtRoutEntry  Ct, fbc, RdHit, 0,                      ; 34 ;b722131
        PvwMtRoutEntry  Ct, fbc, RdMiss, 0,                     ; 35 ;b722131
        PvwMtRoutEntry  Ct, fbc, WrtHit, 0,                     ; 36 ;b722131
        PvwMtRoutEntry  Ct, fbc, WrtMiss, 0,                    ; 37 ;b722131
        PvwMtRoutEntry  Ct, fbc, WrtActiv, 0, , far32           ; 38 ;b722131
;       PvwMtRoutEntry  ET, fbc, Wrt, 0, , far32                ;    ;aa04447
;       PvwMtRoutEntry  ST, fbc, Wrt, 0, , far32                ;    ;aa04447
;       PvwMtRoutEntry  LQ, fbc, QWrt, 0, , far32               ;    ;aa04447
;       PvwMtRoutEntry  EQ, fbc, QWrt, 0, , far32               ;    ;aa04447
        PvwMtRoutEntry  Ct, fbc, Bypass, 0, , far32             ; 39 ;b722131

;b734380PvwMtRoutEntry  LQ, prc, QPg, 0, Init,                  ;    ;b728729
;b734380PvwMtRoutEntry  EQ, prc, QPg, 0, Init,                  ;    ;b728729

IFDEF PERFSTRICT                                ;All PERFSTRICT entries.
        PvwMtRoutEntrySpares Spare1                             ;+1-8
        PvwMtRoutEntrySpares Spare2                             ;+9-16
        PvwMtRoutEntrySpares Spare3                             ;+17-24
        PvwMtRoutEntrySpares Spare4                             ;+25-32
        PvwMtRoutEntrySpares Spare5                             ;+33-40
        PvwMtRoutEntrySpares Spare6                             ;+41-48
        PvwMtRoutEntrySpares Spare7                             ;+49-56
        PvwMtRoutEntrySpares Spare8                             ;+57-64
        PvwMtRoutEntrySpares Spare9                             ;+65-72
        PvwMtRoutEntrySpares Spare10                            ;+73-80

;       PvwMtRoutEntry Ct, vdm, Int, 0, ,                       ;+81   ;b729110
;       PvwMtRoutEntry Ct, vdm, BP, 0, ,                        ;+82   ;b729110
;       PvwMtRoutEntry Ct, vdm, V86Trap, 0, ,                   ;+83   ;b729110
;       PvwMtRoutEntry Ct, vdm, TrapPage, 0, ,                  ;+84   ;b729110
;       PvwMtRoutEntry Ct, vdm, MapPage,  0, ,                  ;+85   ;b729110




ENDIF ;PERFSTRICT

NUM_PVMRT_ENTRIES       EQU     (($-_PvwMtRouterTable)/DWORD)

.errnz (NUM_PVMRT_ENTRIES - (LAST_PVMRT_INDEX+1))
.errnz (($-_PvwMtRouterTable) - PVMRT_SIZE)
.erre  (($-_PvwMtRouterTable) LE MAX_PVMRT_SIZE)



;       This MUST precede the first measurement function or exception handler.
;       All code below this point is locked down by Dos32ConfigurePerf().

GenPublic _PvwMtStartLock
_PvwMtStartLock:

;***EP  PERFVIEW Measurement functions.
;
;       ENTRY   (EBP) = Caller's stack frame.
;               (DS) = (ES) = Flat.
;
;       USES    EFlags. If <savreg> blank, uses EAX, ECX, EDX.
;
;       NOTES   These functions MUST follow the _PvwMtRouterTable, because
;               the PVWMI_... indexes which they use are created by the
;               PvwMtRoutEntry macro invocations.
;
;               These functions may depend considerably on the state of the
;               processor registers when this exception was encountered.
;
;               Place all functions which appear only in PERFSTRICT kernels
;               at the end of this section within the PERFSTRICT conditional.
;
;               It is critical that Timers and Timer/Counter combinations be
;               initialized properly.  Time intervals are measured by
;               subtracting the current time from a timer when an event
;               begins, and adding the current time to a timer when the
;               event ends.  This yields a delta time.  It is possible for
;               Perfview to be activated in the middle of an event.  This
;               could result in an 'End Time' operation without a
;               corresponding 'Start Time' operation.  This is avoided by
;               clearing all Timers when Perfview is activated, and testing
;               Timers for zero before performing the 'End Time' operation.
;               All of this is done automatically at Perfview start-up and
;               in the Timer addition functions (TMR32AddTime(),
;               TMR32AddNTimes()).  No further initialization is required
;               except in unusual circumstances.
;
;               Some functions require special initialization.  This is
;               particularly true of Queue lengths.  These functions modify
;               the Perfview hook by replacing the call to the 'Init' function
;               with a call to the associated standard run-time function.
;               The queue length init. functions reset BOTH the 'Enter Queue'
;               (EQ) and 'Leave Queue' (LQ) hooks, since they both typically
;               begin in the init. state because substantial time can
;               elapse between the execution of the two hooks.


        ASSUME DS:FLAT,ES:FLAT,SS:NOTHING,FS:NOTHING,GS:NOTHING

; BUGBUG 09-Aug-90, DaveBe, <As a safety precaution, I've added "jecxz 'exit'"
; following every load of (ECX) = pbDataBlk for Persistent counters:
;       PvwMtDataBlkPtr pers,cpu,ecx,
;       jecxz   short 'exit'
; This should only be necessary for Transient counters, since Persistent hooks
; should never be enabled unless the Persistent data blocks were first
; initialized by _pvwInitPersist(), and could be removed at a later date as
; an optimization.>

                                        ;All permanent (non-PERFSTRICT) functions.
PvwMtCt         pers, cpu, Int, 0, savreg
;aa05449PvwMtCt         pers, cpu, Sched, 0, savreg
PvwMtST         pers, cpu, NotIdle, 0, savreg
;sfb3PvwMtET         pers, cpu, NotIdle, 0, savreg

_TEXT   SEGMENT                                                        ;b727647
PvwMtCt         pers, mem, DemandLd, 0,                                ;b727647
_TEXT   ENDS                                                           ;b727647

PvwMtCt         pers, mem, Discard, 0,

PvwMtCt         pers, mem, SwapIn,  0,

PvwMtCt         pers, mem, Recovered, 0,

PvwMtCt         pers, mem, Idled, 0,


_TEXT   SEGMENT                                                        ;b727647
;PvwMtCt         pers, mem, Reclaim,  0,   ;51579 remove this line     ;51579
PvwMtCt         pers, mem, Reassigned,  0, ;51579 rename reclaim to reassigned
_TEXT   ENDS                                                           ;b727647


;PvwMtCt         pers, mem, Reassigned,  1, ;51579 rename reclaim to reassigned
;***EP  pvwMt_Ct_mem_Reassigned_1 - count pages reassigned
;
;       Decrement count of reassigned pages defect 51579
;
;       ENTRY   (SS:EBP) = PGPageFault's stack frame
;               (DS) = (ES) = FLAT
;       EXIT    NONE
;       USES    EAX, ECX, EDX, Flags

Procedure pvwMt_Ct_mem_Reassigned_1,near
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING
        PvwMtDataBlkPtr pers,mem,ecx,
        jecxz   short reass0x
        dec     [ecx].mem_hdr.dbh_ulSem ; Mark ctr block as modified.
        dec     [ecx].mem_ctReassigned  ; Decrement counter
reass0x:  RETC

EndProc pvwMt_Ct_mem_Reassigned_1


PvwMtEQ         pers, mem, QFree, 0,

;PvwMtEQ        pers, mem, Resident, 0,      ;#51579 don't need these
;PvwMtLQ        pers, mem, Resident, 0,      ;#51579 macro definitions


;PvwMtEQ         pers, mem, QPresent, 0,     ;51579 remove and substitute with
;PvwMtLQ         pers, mem, QPresent, 0,     ;51579


;       PvwMtInitEQ     Pers, mem, QUsed   , 0

Procedure pvwMt_Init_EQ_mem_QUsed_0,near
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING

Entry     pvwMt_Init_LQ_mem_QUsed_0,near

        CCALL32 _PVWSetHook,<PVWMI_EQ_mem_QUsed_0, \
                            OFFSET FLAT:pvwMt_EQ_mem_QUsed_0>

        CCALL32 _PVWSetHook,<PVWMI_LQ_mem_QUsed_0, \
                            OFFSET FLAT:pvwMt_LQ_mem_QUsed_0>

        PvwMtDataBlkPtr pers,mem,ecx,
        jecxz   short mqr0x
        inc     [ecx].mem_hdr.dbh_ulSem ;Mark ctr block as modified.
        add     ecx,mem_qlQUsed
        push    ecx
        CCALL32 _PGPhysAvail            ; (EAX) = # of bytes of free pages
        pop     ecx
        shr     eax,PAGESHIFT           ; (EAX) = count of free pages
        mov     edx,_pgListCount        ; (EDX) = free plus Useable pages
        sub     edx,eax                 ; (EDX) = count of Useable pages
        push    ecx
        CCALL32 _PGPhysPresent          ; (EAX) = count of present PFs
        pop     ecx
        add     edx, eax                ; add count of present PFs
        mov     [ecx].ql_ct,edx         ; Init. queue cnt.
        add     ecx,ql_tm               ; (ECX) -> QLen timer.
        CCALL32 TMR32ClrTime
        jmp     TMR32SubNTimes          ; Optimized -- RETC from TMR32SubNTimes.
mqr0x:  RETC

EndProc pvwMt_Init_EQ_mem_QUsed_0


;51579 remove all instances of QReclaim

PvwMtEQ         pers, mem, QUsed, 0,       ;51579
PvwMtLQ         pers, mem, QUsed, 0,       ;51579

;b734380PvwMtST         tran, thd, Sleep, 0
;b734380PvwMtET         tran, thd, Sleep, 0


; BUGBUG 29-Aug-90, DaveBe, Always resident until 16-bit patching implemeted.
;b734380_TEXT   SEGMENT

;b734380PvwMtST         tran, thd, PipeIWait, 0, <savreg,loaddses>, <far32>
;b734380PvwMtET         tran, thd, PipeIWait, 0, <savreg,loaddses>, <far32>

;b734380PvwMtST         tran, thd, PipeOWait, 0, <savreg,loaddses>, <far32>
;b734380PvwMtET         tran, thd, PipeOWait, 0, <savreg,loaddses>, <far32>

;b734380PvwMtST         tran, thd, PipeCWait, 0, <savreg,loaddses>, <far32>
;b734380PvwMtET         tran, thd, PipeCWait, 0, <savreg,loaddses>, <far32>

; BUGBUG 29-Aug-90, DaveBe, Always resident until 16-bit patching implemented.
;b734380_TEXT   ENDS

;       Calibration measurement functions.

PvwMtCtST       pers, cal, Masm, 0, savreg
PvwMtET         pers, cal, Masm, 0, savreg

PvwMtCtST       pers, cal, C, 0,
PvwMtET         pers, cal, C, 0,

;       Semaphore measurement functions.

;b734380PvwMtSmTm       tran, sem, Set, 0
;b734380PvwMtSmET       tran, sem, Set, 0
;b734380PvwMtSmTm       tran, sem, Blk, 0
;b734380PvwMtSmET       tran, sem, Blk, 0

;     FAT Disk Cache functions                                         ;b722131

_TEXT   SEGMENT                                                        ;b725935

PvwMtCt    pers, fbc, RdHit,  0                                        ;b722131
PvwMtCt    pers, fbc, RdMiss, 0                                        ;b722131
PvwMtCt    pers, fbc, WrtHit, 0                                        ;b722131
PvwMtCt    pers, fbc, WrtMiss, 0                                       ;b722131
PvwMtCt    pers, fbc, WrtActiv, 0, <savreg, loaddses>, <far32>         ;b722131
;PvwMtST    pers, fbc, Wrt, 0, <savreg,loaddses>, <far32>              ;aa04447
;PvwMtET    pers, fbc, Wrt, 0, <savreg,loaddses>, <far32>              ;aa04447
;PvwMtEQ    pers, fbc, QWrt, 0, <savreg,loaddses>, <far32>             ;aa04447
;PvwMtLQ    pers, fbc, QWrt, 0, <savreg,loaddses>, <far32>             ;aa04447
PvwMtCt    pers, fbc, Bypass, 0, <savreg,loaddses>, <far32>            ;b722131

_TEXT   ENDS                                                           ;b725935
; BUGBUG 11-Sep-90, DaveBe, Always resident until 16-bit patching implemeted.
;b734380_TEXT   SEGMENT

;b734380PvwMtCtST       tran, sem, Set, 1, <savreg,loaddses>, <far32>
;b734380PvwMtET         tran, sem, Set, 1, <savreg,loaddses>, <far32>
;b734380PvwMtCtST       tran, sem, Blk, 1, <savreg,loaddses>, <far32>
;b734380PvwMtET         tran, sem, Blk, 1, <savreg,loaddses>, <far32>


; BUGBUG 11-Sep-90, DaveBe, Always resident until 16-bit patching implemented.
;b734380_TEXT   ENDS


;***LP  pvwMt_Mt_cpu_STInt_STNotIdle_0 -- Start Interrupt and NotIdle Timers
;***LP  pvwMt_Mt_cpu_ETInt_ETNotIdle_0 -- End Interrupt and NotIdle Timers
;
;       NOTES   We do not do any explicit initialization for these Timers.
;               Most initialization is covered by the checks for zero Timers
;               in the 'End Time' logic; the Timers will never be stopped
;               unless they were first started.

pvwMt_Mt_cpu_STInt_STNotIdle_0:
        SaveReg <eax,ecx,edx>
        PvwMtDataBlkPtr pers,cpu,ecx,
        jecxz   short cpustx
        inc     [ecx].cpu_hdr.dbh_ulSem ;Mark ctr block as modified.
        CCALL32 DHF.DosHlpTmr32QueryTime        ;(EDX:EAX) = current QWRD time
        sub     DWORD PTR [ecx].cpu_tmInt.qw_ulLo,eax
        sbb     DWORD PTR [ecx].cpu_tmInt.qw_ulHi,edx

        cmp     fIdle,TRUE                      ; If and only if fIdle == TRUE.
        jne     short cpustx
        sub     DWORD PTR [ecx].cpu_tmNotIdle.qw_ulLo,eax
        sbb     DWORD PTR [ecx].cpu_tmNotIdle.qw_ulHi,edx

cpustx: RestoreReg <edx,ecx,eax>
        RETC

pvwMt_Mt_cpu_ETInt_ETNotIdle_0:
        SaveReg <eax,ecx,edx>
        PvwMtDataBlkPtr pers,cpu,ecx,
        jecxz   short cpuetx
        inc     [ecx].cpu_hdr.dbh_ulSem ;Mark ctr block as modified.
        CCALL32 DHF.DosHlpTmr32QueryTime        ;(EDX:EAX) = current QWRD time

        cmp     DWORD PTR [ecx].cpu_tmInt.qw_ulLo,0     ;Lower half = 0?
        je      short cpuet5                            ; yes--expensive jump.
cpuet2: add     DWORD PTR [ecx].cpu_tmInt.qw_ulLo,eax
        adc     DWORD PTR [ecx].cpu_tmInt.qw_ulHi,edx

cpuet3: cmp     fIdle,TRUE                      ; If and only if fIdle == TRUE.
        jne     short cpuetx
        cmp     DWORD PTR [ecx].cpu_tmNotIdle.qw_ulLo,0 ;Lower half = 0?
        je      short cpuet6                            ; yes--expensive jump.
cpuet4: add     DWORD PTR [ecx].cpu_tmNotIdle.qw_ulLo,eax
        adc     DWORD PTR [ecx].cpu_tmNotIdle.qw_ulHi,edx

cpuetx: RestoreReg <edx,ecx,eax>
        RETC

cpuet5: cmp     DWORD PTR [ecx].cpu_tmInt.qw_ulHi,0     ;Upper half also = 0?
        jne     short cpuet2                            ; no -- do add.
        jmp     short cpuet3                            ; yes -- exit.

cpuet6: cmp     DWORD PTR [ecx].cpu_tmNotIdle.qw_ulHi,0 ;Upper half also = 0?
        jne     short cpuet4                            ; no -- do add.
        jmp     short cpuetx                            ; yes -- exit.




;***LP  pvwMt_Init_Mt_mem_PageFault_0 - per-page-fault measurement init. start
;***LP  pvwMt_Mt_mem_PageFault_0 - per-page-fault measurement start
;***LP  pvwMt_Init_Mt_mem_PageFault_1 - per-page-fault measurement init. finish
;***LP  pvwMt_Mt_mem_PageFault_1 - per-page-fault measurement finish
;
;       Per-page-fault counters both for persistent and transient
;       entities.  These entries serve mem_ctPgFault, mem_qlQLen,
;       thd_ctFault, and thd_tmFault.
;
;       ENTRY   (SS:EBP) = PGPageFault's frame pointer
;       EXIT    NONE
;       USES    EAX, ECX, EDX, Flags

Procedure pvwMt_Init_Mt_mem_PageFault_0,near
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING

        PGPageFault_frame1

        CCALL32 _PVWSetHook,<PVWMI_Mt_mem_PageFault_0, \
                            OFFSET FLAT:pvwMt_Mt_mem_PageFault_0>
        CCALL32 _PVWSetHook,<PVWMI_Mt_mem_PageFault_1, \
                            OFFSET FLAT:pvwMt_Mt_mem_PageFault_1>
        PvwMtDataBlkPtr pers,mem,ecx,
        jecxz   short mpf00
;b734380inc     [ecx].mem_hdr.dbh_ulSem ; Mark ctr block as modified.
;       add     ecx,mem_qlQLen                                         ;b729110
;b734380add     ecx,mem_qlQPgFault

;b734380mov     edx,_pgcPageFaultsActive; (EDX) = Current # of queue entries
;b734380mov     [ecx].ql_ct,edx         ; Init. queue cnt.
;b734380add     ecx,ql_tm               ; (ECX) -> QLen timer.
;b734380CCALL32 TMR32ClrTime
;b734380CCALL32 TMR32SubNTimes          ; Initialize the timer
                                        ; Fall through.

; BUGBUG 06-Aug-90, DaveBe, <Falling thru may make qlQLen off by 1.>

Entry pvwMt_Mt_mem_PageFault_0,near
        PvwMtDataBlkPtr pers,mem,ecx,
        jecxz   short mpf00
        inc     [ecx].mem_hdr.dbh_ulSem ; Mark ctr block as modified.
        inc     [ecx].mem_ctPgFault     ; Increment count of page faults
;       add     ecx,mem_qlQLen          ; (ECX) = timer address
;b734380add     ecx,mem_qlQPgFault      ; (ECX) = timer address        ;b729110
;b734380inc     [ecx].ql_ct             ; Add member to queue.
;b734380add     ecx,ql_tm               ; (ECX) -> QLen timer.
;b734380CCALL32 TMR32SubTime            ; Start the timer
        PvwMtDataBlkPtr tran,thd,ecx,   ; (ECX) = thread's data block
        jecxz   mpf00
        inc     [ecx].thd_ctFlg.hiword  ; 63556
        cmp     [ecx].thd_ctFlg.lobyte,0 ;63556
        jne     mpfxx                    ;63556
        inc     [ecx].thd_hdr.dbh_ulSem ; Mark ctr block as modified.
        mov     [ecx].thd_ctFlg.lobyte,1 ;63556
        inc     [ecx].thd_ctFault       ; Increment count of page faults
        add     ecx,thd_tmFault         ; (ECX) = timer address
        jmp     TMR32SubTime            ; Start the timer

mpf00:  RETC

mpfxx:                                  ;63556
        inc     [ecx].thd_hdr.dbh_ulSem ; Mark ctr block as modified.
        inc     [ecx].thd_ctFault       ; Increment count of page faults
        jmp short mpf00                 ;63556
        PGPageFault_frame1_end
EndProc pvwMt_Init_Mt_mem_PageFault_0


Procedure pvwMt_Init_Mt_mem_PageFault_1,near
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING

        PGPageFault_frame2

        CCALL32 _PVWSetHook,<PVWMI_Mt_mem_PageFault_0, \
                            OFFSET FLAT:pvwMt_Mt_mem_PageFault_0>
        CCALL32 _PVWSetHook,<PVWMI_Mt_mem_PageFault_1, \
                            OFFSET FLAT:pvwMt_Mt_mem_PageFault_1>
        PvwMtDataBlkPtr pers,mem,ecx,
        jecxz   short mpf11
;b734380inc     [ecx].mem_hdr.dbh_ulSem ; Mark ctr block as modified.
;       add     ecx,mem_qlQLen
;b734380add     ecx,mem_qlQPgFault                                     ;b729110
;b734380mov     edx,_pgcPageFaultsActive; (EDX) = Current # of queue entries
;b734380mov     [ecx].ql_ct,edx         ; Init. queue cnt.
;b734380add     ecx,ql_tm               ; (ECX) -> QLen timer.
;b734380CCALL32 TMR32ClrTime
;b734380CCALL32 TMR32SubNTimes          ; Initialize the timer
                                        ; No need to init. thd_tmFault; it
                                        ;  will be ignored when we fall thru,
                                        ;  and initialized in PageFault_0.
                                        ; Fall through.

; BUGBUG 06-Aug-90, DaveBe, <Falling thru may make qlQLen off by 1.>

Entry pvwMt_Mt_mem_PageFault_1,near
mpf10:  PvwMtDataBlkPtr pers,mem,ecx,
        jecxz   short mpf11
;b734380inc     [ecx].mem_hdr.dbh_ulSem ; Mark ctr block as modified.
;       add     ecx,mem_qlQLen          ; (ECX) = timer address
;b734380add     ecx,mem_qlQPgFault      ; (ECX) = timer address
;b734380dec     [ecx].ql_ct             ; Remove member from queue.
;b734380add     ecx,ql_tm               ; (ECX) -> QLen timer.
;b734380CCALL32 TMR32AddTime            ; Stop the timer
        PvwMtDataBlkPtr tran,thd,ecx,   ; (ECX) = thread's data block
        jecxz   mpf11
        inc     [ecx].thd_hdr.dbh_ulSem ;  63556
        dec     [ecx].thd_ctFlg.hiword  ; 63556
        cmp     [ecx].thd_ctFlg.hiword,0 ; 63556
        jne     mpfxx1                   ; 63556
        cmp     [ecx].thd_ctFlg.lobyte,1 ;63556
        jne     mpfxx1                   ;63556
        inc     [ecx].thd_hdr.dbh_ulSem ; Mark ctr block as modified.
        mov     [ecx].thd_ctFlg.lobyte,0 ;63556
        add     ecx,thd_tmFault         ; (ECX) = timer address
        jmp     TMR32AddTime            ; Stop the timer

mpf11:  RETC
mpfxx1:
        jmp short mpf11                       ;63556
        PGPageFault_frame2_end
EndProc pvwMt_Init_Mt_mem_PageFault_1


;***EP  pvwMt_Ct_mem_SwapOut_0 - count pages swapped out
;
;       This is the handler for the memory swapout counter.
;       See DCR 614.  This handler is called from 32-bit C.
;
;       ENTRY   (SS:EBP) = SMSwapOut's stack frame
;               (DS) = (ES) = FLAT
;       EXIT    NONE
;       USES    EAX, ECX, EDX, Flags

Procedure pvwMt_Ct_mem_SwapOut_0,near
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING

        SMSwapOut_frame

        movzx   eax,??ncmds             ; (ECX) = count of outgoing pages
        PvwMtDataBlkPtr pers,mem,ecx,
        jecxz   short cso0x
        inc     [ecx].mem_hdr.dbh_ulSem ; Mark ctr block as modified.
        add     [ecx].mem_ctSwapOut,eax ; Increment count of swapouts

        SMSwapOut_frame_end
cso0x:  RETC

EndProc pvwMt_Ct_mem_SwapOut_0

;b734380;***EP  pvwMt_SmET_sem_Set_0 -
;b734380;
;b734380;       This is the handler for the semaphore set counter.
;b734380;       See DCR 614.  This handler is called from 32-bit C.
;b734380;
;b734380;       ENTRY   (
;b734380;               (DS) = (ES) = FLAT
;b734380;       EXIT    NONE
;b734380;       USES    EAX, ECX, EDX, Flags

;b734380Procedure pvwMt_SmET_sem_Set_0,near
;b734380        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING
;b734380
;b734380                                 ; (EBX) = address of perfview data blk
;b734380
;b734380        or      ebx,ebx
;b734380        jz      exit
;b734380        push    ecx
;b734380        mov     ecx,ebx
;b734380        inc     [ecx].sem_hdr.dbh_ulSem ;Mark ctr block as modified.
;b734380        inc     [ecx].sem_ctSet
;b734380        add     ecx,sem_tmSet
;b734380        CCALL32 TMR32SubTime
;b734380        pop     ecx
;b734380exit:
;b734380        RETC

;b734380EndProc pvwMt_SmET_sem_Set_0

;b734380;***EP  pvwMt_SmTm_sem_Set_0 -
;b734380;
;b734380;       This is the handler for the semaphore set counter.
;b734380;       See DCR 614.  This handler is called from 32-bit C.
;b734380;
;b734380;       ENTRY   (SS:EBP) =
;b734380;               (DS) = (ES) = FLAT
;b734380;       EXIT    NONE
;b734380;       USES    EAX, ECX, EDX, Flags

;b734380Procedure pvwMt_SmTm_sem_Set_0,near
;b734380        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING
;b734380
;b734380
;b734380                                 ; (EBX) = address of perfview data blk
;b734380        or      ebx,ebx
;b734380        jz      leave2
;b734380        push    ecx
;b734380        mov     ecx,ebx
;b734380        inc     [ecx].sem_hdr.dbh_ulSem ;Mark ctr block as modified.
;b734380        add     ecx,sem_tmSet
;b734380        CCALL32 TMR32AddTime
;b734380        pop     ecx
;b734380 leave2:
;b734380        RETC
;b734380 EndProc pvwMt_SmTm_sem_Set_0

;b734380;***EP  pvwMt_SmET_sem_Blk_0 -
;b734380;
;b734380;       This is the handler for the semaphore set counter.
;b734380;       See DCR 614.  This handler is called from 32-bit C.
;b734380;
;b734380;       ENTRY   (SS:EBP) =
;b734380;               (DS) = (ES) = FLAT
;b734380;       EXIT    NONE
;b734380;       USES    EAX, ECX, EDX, Flags

;b734380 Procedure pvwMt_SmET_sem_Blk_0,near
;b734380        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING
;b734380
;b734380
;b734380                                 ; (EBX) = address of perfview data blk
;b734380
;b734380        or      ebx,ebx
;b734380        jz      leave1
;b734380        push    ecx
;b734380        mov     ecx,ebx
;b734380        inc     [ecx].sem_hdr.dbh_ulSem ;Mark ctr block as modified.
;b734380        inc     [ecx].sem_ctBlk
;b734380        add     ecx,sem_tmBlk
;b734380        CCALL32 TMR32SubTime
;b734380        pop     ecx
;b734380 leave1:
;b734380        RETC
;b734380EndProc pvwMt_SmET_sem_Blk_0

;b734380;***EP  pvwMt_SmTm_sem_Blk_0 -
;b734380;
;b734380;       This is the handler for the semaphore set counter.
;b734380;       See DCR 614.  This handler is called from 32-bit C.
;b734380;
;b734380;       ENTRY   (SS:EBP) =
;b734380;               (DS) = (ES) = FLAT
;b734380;       EXIT    NONE
;b734380;       USES    EAX, ECX, EDX, Flags

;b734380Procedure pvwMt_SmTm_sem_Blk_0,near
;b734380        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING
;b734380
;b734380
;b734380                                 ; (EBX) = address of perfview data blk
;b734380        or      ebx,ebx
;b734380        jz      leave3
;b734380        push    ecx
;b734380        mov     ecx,ebx
;b734380        inc     [ecx].sem_hdr.dbh_ulSem ;Mark ctr block as modified.
;b734380        add     ecx,sem_tmBlk
;b734380        CCALL32 TMR32AddTime
;b734380        pop     ecx
;b734380leave3:
;b734380        RETC
;b734380EndProc pvwMt_SmTm_sem_Blk_0



; BUGBUG 29-Aug-90, DaveBe, Always resident until 16-bit patching implemented.
_TEXT   SEGMENT

;***EP  pvwMt_ST_thd_FileIOWait_0 - per-thread file wait time
;***EP  pvwMt_ST_thd_FileIOWait_1 - per-thread file wait time
;
;       This is the handler for thread file I/O wait time (start),
;       file count of reads, and file read time (start).  See
;       thread hook 7 and file hooks 1 and 2 as described in DCR 614.
;
;       This handler is called from 16-bit assembler.
;
;       ENTRY   pTCBCur points to the TCB.
;               pTCBCur->TCBThisSFT points to the SFT.
;       EXIT    NONE
;       USES    NONE

Procedure pvwMt_ST_thd_FileIOWait_0,far32
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING

Entry pvwMt_ST_thd_FileIOWait_1,far32
        pushfd
        pushad
        push    ds
        push    es
        FlatContext <ds,es>,eax
;b734380cmp     _fPerfview,0            ; check if perfview is up      ;aa04482
;b734380je      short tfws05            ; perfview not up              ;aa04482
        PvwMtDataBlkPtr tran,fil,ecx,   ; (ECX) = file's data block
        jecxz   tfws00                  ; Skip ahead if file uninteresting
        inc     [ecx].fil_hdr.dbh_ulSem ; Mark ctr block as modified.
        inc     [ecx].fil_ctRd          ; Increment count of reads
        add     ecx,fil_tmRd
        CCALL32 TMR32SubTime            ; Start the timer
tfws00: PvwMtDataBlkPtr tran,thd,ecx,   ; (ECX) = thread's data block
        jecxz   tfws05                  ; Skip ahead if thread uninteresting
        inc     [ecx].thd_hdr.dbh_ulSem ; Mark ctr block as modified.
        add     ecx,thd_tmFileIOWait    ; (ECX) = timer address
        CCALL32 TMR32SubTime            ; Start the timer (so we can stop it)
tfws05: pop     es
        pop     ds
    ASSUME      DS:NOTHING, ES:NOTHING
        popad
        popfd
        RETC

EndProc pvwMt_ST_thd_FileIOWait_0


;***EP  pvwMt_ET_thd_FileIOWait_0 - per-thread file wait time
;***EP  pvwMt_ET_thd_FileIOWait_1 - per-thread file wait time
;
;       This is the handler for thread file I/O wait time (end),
;       file read time (end), and file count of bytes read.  See
;       thread hook 7 and file hooks 2 and 3 as described in DCR 614.
;
;       This handler is called from 16-bit assembler.
;
;       ENTRY   pTCBCur points to the TCB.
;               pTCBCur->TCBThisSFT points to the SFT.
;               if carry clear, (CX) = number of bytes read
;       EXIT    NONE
;       USES    NONE

Procedure pvwMt_ET_thd_FileIOWait_0,far32
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING

Entry pvwMt_ET_thd_FileIOWait_1,far32
        pushad
        push    ds
        push    es
        pushfd
        FlatContext <ds,es>,eax
;b734380cmp     _fPerfview,0            ; check if perfview is up      ;aa04482
;b734380je      short tfwe03            ; perfview not up              ;aa04482
        PvwMtDataBlkPtr tran,fil,edi,   ; (EDI) = file's data block
        or      edi,edi                 ; Null pointer (file uninteresting)?
        jz      short tfwe02            ;  yes, skip ahead
        inc     [edi].fil_hdr.dbh_ulSem ; Mark ctr block as modified.
        pop     eax                     ; (EAX) = flags
        push    eax
        test    al,F_CARRY              ; Was carry set?
        jnz     short tfwe01            ;  yes, skip ahead
        movzx   ecx,cx                  ; (ECX) = count of bytes read
        add     [edi].fil_ctRdByte,ecx  ; Increment count of bytes
tfwe01: lea     ecx,[edi].fil_tmRd
        CCALL32 TMR32AddTime            ; Stop the timer
        chk_neg                                                 ;@DB74471
tfwe02: PvwMtDataBlkPtr tran,thd,ecx,   ; (ECX) = thread's data block
        jecxz   tfwe03                  ; Skip ahead if thread uninteresting
        inc     [ecx].thd_hdr.dbh_ulSem ; Mark ctr block as modified.
        add     ecx,thd_tmFileIOWait    ; (ECX) = timer address
        CCALL32 TMR32AddTime            ; Stop the timer
        chk_neg                                                 ;@DB74471
tfwe03: popfd
        pop     es
        pop     ds
    ASSUME      DS:NOTHING, ES:NOTHING
        popad
        RETC

EndProc pvwMt_ET_thd_FileIOWait_0


;***EP  pvwMt_ST_thd_FileIOWait_2 - per-thread file wait time
;***EP  pvwMt_ST_thd_FileIOWait_3 - per-thread file wait time
;
;       This is the handler for thread file I/O wait time (start),
;       file count of writes, and file write time (start).  See
;       thread hook 7 and file hooks 4 and 5 as described in DCR 614.
;
;       This handler is called from 16-bit assembler.
;
;       ENTRY   pTCBCur points to the TCB.
;               pTCBCur->TCBThisSFT points to the SFT.
;       EXIT    NONE
;       USES    NONE

Procedure pvwMt_ST_thd_FileIOWait_2,far32
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING

Entry pvwMt_ST_thd_FileIOWait_3,far32
        pushfd
        pushad
        push    ds
        push    es
        FlatContext <ds,es>,eax
;b734380cmp     _fPerfview,0            ; check if perfview is up      ;aa04482
;b734380je      short tfws25            ; perfview not up              ;aa04482
        PvwMtDataBlkPtr tran,fil,ecx,   ; (ECX) = file's data block
        jecxz   tfws20                  ; Skip ahead if file uninteresting
        inc     [ecx].fil_hdr.dbh_ulSem ; Mark ctr block as modified.
        inc     [ecx].fil_ctWrt         ; Increment count of writes
        add     ecx,fil_tmWrt
        CCALL32 TMR32SubTime            ; Start the timer
tfws20: PvwMtDataBlkPtr tran,thd,ecx,   ; (ECX) = thread's data block
        jecxz   tfws25                  ; Skip ahead if thread uninteresting
        inc     [ecx].thd_hdr.dbh_ulSem ; Mark ctr block as modified.
        add     ecx,thd_tmFileIOWait    ; (ECX) = timer address
        CCALL32 TMR32SubTime            ; Start the timer (so we can stop it)
tfws25: pop     es
        pop     ds
    ASSUME      DS:NOTHING, ES:NOTHING
        popad
        popfd
        RETC

EndProc pvwMt_ST_thd_FileIOWait_2


;***EP  pvwMt_ET_thd_FileIOWait_2 - per-thread file wait time
;***EP  pvwMt_ET_thd_FileIOWait_3 - per-thread file wait time
;
;       This is the handler for thread file I/O wait time (end),
;       file read time (end), and file count of bytes read.  See
;       thread hook 7 and file hooks 2 and 3 as described in DCR 614.
;
;       This handler is called from 16-bit assembler.
;
;       ENTRY   pTCBCur points to the TCB.
;               pTCBCur->TCBThisSFT points to the SFT.
;               if carry clear, (CX) = number of bytes written. (_2)
;               if (AX) = NO_ERROR, (CX) = number of bytes written. (_3)
;       EXIT    NONE
;       USES    NONE

Procedure pvwMt_ET_thd_FileIOWait_2,far32
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING

        pushfd
        pushad
        sbb     eax,eax                 ; (EAX) = -1 if carry set, else 0
        jmp     short tfwe20

Entry pvwMt_ET_thd_FileIOWait_3,far32
        pushfd
        pushad
tfwe20: push    ds
        push    es
        FlatContext <ds,es>,edx
;b734380cmp     _fPerfview,0            ; check if perfview is up      ;aa04482
;b734380je      short tfwe23            ; perfview not up              ;aa04482
        PvwMtDataBlkPtr tran,fil,edi,   ; (EDI) = file's data block
        or      edi,edi                 ; Null pointer (file uninteresting)?
        jz      short tfwe22            ;  yes, skip ahead
        inc     [edi].fil_hdr.dbh_ulSem ; Mark ctr block as modified.
;sfb2   or      eax,eax                 ; Write error?
        or       ax, ax                 ; Write error?                 ;sfb2
        .errnz  NO_ERROR
        jnz     short tfwe21            ;  yes, skip ahead
        movzx   ecx,cx                  ; (ECX) = count of bytes written
        add     [edi].fil_ctWrtByte,ecx ; Increment count of bytes
tfwe21: lea     ecx,[edi].fil_tmWrt
        CCALL32 TMR32AddTime            ; Stop the timer
        chk_neg                                                 ;@DB74471
tfwe22: PvwMtDataBlkPtr tran,thd,ecx,   ; (ECX) = thread's data block
        jecxz   tfwe23                  ; Skip ahead if thread uninteresting
        inc     [ecx].thd_hdr.dbh_ulSem ; Mark ctr block as modified.
        add     ecx,thd_tmFileIOWait    ; (ECX) = timer address
        CCALL32 TMR32AddTime            ; Stop the timer
        chk_neg                                                 ;@DB74471
tfwe23: pop     es
        pop     ds
    ASSUME      DS:NOTHING, ES:NOTHING
        popad
        popfd
        RETC

EndProc pvwMt_ET_thd_FileIOWait_2

; BUGBUG 29-Aug-90, DaveBe, Permanently resident until 16-bit patching done.
_TEXT   ENDS




;       PvwMtInitEQ     Pers, mem, QFree, 0
;       PvwMtInitLQ     Pers, mem, QFree, 0

Procedure pvwMt_Init_EQ_mem_QFree_0,near
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING

Entry     pvwMt_Init_LQ_mem_QFree_0,near
        CCALL32 _PVWSetHook,<PVWMI_EQ_mem_QFree_0, \
                            OFFSET FLAT:pvwMt_EQ_mem_QFree_0>
        CCALL32 _PVWSetHook,<PVWMI_LQ_mem_QFree_0, \
                            OFFSET FLAT:pvwMt_LQ_mem_QFree_0>
        PvwMtDataBlkPtr pers,mem,ecx,
        jecxz   short eqf0x
        inc     [ecx].mem_hdr.dbh_ulSem ;Mark ctr block as modified.
        add     ecx,mem_qlQFree
        push    ecx
        CCALL32 _PGPhysAvail            ; (EAX) = # of bytes of free pages
        pop     ecx
        shr     eax,PAGESHIFT           ; (EAX) = count of free pages
        mov     edx,eax                 ; (EDX) = free pages
        mov     [ecx].ql_ct,edx         ; Init. queue cnt.
        add     ecx,ql_tm               ; (ECX) -> QLen timer.
        CCALL32 TMR32ClrTime
        jmp     TMR32SubNTimes          ; Optimized -- RETC from TMR32SubNTimes.
eqf0x:  RETC

EndProc pvwMt_Init_EQ_mem_QFree_0



;       PvwMtLQ         Pers, mem, QFree, 0

Procedure pvwMt_LQ_mem_QFree_0,near
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING

        pgDeletePF_frame2

        mov     ecx,??ppf               ; (ECX) = page frame pointer   ;aa05235
;       test    [ecx].pf_free,00400000  ; pf_pfree is 4 into ppf       ;aa05235
        test    [ecx +4],4194304        ; Is frame free                ;aa05235

        jnz     short lqf0              ; Yes add in time and dec ctr  ;aa05235
;;BUGBUG bsbs test    [ecx].pf_flags,PF_FREE  ; Is frame free?
;aa05235xor     ecx,ecx

;aa05235jnz     short lqf0              ;  yes, skip ahead
        RETC                            ; Do nothing

lqf0:   PvwMtDataBlkPtr pers,mem,ecx,
        jecxz   short lqf0x
        push    eax
        mov     eax, [ecx+mem_qlQFree].ql_ct             ; Remove member from queue.
        sub     eax,1                        ; set carry
        jc      lqf0xa
        inc     [ecx].mem_hdr.dbh_ulSem ; Mark ctr block as modified.
        mov     [ecx+mem_qlQFree].ql_ct, eax
        pop     eax
        add     ecx, ql_tm+mem_qlQFree        ; (ECX) -> QLen timer.
        jmp     TMR32AddTime
lqf0x:  RETC

lqf0xa: pop     eax
        clc
        RETC
        pgDeletePF_frame2_end

EndProc pvwMt_LQ_mem_QFree_0



;       PvwMtInitEQ     Pers, mem, QResident, 0
;       PvwMtInitLQ     Pers, mem, QResident, 0
;       PvwMtInitEQ     Pers, mem, QResident, 1
;       PvwMtInitLQ     Pers, mem, QResident, 1

Procedure pvwMt_Init_EQ_mem_QCTResident_0,near
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING

Entry     pvwMt_Init_LQ_mem_QCTResident_0,near

        CCALL32 _PVWSetHook,<PVWMI_EQ_mem_QCTResident_0, \
                            OFFSET FLAT:pvwMt_EQ_mem_QCTResident_0>
        CCALL32 _PVWSetHook,<PVWMI_LQ_mem_QCTResident_0, \
                            OFFSET FLAT:pvwMt_LQ_mem_QCTResident_0>

        PvwMtDataBlkPtr pers,mem,ecx,
        jecxz   short eqr0x
        inc     [ecx].mem_hdr.dbh_ulSem ;Mark ctr block as modified.

;#51579 remove following lines
;#51579 add     ecx,mem_qlQResident
;#51579 mov     edx,_pgResidentPages    ; (EDX) = Current # of resident pages
;#51579 mov     [ecx].ql_ct,edx         ; Init. queue cnt.
;#51579 add     ecx,ql_tm               ; (ECX) -> QLen timer.
;#51579 CCALL32 TMR32ClrTime
;#51579 jmp     TMR32SubNTimes          ; Optimized -- RETC from TMR32SubNTimes.
        mov     edx,_pgResidentPages    ; (EDX) = Current # of resident pages
        mov     [ecx].mem_qctResident,edx ;#51579      Init. queue cnt.
eqr0x:  RETC

EndProc pvwMt_Init_EQ_mem_QCTResident_0


;51579 Carlos A. Romero - CP Change Team
;51579 changes start here

;51579  Since pgResidentPages represents the actual number of resident
;51579  physical pages, QCTResident is maintained by equating it to
;51579  pgResidentPages after every pgResidentPages update (enter or leave)
;       PvwMtEQ         pers, mem, QResident, 0,
;       PvwMtLQ         pers, mem, QResident, 0,
pvwMt_EQ_mem_QCTResident_0:
pvwMt_LQ_mem_QCTResident_0:
        PvwMtDataBlkPtr pers,mem,ecx,
        jecxz   short eqr1x
        inc     [ecx].mem_hdr.dbh_ulSem    ;Mark ctr block as modified.
        mov     edx,_pgResidentPages       ; (EDX) = Current # of resident pages
        mov     [ecx].mem_qctResident,edx  ;Update Resident Queue
eqr1x:  RETC

;51579 changes end here

;b734380;       PvwMtInitEQ     tran, prc, QPg, 0                      ;b728729
;b734380;       PvwMtInitLQ     tran, prc, QPg, 0                      ;b728729
;b734380                                                               ;b728729
;b734380Procedure pvwMt_Init_EQ_prc_QPg_0,near                         ;b728729
;b734380        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING                   ;b728729
;b734380                                                               ;b728729
;b734380Entry     pvwMt_Init_LQ_prc_QPg_0,near                         ;b728729
;b734380        CCALL32 _PVWSetHook,<PVWMI_EQ_prc_QPg_0, \
;b734380                            OFFSET FLAT:pvwMt_EQ_prc_QPg_0>
;b734380        CCALL32 _PVWSetHook,<PVWMI_LQ_prc_QPg_0, \
;b734380                            OFFSET FLAT:pvwMt_LQ_prc_QPg_0>
;b734380        PvwMtDataBlkPtr tran,prc,ecx,                          ;b728729
;b734380        jecxz   short iqp1x                                    ;b728729
;b734380        inc     [ecx].prc_hdr.dbh_ulSem ;Mark ctr block as modified.   ;b728729
;b734380        add     ecx,prc_qlQPg                                  ;b728729
;aa04610push    ecx                                                    ;b728729
;aa04610mov      ecx,_pPTDACur          ; (ECX) = pointer to current PTDA
;aa04610CCALL32 _PGPhysPresentInProcess, <ecx> ;(EAX) = count of present PFs
;aa04610pop     ecx                                                    ;b728729
;aa04160mov     edx,eax                 ; need count into EDX          ;b728729
;aa04610mov     [ecx].ql_ct,edx         ; Init. queue cnt.             ;b728729
;b734380        add     ecx,ql_tm               ; (ECX) -> QLen timer. ;b728729
;b734380        CCALL32 TMR32ClrTime                                   ;b728729
;aa04610jmp     TMR32SubNTimes          ; Optimized -- RETC from TMR32SubNTimes.
;b734380iqp1x:  RETC                                                   ;b728729
;b734380                                                               ;b728729
;b734380EndProc pvwMt_Init_EQ_prc_QPg_0                                ;b728729
;b734380
;b734380;       PvwMtEQ         tran, prc, QPg, 0,                             ;b728729

;b734380Procedure pvwMt_EQ_prc_QPg_0,near
;b734380        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING
;b734380        PvwMtDataBlkPtr tran,prc,ecx,                                  ;b728729
;b734380        jecxz   short eqp0x                                            ;b728729
;b734380        inc     [ecx].mem_hdr.dbh_ulSem ;Mark ctr block as modified.   ;b728729
;b734380        add     ecx,prc_qlQPg                                          ;b728729
;b734380        push    ecx                                                    ;b728729
;b734380        mov      ecx,_pPTDACur          ; (ECX) = pointer to current PTDA
;b734380        CCALL32 _PGPhysPresentInProcess, <ecx> ;(EAX) = count of present PFs
;b734380        pop     ecx                                                    ;b728729
;b734380        cmp     eax,[ecx].ql_ct                                        ;aa04610
;b734380        jbe     eqp0x                                                  ;aa04610
;b734380        mov     edx,[ecx].ql_ct
;b734380        mov     [ecx].ql_ct,eax         ; update # in count            ;aa04610
;b734380        sub     eax,edx
;b734380        mov     edx,eax                 ; calculate the delta
;aa04610add     ecx,prc_qlQPg                                          ;b728729
;b734380        add     ecx,ql_tm               ; (ECX) -> QLen timer.         ;b728729
;b734380        jmp     TMR32SubNTimes          ;Optimized -- RETC from TMR32SubNTimes.
;b734380eqp0x:  RETC                                                           ;b728729
;b734380EndProc pvwMt_EQ_prc_QPg_0                                             ;b728729


;b734380;       PvwMtLQ         tran, prc, QPq, 0,                             ;b728729
;b734380
;b734380Procedure pvwMt_LQ_prc_QPg_0,near                                      ;b728729
;b734380        PvwMtDataBlkPtr tran,prc,ecx,                                  ;b728729
;b734380        jecxz   short lqp0x                                            ;b728729
;b734380        inc     [ecx].mem_hdr.dbh_ulSem ;Mark ctr block as modified.   ;b728729
;b734380        add     ecx,prc_qlQPg                                          ;b728729
;b734380        push    ecx                                                    ;b728729
;b734380        mov      ecx,_pPTDACur          ; (ECX) = pointer to current PTDA
;b734380        CCALL32 _PGPhysPresentInProcess, <ecx> ;(EAX) = count of present PFs
;b734380        pop     ecx                                                    ;b728729
;b734380        cmp     eax,[ecx].ql_ct                                        ;aa04610
;b734380        jae     lqp0x                                                  ;aa04610
;b734380        mov     edx,[ecx].ql_ct
;b734380        mov     [ecx].ql_ct,eax         ; update # in count            ;aa04610
;b734380        sub     edx,eax
;b734380        add     ecx,ql_tm               ; (ECX) -> QLen timer.         ;b728729
;b734380        jmp     TMR32AddNTimes          ;Optimized -- RETC from TMR32AddNTimes.
;b734380lqp0x:  RETC                                                           ;b729729
;b734380EndProc pvwMt_LQ_prc_QPg_0                                             ;b728729



;***LP  pvwMt_Ct_cpu_CtSched  - Counter for thd and cpu sched          ;aa05449
;                                                                      ;aa05449
                                                                       ;aa05449
Procedure pvwMt_Ct_cpu_Sched_0,near                                    ;aa05449
        SaveReg <ecx>                                                  ;aa05449
        SaveReg <eax>                                                  ;53160
        SaveReg <ebx>                                                  ;53160
        mov     ebx,ecx                 ;place ptcb into ebx           ;53160
        PvwMtDataBlkPtr pers,cpu,ecx,                                  ;aa05449
        jecxz   short cpucts10                                         ;aa05449
        inc     [ecx].cpu_hdr.dbh_ulSem ;Mark ctr block as modified.   ;aa05449
        inc     [ecx].cpu_ctSched                                      ;aa05449
cpucts10:                                                              ;aa05449
        PvwMtDataBlkPtr tran,thd,ecx,   ; (ECX) = thread's data block  ;aa05449
        jecxz   short cpucts15                                         ;aa05449
        inc     [ecx].thd_hdr.dbh_ulSem ; Mark ctr block as modified.  ;aa05449
        inc     [ecx].thd_ctSched       ; Increment count of sched     ;aa05449
cpucts15:                                                              ;53160
        cmp     _Pvwptcblast,ebx         ; check if current tcb is the ;53160
        je      short cpucts100         ; same as previous tcb         ;53160
        cmp     _Pvwptcblast,0           ; no previous tcb             ;53160
        je      short cpucts50                                         ;53160
                                                                       ;53160
cpucts20:                                                              ;53160
        PvwMtDataBlkPtr tran,thd,ecx,_Pvwptcblast                      ;53160
        jecxz   short cpucts50
        jmp     short cpucts40                                         ;53160

cpucts25:                                                              ;53160
        cmp     [ecx].thd_ctFlg.hibyte,0  ; ok to start timer          ;53160
        jne     cpucts100                                              ;53160
        mov     _Pvwptcblast,ebx        ; save ptcb                    ;53160
        inc     [ecx].thd_hdr.dbh_ulSem ; Mark ctr block as modified.  ;53160
        mov     [ecx].thd_ctFlg.hibyte,1                               ;53160
        add     ecx,thd_tmRun                                          ;53160
        push    edx                                                    ;53160
        CCALL32 TMR32SubTime            ; Start timer and we're done.  ;53160
        pop     edx                                                    ;53160
        jmp     short cpucts100         ; done                         ;53160
cpucts40:                                                              ;53160
        cmp     [ecx].thd_ctFlg.hibyte,1  ; ok to stop timer           ;53160
        jne     cpucts50                                               ;53160
        inc     [ecx].thd_hdr.dbh_ulSem ; Mark ctr block as modified.  ;53160
        mov     [ecx].thd_ctFlg.hibyte,0                               ;53160
        add     ecx,thd_tmRun                                          ;53160

        push    edx                                                    ;53160
        CCALL32 TMR32AddTime            ; Stop timer                   ;53160
        chk_neg                                                 ;@DB74471
        pop     edx                                                    ;53160

cpucts50:                               ; restore current ptcb         ;53160
        PvwMtDataBlkPtr tran,thd,ecx,   ; (ECX) = thread's data block  ;53160
        jecxz   short cpucts100                                        ;53160
        jmp     short cpucts25          ;                              ;53160

cpucts100:
           RestoreReg <ebx>                                            ;53160
           RestoreReg <eax>                                            ;53160
           RestoreReg <ecx>                                            ;aa05449

        RETC                                                           ;aa05449

EndProc pvwMt_Ct_cpu_Sched_0                                           ;aa05449


;***LP  pvwMt_ET_cpu_NotIdle  - Stop cpu tmnotidle and check to see    ;sfb3
;       if pvwptcblast is not 0 stop this timer                        ;sfb3
                                                                       ;sfb3
Procedure pvwMt_ET_cpu_NotIdle_0,near                                  ;sfb3
        SaveReg <ecx>                                                  ;sfb3
        SaveReg <eax>                                                  ;sfb3
        SaveReg <edx>                                                  ;sfb3
        PvwMtDataBlkPtr pers,cpu,ecx,                                  ;sfb3
        jecxz   short cpunot100                                        ;sfb3
        inc     [ecx].cpu_hdr.dbh_ulSem ;Mark ctr block as modified.   ;sfb3
        add     ecx,cpu_tmNotIdle      ;                               ;sfb3
        CCALL32 TMR32AddTime            ; Stop timer                   ;sfb3
        chk_neg                                                 ;@DB74471
                                                                       ;sfb3
        cmp     _Pvwptcblast,0           ; no previous tcb             ;sfb3
        je      short cpunot100                                        ;sfb3
                                                                       ;sfb3
        PvwMtDataBlkPtr tran,thd,ecx,_Pvwptcblast                      ;sfb3
        jecxz   short cpunot100                                        ;sfb3
        mov     _Pvwptcblast,0                                         ;sfb3
        cmp     [ecx].thd_ctFlg.hibyte,1  ; ok to stop timer           ;sfb3
        jne     cpunot100                                              ;sfb3
                                                                       ;sfb3
        inc     [ecx].thd_hdr.dbh_ulSem ; Mark ctr block as modified.  ;sfb3
        mov     [ecx].thd_ctFlg.hibyte,0                               ;sfb3
        add     ecx,thd_tmRun                                          ;sfb3
                                                                       ;sfb3
        CCALL32 TMR32AddTime            ; Stop timer                   ;sfb3
        chk_neg                                                 ;@DB74471
                                                                       ;sfb3
cpunot100:                                                             ;sfb3
           RestoreReg <edx>                                            ;sfb3
           RestoreReg <eax>                                            ;sfb3
           RestoreReg <ecx>                                            ;sfb3
                                                                       ;sfb3
        RETC                                                           ;sfb3
                                                                       ;sfb3
EndProc pvwMt_ET_cpu_NotIdle_0                                         ;sfb3
IFDEF PERFSTRICT                        ;All PERFSTRICT functions.
PvwMtSpare Spare1
PvwMtSpare Spare2
PvwMtSpare Spare3
PvwMtSpare Spare4
PvwMtSpare Spare5
PvwMtSpare Spare6
PvwMtSpare Spare7
PvwMtSpare Spare8
PvwMtSpare Spare9
PvwMtSpare Spare10

;PvwMtCt         pers, vdm, Int, 0, savreg                             ;b729110
;PvwMtCt         pers, vdm, BP, 0, savreg                              ;b729110
;PvwMtCt         pers, vdm, V86Trap, 0, savreg                         ;b729110
;PvwMtCt         pers, vdm, TrapPage, 0,                               ;b729110
;PvwMtCt         pers, vdm, MapPage,  0,                               ;b729110
ENDIF ;PERFSTRICT


;***EP  _pvwStopTimers                                                 ;aa05233
;                                                                      ;aa05233
;       Stop the tmrun or tmready counters for the thread group        ;aa05233
;                                                                      ;aa05233
;       ENTRY   (DS) = (ES) = Flat.                                    ;aa05233
;                                                                      ;aa05233
;       EXIT    (EAX) = NO_ERROR                                       ;aa05233
;                                                                      ;aa05233
;       USES    EAX,ECX,EDX, EFlags                                    ;aa05233
;                                                                      ;aa05233
;       NOTES   Both the tmrun and tmready threads are check to see if ;aa05233
;               these timers need to be stopped before the thread dies.;aa05233
;               This was the only way to not give negative values for these
;               two counters, since the scheduler does not place the thread
;               in a dead state.                                       ;aa05233
                                                                       ;aa05233
Procedure _pvwStopTimers,near                                          ;aa05233
ArgVar  pbDataBlk,DWORD                                                ;aa05233
                                                                       ;aa05233
        ASSUME DS:FLAT,ES:FLAT,SS:NOTHING,FS:NOTHING,GS:NOTHING        ;aa05233
        EnterProc
                                                                       ;aa05233
        mov     ecx,pbDataBlk                                          ;aa05448
        cmp     [ecx].thd_ctFlg.hibyte,1  ; ok to stop timer         ;aa05233
        jne     stop2                                                  ;aa05233
        inc     [ecx].thd_hdr.dbh_ulSem ; Mark ctr block as modified.  ;aa05233
        mov     [ecx].thd_ctFlg.hibyte,0                             ;aa05233
        add     ecx,thd_tmRun                                          ;aa05233
        CCALL32 TMR32AddTime            ; Stop tmRun timer             ;aa05233
        chk_neg                                                 ;@DB74471
stop2:                                                                 ;aa05233

        LeaveProc
        RETC                                                           ;aa05233
                                                                       ;aa05233
EndProc _pvwStopTimers                                                 ;aa05233


;***EP  _pvwCalibrateTimers
;
;       Calibrate Perfview MASM and 'C' timers.
;
;       ENTRY   (DS) = (ES) = Flat.
;
;       EXIT    (EAX) = NO_ERROR
;
;       USES    EAX,ECX,EDX, EFlags
;
;       NOTES   Both the MASM and 'C' timers are calibrated by executing
;               consecutive StartTm and EndTm hooks.  The hooks are executed
;               for PVW_CAL_ITERATIONS and the resultant times are then
;               divided by the total iterations.

Procedure _pvwCalibrateTimers
        ASSUME DS:FLAT,ES:FLAT,SS:NOTHING,FS:NOTHING,GS:NOTHING

        SaveReg <ebx>
        mov     ebx,PVW_CAL_ITERATIONS
pct10:  CCALL32 _pvwCalCTimer           ;uses EAX,ECX,EDX.

        PvwCntStartTm cal,Masm,0,
        PvwEndTm cal,Masm,0

        dec     ebx
        ja      short pct10

        PvwMtDataBlkPtr pers,cal,ecx,
        jecxz   short pct20

;       (ECX) -> Calibration data block.

        mov     ebx,[ecx].cal_tmC.qw_ulHi       ;'C' timer.
        shrd    DWORD PTR [ecx].cal_tmC.qw_ulLo,ebx,PVW_CAL_POWEROF2
        shr     [ecx].cal_tmC.qw_ulHi,PVW_CAL_POWEROF2
        mov     [ecx].cal_ctC,1                 ;Count is effectively 1 now.

        mov     ebx,[ecx].cal_tmMasm.qw_ulHi          ;MASM timer.
        shrd    DWORD PTR [ecx].cal_tmMasm.qw_ulLo,ebx,PVW_CAL_POWEROF2
        shr     [ecx].cal_tmMasm.qw_ulHi,PVW_CAL_POWEROF2
        mov     [ecx].cal_ctMasm,1              ;Count is effectively 1 now.

;BUGBUG 19-Jun-90,DaveBe,<Need to flag calibration times as valid; no
;                         measurement functions should use them prior to this.>

pct20:  xor     eax,eax                         ;Return NO_ERROR.
        RestoreReg <ebx>
        RETC

EndProc _pvwCalibrateTimers


;       This MUST follow the last measurement function or exception handler.
;       All code above this point is locked down by Dos32ConfigurePerf().

GenPublic _PvwMtEndLock
_PvwMtEndLock:

endif ;PERFVIEW

PERFSWAP_TEXT ENDS


; BUGBUG 21-May-90, DaveBe, <Will eventually want to discard as much of the
;                            patching code as possible, following completion
;                            of patching or some pre-determined length of time.>

        FARCODE HIGH32
_TEXT   SEGMENT

ifdef PERFVIEW

;***    PvwGetMFTName - get file name from MFT name field              ;aa04705
;
;       This procedure returns a pointer to the appropriate mft
;       name of the file
;
;       EAX contains the data block address
;       error
;       eax = 0
;
Procedure _PvwGetMFTName,near
;aa05408ArgVar    pptda, DWORD          ; ptr to the ptda
ArgVar    ptcb, DWORD          ; ptr to the tcb
ArgVar    handle, WORD         ; handle SFN

        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING

        EnterProc
        push    ds
        push    es

        FlatContext <ds,es>,eax

        push    ebx
        push    edi
        push    edx
        mov     bx,[handle]
        cmp     bx,-1
        je      short getmft0
        CALL16  SFFromSFN                 ; es:di -> sft               ;aa05408
        jc      SHORT getmft5              ; error, go exit             ;aa05408
        mov     bx,di                     ; make es:bx -> sft          ;aa05408
        jmp     short getmft2
getmft0:
;aa05408mov     eax, _pTCBCur
        mov     eax, [ptcb]
        les     bx,[eax].TCBThisSFT
getmft2:
        test    es:[di].sf_flags,DEVID_DEVICE   ; Yes, set device flag  ;46691
        jnz     short getmft5           ; not a file so return 0        ;46691
        ; only get data block for files                                 ;46691
        mov     edi,es:[bx].sf_MFT      ; get the mft pointer
        cmp     edi,SF_MFT_NULL         ; NO  MFT ?
        je      SHORT getmft5           ;

        FlatContext     es,ax           ; es:edi -> MFT
        lea     edi,es:[edi].mft_name   ; es:edi -> MFT_name
        mov     eax,edi                 ; place address of mft name into eax
        jmp     short getmft10
getmft5:
        mov     eax,0                     ; no mft for this sft set error

getmft10:
        pop     edx
        pop     edi
        pop     ebx
        pop     es
        pop     ds

    ASSUME      DS:NOTHING, ES:NOTHING
        LeaveProc
        RETC
EndProc _PvwGetMFTName                                                 ;aa04705

;***    PvwMtFilDataBlk - get pointer to File PerfView data block ;b722136
;
;       This procedure returns a pointer to the appropriate data
;       block for the file counters
;
;       EAX contains the data block address
;       error if eax =0                                                ;aa05408
Procedure _PvwMtFilDataBlk,near
ArgVar    pptda, DWORD          ; ptr to the ptda
ArgVar    ptcb,  DWORD          ; ptr to the tcb                       ;aa05408
ArgVar    handle   , WORD       ; handle - SFN                         ;aa05408

        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING

        EnterProc
        push    ds
        push    es

        FlatContext <ds,es>,eax

        push    es
        push    ebx
        push    ecx
        push    edx
        push    edi                                                    ;aa05408
;aa05408mov     eax, _pTCBCur
        mov     eax,[ptcb]                                             ;aa05408
        cmp     eax,0                     ; if ptcb is 0 use the tcbcur;aa05408
        jne     short pvw2                                             ;aa05408
        mov     eax,_pTCBCur                                           ;aa05408
pvw2:                                                                  ;aa05408
        xor     ebx,ebx                   ; clear ecx                  ;aa05408
        mov     bx,[handle]               ; -1  don't use handle       ;aa05408
        cmp     bx,-1                                                   ;aa05408
        je      short pvw2a               ; no handle passed in        ;aa05408
        CALL16  SFFromSFN                 ; es:di -> sft               ;aa05408
        jc      SHORT pvw2b               ; error, go exit             ;aa05408
        mov     bx,di                     ; make es:bx -> sft          ;aa05408
        jmp     short pvw3                                             ;aa05408
pvw2a:
        les     bx,[eax].TCBThisSFT
        mov     ax,es                     ; check for sft              ;aa05408
        cmp     ax,0
        jne     short pvw3                                             ;aa05408
pvw2b:
        mov     eax,0                     ; set address = to zero as   ;aa05408
        jmp     short pvw4                ; bad return code            ;aa05408
pvw3:
        lea     bx,es:[bx].sf_fsi.pPVDBFil
                                          ; sel is in es
                                          ; offset is bx
        xor     eax,eax
        mov     ax,es                     ; make 16;16 address in 0:32 addr
        push    ebx
        CCALL32 _SELConvertToLinear <eax, [pptda]> ; make sel a 32 address
        pop     ebx
        movzx   ecx,bx                    ;
        add     eax,ecx                   ; add offset into get the 0:32 addr
pvw4:                                     ; address is return in eax
        pop     edi                                                    ;aa05408
        pop     edx
        pop     ecx
        pop     ebx
        pop     es

        pop     es
        pop     ds

    ASSUME      DS:NOTHING, ES:NOTHING
        LeaveProc
        RETC
EndProc _PvwMtFilDataBlk

;***LP  pvwAliasHook
;
;       Obtain writeable alias to hook.  This function encapsulates aliasing
;       for _PVWSetHook and _PVWUnSetHook.  It also forces the hook present.
;
;       ENTRY   (EAX) = Entity index.
;               (DS) = (ES) = Flat.
;
;       EXIT    (EAX) = Linear address of hook.
;                     == 0 if no hook address found in _pbPvwMtHook table.
;               (EDX) = Alias of hook (invalid if EAX == 0).
;
;       USES    EAX, ECX, EDX, EFlags.
;
;       NOTES   Size of hook (alias range) must be less than (PAGESIZE+1).

Procedure pvwAliasHook,near,local
        ASSUME DS:FLAT,ES:FLAT,SS:FLAT,FS:NOTHING,GS:NOTHING

LocalVar        PAH_pbHook      DWORD           ;pbHook = Hook laddr.

        EnterProc

;       Lookup (EAX) = pbHook.  Exit if address of hook can't be found.

        mov     edx,_ppbPvwMtHook
        mov     eax,[edx][eax*DWORD]    ;(EAX) = pbHook = (*ppbPvwMtHook)[ulEI]
        or      eax,eax
        jz      short pahx              ;Exit if NULL.
        mov     PAH_pbHook,eax          ;Save pbHook.

;       Force entire hook to be present.  Perform 2 overlapping reads; if
;       the instruction crosses a page boundary, 1 of these 2 reads is
;       guaranteed to force both pages present.

        mov     ecx,[eax]               ;Read 1st 4 bytes.
        mov     ecx,[eax].1             ;Read 2nd 4 bytes.

.errnz (SIZE_CALL_NEAR_REL - (SIZE DWRD + 1))

        shr     eax,PAGESHIFT           ;(EAX) = page number.
        CCALL32 _PGMapTmpAlias,<eax>    ;(EAX) = aliased page number.
        shl     eax,PAGESHIFT
        mov     edx,eax
        mov     eax,PAH_pbHook
        mov     ecx,eax                 ;(EAX) = (ECX) = pbHook.
        and     ecx,PAGEMASK
        add     edx,ecx                 ;(EDX) = pbHookAlias.

pahx:   LeaveProc
        RETC

EndProc pvwAliasHook


;***EP  _PVWSetHook
;
;       Replace multi-byte NOP with Near Call to indicated Perfview
;       measurement function.
;
;       ENTRY   ulEI  -- Entity index
;               pfnMt -- Address of Measurement function
;
;       EXIT    NO_ERROR - success
;
;       USES    EAX, ECX, EDX, EFlags
;
;       NOTES   This should be locked resident while executing so that
;               it doesn't block on a code page fault.


Procedure _PVWSetHook,near
        ASSUME DS:FLAT,ES:FLAT,SS:FLAT,FS:NOTHING,GS:NOTHING

ArgVar          PSH_ulEI        DWORD           ;Entity index.
ArgVar          PSH_pfnMt       DWORD           ;Address of measurement func.

        EnterProc

;       Force hook present and obtain hook's address (EAX) and a writeable
;       alias to hook (EDX).

        mov     eax,PSH_ulEI

IFDEF TESTONLY
        jmp     short psh0              ; Proceed.
        nop
        nop
        nop
        jmp     short psh5              ; Exit without modifying hook.
        nop
        nop
        nop
        cmp     eax,5                   ; Only modify specific hooks.
        ja      short psh5
        nop
        nop
        nop
psh0:
ENDIF ;TESTONLY

        CCALL32 pvwAliasHook            ;(EAX) = pbHook, (EDX) = pbHookAlias.
        or      eax,eax
        jz      short pshx              ;Exit if no hook address found.

;       Compute (ECX) = displacement of measurement function relative to
;       instruction following hook.

        mov     ecx,PSH_pfnMt
        sub     ecx,eax
        sub     ecx,SIZE_CALL_NEAR_REL

        pushfd
        cli                             ;Disable interrupts during write.

;       Set hook = NEAR call to measure. fn.

        mov     [edx].0,BYTE PTR MI_CALL_NEAR_REL
        mov     [edx].1,ecx

        popfd                           ;Restore interrupt state.

psh5:   xor     eax,eax                 ;return(NO_ERROR).
pshx:   LeaveProc
        RETC

EndProc _PVWSetHook


;***EP  _PVWUnSetHook
;
;       Replace call to Perfview measurement function with multi-byte
;       NOP.
;
;       ENTRY   ulEI -- Entity Index
;
;       EXIT    NO_ERROR - success
;
;       USES    EAX, ECX, EDX, EFlags
;
;       NOTES   This should be locked resident while executing so that it
;               doesn't block on a code page fault.


Procedure _PVWUnSetHook,near
        ASSUME DS:FLAT,ES:FLAT,SS:FLAT,FS:NOTHING,GS:NOTHING

ArgVar          PUSH_ulEI       DWORD           ;Entity index.

        EnterProc

;       Force hook present and obtain hook's address (EAX) and a writeable
;       alias to hook (EDX).

        mov     eax,PUSH_ulEI
        CCALL32 pvwAliasHook            ;(EAX) = pbHook, (EDX) = pbHookAlias.
        or      eax,eax
        jz      short pushx             ;Exit if no hook address found.

        xor     eax,eax

        pushfd
        cli                             ;Disable interrupts during write.

;       Hook <- 5-byte NOP == (ADD EAX,0); Only EFlags affected.

        mov     [edx].0,BYTE PTR MI_ADD_AX_IMM
        mov     [edx].1,eax

        popfd                           ;Restore interrupt state.

        xor     eax,eax                 ;return(NO_ERROR).
pushx:  LeaveProc
        RETC

EndProc _PVWUnSetHook


;***LP  pvwPatchHook
;
;       Common worker for Perfview patch functions.  This patches out the
;       hook on the first call to each patch function.  The hook is
;       replaced with the equivalent of a multiple-byte NOP.
;
;       ENTRY   (EBP) = Caller's stack frame
;               (ESP) = Patch Function stack frame (pvpff_s) -- actually,
;                       EAX,ECX,EDX aren't pushed onto the stack until this
;                       function is entered.
;               (DS) = (ES) = Flat.
;
;       USES    EFlags.
;
;       NOTES   Pseudo-code:
;
;               if (Not currently patching--i.e. don't allow nested patching)
;               {
;                   Record Caller's address in _pbPvwMtHook table.
;
;                   if (Perfview active)
;                   {
;                       if(Kernel Hooks active)
;                       {
;                           Replace hook's original Call with Call to
;                             measurement function.
;                           Execute measurement function.
;                       }
;                   }
;                   else
;                   {
;                       Replace Hook's original Near Call with a multiple-byte
;                         NOP.
;                   }
;               }
;
;
;
;               If Perfview is active (_fPerfview == TRUE), but it has not
;               yet activated the kernel hooks, let it complete this
;               activation before doing any further patching.  This way,
;               either the hook activation (in DosConfigurePerf(CC_INIT))
;               will "set" the hook, (since the hook address has already been
;               recorded in the _pbPvwMtHook), or the next time pvwPatchHook()
;               is entered for this hook (once activation is complete), the
;               "set" will take place.  Note that this leaves the possibility
;               that the _pbPvwMtHook entry is non-null while the hook
;               still points at the Patch function, but this shouldn't cause
;               any problems; the _pbPvwMtHook entry will simply be
;               re-initialized on the next pass through pvwPatchHook().



Procedure pvwPatchHook,near,local
        ASSUME DS:FLAT,ES:FLAT,SS:FLAT,FS:NOTHING,GS:NOTHING

        SaveReg <eax,ecx,edx>
        mov     eax,DWORD PTR [esp].pvpff_ulEI  ;(EAX) = Entity index = ulEI.
        mov     edx,[esp].pvpff_eip
        sub     edx,SIZE_CALL_NEAR_REL  ;(EDX) = Address of Caller.

        cmp     fbPvwPatch,TRUE         ;Do not allow nested patching.
        je      short pphx

        mov     BYTE PTR fbPvwPatch,TRUE        ;Patching underway.

;       Save measurement hook address in pbPvwMtHook table.

        mov     ecx,_ppbPvwMtHook
        mov     [ecx][eax*DWORD],edx    ;ppbPvwMtHook[ulEI] = pbHook.

        cmp     _fPerfview,FALSE
        jne      short pph40            ;Jump if Perfview active.

;       Patch-out measurement hook.

        CCALL32 _PVWUnSetHook,<eax>
        jmp     short pph80

;       Check if kernel hooks active before "setting" hook.

pph40:  mov     edx,_flPvwFlags
        and     edx,PVW_FLM_KRNL_HOOKS
        cmp     edx,PVW_FLM_KRNL_HOOKS  ;Kernel hooks activated yet?
        jne     short pph80             ; no -- exit.

;       Set measurement hook to measurement function, and execute measurement
;       function.

        mov     edx,DWORD PTR [_PvwMtRouterTable][eax*DWORD]

;       (EDX) = measurement function address = (PFN) PvwMtRouterTable[ulEI].

        push    edx                     ;Save measurement function address.
        CCALL32 _PVWSetHook,<eax,edx>
        pop     edx
        CCALL32 edx                     ;Execute measurement function.

pph80:  mov     BYTE PTR fbPvwPatch,FALSE ;Patching complete.

pphx:   RestoreReg <edx,ecx,eax>
        add     esp,TYPE pvpff_ulEI     ;This compensates for the Entity Index
                                        ; which was pushed onto the stack in
                                        ; the PvwPatchFn macro invocation.
        RETC

;       This minimizes the memory consumed by the Patch functions, since
;       it maximizes the number of "short" jumps to pvwPatchCaller.

Entry   pvwPatchHookA,near,local
        jmp     short pvwPatchHook

EndProc pvwPatchHook

;************************************************************************
;****** NOTE:  DO NOT PLACE CODE BETWEEN THE END OF pvwPatchHook    *****
;****** (pvwPatchCaller) AND THE START OF THE PvwPatchFn FUNCTIONS. *****               ******
;************************************************************************

;***EP  PERFVIEW Patch functions.
;
;       ENTRY   (EBP) = Caller's stack frame.
;               (DS) = (ES) = Flat.
;
;       USES    EFlags.
;
;       NOTES   These functions MUST follow the _PvwMtRouterTable, because
;               the PVWMI_... indexes which they use are created by the
;               PvwMtRoutEntry macro invocations.  There MUST be exactly
;               one Patch routine for each entry in _PvwMtRouterTable.  Each
;               Patch routine MUST have a unique name.
;
;               Place all functions which appear only in PERFSTRICT kernels
;               at the end of this section within the PERFSTRICT conditional.

        ASSUME DS:FLAT,ES:FLAT,SS:FLAT,FS:NOTHING,GS:NOTHING

                                        ;All permanent (non-PERFSTRICT) functions.
PvwPatchFn      Ct, cpu, Int, 0
PvwPatchFn      Mt, cpu, STInt_STNotIdle, 0
PvwPatchFn      Mt, cpu, ETInt_ETNotIdle, 0
PvwPatchFn      Ct, cpu, Sched, 0
PvwPatchFn      ST, cpu, NotIdle, 0
PvwPatchFn      ET, cpu, NotIdle, 0

;53160PvwPatchFn      Mt, cpu, StateChange, 0

PvwPatchFn      Ct, mem, DemandLd, 0                                   ;b727647

PvwPatchFn      Ct, mem, Discard, 0

PvwPatchFn      Mt, mem, PageFault, 0
PvwPatchFn      Mt, mem, PageFault, 1

PvwPatchFn      Ct, mem, SwapOut, 0
PvwPatchFn      Ct, mem, SwapIn,  0

;51579 PvwPatchFn      Ct, mem, Reclaim,  0
PvwPatchFn      Ct, mem, Reassigned,  0                    //51579
PvwPatchFn      Ct, mem, Reassigned,  1                    //51579

PvwPatchFn      Ct, mem, Recovered,  0                     //51579
PvwPatchFn      Ct, mem, Idled,  0

;51579 remove QReclaim entries
;PvwPatchFn      EQ, mem, QReclaim, 0
;PvwPatchFn      LQ, mem, QReclaim, 0
;PvwPatchFn      LQ, mem, QReclaim, 1
;PvwPatchFn      LQ, mem, QReclaim, 2
;PvwPatchFn      LQ, mem, QReclaim, 3
;PvwPatchFn      LQ, mem, QReclaim, 4

PvwPatchFn      EQ, mem, QUsed   , 0
PvwPatchFn      LQ, mem, QUsed   , 0

PvwPatchFn      EQ, mem, QFree, 0
PvwPatchFn      LQ, mem, QFree, 0

PvwPatchFn      EQ, mem, QCTResident, 0              //51579
PvwPatchFn      LQ, mem, QCTResident, 0              //51579

;51579 remove QPresent
;PvwPatchFn      EQ, mem, QPresent, 0
;PvwPatchFn      LQ, mem, QPresent, 0

;b734380PvwPatchFn      ST, thd, Sleep, 0
;b734380PvwPatchFn      ET, thd, Sleep, 0

PvwPatchFn      ST, thd, FileIOWait, 0
PvwPatchFn      ET, thd, FileIOWait, 0
PvwPatchFn      ST, thd, FileIOWait, 1
PvwPatchFn      ET, thd, FileIOWait, 1
PvwPatchFn      ST, thd, FileIOWait, 2
PvwPatchFn      ET, thd, FileIOWait, 2
PvwPatchFn      ST, thd, FileIOWait, 3
PvwPatchFn      ET, thd, FileIOWait, 3

;b734380PvwPatchFn      ST, thd, PipeIWait, 0
;b734380PvwPatchFn      ET, thd, PipeIWait, 0

;b734380PvwPatchFn      ST, thd, PipeOWait, 0
;b734380PvwPatchFn      ET, thd, PipeOWait, 0

;b734380PvwPatchFn      ST, thd, PipeCWait, 0
;b734380PvwPatchFn      ET, thd, PipeCWait, 0

PvwPatchFn      CtST, cal, Masm, 0
PvwPatchFn      ET,   cal, Masm, 0

PvwPatchFn      CtST, cal, C, 0
PvwPatchFn      ET,   cal, C, 0

;b734380PvwPatchFn      SmTm, sem, Set, 0
;b734380PvwPatchFn      SmET, sem, Set, 0
;b734380PvwPatchFn      SmTm, sem, Blk, 0
;b734380PvwPatchFn      SmET, sem, Blk, 0

;b734380PvwPatchFn      CtST, sem, Set, 1
;b734380PvwPatchFn      ET, sem, Set, 1
;b734380PvwPatchFn      CtST, sem, Blk, 1
;b734380PvwPatchFn      ET, sem, Blk, 1

PvwPatchFn      Ct, fbc, RdHit,  0                                     ;b722131
PvwPatchFn      Ct, fbc, RdMiss, 0                                     ;b722131
PvwPatchFn      Ct, fbc, WrtHit, 0                                     ;b722131
PvwPatchFn      Ct, fbc, WrtMiss, 0                                    ;b722131
PvwPatchFn      Ct, fbc, WrtActiv, 0                                   ;b722131
;PvwPatchFn      ET, fbc, Wrt, 0                                       ;aa04447
;PvwPatchFn      ST, fbc, Wrt, 0                                       ;aa04447
;PvwPatchFn      LQ, fbc, QWrt, 0                                      ;aa04447
;PvwPatchFn      EQ, fbc, QWrt, 0                                      ;aa04447
PvwPatchFn      Ct, fbc, Bypass,0                                      ;b722131

;b734380PvwPatchFn      LQ, prc, QPg, 0                                        ;b728729
;b734380PvwPatchFn      EQ, prc, QPg, 0                                        ;b728729

IFDEF PERFSTRICT                        ;All PERFSTRICT functions.
PvwPatchFnSpare Spare1
PvwPatchFnSpare Spare2
PvwPatchFnSpare Spare3
PvwPatchFnSpare Spare4
PvwPatchFnSpare Spare5
PvwPatchFnSpare Spare6
PvwPatchFnSpare Spare7
PvwPatchFnSpare Spare8
PvwPatchFnSpare Spare9
PvwPatchFnSpare Spare10

;PvwPatchFn      Ct, vdm, Int, 0                                       ;b729110
;PvwPatchFn      Ct, vdm, BP, 0                                        ;b729110
;PvwPatchFn      Ct, vdm, V86Trap, 0                                   ;b729110
;PvwPatchFn      Ct, vdm, TrapPage, 0                                  ;b729110
;PvwPatchFn      Ct, vdm, MapPage,  0                                  ;b729110
ENDIF ;PERFSTRICT

endif ;PERFVIEW

_TEXT ENDS


ifdef PERFVIEW

;       DGROUP data (USE32)

_DATA   SEGMENT

;       Table which parallels the Perfview Measurement Router table, and
;       which contains the addresses of the original callers to the Perfview
;       Patch functions.

ALIGN 4

;b735306_pbPvwMtHook    dd      (NUM_PVMRT_ENTRIES) DUP (0)
_pbPvwMtHook    dd      offset FLAT:cpu_int
                dd      offset FLAT:cpu_etint             ;aa05232
                dd      offset FLAT:cpu_stint             ;aa05232
                dd     (NUM_PVMRT_ENTRIES - 3) DUP (0)

_DATA   ENDS

endif ;PERFVIEW

        END
