Home | History | Annotate | Download | only in simpleperf
      1 /*
      2  * Copyright (C) 2016 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 "IOEventLoop.h"
     18 
     19 #include <gtest/gtest.h>
     20 
     21 #include <atomic>
     22 #include <chrono>
     23 #include <thread>
     24 
     25 TEST(IOEventLoop, read) {
     26   int fd[2];
     27   ASSERT_EQ(0, pipe(fd));
     28   IOEventLoop loop;
     29   int count = 0;
     30   int retry_count = 0;
     31   ASSERT_NE(nullptr, loop.AddReadEvent(fd[0], [&]() {
     32     while (true) {
     33       char c;
     34       int ret = read(fd[0], &c, 1);
     35       if (ret == 1) {
     36         if (++count == 100) {
     37           return loop.ExitLoop();
     38         }
     39       } else if (ret == -1 && errno == EAGAIN) {
     40         retry_count++;
     41         break;
     42       } else {
     43         return false;
     44       }
     45     }
     46     return true;
     47   }));
     48   std::thread thread([&]() {
     49     for (int i = 0; i < 100; ++i) {
     50       usleep(1000);
     51       char c;
     52       write(fd[1], &c, 1);
     53     }
     54   });
     55   ASSERT_TRUE(loop.RunLoop());
     56   thread.join();
     57   ASSERT_EQ(100, count);
     58   // Test retry_count to make sure we are not doing blocking read.
     59   ASSERT_GT(retry_count, 0);
     60   close(fd[0]);
     61   close(fd[1]);
     62 }
     63 
     64 TEST(IOEventLoop, write) {
     65   int fd[2];
     66   ASSERT_EQ(0, pipe(fd));
     67   IOEventLoop loop;
     68   int count = 0;
     69   ASSERT_NE(nullptr, loop.AddWriteEvent(fd[1], [&]() {
     70     int ret = 0;
     71     char buf[4096];
     72     while ((ret = write(fd[1], buf, sizeof(buf))) > 0) {
     73     }
     74     if (ret == -1 && errno == EAGAIN) {
     75       if (++count == 100) {
     76         loop.ExitLoop();
     77       }
     78       return true;
     79     }
     80     return false;
     81   }));
     82   std::thread thread([&]() {
     83     usleep(500000);
     84     while (true) {
     85       usleep(1000);
     86       char buf[4096];
     87       if (read(fd[0], buf, sizeof(buf)) <= 0) {
     88         break;
     89       }
     90     }
     91   });
     92   ASSERT_TRUE(loop.RunLoop());
     93   // close fd[1] to make read thread stop.
     94   close(fd[1]);
     95   thread.join();
     96   close(fd[0]);
     97   ASSERT_EQ(100, count);
     98 }
     99 
    100 TEST(IOEventLoop, signal) {
    101   IOEventLoop loop;
    102   int count = 0;
    103   ASSERT_TRUE(loop.AddSignalEvent(SIGINT, [&]() {
    104     if (++count == 100) {
    105       loop.ExitLoop();
    106     }
    107     return true;
    108   }));
    109   std::atomic<bool> stop_thread(false);
    110   std::thread thread([&]() {
    111     while (!stop_thread) {
    112       usleep(1000);
    113       kill(getpid(), SIGINT);
    114     }
    115   });
    116   ASSERT_TRUE(loop.RunLoop());
    117   stop_thread = true;
    118   thread.join();
    119   ASSERT_EQ(100, count);
    120 }
    121 
    122 void TestPeriodicEvents(int period_in_us, int iterations, bool precise) {
    123   timeval tv;
    124   tv.tv_sec = period_in_us / 1000000;
    125   tv.tv_usec = period_in_us % 1000000;
    126   int count = 0;
    127   IOEventLoop loop;
    128   if (precise) {
    129     ASSERT_TRUE(loop.UsePreciseTimer());
    130   }
    131   ASSERT_TRUE(loop.AddPeriodicEvent(tv, [&]() {
    132     if (++count == iterations) {
    133       loop.ExitLoop();
    134     }
    135     return true;
    136   }));
    137   auto start_time = std::chrono::steady_clock::now();
    138   ASSERT_TRUE(loop.RunLoop());
    139   auto end_time = std::chrono::steady_clock::now();
    140   ASSERT_EQ(iterations, count);
    141   double time_used = std::chrono::duration_cast<std::chrono::duration<double>>(
    142                          end_time - start_time).count();
    143   double min_time_in_sec = period_in_us / 1e6 * iterations;
    144   double max_time_in_sec = min_time_in_sec + (precise ? 0.1 : 1);
    145   ASSERT_GE(time_used, min_time_in_sec);
    146   ASSERT_LT(time_used, max_time_in_sec);
    147 }
    148 
    149 TEST(IOEventLoop, periodic) {
    150   TestPeriodicEvents(1000000, 1, false);
    151 }
    152 
    153 TEST(IOEventLoop, periodic_precise) {
    154   TestPeriodicEvents(1000, 100, true);
    155 }
    156 
    157 TEST(IOEventLoop, read_and_del_event) {
    158   int fd[2];
    159   ASSERT_EQ(0, pipe(fd));
    160   IOEventLoop loop;
    161   int count = 0;
    162   IOEventRef ref = loop.AddReadEvent(fd[0], [&]() {
    163     count++;
    164     return IOEventLoop::DelEvent(ref);
    165   });
    166   ASSERT_NE(nullptr, ref);
    167 
    168   std::thread thread([&]() {
    169     for (int i = 0; i < 100; ++i) {
    170       usleep(1000);
    171       char c;
    172       write(fd[1], &c, 1);
    173     }
    174   });
    175   ASSERT_TRUE(loop.RunLoop());
    176   thread.join();
    177   ASSERT_EQ(1, count);
    178   close(fd[0]);
    179   close(fd[1]);
    180 }
    181 
    182 TEST(IOEventLoop, disable_enable_event) {
    183   int fd[2];
    184   ASSERT_EQ(0, pipe(fd));
    185   IOEventLoop loop;
    186   int count = 0;
    187   IOEventRef ref = loop.AddWriteEvent(fd[1], [&]() {
    188     count++;
    189     return IOEventLoop::DisableEvent(ref);
    190   });
    191   ASSERT_NE(nullptr, ref);
    192 
    193   timeval tv;
    194   tv.tv_sec = 0;
    195   tv.tv_usec = 500000;
    196   int periodic_count = 0;
    197   ASSERT_TRUE(loop.AddPeriodicEvent(tv, [&]() {
    198     periodic_count++;
    199     if (periodic_count == 1) {
    200       if (count != 1) {
    201         return false;
    202       }
    203       return IOEventLoop::EnableEvent(ref);
    204     } else {
    205       if (count != 2) {
    206         return false;
    207       }
    208       return loop.ExitLoop();
    209     }
    210   }));
    211 
    212   ASSERT_TRUE(loop.RunLoop());
    213   ASSERT_EQ(2, count);
    214   ASSERT_EQ(2, periodic_count);
    215   close(fd[0]);
    216   close(fd[1]);
    217 }
    218