#!/bin/bash
# simple tester for ocperf

set -x

PERF=${PERF:-perf}
WRAP=${WRAP:-}


failed() {
	echo FAILED
}
trap failed ERR 0

. ./cpumap.sh

#for j in ${cpus[@]} ; do
#	if [ ! -r ~/.events/$j-core.json ] ; then
#		./event_download $j
#	fi
#done

# handle unknown event
$PERF stat -e branch-misses true

checklist()
{
	echo cpu $1 = ${cpus[$1]}

	# just see that it doesn't fail
	EVENTMAP=${cpus[$1]} $WRAP ./ocperf.py list > /dev/null

	# see if all events are visible
	R=$(EVENTMAP=${cpus[$1]} $WRAP ./ocperf.py list | wc -l)
	if [ $((R - BASELEN)) -lt $2 ]; then
		echo $1 list mismatch $((R - BASELEN))
		exit 1
	fi
}

BASELEN=$($PERF list | wc -l)

checklist hsw 100
checklist hsx 100
checklist wsm-sp 100
checklist wsm-dp 100
checklist snb 100
checklist jkt 100
checklist ivb 100
checklist nhm-ex 100
checklist nhm-ep 100
checklist bnl 100
checklist ivt 100
checklist slm 100
checklist bdw-de 100
checklist bdw 100
checklist skl 100
checklist icl 100
checklist tgl 100

O=$(EVENTMAP=${cpus[skl]} $WRAP ./ocperf.py list | wc -l)
E=$(EVENTMAP=${cpus[skl]} $WRAP ./ocperf.py list --experimental  | wc -l)
if [ $E -lt $O ] ;then
	echo "No experimental events on SKL"
	exit 1
fi

set -e
$WRAP ./ocperf.py stat -e inst_retired.any /bin/true

# xxx cover new syntax too
checkmsr()
{
	DIRECT_MSR=1 EVENTMAP=${cpus[$1]} $WRAP ./ocperf.py --print stat -e $2 /bin/true | grep "msr 1a6 ="
}

checkmsr wsm-dp OFFCORE_RESPONSE.ANY_DATA.ANY_CACHE_DRAM
checkmsr nhm-ex OFFCORE_RESPONSE_0.ANY_DATA.ANY_CACHE_DRAM
checkmsr hsw offcore_response.all_reads.l3_miss.any_response
checkmsr hsw offcore_response.demand_data_rd.l3_hit.hit_other_core_no_fwd

checkev()
{
	DIRECT_MSR=1 EVENTMAP=${cpus[$1]} $WRAP ./ocperf.py stat -e $2 /bin/true | grep -E -- "-e $3"
}
checkev nhm-ep L1D.M_EVICT '(r451|cpu/event=0x51,umask=0x4/)'
checkev nhm-ep L1D.M_EVICT:c4 r4000451
checkev nhm-ex L1D.M_EVICT:c4 r4000451
checkev wsm-dp L1D.M_EVICT:c4 r4000451
checkev hsw DTLB_LOAD_MISSES.STLB_HIT_2M r4008 
checkev ivb IDQ.DSB_CYCLES r1000879
checkev snb IDQ.DSB_CYCLES r1000879
checkev bnl snoop_stall_drv.self r407e
checkev ivt uops_issued.core_stall_cycles r1a0010e
checkev icx imc/unc_m_hclockticks/,cpu/cpu_clk_unhalted.thread/ "" # XXX

cat >topology <<EOL
/sys/bus/event_source/devices/uncore_ha
/sys/bus/event_source/devices/uncore_ha/format/umask
EOL

cat >cputopology <<EOL
/sys/bus/event_source/devices/cpu/format/offcore_rsp
EOL

checkuc()
{
	TOPOLOGY=topology \
	EVENTMAP=${cpus[$1]} UNCORE=$2 $WRAP ./ocperf.py stat --print -e $3 /bin/true | grep -E -- "$4"
}

checkuc hsw test-uncore.json unc_h_directory_lookup.no_snp 'uncore_ha(_[0-9]+)?/event=0xc,umask=0x2,name=unc_h_directory_lookup_no_snp(_[0-9]+)?/'

