Skip to content

Commit fa9b570

Browse files
Calculating the average memory consumption of a single thread and coroutine
1 parent 5107c9a commit fa9b570

11 files changed

Lines changed: 109 additions & 155 deletions

File tree

app/src/main/java/com/techyourchance/android/backgroundtasksbenchmark/memory/BackgroundTasksMemoryResult.kt renamed to app/src/main/java/com/techyourchance/android/backgroundtasksbenchmark/memory/BackgroundTaskGroupsMemoryResult.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package com.techyourchance.android.backgroundtasksbenchmark.memory
22

3-
data class BackgroundTasksMemoryResult(
3+
data class BackgroundTaskGroupsMemoryResult(
44
val averageAppMemoryConsumption: Map<Int, BackgroundTaskMemoryData>,
5+
val averageLinearFitSlope: Float,
6+
val averageLinearFitIntercept: Float,
57
val tasksData: Map<Int, Map<Int, BackgroundTaskMemoryData>>,
68
) {
79
companion object {
8-
val NULL_OBJECT = BackgroundTasksMemoryResult(mapOf(), mapOf())
10+
val NULL_OBJECT = BackgroundTaskGroupsMemoryResult(mapOf(), 0f, 0f, mapOf())
911
}
1012
}
Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
package com.techyourchance.android.backgroundtasksbenchmark.memory
22

3-
import com.techyourchance.android.common.application.AppMemoryInfo
4-
53
data class BackgroundTaskMemoryData(
6-
val appMemoryInfo: AppMemoryInfo,
4+
val consumedMemory: Float,
75
) {
86
companion object {
9-
val NULL_OBJECT = BackgroundTaskMemoryData(AppMemoryInfo(0f, 0f))
7+
val NULL_OBJECT = BackgroundTaskMemoryData(0f)
108
}
119
}

app/src/main/java/com/techyourchance/android/backgroundtasksbenchmark/memory/BackgroundTasksMemoryBenchmarkUseCase.kt

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.techyourchance.android.backgroundtasksbenchmark.memory
22

3-
import com.techyourchance.android.common.application.AppMemoryInfo
43
import com.techyourchance.android.common.application.AppMemoryInfoProvider
54
import com.techyourchance.android.common.coroutines.BackgroundDispatcher.Background
65
import com.techyourchance.android.common.logs.MyLogger
@@ -38,9 +37,9 @@ class BackgroundTasksMemoryBenchmarkUseCase @Inject constructor(
3837
data class Result(
3938
val isCompleteResult: Boolean,
4039
val numTasksInGroup: Int,
41-
val threadsResult: BackgroundTasksMemoryResult,
42-
val coroutinesResult: BackgroundTasksMemoryResult,
43-
val threadPoolResult: BackgroundTasksMemoryResult,
40+
val threadsResult: BackgroundTaskGroupsMemoryResult,
41+
val coroutinesResult: BackgroundTaskGroupsMemoryResult,
42+
val threadPoolResult: BackgroundTaskGroupsMemoryResult,
4443
)
4544

4645
suspend fun runBenchmark(benchmarkPhase: BackgroundTasksMemoryBenchmarkPhase, benchmarkIterationNum: Int): Result {
@@ -79,9 +78,9 @@ class BackgroundTasksMemoryBenchmarkUseCase @Inject constructor(
7978
Result(
8079
false,
8180
0,
82-
BackgroundTasksMemoryResult.NULL_OBJECT,
83-
BackgroundTasksMemoryResult.NULL_OBJECT,
84-
BackgroundTasksMemoryResult.NULL_OBJECT,
81+
BackgroundTaskGroupsMemoryResult.NULL_OBJECT,
82+
BackgroundTaskGroupsMemoryResult.NULL_OBJECT,
83+
BackgroundTaskGroupsMemoryResult.NULL_OBJECT,
8584
)
8685
}
8786
}
@@ -129,8 +128,7 @@ class BackgroundTasksMemoryBenchmarkUseCase @Inject constructor(
129128
MyLogger.d("Thread started; iteration: $iterationNum; group $taskGroupNum; task $taskInGroup")
130129
groupThreadBarrier.await() // make sure all threads started
131130
if (taskInGroup == NUM_TASKS_IN_GROUP - 1) {
132-
val appMemoryConsumption = appMemoryInfoProvider.getAppMemoryConsumption()
133-
threadsData[taskGroupNum] = BackgroundTaskMemoryData(appMemoryConsumption)
131+
threadsData[taskGroupNum] = BackgroundTaskMemoryData(getAppMemoryConsumption())
134132
continuation.resume(Unit)
135133
}
136134
threadBarrier.await()
@@ -198,8 +196,7 @@ class BackgroundTasksMemoryBenchmarkUseCase @Inject constructor(
198196
}
199197
}
200198
if (taskInGroup == NUM_TASKS_IN_GROUP - 1) {
201-
val appMemoryConsumption = appMemoryInfoProvider.getAppMemoryConsumption()
202-
iterationData[taskGroupNum] = BackgroundTaskMemoryData(appMemoryConsumption)
199+
iterationData[taskGroupNum] = BackgroundTaskMemoryData(getAppMemoryConsumption())
203200
continuation.resume(Unit)
204201
}
205202
try {
@@ -257,8 +254,7 @@ class BackgroundTasksMemoryBenchmarkUseCase @Inject constructor(
257254
MyLogger.d("Thread pool started; iteration: $iterationNum; group $taskGroupNum; task $taskInGroup")
258255
groupThreadBarrier.await() // make sure all threads started
259256
if (taskInGroup == NUM_TASKS_IN_GROUP - 1) {
260-
val appMemoryConsumption = appMemoryInfoProvider.getAppMemoryConsumption()
261-
iterationData[taskGroupNum] = BackgroundTaskMemoryData(appMemoryConsumption)
257+
iterationData[taskGroupNum] = BackgroundTaskMemoryData(getAppMemoryConsumption())
262258
continuation.resume(Unit)
263259
}
264260
threadsBarrier.await()
@@ -268,6 +264,11 @@ class BackgroundTasksMemoryBenchmarkUseCase @Inject constructor(
268264
}
269265
}
270266

267+
private fun getAppMemoryConsumption(): Float {
268+
val appMemoryConsumption = appMemoryInfoProvider.getAppMemoryConsumption()
269+
return appMemoryConsumption.heapMemoryKb + appMemoryConsumption.nativeMemoryKb
270+
}
271+
271272
private fun restartAppForNextIteration(
272273
currentBenchmarkPhase: BackgroundTasksMemoryBenchmarkPhase,
273274
currentIterationNum: Int
@@ -310,9 +311,9 @@ class BackgroundTasksMemoryBenchmarkUseCase @Inject constructor(
310311
}
311312

312313
companion object {
313-
const val NUM_TASK_GROUPS = 100
314+
const val NUM_TASK_GROUPS = 50
314315
const val NUM_TASKS_IN_GROUP = 1
315-
const val NUM_ITERATIONS = 5
316+
const val NUM_ITERATIONS = 10
316317

317318
const val LABEL_THREADS = "threads"
318319
const val LABEL_COROUTINES = "coroutines"
Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.techyourchance.android.backgroundtasksbenchmark.memory
22

3-
import com.techyourchance.android.common.application.AppMemoryInfo
43
import com.techyourchance.android.database.entities.backgroundtasksmemory.BackgroundTasksMemoryDao
54
import java.util.concurrent.ConcurrentHashMap
65
import javax.inject.Inject
@@ -10,21 +9,22 @@ class FetchBackgroundTaskMemoryDataUseCase @Inject constructor(
109

1110
) {
1211

13-
suspend fun fetchData(label: String): BackgroundTasksMemoryResult {
12+
suspend fun fetchData(label: String): BackgroundTaskGroupsMemoryResult {
1413
val dbEntities = backgroundTasksMemoryDao.fetchAllWithLabel(label)
1514
val sortedDbEntities = dbEntities.sortedBy { it.iteration * 100 + it.tasksGroup }
1615
val tasksData = preAllocatedDataStructures()
1716
sortedDbEntities.forEach { dbEntity ->
1817
tasksData[dbEntity.iteration]!![dbEntity.tasksGroup] = BackgroundTaskMemoryData(
19-
AppMemoryInfo(
20-
dbEntity.memoryInfo.heapMemoryKb,
21-
dbEntity.memoryInfo.nativeMemoryKb
22-
)
18+
dbEntity.memoryInfo.consumedMemory
2319
)
2420
}
25-
return BackgroundTasksMemoryResult(
26-
computeAverage(tasksData),
27-
tasksData
21+
val averagedTasksData = computeAverage(tasksData)
22+
val (averageLinearFitSlope, averageLinearFitIntercept) = computeLinearFitCoefficients(averagedTasksData)
23+
return BackgroundTaskGroupsMemoryResult(
24+
averagedTasksData,
25+
averageLinearFitSlope,
26+
averageLinearFitIntercept,
27+
tasksData,
2828
)
2929
}
3030

@@ -43,26 +43,40 @@ class FetchBackgroundTaskMemoryDataUseCase @Inject constructor(
4343
}
4444

4545
private fun computeAverage(tasksData: MutableMap<Int, MutableMap<Int, BackgroundTaskMemoryData>>): Map<Int, BackgroundTaskMemoryData> {
46+
val numTaskGroups = tasksData[0]!!.size
4647
val averageTasksMemoryConsumptions = ConcurrentHashMap<Int, BackgroundTaskMemoryData>(
47-
BackgroundTasksMemoryBenchmarkUseCase.NUM_TASK_GROUPS
48+
numTaskGroups
4849
)
49-
for (taskNum in 0 until BackgroundTasksMemoryBenchmarkUseCase.NUM_TASK_GROUPS) {
50-
var sumTaskHeapMemoryConsumption = 0f
51-
var sumTaskNativeMemoryConsumption = 0f
52-
for (iterationNum in 0 until BackgroundTasksMemoryBenchmarkUseCase.NUM_ITERATIONS) {
53-
sumTaskHeapMemoryConsumption += tasksData[iterationNum]!![taskNum]!!.appMemoryInfo.heapMemoryKb
54-
sumTaskNativeMemoryConsumption += tasksData[iterationNum]!![taskNum]!!.appMemoryInfo.nativeMemoryKb
50+
for (taskNum in 0 until numTaskGroups) {
51+
var sumTaskMemoryConsumption = 0f
52+
for (iterationNum in 0 until tasksData.size) {
53+
sumTaskMemoryConsumption += tasksData[iterationNum]!![taskNum]!!.consumedMemory
5554
}
56-
val averageHeapTaskMemoryConsumption = sumTaskHeapMemoryConsumption / BackgroundTasksMemoryBenchmarkUseCase.NUM_TASK_GROUPS
57-
val averageNativeTaskMemoryConsumption = sumTaskNativeMemoryConsumption / BackgroundTasksMemoryBenchmarkUseCase.NUM_TASK_GROUPS
58-
averageTasksMemoryConsumptions[taskNum] = BackgroundTaskMemoryData(
59-
AppMemoryInfo(
60-
averageHeapTaskMemoryConsumption,
61-
averageNativeTaskMemoryConsumption
62-
)
63-
)
55+
val averageTaskMemoryConsumption = sumTaskMemoryConsumption / numTaskGroups
56+
averageTasksMemoryConsumptions[taskNum] = BackgroundTaskMemoryData(averageTaskMemoryConsumption)
6457
}
6558
return averageTasksMemoryConsumptions
6659
}
6760

61+
private fun computeLinearFitCoefficients(tasksData: Map<Int, BackgroundTaskMemoryData>): Pair<Float, Float> {
62+
val n = tasksData.size
63+
var sumX = 0f
64+
var sumY = 0f
65+
var sumXY = 0f
66+
var sumXX = 0f
67+
68+
for (i in 0 until n) {
69+
sumX += i
70+
sumY += tasksData[i]!!.consumedMemory
71+
sumXY += i * tasksData[i]!!.consumedMemory
72+
sumXX += i * i
73+
}
74+
75+
val slope = (n * sumXY - sumX * sumY) / (n * sumXX - sumX * sumX)
76+
val intercept = (sumY - slope * sumX) / n
77+
78+
return Pair(slope, intercept)
79+
}
80+
81+
6882
}

app/src/main/java/com/techyourchance/android/backgroundtasksbenchmark/memory/SaveBackgroundTaskMemoryDataUseCase.kt

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,14 @@ class SaveBackgroundTaskMemoryDataUseCase @Inject constructor(
1212

1313
suspend fun saveData(label: String, iteration: Int, data: MutableMap<Int, BackgroundTaskMemoryData>) {
1414
for (tasksGroup in data.keys) {
15-
val appMemoryInfo = data.values.toList()[tasksGroup].appMemoryInfo
15+
val consumedMemory = data.values.toList()[tasksGroup].consumedMemory
1616
backgroundTasksMemoryDao.upsert(
1717
BackgroundTasksMemoryDb(
1818
0,
1919
label,
2020
iteration,
2121
tasksGroup,
22-
AppMemoryInfoDb(
23-
0,
24-
appMemoryInfo.heapMemoryKb,
25-
appMemoryInfo.nativeMemoryKb,
26-
)
22+
AppMemoryInfoDb(0, consumedMemory)
2723
)
2824
)
2925
}

app/src/main/java/com/techyourchance/android/screens/backgroundtasksmemorybenchmark/BackgroundTasksMemoryBenchmarkViewMvc.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.techyourchance.android.screens.backgroundtasksmemorybenchmark
22

3-
import com.techyourchance.android.backgroundtasksbenchmark.memory.BackgroundTasksMemoryResult
3+
import com.techyourchance.android.backgroundtasksbenchmark.memory.BackgroundTaskGroupsMemoryResult
44
import com.techyourchance.android.screens.common.mvcviews.BaseObservableViewMvc
55

66
abstract class BackgroundTasksMemoryBenchmarkViewMvc: BaseObservableViewMvc<BackgroundTasksMemoryBenchmarkViewMvc.Listener>() {
@@ -12,9 +12,9 @@ abstract class BackgroundTasksMemoryBenchmarkViewMvc: BaseObservableViewMvc<Back
1212

1313
abstract fun bindBenchmarkResults(
1414
numTasksInGroup: Int,
15-
threadsResult: BackgroundTasksMemoryResult,
16-
coroutinesResult: BackgroundTasksMemoryResult,
17-
threadPoolResult: BackgroundTasksMemoryResult,
15+
threadsResult: BackgroundTaskGroupsMemoryResult,
16+
coroutinesResult: BackgroundTaskGroupsMemoryResult,
17+
threadPoolResult: BackgroundTaskGroupsMemoryResult,
1818
)
1919
abstract fun showBenchmarkStarted()
2020
abstract fun showBenchmarkStopped()

app/src/main/java/com/techyourchance/android/screens/backgroundtasksmemorybenchmark/BackgroundTasksMemoryBenchmarkViewMvcImpl.kt

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@ package com.techyourchance.android.screens.backgroundtasksmemorybenchmark
22

33
import android.view.LayoutInflater
44
import android.view.ViewGroup
5+
import android.widget.TextView
56
import com.github.mikephil.charting.charts.ScatterChart
67
import com.github.mikephil.charting.components.Legend
78
import com.github.mikephil.charting.components.XAxis
89
import com.github.mikephil.charting.data.Entry
910
import com.github.mikephil.charting.data.ScatterData
1011
import com.github.mikephil.charting.data.ScatterDataSet
1112
import com.techyourchance.android.R
12-
import com.techyourchance.android.backgroundtasksbenchmark.memory.BackgroundTasksMemoryResult
13+
import com.techyourchance.android.backgroundtasksbenchmark.memory.BackgroundTaskGroupsMemoryResult
1314
import com.techyourchance.android.screens.common.toolbar.MyToolbar
1415
import com.techyourchance.android.screens.common.widgets.MyButton
1516

@@ -22,13 +23,15 @@ class BackgroundTasksMemoryBenchmarkViewMvcImpl(
2223
private val toolbar: MyToolbar
2324
private val btnToggleBenchmark: MyButton
2425
private val scatterChart: ScatterChart
26+
private val txtTaskMemoryConsumption: TextView
2527

2628
init {
2729
setRootView(layoutInflater.inflate(R.layout.layout_background_tasks_memory_benchmark, parent, false))
2830

2931
toolbar = findViewById(R.id.toolbar)
3032
btnToggleBenchmark = findViewById(R.id.btnToggleBenchmark)
3133
scatterChart = findViewById(R.id.scatterChart)
34+
txtTaskMemoryConsumption = findViewById(R.id.txtTaskMemoryConsumption)
3235

3336
scatterChart.axisRight.isEnabled = false
3437
scatterChart.axisLeft.axisMinimum = 0f
@@ -55,10 +58,25 @@ class BackgroundTasksMemoryBenchmarkViewMvcImpl(
5558

5659
override fun bindBenchmarkResults(
5760
numTasksInGroup: Int,
58-
threadsResult: BackgroundTasksMemoryResult,
59-
coroutinesResult: BackgroundTasksMemoryResult,
60-
threadPoolResult: BackgroundTasksMemoryResult,
61+
threadsResult: BackgroundTaskGroupsMemoryResult,
62+
coroutinesResult: BackgroundTaskGroupsMemoryResult,
63+
threadPoolResult: BackgroundTaskGroupsMemoryResult,
6164
) {
65+
val threadsString = getString(
66+
R.string.background_tasks_memory_benchmark_thread_memory,
67+
threadsResult.averageLinearFitSlope / numTasksInGroup
68+
)
69+
val coroutinesString = getString(
70+
R.string.background_tasks_memory_benchmark_coroutine_memory,
71+
coroutinesResult.averageLinearFitSlope / numTasksInGroup
72+
)
73+
val threadPoolString = getString(
74+
R.string.background_tasks_memory_benchmark_thread_in_thread_pool_memory,
75+
threadPoolResult.averageLinearFitSlope / numTasksInGroup
76+
)
77+
78+
txtTaskMemoryConsumption.text = "$threadsString\n$coroutinesString\n$threadPoolString"
79+
6280
val threadsDataSet = toScatterChartDataSet(
6381
numTasksInGroup,
6482
threadsResult,
@@ -90,22 +108,23 @@ class BackgroundTasksMemoryBenchmarkViewMvcImpl(
90108

91109
private fun toScatterChartDataSet(
92110
numTasksInGroup: Int,
93-
result: BackgroundTasksMemoryResult,
111+
result: BackgroundTaskGroupsMemoryResult,
94112
dataSetName: String,
95113
color: Int,
96114
): ScatterDataSet {
97115
val resultEntries = result.averageAppMemoryConsumption.entries.sortedBy { it.key }
98116
val chartEntries = resultEntries.map {
99117
Entry(
100118
it.key.toFloat() * numTasksInGroup, // each key represents group index, which can contain multiple threads
101-
it.value.appMemoryInfo.nativeMemoryKb + it.value.appMemoryInfo.heapMemoryKb,
119+
it.value.consumedMemory,
102120
)
103121
}
104122
val dataSet = ScatterDataSet(chartEntries, dataSetName)
105123
dataSet.setScatterShape(ScatterChart.ScatterShape.CIRCLE)
106124
dataSet.color = color
107125
dataSet.scatterShapeSize = 10f
108126
dataSet.setDrawValues(false)
127+
109128
return dataSet
110129
}
111130

app/src/main/res/layout/layout_background_tasks_memory_benchmark.xml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,22 @@
3131
android:layout_width="match_parent"
3232
android:layout_height="0dp"
3333
app:layout_constraintTop_toBottomOf="@id/btnToggleBenchmark"
34-
app:layout_constraintBottom_toBottomOf="parent"
34+
app:layout_constraintBottom_toTopOf="@id/txtTaskMemoryConsumption"
3535
android:layout_marginTop="50dp"
36-
android:layout_marginBottom="50dp"
3736
android:layout_marginHorizontal="20dp"
3837
/>
3938

39+
<TextView
40+
android:id="@+id/txtTaskMemoryConsumption"
41+
android:layout_width="match_parent"
42+
android:layout_height="wrap_content"
43+
app:layout_constraintTop_toBottomOf="@id/scatterChart"
44+
app:layout_constraintBottom_toBottomOf="parent"
45+
android:layout_marginTop="20dp"
46+
android:layout_marginBottom="40dp"
47+
android:layout_marginHorizontal="20dp"
48+
android:lines="3"
49+
android:gravity="start"
50+
/>
51+
4052
</androidx.constraintlayout.widget.ConstraintLayout>

app/src/main/res/values/strings.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,5 +74,8 @@
7474
<string name="background_tasks_memory_benchmark_threads_chart_label">Threads memory consumption [kB]</string>
7575
<string name="background_tasks_memory_benchmark_coroutines_chart_label">Coroutines memory consumption [kB]</string>
7676
<string name="background_tasks_memory_benchmark_thread_pool_chart_label">Thread pool memory consumption [kB]</string>
77+
<string name="background_tasks_memory_benchmark_thread_memory">Single thread: %1$.2f kB</string>
78+
<string name="background_tasks_memory_benchmark_coroutine_memory">Single coroutine: %1$.2f kB</string>
79+
<string name="background_tasks_memory_benchmark_thread_in_thread_pool_memory">Single thread in thread pool: %1$.2f kB</string>
7780

7881
</resources>

0 commit comments

Comments
 (0)