1 /* 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 <pthread.h> 18 #include <semaphore.h> 19 #include <stdatomic.h> 20 #include <stdio.h> 21 22 #include <benchmark/Benchmark.h> 23 24 BENCHMARK_NO_ARG(BM_semaphore_sem_getvalue); 25 void BM_semaphore_sem_getvalue::Run(int iters) { 26 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 } 38 39 BENCHMARK_NO_ARG(BM_semaphore_sem_wait_sem_post); 40 void BM_semaphore_sem_wait_sem_post::Run(int iters) { 41 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 } 53 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 */ 78 static atomic_int BM_semaphore_sem_post_running; 79 80 static 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 90 BENCHMARK_NO_ARG(BM_semaphore_sem_post); 91 void BM_semaphore_sem_post::Run(int iters) { 92 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, ¶m); 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, ¶m); 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, ¶m); 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, ¶m); 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, ¶m); 133 } 134 sched_setscheduler((pid_t)0, SCHED_OTHER, ¶m); 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 } 144