checkmsr2()
{
	EVENTMAP=${cpus[$1]} DIRECT_MSR=1 $WRAP ./ocperf.py --print stat -e $2 /bin/true | grep "$3"
}

# FIXME: need to adapt to new event file format
#checkmsr2 wsm-sp offcore_response.pf_rfo.remote_cache_hitm_1 "msr 1a7 = 820"
checkmsr2 nhm-ex offcore_response_0.data_ifetch.any_location "msr 1a6 = ff77"
# xxx add hsw
checkmsr2 ivt offcore_response.all_data_rd.llc_hit.hit_other_core_no_fwd "msr 1a6 = 4003c0091"
checkmsr2 jkt offcore_response.all_data_rd.llc_hit.hit_other_core_no_fwd "msr 1a6 = 4003c0091"
checkmsr2 slm offcore_response.any_request.any_response "msr 1a6 = 18008"

# parser checks
checkp() 
{
	$WRAP ./ocperf.py --print stat $3 -e "$1" > tlog$$
	grep -E "$2" tlog$$
}

checknotp()
{
	$WRAP ./ocperf.py --print stat $3 -e "$1" > tlog$$
	grep -E -v "$2" tlog$$
}

checkp_record() {
	$WRAP ./ocperf.py --print record -e "$1" > tlog$$
	grep -E "$2" tlog$$
}
export EVENTMAP=${cpus[hsw]}
DIRECT_MSR=1 checkp BR_INST_RETIRED.CONDITIONAL 'r1c4$'
DIRECT_MSR=1 checkp BR_INST_RETIRED.CONDITIONAL:p  'r1c4:p$'
DIRECT_MSR=1 checkp BR_INST_RETIRED.CONDITIONAL:p  'r1c4:p$'
DIRECT_MSR=1 checkp BR_INST_RETIRED.CONDITIONAL:ppp  'r1c4:ppp$'

unset DIRECT_MSR
checkp CPU_CLK_UNHALTED.THREAD:cmask=3 'cmask=3'
checkp CPU_CLK_UNHALTED.THREAD:c3:e1 'edge=1'
checkp CPU_CLK_UNHALTED.THREAD:amt1 'any=1'
checkp CPU_CLK_UNHALTED.THREAD:amt1:tx 'in_tx=1'
checkp CPU_CLK_UNHALTED.THREAD:amt1:cp 'any=1'
checkp CPU_CLK_UNHALTED.THREAD:c3 'cmask=3'
checkp CPU_CLK_UNHALTED.THREAD:sa=10000 'period=10000'
checkp CPU_CLK_UNHALTED.THREAD:ppp '/ppp'
checkp INST_RETIRED.PREC_DIST "/p"

# following tests need new enough perf

checkp cpu/BR_INST_RETIRED.CONDITIONAL,foo=bar/  'event=0xc4,umask=0x1,name=br_inst_retired_conditional,foo=bar/$'
checkp cpu/BR_INST_RETIRED.CONDITIONAL/  'event=0xc4,umask=0x1,name=br_inst_retired_conditional/$'
checkp cpu/br_inst_retired.conditional/  'event=0xc4,umask=0x1,name=br_inst_retired_conditional/$'
checkp cpu/BR_INST_RETIRED.CONDITIONAL,foo=bar/p  'event=0xc4,umask=0x1,name=br_inst_retired_conditional,foo=bar/p$'
checkp 'cpu/BR_INST_RETIRED.CONDITIONAL,foo=bar/upp'  'event=0xc4,umask=0x1,name=br_inst_retired_conditional,foo=bar/(ppu|upp)$'
export EVENTMAP=${cpus[wsm-sp]}
DIRECT_MSR=1 checkp l2_write.rfo.m_state:c4 'r4000827'
unset DIRECT_MSR
#checkp l2_write.rfo.m_state:c4 'cpu/event=0x27,umask=0x8,cmask=4,name=l2_write_rfo_m_state/'

export EVENTMAP=${cpus[hsx]}
# check :request :response syntax
TOPOLOGY=cputopology \
checkp OFFCORE_RESPONSE:request=DEMAND_RFO:response=LLC_MISS.REMOTE_HITM  \
	cpu/event=0xb7,umask=0x1,offcore_rsp=0x10[37]fc00002,name=offcore_response_request_demand_rfo_response_llc_miss_remote_hitm/

