Skip to content
This repository was archived by the owner on Sep 10, 2025. It is now read-only.
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
2 changes: 1 addition & 1 deletion torchchat/edge/android/torchchat/app/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1 @@
/build
/build
116 changes: 84 additions & 32 deletions torchchat/edge/android/torchchat/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,45 +1,97 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

plugins {
id("com.android.application")
id("com.android.application")
id("org.jetbrains.kotlin.android")
}

android {
namespace = "org.pytorch.torchchat"
compileSdk = 33
namespace = "org.pytorch.torchchat"
compileSdk = 34

defaultConfig {
applicationId = "org.pytorch.torchchat"
minSdk = 24
targetSdk = 33
versionCode = 1
versionName = "1.0"
defaultConfig {
applicationId = "org.pytorch.torchchat"
minSdk = 28
targetSdk = 33
versionCode = 1
versionName = "1.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables { useSupportLibrary = true }
externalNativeBuild { cmake { cppFlags += "" } }
}

buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions { jvmTarget = "1.8" }
buildFeatures { compose = true }
composeOptions { kotlinCompilerExtensionVersion = "1.4.3" }
packaging { resources { excludes += "/META-INF/{AL2.0,LGPL2.1}" } }
}

dependencies {
implementation("androidx.core:core-ktx:1.9.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1")
implementation("androidx.activity:activity-compose:1.7.0")
implementation(platform("androidx.compose:compose-bom:2023.03.00"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.camera:camera-core:1.3.0-rc02")
implementation("androidx.constraintlayout:constraintlayout:2.2.0-alpha12")
implementation("com.facebook.fbjni:fbjni:0.5.1")
implementation("com.google.code.gson:gson:2.8.6")
implementation(files("libs/executorch-llama.aar"))
implementation("com.google.android.material:material:1.12.0")
implementation("androidx.activity:activity:1.9.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation(platform("androidx.compose:compose-bom:2023.03.00"))
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")
}

tasks.register("setup") {
doFirst {
exec {
commandLine("sh", "examples/demo-apps/android/LlamaDemo/setup.sh")
workingDir("../../../../../")
}
buildFeatures {
viewBinding = true
}
}

tasks.register("setupQnn") {
doFirst {
exec {
commandLine("sh", "examples/demo-apps/android/LlamaDemo/setup-with-qnn.sh")
workingDir("../../../../../")
}
}
}

dependencies {
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("com.facebook.fbjni:fbjni:0.5.1")
implementation(files("libs/executorch.aar"))
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
tasks.register("download_prebuilt_lib") {
doFirst {
exec {
commandLine("sh", "examples/demo-apps/android/LlamaDemo/download_prebuilt_lib.sh")
workingDir("../../../../../")
}
}
}
2 changes: 1 addition & 1 deletion torchchat/edge/android/torchchat/app/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
#-renamesourcefileattribute SourceFile

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

package org.pytorch.torchchat;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;

import android.os.Bundle;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.pytorch.executorch.LlamaCallback;
import org.pytorch.executorch.LlamaModule;

@RunWith(AndroidJUnit4.class)
public class PerfTest implements LlamaCallback {

private static final String RESOURCE_PATH = "/data/local/tmp/llama/";
private static final String TOKENIZER_BIN = "tokenizer.bin";

private final List<String> results = new ArrayList<>();
private final List<Float> tokensPerSecond = new ArrayList<>();

@Test
public void testTokensPerSecond() {
String tokenizerPath = RESOURCE_PATH + TOKENIZER_BIN;
// Find out the model name
File directory = new File(RESOURCE_PATH);
Arrays.stream(directory.listFiles())
.filter(file -> file.getName().endsWith(".pte"))
.forEach(
model -> {
LlamaModule mModule = new LlamaModule(model.getPath(), tokenizerPath, 0.8f);
// Print the model name because there might be more than one of them
report("ModelName", model.getName());

int loadResult = mModule.load();
// Check that the model can be load successfully
assertEquals(0, loadResult);

// Run a testing prompt
mModule.generate("How do you do! I'm testing llama2 on mobile device", PerfTest.this);
assertFalse(tokensPerSecond.isEmpty());

final Float tps = tokensPerSecond.get(tokensPerSecond.size() - 1);
report("TPS", tps);
});
}

@Override
public void onResult(String result) {
results.add(result);
}

@Override
public void onStats(float tps) {
tokensPerSecond.add(tps);
}

private void report(final String metric, final Float value) {
Bundle bundle = new Bundle();
bundle.putFloat(metric, value);
InstrumentationRegistry.getInstrumentation().sendStatus(0, bundle);
}

private void report(final String key, final String value) {
Bundle bundle = new Bundle();
bundle.putString(key, value);
InstrumentationRegistry.getInstrumentation().sendStatus(0, bundle);
}
}
52 changes: 39 additions & 13 deletions torchchat/edge/android/torchchat/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,35 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) Meta Platforms, Inc. and affiliates.
All rights reserved.

This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
xmlns:tools="http://schemas.android.com/tools"
package="org.pytorch.torchchat">

<uses-sdk
android:maxSdkVersion="40"
android:minSdkVersion="28"
android:targetSdkVersion="34" />

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />

<uses-feature android:name="android.hardware.camera" />

<application
android:name=".ETLogging"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:extractNativeLibs="true"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:icon="@drawable/logo"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.torchchat"
tools:targetApi="31">
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
tools:targetApi="34">
<activity
android:name=".LogsActivity"
android:exported="false" />
<activity
android:name=".SettingsActivity"
android:exported="false" />

<uses-native-library
android:name="libcdsprpc.so"
android:required="false" />

<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.torchchat">
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<activity
android:name=".LlmBenchmarkRunner"
android:exported="true">
<intent-filter>
<action android:name="org.pytorch.torchchat.BENCHMARK" />
</intent-filter>
</activity>

</application>

</manifest>
Loading
Loading