Skip to content
This repository has been archived by the owner on Jun 10, 2024. It is now read-only.

Continuous growth of CPU and memory #511

Open
liujiachang opened this issue Aug 7, 2023 · 1 comment
Open

Continuous growth of CPU and memory #511

liujiachang opened this issue Aug 7, 2023 · 1 comment

Comments

@liujiachang
Copy link

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)
@david-molnar-oculai
Copy link

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.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants