1b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes/*
2b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes * Copyright (C) 2014 The Android Open Source Project
3b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes *
4b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
5b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes * you may not use this file except in compliance with the License.
6b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes * You may obtain a copy of the License at
7b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes *
8b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
9b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes *
10b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes * Unless required by applicable law or agreed to in writing, software
11b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
12b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes * See the License for the specific language governing permissions and
14b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes * limitations under the License.
15b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes */
16b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes
177e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn#include <pthread.h>
18b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes#include <semaphore.h>
197e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn#include <stdatomic.h>
207e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn#include <stdio.h>
21a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes#include <stdlib.h>
22b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes
23a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes#include <benchmark/benchmark.h>
24df4942c04a63ae6e4f5c78ece9f696d6b8b74d32Christopher Ferris
25a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughesstatic void BM_semaphore_sem_getvalue(benchmark::State& state) {
26b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes  sem_t semaphore;
27b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes  sem_init(&semaphore, 1, 1);
28b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes
29a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes  while (state.KeepRunning()) {
30b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes    int dummy;
31b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes    sem_getvalue(&semaphore, &dummy);
32b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes  }
33b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes}
34a630784fe1124ae5956da2639f1b324c15365fa7Elliott HughesBENCHMARK(BM_semaphore_sem_getvalue);
35b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes
36a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughesstatic void BM_semaphore_sem_wait_sem_post(benchmark::State& state) {
37b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes  sem_t semaphore;
38b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes  sem_init(&semaphore, 1, 1);
39b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes
40a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes  while (state.KeepRunning()) {
41b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes    sem_wait(&semaphore);
42b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes    sem_post(&semaphore);
43b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes  }
44b28e490b7350b21c5ae9e5b3bb3e082d8357a1b0Elliott Hughes}
45a630784fe1124ae5956da2639f1b324c15365fa7Elliott HughesBENCHMARK(BM_semaphore_sem_wait_sem_post);
46a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes
47a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes// This test reports the overhead of the underlying futex wake syscall on
48a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes// the producer. It does not report the overhead from issuing the wake to the
49a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes// point where the posted consumer thread wakes up. It suffers from
50a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes// clock_gettime syscall overhead. Lock the CPU speed for consistent results
51a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes// as we may not reach >50% cpu utilization.
52a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes//
53a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes// We will run a background thread that catches the sem_post wakeup and
54a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes// loops immediately returning back to sleep in sem_wait for the next one. This
55a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes// thread is run with policy SCHED_OTHER (normal policy), a middle policy.
56a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes//
57a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes// The primary thread will run at SCHED_IDLE (lowest priority policy) when
58a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes// monitoring the background thread to detect when it hits sem_wait sleep. It
59a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes// will do so with no clock running. Once we are ready, we will switch to
60a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes// SCHED_FIFO (highest priority policy) to time the act of running sem_post
61a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes// with the benchmark clock running. This ensures nothing else in the system
62a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes// can preempt our timed activity, including the background thread. We are
63a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes// also protected with the scheduling policy of letting a process hit a
64a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes// resource limit rather than get hit with a context switch.
65a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes//
66a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes// The background thread will start executing either on another CPU, or
67a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes// after we back down from SCHED_FIFO, but certainly not in the context of
68a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes// the timing of the sem_post.
697e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn
707e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzynstatic atomic_int BM_semaphore_sem_post_running;
717e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn
72a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughesstatic void* BM_semaphore_sem_post_start_thread(void* arg) {
73a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes  sem_t* semaphore = reinterpret_cast<sem_t*>(arg);
74a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes  while ((BM_semaphore_sem_post_running > 0) && !sem_wait(semaphore)) {
75a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes  }
76a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes  BM_semaphore_sem_post_running = -1;
77a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes  return NULL;
787e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn}
797e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn
80a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughesclass SemaphoreFixture : public benchmark::Fixture {
81a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes public:
82a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes  void SetUp(const benchmark::State&) {
83a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes    sem_init(&semaphore, 0, 0);
84a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes
85a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes    pthread_attr_t attr;
86a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes    pthread_attr_init(&attr);
87a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes
88a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes    memset(&param, 0, sizeof(param));
89a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes    pthread_attr_setschedparam(&attr, &param);
90a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes    pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
91a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
92a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes    pthread_t pthread;
93a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes    pthread_create(&pthread, &attr, BM_semaphore_sem_post_start_thread, &semaphore);
94a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes    pthread_attr_destroy(&attr);
95a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes
96a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes    sched_setscheduler(0, SCHED_IDLE, &param);
97a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes
98a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes    BM_semaphore_sem_post_running = 1;
99a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes  }
100a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes
101a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes  ~SemaphoreFixture() {
102a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes    sched_setscheduler(0, SCHED_OTHER, &param);
103a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes
104a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes    if (BM_semaphore_sem_post_running > 0) {
105a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes      BM_semaphore_sem_post_running = 0;
106a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes    }
107a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes    do {
108a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes      sem_post(&semaphore);
109a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes      sched_yield();
110a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes    } while (BM_semaphore_sem_post_running != -1);
111a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes  }
1127e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn
1137e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn  sem_t semaphore;
114a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes  sched_param param;
115a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes};
116a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes
117a630784fe1124ae5956da2639f1b324c15365fa7Elliott HughesBENCHMARK_F(SemaphoreFixture, semaphore_sem_post)(benchmark::State& state) {
118a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes  while (state.KeepRunning()) {
119a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes    state.PauseTiming();
120a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes
1217e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn    int trys = 3, dummy = 0;
1227e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn    do {
1237e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn      if (BM_semaphore_sem_post_running < 0) {
124a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes        sched_setscheduler(0, SCHED_OTHER, &param);
1257e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn        fprintf(stderr, "BM_semaphore_sem_post: start_thread died unexpectedly\n");
126a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes        abort();
1277e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn      }
1287e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn      sched_yield();
1297e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn      sem_getvalue(&semaphore, &dummy);
1307e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn      if (dummy < 0) {  // POSIX.1-2001 possibility 1
1317e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn        break;
1327e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn      }
1337e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn      if (dummy == 0) { // POSIX.1-2001 possibility 2
1347e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn        --trys;
1357e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn      }
1367e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn    } while (trys);
137a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes
1387e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn    param.sched_priority = 1;
139a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes    sched_setscheduler(0, SCHED_FIFO, &param);
140a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes
141a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes    state.ResumeTiming();
1427e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn    sem_post(&semaphore);
1437e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn
144a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes    param.sched_priority = 0;
145a630784fe1124ae5956da2639f1b324c15365fa7Elliott Hughes    sched_setscheduler(0, SCHED_IDLE, &param);
1467e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn  }
1477e50fb2a681c858ec7d85ff92e97794f41fd1f08Mark Salyzyn}
148