mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-05-24 02:04:11 +00:00
Remove allocation tracking for computers
Reverts 76968f2f28435ddd8cf1efe5dc7330410e87cc09. We'd originally added this to gather some numbers for #1580, with the hope that it would also be useful for server admins. Sadly, it's not as accurate as I originally hoped — the number sometimes goes down for unclear reasons (something to do with the TLAB maybe??). Closes #1739.
This commit is contained in:
parent
9c0ce27ce6
commit
8711512769
@ -185,7 +185,6 @@ public final class LanguageProvider implements DataProvider {
|
||||
// Metrics
|
||||
add(Metrics.COMPUTER_TASKS, "Tasks");
|
||||
add(Metrics.SERVER_TASKS, "Server tasks");
|
||||
add(Metrics.JAVA_ALLOCATION, "Java Allocations");
|
||||
add(Metrics.PERIPHERAL_OPS, "Peripheral calls");
|
||||
add(Metrics.FS_OPS, "Filesystem operations");
|
||||
add(Metrics.HTTP_REQUESTS, "HTTP requests");
|
||||
|
@ -217,7 +217,6 @@
|
||||
"tracking_field.computercraft.http_download.name": "HTTP download",
|
||||
"tracking_field.computercraft.http_requests.name": "HTTP requests",
|
||||
"tracking_field.computercraft.http_upload.name": "HTTP upload",
|
||||
"tracking_field.computercraft.java_allocation.name": "Java Allocations",
|
||||
"tracking_field.computercraft.max": "%s (max)",
|
||||
"tracking_field.computercraft.peripheral.name": "Peripheral calls",
|
||||
"tracking_field.computercraft.server_tasks.name": "Server tasks",
|
||||
|
@ -165,7 +165,7 @@ public final class TickScheduler {
|
||||
UNLOADED,
|
||||
}
|
||||
|
||||
private record ChunkReference(ResourceKey<Level> level, Long position) {
|
||||
private record ChunkReference(ResourceKey<Level> level, long position) {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ChunkReference(" + level + " at " + new ChunkPos(position) + ")";
|
||||
|
@ -215,7 +215,6 @@
|
||||
"tracking_field.computercraft.http_download.name": "Stahování HTTP",
|
||||
"tracking_field.computercraft.http_requests.name": "Požadavky HTTP",
|
||||
"tracking_field.computercraft.http_upload.name": "Nahrávání HTTP",
|
||||
"tracking_field.computercraft.java_allocation.name": "Java alokace",
|
||||
"tracking_field.computercraft.max": "%s (max)",
|
||||
"tracking_field.computercraft.peripheral.name": "Periferní volání",
|
||||
"tracking_field.computercraft.server_tasks.name": "Serverové úlohy",
|
||||
|
@ -206,7 +206,6 @@
|
||||
"tracking_field.computercraft.http_download.name": "Descarga HTTP",
|
||||
"tracking_field.computercraft.http_requests.name": "Peticiones HTTP",
|
||||
"tracking_field.computercraft.http_upload.name": "Subida HTTP",
|
||||
"tracking_field.computercraft.java_allocation.name": "Asignaciones de Java",
|
||||
"tracking_field.computercraft.max": "%s (max)",
|
||||
"tracking_field.computercraft.peripheral.name": "Llamadas del periférico",
|
||||
"tracking_field.computercraft.server_tasks.name": "Tareas del servidor",
|
||||
|
@ -215,7 +215,6 @@
|
||||
"tracking_field.computercraft.http_download.name": "Téléchargement HTTP",
|
||||
"tracking_field.computercraft.http_requests.name": "Requêtes HTTP",
|
||||
"tracking_field.computercraft.http_upload.name": "Publication HTTP",
|
||||
"tracking_field.computercraft.java_allocation.name": "Allocations Java",
|
||||
"tracking_field.computercraft.max": "%s (max)",
|
||||
"tracking_field.computercraft.peripheral.name": "Appels aux périphériques",
|
||||
"tracking_field.computercraft.server_tasks.name": "Tâches du serveur",
|
||||
|
@ -12,9 +12,12 @@
|
||||
"block.computercraft.cable": "Cavo Di Rete",
|
||||
"block.computercraft.computer_advanced": "Computer Avanzato",
|
||||
"block.computercraft.computer_command": "Computer Comando",
|
||||
"block.computercraft.computer_normal": "Computer",
|
||||
"block.computercraft.disk_drive": "Lettore Di Dischi",
|
||||
"block.computercraft.monitor_advanced": "Monitor Avanzato",
|
||||
"block.computercraft.monitor_normal": "Monitor",
|
||||
"block.computercraft.printer": "Stampante",
|
||||
"block.computercraft.redstone_relay": "Relè di redstone",
|
||||
"block.computercraft.speaker": "Altoparlante",
|
||||
"block.computercraft.turtle_advanced": "Tartaruga Avanzata",
|
||||
"block.computercraft.turtle_advanced.upgraded": "Tartaruga %s Avanzata",
|
||||
@ -35,6 +38,7 @@
|
||||
"commands.computercraft.dump.synopsis": "Mostra lo stato dei computer.",
|
||||
"commands.computercraft.generic.additional_rows": "%d colonne aggiuntive…",
|
||||
"commands.computercraft.generic.exception": "Eccezione non gestita (%s)",
|
||||
"commands.computercraft.generic.no": "N",
|
||||
"commands.computercraft.generic.yes": "S",
|
||||
"commands.computercraft.help.desc": "Mostra questo messaggio d'aiuto",
|
||||
"commands.computercraft.help.no_children": "%s non ha sottocomandi",
|
||||
@ -50,6 +54,7 @@
|
||||
"commands.computercraft.tp.desc": "Teletrasporta alla posizione di un computer. Puoi specificare il computer con l'instance id (e.g. 123) o con l'id (e.g. #123).",
|
||||
"commands.computercraft.tp.synopsis": "Teletrasporta al computer specificato.",
|
||||
"commands.computercraft.track.desc": "Monitora per quanto tempo i computer vengono eseguiti e quanti eventi ricevono. Questo comando fornisce le informazioni in modo simile a /forge track e può essere utile per diagnosticare il lag.",
|
||||
"commands.computercraft.track.dump.computer": "Computer",
|
||||
"commands.computercraft.track.dump.desc": "Cancella gli ultimi risultati del monitoraggio dei computer.",
|
||||
"commands.computercraft.track.dump.no_timings": "No ci sono tempi disponibili",
|
||||
"commands.computercraft.track.dump.synopsis": "Cancella gli ultimi risultati monitorati",
|
||||
@ -86,6 +91,7 @@
|
||||
"gui.computercraft.config.execution.tooltip": "Controlla comportamento esecuzione dei computer. Questo è largamente utilizzato\nper ritoccare la performance dei server, e generale non dovrebbe essere toccato.",
|
||||
"gui.computercraft.config.floppy_space_limit": "Limite spazio Disco Floppy (bytes)",
|
||||
"gui.computercraft.config.floppy_space_limit.tooltip": "Limite di spazio di archiviazione per i dischi floppy, in byte.",
|
||||
"gui.computercraft.config.http": "HTTP",
|
||||
"gui.computercraft.config.http.bandwidth": "Banda larga",
|
||||
"gui.computercraft.config.http.bandwidth.global_download": "Limite download globale",
|
||||
"gui.computercraft.config.http.bandwidth.global_download.tooltip": "Numero di byte che possono essere scaricati in un secondo. Questo è condiviso tra tutti i computer. (bytes/s).",
|
||||
@ -98,6 +104,7 @@
|
||||
"gui.computercraft.config.http.max_requests.tooltip": "Il numero di richieste http che un computer può fare alla volta. Ulteriori richieste verranno messe in coda, ed inviate quando le richieste correnti sono terminate. Imposta a 0 per illimitato.",
|
||||
"gui.computercraft.config.http.max_websockets": "Connessioni websocket massime",
|
||||
"gui.computercraft.config.http.max_websockets.tooltip": "Il numero di websocket che un computer può avere aperte allo stesso momento.Imposta a 0 per illimitato.",
|
||||
"gui.computercraft.config.http.proxy": "Proxy",
|
||||
"gui.computercraft.config.http.proxy.host": "Nome host",
|
||||
"gui.computercraft.config.http.proxy.host.tooltip": "Il nome dell'host o l'indirizzo IP del server proxy.",
|
||||
"gui.computercraft.config.http.proxy.port": "Porta",
|
||||
@ -135,16 +142,24 @@
|
||||
"gui.computercraft.config.peripheral.monitor_bandwidth.tooltip": "Il limite di quanti dati dei monitor possono essere inviati *al tick*. Nota:\n - La banda larga è misurata prima della compressione, così che il dato inviato al client è\n più piccolo.\n - Questo ignora il numero di giocatori a cui viene inviato il pacchetto. Aggiornare un monitor\n per un giocatore consuma lo stesso limite di banda larga dell'invio a 20 giocatori.\n - Un monitor alla massima grandezza invia ~25kb di dati. Quindi il valore predefinito (1MB) concede\n ~40 monitor di essere aggiornati in un singolo tick.\nImposta a 0 per disattivare.",
|
||||
"gui.computercraft.config.peripheral.tooltip": "Opzioni varie riguardo le periferiche.",
|
||||
"gui.computercraft.config.term_sizes": "Dimensioni terminale",
|
||||
"gui.computercraft.config.term_sizes.computer": "Computer",
|
||||
"gui.computercraft.config.term_sizes.computer.height": "Altezza terminale",
|
||||
"gui.computercraft.config.term_sizes.computer.height.tooltip": "Altezza del terminale del computer",
|
||||
"gui.computercraft.config.term_sizes.computer.tooltip": "Dimensioni del terminale dei computer.",
|
||||
"gui.computercraft.config.term_sizes.computer.width": "Larghezza terminale",
|
||||
"gui.computercraft.config.term_sizes.computer.width.tooltip": "Larghezza del terminale del computer",
|
||||
"gui.computercraft.config.term_sizes.monitor": "Monitor",
|
||||
"gui.computercraft.config.term_sizes.monitor.height": "Massima altezza del monitor",
|
||||
"gui.computercraft.config.term_sizes.monitor.height.tooltip": "Altezza massima dei monitor",
|
||||
"gui.computercraft.config.term_sizes.monitor.tooltip": "Massima grandezza dei monitor (in blocchi).",
|
||||
"gui.computercraft.config.term_sizes.monitor.width": "Larghezza massima del monitor",
|
||||
"gui.computercraft.config.term_sizes.monitor.width.tooltip": "Larghezza massima dei monitor",
|
||||
"gui.computercraft.config.term_sizes.pocket_computer": "Computer Tascabile",
|
||||
"gui.computercraft.config.term_sizes.pocket_computer.height": "Altezza terminale",
|
||||
"gui.computercraft.config.term_sizes.pocket_computer.height.tooltip": "Altezza del terminale dei computer tascabili",
|
||||
"gui.computercraft.config.term_sizes.pocket_computer.tooltip": "Dimensioni del terminale dei computer tascabili.",
|
||||
"gui.computercraft.config.term_sizes.pocket_computer.width": "Larghezza terminale",
|
||||
"gui.computercraft.config.term_sizes.pocket_computer.width.tooltip": "Larghezza del terminale del computer tascabile",
|
||||
"gui.computercraft.config.term_sizes.tooltip": "Configura le dimensioni dei terminali di vari computer.\nTerminali più grandi richiedono più banda larga, usa con cautela.",
|
||||
"gui.computercraft.config.turtle": "Tartarughe",
|
||||
"gui.computercraft.config.turtle.advanced_fuel_limit": "Limite carburante tartarughe avanzate",
|
||||
@ -188,6 +203,7 @@
|
||||
"item.computercraft.printed_page": "Pagina Stampata",
|
||||
"item.computercraft.printed_pages": "Pagine Stampate",
|
||||
"item.computercraft.treasure_disk": "Disco Floppy",
|
||||
"itemGroup.computercraft": "ComputerCraft",
|
||||
"tag.item.computercraft.computer": "Computer",
|
||||
"tag.item.computercraft.monitor": "Monitor",
|
||||
"tag.item.computercraft.turtle": "Tartarughe",
|
||||
@ -199,7 +215,6 @@
|
||||
"tracking_field.computercraft.http_download.name": "Download HTTP",
|
||||
"tracking_field.computercraft.http_requests.name": "Richieste HTTP",
|
||||
"tracking_field.computercraft.http_upload.name": "Upload HTTP",
|
||||
"tracking_field.computercraft.java_allocation.name": "Allocazioni Java",
|
||||
"tracking_field.computercraft.max": "%s (massimo)",
|
||||
"tracking_field.computercraft.peripheral.name": "Chiamate alle periferiche",
|
||||
"tracking_field.computercraft.server_tasks.name": "Attività server",
|
||||
@ -207,6 +222,8 @@
|
||||
"tracking_field.computercraft.websocket_incoming.name": "Websocket in arrivo",
|
||||
"tracking_field.computercraft.websocket_outgoing.name": "Websocket in uscita",
|
||||
"upgrade.computercraft.speaker.adjective": "Rumoroso",
|
||||
"upgrade.computercraft.wireless_modem_advanced.adjective": "Ender",
|
||||
"upgrade.computercraft.wireless_modem_normal.adjective": "Senza fili",
|
||||
"upgrade.minecraft.crafting_table.adjective": "Artigiana",
|
||||
"upgrade.minecraft.diamond_axe.adjective": "Taglialegna",
|
||||
"upgrade.minecraft.diamond_hoe.adjective": "Contadina",
|
||||
|
@ -215,7 +215,6 @@
|
||||
"tracking_field.computercraft.http_download.name": "HTTPダウンロード",
|
||||
"tracking_field.computercraft.http_requests.name": "HTTPリクエスト",
|
||||
"tracking_field.computercraft.http_upload.name": "HTTPアップロード",
|
||||
"tracking_field.computercraft.java_allocation.name": "Java割当",
|
||||
"tracking_field.computercraft.max": "%s (最大)",
|
||||
"tracking_field.computercraft.peripheral.name": "実行呼び出し",
|
||||
"tracking_field.computercraft.server_tasks.name": "サーバータスク",
|
||||
|
@ -208,7 +208,6 @@
|
||||
"tracking_field.computercraft.http_download.name": "Download HTTP",
|
||||
"tracking_field.computercraft.http_requests.name": "Solicitações HTTP",
|
||||
"tracking_field.computercraft.http_upload.name": "Upload de HTTP",
|
||||
"tracking_field.computercraft.java_allocation.name": "Alocações Java",
|
||||
"tracking_field.computercraft.max": "%s (máximo)",
|
||||
"tracking_field.computercraft.peripheral.name": "Chamadas Periféricas",
|
||||
"tracking_field.computercraft.server_tasks.name": "Tarefas do servidor",
|
||||
|
@ -109,6 +109,7 @@
|
||||
"gui.computercraft.config.log_computer_errors": "Регистрировать ошибки компьютера",
|
||||
"gui.computercraft.config.log_computer_errors.tooltip": "Регистрировать исключения, вызванные периферийными устройствами и другими объектами Lua. Это облегчает\nдля авторам модов устранение проблем, но может привести к спаму в логах, если люди будут использовать\nглючные методы.",
|
||||
"gui.computercraft.config.maximum_open_files": "Максимальное количество файлов, открытых на одном компьютере",
|
||||
"gui.computercraft.config.peripheral": "Периферия",
|
||||
"gui.computercraft.config.term_sizes": "Размер терминала",
|
||||
"gui.computercraft.config.term_sizes.computer": "Компьютер",
|
||||
"gui.computercraft.config.term_sizes.computer.height": "Высота терминала",
|
||||
|
@ -1,8 +1,14 @@
|
||||
{
|
||||
"argument.computercraft.argument_expected": "Argument förväntas",
|
||||
"argument.computercraft.computer.distance": "Distans till entitet",
|
||||
"argument.computercraft.computer.family": "Datorfamilj",
|
||||
"argument.computercraft.computer.id": "Dator-ID",
|
||||
"argument.computercraft.computer.instance": "Unikt instans-ID",
|
||||
"argument.computercraft.computer.label": "Datoretikett",
|
||||
"argument.computercraft.computer.many_matching": "Flera datorer matchar '%s' (%s träffar)",
|
||||
"argument.computercraft.computer.no_matching": "Inga datorer matchar '%s'",
|
||||
"argument.computercraft.tracking_field.no_field": "Okänt fält '%s'",
|
||||
"argument.computercraft.unknown_computer_family": "Okänd datorfamilj '%s'",
|
||||
"block.computercraft.cable": "Nätverkskabel",
|
||||
"block.computercraft.computer_advanced": "Avancerad Dator",
|
||||
"block.computercraft.computer_command": "Kommandodator",
|
||||
@ -66,7 +72,10 @@
|
||||
"commands.computercraft.view.desc": "Öppna datorns terminal för att möjligöra fjärrstyrning. Detta ger inte tillgång till turtlens inventory. Du kan ange en dators instans-id (t.ex. 123) eller dator-id (t.ex. #123).",
|
||||
"commands.computercraft.view.not_player": "Kan inte öppna terminalen för en ickespelare",
|
||||
"commands.computercraft.view.synopsis": "Titta på datorns terminal.",
|
||||
"gui.computercraft.config.command_require_creative": "Kommandodatorer kräver kreativt läge",
|
||||
"gui.computercraft.config.command_require_creative.tooltip": "Kräv att spelare är i kreativt läge och har operatörsrättigheter för att kunna interagera med kommandodatorer.\nDetta är standardbeteendet för vaniljversionens kommandoblock.",
|
||||
"gui.computercraft.config.computer_space_limit": "Dator maximalt utrymme (bytes)",
|
||||
"gui.computercraft.config.computer_space_limit.tooltip": "Gränsen för diskutrymme för datorer och sköldpaddor, i bytes.",
|
||||
"gui.computercraft.config.default_computer_settings": "Standard Datorinställningar",
|
||||
"gui.computercraft.config.execution.computer_threads": "Dator trådar",
|
||||
"gui.computercraft.config.floppy_space_limit": "Diskett maximalt utrymme (bytes)",
|
||||
|
@ -215,7 +215,6 @@
|
||||
"tracking_field.computercraft.http_download.name": "HTTP indirme",
|
||||
"tracking_field.computercraft.http_requests.name": "HTTP istekleri",
|
||||
"tracking_field.computercraft.http_upload.name": "HTTP yükleme",
|
||||
"tracking_field.computercraft.java_allocation.name": "Java'ya Ayrılan",
|
||||
"tracking_field.computercraft.max": "%s (azami)",
|
||||
"tracking_field.computercraft.peripheral.name": "Çevre birimi çağrıları",
|
||||
"tracking_field.computercraft.server_tasks.name": "Sunucu görevleri",
|
||||
|
@ -215,7 +215,6 @@
|
||||
"tracking_field.computercraft.http_download.name": "HTTP завантаження",
|
||||
"tracking_field.computercraft.http_requests.name": "HTTP запитів",
|
||||
"tracking_field.computercraft.http_upload.name": "HTTP завантаження",
|
||||
"tracking_field.computercraft.java_allocation.name": "Java Виділення",
|
||||
"tracking_field.computercraft.max": "%s (макс)",
|
||||
"tracking_field.computercraft.peripheral.name": "Викликів преферійних девайсів",
|
||||
"tracking_field.computercraft.server_tasks.name": "Серверних задач",
|
||||
|
@ -215,7 +215,6 @@
|
||||
"tracking_field.computercraft.http_download.name": "HTTP下载",
|
||||
"tracking_field.computercraft.http_requests.name": "HTTP请求",
|
||||
"tracking_field.computercraft.http_upload.name": "HTTP上传",
|
||||
"tracking_field.computercraft.java_allocation.name": "Java分配",
|
||||
"tracking_field.computercraft.max": "%s (最大)",
|
||||
"tracking_field.computercraft.peripheral.name": "外部设备呼叫",
|
||||
"tracking_field.computercraft.server_tasks.name": "服务器任务",
|
||||
|
@ -12,13 +12,11 @@ import dan200.computercraft.core.Logging;
|
||||
import dan200.computercraft.core.computer.TimeoutState;
|
||||
import dan200.computercraft.core.metrics.Metrics;
|
||||
import dan200.computercraft.core.metrics.MetricsObserver;
|
||||
import dan200.computercraft.core.metrics.ThreadAllocations;
|
||||
import dan200.computercraft.core.util.ThreadUtils;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
@ -489,9 +487,6 @@ public final class ComputerThread implements ComputerScheduler {
|
||||
}
|
||||
|
||||
private void runImpl() {
|
||||
var workerThreadIds = new long[workersReadOnly().length];
|
||||
Arrays.fill(workerThreadIds, Thread.currentThread().getId());
|
||||
|
||||
while (state.get() < CLOSED) {
|
||||
computerLock.lock();
|
||||
try {
|
||||
@ -506,33 +501,12 @@ public final class ComputerThread implements ComputerScheduler {
|
||||
computerLock.unlock();
|
||||
}
|
||||
|
||||
checkRunners(workerThreadIds);
|
||||
checkRunners();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkRunners(long[] workerThreadIds) {
|
||||
var workers = workersReadOnly();
|
||||
|
||||
long[] allocations;
|
||||
if (ThreadAllocations.isSupported()) {
|
||||
// If allocation tracking is supported, update the current thread IDs and then fetch the total allocated
|
||||
// memory. When dealing with multiple workers, it's more efficient to getAllocatedBytes in bulk rather
|
||||
// than, hence doing it within the worker loop.
|
||||
// However, this does mean we need to maintain an array of worker thread IDs. We could have a shared
|
||||
// array and update it within .addWorker(_), but that's got all sorts of thread-safety issues. It ends
|
||||
// up being easier (and not too inefficient) to just recompute the array each time.
|
||||
for (var i = 0; i < workers.length; i++) {
|
||||
var runner = workers[i];
|
||||
if (runner != null) workerThreadIds[i] = runner.owner.getId();
|
||||
}
|
||||
allocations = ThreadAllocations.getAllocatedBytes(workerThreadIds);
|
||||
} else {
|
||||
allocations = null;
|
||||
}
|
||||
var allocationTime = System.nanoTime();
|
||||
|
||||
for (var i = 0; i < workers.length; i++) {
|
||||
var runner = workers[i];
|
||||
private void checkRunners() {
|
||||
for (var runner : workersReadOnly()) {
|
||||
if (runner == null) continue;
|
||||
|
||||
// If the worker has no work, skip
|
||||
@ -542,11 +516,6 @@ public final class ComputerThread implements ComputerScheduler {
|
||||
// Refresh the timeout state. Will set the pause/soft timeout flags as appropriate.
|
||||
executor.timeout.refresh();
|
||||
|
||||
// And track the allocated memory.
|
||||
if (allocations != null) {
|
||||
executor.updateAllocations(new ThreadAllocation(workerThreadIds[i], allocations[i], allocationTime));
|
||||
}
|
||||
|
||||
// If we're still within normal execution times (TIMEOUT) or soft abort (ABORT_TIMEOUT),
|
||||
// then we can let the Lua machine do its work.
|
||||
var remainingTime = executor.timeout.getRemainingTime();
|
||||
@ -774,9 +743,6 @@ public final class ComputerThread implements ComputerScheduler {
|
||||
public static final AtomicReferenceFieldUpdater<ExecutorImpl, ExecutorState> STATE = AtomicReferenceFieldUpdater.newUpdater(
|
||||
ExecutorImpl.class, ExecutorState.class, "$state"
|
||||
);
|
||||
public static final AtomicReferenceFieldUpdater<ExecutorImpl, ThreadAllocation> THREAD_ALLOCATION = AtomicReferenceFieldUpdater.newUpdater(
|
||||
ExecutorImpl.class, ThreadAllocation.class, "$threadAllocation"
|
||||
);
|
||||
|
||||
final Worker worker;
|
||||
private final MetricsObserver metrics;
|
||||
@ -788,17 +754,6 @@ public final class ComputerThread implements ComputerScheduler {
|
||||
@Keep
|
||||
private volatile ExecutorState $state = ExecutorState.IDLE;
|
||||
|
||||
/**
|
||||
* Information about allocations on the currently executing thread.
|
||||
* <p>
|
||||
* {@linkplain #beforeWork() Before starting any work}, we set this to the current thread and the current
|
||||
* {@linkplain ThreadAllocations#getAllocatedBytes(long) amount of allocated memory}. When the computer
|
||||
* {@linkplain #afterWork()} finishes executing, we set this back to null and compute the difference between the
|
||||
* two, updating the {@link Metrics#JAVA_ALLOCATION} metric.
|
||||
*/
|
||||
@Keep
|
||||
private volatile @Nullable ThreadAllocation $threadAllocation = null;
|
||||
|
||||
/**
|
||||
* The amount of time this computer has used on a theoretical machine which shares work evenly amongst computers.
|
||||
*
|
||||
@ -825,11 +780,6 @@ public final class ComputerThread implements ComputerScheduler {
|
||||
void beforeWork() {
|
||||
vRuntimeStart = System.nanoTime();
|
||||
timeout.startTimer(scaledPeriod());
|
||||
|
||||
if (ThreadAllocations.isSupported()) {
|
||||
var current = Thread.currentThread().getId();
|
||||
THREAD_ALLOCATION.set(this, new ThreadAllocation(current, ThreadAllocations.getAllocatedBytes(current), System.nanoTime()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -841,55 +791,10 @@ public final class ComputerThread implements ComputerScheduler {
|
||||
timeout.reset();
|
||||
metrics.observe(Metrics.COMPUTER_TASKS, timeout.getExecutionTime());
|
||||
|
||||
if (ThreadAllocations.isSupported()) {
|
||||
var current = Thread.currentThread().getId();
|
||||
var info = THREAD_ALLOCATION.getAndSet(this, null);
|
||||
assert info.threadId() == current;
|
||||
|
||||
var allocatedTotal = ThreadAllocations.getAllocatedBytes(current);
|
||||
var allocated = allocatedTotal - info.allocatedBytes();
|
||||
if (allocated > 0) {
|
||||
metrics.observe(Metrics.JAVA_ALLOCATION, allocated);
|
||||
} else if (allocated < 0) {
|
||||
LOG.warn(
|
||||
"""
|
||||
Allocated a negative number of bytes ({})!
|
||||
Previous measurement at t={} on Thread #{} = {}
|
||||
Current measurement at t={} on Thread #{} = {}""",
|
||||
allocated,
|
||||
info.time(), info.threadId(), info.allocatedBytes(),
|
||||
System.nanoTime(), current, allocatedTotal
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var state = STATE.getAndUpdate(this, ExecutorState::requeue);
|
||||
return state == ExecutorState.REPEAT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the per-thread allocation information.
|
||||
*
|
||||
* @param allocation The latest allocation information.
|
||||
*/
|
||||
void updateAllocations(ThreadAllocation allocation) {
|
||||
ThreadAllocation current;
|
||||
long allocated;
|
||||
do {
|
||||
// Probe the current information - if it's null or the thread has changed, then the worker has already
|
||||
// finished and this information is out-of-date, so just abort.
|
||||
current = THREAD_ALLOCATION.get(this);
|
||||
if (current == null || current.threadId() != allocation.threadId()) return;
|
||||
|
||||
// Then compute the difference since the previous measurement. If the new value is less than the current
|
||||
// one, then it must be out-of-date. Again, just abort.
|
||||
allocated = allocation.allocatedBytes() - current.allocatedBytes();
|
||||
if (allocated <= 0) return;
|
||||
} while (!THREAD_ALLOCATION.compareAndSet(this, current, allocation));
|
||||
|
||||
metrics.observe(Metrics.JAVA_ALLOCATION, allocated);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submit() {
|
||||
var state = STATE.getAndUpdate(this, ExecutorState::enqueue);
|
||||
@ -918,14 +823,4 @@ public final class ComputerThread implements ComputerScheduler {
|
||||
return hasPendingWork();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocation information about a specific thread.
|
||||
*
|
||||
* @param threadId The ID of this thread.
|
||||
* @param allocatedBytes The amount of memory this thread has allocated.
|
||||
* @param time The time (in nanoseconds) when this time was computed.
|
||||
*/
|
||||
private record ThreadAllocation(long threadId, long allocatedBytes, long time) {
|
||||
}
|
||||
}
|
||||
|
@ -14,8 +14,6 @@ public final class Metrics {
|
||||
public static final Metric.Event COMPUTER_TASKS = new Metric.Event("computer_tasks", "ns", Metric::formatTime);
|
||||
public static final Metric.Event SERVER_TASKS = new Metric.Event("server_tasks", "ns", Metric::formatTime);
|
||||
|
||||
public static final Metric.Event JAVA_ALLOCATION = new Metric.Event("java_allocation", "bytes", Metric::formatBytes);
|
||||
|
||||
public static final Metric.Event PERIPHERAL_OPS = new Metric.Event("peripheral", "ns", Metric::formatTime);
|
||||
public static final Metric.Event FS_OPS = new Metric.Event("fs", "ns", Metric::formatTime);
|
||||
|
||||
|
@ -1,114 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.core.metrics;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.ThreadMXBean;
|
||||
|
||||
/**
|
||||
* Provides a way to get the memory allocated by a specific thread.
|
||||
* <p>
|
||||
* This uses Hotspot-specific functionality, so may not be available on all JVMs. Consumers should call
|
||||
* {@link #isSupported()} before calling more specific methods.
|
||||
*
|
||||
* @see com.sun.management.ThreadMXBean
|
||||
*/
|
||||
public final class ThreadAllocations {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ThreadAllocations.class);
|
||||
|
||||
private static final @Nullable MethodHandle threadAllocatedBytes;
|
||||
private static final @Nullable MethodHandle threadsAllocatedBytes;
|
||||
|
||||
static {
|
||||
MethodHandle threadAllocatedBytesHandle, threadsAllocatedBytesHandle;
|
||||
try {
|
||||
var threadMxBean = Class.forName("com.sun.management.ThreadMXBean").asSubclass(ThreadMXBean.class);
|
||||
var bean = ManagementFactory.getPlatformMXBean(threadMxBean);
|
||||
|
||||
// Enable allocation tracking.
|
||||
threadMxBean.getMethod("setThreadAllocatedMemoryEnabled", boolean.class).invoke(bean, true);
|
||||
|
||||
// Just probe this method once to check it doesn't error.
|
||||
threadMxBean.getMethod("getCurrentThreadAllocatedBytes").invoke(bean);
|
||||
|
||||
threadAllocatedBytesHandle = MethodHandles.publicLookup()
|
||||
.findVirtual(threadMxBean, "getThreadAllocatedBytes", MethodType.methodType(long.class, long.class))
|
||||
.bindTo(bean);
|
||||
threadsAllocatedBytesHandle = MethodHandles.publicLookup()
|
||||
.findVirtual(threadMxBean, "getThreadAllocatedBytes", MethodType.methodType(long[].class, long[].class))
|
||||
.bindTo(bean);
|
||||
} catch (LinkageError | ReflectiveOperationException | RuntimeException e) {
|
||||
LOG.warn("Cannot track allocated memory of computer threads", e);
|
||||
threadAllocatedBytesHandle = threadsAllocatedBytesHandle = null;
|
||||
}
|
||||
|
||||
threadAllocatedBytes = threadAllocatedBytesHandle;
|
||||
threadsAllocatedBytes = threadsAllocatedBytesHandle;
|
||||
}
|
||||
|
||||
private ThreadAllocations() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the current JVM provides information about per-thread allocations.
|
||||
*
|
||||
* @return Whether per-thread allocation information is available.
|
||||
*/
|
||||
public static boolean isSupported() {
|
||||
return threadAllocatedBytes != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an approximation the amount of memory a thread has allocated over its lifetime.
|
||||
*
|
||||
* @param threadId The ID of the thread.
|
||||
* @return The allocated memory, in bytes.
|
||||
* @see com.sun.management.ThreadMXBean#getThreadAllocatedBytes(long)
|
||||
*/
|
||||
public static long getAllocatedBytes(long threadId) {
|
||||
if (threadAllocatedBytes == null) {
|
||||
throw new UnsupportedOperationException("Allocated bytes are not supported");
|
||||
}
|
||||
|
||||
try {
|
||||
return (long) threadAllocatedBytes.invokeExact(threadId);
|
||||
} catch (Throwable t) {
|
||||
throw throwUnchecked0(t); // Should never occur, but if it does it's guaranteed to be a runtime exception.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an approximation the amount of memory a thread has allocated over its lifetime.
|
||||
* <p>
|
||||
* This is equivalent to calling {@link #getAllocatedBytes(long)} for each thread in {@code threadIds}.
|
||||
*
|
||||
* @param threadIds An array of thread IDs.
|
||||
* @return An array with the same length as {@code threadIds}, containing the allocated memory for each thread.
|
||||
* @see com.sun.management.ThreadMXBean#getThreadAllocatedBytes(long[])
|
||||
*/
|
||||
public static long[] getAllocatedBytes(long[] threadIds) {
|
||||
if (threadsAllocatedBytes == null) {
|
||||
throw new UnsupportedOperationException("Allocated bytes are not supported");
|
||||
}
|
||||
|
||||
try {
|
||||
return (long[]) threadsAllocatedBytes.invokeExact(threadIds);
|
||||
} catch (Throwable t) {
|
||||
throw throwUnchecked0(t); // Should never occur, but if it does it's guaranteed to be a runtime exception.
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "TypeParameterUnusedInFormals" })
|
||||
private static <T extends Throwable> T throwUnchecked0(Throwable t) throws T {
|
||||
throw (T) t;
|
||||
}
|
||||
}
|
@ -5,21 +5,22 @@
|
||||
package dan200.computercraft.core.computer.computerthread;
|
||||
|
||||
import dan200.computercraft.core.computer.TimeoutState;
|
||||
import dan200.computercraft.core.metrics.Metrics;
|
||||
import dan200.computercraft.core.metrics.ThreadAllocations;
|
||||
import dan200.computercraft.test.core.ConcurrentHelpers;
|
||||
import org.junit.jupiter.api.*;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.Timeout;
|
||||
import org.junit.jupiter.api.parallel.Execution;
|
||||
import org.junit.jupiter.api.parallel.ExecutionMode;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.hamcrest.Matchers.closeTo;
|
||||
import static org.hamcrest.Matchers.lessThanOrEqualTo;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@Timeout(value = 15)
|
||||
@ -91,21 +92,4 @@ public class ComputerThreadTest {
|
||||
|
||||
manager.startAndWait(computer);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllocationTracking() throws Exception {
|
||||
Assumptions.assumeTrue(ThreadAllocations.isSupported(), "Allocation tracking is supported");
|
||||
|
||||
var size = 1024 * 1024 * 64;
|
||||
var computer = manager.createWorker((executor, timeout) -> {
|
||||
// Allocate some slab of memory. We try to blackhole the allocated object, but it's pretty naive
|
||||
// so who knows how useful it'll be.
|
||||
assertNotEquals(0, Objects.toString(new byte[size]).length());
|
||||
});
|
||||
manager.startAndWait(computer);
|
||||
|
||||
assertThat(computer.getMetric(Metrics.JAVA_ALLOCATION), allOf(
|
||||
greaterThan((long) size), lessThan((long) (size + (size >> 2)))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user