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.
|
* 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(
|
data class PointerVarianceBounds(
|
||||||
val xVariance: Int = 25,
|
val xVariance: Int = 25,
|
||||||
|
|||||||
@ -29,7 +29,7 @@ interface TemporalController {
|
|||||||
val duration = if(maxAdditionalDuration == 0L){
|
val duration = if(maxAdditionalDuration == 0L){
|
||||||
baseDuration
|
baseDuration
|
||||||
}else{
|
}else{
|
||||||
baseDuration + util.HelperFunctions.getRandomLongFromNormalDistribution(maxAdditionalDuration)
|
baseDuration + util.HelperFunctions.getGaussianLong(maxAdditionalDuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeUnit.MILLISECONDS.sleep(duration)
|
TimeUnit.MILLISECONDS.sleep(duration)
|
||||||
|
|||||||
@ -115,7 +115,6 @@ interface WindowsOSProxy : MousePointerObserver, OSProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum class DwmWindowAttribute {
|
enum class DwmWindowAttribute {
|
||||||
|
|
||||||
DWMWA_NCRENDERING_ENABLED,
|
DWMWA_NCRENDERING_ENABLED,
|
||||||
DWMWA_NCRENDERING_POLICY,
|
DWMWA_NCRENDERING_POLICY,
|
||||||
DWMWA_TRANSITIONS_FORCEDISABLED,
|
DWMWA_TRANSITIONS_FORCEDISABLED,
|
||||||
@ -320,18 +319,15 @@ interface WindowsOSProxy : MousePointerObserver, OSProxy {
|
|||||||
val hWnd = user32.GetForegroundWindow()
|
val hWnd = user32.GetForegroundWindow()
|
||||||
|
|
||||||
val rect = WinRect()
|
val rect = WinRect()
|
||||||
val success = user32.DwmGetWindowAttribute(
|
// val attr = user32.DwmGetWindowAttribute(
|
||||||
hWnd,
|
// hWnd,
|
||||||
8,
|
// 8,
|
||||||
rect.pointer,
|
// rect.pointer,
|
||||||
rect.size()
|
// rect.size()
|
||||||
)
|
// )
|
||||||
return if (true){
|
|
||||||
rect.read()
|
rect.read()
|
||||||
Rectangle(rect.top, rect.left, (rect.right - rect.left), rect.bottom - rect.top)
|
return Rectangle(rect.top, rect.left, (rect.right - rect.left), rect.bottom - rect.top)
|
||||||
}else{
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun barelyFunctionalWindowQuery(): Rectangle? {
|
fun barelyFunctionalWindowQuery(): Rectangle? {
|
||||||
|
|||||||
@ -42,21 +42,38 @@ object HelperFunctions {
|
|||||||
* @param upperBound The upper bound to sample from
|
* @param upperBound The upper bound to sample from
|
||||||
* @return A random long value following an approximate normal distribution
|
* @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
|
// anything lower to 2 will round down to zero, so return zero. Additionally, this guarantees a positive upper
|
||||||
//bound in one step
|
//bound in one step
|
||||||
if(upperBound <= 2L){
|
if (upperBound <= 2L) {
|
||||||
return 0L
|
return 0L
|
||||||
}
|
}
|
||||||
|
|
||||||
// To create more natural distribution Take two random samples from 0 to upperBound/2 and add them. This
|
// 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.
|
// approximates a normal distribution better than single random sample.
|
||||||
val subBound = upperBound/2L
|
val subBound = upperBound / 2L
|
||||||
val result1 = Random.nextLong(subBound)
|
val result1 = Random.nextLong(subBound)
|
||||||
val result2 = Random.nextLong(subBound)
|
val result2 = Random.nextLong(subBound)
|
||||||
return result1 + result2
|
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.
|
* Prints a progress report to console showing current step, total steps, elapsed time, and estimated remaining time.
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
package util
|
package util
|
||||||
|
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
import kotlin.test.*
|
import kotlin.system.measureNanoTime
|
||||||
|
import kotlin.system.measureTimeMillis
|
||||||
|
import kotlin.test.Test
|
||||||
|
|
||||||
|
|
||||||
class HelperFunctionsTest {
|
class HelperFunctionsTest {
|
||||||
@ -14,7 +16,7 @@ class HelperFunctionsTest {
|
|||||||
val numSamples = 10000
|
val numSamples = 10000
|
||||||
val upperBound = 1000L
|
val upperBound = 1000L
|
||||||
val samples = (1..numSamples).map {
|
val samples = (1..numSamples).map {
|
||||||
HelperFunctions.getRandomLongFromNormalDistribution(upperBound)
|
HelperFunctions.getGaussianLong(upperBound)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate mean and standard deviation
|
// Calculate mean and standard deviation
|
||||||
@ -26,4 +28,117 @@ class HelperFunctionsTest {
|
|||||||
assert(stdDev > upperBound * 0.2 && stdDev < upperBound * 0.3)
|
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