Optimize boot time

This commit is contained in:
utkabobr
2025-04-01 23:06:08 +03:00
parent 6092f123b5
commit 662018834e
14 changed files with 337 additions and 41 deletions
+1
View File
@@ -90,6 +90,7 @@ dependencies {
implementation project(":eventbus")
implementation project(":eventbus_api")
annotationProcessor project(":eventbus_processor")
implementation 'com.github.instacart:truetime-android:3.5'
implementation 'com.github.mrudultora:Colorpicker:1.2.0'
implementation 'com.github.bumptech.glide:glide:4.16.0'
@@ -6,6 +6,8 @@ import android.content.Intent;
import android.util.Log;
import android.webkit.WebView;
import com.instacart.library.truetime.TrueTime;
import org.json.JSONException;
import org.json.JSONObject;
@@ -15,15 +17,30 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Map;
import ru.ytkab0bp.eventbus.EventBus;
import ru.ytkab0bp.slicebeam.boot.AppBoot;
import ru.ytkab0bp.slicebeam.boot.BeamServerDataTask;
import ru.ytkab0bp.slicebeam.boot.CheckUpdateJsonTask;
import ru.ytkab0bp.slicebeam.boot.ClearModelCacheTask;
import ru.ytkab0bp.slicebeam.boot.CloudInitTask;
import ru.ytkab0bp.slicebeam.boot.EventBusTask;
import ru.ytkab0bp.slicebeam.boot.LoadSlic3rConfigTask;
import ru.ytkab0bp.slicebeam.boot.PrefsTask;
import ru.ytkab0bp.slicebeam.boot.PrintConfigWarmupTask;
import ru.ytkab0bp.slicebeam.boot.TrueTimeTask;
import ru.ytkab0bp.slicebeam.boot.VibrationUtilsTask;
import ru.ytkab0bp.slicebeam.cloud.CloudController;
import ru.ytkab0bp.slicebeam.config.ConfigObject;
import ru.ytkab0bp.slicebeam.slic3r.ConfigOptionDef;
import ru.ytkab0bp.slicebeam.slic3r.PrintConfigDef;
import ru.ytkab0bp.slicebeam.slic3r.Slic3rConfigWrapper;
import ru.ytkab0bp.slicebeam.utils.IOUtils;
import ru.ytkab0bp.slicebeam.utils.Prefs;
import ru.ytkab0bp.slicebeam.utils.VibrationUtils;
import ru.ytkab0bp.slicebeam.utils.ViewUtils;
public class SliceBeam extends Application {
public static SliceBeam INSTANCE;
@@ -38,36 +55,18 @@ public class SliceBeam extends Application {
public void onCreate() {
super.onCreate();
INSTANCE = this;
EventBus.registerImpl(this);
Prefs.init(this);
VibrationUtils.init(this);
tryCheckInfo();
PrintConfigDef.getInstance();
try {
getAssets().open("update.json").close();
hasUpdateInfo = true;
} catch (IOException e) {
hasUpdateInfo = false;
}
File cache = SliceBeam.getModelCacheDir();
if (cache.exists()) {
for (File f : cache.listFiles()) {
f.delete();
}
}
File cfgFile = getConfigFile();
getCurrentConfigFile().delete();
if (cfgFile.exists()) {
try {
CONFIG = new Slic3rConfigWrapper(cfgFile);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
WebView.setWebContentsDebuggingEnabled(BuildConfig.DEBUG);
AppBoot.run(Arrays.asList(
new EventBusTask(),
new PrefsTask(),
new VibrationUtilsTask(),
new TrueTimeTask(),
new BeamServerDataTask(),
new PrintConfigWarmupTask(),
new CheckUpdateJsonTask(),
new ClearModelCacheTask(),
new LoadSlic3rConfigTask(),
new CloudInitTask()
));
Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
@@ -81,17 +80,6 @@ public class SliceBeam extends Application {
});
}
private static void tryCheckInfo() {
try {
SERVER_DATA = new BeamServerData(new JSONObject(Prefs.getBeamServerData()));
} catch (JSONException e) {
throw new RuntimeException(e);
}
if (System.currentTimeMillis() - Prefs.getLastCheckedInfo() >= 86400000L) {
BeamServerData.load();
}
}
public static void saveConfig() {
SliceBeam.CONFIG_UID++;
File f = getConfigFile();
@@ -122,6 +110,7 @@ public class SliceBeam extends Application {
if (SliceBeam.CONFIG.findPrint(SliceBeam.CONFIG.presets.get("print")) != null) {
singleObject.values.putAll(SliceBeam.CONFIG.findPrint(SliceBeam.CONFIG.presets.get("print")).values);
}
// TODO: MMU. Detect by printerConfig#getExtruderCount()
if (SliceBeam.CONFIG.findFilament(SliceBeam.CONFIG.presets.get("filament")) != null) {
singleObject.values.putAll(SliceBeam.CONFIG.findFilament(SliceBeam.CONFIG.presets.get("filament")).values);
}
@@ -0,0 +1,105 @@
package ru.ytkab0bp.slicebeam.boot;
import android.util.Log;
import android.util.SparseBooleanArray;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class AppBoot {
static ExecutorService executor = Executors.newCachedThreadPool();
static List<BootTask> tasks;
static List<Runnable> pendingMain = new ArrayList<>();
static List<BootTask> pendingTasks = new ArrayList<>();
static SparseBooleanArray completed = new SparseBooleanArray();
static CountDownLatch latch;
public static void run(List<BootTask> tasks) {
long start = System.currentTimeMillis();
AppBoot.tasks = tasks;
AppBoot.latch = new CountDownLatch(tasks.size());
for (int i = 0, s = tasks.size(); i < s; i++) {
BootTask task = tasks.get(i);
task.index = i;
tryRunTask(task, true, false);
}
try {
while (!latch.await(50, TimeUnit.MILLISECONDS)) {
if (!pendingMain.isEmpty()) {
List<Runnable> clone = new ArrayList<>(pendingMain);
for (Runnable r : clone) {
r.run();
}
pendingMain.removeAll(clone);
}
}
Log.d("boot", "Boot in " + (System.currentTimeMillis() - start) + "ms");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
private static void tryRunTask(BootTask task, boolean fromMain, boolean isContinue) {
if (checkDependencies(task.dependencies)) {
if (task.workerThread) {
executor.submit(() -> {
task.run.run();
completed.put(task.index, true);
latch.countDown();
if (!isContinue) {
continueTasks(fromMain);
}
});
} else {
Runnable r = () -> {
task.run.run();
completed.put(task.index, true);
latch.countDown();
if (!isContinue) {
continueTasks(fromMain);
}
};
if (fromMain) {
r.run();
} else {
pendingMain.add(r);
}
}
} else {
pendingTasks.add(task);
}
}
private static void continueTasks(boolean fromMain) {
for (Iterator<BootTask> it = pendingTasks.iterator(); it.hasNext();) {
BootTask task = it.next();
if (checkDependencies(task.dependencies)) {
tryRunTask(task, fromMain, true);
it.remove();
}
}
}
private static boolean checkDependencies(List<Class<?>> clzs) {
if (clzs.isEmpty()) {
return true;
}
for (int i = 0, s = tasks.size(); i < s; i++) {
if (clzs.contains(tasks.get(i).getClass())) {
if (!completed.get(i)) {
return false;
}
}
}
return true;
}
}
@@ -0,0 +1,24 @@
package ru.ytkab0bp.slicebeam.boot;
import org.json.JSONException;
import org.json.JSONObject;
import ru.ytkab0bp.slicebeam.BeamServerData;
import ru.ytkab0bp.slicebeam.SliceBeam;
import ru.ytkab0bp.slicebeam.utils.Prefs;
public class BeamServerDataTask extends BootTask {
public BeamServerDataTask() {
super(() -> {
try {
SliceBeam.SERVER_DATA = new BeamServerData(new JSONObject(Prefs.getBeamServerData()));
} catch (JSONException e) {
throw new RuntimeException(e);
}
if (System.currentTimeMillis() - Prefs.getLastCheckedInfo() >= 86400000L) {
BeamServerData.load();
}
});
onWorker();
}
}
@@ -0,0 +1,33 @@
package ru.ytkab0bp.slicebeam.boot;
import java.util.Collections;
import java.util.List;
public class BootTask {
public final List<Class<?>> dependencies;
public final Runnable run;
public boolean workerThread;
public int priority;
/* package */ int index;
public BootTask(Runnable run) {
this.dependencies = Collections.emptyList();
this.run = run;
}
public BootTask(List<Class<?>> dependencies, Runnable run) {
this.dependencies = dependencies;
this.run = run;
}
public BootTask onWorker() {
return onWorker(-20);
}
public BootTask onWorker(int priority) {
this.workerThread = true;
this.priority = priority;
return this;
}
}
@@ -0,0 +1,19 @@
package ru.ytkab0bp.slicebeam.boot;
import java.io.IOException;
import ru.ytkab0bp.slicebeam.SliceBeam;
public class CheckUpdateJsonTask extends BootTask {
public CheckUpdateJsonTask() {
super(() -> {
try {
SliceBeam.INSTANCE.getAssets().open("update.json").close();
SliceBeam.hasUpdateInfo = true;
} catch (IOException e) {
SliceBeam.hasUpdateInfo = false;
}
});
onWorker();
}
}
@@ -0,0 +1,20 @@
package ru.ytkab0bp.slicebeam.boot;
import java.io.File;
import ru.ytkab0bp.slicebeam.SliceBeam;
public class ClearModelCacheTask extends BootTask {
@SuppressWarnings("ResultOfMethodCallIgnored")
public ClearModelCacheTask() {
super(()->{
File cache = SliceBeam.getModelCacheDir();
if (cache.exists()) {
for (File f : cache.listFiles()) {
f.delete();
}
}
});
onWorker();
}
}
@@ -0,0 +1,12 @@
package ru.ytkab0bp.slicebeam.boot;
import java.util.Arrays;
import ru.ytkab0bp.slicebeam.cloud.CloudController;
public class CloudInitTask extends BootTask {
public CloudInitTask() {
super(Arrays.asList(PrefsTask.class, TrueTimeTask.class, LoadSlic3rConfigTask.class), CloudController::init);
onWorker();
}
}
@@ -0,0 +1,12 @@
package ru.ytkab0bp.slicebeam.boot;
import ru.ytkab0bp.eventbus.EventBus;
import ru.ytkab0bp.slicebeam.BuildConfig;
public class EventBusTask extends BootTask {
public EventBusTask() {
super(() -> EventBus.registerImpl(BuildConfig.APPLICATION_ID));
onWorker();
}
}
@@ -0,0 +1,25 @@
package ru.ytkab0bp.slicebeam.boot;
import java.io.File;
import java.io.IOException;
import ru.ytkab0bp.slicebeam.SliceBeam;
import ru.ytkab0bp.slicebeam.slic3r.Slic3rConfigWrapper;
@SuppressWarnings("ResultOfMethodCallIgnored")
public class LoadSlic3rConfigTask extends BootTask {
public LoadSlic3rConfigTask() {
super(() -> {
File cfgFile = SliceBeam.getConfigFile();
SliceBeam.getCurrentConfigFile().delete();
if (cfgFile.exists()) {
try {
SliceBeam.CONFIG = new Slic3rConfigWrapper(cfgFile);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
});
onWorker();
}
}
@@ -0,0 +1,10 @@
package ru.ytkab0bp.slicebeam.boot;
import ru.ytkab0bp.slicebeam.SliceBeam;
import ru.ytkab0bp.slicebeam.utils.Prefs;
public class PrefsTask extends BootTask {
public PrefsTask() {
super(()->Prefs.init(SliceBeam.INSTANCE));
}
}
@@ -0,0 +1,10 @@
package ru.ytkab0bp.slicebeam.boot;
import ru.ytkab0bp.slicebeam.slic3r.PrintConfigDef;
public class PrintConfigWarmupTask extends BootTask {
public PrintConfigWarmupTask() {
super(PrintConfigDef::getInstance);
onWorker();
}
}
@@ -0,0 +1,24 @@
package ru.ytkab0bp.slicebeam.boot;
import com.instacart.library.truetime.TrueTime;
import java.io.IOException;
public class TrueTimeTask extends BootTask {
/** @noinspection BusyWait*/
public TrueTimeTask() {
super(() -> {
while (true) {
try {
TrueTime.build().withNtpHost("0.ru.pool.ntp.org").initialize();
break;
} catch (IOException ignore) {
try {
Thread.sleep(100);
} catch (InterruptedException ignored) {}
}
}
});
onWorker();
}
}
@@ -0,0 +1,12 @@
package ru.ytkab0bp.slicebeam.boot;
import ru.ytkab0bp.slicebeam.SliceBeam;
import ru.ytkab0bp.slicebeam.utils.VibrationUtils;
public class VibrationUtilsTask extends BootTask {
public VibrationUtilsTask() {
super(() -> VibrationUtils.init(SliceBeam.INSTANCE));
onWorker();
}
}