mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-31 13:42:59 +00:00 
			
		
		
		
	Remove allocation tracking for computers
Reverts 76968f2f28. 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:
		| @@ -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))) | ||||
|         )); | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jonathan Coates
					Jonathan Coates