Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Enable GPU acceleration for new instances #1991

Merged
merged 2 commits into from
Jun 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import flank.corellium.client.core.getProjectInstancesList
import flank.corellium.client.core.startInstance
import flank.corellium.client.core.waitUntilInstanceIsReady
import flank.corellium.client.data.Instance
import flank.corellium.client.data.Instance.BootOptions.AdditionalTags.GPU
import kotlinx.coroutines.channels.SendChannel
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.channelFlow
Expand All @@ -20,23 +21,24 @@ private const val SCREEN = "720x1280:280"

fun invokeAndroidDevices(
projectName: String,
) = AndroidInstance.Invoke { (amount) ->
) = AndroidInstance.Invoke { config ->
channelFlow<String> {
val projectId = getProjectId(projectName)
val instances = getCreatedInstances(projectId, amount)
val instances = getCreatedInstances(projectId, config.amount)
startNotRunningInstances(instances)

val ids = instances.map(Instance::id) + let {
// When existing instances size match required amount
// there is not needs for creating more instances.
if (instances.size == amount) emptyList()
if (instances.size == config.amount) emptyList()
// Otherwise is required to create some additional instances
else createInstances(
projectId = projectId,
gpuAcceleration = config.gpuAcceleration,
indexes = calculateAdditionalIndexes(
current = instances,
requiredAmount = amount
)
requiredAmount = config.amount
),
)
}

Expand Down Expand Up @@ -87,7 +89,8 @@ private suspend fun startNotRunningInstances(
*/
private suspend fun createInstances(
projectId: String,
indexes: List<Int>
indexes: List<Int>,
gpuAcceleration: Boolean,
) = indexes
.apply { println("Creating additional ${indexes.size} instances. Connecting to the agents may take longer.") }
.map { index ->
Expand All @@ -98,7 +101,10 @@ private suspend fun createInstances(
flavor = FLAVOUR,
os = OS,
bootOptions = Instance.BootOptions(
screen = SCREEN
screen = SCREEN,
additionalTags = listOfNotNull(
GPU.takeIf { gpuAcceleration }
)
)
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,20 @@ object AndroidInstance {
/**
* Configuration for devices to invoke.
*
* @property amount the amount of devices to invoke.
* @property amount The amount of devices to invoke.
* @property gpuAcceleration Enables gpu acceleration for virtual devices.
*/
data class Config(
val amount: Int
val amount: Int,
val gpuAcceleration: Boolean
)

/**
* Invoke the android corellium devices.
*
* After successful invoke, the devices specified in th [Config] should be running and ready for use.
*
* @return list of invoked device ids.
* @return List of invoked device ids.
*/
fun interface Invoke : (Config) -> Flow<String>
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,17 @@ class RunTestCorelliumAndroidCommand :
]
)
var obfuscate: Boolean? by data

@set:CommandLine.Option(
names = ["--gpu-acceleration"],
description = [
"Enable cloud GPU acceleration (Extra costs incurred)." +
"Currently this option only works for newly devices created." +
"To create new device pool with gpu-acceleration, remove old devices manually and let Flank recreate the pool."
]
)
@set:JsonProperty("gpu-acceleration")
var gpuAcceleration: Boolean? by data
}

@CommandLine.Mixin
Expand Down Expand Up @@ -119,6 +130,7 @@ private fun defaultConfig() = Config().apply {
maxTestShards = 1
localResultsDir = null
obfuscate = false
gpuAcceleration = true
}

private fun RunTestCorelliumAndroidCommand.yamlConfig(): Config =
Expand All @@ -130,4 +142,5 @@ private fun RunTestCorelliumAndroidCommand.createArgs() = Args(
maxShardsCount = config.maxTestShards!!,
outputDir = config.localResultsDir ?: Args.DefaultOutputDir.new,
obfuscateDumpShards = config.obfuscate!!,
gpuAcceleration = config.gpuAcceleration!!
)
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class RunTestCorelliumAndroidCommandTest {
maxTestShards = Int.MAX_VALUE
localResultsDir = "test_result_dir"
obfuscate = true
gpuAcceleration = false
}

/**
Expand All @@ -57,6 +58,7 @@ class RunTestCorelliumAndroidCommandTest {
"--max-test-shards=$maxTestShards",
"--local-result-dir=$localResultsDir",
"--obfuscate=$obfuscate",
"--gpu-acceleration=$gpuAcceleration",
)
}

Expand All @@ -75,6 +77,7 @@ apks:
max-test-shards: $maxTestShards
local-result-dir: $localResultsDir
obfuscate: $obfuscate
gpu-acceleration: $gpuAcceleration
""".trimIndent()
}

Expand Down Expand Up @@ -136,7 +139,8 @@ obfuscate: $obfuscate
apks = apks!!,
maxShardsCount = maxTestShards!!,
outputDir = localResultsDir!!,
obfuscateDumpShards = obfuscate!!
obfuscateDumpShards = obfuscate!!,
gpuAcceleration = gpuAcceleration!!,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,29 @@ data class Instance(
val info: String = ""
)

/**
* @param udid Predefined Unique Device ID (UDID) for iOS device
* @param screen Change the screen metrics for Ranchu devices `XxY[:DPI]`, e.g. `720x1280:280`
* @param additionalTags features to utilize for the device, valid options include. Check [AdditionalTags]
*/
@Serializable
data class BootOptions(
val bootArgs: String = "",
val restoreBootArgs: String = "",
val udid: String = "",
val ecid: String = "",
val screen: String = ""
)
val screen: String = "",
val additionalTags: List<String> = emptyList(),
) {
/**
* @property GPU Enable cloud GPU acceleration (Extra costs incurred, cloud only).
* @property KALLOC Enable kalloc/kfree trace access via GDB (Enterprise only).
*/
object AdditionalTags {
const val GPU = "gpu"
const val KALLOC = "kalloc"
}
}
}

@Serializable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,15 @@ object RunTestCorelliumAndroid {
* @param maxShardsCount Maximum amount of shards to create. For each shard Flank is invoking dedicated device instance, so do not use values grater than maximum number available instances in the Corellium account.
* @param obfuscateDumpShards Obfuscate the test names in shards before dumping to file.
* @param outputDir Set output dir. Default value is [DefaultOutputDir.new]
* @param gpuAcceleration Enable gpu acceleration for newly created virtual devices.
*/
data class Args(
val credentials: Authorization.Credentials,
val apks: List<Apk.App>,
val maxShardsCount: Int,
val obfuscateDumpShards: Boolean = false,
val outputDir: String = DefaultOutputDir.new,
val gpuAcceleration: Boolean = true,
) {
/**
* Default output directory scheme.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,9 @@ import kotlinx.coroutines.flow.toList
*/
internal fun RunTestCorelliumAndroid.Context.invokeDevices() = RunTestCorelliumAndroid.step {
println("* Invoking devices")
copy(ids = api.invokeAndroidDevices(AndroidInstance.Config(shards.size)).toList())
val config = AndroidInstance.Config(
amount = shards.size,
gpuAcceleration = args.gpuAcceleration
)
copy(ids = api.invokeAndroidDevices(config).toList())
}