daemon: add nice value in service file to improve performance
[platform/upstream/pulseaudio.git] / src / pulsecore / core-rtclock.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2004-2006 Lennart Poettering
5   Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
7   PulseAudio is free software; you can redistribute it and/or modify
8   it under the terms of the GNU Lesser General Public License as
9   published by the Free Software Foundation; either version 2.1 of the
10   License, or (at your option) any later version.
11
12   PulseAudio is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   Lesser General Public License for more details.
16
17   You should have received a copy of the GNU Lesser General Public
18   License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #ifdef OS_IS_DARWIN
26 #define _POSIX_C_SOURCE 1
27 #endif
28
29 #include <stddef.h>
30 #include <time.h>
31 #include <sys/time.h>
32 #include <errno.h>
33
34 #ifdef HAVE_SYS_PRCTL_H
35 #include <sys/prctl.h>
36 #endif
37
38 #ifdef OS_IS_DARWIN
39 #include <CoreServices/CoreServices.h>
40 #include <mach/mach.h>
41 #include <mach/mach_time.h>
42 #include <unistd.h>
43 #endif
44
45 #ifdef HAVE_WINDOWS_H
46 #include <windows.h>
47 #endif
48
49 #include <pulse/timeval.h>
50 #include <pulsecore/macro.h>
51 #include <pulsecore/core-error.h>
52
53 #include "core-rtclock.h"
54
55 #ifdef OS_IS_WIN32
56 static int64_t counter_freq = 0;
57 #endif
58
59 pa_usec_t pa_rtclock_age(const struct timeval *tv) {
60     struct timeval now;
61     pa_assert(tv);
62
63     return pa_timeval_diff(pa_rtclock_get(&now), tv);
64 }
65
66 struct timeval *pa_rtclock_get(struct timeval *tv) {
67
68 #if defined(OS_IS_DARWIN)
69     uint64_t val, abs_time = mach_absolute_time();
70     Nanoseconds nanos;
71
72     nanos = AbsoluteToNanoseconds(*(AbsoluteTime *) &abs_time);
73     val = *(uint64_t *) &nanos;
74
75     tv->tv_sec = val / PA_NSEC_PER_SEC;
76     tv->tv_usec = (val % PA_NSEC_PER_SEC) / PA_NSEC_PER_USEC;
77
78     return tv;
79
80 #elif defined(HAVE_CLOCK_GETTIME)
81     struct timespec ts;
82
83 #ifdef CLOCK_MONOTONIC
84     /* No locking or atomic ops for no_monotonic here */
85     static bool no_monotonic = false;
86
87     if (!no_monotonic)
88         if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0)
89             no_monotonic = true;
90
91     if (no_monotonic)
92 #endif /* CLOCK_MONOTONIC */
93         pa_assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
94
95     pa_assert(tv);
96
97     tv->tv_sec = ts.tv_sec;
98     tv->tv_usec = ts.tv_nsec / PA_NSEC_PER_USEC;
99
100     return tv;
101 #elif defined(OS_IS_WIN32)
102     if (counter_freq > 0) {
103         LARGE_INTEGER count;
104
105         pa_assert_se(QueryPerformanceCounter(&count));
106
107         tv->tv_sec = count.QuadPart / counter_freq;
108         tv->tv_usec = (count.QuadPart % counter_freq) * PA_USEC_PER_SEC / counter_freq;
109
110         return tv;
111     }
112 #endif /* HAVE_CLOCK_GETTIME */
113
114     return pa_gettimeofday(tv);
115 }
116
117 bool pa_rtclock_hrtimer(void) {
118
119 #if defined (OS_IS_DARWIN)
120     mach_timebase_info_data_t tbi;
121     uint64_t time_nsec;
122
123     mach_timebase_info(&tbi);
124
125     /* nsec = nticks * (N/D) - we want 1 tick == resolution !? */
126     time_nsec = tbi.numer / tbi.denom;
127     return time_nsec <= (long) (PA_HRTIMER_THRESHOLD_USEC*PA_NSEC_PER_USEC);
128
129 #elif defined(HAVE_CLOCK_GETTIME)
130     struct timespec ts;
131
132 #ifdef CLOCK_MONOTONIC
133
134     if (clock_getres(CLOCK_MONOTONIC, &ts) >= 0)
135         return ts.tv_sec == 0 && ts.tv_nsec <= (long) (PA_HRTIMER_THRESHOLD_USEC*PA_NSEC_PER_USEC);
136
137 #endif /* CLOCK_MONOTONIC */
138
139     pa_assert_se(clock_getres(CLOCK_REALTIME, &ts) == 0);
140     return ts.tv_sec == 0 && ts.tv_nsec <= (long) (PA_HRTIMER_THRESHOLD_USEC*PA_NSEC_PER_USEC);
141
142 #elif defined(OS_IS_WIN32)
143
144     if (counter_freq > 0)
145         return counter_freq >= (int64_t) (PA_USEC_PER_SEC/PA_HRTIMER_THRESHOLD_USEC);
146
147 #endif /* HAVE_CLOCK_GETTIME */
148
149     return false;
150 }
151
152 #define TIMER_SLACK_NS (int) ((500 * PA_NSEC_PER_USEC))
153
154 void pa_rtclock_hrtimer_enable(void) {
155
156 #ifdef PR_SET_TIMERSLACK
157     int slack_ns;
158
159     if ((slack_ns = prctl(PR_GET_TIMERSLACK, 0, 0, 0, 0)) < 0) {
160         pa_log_info("PR_GET_TIMERSLACK/PR_SET_TIMERSLACK not supported.");
161         return;
162     }
163
164     pa_log_debug("Timer slack is set to %i us.", (int) (slack_ns/PA_NSEC_PER_USEC));
165
166     if (slack_ns > TIMER_SLACK_NS) {
167         slack_ns = TIMER_SLACK_NS;
168
169         pa_log_debug("Setting timer slack to %i us.", (int) (slack_ns/PA_NSEC_PER_USEC));
170
171         if (prctl(PR_SET_TIMERSLACK, slack_ns, 0, 0, 0) < 0) {
172             pa_log_warn("PR_SET_TIMERSLACK failed: %s", pa_cstrerror(errno));
173             return;
174         }
175     }
176
177 #elif defined(OS_IS_WIN32)
178     LARGE_INTEGER freq;
179
180     pa_assert_se(QueryPerformanceFrequency(&freq));
181     counter_freq = freq.QuadPart;
182
183 #endif
184 }
185
186 struct timeval* pa_rtclock_from_wallclock(struct timeval *tv) {
187     struct timeval wc_now, rt_now;
188
189     pa_assert(tv);
190
191     pa_gettimeofday(&wc_now);
192     pa_rtclock_get(&rt_now);
193
194     /* pa_timeval_sub() saturates on underflow! */
195
196     if (pa_timeval_cmp(&wc_now, tv) < 0)
197         pa_timeval_add(&rt_now, pa_timeval_diff(tv, &wc_now));
198     else
199         pa_timeval_sub(&rt_now, pa_timeval_diff(&wc_now, tv));
200
201     *tv = rt_now;
202
203     return tv;
204 }
205
206 #ifdef HAVE_CLOCK_GETTIME
207 pa_usec_t pa_timespec_load(const struct timespec *ts) {
208
209     if (PA_UNLIKELY(!ts))
210         return PA_USEC_INVALID;
211
212     return
213         (pa_usec_t) ts->tv_sec * PA_USEC_PER_SEC +
214         (pa_usec_t) ts->tv_nsec / PA_NSEC_PER_USEC;
215 }
216
217 struct timespec* pa_timespec_store(struct timespec *ts, pa_usec_t v) {
218     pa_assert(ts);
219
220     if (PA_UNLIKELY(v == PA_USEC_INVALID)) {
221         ts->tv_sec = PA_INT_TYPE_MAX(time_t);
222         ts->tv_nsec = (long) (PA_NSEC_PER_SEC-1);
223         return NULL;
224     }
225
226     ts->tv_sec = (time_t) (v / PA_USEC_PER_SEC);
227     ts->tv_nsec = (long) ((v % PA_USEC_PER_SEC) * PA_NSEC_PER_USEC);
228
229     return ts;
230 }
231 #endif
232
233 static struct timeval* wallclock_from_rtclock(struct timeval *tv) {
234     struct timeval wc_now, rt_now;
235
236     pa_assert(tv);
237
238     pa_gettimeofday(&wc_now);
239     pa_rtclock_get(&rt_now);
240
241     /* pa_timeval_sub() saturates on underflow! */
242
243     if (pa_timeval_cmp(&rt_now, tv) < 0)
244         pa_timeval_add(&wc_now, pa_timeval_diff(tv, &rt_now));
245     else
246         pa_timeval_sub(&wc_now, pa_timeval_diff(&rt_now, tv));
247
248     *tv = wc_now;
249
250     return tv;
251 }
252
253 struct timeval* pa_timeval_rtstore(struct timeval *tv, pa_usec_t v, bool rtclock) {
254     pa_assert(tv);
255
256     if (v == PA_USEC_INVALID)
257         return NULL;
258
259     pa_timeval_store(tv, v);
260
261     if (rtclock)
262         tv->tv_usec |= PA_TIMEVAL_RTCLOCK;
263     else
264         wallclock_from_rtclock(tv);
265
266     return tv;
267 }