checks()
{
	$WRAP ./ocperf.py stat -e "$1" true > tlog$$
}

checkr()
{
	$WRAP ./ocperf.py record -e "$1" true > tlog$$
}

checks '{cycles,cpu_clk_unhalted.thread,instructions}'
checks '{cycles,cpu/cpu_clk_unhalted.thread,cmask=1/}'
checks '{cpu/cpu_clk_unhalted.thread,cmask=1/u}'
checkr '{cpu/cpu_clk_unhalted.thread,period=10000/u,instructions}:S'
checkr '{cpu/cpu_clk_unhalted.thread,period=10000/u,cpu/cpu-cycles/,instructions}:S'
checks '{cpu/cpu-cycles/,instructions}'
checkr '{node-stores,instructions}:S'
checkr '{cpu/cpu-cycles/,instructions}:S'
checkr '{cpu/instructions,period=1000000/u,cpu_clk_unhalted.thread}:S'
checkp 'cpu_clk_unhalted:period=123' 'period=123'
cat >top2$$ <<EOL
/sys/bus/event_source/devices/uncore_r2pcie
/sys/bus/event_source/devices/uncore_r2pcie/format/umask
/sys/bus/event_source/devices/uncore_r2pcie/format/cmask
EOL
TOPOLOGY=top2$$ UNCORE="Jaketown*" checkp 'unc_r2_iio_credits_acquired.ncb:state=0x123' 'filter_state=0x123'

cat >top2$$ <<EOL
/sys/bus/event_source/devices/uncore_cbox_0
/sys/bus/event_source/devices/uncore_cbox_0/format/umask
/sys/bus/event_source/devices/uncore_cbox_1
/sys/bus/event_source/devices/uncore_cbox_1/format/umask
EOL
TOPOLOGY=top2$$ UNCORE="haswell_uncore*" checkp 'unc_cbo_xsnp_response.hit_xcore' 'uncore_cbox_1'
TOPOLOGY=top2$$ UNCORE="haswell_uncore*" checkp 'unc_cbo_xsnp_response.hit_xcore:one_unit' 'uncore_cbox_0'
TOPOLOGY=top2$$ UNCORE="haswell_uncore*" checknotp 'unc_cbo_xsnp_response.hit_xcore:one_unit' 'uncore_cbox_1'
TOPOLOGY=top2$$ UNCORE="haswell_uncore*" checknotp 'unc_cbo_xsnp_response.hit_xcore' 'uncore_cbox_1' --noexplode
TOPOLOGY=top2$$ UNCORE="haswell_uncore*" checkp 'unc_cbo_xsnp_response.hit_xcore' 'uncore_cbox[^_]' --noexplode

TOPOLOGY=top2$$ EVENTMAP=${cpus[jkt]} checkp 'UNC_C_TOR_INSERTS.MISS_OPCODE:opc=0x1c8:tid=0x3e' 'filter_opc=0x1c8,filter_tid=0x3e'

checkp_record '{cpu/cpu_clk_unhalted.thread/,cpu/br_inst_retired.all_branches/}:S'  \
	'{cpu/event=0x3c,umask=0x0,name=cpu_clk_unhalted_thread,period=2000003/,cpu/event=0xc4,umask=0x0,name=br_inst_retired_all_branches/}:S'

export EVENTMAP=${cpus[skl]}
checkp cpu_clk_unhalted.thread_p:os=yes /k
checkp cpu_clk_unhalted.thread_p:os=no /u
checkp cpu_clk_unhalted.thread_p:sup /k
checkp cpu_clk_unhalted.thread_p:SUP /k
checkp cpu_clk_unhalted.thread_any:anythr=no any=0
checkp cpu_clk_unhalted.thread_any:anythr=yes any=1
checkp cpu_clk_unhalted.thread_any:pdir /ppp
checkp cpu_clk_unhalted.thread_any:precise=yes /pp

trap "" ERR 0
rm -f tlog$$ top2$$

echo SUCCEEDED
