we have over-engineered "getrandom" to death
This commit is contained in:
parent
c36583631c
commit
0f0c343a85
@ -116,9 +116,10 @@ interface InputController {
|
||||
/**
|
||||
* Holds x and y variance bounds for random point generation.
|
||||
*
|
||||
* Used as parameter in [MousePointerObserver.getNearbyPoint] to control the allowed offset range.
|
||||
* Used as parameter in [InputController.getNearbyPoint] to control the allowed offset range.
|
||||
*
|
||||
* @see MousePointerObserver.getNearbyPoint()
|
||||
* @see InputController.getNearbyPoint
|
||||
* @see InputController.animateMoveMouse
|
||||
*/
|
||||
data class PointerVarianceBounds(
|
||||
val xVariance: Int = 25,
|
||||
|
||||
@ -29,7 +29,7 @@ interface TemporalController {
|
||||
val duration = if(maxAdditionalDuration == 0L){
|
||||
baseDuration
|
||||
}else{
|
||||
baseDuration + util.HelperFunctions.getRandomLongFromNormalDistribution(maxAdditionalDuration)
|
||||
baseDuration + util.HelperFunctions.getGaussianLong(maxAdditionalDuration)
|
||||
}
|
||||
|
||||
TimeUnit.MILLISECONDS.sleep(duration)
|
||||
|
||||
@ -115,7 +115,6 @@ interface WindowsOSProxy : MousePointerObserver, OSProxy {
|
||||
}
|
||||
|
||||
enum class DwmWindowAttribute {
|
||||
|
||||
DWMWA_NCRENDERING_ENABLED,
|
||||
DWMWA_NCRENDERING_POLICY,
|
||||
DWMWA_TRANSITIONS_FORCEDISABLED,
|
||||
@ -320,18 +319,15 @@ interface WindowsOSProxy : MousePointerObserver, OSProxy {
|
||||
val hWnd = user32.GetForegroundWindow()
|
||||
|
||||
val rect = WinRect()
|
||||
val success = user32.DwmGetWindowAttribute(
|
||||
hWnd,
|
||||
8,
|
||||
rect.pointer,
|
||||
rect.size()
|
||||
)
|
||||
return if (true){
|
||||
// val attr = user32.DwmGetWindowAttribute(
|
||||
// hWnd,
|
||||
// 8,
|
||||
// rect.pointer,
|
||||
// rect.size()
|
||||
// )
|
||||
|
||||
rect.read()
|
||||
Rectangle(rect.top, rect.left, (rect.right - rect.left), rect.bottom - rect.top)
|
||||
}else{
|
||||
null
|
||||
}
|
||||
return Rectangle(rect.top, rect.left, (rect.right - rect.left), rect.bottom - rect.top)
|
||||
}
|
||||
|
||||
fun barelyFunctionalWindowQuery(): Rectangle? {
|
||||
|
||||
@ -42,21 +42,38 @@ object HelperFunctions {
|
||||
* @param upperBound The upper bound to sample from
|
||||
* @return A random long value following an approximate normal distribution
|
||||
*/
|
||||
fun getRandomLongFromNormalDistribution(upperBound: Long): Long{
|
||||
fun getGaussianLong(upperBound: Long): Long {
|
||||
// anything lower to 2 will round down to zero, so return zero. Additionally, this guarantees a positive upper
|
||||
//bound in one step
|
||||
if(upperBound <= 2L){
|
||||
if (upperBound <= 2L) {
|
||||
return 0L
|
||||
}
|
||||
|
||||
// To create more natural distribution Take two random samples from 0 to upperBound/2 and add them. This
|
||||
// approximates a normal distribution better than single random sample.
|
||||
val subBound = upperBound/2L
|
||||
val subBound = upperBound / 2L
|
||||
val result1 = Random.nextLong(subBound)
|
||||
val result2 = Random.nextLong(subBound)
|
||||
return result1 + result2
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random long following a Gaussian distribution within the given upper bound.
|
||||
*
|
||||
* Models the distribution observed in getRandomLongFromNormalDistribution
|
||||
*
|
||||
* @param upperBound The upper bound of the distribution
|
||||
* @return A random long value
|
||||
*/
|
||||
fun getNextGaussian(upperBound: Long): Long {
|
||||
return java.util.Random()
|
||||
.nextGaussian(
|
||||
upperBound.toDouble() / 2.0,
|
||||
upperBound.toDouble() / 5.0
|
||||
).toLong()
|
||||
.coerceIn(0..upperBound)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prints a progress report to console showing current step, total steps, elapsed time, and estimated remaining time.
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
package util
|
||||
|
||||
import kotlin.math.pow
|
||||
import kotlin.test.*
|
||||
import kotlin.system.measureNanoTime
|
||||
import kotlin.system.measureTimeMillis
|
||||
import kotlin.test.Test
|
||||
|
||||
|
||||
class HelperFunctionsTest {
|
||||
@ -14,7 +16,7 @@ class HelperFunctionsTest {
|
||||
val numSamples = 10000
|
||||
val upperBound = 1000L
|
||||
val samples = (1..numSamples).map {
|
||||
HelperFunctions.getRandomLongFromNormalDistribution(upperBound)
|
||||
HelperFunctions.getGaussianLong(upperBound)
|
||||
}
|
||||
|
||||
// Calculate mean and standard deviation
|
||||
@ -26,4 +28,117 @@ class HelperFunctionsTest {
|
||||
assert(stdDev > upperBound * 0.2 && stdDev < upperBound * 0.3)
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test benchmark getNextLongJanky`() {
|
||||
val iterations = 1000000
|
||||
val upperBound = 1000L
|
||||
|
||||
println("Starting benchmark N=$iterations, Range[0,$upperBound] using getRandomLongFromNormalDistribution...")
|
||||
|
||||
repeat(10) {
|
||||
val samples = ArrayList<Long>(iterations)
|
||||
|
||||
val time = doBenchmark(iterations, upperBound) {
|
||||
val v = HelperFunctions.getGaussianLong(it)
|
||||
samples.add(v)
|
||||
v
|
||||
}
|
||||
// Calculate mean and standard deviation
|
||||
val mean = samples.average()
|
||||
val stdDev = samples.map { (it - mean).pow(2) }.average().pow(0.5)
|
||||
|
||||
println("[Speed] Generated $iterations random longs in $time nanos [${(time.toDouble() / iterations.toDouble())}ns per operation]")
|
||||
println("[Precision] Mean: $mean\tstDev: $stdDev\n")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test benchmark getNextLongGaussian`() {
|
||||
|
||||
val iterations = 1000000
|
||||
val upperBound = 1000L
|
||||
|
||||
println("Starting benchmark N=$iterations, Range[0,$upperBound] using getNextGaussian...")
|
||||
|
||||
repeat(10) {
|
||||
val samples = ArrayList<Long>(iterations)
|
||||
|
||||
val time = doBenchmark(iterations, upperBound) {
|
||||
val v = HelperFunctions.getNextGaussian(it)
|
||||
samples.add(v)
|
||||
v
|
||||
}
|
||||
// Calculate mean and standard deviation
|
||||
val mean = samples.average()
|
||||
val stdDev = samples.map { (it - mean).pow(2) }.average().pow(0.5)
|
||||
|
||||
println("[Speed] Generated $iterations random longs in $time nanos [${(time.toDouble() / iterations.toDouble())}ns per operation]")
|
||||
println("[Precision] Mean: $mean\tstDev: $stdDev\n")
|
||||
}
|
||||
}
|
||||
|
||||
fun eat(d: Number) {
|
||||
|
||||
}
|
||||
|
||||
fun doBenchmark(iterations: Int, upperBound: Long, callback: (Long) -> Long): Long {
|
||||
var total = 0L
|
||||
return measureNanoTime {
|
||||
repeat(iterations) {
|
||||
total += callback(upperBound)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun `test Direct Comparison of performance`() {
|
||||
val heats = 1000
|
||||
val iterations = 1000000
|
||||
val upperBound = 1000L
|
||||
|
||||
val addTimes = ArrayList<Long>(heats)
|
||||
val gaussianTimes = ArrayList<Long>(heats)
|
||||
|
||||
//pre-warm the JIT and caches a bit
|
||||
println("Warming up for a few iterations")
|
||||
val consumer = ArrayList<Long>(iterations)
|
||||
repeat(iterations){
|
||||
consumer.add(HelperFunctions.getGaussianLong(upperBound))
|
||||
consumer.add(HelperFunctions.getNextGaussian(upperBound))
|
||||
}
|
||||
|
||||
println("Benchmarking methods [$heats heats of $iterations iterations]{Range[0,$upperBound]}...")
|
||||
repeat(heats) {
|
||||
var total = 0L
|
||||
val time1 = measureNanoTime {
|
||||
repeat(iterations) {
|
||||
total += HelperFunctions.getGaussianLong(upperBound)
|
||||
}
|
||||
}
|
||||
|
||||
addTimes.add(time1/iterations)
|
||||
|
||||
total = 0L
|
||||
val time2 = measureNanoTime {
|
||||
repeat(iterations) {
|
||||
total += HelperFunctions.getNextGaussian(upperBound)
|
||||
}
|
||||
}
|
||||
|
||||
gaussianTimes.add(time2/iterations)
|
||||
}
|
||||
|
||||
printStatisticsWithPrefix(addTimes, "Add Randoms method:\t", "ns")
|
||||
printStatisticsWithPrefix(gaussianTimes, "NextGaussian method:", "ns")
|
||||
}
|
||||
|
||||
fun printStatisticsWithPrefix(samples: ArrayList<Long>, prefix: String, unit: String = "") {
|
||||
// Calculate mean and standard deviation
|
||||
val mean = samples.average()
|
||||
val stdDev = samples.map { (it - mean).pow(2) }.average().pow(0.5)
|
||||
println("$prefix\tMean: $mean$unit\tstDev: $stdDev$unit")
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user