This repository was archived by the owner on Jun 10, 2024. It is now read-only.
Repository navigation
This repository was archived by the owner on Jun 10, 2024. It is now read-only.
Continuous growth of CPU and memory #511
Copy link
Copy link
Open
Description
When I used SampleDecodeMultiThread. py for testing, the CPU usage and memory usage of the program continued to increase. Initially, it only occupied 300% CPU and 1.8G mem. After running for about ten minutes, it occupied 1000% CPU and 2.3G mem. I slightly modified the test script and read fifty video streams at the same time. I don't think it should consume so much resources.
Here is my code:
import PyNvCodec as nvc
# import numpy as np
import argparse
from threading import Thread
import threading
# import cv2
import time
class Worker(Thread):
def __init__(self, gpuID, encFile):
Thread.__init__(self)
self.st = time.time()
self.pt = time.time()
# Create Decoder with given CUDA context & stream.
self.nvDec = nvc.PyNvDecoder(encFile, gpuID)
self.width, self.height = self.nvDec.Width(), self.nvDec.Height()
# Determine colorspace conversion parameters.
# Some video streams don't specify these parameters so default values
# are most widespread bt601 and mpeg.
cspace, crange = self.nvDec.ColorSpace(), self.nvDec.ColorRange()
if nvc.ColorSpace.UNSPEC == cspace:
cspace = nvc.ColorSpace.BT_601
if nvc.ColorRange.UDEF == crange:
crange = nvc.ColorRange.MPEG
self.cc_ctx = nvc.ColorspaceConversionContext(cspace, crange)
# print("Color space: ", str(cspace))
# print("Color range: ", str(crange))
# Initialize colorspace conversion chain
if self.nvDec.ColorSpace() != nvc.ColorSpace.BT_709:
self.nvYuv = nvc.PySurfaceConverter(
self.width,
self.height,
self.nvDec.Format(),
nvc.PixelFormat.YUV420,
0
)
else:
self.nvYuv = None
if self.nvYuv:
self.nvCvt = nvc.PySurfaceConverter(
self.width,
self.height,
self.nvYuv.Format(),
nvc.PixelFormat.BGR,
0
)
else:
self.nvCvt = nvc.PySurfaceConverter(
self.width,
self.height,
self.nvDec.Format(),
nvc.PixelFormat.BGR,
0
)
# # resize
# self.nvRes = nvc.PySurfaceResizer(
# hwidth, hheight, self.nvCvt.Format(), 0
# )
# self.nvDwn = nvc.PySurfaceDownloader(
# hwidth, hheight, self.nvRes.Format(), 0
# )
self.nvDwn = nvc.PySurfaceDownloader(
self.width, self.height, self.nvCvt.Format(), 0
)
self.num_frame = 0
def run(self):
try:
while True:
try:
self.rawSurface = self.nvDec.DecodeSingleSurface()
if self.rawSurface.Empty():
print("No more video frames")
break
except nvc.HwResetException:
print("Continue after HW decoder was reset")
continue
if 0 == self.num_frame % 5:
if self.nvYuv:
self.yuvSurface = self.nvYuv.Execute(self.rawSurface, self.cc_ctx)
self.cvtSurface = self.nvCvt.Execute(self.yuvSurface, self.cc_ctx)
else:
self.cvtSurface = self.nvCvt.Execute(self.rawSurface, self.cc_ctx)
if self.cvtSurface.Empty():
print("Failed to do color conversion")
break
# self.resSurface = self.nvRes.Execute(self.cvtSurface)
# if self.resSurface.Empty():
# print("Failed to resize surface")
# break
# self.rawFrame = np.ndarray(
# shape=(self.cvtSurface.HostSize()), dtype=np.uint8
# )
# success = self.nvDwn.DownloadSingleSurface(
# self.cvtSurface, self.rawFrame
# )
#
# if not (success):
# print("Failed to download surface")
# break
# print(self.rawFrame.shape)
# self.rawFrame = self.rawFrame.reshape((self.height, self.width, 3))
# cv2.imwrite('test.png', self.rawFrame)
# break
# print(f"Thread {self.ident} at frame {self.num_frame}")
if time.time() - self.pt > 5:
self.pt = time.time()
print(f"Thread {threading.current_thread().name} fps {self.num_frame / (time.time() - self.st)}")
self.num_frame += 1
except Exception as e:
print(getattr(e, "message", str(e)))
def create_threads(gpu_id, input_file, num_threads):
thread_pool = []
for i in range(0, num_threads):
thread = Worker(gpu_id, input_file)
thread.start()
thread_pool.append(thread)
for thread in thread_pool:
thread.join()
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='frame decode')
parser.add_argument('--nums', type=int, default=50, help="stream nums")
parser.add_argument('--gpu', type=int, default=0, help="gpu id")
args = parser.parse_args()
stream = '*******' # This is my video streaming address, sorry I cannot disclose it.
create_threads(args.gpu, stream, args.nums)Metadata
Metadata
Assignees
Labels
No labels
Activity
david-molnar-oculai commentedon Aug 31, 2023
We're using the decoder and encoder and run them continuously to process a stream of 4 second clips. The memory and cpu doesn't increase, it stays constant. We used https://github.com/NVIDIA/VideoProcessingFramework/blob/master/samples/SamplePyTorch.py as a base. Also, more streams are processed on the same machine, using different threads in the same process.