diff mbox

[FFmpeg-devel] avcodec/qsv: polling free synchronization

Message ID 1570627691-9464-2-git-send-email-dmitry.v.rogozhkin@intel.com
State New
Headers show

Commit Message

Rogozhkin, Dmitry V Oct. 9, 2019, 1:28 p.m. UTC
From: Andrey Orlov <andrey.orlov@intel.com>

synchronization by sync point after DEVICE_BUSY

Fixes: CPU usage on AVC decode cases (18% -> 9%)
---
 libavcodec/qsv.c          | 17 +++++++++++++++++
 libavcodec/qsv_internal.h |  2 ++
 libavcodec/qsvdec.c       | 12 ++++++++----
 libavcodec/qsvdec.h       |  2 ++
 libavcodec/qsvenc.c       | 13 +++++++++----
 libavcodec/qsvenc.h       |  2 ++
 6 files changed, 40 insertions(+), 8 deletions(-)

Comments

Rogozhkin, Dmitry V Oct. 9, 2019, 9:45 p.m. UTC | #1
On Wed, 2019-10-09 at 06:28 -0700, Dmitry Rogozhkin wrote:
> From: Andrey Orlov <andrey.orlov@intel.com>

> 

> synchronization by sync point after DEVICE_BUSY

> 

> Fixes: CPU usage on AVC decode cases (18% -> 9%)


I would expect a link or reference to the bug following "Fixes:". If
you don't have it - just a text what is getting fixed. As Zhong pointed
out it would be nice to clarify which codecs other than AVC are
actually affected.

In the code below I see your change affecting decoding and encoding.
What about VP? Should similar change be done there (if yes - in
separate patch)?

> ---

>  libavcodec/qsv.c          | 17 +++++++++++++++++

>  libavcodec/qsv_internal.h |  2 ++

>  libavcodec/qsvdec.c       | 12 ++++++++----

>  libavcodec/qsvdec.h       |  2 ++

>  libavcodec/qsvenc.c       | 13 +++++++++----

>  libavcodec/qsvenc.h       |  2 ++

>  6 files changed, 40 insertions(+), 8 deletions(-)

> 

> diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c

> index b00e427..4b5018b 100644

> --- a/libavcodec/qsv.c

> +++ b/libavcodec/qsv.c

> @@ -32,6 +32,7 @@

>  #include "libavutil/hwcontext_qsv.h"

>  #include "libavutil/imgutils.h"

>  #include "libavutil/avassert.h"

> +#include "libavutil/time.h"

>  

>  #include "avcodec.h"

>  #include "qsv_internal.h"

> @@ -852,3 +853,19 @@ int ff_qsv_close_internal_session(QSVSession

> *qs)

>  #endif

>      return 0;

>  }

> +

> +void ff_qsv_handle_device_busy(mfxSession *session, mfxSyncPoint

> *sync, mfxStatus *ret, unsigned sleep)


Why pass return value in parameter when you have a legacy way? I think
function prototype should be:

int ff_qsv_handle_device_busy(mfxSession *session, mfxSyncPoint *sync,
unsigned int timeout)

> +{

> +    int sync_ret;

Just 'ret', I think.

> +

> +    if (*sync) {

> +        sync_ret = MFXVideoCORE_SyncOperation(*session, *sync,

> MFX_INFINITE);

> +        if (sync_ret == MFX_ERR_NONE) {

> +            *sync = NULL;

> +        } else {

> +            *ret = MFX_ERR_ABORTED;

This masks real error which you get from the call above - just return
it directly.

> +        }

> +    } else {

> +        av_usleep(sleep);

> +    }

> +}

> diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h

> index 3755927..01c98cc 100644

> --- a/libavcodec/qsv_internal.h

> +++ b/libavcodec/qsv_internal.h

