• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 #ifdef HAVE_CONFIG_H
3 #include "config.h"
4 #endif
5 
6 #ifdef HAVE_GETRUSAGE
7 #include "gst-cpu-throttling-clock.h"
8 
9 #include <unistd.h>
10 #include <sys/resource.h>
11 
12 #include "gst-cpu-throttling-clock.h"
13 
14 /**
15  * SECTION: gst-cpu-throttling-clock
16  * @title: GstCpuThrottlingClock
17  * @short_description: TODO
18  *
19  * TODO
20  */
21 
22 /* *INDENT-OFF* */
23 GST_DEBUG_CATEGORY_STATIC (gst_cpu_throttling_clock_debug);
24 #define GST_CAT_DEFAULT gst_cpu_throttling_clock_debug
25 
26 struct _GstCpuThrottlingClockPrivate
27 {
28   guint wanted_cpu_usage;
29 
30   GstClock *sclock;
31   GstClockTime current_wait_time;
32   GstPoll *timer;
33   struct rusage last_usage;
34 
35   GstClockID evaluate_wait_time;
36   GstClockTime time_between_evals;
37 };
38 
39 #define parent_class gst_cpu_throttling_clock_parent_class
40 G_DEFINE_TYPE_WITH_CODE (GstCpuThrottlingClock, gst_cpu_throttling_clock, GST_TYPE_CLOCK, G_ADD_PRIVATE(GstCpuThrottlingClock))
41 
42 enum
43 {
44   PROP_FIRST,
45   PROP_CPU_USAGE,
46   PROP_LAST
47 };
48 
49 static GParamSpec *param_specs[PROP_LAST] = { NULL, };
50 /* *INDENT-ON* */
51 
52 static void
gst_cpu_throttling_clock_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)53 gst_cpu_throttling_clock_get_property (GObject * object,
54     guint property_id, GValue * value, GParamSpec * pspec)
55 {
56   GstCpuThrottlingClock *self = GST_CPU_THROTTLING_CLOCK (object);
57 
58   switch (property_id) {
59     case PROP_CPU_USAGE:
60       g_value_set_uint (value, self->priv->wanted_cpu_usage);
61       break;
62     default:
63       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
64       break;
65   }
66 }
67 
68 static void
gst_cpu_throttling_clock_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)69 gst_cpu_throttling_clock_set_property (GObject * object,
70     guint property_id, const GValue * value, GParamSpec * pspec)
71 {
72   GstCpuThrottlingClock *self = GST_CPU_THROTTLING_CLOCK (object);
73 
74   switch (property_id) {
75     case PROP_CPU_USAGE:
76       self->priv->wanted_cpu_usage = g_value_get_uint (value);
77       if (self->priv->wanted_cpu_usage == 0)
78         self->priv->wanted_cpu_usage = 100;
79       break;
80     default:
81       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
82       break;
83   }
84 }
85 
86 static gboolean
gst_transcoder_adjust_wait_time(GstClock * sync_clock,GstClockTime time,GstClockID id,GstCpuThrottlingClock * self)87 gst_transcoder_adjust_wait_time (GstClock * sync_clock, GstClockTime time,
88     GstClockID id, GstCpuThrottlingClock * self)
89 {
90   struct rusage ru;
91   float delta_usage, usage, coef;
92 
93   GstCpuThrottlingClockPrivate *priv = self->priv;
94 
95   getrusage (RUSAGE_SELF, &ru);
96   delta_usage = GST_TIMEVAL_TO_TIME (ru.ru_utime) -
97       GST_TIMEVAL_TO_TIME (self->priv->last_usage.ru_utime);
98   usage =
99       ((float) delta_usage / self->priv->time_between_evals * 100) /
100       g_get_num_processors ();
101 
102   self->priv->last_usage = ru;
103 
104   coef = GST_MSECOND / 10;
105   if (usage < (gfloat) priv->wanted_cpu_usage) {
106     coef = -coef;
107   }
108 
109   priv->current_wait_time = CLAMP (0,
110       (GstClockTime) priv->current_wait_time + coef, GST_SECOND);
111 
112   GST_DEBUG_OBJECT (self,
113       "Avg is %f (wanted %d) => %" GST_TIME_FORMAT, usage,
114       self->priv->wanted_cpu_usage, GST_TIME_ARGS (priv->current_wait_time));
115 
116   return TRUE;
117 }
118 
119 static GstClockReturn
_wait(GstClock * clock,GstClockEntry * entry,GstClockTimeDiff * jitter)120 _wait (GstClock * clock, GstClockEntry * entry, GstClockTimeDiff * jitter)
121 {
122   GstCpuThrottlingClock *self = GST_CPU_THROTTLING_CLOCK (clock);
123 
124   if (!self->priv->evaluate_wait_time) {
125     if (!(self->priv->sclock)) {
126       GST_ERROR_OBJECT (clock, "Could not find any system clock"
127           " to start the wait time evaluation task");
128     } else {
129       self->priv->evaluate_wait_time =
130           gst_clock_new_periodic_id (self->priv->sclock,
131           gst_clock_get_time (self->priv->sclock),
132           self->priv->time_between_evals);
133 
134       gst_clock_id_wait_async (self->priv->evaluate_wait_time,
135           (GstClockCallback) gst_transcoder_adjust_wait_time,
136           (gpointer) self, NULL);
137     }
138   }
139 
140   if (G_UNLIKELY (GST_CLOCK_ENTRY_STATUS (entry) == GST_CLOCK_UNSCHEDULED))
141     return GST_CLOCK_UNSCHEDULED;
142 
143   if (gst_poll_wait (self->priv->timer, self->priv->current_wait_time)) {
144     GST_INFO_OBJECT (self, "Something happened on the poll");
145   }
146 
147   return GST_CLOCK_ENTRY_STATUS (entry);
148 }
149 
150 static GstClockTime
_get_internal_time(GstClock * clock)151 _get_internal_time (GstClock * clock)
152 {
153   GstCpuThrottlingClock *self = GST_CPU_THROTTLING_CLOCK (clock);
154 
155   return gst_clock_get_internal_time (self->priv->sclock);
156 }
157 
158 static void
gst_cpu_throttling_clock_dispose(GObject * object)159 gst_cpu_throttling_clock_dispose (GObject * object)
160 {
161   GstCpuThrottlingClock *self = GST_CPU_THROTTLING_CLOCK (object);
162 
163   if (self->priv->evaluate_wait_time) {
164     gst_clock_id_unschedule (self->priv->evaluate_wait_time);
165     gst_clock_id_unref (self->priv->evaluate_wait_time);
166     self->priv->evaluate_wait_time = 0;
167   }
168 }
169 
170 static void
gst_cpu_throttling_clock_class_init(GstCpuThrottlingClockClass * klass)171 gst_cpu_throttling_clock_class_init (GstCpuThrottlingClockClass * klass)
172 {
173   GObjectClass *oclass = G_OBJECT_CLASS (klass);
174   GstClockClass *clock_klass = GST_CLOCK_CLASS (klass);
175 
176   GST_DEBUG_CATEGORY_INIT (gst_cpu_throttling_clock_debug, "cpuclock", 0,
177       "UriTranscodebin element");
178 
179   oclass->get_property = gst_cpu_throttling_clock_get_property;
180   oclass->set_property = gst_cpu_throttling_clock_set_property;
181   oclass->dispose = gst_cpu_throttling_clock_dispose;
182 
183   /**
184    * GstCpuThrottlingClock:cpu-usage:
185    *
186    * Since: UNRELEASED
187    */
188   param_specs[PROP_CPU_USAGE] = g_param_spec_uint ("cpu-usage", "cpu-usage",
189       "The percentage of CPU to try to use with the processus running the "
190       "pipeline driven by the clock", 0, 100,
191       100, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
192 
193   g_object_class_install_properties (oclass, PROP_LAST, param_specs);
194 
195   clock_klass->wait = GST_DEBUG_FUNCPTR (_wait);
196   clock_klass->get_internal_time = _get_internal_time;
197 }
198 
199 static void
gst_cpu_throttling_clock_init(GstCpuThrottlingClock * self)200 gst_cpu_throttling_clock_init (GstCpuThrottlingClock * self)
201 {
202   self->priv = gst_cpu_throttling_clock_get_instance_private (self);
203 
204   self->priv->current_wait_time = GST_MSECOND;
205   self->priv->wanted_cpu_usage = 100;
206   self->priv->timer = gst_poll_new_timer ();
207   self->priv->time_between_evals = GST_SECOND / 4;
208   self->priv->sclock = GST_CLOCK (gst_system_clock_obtain ());
209 
210 
211   getrusage (RUSAGE_SELF, &self->priv->last_usage);
212 }
213 
214 GstCpuThrottlingClock *
gst_cpu_throttling_clock_new(guint cpu_usage)215 gst_cpu_throttling_clock_new (guint cpu_usage)
216 {
217   return g_object_new (GST_TYPE_CPU_THROTTLING_CLOCK, "cpu-usage",
218       cpu_usage, NULL);
219 }
220 #endif
221