-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
170 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,57 @@ | ||
package stack | ||
|
||
import stack.elimination.ConcurrentStackWithElimination | ||
import kotlin.random.Random | ||
import org.apache.commons.math3.geometry.euclidean.oned.Interval | ||
import stack.benchmark.MeasureScenario | ||
import stack.benchmark.Operation | ||
import stack.benchmark.StackBenchmark | ||
import stack.simple.ConcurrentTreiberStack | ||
|
||
fun main() { | ||
val st = ConcurrentStackWithElimination<Int>() | ||
val random = Random(System.nanoTime()) | ||
|
||
val threads = List(2) { | ||
Thread { | ||
repeat(100000000) { | ||
val r = random.nextInt(3) | ||
when (r) { | ||
0 -> st.push(random.nextInt(10)) | ||
1 -> st.pop() | ||
2 -> st.top() | ||
} | ||
private val Int.pretty: String | ||
get() { | ||
var zeroCount = 0 | ||
var curNum = this | ||
while (curNum % 10 == 0) { | ||
zeroCount++ | ||
curNum /= 10 | ||
} | ||
if (zeroCount <= 3) { | ||
return this.toString() | ||
} else { | ||
var afterComma = "" | ||
while (curNum > 9) { | ||
afterComma += (curNum % 10) | ||
} | ||
return curNum.toString() + afterComma.reversed() + "0".repeat(zeroCount) | ||
} | ||
|
||
} | ||
|
||
fun main() { | ||
// prepare cases | ||
val threadNums = listOf(1, 2, 4, 6) | ||
val operations = buildList { | ||
for (i in 1e7.toInt()..1e8.toInt() step 1e7.toInt()) { | ||
add(i) | ||
} | ||
} | ||
// calculating | ||
val stackBenchmark = StackBenchmark<Int>() | ||
val results = mutableListOf(mutableListOf<Interval>()) | ||
for (threadNum in threadNums) { | ||
val currentResult = mutableListOf<Interval>() | ||
for (opCount in operations) { | ||
val singleThreadRandomMeasureScenario = MeasureScenario( | ||
threadNum, opCount / threadNum, | ||
ConcurrentTreiberStack(), | ||
Operation.Push(0), | ||
MeasureScenario.randomScenarioIntGenerator | ||
) | ||
// stackBenchmark.loadScenario(singleThreadRandomMeasureScenario) | ||
// val workTime = stackBenchmark.startAndMeasure(20) ?: throw IllegalStateException() | ||
// currentResult.add(workTime) | ||
println("Threads: $threadNum | Operations: $opCount | DONE") | ||
} | ||
results.add(currentResult) | ||
} | ||
val initTime = System.currentTimeMillis() | ||
threads.forEach { it.start() } | ||
threads.forEach { it.join() } | ||
println(System.currentTimeMillis() - initTime) | ||
TODO("print results") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package stack.benchmark | ||
|
||
import stack.common.ConcurrentStack | ||
import kotlin.random.Random | ||
|
||
class MeasureScenario<T>( | ||
val threadsNum: Int, | ||
val operationsPerThread: Int, | ||
val initialStack: ConcurrentStack<T>, | ||
val firstOperation: Operation<T>, | ||
val operationGenerator: (Operation<T>) -> Operation<T> | ||
) { | ||
companion object { | ||
val randomScenarioIntGenerator: (Operation<Int>) -> Operation<Int> = { _ -> | ||
when (Random.nextInt(3)) { | ||
0 -> Operation.Push(Random.nextInt()) | ||
1 -> Operation.Pop() | ||
2 -> Operation.Top() | ||
else -> throw IllegalStateException() | ||
} | ||
} | ||
val pushPopIntGenerator: (Operation<Int>) -> Operation<Int> = { last -> | ||
when (last) { | ||
is Operation.Push -> Operation.Pop() | ||
is Operation.Pop -> Operation.Push(Random.nextInt()) | ||
is Operation.Top -> Operation.Push(Random.nextInt()) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package stack.benchmark | ||
|
||
import stack.common.ConcurrentStack | ||
|
||
sealed interface Operation<T> { | ||
class Push<T>(val value: T) : Operation<T> | ||
class Pop<T> : Operation<T> | ||
class Top<T> : Operation<T> | ||
|
||
fun toStackOperation(): ConcurrentStack<T>.() -> Unit = when (this) { | ||
is Push<T> -> fun ConcurrentStack<T>.() = (::push)(value) | ||
is Pop<T> -> fun ConcurrentStack<T>.() { (::pop)() } | ||
is Top<T> -> fun ConcurrentStack<T>.() { (::top)() } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package stack.benchmark | ||
|
||
import org.apache.commons.math3.distribution.TDistribution | ||
import org.apache.commons.math3.geometry.euclidean.oned.Interval | ||
import org.apache.commons.math3.stat.descriptive.SummaryStatistics | ||
import kotlin.concurrent.thread | ||
import kotlin.math.sqrt | ||
import kotlin.time.Duration.Companion.milliseconds | ||
import kotlin.time.DurationUnit | ||
|
||
|
||
class StackBenchmark<T> { | ||
private val threads: MutableList<Thread> = mutableListOf() | ||
|
||
private fun clearScenario() { | ||
threads.clear() | ||
} | ||
|
||
/** | ||
* Load the scenario. If scenario was already loaded, overrides it | ||
*/ | ||
fun loadScenario(measureScenario: MeasureScenario<T>) { | ||
clearScenario() | ||
|
||
val operations = buildList(measureScenario.operationsPerThread) { | ||
add(measureScenario.firstOperation) | ||
repeat(measureScenario.operationsPerThread - 1) { | ||
add(measureScenario.operationGenerator(this.last())) | ||
} | ||
}.map { it.toStackOperation() } | ||
|
||
repeat(measureScenario.threadsNum) { | ||
threads.add(thread(false) { | ||
operations.forEach { it.invoke(measureScenario.initialStack) } | ||
}) | ||
} | ||
} | ||
|
||
/** | ||
* Execute loaded scenario [n] times and returns work time in milliseconds. Returns null if scenario was not loaded | ||
*/ | ||
fun startAndMeasure(n: Int): Interval? { | ||
if (threads.isEmpty()) return null | ||
|
||
val results = buildList(n) { | ||
val initialTime = System.currentTimeMillis() | ||
threads.forEach { it.start() } | ||
threads.forEach { it.join() } | ||
val workTimeMills = (System.currentTimeMillis() - initialTime) | ||
add(workTimeMills.milliseconds.toDouble(DurationUnit.SECONDS)) | ||
} | ||
|
||
return calculateConfidenceInterval(results) | ||
} | ||
|
||
/** Implemented using [source](https://gist.github.com/gcardone/5536578) */ | ||
private fun calculateConfidenceInterval(results: List<Double>): Interval { | ||
val stats = SummaryStatistics().apply { | ||
results.forEach { this.addValue(it) } | ||
} | ||
val tDist = TDistribution(stats.n.toDouble()) | ||
val crVal = tDist.inverseCumulativeProbability(0.975) | ||
val ci = crVal * stats.getStandardDeviation() / sqrt(stats.n.toDouble()) | ||
return Interval(stats.mean - ci, stats.mean + ci) | ||
} | ||
|
||
fun printLoadedScenario() { | ||
threads.forEach { | ||
println(it.toString()) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters