genode/repos/os/run/cpu_quota.run
Martin Stein 01643ccd94 cpu_quota hw exynos5: raise error tolerance
From our observations we can tell that the error should not exceed 4%.
However, there is no reasonable explanation by now why the test results
are less stable on these platforms. We have tried several things that
did not lead to an explanation or improvement:

  * changing the timing parameters of the scheduler
  * switching off SMP
  * double-checking the speed of userland and kernel timers

Ref #1805
2015-12-10 13:16:26 +01:00

285 lines
7.9 KiB
Plaintext

#
# Check platform
#
# HW is the only kernel that provides appliance of quota to the scheduling.
#
assert_spec hw
#
# Build
#
build "core init drivers/timer test/cpu_quota"
#
# Boot image
#
create_boot_directory
install_config {
<config prio_levels="4">
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="SIGNAL"/>
</parent-provides>
<default-route>
<any-service><parent/><any-child/></any-service>
</default-route>
<start name="test-sync">
<resource name="RAM" quantum="10M"/>
<provides><service name="Sync"/></provides>
</start>
<start name="init_1" priority="-1">
<binary name="init"/>
<resource name="RAM" quantum="20M"/>
<resource name="CPU" quantum="10"/>
<config>
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="SIGNAL"/>
<service name="Timer"/>
<service name="Sync"/>
</parent-provides>
<default-route>
<any-service><parent/><any-child/></any-service>
</default-route>
<start name="test_slow">
<binary name="test-cpu_quota"/>
<resource name="RAM" quantum="10M"/>
<resource name="CPU" quantum="50"/>
</start>
</config>
</start>
<start name="init_2" priority="-2">
<binary name="init"/>
<resource name="RAM" quantum="30M"/>
<resource name="CPU" quantum="80"/>
<config prio_levels="2">
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="SIGNAL"/>
<service name="Timer"/>
<service name="Sync"/>
</parent-provides>
<default-route>
<any-service><parent/></any-service>
</default-route>
<start name="test_midl" priority="0">
<binary name="test-cpu_quota"/>
<resource name="RAM" quantum="10M"/>
<resource name="CPU" quantum="25"/>
</start>
<start name="test_fast" priority="-1">
<binary name="test-cpu_quota"/>
<resource name="RAM" quantum="10M"/>
<resource name="CPU" quantum="75"/>
</start>
</config>
</start>
<start name="timer" priority="0">
<resource name="RAM" quantum="10M"/>
<resource name="CPU" quantum="10"/>
<provides><service name="Timer"/></provides>
</start>
</config>
}
build_boot_image "core init timer test-cpu_quota test-sync"
#
# Execution
#
append qemu_args "-nographic -m 128"
run_genode_until ".*done.*\n.*done.*\n.*done.*\n" 100
#
# Conclusion
#
set err_cnt 0
proc check_counter { name opt cnt total_cnt } {
global err_cnt
set bad 0
set class "Good: "
set tol 0.01
set is 0
#
# On X86, the timer driver uses the PIT with a maximum timeout of 54 ms.
# Thus, the driver frequently interrupts the counters with highest
# priority to update the timer. This is why we need a higher error
# tolerance as for ARM where the driver, once configured, can sleep for
# the whole test timeout.
#
if {[have_spec x86]} { set tol 0.02 }
#
# Zynq is currently tested merely in Qemu and most likely because of
# that, the results are less precise.
#
if {[have_spec zynq_qemu]} { set tol 0.03 }
#
# FIXME: There is no reasonable explanation by now why the test results
# are less stable on these platforms. We have tried several things that
# did not lead to an explanation or improvement:
#
# * changing the timing parameters of the scheduler
# * switching off SMP
# * double-checking the speed of userland and kernel timers
#
if {[have_spec hw_odroid_xu]} { set tol 0.04 }
if {[have_spec hw_arndale]} { set tol 0.04 }
if {[expr $total_cnt != 0]} { set is [expr double($cnt) / $total_cnt ] }
set err [expr $is - $opt]
set is_fmt [format {%0.3f} [expr $is * 100]]
set opt_fmt [format {%0.3f} [expr $opt * 100]]
set err_fmt [format {%0.3f} [expr $err * 100]]
set tol_fmt [format {%0.3f} [expr $tol * 100]]
if {[expr abs($err) > $tol]} {
set class "Bad: "
set err_cnt [expr $err_cnt + 1]
}
puts "$class$name received $is_fmt% CPU (goal $opt_fmt% tol $tol_fmt% err $err_fmt%)"
}
proc check_quota { name opt_sp quota_sp opt quota } {
global err_cnt
if {[expr $quota != $opt]} {
puts "Bad: $name has quota $quota us (goal $opt us)"
set err_cnt [expr $err_cnt + 1]
}
if {[expr $quota_sp != $opt_sp]} {
puts "Bad: $name has super period $quota_sp us (goal $opt_sp us)"
set err_cnt [expr $err_cnt + 1]
}
}
# pre-define variables if regexp does not match
set slow_quota ""; set midl_quota ""; set fast_quota ""
set slow_quota_sp ""; set midl_quota_sp ""; set fast_quota_sp ""
regexp {[0-9]+} [regexp -inline {slow. quota [0-9]+} $output] slow_quota
regexp {[0-9]+} [regexp -inline {midl. quota [0-9]+} $output] midl_quota
regexp {[0-9]+} [regexp -inline {fast. quota [0-9]+} $output] fast_quota
regexp {[0-9]+} [regexp -inline {slow. quota super period [0-9]+} $output] slow_quota_sp
regexp {[0-9]+} [regexp -inline {midl. quota super period [0-9]+} $output] midl_quota_sp
regexp {[0-9]+} [regexp -inline {fast. quota super period [0-9]+} $output] fast_quota_sp
#
# We have to consider the rounding errors as the two translations from init to
# core and then from core to the user are distinct.
#
# Slow quota (1000000 * (0x8000 * 5 / 100)) / 0x8000 = 49987
# Slow quota (1000000 * (0x8000 * 20 / 100)) / 0x8000 = 199981
# Slow quota (1000000 * (0x8000 * 60 / 100)) / 0x8000 = 599975
#
check_quota "Slow test" 1000000 $slow_quota_sp 49987 $slow_quota
check_quota "Middle test" 1000000 $midl_quota_sp 199981 $midl_quota
check_quota "Fast test" 1000000 $fast_quota_sp 599975 $fast_quota
regexp {[0-9]+} [regexp -inline {slow. counter A [0-9]+} $output] slow_a_cnt
regexp {[0-9]+} [regexp -inline {midl. counter A [0-9]+} $output] midl_a_cnt
regexp {[0-9]+} [regexp -inline {fast. counter A [0-9]+} $output] fast_a_cnt
regexp {[0-9]+} [regexp -inline {slow. counter B [0-9]+} $output] slow_b_cnt
regexp {[0-9]+} [regexp -inline {midl. counter B [0-9]+} $output] midl_b_cnt
regexp {[0-9]+} [regexp -inline {fast. counter B [0-9]+} $output] fast_b_cnt
set total_cnt [expr $fast_a_cnt + $midl_a_cnt + $slow_a_cnt + $fast_b_cnt + $midl_b_cnt + $slow_b_cnt]
#
# Slow 5.0 % claim + 5.0 % fill = 10 %
# Stage 1
# A 0.5 % claim + 2.5 % fill = 3 %
# B 4.5 % claim + 2.5 % fill = 7 %
# Stage 2
# A 5.0 % claim + 5.0 % fill = 10 %
# Total
# A 3/4 * 3 + 1/4 * 10 = 4.75 %
# A 3/4 * 7 + 1/4 * 0 = 5.25 %
#
check_counter "Slow counter A" 0.0475 $slow_a_cnt $total_cnt
check_counter "Slow counter B" 0.0525 $slow_b_cnt $total_cnt
#
# Middle 20 % claim + 5.0 % fill = 25.0 %
# Stage 1
# A 2 % claim + 2.5 % fill = 4.5 %
# B 18 % claim + 2.5 % fill = 20.5 %
# Stage 2
# A 20 % claim + 5.0 % fill = 25.0 %
# Total
# A 3/4 * 4.5 + 1/4 * 25 = 9.625 %
# A 3/4 * 20.5 + 1/4 * 0 = 15.375 %
#
check_counter "Middle counter A" 0.09625 $midl_a_cnt $total_cnt
check_counter "Middle counter B" 0.15375 $midl_b_cnt $total_cnt
#
# Fast 60 % claim + 5.0 % fill = 65.0 %
# Stage 1
# A 6 % claim + 2.5 % fill = 8.5 %
# B 54 % claim + 2.5 % fill = 56.5 %
# Stage 2
# A 60 % claim + 5.0 % fill = 65.0 %
# Total
# A 3/4 * 8.5 + 1/4 * 65 = 22.625 %
# A 3/4 * 56.5 + 1/4 * 0 = 42.375 %
#
check_counter "Fast counter A" 0.22625 $fast_a_cnt $total_cnt
check_counter "Fast counter B" 0.42375 $fast_b_cnt $total_cnt
# final conclusion and return
if {[expr $err_cnt > 0]} {
puts "Test failed because of $err_cnt errors"
exit -1
}
puts "Test succeeded"