Skip to content

Commit

Permalink
在支持的 Windows 平台设备上使用 EcoQoS
Browse files Browse the repository at this point in the history
  • Loading branch information
Ghost-chu committed Aug 17, 2024
1 parent 5d512ba commit 469fd4f
Show file tree
Hide file tree
Showing 14 changed files with 250 additions and 11 deletions.
4 changes: 4 additions & 0 deletions cpp-src/build.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
VS2015 x64 本机工具命令提示符
cl /LD /I"%JAVA_HOME%\include" /I"%JAVA_HOME%\include\win32" ghost-common-jni.cpp /link /out:ghost-common-jni_vc2015_amd64.dll
VS2015 x64 ARM 兼容工具命令提示符
cl /LD /I"%JAVA_HOME%\include" /I"%JAVA_HOME%\include\win32" ghost-common-jni.cpp /link /out:ghost-common-jni_vc2015_aarch64.dll
80 changes: 80 additions & 0 deletions cpp-src/ghost-common-jni.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#include <jni.h>
#include <windows.h>
#include <processthreadsapi.h>
#include <string>

extern "C"
{
JNIEXPORT jstring JNICALL Java_com_ghostchu_lib_jni_EcoMode_setEcoMode(JNIEnv *env, jobject obj, jobject enable)
{
PROCESS_POWER_THROTTLING_STATE PowerThrottling;
RtlZeroMemory(&PowerThrottling, sizeof(PowerThrottling));
PowerThrottling.Version = PROCESS_POWER_THROTTLING_CURRENT_VERSION;

//
// EcoQoS
// Turn EXECUTION_SPEED throttling on.
// ControlMask selects the mechanism and StateMask declares which mechanism should be on or off.
//

PowerThrottling.ControlMask = enable ? PROCESS_POWER_THROTTLING_EXECUTION_SPEED : NULL;
PowerThrottling.StateMask = enable ? PROCESS_POWER_THROTTLING_EXECUTION_SPEED : NULL;

std::string message;

if (!SetProcessInformation(GetCurrentProcess(),
ProcessPowerThrottling,
&PowerThrottling,
sizeof(PowerThrottling)))
{
DWORD error = GetLastError();
message = "SetProcessInformation failed with error: " + std::to_string(error);
return env->NewStringUTF(message.c_str());
}

if (!SetPriorityClass(GetCurrentProcess(), enable ? IDLE_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS))
{
DWORD error = GetLastError();
message = "SetPriorityClass failed with error: " + std::to_string(error);
}
else
{
message = "SUCCESS";
}
// 将 C++ 字符串转换为 Java 字符串并返回
return env->NewStringUTF(message.c_str());
}

JNIEXPORT jint JNICALL Java_com_ghostchu_lib_jni_ProcessPriority_setPriority(JNIEnv *env, jclass cls, jint priority)
{
HANDLE hProcess = GetCurrentProcess();
DWORD dwPriorityClass;

switch (priority)
{
case -1:
dwPriorityClass = IDLE_PRIORITY_CLASS;
break;
case 0:
dwPriorityClass = NORMAL_PRIORITY_CLASS;
break;
case 1:
dwPriorityClass = HIGH_PRIORITY_CLASS;
break;
case 2:
dwPriorityClass = REALTIME_PRIORITY_CLASS;
break;
default:
return -1; // Invalid priority
}

if (SetPriorityClass(hProcess, dwPriorityClass))
{
return 0; // Success
}
else
{
return -1; // Failure
}
}
}
8 changes: 7 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.ghostchu.peerbanhelper</groupId>
<artifactId>peerbanhelper</artifactId>
<version>6.0.0-24w33a</version>
<version>6.0.0-24w33b</version>
<packaging>takari-jar</packaging>

