blob: f383da443465252db5ed0c5b0df6a8aaa7250a23 [file] [log] [blame]
Elliott Hughesb28e4902014-03-11 11:19:06 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "benchmark.h"
18
Mark Salyzyn7e50fb22015-02-09 08:18:10 -080019#include <pthread.h>
Elliott Hughesb28e4902014-03-11 11:19:06 -070020#include <semaphore.h>
Mark Salyzyn7e50fb22015-02-09 08:18:10 -080021#include <stdatomic.h>
22#include <stdio.h>
Elliott Hughesb28e4902014-03-11 11:19:06 -070023
24static void BM_semaphore_sem_getvalue(int iters) {
25 StopBenchmarkTiming();
26 sem_t semaphore;
27 sem_init(&semaphore, 1, 1);
28 StartBenchmarkTiming();
29
30 for (int i = 0; i < iters; ++i) {
31 int dummy;
32 sem_getvalue(&semaphore, &dummy);
33 }
34
35 StopBenchmarkTiming();
36}
37BENCHMARK(BM_semaphore_sem_getvalue);
38
39static void BM_semaphore_sem_wait_sem_post(int iters) {
40 StopBenchmarkTiming();
41 sem_t semaphore;
42 sem_init(&semaphore, 1, 1);
43 StartBenchmarkTiming();
44
45 for (int i = 0; i < iters; ++i) {
46 sem_wait(&semaphore);
47 sem_post(&semaphore);
48 }
49
50 StopBenchmarkTiming();
51}
52BENCHMARK(BM_semaphore_sem_wait_sem_post);
Mark Salyzyn7e50fb22015-02-09 08:18:10 -080053
54/*
55 * This test reports the overhead of the underlying futex wake syscall on
56 * the producer. It does not report the overhead from issuing the wake to the
57 * point where the posted consumer thread wakes up. It suffers from
58 * clock_gettime syscall overhead. Lock the CPU speed for consistent results
59 * as we may not reach >50% cpu utilization.
60 *
61 * We will run a background thread that catches the sem_post wakeup and
62 * loops immediately returning back to sleep in sem_wait for the next one. This
63 * thread is run with policy SCHED_OTHER (normal policy), a middle policy.
64 *
65 * The primary thread will run at SCHED_IDLE (lowest priority policy) when
66 * monitoring the background thread to detect when it hits sem_wait sleep. It
67 * will do so with no clock running. Once we are ready, we will switch to
68 * SCHED_FIFO (highest priority policy) to time the act of running sem_post
69 * with the benchmark clock running. This ensures nothing else in the system
70 * can preempt our timed activity, including the background thread. We are
71 * also protected with the scheduling policy of letting a process hit a
72 * resource limit rather than get hit with a context switch.
73 *
74 * The background thread will start executing either on another CPU, or
75 * after we back down from SCHED_FIFO, but certainly not in the context of
76 * the timing of the sem_post.
77 */
78static atomic_int BM_semaphore_sem_post_running;
79
80static void *BM_semaphore_sem_post_start_thread(void *obj) {
81 sem_t *semaphore = reinterpret_cast<sem_t *>(obj);
82
83 while ((BM_semaphore_sem_post_running > 0) && !sem_wait(semaphore)) {
84 ;
85 }
86 BM_semaphore_sem_post_running = -1;
87 return NULL;
88}
89
90static void BM_semaphore_sem_post(int iters) {
91 StopBenchmarkTiming();
92
93 sem_t semaphore;
94 sem_init(&semaphore, 0, 0);
95
96 pthread_attr_t attr;
97 pthread_attr_init(&attr);
98 BM_semaphore_sem_post_running = 1;
99 struct sched_param param = { 0, };
100 pthread_attr_setschedparam(&attr, &param);
101 pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
102 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
103 pthread_t pthread;
104 pthread_create(&pthread, &attr, BM_semaphore_sem_post_start_thread, &semaphore);
105 pthread_attr_destroy(&attr);
106
107 sched_setscheduler((pid_t)0, SCHED_IDLE, &param);
108 for (int i = 0; i < iters; ++i) {
109 int trys = 3, dummy = 0;
110 do {
111 if (BM_semaphore_sem_post_running < 0) {
112 sched_setscheduler((pid_t)0, SCHED_OTHER, &param);
113 fprintf(stderr, "BM_semaphore_sem_post: start_thread died unexpectedly\n");
114 return;
115 }
116 sched_yield();
117 sem_getvalue(&semaphore, &dummy);
118 if (dummy < 0) { // POSIX.1-2001 possibility 1
119 break;
120 }
121 if (dummy == 0) { // POSIX.1-2001 possibility 2
122 --trys;
123 }
124 } while (trys);
125 param.sched_priority = 1;
126 sched_setscheduler((pid_t)0, SCHED_FIFO, &param);
127 StartBenchmarkTiming();
128 sem_post(&semaphore);
129 StopBenchmarkTiming(); // Remember to subtract clock syscall overhead
130 param.sched_priority = 0;
131 sched_setscheduler((pid_t)0, SCHED_IDLE, &param);
132 }
133 sched_setscheduler((pid_t)0, SCHED_OTHER, &param);
134
135 if (BM_semaphore_sem_post_running > 0) {
136 BM_semaphore_sem_post_running = 0;
137 }
138 do {
139 sem_post(&semaphore);
140 sched_yield();
141 } while (!BM_semaphore_sem_post_running);
142}
143BENCHMARK(BM_semaphore_sem_post);