;       SCCSID = @(#)perfkia.asm
SCCSID equ "@(#)perfkia.asm
TITLE   PERFKIA -- OS/2 PERFKIA module

;       Performance measurement of idle times in kernel.
;
;       IBM Confidential
;
;       Copyright (c) IBM Corporation 1996

.xlist
include dosseg.inc
include fnotask.inc
include basemaca.inc
include osmaca.inc
include defdbug.inc
include dossymc.inc
include bseerr.inc
include proc.inc
include sched.inc
include mi.inc
include pmode.inc
include infoseg.inc
include except.inc
include screen.inc
include ostypes.inc
include sft.inc
.list
include tkexport.inc
.xlist
include kmode.inc
include sigdef.inc
include argframe.inc
include osconst.inc
include pgexport.inc
include vmexport.inc
include selxport.inc
include curdir.inc
include dirent.inc
include find.inc
include sem.inc
include protmode.inc
.list
include tkptda.inc
.xlist
include tom.inc
include doshlp.inc
include ..\memory\pglocal.inc
.list
ifdef SMP
include ipc.inc
include tkmp.inc
endif
include perfvw.inc
include perfki.inc

CpuMode 386

	ReferGlobal	DHF, DWORD

	ReferFlat	_CpuType, DWORD
	ReferFlat	_Pentium_Feature_Flags, DWORD
	ReferFlat	_fsTmrStatus, WORD

ifdef SMP
	ReferFlat	_KISyncFlag,DWORD
	ReferFlat	_cProcessors,DWORD

	ReferFlat	_KI_proc_state,DWORD
	ReferFlat	_KI_statechg_lts,DWORD
	ReferFlat	_KI_statechg_hts,DWORD
	ReferFlat	_KI_idle_ltime,DWORD
	ReferFlat	_KI_idle_htime,DWORD
	ReferFlat	_KI_busy_ltime,DWORD
	ReferFlat	_KI_busy_htime,DWORD
	ReferFlat	_KI_intr_ltime,DWORD
	ReferFlat	_KI_intr_htime,DWORD
	ReferFlat	_KI_latch_lts,DWORD
	ReferFlat	_KI_latch_hts,DWORD
	ReferFlat	_KI_latch_idle_ltime,DWORD
	ReferFlat	_KI_latch_idle_htime,DWORD
	ReferFlat	_KI_latch_busy_ltime,DWORD
	ReferFlat	_KI_latch_busy_htime,DWORD
	ReferFlat	_KI_latch_intr_ltime,DWORD
	ReferFlat	_KI_latch_intr_htime,DWORD

	EXTRN	_IPIStart:NEAR
	EXTRN	_EnterKISync:NEAR
else

	ReferFlat	fIdle,BYTE
_DATA	segment

        public          _KI_proc_state
        public          _KI_statechg_lts
        public          _KI_statechg_hts
        public          _KI_idle_ltime
        public          _KI_idle_htime
        public          _KI_busy_ltime
        public          _KI_busy_htime
        public          _KI_intr_ltime
        public          _KI_intr_htime
        public          _KI_latch_lts
        public          _KI_latch_hts
        public          _KI_latch_idle_ltime
        public          _KI_latch_idle_htime
        public          _KI_latch_busy_ltime
        public          _KI_latch_busy_htime
        public          _KI_latch_intr_ltime
        public          _KI_latch_intr_htime

_KI_proc_state		DD	0
_KI_statechg_lts	DD	0
_KI_statechg_hts	DD	0
_KI_idle_ltime		DD	0
_KI_idle_htime		DD	0
_KI_busy_ltime		DD	0
_KI_busy_htime		DD	0
_KI_intr_ltime		DD	0
_KI_intr_htime		DD	0
_KI_latch_lts		DD	0
_KI_latch_hts	DD	0
_KI_latch_idle_ltime	DD	0
_KI_latch_idle_htime	DD	0
_KI_latch_busy_ltime	DD	0
_KI_latch_busy_htime	DD	0
_KI_latch_intr_ltime	DD	0
_KI_latch_intr_htime	DD	0
        
_DATA	ends

endif

	FARCODE HIGH32
HIGH32CODE SEGMENT


; _KIEnable - Enable KI hooks.
;
;	ENTRY	NONE
;
;	EXIT	NONE
;
;	USES	NONE

ASSUME DS:FLAT, ES:FLAT, FS:NOTHING, GS:NOTHING, SS:NOTHING
Procedure _KIEnable
	EnterProc
	SaveReg <eax, ecx>
	pushfd
ifdef SMP
	xor	ecx, ecx			; processor 0
kie01:
	mov	eax, ecx			; EAX = dest proc
	MPGetPSAAddr				; EAX = pPSA of dest proc
	mov	[eax].PSAvars_KI_proc_state, KI_STATE_IDLE
	cmp	[eax].PSAvars_fIdle, 0		; dest proc busy?
	jne	short kie02			; jump if not busy
	mov	[eax].PSAvars_KI_proc_state, KI_STATE_BUSY
kie02:
	inc	ecx				; next processor
	cmp	ecx, _cProcessors
	jne	short kie01
else
	mov	_KI_proc_state, KI_STATE_IDLE
	cmp	fIdle, 0			; processor busy?
	jne	short kie02			; jump if not busy
	mov	_KI_proc_state, KI_STATE_BUSY
kie02:
endif

	cli
	KITurnOn goidle
	KITurnOn gobusy
	KITurnOn intr_begin, intr
	KITurnOn intr_end, intr
ifdef SMP
	KITurnOn intr_begin, ipi
	KITurnOn intr_end, ipi
endif

	popfd
	RestoreReg <ecx, eax>
	ExitProc
EndProc _KIEnable


; _KIEnableInit - Enable in-kernel system idleness measurement at the
;	system initialization time.  It first checks whether Pentium
;	cycle counter is supported (CPU at least Pentium).  If not,
;	we need to use 8254 timer values.
;
;	ENTRY	NONE
;
;	EXIT	NONE
;
;	USES	NONE

ASSUME DS:FLAT, ES:FLAT, FS:NOTHING, GS:NOTHING, SS:NOTHING
Procedure _KIEnableInit
	EnterProc
	pushad
	;; need to put Pentium checking here.

	cmp	_CpuType, CPU_PENTIUM
	jne	kiei_check_8254tmr

	;; Pentium, check instruction counter support
	test	_Pentium_Feature_Flags, ICNTR_supported
	jnz	kiei_enable_hooks	; jump if supported

kiei_check_8254tmr:
	test	_fsTmrStatus,TMR_INSTALLED  ;Tmr installed?
	jz	short kiei_nohooks	; No, then can't enable KI hooks
	
	pushfd				; need to disable interrupts while
	cli				; we are modifying code.
	;; modify gettimer in KILatch subroutine
	;; 90h --> nop
	;; 0ffh, 15h, addr --> call contents of addr
	mov	eax, 15ff90h
	mov	DWORD PTR KILatch_gettmr, eax
	lea	eax, DHF.DosHlpTmr32QueryTime  ; get address (assuming FLAT)
	mov	DWORD PTR KILatch_gettmr + 3, eax
	
	KIUse8254Tmr goidle
	KIUse8254Tmr gobusy
	KIUse8254Tmr intr_begin, intr
	KIUse8254Tmr intr_end, intr
ifdef SMP
;	KIUse8254Tmr intr_begin, ipi
;	KIUse8254Tmr intr_end, ipi
endif
	popfd

kiei_enable_hooks:
	call	_KIEnable

kiei_nohooks:
	popad
	ExitProc
EndProc _KIEnableInit


; _KIDisable - Disable in-kernel system idleness measurement.  It
;	disables hooks in the kernel that keeps track of times when the
;	system is idle, handling interrupts or doing useful work.
;
;	ENTRY	NONE
;
;	EXIT	NONE
;
;	USES	NONE

ASSUME DS:FLAT, ES:FLAT, FS:NOTHING, GS:NOTHING, SS:NOTHING
Procedure _KIDisable
	EnterProc
	SaveReg <eax>
	
	KITurnOff goidle
	KITurnOff gobusy
	KITurnOff intr_begin, intr
	KITurnOff intr_end, intr
ifdef SMP
	KITurnOff intr_begin, ipi
	KITurnOff intr_end, ipi
endif

	RestoreReg <eax>
	ExitProc
EndProc _KIDisable


; _KILatch - Latch the Kernel Idleness counters.
;
;	ENTRY	NONE
;
;	EXIT	NONE
;
;	USES	NONE

ASSUME DS:FLAT, ES:FLAT, FS:NOTHING, GS:NOTHING, SS:NOTHING
Procedure _KILatch
	EnterProc

ifdef SMP
	;; For SMP, we need to copy current counter values to shadow storage
	;; at the same time.  So we use IPI.
	mov	_KISyncFlag, 0
	CCALL32	_IPIStart <-1, IPI_PERFSYS, PERFSYS_KISYNC>
	CCALL32 _EnterKISync
else
	;; For UP, we can read current counter values directly.  But we
	;; still need to CLI.
	pushfd
	pushad
	cld
	cli
	
	;; update the counters first.
	lea	ebx, _KI_idle_ltime
	mov	eax, _KI_proc_state
	and	eax, 0FFh
	add	ebx, eax
	
KILatch_gettmr:
	KIAccumulate			; update current counters
	
	lea	esi, _KI_statechg_lts	; source address
	lea	edi, _KI_latch_lts	; destination
	mov	ecx, 8			; total 8 DWORDS
	rep	movsd			; copy counters to latched counters
		
	popad
	popfd
endif
	
	ExitProc
EndProc _KILatch


HIGH32CODE ends

	END
