From 662018834e70a30a48aa21ec1fb057583306dd52 Mon Sep 17 00:00:00 2001 From: utkabobr Date: Tue, 1 Apr 2025 23:06:08 +0300 Subject: [PATCH] Optimize boot time --- app/build.gradle | 1 + .../java/ru/ytkab0bp/slicebeam/SliceBeam.java | 71 +++++------- .../ru/ytkab0bp/slicebeam/boot/AppBoot.java | 105 ++++++++++++++++++ .../slicebeam/boot/BeamServerDataTask.java | 24 ++++ .../ru/ytkab0bp/slicebeam/boot/BootTask.java | 33 ++++++ .../slicebeam/boot/CheckUpdateJsonTask.java | 19 ++++ .../slicebeam/boot/ClearModelCacheTask.java | 20 ++++ .../slicebeam/boot/CloudInitTask.java | 12 ++ .../ytkab0bp/slicebeam/boot/EventBusTask.java | 12 ++ .../slicebeam/boot/LoadSlic3rConfigTask.java | 25 +++++ .../ru/ytkab0bp/slicebeam/boot/PrefsTask.java | 10 ++ .../slicebeam/boot/PrintConfigWarmupTask.java | 10 ++ .../ytkab0bp/slicebeam/boot/TrueTimeTask.java | 24 ++++ .../slicebeam/boot/VibrationUtilsTask.java | 12 ++ 14 files changed, 337 insertions(+), 41 deletions(-) create mode 100644 app/src/main/java/ru/ytkab0bp/slicebeam/boot/AppBoot.java create mode 100644 app/src/main/java/ru/ytkab0bp/slicebeam/boot/BeamServerDataTask.java create mode 100644 app/src/main/java/ru/ytkab0bp/slicebeam/boot/BootTask.java create mode 100644 app/src/main/java/ru/ytkab0bp/slicebeam/boot/CheckUpdateJsonTask.java create mode 100644 app/src/main/java/ru/ytkab0bp/slicebeam/boot/ClearModelCacheTask.java create mode 100644 app/src/main/java/ru/ytkab0bp/slicebeam/boot/CloudInitTask.java create mode 100644 app/src/main/java/ru/ytkab0bp/slicebeam/boot/EventBusTask.java create mode 100644 app/src/main/java/ru/ytkab0bp/slicebeam/boot/LoadSlic3rConfigTask.java create mode 100644 app/src/main/java/ru/ytkab0bp/slicebeam/boot/PrefsTask.java create mode 100644 app/src/main/java/ru/ytkab0bp/slicebeam/boot/PrintConfigWarmupTask.java create mode 100644 app/src/main/java/ru/ytkab0bp/slicebeam/boot/TrueTimeTask.java create mode 100644 app/src/main/java/ru/ytkab0bp/slicebeam/boot/VibrationUtilsTask.java diff --git a/app/build.gradle b/app/build.gradle index 1ef7fba..bc29161 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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' diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/SliceBeam.java b/app/src/main/java/ru/ytkab0bp/slicebeam/SliceBeam.java index 65d31f5..20f238d 100644 --- a/app/src/main/java/ru/ytkab0bp/slicebeam/SliceBeam.java +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/SliceBeam.java @@ -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); } diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/boot/AppBoot.java b/app/src/main/java/ru/ytkab0bp/slicebeam/boot/AppBoot.java new file mode 100644 index 0000000..ab83cba --- /dev/null +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/boot/AppBoot.java @@ -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 tasks; + static List pendingMain = new ArrayList<>(); + static List pendingTasks = new ArrayList<>(); + static SparseBooleanArray completed = new SparseBooleanArray(); + static CountDownLatch latch; + + public static void run(List 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 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 it = pendingTasks.iterator(); it.hasNext();) { + BootTask task = it.next(); + if (checkDependencies(task.dependencies)) { + tryRunTask(task, fromMain, true); + it.remove(); + } + } + } + + private static boolean checkDependencies(List> 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; + } +} diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/boot/BeamServerDataTask.java b/app/src/main/java/ru/ytkab0bp/slicebeam/boot/BeamServerDataTask.java new file mode 100644 index 0000000..7c6157d --- /dev/null +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/boot/BeamServerDataTask.java @@ -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(); + } +} diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/boot/BootTask.java b/app/src/main/java/ru/ytkab0bp/slicebeam/boot/BootTask.java new file mode 100644 index 0000000..dd79e61 --- /dev/null +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/boot/BootTask.java @@ -0,0 +1,33 @@ +package ru.ytkab0bp.slicebeam.boot; + +import java.util.Collections; +import java.util.List; + +public class BootTask { + public final List> 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> 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; + } +} diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/boot/CheckUpdateJsonTask.java b/app/src/main/java/ru/ytkab0bp/slicebeam/boot/CheckUpdateJsonTask.java new file mode 100644 index 0000000..e1ab18d --- /dev/null +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/boot/CheckUpdateJsonTask.java @@ -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(); + } +} diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/boot/ClearModelCacheTask.java b/app/src/main/java/ru/ytkab0bp/slicebeam/boot/ClearModelCacheTask.java new file mode 100644 index 0000000..272815d --- /dev/null +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/boot/ClearModelCacheTask.java @@ -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(); + } +} diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/boot/CloudInitTask.java b/app/src/main/java/ru/ytkab0bp/slicebeam/boot/CloudInitTask.java new file mode 100644 index 0000000..84cdb02 --- /dev/null +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/boot/CloudInitTask.java @@ -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(); + } +} diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/boot/EventBusTask.java b/app/src/main/java/ru/ytkab0bp/slicebeam/boot/EventBusTask.java new file mode 100644 index 0000000..6c757c3 --- /dev/null +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/boot/EventBusTask.java @@ -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(); + } +} diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/boot/LoadSlic3rConfigTask.java b/app/src/main/java/ru/ytkab0bp/slicebeam/boot/LoadSlic3rConfigTask.java new file mode 100644 index 0000000..6cb952a --- /dev/null +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/boot/LoadSlic3rConfigTask.java @@ -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(); + } +} diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/boot/PrefsTask.java b/app/src/main/java/ru/ytkab0bp/slicebeam/boot/PrefsTask.java new file mode 100644 index 0000000..7285861 --- /dev/null +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/boot/PrefsTask.java @@ -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)); + } +} diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/boot/PrintConfigWarmupTask.java b/app/src/main/java/ru/ytkab0bp/slicebeam/boot/PrintConfigWarmupTask.java new file mode 100644 index 0000000..f7b672f --- /dev/null +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/boot/PrintConfigWarmupTask.java @@ -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(); + } +} diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/boot/TrueTimeTask.java b/app/src/main/java/ru/ytkab0bp/slicebeam/boot/TrueTimeTask.java new file mode 100644 index 0000000..3444541 --- /dev/null +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/boot/TrueTimeTask.java @@ -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(); + } +} diff --git a/app/src/main/java/ru/ytkab0bp/slicebeam/boot/VibrationUtilsTask.java b/app/src/main/java/ru/ytkab0bp/slicebeam/boot/VibrationUtilsTask.java new file mode 100644 index 0000000..f75f773 --- /dev/null +++ b/app/src/main/java/ru/ytkab0bp/slicebeam/boot/VibrationUtilsTask.java @@ -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(); + } +}