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