Skip to content

Commit

Permalink
tx/pacing: add wide support (#281)
Browse files Browse the repository at this point in the history
use "--shaping wide" to enable wide sender.
Fix the rtp time stamp to not include the warmup pkts.
Also add vrx customization support, ex, use "--vrx 30" to set the vrx
buffer to 30 pkts for a wide pacing.

Signed-off-by: Frank Du <frank.du@intel.com>
  • Loading branch information
frankdjx committed May 22, 2023
1 parent edf06dc commit cea105f
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 54 deletions.
2 changes: 2 additions & 0 deletions app/src/app_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,8 @@ struct st_app_context {
struct st_app_tx_video_session* tx_video_sessions;
int tx_video_session_cnt;
int tx_video_rtp_ring_size; /* the ring size for tx video rtp type */
uint16_t tx_vrx;
enum st21_pacing tx_pacing_type;

struct st_app_tx_audio_session* tx_audio_sessions;
char tx_audio_url[ST_APP_URL_MAX_LEN];
Expand Down
17 changes: 17 additions & 0 deletions app/src/args.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ enum st_args_cmd {
ST22_ARG_RX_SESSIONS_CNT,
ST_ARG_HDR_SPLIT,
ST_ARG_PACING_WAY,
ST_ARG_VRX,
ST_ARG_SHAPING,

ST_ARG_CONFIG_FILE = 0x300,
ST_ARG_TEST_TIME,
Expand Down Expand Up @@ -144,6 +146,8 @@ static struct option st_app_args_options[] = {
{"rx_st22_sessions_count", required_argument, 0, ST22_ARG_RX_SESSIONS_CNT},
{"hdr_split", no_argument, 0, ST_ARG_HDR_SPLIT},
{"pacing_way", required_argument, 0, ST_ARG_PACING_WAY},
{"vrx", required_argument, 0, ST_ARG_VRX},
{"shaping", required_argument, 0, ST_ARG_SHAPING},

{"config_file", required_argument, 0, ST_ARG_CONFIG_FILE},
{"test_time", required_argument, 0, ST_ARG_TEST_TIME},
Expand Down Expand Up @@ -407,6 +411,19 @@ int st_app_parse_args(struct st_app_context* ctx, struct mtl_init_params* p, int
else
err("%s, unknow pacing way %s\n", __func__, optarg);
break;
case ST_ARG_VRX:
ctx->tx_vrx = atoi(optarg);
break;
case ST_ARG_SHAPING:
if (!strcmp(optarg, "narrow"))
ctx->tx_pacing_type = ST21_PACING_NARROW;
else if (!strcmp(optarg, "wide"))
ctx->tx_pacing_type = ST21_PACING_WIDE;
else if (!strcmp(optarg, "linear"))
ctx->tx_pacing_type = ST21_PACING_LINEAR;
else
err("%s, unknow shaping way %s\n", __func__, optarg);
break;
case ST_ARG_CONFIG_FILE:
app_args_json(ctx, p, optarg);
break;
Expand Down
3 changes: 2 additions & 1 deletion app/src/tx_video_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -707,7 +707,7 @@ static int app_tx_video_init(struct st_app_context* ctx, st_json_video_session_t
ops.flags |= ST20_TX_FLAG_USER_R_MAC;
}
}
ops.pacing = ST21_PACING_NARROW;
ops.pacing = ctx->tx_pacing_type;
ops.packing = video ? video->info.packing : ST20_PACKING_BPM;
ops.type = video ? video->info.type : ST20_TYPE_FRAME_LEVEL;
ops.width = video ? st_app_get_width(video->info.video_format) : 1920;
Expand All @@ -722,6 +722,7 @@ static int app_tx_video_init(struct st_app_context* ctx, st_json_video_session_t
ops.notify_event = app_tx_notify_event;
ops.framebuff_cnt = 2;
ops.payload_type = video ? video->base.payload_type : ST_APP_PAYLOAD_TYPE_VIDEO;
ops.vrx = ctx->tx_vrx;
if (s->enable_vsync) ops.flags |= ST20_TX_FLAG_ENABLE_VSYNC;

ret = st20_get_pgroup(ops.fmt, &s->st20_pg);
Expand Down
4 changes: 3 additions & 1 deletion doc/run.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,9 @@ For the supported parameters in the json, please refer to [JSON configuration gu
--nb_rx_desc <count> : debug option, number of receive descriptors for each NIC RX queue, affect the memory usage and the performance.
--tasklet_time : debug option, enable stat info for tasklet running time.
--tsc : debug option, force to use tsc pacing.
--pacing_way : debug option, set pacing way, ex, auto, rl, tsc, tsc_narrow, ptp, tsn.
--pacing_way <way> : debug option, set pacing way, available value: "auto", "rl", "tsc", "tsc_narrow", "ptp", "tsn".
--shaping <shaping> : debug option, set st21 shaping type, available value: "narrow", "wide".
--vrx <n> : debug option, set st21 vrx value, refer to st21 spec for possible vrx value.
--mono_pool : debug option, use mono pool for all tx and rx queues(sessions).
--tasklet_thread : debug option, run the tasklet under thread instead of a pinned lcore.
--tasklet_sleep : debug option, enable sleep if all tasklet report done status.
Expand Down
8 changes: 8 additions & 0 deletions include/st20_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,14 @@ struct st20_tx_ops {
* Valid if ST20_TX_FLAG_USER_P(R)_MAC is enabled
*/
uint8_t tx_dst_mac[MTL_SESSION_PORT_MAX][MTL_MAC_ADDR_LEN];
/**
* vrx buffer for tx.
* Leave to zero if not know detail, lib will assign vrx(narrow) based on resolution and
* timing.
* Refer to st21 spec for the possible vrx value, lib will follow this VRX if it's not a
* zero value, and also fine tune is required since network setup difference.
*/
uint16_t vrx;

/**
* the frame buffer count requested for one st20 tx session,
Expand Down
14 changes: 6 additions & 8 deletions lib/src/st2110/st_header.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,21 +141,19 @@ struct st_frame_trans {

/* timing for pacing */
struct st_tx_video_pacing {
double trs; /* in ns for of 2 consecutive packets, T-Frame / N-Packets */
double tr_offset; /* in ns, tr offset time of each frame */
uint32_t tr_offset_vrx; /* packets unit, VRX start value of each frame */
double frame_time; /* time of the frame in nanoseconds */
double trs; /* in ns for of 2 consecutive packets, T-Frame / N-Packets */
double tr_offset; /* in ns, tr offset time of each frame */
uint32_t vrx; /* packets unit, VRX start value of each frame */
uint32_t warm_pkts; /* packets unit, pkts for RL pacing warm boot */
double frame_time; /* time of the frame in nanoseconds */
double frame_time_sampling; /* time of the frame in sampling(90k) */
/* in ns, idle time at the end of frame, frame_time - tr_offset - (trs * pkts) */
double frame_idle_time;
uint32_t warm_pkts; /* pkts for RL pacing warm boot */
float pad_interval; /* padding pkt interval(pkts level) for RL pacing */

uint64_t cur_epochs; /* epoch of current frame */
/* timestamp for rtp header */
uint32_t rtp_time_stamp;
/* timestamp for pacing */
uint32_t pacing_time_stamp;
uint64_t cur_epoch_time;
double tsc_time_cursor; /* in ns, tsc time cursor for packet pacing */
double ptp_time_cursor; /* in ns, ptp time cursor for packet pacing */
Expand Down Expand Up @@ -439,7 +437,7 @@ struct st_rx_video_ebu_stat {
bool compliant_narrow;

/* Cinst, packet level check */
uint64_t cinmtl_initial_time;
uint64_t cinst_initial_time;
int32_t cinst_max;
int32_t cinst_min;
uint32_t cinst_cnt;
Expand Down
13 changes: 8 additions & 5 deletions lib/src/st2110/st_rx_video_session.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,9 +252,12 @@ static void rv_ebu_on_frame(struct st_rx_video_session_impl* s, uint32_t rtp_tms
if (!ebu_info->dropped_results) {
rv_ebu_result(s);
if (ebu_result->ebu_result_num) {
info("%s(%d), Compliance Rate Narrow %.2f%%, total %d narrow %d\n\n", __func__,
s->idx, rv_ebu_pass_rate(ebu_result, ebu_result->compliance_narrow),
ebu_result->ebu_result_num, ebu_result->compliance_narrow);
double pass_narrow = rv_ebu_pass_rate(ebu_result, ebu_result->compliance_narrow);
double pass_wide = rv_ebu_pass_rate(
ebu_result, ebu_result->compliance - ebu_result->compliance_narrow);
info("%s(%d), Compliance Rate Narrow %.2f%% Wide %.2f%%, total %d narrow %d\n\n",
__func__, s->idx, pass_narrow, pass_wide, ebu_result->ebu_result_num,
ebu_result->compliance_narrow);
}
} else {
if (ebu_result->ebu_result_num > ebu_info->dropped_results) {
Expand All @@ -268,7 +271,7 @@ static void rv_ebu_on_frame(struct st_rx_video_session_impl* s, uint32_t rtp_tms
ebu->cur_epochs = epochs;
ebu->vrx_drained_prev = 0;
ebu->vrx_prev = 0;
ebu->cinmtl_initial_time = pkt_tmstamp;
ebu->cinst_initial_time = pkt_tmstamp;
ebu->prev_rtp_ipt_ts = 0;

/* calculate fpt */
Expand Down Expand Up @@ -337,7 +340,7 @@ static void rv_ebu_on_packet(struct st_rx_video_session_impl* s, uint32_t rtp_tm

/* Calculate C-inst */
int exp_cin_pkts =
((pkt_tmstamp - ebu->cinmtl_initial_time) / trs) * ST_EBU_CINST_DRAIN_FACTOR;
((pkt_tmstamp - ebu->cinst_initial_time) / trs) * ST_EBU_CINST_DRAIN_FACTOR;
int cinst = RTE_MAX(0, pkt_idx - exp_cin_pkts);

ebu->cinst_sum += cinst;
Expand Down
101 changes: 62 additions & 39 deletions lib/src/st2110/st_tx_video_session.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,21 @@ static inline double pacing_time(struct st_tx_video_pacing* pacing, uint64_t epo

static inline double pacing_tr_offset_time(struct st_tx_video_pacing* pacing,
uint64_t epochs) {
return pacing_time(pacing, epochs) + pacing->tr_offset - (pacing->vrx * pacing->trs);
}

/* pacing start time(warmup pkt if has warmup stage) of the frame */
static inline double pacing_start_time(struct st_tx_video_pacing* pacing,
uint64_t epochs) {
return pacing_time(pacing, epochs) + pacing->tr_offset -
(pacing->tr_offset_vrx * pacing->trs);
((pacing->vrx + pacing->warm_pkts) * pacing->trs);
}

/* time stamp on the first pkt video pkt(not the warmup) */
static inline uint32_t pacing_time_stamp(struct st_tx_video_pacing* pacing,
uint64_t epochs) {
double tr_offset_time = pacing_tr_offset_time(pacing, epochs);
if (pacing->warm_pkts) tr_offset_time -= 3 * pacing->trs; /* deviation for VRX */
uint64_t tmstamp64 =
(tr_offset_time / pacing->frame_time) * pacing->frame_time_sampling;
uint32_t tmstamp32 = tmstamp64;
Expand Down Expand Up @@ -360,10 +368,10 @@ static int tv_init_pacing(struct mtl_main_impl* impl,
pacing->frame_time_sampling =
(double)(s->fps_tm.sampling_clock_rate) * s->fps_tm.den / s->fps_tm.mul;
double reactive = 1080.0 / 1125.0;

/* calculate tr offset */
pacing->tr_offset =
s->ops.height >= 1080 ? frame_time * (43.0 / 1125.0) : frame_time * (28.0 / 750.0);
pacing->tr_offset_vrx = s->st21_vrx_narrow;

if (s->ops.interlaced) {
if (s->ops.height <= 576)
reactive = (s->ops.height == 480) ? 487.0 / 525.0 : 576.0 / 625.0;
Expand Down Expand Up @@ -413,36 +421,55 @@ static int tv_init_pacing(struct mtl_main_impl* impl,
}
}

uint32_t troffset_warm_pkts = 0;
uint32_t pkts_in_tr_offset = pacing->tr_offset / pacing->trs;
/* calculate warmup pkts for rl */
uint32_t warm_pkts = 0;
if (s->pacing_way[MTL_SESSION_PORT_P] == ST21_TX_PACING_WAY_RL) {
/* 80 percent tr offset time as warmup pkts for rl */
troffset_warm_pkts = pacing->tr_offset / pacing->trs;
troffset_warm_pkts = troffset_warm_pkts * 8 / 10;
troffset_warm_pkts = RTE_MIN(troffset_warm_pkts, 128); /* limit to 128 pkts */
warm_pkts = pkts_in_tr_offset;
warm_pkts = warm_pkts * 8 / 10;
warm_pkts = RTE_MIN(warm_pkts, 128); /* limit to 128 pkts */
}
pacing->warm_pkts = troffset_warm_pkts;
pacing->tr_offset_vrx += troffset_warm_pkts; /* time for warm pkts */
pacing->warm_pkts = warm_pkts;

/* calculate vrx pkts */
pacing->vrx = s->st21_vrx_narrow;
if (s->pacing_way[MTL_SESSION_PORT_P] == ST21_TX_PACING_WAY_RL) {
pacing->tr_offset_vrx -= 2; /* VRX compensate to rl burst(max_burst_size=2048) */
pacing->tr_offset_vrx -= 2; /* leave VRX space for deviation */
pacing->vrx -= 2; /* VRX compensate to rl burst(max_burst_size=2048) */
pacing->vrx -= 2; /* leave VRX space for deviation */
if (s->ops.height <= 576) {
pacing->warm_pkts = 8; /* fix me */
pacing->tr_offset_vrx = s->st21_vrx_narrow;
pacing->vrx = s->st21_vrx_narrow;
}
} else if (s->pacing_way[MTL_SESSION_PORT_P] == ST21_TX_PACING_WAY_TSC_NARROW) {
/* tsc narrow use single bulk for better accuracy */
s->bulk = 1;
} else {
pacing->tr_offset_vrx -= (s->bulk - 1); /* compensate for bulk */
pacing->vrx -= (s->bulk - 1); /* compensate for bulk */
}

if (s->s_type == MT_ST22_HANDLE_TX_VIDEO) {
/* not sure the pacing for st22, none now */
pacing->tr_offset_vrx = 0;
pacing->vrx = 0;
pacing->warm_pkts = 0;
}
info("%s[%02d], trs %f trOffset %f warm pkts %u\n", __func__, idx, pacing->trs,
pacing->tr_offset, troffset_warm_pkts);
if (s->ops.vrx) {
if (s->ops.vrx >= pkts_in_tr_offset) {
err("%s[%02d], use vrx %u larger than pkts in tr offset %u\n", __func__, idx,
s->ops.vrx, pkts_in_tr_offset);
} else {
info("%s[%02d], use vrx %u from user\n", __func__, idx, s->ops.vrx);
pacing->vrx = s->ops.vrx;
}
} else if (s->ops.pacing == ST21_PACING_WIDE) {
uint32_t wide_vrx = pkts_in_tr_offset * 8 / 10;
uint32_t max_vrx = s->st21_vrx_wide * 8 / 10;
pacing->vrx = RTE_MIN(max_vrx, wide_vrx);
pacing->warm_pkts = 0; /* no need warmup for wide */
info("%s[%02d], wide pacing\n", __func__, idx);
}
info("%s[%02d], trs %f trOffset %f vrx %u warm_pkts %u\n", __func__, idx, pacing->trs,
pacing->tr_offset, pacing->vrx, pacing->warm_pkts);

/* resolve pacing tasklet */
for (int i = 0; i < num_port; i++) {
Expand Down Expand Up @@ -470,7 +497,6 @@ static int tv_sync_pacing(struct mtl_main_impl* impl, struct st_tx_video_session
uint64_t ptp_time = mt_get_ptp_time(impl, MTL_PORT_P);
uint64_t next_epochs = pacing->cur_epochs + 1;
uint64_t epochs;
double to_epoch_tr_offset;
bool interlaced = s->ops.interlaced;

if (required_tai) {
Expand Down Expand Up @@ -502,42 +528,39 @@ static int tv_sync_pacing(struct mtl_main_impl* impl, struct st_tx_video_session
}

/* epoch resolved */
double ptp_tr_offset_time = pacing_tr_offset_time(pacing, epochs);
to_epoch_tr_offset = ptp_tr_offset_time - ptp_time;
if (to_epoch_tr_offset < 0) {
/* time bigger than the assigned epoch troffset time */
dbg("%s(%d), to_epoch_tr_offset %f, ptp epochs %" PRIu64 " cur_epochs %" PRIu64
double start_time_ptp = pacing_start_time(pacing, epochs);
double to_epoch = start_time_ptp - ptp_time;
if (to_epoch < 0) {
/* time larger than the next assigned epoch time */
dbg("%s(%d), to_epoch %f, ptp epochs %" PRIu64 " cur_epochs %" PRIu64
", ptp_time %" PRIu64 "ms\n",
__func__, idx, to_epoch_tr_offset, epochs, pacing->cur_epochs,
ptp_time / 1000 / 1000);
__func__, idx, to_epoch, epochs, pacing->cur_epochs, ptp_time / 1000 / 1000);
s->stat_epoch_troffset_mismatch++;
epochs++; /* assign to next */
ptp_tr_offset_time = pacing_tr_offset_time(pacing, epochs);
to_epoch_tr_offset = ptp_tr_offset_time - ptp_time;
start_time_ptp = pacing_start_time(pacing, epochs);
to_epoch = start_time_ptp - ptp_time;
}

if (to_epoch_tr_offset < 0) {
if (to_epoch < 0) {
/* should never happen */
err("%s(%d), error to_epoch_tr_offset %f, ptp_time %" PRIu64 ", epochs %" PRIu64
" %" PRIu64 "\n",
__func__, idx, to_epoch_tr_offset, ptp_time, epochs, pacing->cur_epochs);
to_epoch_tr_offset = 0;
err("%s(%d), error to_epoch %f, ptp_time %" PRIu64 ", epochs %" PRIu64 " %" PRIu64
"\n",
__func__, idx, to_epoch, ptp_time, epochs, pacing->cur_epochs);
to_epoch = 0;
}

if (epochs > next_epochs) s->stat_epoch_drop += (epochs - next_epochs);
if (epochs < next_epochs) s->stat_epoch_onward += (next_epochs - epochs);
pacing->cur_epochs = epochs;
pacing->cur_epoch_time = pacing_time(pacing, epochs);
pacing->pacing_time_stamp = pacing_time_stamp(pacing, epochs);
pacing->rtp_time_stamp = pacing->pacing_time_stamp;
pacing->rtp_time_stamp = pacing_time_stamp(pacing, epochs);
dbg("%s(%d), old time_cursor %fms\n", __func__, idx,
pacing->tsc_time_cursor / 1000 / 1000);
pacing->tsc_time_cursor = (double)mt_get_tsc(impl) + to_epoch_tr_offset;
dbg("%s(%d), epochs %" PRIu64
" time_stamp %u time_cursor %fms to_epoch_tr_offset %fms\n",
__func__, idx, pacing->cur_epochs, pacing->pacing_time_stamp,
pacing->tsc_time_cursor / 1000 / 1000, to_epoch_tr_offset / 1000 / 1000);
pacing->ptp_time_cursor = ptp_tr_offset_time;
pacing->tsc_time_cursor = (double)mt_get_tsc(impl) + to_epoch;
dbg("%s(%d), epochs %" PRIu64 " time_stamp %u time_cursor %fms to_epoch %fms\n",
__func__, idx, pacing->cur_epochs, pacing->rtp_time_stamp,
pacing->tsc_time_cursor / 1000 / 1000, to_epoch / 1000 / 1000);
pacing->ptp_time_cursor = start_time_ptp;

if (sync) {
dbg("%s(%d), delay to epoch_time %f, cur %" PRIu64 "\n", __func__, idx,
Expand Down

0 comments on commit cea105f

Please sign in to comment.