@@ -20,7 +20,6 @@ import java.util.concurrent.CyclicBarrier
2020import java.util.concurrent.SynchronousQueue
2121import java.util.concurrent.ThreadPoolExecutor
2222import java.util.concurrent.TimeUnit
23- import java.util.concurrent.atomic.AtomicInteger
2423import javax.inject.Inject
2524import kotlin.coroutines.coroutineContext
2625import kotlin.coroutines.resume
@@ -36,10 +35,9 @@ class BackgroundTasksMemoryBenchmarkUseCase @Inject constructor(
3635
3736 data class Result (
3837 val isCompleteResult : Boolean ,
39- val numTasksInGroup : Int ,
40- val threadsResult : BackgroundTaskGroupsMemoryResult ,
41- val coroutinesResult : BackgroundTaskGroupsMemoryResult ,
42- val threadPoolResult : BackgroundTaskGroupsMemoryResult ,
38+ val threadsResult : BackgroundTasksMemoryResult ,
39+ val coroutinesResult : BackgroundTasksMemoryResult ,
40+ val threadPoolResult : BackgroundTasksMemoryResult ,
4341 )
4442
4543 suspend fun runBenchmark (benchmarkPhase : BackgroundTasksMemoryBenchmarkPhase , benchmarkIterationNum : Int ): Result {
@@ -69,26 +67,24 @@ class BackgroundTasksMemoryBenchmarkUseCase @Inject constructor(
6967 return @withContext if (isBenchmarkCompleted) {
7068 Result (
7169 true ,
72- NUM_TASKS_IN_GROUP ,
7370 fetchBackgroundTaskMemoryDataUseCase.fetchData(LABEL_THREADS ),
7471 fetchBackgroundTaskMemoryDataUseCase.fetchData(LABEL_COROUTINES ),
7572 fetchBackgroundTaskMemoryDataUseCase.fetchData(LABEL_THREAD_POOL ),
7673 )
7774 } else {
7875 Result (
7976 false ,
80- 0 ,
81- BackgroundTaskGroupsMemoryResult .NULL_OBJECT ,
82- BackgroundTaskGroupsMemoryResult .NULL_OBJECT ,
83- BackgroundTaskGroupsMemoryResult .NULL_OBJECT ,
77+ BackgroundTasksMemoryResult .NULL_OBJECT ,
78+ BackgroundTasksMemoryResult .NULL_OBJECT ,
79+ BackgroundTasksMemoryResult .NULL_OBJECT ,
8480 )
8581 }
8682 }
8783 }
8884
8985 private fun preAllocateIterationData (): ConcurrentHashMap <Int , BackgroundTaskMemoryData > {
90- val iterationData = ConcurrentHashMap <Int , BackgroundTaskMemoryData >(NUM_TASK_GROUPS )
91- for (taskNum in 0 until NUM_TASK_GROUPS ) {
86+ val iterationData = ConcurrentHashMap <Int , BackgroundTaskMemoryData >(NUM_TASKS )
87+ for (taskNum in 0 until NUM_TASKS ) {
9288 iterationData[taskNum] = BackgroundTaskMemoryData .NULL_OBJECT
9389 }
9490 return iterationData
@@ -100,46 +96,37 @@ class BackgroundTasksMemoryBenchmarkUseCase @Inject constructor(
10096 ): Boolean {
10197 MyLogger .i(" benchmarkThreads(); iteration: $iterationNum " )
10298 val startedThreads = mutableListOf<Thread >()
103- val threadBarrier = CyclicBarrier (NUM_TASK_GROUPS * NUM_TASKS_IN_GROUP + 1 )
104- for (taskGroupNum in 0 until NUM_TASK_GROUPS ) {
99+ val threadBarrier = CyclicBarrier (NUM_TASKS + 1 )
100+ for (taskNum in 0 until NUM_TASKS ) {
105101 coroutineContext.ensureActive()
106- val groupStartedThreads = benchmarkSingleThreadsGroup (
107- iterationNum, taskGroupNum , iterationData, threadBarrier
102+ val thread = benchmarkSingleThread (
103+ iterationNum, taskNum , iterationData, threadBarrier
108104 )
109- startedThreads.addAll(groupStartedThreads )
105+ startedThreads.add(thread )
110106 }
111107 threadBarrier.await()
112108 startedThreads.forEach { it.join() }
113109 saveBackgroundTaskMemoryDataUseCase.saveData(LABEL_THREADS , iterationNum, iterationData)
114110 return ! restartAppForNextIteration(BackgroundTasksMemoryBenchmarkPhase .THREADS , iterationNum)
115111 }
116112
117- private suspend fun benchmarkSingleThreadsGroup (
113+ private suspend fun benchmarkSingleThread (
118114 iterationNum : Int ,
119- taskGroupNum : Int ,
115+ taskNum : Int ,
120116 threadsData : MutableMap <Int , BackgroundTaskMemoryData >,
121117 threadBarrier : CyclicBarrier
122- ): List <Thread > {
123- val groupThreads = mutableListOf<Thread >()
124- suspendCoroutine { continuation ->
125- val groupThreadBarrier = CyclicBarrier (NUM_TASKS_IN_GROUP )
126- for (taskInGroup in 0 until NUM_TASKS_IN_GROUP ) {
127- Thread {
128- MyLogger .d(" Thread started; iteration: $iterationNum ; group $taskGroupNum ; task $taskInGroup " )
129- groupThreadBarrier.await() // make sure all threads started
130- if (taskInGroup == NUM_TASKS_IN_GROUP - 1 ) {
131- threadsData[taskGroupNum] = BackgroundTaskMemoryData (getAppMemoryConsumption())
132- continuation.resume(Unit )
133- }
134- threadBarrier.await()
135- MyLogger .d(" Thread terminates; iteration: $iterationNum ; group $taskGroupNum ; task $taskInGroup " )
136- }.apply {
137- start()
138- groupThreads.add(this )
139- }
118+ ): Thread {
119+ return suspendCoroutine { continuation ->
120+ val thread = Thread {
121+ MyLogger .d(" Thread started; iteration: $iterationNum ; task $taskNum " )
122+ threadsData[taskNum] = BackgroundTaskMemoryData (getAppMemoryConsumption())
123+ continuation.resume(Thread .currentThread())
124+ threadBarrier.await()
125+ MyLogger .d(" Thread terminates; iteration: $iterationNum ; task $taskNum " )
126+ }.apply {
127+ start()
140128 }
141129 }
142- return groupThreads
143130 }
144131
145132 private suspend fun benchmarkCoroutines (
@@ -156,10 +143,10 @@ class BackgroundTasksMemoryBenchmarkUseCase @Inject constructor(
156143
157144 MyLogger .i(" benchmarkCoroutines(); iteration: $iterationNum " )
158145 val awaitFlow = MutableSharedFlow <Unit >()
159- for (taskGroupNum in 0 until NUM_TASK_GROUPS ) {
146+ for (taskNum in 0 until NUM_TASKS ) {
160147 coroutineContext.ensureActive()
161- benchmarkSingleCoroutineGroup (
162- iterationNum, taskGroupNum , iterationData, awaitFlow, coroutinesScope
148+ benchmarkSingleCoroutine (
149+ iterationNum, taskNum , iterationData, awaitFlow, coroutinesScope
163150 )
164151 }
165152 awaitFlow.emit(Unit )
@@ -171,43 +158,26 @@ class BackgroundTasksMemoryBenchmarkUseCase @Inject constructor(
171158 return ! restartAppForNextIteration(BackgroundTasksMemoryBenchmarkPhase .COROUTINES , iterationNum)
172159 }
173160
174- private suspend fun benchmarkSingleCoroutineGroup (
161+ private suspend fun benchmarkSingleCoroutine (
175162 iterationNum : Int ,
176- taskGroupNum : Int ,
163+ taskNum : Int ,
177164 iterationData : MutableMap <Int , BackgroundTaskMemoryData >,
178165 awaitFlow : MutableSharedFlow <Unit >,
179166 coroutinesScope : CoroutineScope ,
180167 ) {
181168 suspendCoroutine { continuation ->
182- val groupLaunchedCounter = AtomicInteger (0 )
183- val groupAwaitFlow = MutableSharedFlow <Unit >()
184- for (taskInGroup in 0 until NUM_TASKS_IN_GROUP ) {
185- coroutinesScope.launch {
186- MyLogger .d(" Coroutine launched; iteration: $iterationNum ; group $taskGroupNum ; task $taskInGroup " )
187- if (groupLaunchedCounter.incrementAndGet() == NUM_TASKS_IN_GROUP ) {
188- groupAwaitFlow.emit(Unit )
189- } else {
190- try {
191- groupAwaitFlow.collect {
192- throw CancellationException ()
193- }
194- } catch (e: CancellationException ) {
195- // no-op
196- }
197- }
198- if (taskInGroup == NUM_TASKS_IN_GROUP - 1 ) {
199- iterationData[taskGroupNum] = BackgroundTaskMemoryData (getAppMemoryConsumption())
200- continuation.resume(Unit )
169+ coroutinesScope.launch {
170+ MyLogger .d(" Coroutine launched; iteration: $iterationNum ; task $taskNum " )
171+ iterationData[taskNum] = BackgroundTaskMemoryData (getAppMemoryConsumption())
172+ continuation.resume(Unit )
173+ try {
174+ awaitFlow.collect {
175+ throw CancellationException ()
201176 }
202- try {
203- awaitFlow.collect {
204- throw CancellationException ()
205- }
206- } catch (e: CancellationException ) {
207- // no-op
208- }
209- MyLogger .d(" Coroutine terminates; iteration: $iterationNum ; group $taskGroupNum ; task $taskInGroup " )
177+ } catch (e: CancellationException ) {
178+ // no-op
210179 }
180+ MyLogger .d(" Coroutine terminates; iteration: $iterationNum ; task $taskNum " )
211181 }
212182 }
213183 }
@@ -224,10 +194,10 @@ class BackgroundTasksMemoryBenchmarkUseCase @Inject constructor(
224194 )
225195
226196 MyLogger .i(" benchmarkThreadPool(); iteration: $iterationNum " )
227- val threadsBarrier = CyclicBarrier (NUM_TASK_GROUPS * NUM_TASKS_IN_GROUP + 1 )
228- for (taskGroupNum in 0 until NUM_TASK_GROUPS ) {
197+ val threadsBarrier = CyclicBarrier (NUM_TASKS + 1 )
198+ for (taskNum in 0 until NUM_TASKS ) {
229199 coroutineContext.ensureActive()
230- benchmarkSingleThreadPoolGroup (iterationNum, taskGroupNum , iterationData, threadPool, threadsBarrier)
200+ benchmarkSingleThreadPoolThread (iterationNum, taskNum , iterationData, threadPool, threadsBarrier)
231201 }
232202 threadsBarrier.await()
233203
@@ -240,26 +210,20 @@ class BackgroundTasksMemoryBenchmarkUseCase @Inject constructor(
240210 return ! restartAppForNextIteration(BackgroundTasksMemoryBenchmarkPhase .THREAD_POOL , iterationNum)
241211 }
242212
243- private suspend fun benchmarkSingleThreadPoolGroup (
213+ private suspend fun benchmarkSingleThreadPoolThread (
244214 iterationNum : Int ,
245- taskGroupNum : Int ,
215+ taskNum : Int ,
246216 iterationData : MutableMap <Int , BackgroundTaskMemoryData >,
247217 threadPool : ThreadPoolExecutor ,
248218 threadsBarrier : CyclicBarrier
249219 ) {
250220 suspendCoroutine { continuation ->
251- val groupThreadBarrier = CyclicBarrier (NUM_TASKS_IN_GROUP )
252- for (taskInGroup in 0 until NUM_TASKS_IN_GROUP ) {
253- threadPool.execute {
254- MyLogger .d(" Thread pool started; iteration: $iterationNum ; group $taskGroupNum ; task $taskInGroup " )
255- groupThreadBarrier.await() // make sure all threads started
256- if (taskInGroup == NUM_TASKS_IN_GROUP - 1 ) {
257- iterationData[taskGroupNum] = BackgroundTaskMemoryData (getAppMemoryConsumption())
258- continuation.resume(Unit )
259- }
260- threadsBarrier.await()
261- MyLogger .d(" Thread pool terminates; iteration: $iterationNum ; group $taskGroupNum ; task $taskInGroup " )
262- }
221+ threadPool.execute {
222+ MyLogger .d(" Thread pool started; iteration: $iterationNum ; task $taskNum " )
223+ iterationData[taskNum] = BackgroundTaskMemoryData (getAppMemoryConsumption())
224+ continuation.resume(Unit )
225+ threadsBarrier.await()
226+ MyLogger .d(" Thread pool terminates; iteration: $iterationNum ; task $taskNum " )
263227 }
264228 }
265229 }
@@ -311,9 +275,8 @@ class BackgroundTasksMemoryBenchmarkUseCase @Inject constructor(
311275 }
312276
313277 companion object {
314- const val NUM_TASK_GROUPS = 50
315- const val NUM_TASKS_IN_GROUP = 1
316- const val NUM_ITERATIONS = 10
278+ const val NUM_TASKS = 100
279+ const val NUM_ITERATIONS = 3
317280
318281 const val LABEL_THREADS = " threads"
319282 const val LABEL_COROUTINES = " coroutines"
0 commit comments