<name>PeerBanHelper</name>
Expand Down Expand Up @@ -249,6 +249,7 @@
<exclude>static/**</exclude>
<exclude>assets/**</exclude>
<exclude>javafx/**</exclude>
<exclude>native/**</exclude>
</excludes>
</resource>
<resource>
Expand All @@ -269,6 +270,11 @@
<targetPath>assets</targetPath>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources/native</directory>
<targetPath>native</targetPath>
<filtering>false</filtering>
</resource>
</resources>
</build>

Expand Down
41 changes: 41 additions & 0 deletions src/main/java/com/ghostchu/lib/jni/EcoMode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.ghostchu.lib.jni;

import com.ghostchu.peerbanhelper.Main;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.Locale;

@Slf4j
public class EcoMode {
public static boolean ecoMode(boolean enable) {
String os = System.getProperty("os.name").toLowerCase(Locale.ROOT);
if (!os.startsWith("win")) {
throw new IllegalStateException("Only Windows OS support EcoMode API");
}
String arch = System.getProperty("os.arch").toLowerCase(Locale.ROOT);
try {
File tmpFile = Files.createTempFile("pbh-jni-lib", ".dll").toFile();
tmpFile.deleteOnExit();
if (arch.contains("aarch64")) {
Files.copy(Main.class.getResourceAsStream("/native/windows/ghost-common-jni_vc2015_aarch64.dll"), tmpFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
} else {
Files.copy(Main.class.getResourceAsStream("/native/windows/ghost-common-jni_vc2015_amd64.dll"), tmpFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
System.load(tmpFile.getAbsolutePath());
} catch (IOException e) {
log.error("Unable load JNI native libraries", e);
}
try {
String data = setEcoMode(enable);
return data.equals("SUCCESS");
} catch (Throwable e) {
return false;
}
}

private native static String setEcoMode(boolean enable);
}
27 changes: 27 additions & 0 deletions src/main/java/com/ghostchu/peerbanhelper/exchange/ExchangeMap.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.ghostchu.peerbanhelper.exchange;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.jetbrains.annotations.NotNull;

import java.util.Collections;
import java.util.Set;
import java.util.TreeSet;

public class ExchangeMap {
public static final Set<DisplayFlag> GUI_DISPLAY_FLAGS = Collections.synchronizedSet(new TreeSet<>());

@Data
@AllArgsConstructor
@NoArgsConstructor
public static class DisplayFlag implements Comparable<DisplayFlag> {
private int priority;
private String content;

@Override
public int compareTo(@NotNull ExchangeMap.DisplayFlag o) {
return Integer.compare(priority, o.priority);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.ghostchu.peerbanhelper.Main;
import com.ghostchu.peerbanhelper.MainJavaFx;
import com.ghostchu.peerbanhelper.event.PBHServerStartedEvent;
import com.ghostchu.peerbanhelper.exchange.ExchangeMap;
import com.ghostchu.peerbanhelper.gui.impl.GuiImpl;
import com.ghostchu.peerbanhelper.gui.impl.console.ConsoleGuiImpl;
import com.ghostchu.peerbanhelper.gui.impl.javafx.mainwindow.JFXWindowController;
Expand Down Expand Up @@ -45,11 +46,11 @@
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;

import static com.ghostchu.peerbanhelper.text.TextManager.tlUI;
Expand All @@ -72,6 +73,7 @@ public class JavaFxImpl extends ConsoleGuiImpl implements GuiImpl {
private final boolean silentStart;
private final String[] args;
private final Set<ListCell<ListLogEntry>> selected = new HashSet<>();
private final ScheduledExecutorService scheduledService = Executors.newScheduledThreadPool(1, Thread.ofVirtual().factory());
private TrayIcon trayIcon;
private ListView<ListLogEntry> logsView;
private boolean persistFlagTrayMessageSent = false;
Expand Down Expand Up @@ -102,7 +104,8 @@ public void setup() {

@Subscribe
public void onPBHServerStarted(PBHServerStartedEvent event) {
Platform.runLater(() -> MainJavaFx.getStage().setTitle(tlUI(Lang.GUI_TITLE_LOADED, "JavaFx", Main.getMeta().getVersion(), Main.getMeta().getAbbrev())));
//Platform.runLater(() -> MainJavaFx.getStage().setTitle(tlUI(Lang.GUI_TITLE_LOADED, "JavaFx", Main.getMeta().getVersion(), Main.getMeta().getAbbrev())));
scheduledService.scheduleWithFixedDelay(this::updateTitleFlags, 0, 5, TimeUnit.SECONDS);
if (Arrays.stream(Main.getStartupArgs()).noneMatch(s -> s.equalsIgnoreCase("enableWebview"))) {
log.info(tlUI(Lang.WEBVIEW_DEFAULT_DISABLED));
return;
Expand All @@ -128,6 +131,13 @@ public void onPBHServerStarted(PBHServerStartedEvent event) {

}

public void updateTitleFlags() {
StringJoiner joiner = new StringJoiner(" ", "[", "]");
String base = tlUI(Lang.GUI_TITLE_LOADED, "JavaFx", Main.getMeta().getVersion(), Main.getMeta().getAbbrev());
ExchangeMap.GUI_DISPLAY_FLAGS.forEach(flag -> joiner.add(flag.getContent()));
Platform.runLater(() -> MainJavaFx.getStage().setTitle(base + " " + joiner));
}

@SneakyThrows
@Override
public void createMainWindow() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.ghostchu.peerbanhelper.platform;

import com.ghostchu.lib.jni.EcoMode;
import com.ghostchu.peerbanhelper.Main;
import com.ghostchu.peerbanhelper.exchange.ExchangeMap;
import com.ghostchu.peerbanhelper.text.Lang;
import lombok.extern.slf4j.Slf4j;
import org.bspfsystems.yamlconfiguration.file.YamlConfiguration;
import org.springframework.stereotype.Component;

import java.util.Locale;

import static com.ghostchu.peerbanhelper.text.TextManager.tlUI;

@Component
@Slf4j
public class WindowsEcoQosAPI {
private final YamlConfiguration config;

public WindowsEcoQosAPI() {
this.config = Main.getMainConfig();
if (this.config.getBoolean("performance.windows-ecoqos-api")) {
installEcoQosApi();
}
}

private void installEcoQosApi() {
String os = System.getProperty("os.name").toLowerCase(Locale.ROOT);
if (os.startsWith("win")) {
if (EcoMode.ecoMode(true)) {
log.info(tlUI(Lang.IN_ECOMODE_DESCRIPTION));
ExchangeMap.GUI_DISPLAY_FLAGS.add(new ExchangeMap.DisplayFlag(10, tlUI(Lang.IN_ECOMODE_SHORT)));
}
}
}
}
22 changes: 21 additions & 1 deletion src/main/java/com/ghostchu/peerbanhelper/text/Lang.java
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,27 @@ public enum Lang {
DONATION_KEY_VERIFICATION_SUCCESSFUL,
OOBE_DISALLOW_REINIT,

PBH_OOBE_REQUIRED, WEBVIEW_DEFAULT_DISABLED, PCB_SHUTTING_DOWN, PBHPLUS_LICENSE_FAILED, CHARTS_IPDB_NEED_INIT, IP_MANUALLY_BAN_FAILED_INVALID_IP, IP_MANUALLY_BAN_FAILED_ONLY_SINGLE_IP_ACCEPTED, IP_BLACKLIST_PUT_IP_INVALID_IP, IP_BLACKLIST_PUT_IP_INVALID_ARG, IP_BLACKLIST_PUT_PORT_INVALID_RANGE, IP_BLACKLIST_PUT_PORT_PRIVILEGED_PORT_TIPS, APPLYING_FULL_BANLIST_TO_DOWNLOADER, SCHEDULED_FULL_BANLIST_APPLY, CLEANED_BANLOGS, OPERATION_EXECUTE_SUCCESSFULLY, PBH_PLUS_LICENSE_UPDATE, GUI_MENU_DEBUG_RELOAD_CONFIGURATION, GUI_MENU_DEBUG_HEAP_DUMP, GUI_MENU_PRINT_THREADS, RELOAD_COMPLETED_TITLE, RELOAD_COMPLETED_DESCRIPTION, HEAPDUMP_COMPLETED_TITLE, HEAPDUMP_COMPLETED_DESCRIPTION, HEAPDUMP_FAILED_DESCRIPTION, HEAPDUMP_FAILED_TITLE, RELOADING_MODULE, GUI_MENU_DEBUG, TORRENT_NOT_FOUND, PEER_NOT_FOUND, PBH_PLUS_LICENSE_INVALID, PBH_PLUS_LICENSE_EXPIRED;
PBH_OOBE_REQUIRED,
WEBVIEW_DEFAULT_DISABLED,
PCB_SHUTTING_DOWN,
PBHPLUS_LICENSE_FAILED,
CHARTS_IPDB_NEED_INIT,
IP_MANUALLY_BAN_FAILED_INVALID_IP,
IP_MANUALLY_BAN_FAILED_ONLY_SINGLE_IP_ACCEPTED,
IP_BLACKLIST_PUT_IP_INVALID_IP,
IP_BLACKLIST_PUT_IP_INVALID_ARG,
IP_BLACKLIST_PUT_PORT_INVALID_RANGE,
IP_BLACKLIST_PUT_PORT_PRIVILEGED_PORT_TIPS,
APPLYING_FULL_BANLIST_TO_DOWNLOADER,
SCHEDULED_FULL_BANLIST_APPLY,
CLEANED_BANLOGS,
OPERATION_EXECUTE_SUCCESSFULLY,
PBH_PLUS_LICENSE_UPDATE,
GUI_MENU_DEBUG_RELOAD_CONFIGURATION, GUI_MENU_DEBUG_HEAP_DUMP, GUI_MENU_PRINT_THREADS,
RELOAD_COMPLETED_TITLE, RELOAD_COMPLETED_DESCRIPTION, HEAPDUMP_COMPLETED_TITLE,
HEAPDUMP_COMPLETED_DESCRIPTION, HEAPDUMP_FAILED_DESCRIPTION, HEAPDUMP_FAILED_TITLE,
RELOADING_MODULE, GUI_MENU_DEBUG, TORRENT_NOT_FOUND, PEER_NOT_FOUND,
PBH_PLUS_LICENSE_INVALID, PBH_PLUS_LICENSE_EXPIRED, IN_ECOMODE_DESCRIPTION, IN_ECOMODE_SHORT;

public String getKey() {
return name();
Expand Down
8 changes: 7 additions & 1 deletion src/main/resources/config.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
config-version: 16
config-version: 17
# 设置程序语言
# Set the program language
# default 跟随操作系统 (Follow the operating system)
Expand Down Expand Up @@ -157,3 +157,9 @@ proxy:
port: 7890
# 代理例外地址,使用 | 分隔不同条目 - Exception list, spilt with | symbol
non-proxy-hosts: "localhost|127.*|192.168.*|10.*|172.16.*|172.17.*|172.18.*|172.19.*|172.20.*|172.21.*|172.22.*|172.23.*|172.24.*|172.25.*|172.26.*|172.27.*|172.28.*|172.29.*|172.30.*|172.31.*"

performance:
# 启用 Windows 平台上的 EcoQoS API
# Enable EcoQoS API on Windows Platform
# https://devblogs.microsoft.com/performance-diagnostics/introducing-ecoqos/
windows-ecoqos-api: true
5 changes: 4 additions & 1 deletion src/main/resources/lang/en_us/messages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -359,4 +359,7 @@ HEAPDUMP_COMPLETED_DESCRIPTION: "Memory snapshot dump successfully, check .hprof
RELOADING_MODULE: "[Reload] {}: {}"

TORRENT_NOT_FOUND: "No records found by given InfoHash"
PEER_NOT_FOUND: "No records found by given Peer"
PEER_NOT_FOUND: "No records found by given Peer"

IN_ECOMODE_SHORT: "🍃EcoQoS"
IN_ECOMODE_DESCRIPTION: "EcoQoS API load successfully,Windows Efficiency Mode now applied to PeerBanHelper for saving power usage."
5 changes: 4 additions & 1 deletion src/main/resources/lang/messages_fallback.yml
Original file line number Diff line number Diff line change
Expand Up @@ -359,4 +359,7 @@ HEAPDUMP_COMPLETED_DESCRIPTION: "内存快照已转储成功,请见 data/debug
RELOADING_MODULE: "[重载] {}: {}"

TORRENT_NOT_FOUND: "指定的 Torrent 记录不存在"
PEER_NOT_FOUND: "指定的 Peer 记录不存在"
PEER_NOT_FOUND: "指定的 Peer 记录不存在"

IN_ECOMODE_SHORT: "🍃EcoQoS"
IN_ECOMODE_DESCRIPTION: "EcoQoS API 加载成功,Windows 效率模式已应用至 PeerBanHelper 以降低系统能耗"
5 changes: 4 additions & 1 deletion src/main/resources/lang/zh_cn/messages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -358,4 +358,7 @@ HEAPDUMP_COMPLETED_DESCRIPTION: "内存快照已转储成功,请见 data/debug
RELOADING_MODULE: "[重载] {}: {}"

TORRENT_NOT_FOUND: "指定的 Torrent 记录不存在"
PEER_NOT_FOUND: "指定的 Peer 记录不存在"
PEER_NOT_FOUND: "指定的 Peer 记录不存在"

IN_ECOMODE_SHORT: "🍃EcoQoS"
IN_ECOMODE_DESCRIPTION: "EcoQoS API 加载成功,Windows 效率模式已应用至 PeerBanHelper 以降低系统能耗"
Binary file not shown.
Binary file not shown.

0 comments on commit 469fd4f

Please sign in to comment.