Я пишу программу, которая требует конвейерной передачи тензоров графического процессора между процессами.
Я знал, что использование torch.Multiprocessing автоматически получит для меня CudaIpcMemHandle и отправит его через канал под капотом Multiprocessing.Queue.
Я хотел измерить задержку каждого элемента, проходящего через очередь.
Я реализовал этот код main_high.py :
Этот метод заключается в том, что когда производитель помещает элемент в очередь, он также добавляет временную метку time.perf_counter_ns() в кортеж, отправляемый через очередь.
Обычно IPC с Pipes не должен занимать сотни миллисекунд. Итак, я нашел еще одну тему переполнения стека, которая также измеряет этот компонент.
Вот воспроизводимый фрагмент main_low.py
Я не могу придумать какой-либо конкретной причины, почему должна быть такая огромная разница в измерениях.
В любом случае должна быть временная метка, отправляемая через mp.Queue. Таким образом, проблема не должна заключаться в выборе целого числа временной метки.
Еще одно сомнение заключается в том, что часы между процессами не синхронизированы. Но я проверил, что time.perf_counter_ns() использует CLOCK_MONOTONIC. Так что точность не должна быть такой высокой.
Я пишу программу, которая требует конвейерной передачи тензоров графического процессора между процессами. Я знал, что использование torch.Multiprocessing автоматически получит для меня CudaIpcMemHandle и отправит его через канал под капотом Multiprocessing.Queue. Я хотел измерить задержку каждого элемента, проходящего через очередь. Я реализовал этот код main_high.py : Этот метод заключается в том, что когда производитель помещает элемент в очередь, он также добавляет временную метку time.perf_counter_ns() в кортеж, отправляемый через очередь. [code]import csv import os import time from typing import Dict, List, Tuple
import torch import torch.multiprocessing as mp
def producer(queue: mp.Queue, num_items: int) -> None: # float32 uses 4 bytes per element -> 5 MiB tensor. num_elements = (5 * 1024 * 1024) // 4 tensor_bytes = num_elements * torch.tensor([], dtype=torch.float32).element_size() print(f"[producer] creating a new tensor per item, size={tensor_bytes} bytes")
for item_index in range(num_items): tensor = torch.rand(num_elements, dtype=torch.float32, device="cuda") # Ensure tensor materialization is complete before starting transfer timing. torch.cuda.synchronize()
with open("latencies_high.csv", "w", newline="") as f: writer = csv.writer(f) writer.writerow(["item_index", "latency_ms"]) for item_index, latency_ms in sorted(latencies_ms.items()): writer.writerow([item_index, latency_ms])
if __name__ == "__main__": main() [/code] Проблема в том, что измеренная задержка каждого элемента очень велика: [code]item_index,latency_ms 0,130.301841 1,128.7352 2,128.617645 3,128.545633 . . . 48,127.844094 49,127.786926 [/code] Обычно IPC с Pipes не должен занимать сотни миллисекунд. Итак, я нашел еще одну тему переполнения стека, которая также измеряет этот компонент. Вот воспроизводимый фрагмент main_low.py [code]import csv import os import time from typing import Dict, List, Tuple
with open("latencies_low.csv", "w", newline="") as f: writer = csv.writer(f) writer.writerow(["item_index", "latency_ms"]) for item_index, latency_ms in sorted(latencies_ms.items()): writer.writerow([item_index, latency_ms])
if __name__ == "__main__": main() [/code] И результаты оказались более точными: [code]item_index,latency_ms 0,106.522214 1,0.569158 2,0.391128 3,0.333409 . . . 47,0.310437 48,0.306123 49,0.307088 [/code] Вот мои проблемы с этой разницей: [list] [*]Я не могу придумать какой-либо конкретной причины, почему должна быть такая огромная разница в измерениях.
[*]В любом случае должна быть временная метка, отправляемая через mp.Queue. Таким образом, проблема не должна заключаться в выборе целого числа временной метки.
[*]Еще одно сомнение заключается в том, что часы между процессами не синхронизированы. Но я проверил, что time.perf_counter_ns() использует CLOCK_MONOTONIC. Так что точность не должна быть такой высокой.