sw_limits: extend API to "get remaining counts" before the limit is reached
authorGerhard Sittig <gerhard.sittig@gmx.net>
Tue, 12 Oct 2021 14:34:32 +0000 (16:34 +0200)
committerGerhard Sittig <gerhard.sittig@gmx.net>
Wed, 13 Oct 2021 16:09:11 +0000 (18:09 +0200)
The current sw_limits API provides routines which interface nicely with
config get/set and Glib data types, and which check whether a limit was
exceeded after previous submission of samples (summary result).

Device drivers may want to check _before_ a limit was reached, some may
want to cap to-get-submitted sample data such that a limit gets reached
but is not exceeded. This need becomes more obvious when devices with
efficient hardware compression "severely overshoot" the user specified
limits when the check is only done late after submission of another
chunk of data which results from uncompression.

Introduce an API routine which gets the remaining count until the limit
is reached. Phrase the implementation for cheapest cost of execution.
These routines may execute in tight loops in acquisition code paths.

src/libsigrok-internal.h
src/sw_limits.c

index 1960264c729fa9c86ac2841d9834ece20374c0a1..7a5b717d6d4c7482534a185fbb30ab67e48e2cb4 100644 (file)
@@ -2671,6 +2671,9 @@ SR_PRIV int sr_sw_limits_config_set(struct sr_sw_limits *limits, uint32_t key,
        GVariant *data);
 SR_PRIV void sr_sw_limits_acquisition_start(struct sr_sw_limits *limits);
 SR_PRIV gboolean sr_sw_limits_check(struct sr_sw_limits *limits);
+SR_PRIV int sr_sw_limits_get_remain(const struct sr_sw_limits *limits,
+       uint64_t *samples, uint64_t *frames, uint64_t *msecs,
+       gboolean *exceeded);
 SR_PRIV void sr_sw_limits_update_samples_read(struct sr_sw_limits *limits,
        uint64_t samples_read);
 SR_PRIV void sr_sw_limits_update_frames_read(struct sr_sw_limits *limits,
index 55ca79dafbb58ef53235e67254fd4670c9cd03f8..1a9c4c58e123145d6ed2015e3eb2677d7084b053 100644 (file)
@@ -165,6 +165,87 @@ SR_PRIV gboolean sr_sw_limits_check(struct sr_sw_limits *limits)
        return FALSE;
 }
 
+/**
+ * Get remaining counts until software limits are reached.
+ *
+ * This routine fills in those C language variables which callers
+ * requested, and provides the remaining value until a specified limit
+ * would be reached.
+ *
+ * The @ref sr_sw_limits_config_get() routine is suitable for rare
+ * configuration calls and interfaces nicely with Glib data types. The
+ * @ref sr_sw_limits_check() routine only provides a weak "exceeded"
+ * result. This @ref sr_sw_limits_get_remain() routine is suitable for
+ * additional checks and more eager limits enforcement in (potentially
+ * tight) acquisition code paths. Hardware compression may result in
+ * rather large "overshoots" when checks are done only late.
+ *
+ * @param[in] limits software limit instance
+ * @param[out] samples remaining samples count until the limit is reached
+ * @param[out] frames remaining frames count until the limit is reached
+ * @param[out] msecs remaining milliseconds until the limit is reached
+ *
+ * @return SR_ERR_* upon error, SR_OK otherwise
+ */
+SR_PRIV int sr_sw_limits_get_remain(const struct sr_sw_limits *limits,
+       uint64_t *samples, uint64_t *frames, uint64_t *msecs,
+       gboolean *exceeded)
+{
+
+       if (!limits)
+               return SR_ERR_ARG;
+
+       if (exceeded)
+               *exceeded = FALSE;
+
+       if (samples) do {
+               *samples = 0;
+               if (!limits->limit_samples)
+                       break;
+               if (limits->samples_read >= limits->limit_samples) {
+                       if (exceeded)
+                               *exceeded = TRUE;
+                       break;
+               }
+               *samples = limits->limit_samples - limits->samples_read;
+       } while (0);
+
+       if (frames) do {
+               *frames = 0;
+               if (!limits->limit_frames)
+                       break;
+               if (limits->frames_read >= limits->limit_frames) {
+                       if (exceeded)
+                               *exceeded = TRUE;
+                       break;
+               }
+               *frames = limits->limit_frames - limits->frames_read;
+       } while (0);
+
+       if (msecs) do {
+               guint64 now, elapsed, remain;
+
+               *msecs = 0;
+               if (!limits->limit_msec)
+                       break;
+               if (!limits->start_time)
+                       break;
+               now = g_get_monotonic_time();
+               if (now < limits->start_time)
+                       break;
+               elapsed = now - limits->start_time;
+               if (elapsed >= limits->limit_msec) {
+                       if (exceeded)
+                               *exceeded = TRUE;
+                       break;
+               }
+               remain = limits->limit_msec - elapsed;
+               *msecs = remain / 1000;
+       } while (0);
+
+       return SR_OK;
+}
+
 /**
  * Update the amount of samples that have been read
  *