> @@ -141,4 +141,6 @@ int ff_qsv_init_session_frames(AVCodecContext

> *avctx, mfxSession *session,

>  

>  int ff_qsv_find_surface_idx(QSVFramesContext *ctx, QSVFrame *frame);

>  

> +void ff_qsv_handle_device_busy(mfxSession *session, mfxSyncPoint

> *sync, mfxStatus *ret, unsigned sleep);

> +

>  #endif /* AVCODEC_QSV_INTERNAL_H */

> diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c

> index ae50239..aa83272 100644

> --- a/libavcodec/qsvdec.c

> +++ b/libavcodec/qsvdec.c

> @@ -457,8 +457,12 @@ static int qsv_decode(AVCodecContext *avctx,

> QSVContext *q,

>  

>          ret = MFXVideoDECODE_DecodeFrameAsync(q->session, avpkt-

> >size ? &bs : NULL,

>                                                insurf, &outsurf,

> sync);

> +

> +        if (ret == MFX_ERR_NONE)

> +            q->last_dec_sync = *sync;

> +

>          if (ret == MFX_WRN_DEVICE_BUSY)

> -            av_usleep(500);

> +            ff_qsv_handle_device_busy(&q->session, &q-

> >last_dec_sync, &ret, 500);

>  

>      } while (ret == MFX_WRN_DEVICE_BUSY || ret ==

> MFX_ERR_MORE_SURFACE);

>  

> @@ -510,9 +514,9 @@ static int qsv_decode(AVCodecContext *avctx,

> QSVContext *q,

>          out_frame->queued = 0;

>  

>          if (avctx->pix_fmt != AV_PIX_FMT_QSV) {

> -            do {

> -                ret = MFXVideoCORE_SyncOperation(q->session, *sync,

> 1000);

> -            } while (ret == MFX_WRN_IN_EXECUTION);

> +            ret = MFXVideoCORE_SyncOperation(q->session, *sync,

> MFX_INFINITE);

> +            if (ret < 0)

> +                return ret;


This change is not the primary goal of the patch, so I suggest to put
it in a separate patch if you believe it is needed. From my perspective
you change is LGTM.

>          }

>  

>          av_freep(&sync);

> diff --git a/libavcodec/qsvdec.h b/libavcodec/qsvdec.h

> index dec1f61..d27ea68 100644

> --- a/libavcodec/qsvdec.h

> +++ b/libavcodec/qsvdec.h

> @@ -72,6 +72,8 @@ typedef struct QSVContext {

>  

>      mfxExtBuffer **ext_buffers;

>      int         nb_ext_buffers;

> +

> +    mfxSyncPoint last_dec_sync;

>  } QSVContext;

>  

>  extern const AVCodecHWConfigInternal *ff_qsv_hw_configs[];

> diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c

> index ba85d64..bd5dd75 100644

> --- a/libavcodec/qsvenc.c

> +++ b/libavcodec/qsvenc.c

> @@ -1368,8 +1368,13 @@ static int encode_frame(AVCodecContext *avctx,

> QSVEncContext *q,

>  

>      do {

>          ret = MFXVideoENCODE_EncodeFrameAsync(q->session, enc_ctrl,

> surf, bs, sync);

> +

> +        if (ret == MFX_ERR_NONE)

> +            q->last_enc_sync = *sync;

> +

>          if (ret == MFX_WRN_DEVICE_BUSY)

> -            av_usleep(500);

> +            ff_qsv_handle_device_busy(&q->session, &q-

> >last_enc_sync, &ret, 500);

> +

>      } while (ret == MFX_WRN_DEVICE_BUSY || ret ==

> MFX_WRN_IN_EXECUTION);

>  

>      if (ret > 0)

> @@ -1435,9 +1440,9 @@ int ff_qsv_encode(AVCodecContext *avctx,

> QSVEncContext *q,

>          av_fifo_generic_read(q->async_fifo,

> &sync,    sizeof(sync),    NULL);

>          av_fifo_generic_read(q->async_fifo,

> &bs,      sizeof(bs),      NULL);

>  

> -        do {

> -            ret = MFXVideoCORE_SyncOperation(q->session, *sync,

> 1000);

> -        } while (ret == MFX_WRN_IN_EXECUTION);

> +        ret = MFXVideoCORE_SyncOperation(q->session, *sync,

> MFX_INFINITE);

> +        if (ret < 0)

> +            return ret;


Same as above - separate patch.

>  

>          new_pkt.dts  = av_rescale_q(bs->DecodeTimeStamp,

> (AVRational){1, 90000}, avctx->time_base);

>          new_pkt.pts  = av_rescale_q(bs-

> >TimeStamp,       (AVRational){1, 90000}, avctx->time_base);

> diff --git a/libavcodec/qsvenc.h b/libavcodec/qsvenc.h

> index ec8b541..f1c22d7 100644

> --- a/libavcodec/qsvenc.h

> +++ b/libavcodec/qsvenc.h

> @@ -185,6 +185,8 @@ typedef struct QSVEncContext {

>      char *load_plugins;

>      SetEncodeCtrlCB *set_encode_ctrl_cb;

>      int forced_idr;

> +

> +    mfxSyncPoint last_enc_sync;

>  } QSVEncContext;

>  

>  int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q);
Fu, Linjie Oct. 10, 2019, 2:45 a.m. UTC | #2
> -----Original Message-----

> From: ffmpeg-devel <ffmpeg-devel-bounces@ffmpeg.org> On Behalf Of

> Dmitry Rogozhkin

> Sent: Wednesday, October 9, 2019 21:28

> To: ffmpeg-devel@ffmpeg.org

> Cc: Orlov, Andrey <andrey.orlov@intel.com>

> Subject: [FFmpeg-devel] [PATCH] avcodec/qsv: polling free synchronization

> 

> From: Andrey Orlov <andrey.orlov@intel.com>

> 

> synchronization by sync point after DEVICE_BUSY

> 

> Fixes: CPU usage on AVC decode cases (18% -> 9%)

> ---

>  libavcodec/qsv.c          | 17 +++++++++++++++++

>  libavcodec/qsv_internal.h |  2 ++

>  libavcodec/qsvdec.c       | 12 ++++++++----

>  libavcodec/qsvdec.h       |  2 ++

>  libavcodec/qsvenc.c       | 13 +++++++++----

>  libavcodec/qsvenc.h       |  2 ++

>  6 files changed, 40 insertions(+), 8 deletions(-)

> --- a/libavcodec/qsvdec.c

> +++ b/libavcodec/qsvdec.c

> @@ -457,8 +457,12 @@ static int qsv_decode(AVCodecContext *avctx,

> QSVContext *q,

> 

>          ret = MFXVideoDECODE_DecodeFrameAsync(q->session, avpkt->size ?

> &bs : NULL,

>                                                insurf, &outsurf, sync);

> +

> +        if (ret == MFX_ERR_NONE)

> +            q->last_dec_sync = *sync;

> +

>          if (ret == MFX_WRN_DEVICE_BUSY)

> -            av_usleep(500);


Since av_usleep is removed, "libavutil/time.h" is redundant and should be removed as well.

> +            ff_qsv_handle_device_busy(&q->session, &q->last_dec_sync, &ret,

> 500);


If the value of sleep is hardcode to 500, is it still necessary to pass it as a parameter?

> 

>      } while (ret == MFX_WRN_DEVICE_BUSY || ret ==

> MFX_ERR_MORE_SURFACE);

> 

> @@ -510,9 +514,9 @@ static int qsv_decode(AVCodecContext *avctx,

> QSVContext *q,

>          out_frame->queued = 0;

> 

>          if (avctx->pix_fmt != AV_PIX_FMT_QSV) {

> -            do {

> -                ret = MFXVideoCORE_SyncOperation(q->session, *sync, 1000);

> -            } while (ret == MFX_WRN_IN_EXECUTION);

> +            ret = MFXVideoCORE_SyncOperation(q->session, *sync,

> MFX_INFINITE);

> +            if (ret < 0)

> +                return ret;

>          }

> 

>          av_freep(&sync);

> diff --git a/libavcodec/qsvdec.h b/libavcodec/qsvdec.h

> index dec1f61..d27ea68 100644

> --- a/libavcodec/qsvdec.h

> +++ b/libavcodec/qsvdec.h

> @@ -72,6 +72,8 @@ typedef struct QSVContext {

> 

>      mfxExtBuffer **ext_buffers;

>      int         nb_ext_buffers;

> +

> +    mfxSyncPoint last_dec_sync;

>  } QSVContext;

> 

>  extern const AVCodecHWConfigInternal *ff_qsv_hw_configs[];

> diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c

> index ba85d64..bd5dd75 100644

> --- a/libavcodec/qsvenc.c

> +++ b/libavcodec/qsvenc.c

> @@ -1368,8 +1368,13 @@ static int encode_frame(AVCodecContext *avctx,

> QSVEncContext *q,

> 

>      do {

>          ret = MFXVideoENCODE_EncodeFrameAsync(q->session, enc_ctrl, surf,

> bs, sync);

> +

> +        if (ret == MFX_ERR_NONE)

> +            q->last_enc_sync = *sync;

> +

>          if (ret == MFX_WRN_DEVICE_BUSY)

> -            av_usleep(500);


Same here.

- linjie
diff mbox

Patch

diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c
index b00e427..4b5018b 100644
--- a/libavcodec/qsv.c
+++ b/libavcodec/qsv.c
@@ -32,6 +32,7 @@ 
 #include "libavutil/hwcontext_qsv.h"
 #include "libavutil/imgutils.h"
 #include "libavutil/avassert.h"
+#include "libavutil/time.h"
 
 #include "avcodec.h"
 #include "qsv_internal.h"
@@ -852,3 +853,19 @@  int ff_qsv_close_internal_session(QSVSession *qs)
 #endif
     return 0;
 }
+
+void ff_qsv_handle_device_busy(mfxSession *session, mfxSyncPoint *sync, mfxStatus *ret, unsigned sleep)
+{
+    int sync_ret;
+
+    if (*sync) {
+        sync_ret = MFXVideoCORE_SyncOperation(*session, *sync, MFX_INFINITE);
+        if (sync_ret == MFX_ERR_NONE) {
+            *sync = NULL;
+        } else {
+            *ret = MFX_ERR_ABORTED;
+        }
+    } else {
+        av_usleep(sleep);
+    }
+}
diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h
index 3755927..01c98cc 100644
--- a/libavcodec/qsv_internal.h
+++ b/libavcodec/qsv_internal.h
@@ -141,4 +141,6 @@  int ff_qsv_init_session_frames(AVCodecContext *avctx, mfxSession *session,
 
 int ff_qsv_find_surface_idx(QSVFramesContext *ctx, QSVFrame *frame);
 
+void ff_qsv_handle_device_busy(mfxSession *session, mfxSyncPoint *sync, mfxStatus *ret, unsigned sleep);
+
 #endif /* AVCODEC_QSV_INTERNAL_H */
diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c
index ae50239..aa83272 100644
--- a/libavcodec/qsvdec.c
+++ b/libavcodec/qsvdec.c
@@ -457,8 +457,12 @@  static int qsv_decode(AVCodecContext *avctx, QSVContext *q,
 
         ret = MFXVideoDECODE_DecodeFrameAsync(q->session, avpkt->size ? &bs : NULL,
                                               insurf, &outsurf, sync);
+
+        if (ret == MFX_ERR_NONE)
+            q->last_dec_sync = *sync;
+
         if (ret == MFX_WRN_DEVICE_BUSY)
-            av_usleep(500);
+            ff_qsv_handle_device_busy(&q->session, &q->last_dec_sync, &ret, 500);
 
     } while (ret == MFX_WRN_DEVICE_BUSY || ret == MFX_ERR_MORE_SURFACE);
 
@@ -510,9 +514,9 @@  static int qsv_decode(AVCodecContext *avctx, QSVContext *q,
         out_frame->queued = 0;
 
         if (avctx->pix_fmt != AV_PIX_FMT_QSV) {
-            do {
-                ret = MFXVideoCORE_SyncOperation(q->session, *sync, 1000);
-            } while (ret == MFX_WRN_IN_EXECUTION);
+            ret = MFXVideoCORE_SyncOperation(q->session, *sync, MFX_INFINITE);
+            if (ret < 0)
+                return ret;
         }
 
         av_freep(&sync);
diff --git a/libavcodec/qsvdec.h b/libavcodec/qsvdec.h
index dec1f61..d27ea68 100644
--- a/libavcodec/qsvdec.h
+++ b/libavcodec/qsvdec.h
@@ -72,6 +72,8 @@  typedef struct QSVContext {
 
     mfxExtBuffer **ext_buffers;
     int         nb_ext_buffers;
+
+    mfxSyncPoint last_dec_sync;
 } QSVContext;
 
 extern const AVCodecHWConfigInternal *ff_qsv_hw_configs[];
diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c
index ba85d64..bd5dd75 100644
--- a/libavcodec/qsvenc.c
+++ b/libavcodec/qsvenc.c
@@ -1368,8 +1368,13 @@  static int encode_frame(AVCodecContext *avctx, QSVEncContext *q,
 
     do {
         ret = MFXVideoENCODE_EncodeFrameAsync(q->session, enc_ctrl, surf, bs, sync);
+
+        if (ret == MFX_ERR_NONE)
+            q->last_enc_sync = *sync;
+
         if (ret == MFX_WRN_DEVICE_BUSY)
-            av_usleep(500);
+            ff_qsv_handle_device_busy(&q->session, &q->last_enc_sync, &ret, 500);
+
     } while (ret == MFX_WRN_DEVICE_BUSY || ret == MFX_WRN_IN_EXECUTION);
 
     if (ret > 0)
@@ -1435,9 +1440,9 @@  int ff_qsv_encode(AVCodecContext *avctx, QSVEncContext *q,
         av_fifo_generic_read(q->async_fifo, &sync,    sizeof(sync),    NULL);
         av_fifo_generic_read(q->async_fifo, &bs,      sizeof(bs),      NULL);
 
-        do {
-            ret = MFXVideoCORE_SyncOperation(q->session, *sync, 1000);
-        } while (ret == MFX_WRN_IN_EXECUTION);
+        ret = MFXVideoCORE_SyncOperation(q->session, *sync, MFX_INFINITE);
+        if (ret < 0)
+            return ret;
 
         new_pkt.dts  = av_rescale_q(bs->DecodeTimeStamp, (AVRational){1, 90000}, avctx->time_base);
         new_pkt.pts  = av_rescale_q(bs->TimeStamp,       (AVRational){1, 90000}, avctx->time_base);
diff --git a/libavcodec/qsvenc.h b/libavcodec/qsvenc.h
index ec8b541..f1c22d7 100644
--- a/libavcodec/qsvenc.h
+++ b/libavcodec/qsvenc.h
@@ -185,6 +185,8 @@  typedef struct QSVEncContext {
     char *load_plugins;
     SetEncodeCtrlCB *set_encode_ctrl_cb;
     int forced_idr;
+
+    mfxSyncPoint last_enc_sync;
 } QSVEncContext;
 
 int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q);