blob: 8dd56849d3662b5e18ac601545594977cd99d092 [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
Mark Salyzyn7e50fb22015-02-09 08:18:10 -080017#include <pthread.h>
Elliott Hughesb28e4902014-03-11 11:19:06 -070018#include <semaphore.h>
Mark Salyzyn7e50fb22015-02-09 08:18:10 -080019#include <stdatomic.h>
20#include <stdio.h>
Elliott Hughesb28e4902014-03-11 11:19:06 -070021
Christopher Ferrisdf4942c2015-02-17 19:58:53 -080022#include <benchmark/Benchmark.h>
23
24BENCHMARK_NO_ARG(BM_semaphore_sem_getvalue);
25void BM_semaphore_sem_getvalue::Run(int iters) {
Elliott Hughesb28e4902014-03-11 11:19:06 -070026 StopBenchmarkTiming();
27 sem_t semaphore;
28 sem_init(&semaphore, 1, 1);
29 StartBenchmarkTiming();
30
31 for (int i = 0; i < iters; ++i) {
32 int dummy;
33 sem_getvalue(&semaphore, &dummy);
34 }
35
36 StopBenchmarkTiming();
37}
Elliott Hughesb28e4902014-03-11 11:19:06 -070038
Christopher Ferrisdf4942c2015-02-17 19:58:53 -080039BENCHMARK_NO_ARG(BM_semaphore_sem_wait_sem_post);
40void BM_semaphore_sem_wait_sem_post::Run(int iters) {
Elliott Hughesb28e4902014-03-11 11:19:06 -070041 StopBenchmarkTiming();
42 sem_t semaphore;
43 sem_init(&semaphore, 1, 1);
44 StartBenchmarkTiming();
45
46 for (int i = 0; i < iters; ++i) {
47 sem_wait(&semaphore);
48 sem_post(&semaphore);
49 }
50
51 StopBenchmarkTiming();
52}
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
Christopher Ferrisdf4942c2015-02-17 19:58:53 -080090BENCHMARK_NO_ARG(BM_semaphore_sem_post);
91void BM_semaphore_sem_post::Run(int iters) {
Mark Salyzyn7e50fb22015-02-09 08:18:10 -080092 StopBenchmarkTiming();
93
94 sem_t semaphore;
95 sem_init(&semaphore, 0, 0);
96
97 pthread_attr_t attr;
98 pthread_attr_init(&attr);
99 BM_semaphore_sem_post_running = 1;
100 struct sched_param param = { 0, };
101 pthread_attr_setschedparam(&attr, &param);
102 pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
103 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
104 pthread_t pthread;
105 pthread_create(&pthread, &attr, BM_semaphore_sem_post_start_thread, &semaphore);
106 pthread_attr_destroy(&attr);
107
108 sched_setscheduler((pid_t)0, SCHED_IDLE, &param);
109 for (int i = 0; i < iters; ++i) {
110 int trys = 3, dummy = 0;
111 do {
112 if (BM_semaphore_sem_post_running < 0) {
113 sched_setscheduler((pid_t)0, SCHED_OTHER, &param);
114 fprintf(stderr, "BM_semaphore_sem_post: start_thread died unexpectedly\n");
115 return;
116 }
117 sched_yield();
118 sem_getvalue(&semaphore, &dummy);
119 if (dummy < 0) { // POSIX.1-2001 possibility 1
120 break;
121 }
122 if (dummy == 0) { // POSIX.1-2001 possibility 2
123 --trys;
124 }
125 } while (trys);
126 param.sched_priority = 1;
127 sched_setscheduler((pid_t)0, SCHED_FIFO, &param);
128 StartBenchmarkTiming();
129 sem_post(&semaphore);
130 StopBenchmarkTiming(); // Remember to subtract clock syscall overhead
131 param.sched_priority = 0;
132 sched_setscheduler((pid_t)0, SCHED_IDLE, &param);
133 }
134 sched_setscheduler((pid_t)0, SCHED_OTHER, &param);
135
136 if (BM_semaphore_sem_post_running > 0) {
137 BM_semaphore_sem_post_running = 0;
138 }
139 do {
140 sem_post(&semaphore);
141 sched_yield();
142 } while (!BM_semaphore_sem_post_running);
143}